Skip to content

Commit

Permalink
Add tests for metaclasses and typing_extensions.get_annotations
Browse files Browse the repository at this point in the history
Tests from python/cpython#122074. We don't have to use the base descriptor
approach here because we find the annotations directly in the `__dict__`
for the class, which avoids metaclass problems.
  • Loading branch information
JelleZijlstra committed Jul 27, 2024
1 parent 70cec91 commit 6a08abe
Showing 1 changed file with 66 additions and 0 deletions.
66 changes: 66 additions & 0 deletions src/test_typing_extensions.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import importlib
import inspect
import io
import itertools
import pickle
import re
import subprocess
Expand Down Expand Up @@ -7647,6 +7648,71 @@ def f(x: int):
self.assertEqual(get_annotations(f), {"x": str})


class TestGetAnnotationsMetaclasses(BaseTestCase):
def test_annotated_meta(self):
class Meta(type):
a: int

class X(metaclass=Meta):
pass

class Y(metaclass=Meta):
b: float

self.assertEqual(get_annotations(Meta), {"a": int})
self.assertEqual(get_annotations(X), {})
self.assertEqual(get_annotations(Y), {"b": float})

def test_unannotated_meta(self):
class Meta(type): pass

class X(metaclass=Meta):
a: str

class Y(X): pass

self.assertEqual(get_annotations(Meta), {})
self.assertEqual(get_annotations(Y), {})
self.assertEqual(get_annotations(X), {"a": str})

def test_ordering(self):
# Based on a sample by David Ellis
# https://discuss.python.org/t/pep-749-implementing-pep-649/54974/38

def make_classes():
class Meta(type):
a: int
expected_annotations = {"a": int}

class A(type, metaclass=Meta):
b: float
expected_annotations = {"b": float}

class B(metaclass=A):
c: str
expected_annotations = {"c": str}

class C(B):
expected_annotations = {}

class D(metaclass=Meta):
expected_annotations = {}

return Meta, A, B, C, D

classes = make_classes()
class_count = len(classes)
for order in itertools.permutations(range(class_count), class_count):
names = ", ".join(classes[i].__name__ for i in order)
with self.subTest(names=names):
classes = make_classes() # Regenerate classes
for i in order:
get_annotations(classes[i])
for c in classes:
with self.subTest(c=c):
self.assertEqual(get_annotations(c), c.expected_annotations)


@skipIf(STRINGIZED_ANNOTATIONS_PEP_695 is None, "PEP 695 has yet to be")
class TestGetAnnotationsWithPEP695(BaseTestCase):
@classmethod
Expand Down

0 comments on commit 6a08abe

Please sign in to comment.