Skip to content

Commit 0056701

Browse files
adriangbAlexWaygoodJelleZijlstra
authored
GH-103699: Add __orig_bases__ to various typing classes (#103698)
Co-authored-by: Alex Waygood <[email protected]> Co-authored-by: Jelle Zijlstra <[email protected]>
1 parent e38bebb commit 0056701

File tree

3 files changed

+70
-2
lines changed

3 files changed

+70
-2
lines changed

Lib/test/test_typing.py

+59
Original file line numberDiff line numberDiff line change
@@ -6695,6 +6695,22 @@ def test_copy_and_pickle(self):
66956695
self.assertEqual(jane2, jane)
66966696
self.assertIsInstance(jane2, cls)
66976697

6698+
def test_orig_bases(self):
6699+
T = TypeVar('T')
6700+
6701+
class SimpleNamedTuple(NamedTuple):
6702+
pass
6703+
6704+
class GenericNamedTuple(NamedTuple, Generic[T]):
6705+
pass
6706+
6707+
self.assertEqual(SimpleNamedTuple.__orig_bases__, (NamedTuple,))
6708+
self.assertEqual(GenericNamedTuple.__orig_bases__, (NamedTuple, Generic[T]))
6709+
6710+
CallNamedTuple = NamedTuple('CallNamedTuple', [])
6711+
6712+
self.assertEqual(CallNamedTuple.__orig_bases__, (NamedTuple,))
6713+
66986714

66996715
class TypedDictTests(BaseTestCase):
67006716
def test_basics_functional_syntax(self):
@@ -7126,6 +7142,49 @@ class TD(TypedDict):
71267142
self.assertIs(type(a), dict)
71277143
self.assertEqual(a, {'a': 1})
71287144

7145+
def test_orig_bases(self):
7146+
T = TypeVar('T')
7147+
7148+
class Parent(TypedDict):
7149+
pass
7150+
7151+
class Child(Parent):
7152+
pass
7153+
7154+
class OtherChild(Parent):
7155+
pass
7156+
7157+
class MixedChild(Child, OtherChild, Parent):
7158+
pass
7159+
7160+
class GenericParent(TypedDict, Generic[T]):
7161+
pass
7162+
7163+
class GenericChild(GenericParent[int]):
7164+
pass
7165+
7166+
class OtherGenericChild(GenericParent[str]):
7167+
pass
7168+
7169+
class MixedGenericChild(GenericChild, OtherGenericChild, GenericParent[float]):
7170+
pass
7171+
7172+
class MultipleGenericBases(GenericParent[int], GenericParent[float]):
7173+
pass
7174+
7175+
CallTypedDict = TypedDict('CallTypedDict', {})
7176+
7177+
self.assertEqual(Parent.__orig_bases__, (TypedDict,))
7178+
self.assertEqual(Child.__orig_bases__, (Parent,))
7179+
self.assertEqual(OtherChild.__orig_bases__, (Parent,))
7180+
self.assertEqual(MixedChild.__orig_bases__, (Child, OtherChild, Parent,))
7181+
self.assertEqual(GenericParent.__orig_bases__, (TypedDict, Generic[T]))
7182+
self.assertEqual(GenericChild.__orig_bases__, (GenericParent[int],))
7183+
self.assertEqual(OtherGenericChild.__orig_bases__, (GenericParent[str],))
7184+
self.assertEqual(MixedGenericChild.__orig_bases__, (GenericChild, OtherGenericChild, GenericParent[float]))
7185+
self.assertEqual(MultipleGenericBases.__orig_bases__, (GenericParent[int], GenericParent[float]))
7186+
self.assertEqual(CallTypedDict.__orig_bases__, (TypedDict,))
7187+
71297188

71307189
class RequiredTests(BaseTestCase):
71317190

Lib/typing.py

+9-2
Original file line numberDiff line numberDiff line change
@@ -2962,7 +2962,9 @@ class Employee(NamedTuple):
29622962
elif kwargs:
29632963
raise TypeError("Either list of fields or keywords"
29642964
" can be provided to NamedTuple, not both")
2965-
return _make_nmtuple(typename, fields, module=_caller())
2965+
nt = _make_nmtuple(typename, fields, module=_caller())
2966+
nt.__orig_bases__ = (NamedTuple,)
2967+
return nt
29662968

29672969
_NamedTuple = type.__new__(NamedTupleMeta, 'NamedTuple', (), {})
29682970

@@ -2994,6 +2996,9 @@ def __new__(cls, name, bases, ns, total=True):
29942996

29952997
tp_dict = type.__new__(_TypedDictMeta, name, (*generic_base, dict), ns)
29962998

2999+
if not hasattr(tp_dict, '__orig_bases__'):
3000+
tp_dict.__orig_bases__ = bases
3001+
29973002
annotations = {}
29983003
own_annotations = ns.get('__annotations__', {})
29993004
msg = "TypedDict('Name', {f0: t0, f1: t1, ...}); each t must be a type"
@@ -3104,7 +3109,9 @@ class body be required.
31043109
# Setting correct module is necessary to make typed dict classes pickleable.
31053110
ns['__module__'] = module
31063111

3107-
return _TypedDictMeta(typename, (), ns, total=total)
3112+
td = _TypedDictMeta(typename, (), ns, total=total)
3113+
td.__orig_bases__ = (TypedDict,)
3114+
return td
31083115

31093116
_TypedDict = type.__new__(_TypedDictMeta, 'TypedDict', (), {})
31103117
TypedDict.__mro_entries__ = lambda bases: (_TypedDict,)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Add ``__orig_bases__`` to non-generic TypedDicts, call-based TypedDicts, and
2+
call-based NamedTuples. Other TypedDicts and NamedTuples already had the attribute.

0 commit comments

Comments
 (0)