]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.11] gh-115165: Fix `typing.Annotated` for immutable types (GH-115213) (#115228)
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Fri, 9 Feb 2024 22:43:24 +0000 (23:43 +0100)
committerGitHub <noreply@github.com>
Fri, 9 Feb 2024 22:43:24 +0000 (22:43 +0000)
gh-115165: Fix `typing.Annotated` for immutable types (GH-115213)

The return value from an annotated callable can raise any exception from
__setattr__ for the `__orig_class__` property.
(cherry picked from commit 564385612cdf72c2fa8e629a68225fb2cd3b3d99)

Co-authored-by: dave-shawley <daveshawley@gmail.com>
Lib/test/test_typing.py
Lib/typing.py
Misc/NEWS.d/next/Library/2024-02-09-07-20-16.gh-issue-115165.yfJLXA.rst [new file with mode: 0644]

index b0e3ca96fd1c7ffb45970cf1a1ed6fb2860d5b36..8d6d693ed08437b77558f1fdd4111f30eaf8cf6f 100644 (file)
@@ -3665,6 +3665,17 @@ class GenericTests(BaseTestCase):
         c.bar = 'abc'
         self.assertEqual(c.__dict__, {'bar': 'abc'})
 
+    def test_setattr_exceptions(self):
+        T = TypeVar("T")
+        class Immutable(Generic[T]):
+            def __setattr__(self, key, value):
+                raise RuntimeError("immutable")
+
+        # gh-115165: This used to cause RuntimeError to be raised
+        # when we tried to set `__orig_class__` on the `Immutable` instance
+        # returned by the `Immutable[int]()` call
+        self.assertIsInstance(Immutable[int](), Immutable)
+
     def test_subscripted_generics_as_proxies(self):
         T = TypeVar('T')
         class C(Generic[T]):
@@ -7397,6 +7408,17 @@ class AnnotatedTests(BaseTestCase):
         self.assertEqual(MyCount([4, 4, 5]), {4: 2, 5: 1})
         self.assertEqual(MyCount[int]([4, 4, 5]), {4: 2, 5: 1})
 
+    def test_instantiate_immutable(self):
+        class C:
+            def __setattr__(self, key, value):
+                raise Exception("should be ignored")
+
+        A = Annotated[C, "a decoration"]
+        # gh-115165: This used to cause RuntimeError to be raised
+        # when we tried to set `__orig_class__` on the `C` instance
+        # returned by the `A()` call
+        self.assertIsInstance(A(), C)
+
     def test_cannot_instantiate_forward(self):
         A = Annotated["int", (5, 6)]
         with self.assertRaises(TypeError):
index 52898189504c78de3f05cdd5148b328c5a0df250..c62993dbd515f824210d82296067537f15ca7b24 100644 (file)
@@ -1275,7 +1275,9 @@ class _BaseGenericAlias(_Final, _root=True):
         result = self.__origin__(*args, **kwargs)
         try:
             result.__orig_class__ = self
-        except AttributeError:
+        # Some objects raise TypeError (or something even more exotic)
+        # if you try to set attributes on them; we guard against that here
+        except Exception:
             pass
         return result
 
diff --git a/Misc/NEWS.d/next/Library/2024-02-09-07-20-16.gh-issue-115165.yfJLXA.rst b/Misc/NEWS.d/next/Library/2024-02-09-07-20-16.gh-issue-115165.yfJLXA.rst
new file mode 100644 (file)
index 0000000..73d3d00
--- /dev/null
@@ -0,0 +1,4 @@
+Most exceptions are now ignored when attempting to set the ``__orig_class__``
+attribute on objects returned when calling :mod:`typing` generic aliases
+(including generic aliases created using :data:`typing.Annotated`).
+Previously only :exc:`AttributeError`` was ignored. Patch by Dave Shawley.