Skip to content

Commit 04d81e8

Browse files
dave-shawleymiss-islington
authored andcommitted
pythongh-115165: Fix typing.Annotated for immutable types (pythonGH-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>
1 parent ca3eca1 commit 04d81e8

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
@@ -3665,6 +3665,16 @@ class C(B[int]):
36653665
c.bar = 'abc'
36663666
self.assertEqual(c.__dict__, {'bar': 'abc'})
36673667

3668+
def test_setattr_exceptions(self):
3669+
class Immutable[T]:
3670+
def __setattr__(self, key, value):
3671+
raise RuntimeError("immutable")
3672+
3673+
# gh-115165: This used to cause RuntimeError to be raised
3674+
# when we tried to set `__orig_class__` on the `Immutable` instance
3675+
# returned by the `Immutable[int]()` call
3676+
self.assertIsInstance(Immutable[int](), Immutable)
3677+
36683678
def test_subscripted_generics_as_proxies(self):
36693679
T = TypeVar('T')
36703680
class C(Generic[T]):
@@ -7397,6 +7407,17 @@ def test_instantiate_generic(self):
73977407
self.assertEqual(MyCount([4, 4, 5]), {4: 2, 5: 1})
73987408
self.assertEqual(MyCount[int]([4, 4, 5]), {4: 2, 5: 1})
73997409

7410+
def test_instantiate_immutable(self):
7411+
class C:
7412+
def __setattr__(self, key, value):
7413+
raise Exception("should be ignored")
7414+
7415+
A = Annotated[C, "a decoration"]
7416+
# gh-115165: This used to cause RuntimeError to be raised
7417+
# when we tried to set `__orig_class__` on the `C` instance
7418+
# returned by the `A()` call
7419+
self.assertIsInstance(A(), C)
7420+
74007421
def test_cannot_instantiate_forward(self):
74017422
A = Annotated["int", (5, 6)]
74027423
with self.assertRaises(TypeError):

Lib/typing.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1275,7 +1275,9 @@ def __call__(self, *args, **kwargs):
12751275
result = self.__origin__(*args, **kwargs)
12761276
try:
12771277
result.__orig_class__ = self
1278-
except AttributeError:
1278+
# Some objects raise TypeError (or something even more exotic)
1279+
# if you try to set attributes on them; we guard against that here
1280+
except Exception:
12791281
pass
12801282
return result
12811283

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)