@@ -846,13 +846,6 @@ def __round__(self, ndigits: int = 0) -> T_co:
846846 pass
847847
848848
849- def _ensure_subclassable (mro_entries ):
850- def inner (obj ):
851- obj .__mro_entries__ = mro_entries
852- return obj
853- return inner
854-
855-
856849_NEEDS_SINGLETONMETA = (
857850 not hasattr (typing , "NoDefault" ) or not hasattr (typing , "NoExtraItems" )
858851)
@@ -1078,17 +1071,94 @@ def __subclasscheck__(cls, other):
10781071
10791072 _TypedDict = type .__new__ (_TypedDictMeta , 'TypedDict' , (), {})
10801073
1081- @_ensure_subclassable (lambda bases : (_TypedDict ,))
1082- def TypedDict (
1074+ def _create_typeddict (
10831075 typename ,
1084- fields = _marker ,
1076+ fields ,
10851077 / ,
10861078 * ,
1087- total = True ,
1088- closed = None ,
1089- extra_items = NoExtraItems ,
1090- ** kwargs
1079+ typing_is_inline ,
1080+ total ,
1081+ closed ,
1082+ extra_items ,
1083+ ** kwargs ,
10911084 ):
1085+ if fields is _marker or fields is None :
1086+ if fields is _marker :
1087+ deprecated_thing = (
1088+ "Failing to pass a value for the 'fields' parameter"
1089+ )
1090+ else :
1091+ deprecated_thing = "Passing `None` as the 'fields' parameter"
1092+
1093+ example = f"`{ typename } = TypedDict({ typename !r} , {{}})`"
1094+ deprecation_msg = (
1095+ f"{ deprecated_thing } is deprecated and will be disallowed in "
1096+ "Python 3.15. To create a TypedDict class with 0 fields "
1097+ "using the functional syntax, pass an empty dictionary, e.g. "
1098+ ) + example + "."
1099+ warnings .warn (deprecation_msg , DeprecationWarning , stacklevel = 2 )
1100+ # Support a field called "closed"
1101+ if closed is not False and closed is not True and closed is not None :
1102+ kwargs ["closed" ] = closed
1103+ closed = None
1104+ # Or "extra_items"
1105+ if extra_items is not NoExtraItems :
1106+ kwargs ["extra_items" ] = extra_items
1107+ extra_items = NoExtraItems
1108+ fields = kwargs
1109+ elif kwargs :
1110+ raise TypeError ("TypedDict takes either a dict or keyword arguments,"
1111+ " but not both" )
1112+ if kwargs :
1113+ if sys .version_info >= (3 , 13 ):
1114+ raise TypeError ("TypedDict takes no keyword arguments" )
1115+ warnings .warn (
1116+ "The kwargs-based syntax for TypedDict definitions is deprecated "
1117+ "in Python 3.11, will be removed in Python 3.13, and may not be "
1118+ "understood by third-party type checkers." ,
1119+ DeprecationWarning ,
1120+ stacklevel = 2 ,
1121+ )
1122+
1123+ ns = {'__annotations__' : dict (fields )}
1124+ module = _caller (depth = 5 if typing_is_inline else 3 )
1125+ if module is not None :
1126+ # Setting correct module is necessary to make typed dict classes
1127+ # pickleable.
1128+ ns ['__module__' ] = module
1129+
1130+ td = _TypedDictMeta (typename , (), ns , total = total , closed = closed ,
1131+ extra_items = extra_items )
1132+ td .__orig_bases__ = (TypedDict ,)
1133+ return td
1134+
1135+ class _TypedDictSpecialForm (_ExtensionsSpecialForm , _root = True ):
1136+ def __call__ (
1137+ self ,
1138+ typename ,
1139+ fields = _marker ,
1140+ / ,
1141+ * ,
1142+ total = True ,
1143+ closed = None ,
1144+ extra_items = NoExtraItems ,
1145+ ** kwargs
1146+ ):
1147+ return _create_typeddict (
1148+ typename ,
1149+ fields ,
1150+ typing_is_inline = False ,
1151+ total = total ,
1152+ closed = closed ,
1153+ extra_items = extra_items ,
1154+ ** kwargs ,
1155+ )
1156+
1157+ def __mro_entries__ (self , bases ):
1158+ return (_TypedDict ,)
1159+
1160+ @_TypedDictSpecialForm
1161+ def TypedDict (self , args ):
10921162 """A simple typed namespace. At runtime it is equivalent to a plain dict.
10931163
10941164 TypedDict creates a dictionary type such that a type checker will expect all
@@ -1135,52 +1205,20 @@ class Point2D(TypedDict):
11351205
11361206 See PEP 655 for more details on Required and NotRequired.
11371207 """
1138- if fields is _marker or fields is None :
1139- if fields is _marker :
1140- deprecated_thing = "Failing to pass a value for the 'fields' parameter"
1141- else :
1142- deprecated_thing = "Passing `None` as the 'fields' parameter"
1143-
1144- example = f"`{ typename } = TypedDict({ typename !r} , {{}})`"
1145- deprecation_msg = (
1146- f"{ deprecated_thing } is deprecated and will be disallowed in "
1147- "Python 3.15. To create a TypedDict class with 0 fields "
1148- "using the functional syntax, pass an empty dictionary, e.g. "
1149- ) + example + "."
1150- warnings .warn (deprecation_msg , DeprecationWarning , stacklevel = 2 )
1151- # Support a field called "closed"
1152- if closed is not False and closed is not True and closed is not None :
1153- kwargs ["closed" ] = closed
1154- closed = None
1155- # Or "extra_items"
1156- if extra_items is not NoExtraItems :
1157- kwargs ["extra_items" ] = extra_items
1158- extra_items = NoExtraItems
1159- fields = kwargs
1160- elif kwargs :
1161- raise TypeError ("TypedDict takes either a dict or keyword arguments,"
1162- " but not both" )
1163- if kwargs :
1164- if sys .version_info >= (3 , 13 ):
1165- raise TypeError ("TypedDict takes no keyword arguments" )
1166- warnings .warn (
1167- "The kwargs-based syntax for TypedDict definitions is deprecated "
1168- "in Python 3.11, will be removed in Python 3.13, and may not be "
1169- "understood by third-party type checkers." ,
1170- DeprecationWarning ,
1171- stacklevel = 2 ,
1208+ # This runs when creating inline TypedDicts:
1209+ if not isinstance (args , dict ):
1210+ raise TypeError (
1211+ "TypedDict[...] should be used with a single dict argument"
11721212 )
11731213
1174- ns = {'__annotations__' : dict (fields )}
1175- module = _caller ()
1176- if module is not None :
1177- # Setting correct module is necessary to make typed dict classes pickleable.
1178- ns ['__module__' ] = module
1179-
1180- td = _TypedDictMeta (typename , (), ns , total = total , closed = closed ,
1181- extra_items = extra_items )
1182- td .__orig_bases__ = (TypedDict ,)
1183- return td
1214+ return _create_typeddict (
1215+ "<inline TypedDict>" ,
1216+ args ,
1217+ typing_is_inline = True ,
1218+ total = True ,
1219+ closed = True ,
1220+ extra_items = NoExtraItems ,
1221+ )
11841222
11851223 _TYPEDDICT_TYPES = (typing ._TypedDictMeta , _TypedDictMeta )
11861224
@@ -3194,7 +3232,6 @@ def _namedtuple_mro_entries(bases):
31943232 assert NamedTuple in bases
31953233 return (_NamedTuple ,)
31963234
3197- @_ensure_subclassable (_namedtuple_mro_entries )
31983235 def NamedTuple (typename , fields = _marker , / , ** kwargs ):
31993236 """Typed version of namedtuple.
32003237
@@ -3260,6 +3297,8 @@ class Employee(NamedTuple):
32603297 nt .__orig_bases__ = (NamedTuple ,)
32613298 return nt
32623299
3300+ NamedTuple .__mro_entries__ = _namedtuple_mro_entries
3301+
32633302
32643303if hasattr (collections .abc , "Buffer" ):
32653304 Buffer = collections .abc .Buffer
0 commit comments