Skip to content

Commit

Permalink
pythongh-115165: Fix typing.Annotated for immutable types (pythonGH…
Browse files Browse the repository at this point in the history
…-115213)

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

Co-authored-by: dave-shawley <daveshawley@gmail.com>
  • Loading branch information
dave-shawley authored and miss-islington committed Feb 9, 2024
1 parent 3539b02 commit fcc6c71
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 1 deletion.
21 changes: 21 additions & 0 deletions Lib/test/test_typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -4181,6 +4181,16 @@ class C(B[int]):
c.bar = 'abc'
self.assertEqual(c.__dict__, {'bar': 'abc'})

def test_setattr_exceptions(self):
class Immutable[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]):
Expand Down Expand Up @@ -8207,6 +8217,17 @@ def test_instantiate_generic(self):
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):
Expand Down
4 changes: 3 additions & 1 deletion Lib/typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -1140,7 +1140,9 @@ def __call__(self, *args, **kwargs):
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

Expand Down
Original file line number Diff line number Diff line change
@@ -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.

0 comments on commit fcc6c71

Please sign in to comment.