Skip to content

Commit 5643856

Browse files
authored
gh-115165: Fix typing.Annotated for immutable types (#115213)
The return value from an annotated callable can raise any exception from __setattr__ for the `__orig_class__` property.
1 parent a3af3cb commit 5643856

File tree

3 files changed

+28
-1
lines changed

3 files changed

+28
-1
lines changed

Lib/test/test_typing.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4323,6 +4323,16 @@ class C(B[int]):
43234323
c.bar = 'abc'
43244324
self.assertEqual(c.__dict__, {'bar': 'abc'})
43254325

4326+
def test_setattr_exceptions(self):
4327+
class Immutable[T]:
4328+
def __setattr__(self, key, value):
4329+
raise RuntimeError("immutable")
4330+
4331+
# gh-115165: This used to cause RuntimeError to be raised
4332+
# when we tried to set `__orig_class__` on the `Immutable` instance
4333+
# returned by the `Immutable[int]()` call
4334+
self.assertIsInstance(Immutable[int](), Immutable)
4335+
43264336
def test_subscripted_generics_as_proxies(self):
43274337
T = TypeVar('T')
43284338
class C(Generic[T]):
@@ -8561,6 +8571,17 @@ def test_instantiate_generic(self):
85618571
self.assertEqual(MyCount([4, 4, 5]), {4: 2, 5: 1})
85628572
self.assertEqual(MyCount[int]([4, 4, 5]), {4: 2, 5: 1})
85638573

8574+
def test_instantiate_immutable(self):
8575+
class C:
8576+
def __setattr__(self, key, value):
8577+
raise Exception("should be ignored")
8578+
8579+
A = Annotated[C, "a decoration"]
8580+
# gh-115165: This used to cause RuntimeError to be raised
8581+
# when we tried to set `__orig_class__` on the `C` instance
8582+
# returned by the `A()` call
8583+
self.assertIsInstance(A(), C)
8584+
85648585
def test_cannot_instantiate_forward(self):
85658586
A = Annotated["int", (5, 6)]
85668587
with self.assertRaises(TypeError):

Lib/typing.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1127,7 +1127,9 @@ def __call__(self, *args, **kwargs):
11271127
result = self.__origin__(*args, **kwargs)
11281128
try:
11291129
result.__orig_class__ = self
1130-
except AttributeError:
1130+
# Some objects raise TypeError (or something even more exotic)
1131+
# if you try to set attributes on them; we guard against that here
1132+
except Exception:
11311133
pass
11321134
return result
11331135

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Most exceptions are now ignored when attempting to set the ``__orig_class__``
2+
attribute on objects returned when calling :mod:`typing` generic aliases
3+
(including generic aliases created using :data:`typing.Annotated`).
4+
Previously only :exc:`AttributeError`` was ignored. Patch by Dave Shawley.

0 commit comments

Comments
 (0)