Skip to content

Commit 321ec5e

Browse files
[3.12] gh-115165: Fix typing.Annotated for immutable types (GH-115213) (#115227)
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 5643856) Co-authored-by: dave-shawley <[email protected]>
1 parent 3539b02 commit 321ec5e

File tree

3 files changed

+28
-1
lines changed

3 files changed

+28
-1
lines changed

Lib/test/test_typing.py

+21
Original file line numberDiff line numberDiff line change
@@ -4181,6 +4181,16 @@ class C(B[int]):
41814181
c.bar = 'abc'
41824182
self.assertEqual(c.__dict__, {'bar': 'abc'})
41834183

4184+
def test_setattr_exceptions(self):
4185+
class Immutable[T]:
4186+
def __setattr__(self, key, value):
4187+
raise RuntimeError("immutable")
4188+
4189+
# gh-115165: This used to cause RuntimeError to be raised
4190+
# when we tried to set `__orig_class__` on the `Immutable` instance
4191+
# returned by the `Immutable[int]()` call
4192+
self.assertIsInstance(Immutable[int](), Immutable)
4193+
41844194
def test_subscripted_generics_as_proxies(self):
41854195
T = TypeVar('T')
41864196
class C(Generic[T]):
@@ -8207,6 +8217,17 @@ def test_instantiate_generic(self):
82078217
self.assertEqual(MyCount([4, 4, 5]), {4: 2, 5: 1})
82088218
self.assertEqual(MyCount[int]([4, 4, 5]), {4: 2, 5: 1})
82098219

8220+
def test_instantiate_immutable(self):
8221+
class C:
8222+
def __setattr__(self, key, value):
8223+
raise Exception("should be ignored")
8224+
8225+
A = Annotated[C, "a decoration"]
8226+
# gh-115165: This used to cause RuntimeError to be raised
8227+
# when we tried to set `__orig_class__` on the `C` instance
8228+
# returned by the `A()` call
8229+
self.assertIsInstance(A(), C)
8230+
82108231
def test_cannot_instantiate_forward(self):
82118232
A = Annotated["int", (5, 6)]
82128233
with self.assertRaises(TypeError):

Lib/typing.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -1140,7 +1140,9 @@ def __call__(self, *args, **kwargs):
11401140
result = self.__origin__(*args, **kwargs)
11411141
try:
11421142
result.__orig_class__ = self
1143-
except AttributeError:
1143+
# Some objects raise TypeError (or something even more exotic)
1144+
# if you try to set attributes on them; we guard against that here
1145+
except Exception:
11441146
pass
11451147
return result
11461148

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)