@@ -953,6 +953,21 @@ def __round__(self, ndigits: int = 0) -> T_co:
953953 pass
954954
955955
956+ def _ensure_subclassable (mro_entries ):
957+ def inner (func ):
958+ if sys .implementation .name == "pypy" and sys .version_info < (3 , 9 ):
959+ cls_dict = {
960+ "__call__" : staticmethod (func ),
961+ "__mro_entries__" : staticmethod (mro_entries )
962+ }
963+ t = type (func .__name__ , (), cls_dict )
964+ return functools .update_wrapper (t (), func )
965+ else :
966+ func .__mro_entries__ = mro_entries
967+ return func
968+ return inner
969+
970+
956971if sys .version_info >= (3 , 13 ):
957972 # The standard library TypedDict in Python 3.8 does not store runtime information
958973 # about which (if any) keys are optional. See https://bugs.python.org/issue38834
@@ -1059,6 +1074,9 @@ def __subclasscheck__(cls, other):
10591074
10601075 __instancecheck__ = __subclasscheck__
10611076
1077+ _TypedDict = type .__new__ (_TypedDictMeta , 'TypedDict' , (), {})
1078+
1079+ @_ensure_subclassable (lambda bases : (_TypedDict ,))
10621080 def TypedDict (__typename , __fields = _marker , * , total = True , ** kwargs ):
10631081 """A simple typed namespace. At runtime it is equivalent to a plain dict.
10641082
@@ -1142,9 +1160,6 @@ class Point2D(TypedDict):
11421160 td .__orig_bases__ = (TypedDict ,)
11431161 return td
11441162
1145- _TypedDict = type .__new__ (_TypedDictMeta , 'TypedDict' , (), {})
1146- TypedDict .__mro_entries__ = lambda bases : (_TypedDict ,)
1147-
11481163 if hasattr (typing , "_TypedDictMeta" ):
11491164 _TYPEDDICT_TYPES = (typing ._TypedDictMeta , _TypedDictMeta )
11501165 else :
@@ -2633,6 +2648,13 @@ def __new__(cls, typename, bases, ns):
26332648 nm_tpl .__init_subclass__ ()
26342649 return nm_tpl
26352650
2651+ _NamedTuple = type .__new__ (_NamedTupleMeta , 'NamedTuple' , (), {})
2652+
2653+ def _namedtuple_mro_entries (bases ):
2654+ assert NamedTuple in bases
2655+ return (_NamedTuple ,)
2656+
2657+ @_ensure_subclassable (_namedtuple_mro_entries )
26362658 def NamedTuple (__typename , __fields = _marker , ** kwargs ):
26372659 """Typed version of namedtuple.
26382660
@@ -2698,19 +2720,15 @@ class Employee(NamedTuple):
26982720 nt .__orig_bases__ = (NamedTuple ,)
26992721 return nt
27002722
2701- _NamedTuple = type .__new__ (_NamedTupleMeta , 'NamedTuple' , (), {})
2702-
27032723 # On 3.8+, alter the signature so that it matches typing.NamedTuple.
27042724 # The signature of typing.NamedTuple on >=3.8 is invalid syntax in Python 3.7,
27052725 # so just leave the signature as it is on 3.7.
27062726 if sys .version_info >= (3 , 8 ):
2707- NamedTuple .__text_signature__ = '(typename, fields=None, /, **kwargs)'
2708-
2709- def _namedtuple_mro_entries (bases ):
2710- assert NamedTuple in bases
2711- return (_NamedTuple ,)
2712-
2713- NamedTuple .__mro_entries__ = _namedtuple_mro_entries
2727+ _new_signature = '(typename, fields=None, /, **kwargs)'
2728+ if isinstance (NamedTuple , _types .FunctionType ):
2729+ NamedTuple .__text_signature__ = _new_signature
2730+ else :
2731+ NamedTuple .__call__ .__text_signature__ = _new_signature
27142732
27152733
27162734if hasattr (collections .abc , "Buffer" ):
@@ -2986,7 +3004,8 @@ def is_protocol(__tp: type) -> bool:
29863004 return (
29873005 isinstance (__tp , type )
29883006 and getattr (__tp , '_is_protocol' , False )
2989- and __tp != Protocol
3007+ and __tp is not Protocol
3008+ and __tp is not getattr (typing , "Protocol" , object ())
29903009 )
29913010
29923011 def get_protocol_members (__tp : type ) -> typing .FrozenSet [str ]:
0 commit comments