[3.12] gh-112618: Make Annotated cache typed (#112619) (#112628)

This commit is contained in:
Alex Waygood 2023-12-03 00:41:03 +00:00 committed by GitHub
parent e3c7947770
commit 2a378ca2ef
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 43 additions and 2 deletions

View file

@ -8403,6 +8403,40 @@ class AnnotatedTests(BaseTestCase):
self.assertEqual(X.__mro__, (X, int, object), self.assertEqual(X.__mro__, (X, int, object),
"Annotated should be transparent.") "Annotated should be transparent.")
def test_annotated_cached_with_types(self):
class A(str): ...
class B(str): ...
field_a1 = Annotated[str, A("X")]
field_a2 = Annotated[str, B("X")]
a1_metadata = field_a1.__metadata__[0]
a2_metadata = field_a2.__metadata__[0]
self.assertIs(type(a1_metadata), A)
self.assertEqual(a1_metadata, A("X"))
self.assertIs(type(a2_metadata), B)
self.assertEqual(a2_metadata, B("X"))
self.assertIsNot(type(a1_metadata), type(a2_metadata))
field_b1 = Annotated[str, A("Y")]
field_b2 = Annotated[str, B("Y")]
b1_metadata = field_b1.__metadata__[0]
b2_metadata = field_b2.__metadata__[0]
self.assertIs(type(b1_metadata), A)
self.assertEqual(b1_metadata, A("Y"))
self.assertIs(type(b2_metadata), B)
self.assertEqual(b2_metadata, B("Y"))
self.assertIsNot(type(b1_metadata), type(b2_metadata))
field_c1 = Annotated[int, 1]
field_c2 = Annotated[int, 1.0]
field_c3 = Annotated[int, True]
self.assertIs(type(field_c1.__metadata__[0]), int)
self.assertIs(type(field_c2.__metadata__[0]), float)
self.assertIs(type(field_c3.__metadata__[0]), bool)
class TypeAliasTests(BaseTestCase): class TypeAliasTests(BaseTestCase):
def test_canonical_usage_with_variable_annotation(self): def test_canonical_usage_with_variable_annotation(self):

View file

@ -2065,9 +2065,14 @@ class Annotated:
def __new__(cls, *args, **kwargs): def __new__(cls, *args, **kwargs):
raise TypeError("Type Annotated cannot be instantiated.") raise TypeError("Type Annotated cannot be instantiated.")
@_tp_cache
def __class_getitem__(cls, params): def __class_getitem__(cls, params):
if not isinstance(params, tuple) or len(params) < 2: if not isinstance(params, tuple):
params = (params,)
return cls._class_getitem_inner(cls, *params)
@_tp_cache(typed=True)
def _class_getitem_inner(cls, *params):
if len(params) < 2:
raise TypeError("Annotated[...] should be used " raise TypeError("Annotated[...] should be used "
"with at least two arguments (a type and an " "with at least two arguments (a type and an "
"annotation).") "annotation).")

View file

@ -0,0 +1,2 @@
Fix a caching bug relating to :data:`typing.Annotated`.
``Annotated[str, True]`` is no longer identical to ``Annotated[str, 1]``.