@@ -953,6 +953,21 @@ def __round__(self, ndigits: int = 0) -> T_co:
953
953
pass
954
954
955
955
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
+
956
971
if sys .version_info >= (3 , 13 ):
957
972
# The standard library TypedDict in Python 3.8 does not store runtime information
958
973
# about which (if any) keys are optional. See https://bugs.python.org/issue38834
@@ -1059,6 +1074,9 @@ def __subclasscheck__(cls, other):
1059
1074
1060
1075
__instancecheck__ = __subclasscheck__
1061
1076
1077
+ _TypedDict = type .__new__ (_TypedDictMeta , 'TypedDict' , (), {})
1078
+
1079
+ @_ensure_subclassable (lambda bases : (_TypedDict ,))
1062
1080
def TypedDict (__typename , __fields = _marker , * , total = True , ** kwargs ):
1063
1081
"""A simple typed namespace. At runtime it is equivalent to a plain dict.
1064
1082
@@ -1142,9 +1160,6 @@ class Point2D(TypedDict):
1142
1160
td .__orig_bases__ = (TypedDict ,)
1143
1161
return td
1144
1162
1145
- _TypedDict = type .__new__ (_TypedDictMeta , 'TypedDict' , (), {})
1146
- TypedDict .__mro_entries__ = lambda bases : (_TypedDict ,)
1147
-
1148
1163
if hasattr (typing , "_TypedDictMeta" ):
1149
1164
_TYPEDDICT_TYPES = (typing ._TypedDictMeta , _TypedDictMeta )
1150
1165
else :
@@ -2633,6 +2648,13 @@ def __new__(cls, typename, bases, ns):
2633
2648
nm_tpl .__init_subclass__ ()
2634
2649
return nm_tpl
2635
2650
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 )
2636
2658
def NamedTuple (__typename , __fields = _marker , ** kwargs ):
2637
2659
"""Typed version of namedtuple.
2638
2660
@@ -2698,19 +2720,15 @@ class Employee(NamedTuple):
2698
2720
nt .__orig_bases__ = (NamedTuple ,)
2699
2721
return nt
2700
2722
2701
- _NamedTuple = type .__new__ (_NamedTupleMeta , 'NamedTuple' , (), {})
2702
-
2703
2723
# On 3.8+, alter the signature so that it matches typing.NamedTuple.
2704
2724
# The signature of typing.NamedTuple on >=3.8 is invalid syntax in Python 3.7,
2705
2725
# so just leave the signature as it is on 3.7.
2706
2726
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
2714
2732
2715
2733
2716
2734
if hasattr (collections .abc , "Buffer" ):
@@ -2986,7 +3004,8 @@ def is_protocol(__tp: type) -> bool:
2986
3004
return (
2987
3005
isinstance (__tp , type )
2988
3006
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 ())
2990
3009
)
2991
3010
2992
3011
def get_protocol_members (__tp : type ) -> typing .FrozenSet [str ]:
0 commit comments