@@ -1078,17 +1078,73 @@ def __subclasscheck__(cls, other):
10781078
10791079 _TypedDict = type .__new__ (_TypedDictMeta , 'TypedDict' , (), {})
10801080
1081+
1082+ class _TypedDictSpecialForm (_ExtensionsSpecialForm , _root = True ):
1083+ def __call__ (
1084+ self ,
1085+ typename ,
1086+ fields = _marker ,
1087+ / ,
1088+ * ,
1089+ total = True ,
1090+ closed = None ,
1091+ extra_items = NoExtraItems ,
1092+ __typing_is_inline__ = False ,
1093+ ** kwargs
1094+ ):
1095+ if fields is _marker or fields is None :
1096+ if fields is _marker :
1097+ deprecated_thing = (
1098+ "Failing to pass a value for the 'fields' parameter"
1099+ )
1100+ else :
1101+ deprecated_thing = "Passing `None` as the 'fields' parameter"
1102+
1103+ example = f"`{ typename } = TypedDict({ typename !r} , {{}})`"
1104+ deprecation_msg = (
1105+ f"{ deprecated_thing } is deprecated and will be disallowed in "
1106+ "Python 3.15. To create a TypedDict class with 0 fields "
1107+ "using the functional syntax, pass an empty dictionary, e.g. "
1108+ ) + example + "."
1109+ warnings .warn (deprecation_msg , DeprecationWarning , stacklevel = 2 )
1110+ # Support a field called "closed"
1111+ if closed is not False and closed is not True and closed is not None :
1112+ kwargs ["closed" ] = closed
1113+ closed = None
1114+ # Or "extra_items"
1115+ if extra_items is not NoExtraItems :
1116+ kwargs ["extra_items" ] = extra_items
1117+ extra_items = NoExtraItems
1118+ fields = kwargs
1119+ elif kwargs :
1120+ raise TypeError ("TypedDict takes either a dict or keyword arguments,"
1121+ " but not both" )
1122+ if kwargs :
1123+ if sys .version_info >= (3 , 13 ):
1124+ raise TypeError ("TypedDict takes no keyword arguments" )
1125+ warnings .warn (
1126+ "The kwargs-based syntax for TypedDict definitions is deprecated "
1127+ "in Python 3.11, will be removed in Python 3.13, and may not be "
1128+ "understood by third-party type checkers." ,
1129+ DeprecationWarning ,
1130+ stacklevel = 2 ,
1131+ )
1132+
1133+ ns = {'__annotations__' : dict (fields )}
1134+ module = _caller (depth = 5 if __typing_is_inline__ else 2 )
1135+ if module is not None :
1136+ # Setting correct module is necessary to make typed dict classes
1137+ # pickleable.
1138+ ns ['__module__' ] = module
1139+
1140+ td = _TypedDictMeta (typename , (), ns , total = total , closed = closed ,
1141+ extra_items = extra_items )
1142+ td .__orig_bases__ = (TypedDict ,)
1143+ return td
1144+
10811145 @_ensure_subclassable (lambda bases : (_TypedDict ,))
1082- def TypedDict (
1083- typename ,
1084- fields = _marker ,
1085- / ,
1086- * ,
1087- total = True ,
1088- closed = None ,
1089- extra_items = NoExtraItems ,
1090- ** kwargs
1091- ):
1146+ @_TypedDictSpecialForm
1147+ def TypedDict (self , args ):
10921148 """A simple typed namespace. At runtime it is equivalent to a plain dict.
10931149
10941150 TypedDict creates a dictionary type such that a type checker will expect all
@@ -1135,52 +1191,16 @@ class Point2D(TypedDict):
11351191
11361192 See PEP 655 for more details on Required and NotRequired.
11371193 """
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 ,
1194+ # This runs when creating inline TypedDicts:
1195+ if not isinstance (args , tuple ):
1196+ args = (args ,)
1197+ if len (args ) != 1 or not isinstance (args [0 ], dict ):
1198+ raise TypeError (
1199+ "TypedDict[...] should be used with a single dict argument"
11721200 )
11731201
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
1202+ # Delegate to _TypedDictSpecialForm.__call__:
1203+ return self ("<inlined TypedDict>" , args [0 ], __typing_is_inline__ = True )
11841204
11851205 _TYPEDDICT_TYPES = (typing ._TypedDictMeta , _TypedDictMeta )
11861206
0 commit comments