Skip to content

Commit b6c0558

Browse files
Add tests for metaclasses and typing_extensions.get_annotations (python#440)
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.
1 parent 2849332 commit b6c0558

File tree

2 files changed

+79
-3
lines changed

2 files changed

+79
-3
lines changed

pyproject.toml

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,19 @@ select = [
8181
"W",
8282
]
8383

84-
# Ignore various "modernization" rules that tell you off for importing/using
85-
# deprecated things from the typing module, etc.
86-
ignore = ["UP006", "UP007", "UP013", "UP014", "UP019", "UP035", "UP038"]
84+
ignore = [
85+
# Ignore various "modernization" rules that tell you off for importing/using
86+
# deprecated things from the typing module, etc.
87+
"UP006",
88+
"UP007",
89+
"UP013",
90+
"UP014",
91+
"UP019",
92+
"UP035",
93+
"UP038",
94+
# Not relevant here
95+
"RUF012",
96+
]
8797

8898
[tool.ruff.lint.per-file-ignores]
8999
"!src/typing_extensions.py" = [

src/test_typing_extensions.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import importlib
1010
import inspect
1111
import io
12+
import itertools
1213
import pickle
1314
import re
1415
import subprocess
@@ -7685,6 +7686,71 @@ def f(x: int):
76857686
self.assertEqual(get_annotations(f), {"x": str})
76867687

76877688

7689+
class TestGetAnnotationsMetaclasses(BaseTestCase):
7690+
def test_annotated_meta(self):
7691+
class Meta(type):
7692+
a: int
7693+
7694+
class X(metaclass=Meta):
7695+
pass
7696+
7697+
class Y(metaclass=Meta):
7698+
b: float
7699+
7700+
self.assertEqual(get_annotations(Meta), {"a": int})
7701+
self.assertEqual(get_annotations(X), {})
7702+
self.assertEqual(get_annotations(Y), {"b": float})
7703+
7704+
def test_unannotated_meta(self):
7705+
class Meta(type): pass
7706+
7707+
class X(metaclass=Meta):
7708+
a: str
7709+
7710+
class Y(X): pass
7711+
7712+
self.assertEqual(get_annotations(Meta), {})
7713+
self.assertEqual(get_annotations(Y), {})
7714+
self.assertEqual(get_annotations(X), {"a": str})
7715+
7716+
def test_ordering(self):
7717+
# Based on a sample by David Ellis
7718+
# https://discuss.python.org/t/pep-749-implementing-pep-649/54974/38
7719+
7720+
def make_classes():
7721+
class Meta(type):
7722+
a: int
7723+
expected_annotations = {"a": int}
7724+
7725+
class A(type, metaclass=Meta):
7726+
b: float
7727+
expected_annotations = {"b": float}
7728+
7729+
class B(metaclass=A):
7730+
c: str
7731+
expected_annotations = {"c": str}
7732+
7733+
class C(B):
7734+
expected_annotations = {}
7735+
7736+
class D(metaclass=Meta):
7737+
expected_annotations = {}
7738+
7739+
return Meta, A, B, C, D
7740+
7741+
classes = make_classes()
7742+
class_count = len(classes)
7743+
for order in itertools.permutations(range(class_count), class_count):
7744+
names = ", ".join(classes[i].__name__ for i in order)
7745+
with self.subTest(names=names):
7746+
classes = make_classes() # Regenerate classes
7747+
for i in order:
7748+
get_annotations(classes[i])
7749+
for c in classes:
7750+
with self.subTest(c=c):
7751+
self.assertEqual(get_annotations(c), c.expected_annotations)
7752+
7753+
76887754
@skipIf(STRINGIZED_ANNOTATIONS_PEP_695 is None, "PEP 695 has yet to be")
76897755
class TestGetAnnotationsWithPEP695(BaseTestCase):
76907756
@classmethod

0 commit comments

Comments
 (0)