mirror of
https://github.com/python/cpython.git
synced 2025-09-26 18:29:57 +00:00
GH-103699: Add __orig_bases__
to various typing classes (#103698)
Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com> Co-authored-by: Jelle Zijlstra <jelle.zijlstra@gmail.com>
This commit is contained in:
parent
e38bebb9ee
commit
0056701aa3
3 changed files with 70 additions and 2 deletions
|
@ -6695,6 +6695,22 @@ class NamedTupleTests(BaseTestCase):
|
||||||
self.assertEqual(jane2, jane)
|
self.assertEqual(jane2, jane)
|
||||||
self.assertIsInstance(jane2, cls)
|
self.assertIsInstance(jane2, cls)
|
||||||
|
|
||||||
|
def test_orig_bases(self):
|
||||||
|
T = TypeVar('T')
|
||||||
|
|
||||||
|
class SimpleNamedTuple(NamedTuple):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class GenericNamedTuple(NamedTuple, Generic[T]):
|
||||||
|
pass
|
||||||
|
|
||||||
|
self.assertEqual(SimpleNamedTuple.__orig_bases__, (NamedTuple,))
|
||||||
|
self.assertEqual(GenericNamedTuple.__orig_bases__, (NamedTuple, Generic[T]))
|
||||||
|
|
||||||
|
CallNamedTuple = NamedTuple('CallNamedTuple', [])
|
||||||
|
|
||||||
|
self.assertEqual(CallNamedTuple.__orig_bases__, (NamedTuple,))
|
||||||
|
|
||||||
|
|
||||||
class TypedDictTests(BaseTestCase):
|
class TypedDictTests(BaseTestCase):
|
||||||
def test_basics_functional_syntax(self):
|
def test_basics_functional_syntax(self):
|
||||||
|
@ -7126,6 +7142,49 @@ class TypedDictTests(BaseTestCase):
|
||||||
self.assertIs(type(a), dict)
|
self.assertIs(type(a), dict)
|
||||||
self.assertEqual(a, {'a': 1})
|
self.assertEqual(a, {'a': 1})
|
||||||
|
|
||||||
|
def test_orig_bases(self):
|
||||||
|
T = TypeVar('T')
|
||||||
|
|
||||||
|
class Parent(TypedDict):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class Child(Parent):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class OtherChild(Parent):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class MixedChild(Child, OtherChild, Parent):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class GenericParent(TypedDict, Generic[T]):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class GenericChild(GenericParent[int]):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class OtherGenericChild(GenericParent[str]):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class MixedGenericChild(GenericChild, OtherGenericChild, GenericParent[float]):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class MultipleGenericBases(GenericParent[int], GenericParent[float]):
|
||||||
|
pass
|
||||||
|
|
||||||
|
CallTypedDict = TypedDict('CallTypedDict', {})
|
||||||
|
|
||||||
|
self.assertEqual(Parent.__orig_bases__, (TypedDict,))
|
||||||
|
self.assertEqual(Child.__orig_bases__, (Parent,))
|
||||||
|
self.assertEqual(OtherChild.__orig_bases__, (Parent,))
|
||||||
|
self.assertEqual(MixedChild.__orig_bases__, (Child, OtherChild, Parent,))
|
||||||
|
self.assertEqual(GenericParent.__orig_bases__, (TypedDict, Generic[T]))
|
||||||
|
self.assertEqual(GenericChild.__orig_bases__, (GenericParent[int],))
|
||||||
|
self.assertEqual(OtherGenericChild.__orig_bases__, (GenericParent[str],))
|
||||||
|
self.assertEqual(MixedGenericChild.__orig_bases__, (GenericChild, OtherGenericChild, GenericParent[float]))
|
||||||
|
self.assertEqual(MultipleGenericBases.__orig_bases__, (GenericParent[int], GenericParent[float]))
|
||||||
|
self.assertEqual(CallTypedDict.__orig_bases__, (TypedDict,))
|
||||||
|
|
||||||
|
|
||||||
class RequiredTests(BaseTestCase):
|
class RequiredTests(BaseTestCase):
|
||||||
|
|
||||||
|
|
|
@ -2962,7 +2962,9 @@ def NamedTuple(typename, fields=None, /, **kwargs):
|
||||||
elif kwargs:
|
elif kwargs:
|
||||||
raise TypeError("Either list of fields or keywords"
|
raise TypeError("Either list of fields or keywords"
|
||||||
" can be provided to NamedTuple, not both")
|
" can be provided to NamedTuple, not both")
|
||||||
return _make_nmtuple(typename, fields, module=_caller())
|
nt = _make_nmtuple(typename, fields, module=_caller())
|
||||||
|
nt.__orig_bases__ = (NamedTuple,)
|
||||||
|
return nt
|
||||||
|
|
||||||
_NamedTuple = type.__new__(NamedTupleMeta, 'NamedTuple', (), {})
|
_NamedTuple = type.__new__(NamedTupleMeta, 'NamedTuple', (), {})
|
||||||
|
|
||||||
|
@ -2994,6 +2996,9 @@ class _TypedDictMeta(type):
|
||||||
|
|
||||||
tp_dict = type.__new__(_TypedDictMeta, name, (*generic_base, dict), ns)
|
tp_dict = type.__new__(_TypedDictMeta, name, (*generic_base, dict), ns)
|
||||||
|
|
||||||
|
if not hasattr(tp_dict, '__orig_bases__'):
|
||||||
|
tp_dict.__orig_bases__ = bases
|
||||||
|
|
||||||
annotations = {}
|
annotations = {}
|
||||||
own_annotations = ns.get('__annotations__', {})
|
own_annotations = ns.get('__annotations__', {})
|
||||||
msg = "TypedDict('Name', {f0: t0, f1: t1, ...}); each t must be a type"
|
msg = "TypedDict('Name', {f0: t0, f1: t1, ...}); each t must be a type"
|
||||||
|
@ -3104,7 +3109,9 @@ def TypedDict(typename, fields=None, /, *, total=True, **kwargs):
|
||||||
# Setting correct module is necessary to make typed dict classes pickleable.
|
# Setting correct module is necessary to make typed dict classes pickleable.
|
||||||
ns['__module__'] = module
|
ns['__module__'] = module
|
||||||
|
|
||||||
return _TypedDictMeta(typename, (), ns, total=total)
|
td = _TypedDictMeta(typename, (), ns, total=total)
|
||||||
|
td.__orig_bases__ = (TypedDict,)
|
||||||
|
return td
|
||||||
|
|
||||||
_TypedDict = type.__new__(_TypedDictMeta, 'TypedDict', (), {})
|
_TypedDict = type.__new__(_TypedDictMeta, 'TypedDict', (), {})
|
||||||
TypedDict.__mro_entries__ = lambda bases: (_TypedDict,)
|
TypedDict.__mro_entries__ = lambda bases: (_TypedDict,)
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
Add ``__orig_bases__`` to non-generic TypedDicts, call-based TypedDicts, and
|
||||||
|
call-based NamedTuples. Other TypedDicts and NamedTuples already had the attribute.
|
Loading…
Add table
Add a link
Reference in a new issue