1
+ # pyright: ignore[reportShadowedImports]
1
2
import abc
2
3
import builtins
3
4
import collections
@@ -935,11 +936,11 @@ def __reduce__(self):
935
936
del SingletonMeta
936
937
937
938
938
- # Update this to something like >=3.13.0b1 if and when
939
- # PEP 728 is implemented in CPython
940
- _PEP_728_IMPLEMENTED = False
939
+ # Update this to something like >=3.14 if and when
940
+ # PEP 728/PEP 764 is implemented in CPython
941
+ _PEP_728_OR_764_IMPLEMENTED = False
941
942
942
- if _PEP_728_IMPLEMENTED :
943
+ if _PEP_728_OR_764_IMPLEMENTED :
943
944
# The standard library TypedDict in Python 3.8 does not store runtime information
944
945
# about which (if any) keys are optional. See https://bugs.python.org/issue38834
945
946
# The standard library TypedDict in Python 3.9.0/1 does not honour the "total"
@@ -951,7 +952,7 @@ def __reduce__(self):
951
952
# to enable better runtime introspection.
952
953
# On 3.13 we deprecate some odd ways of creating TypedDicts.
953
954
# Also on 3.13, PEP 705 adds the ReadOnly[] qualifier.
954
- # PEP 728 (still pending) makes more changes.
955
+ # PEP 728 and PEP 764 (still pending) makes more changes.
955
956
TypedDict = typing .TypedDict
956
957
_TypedDictMeta = typing ._TypedDictMeta
957
958
is_typeddict = typing .is_typeddict
@@ -1095,7 +1096,11 @@ def __new__(cls, name, bases, ns, *, total=True, closed=None,
1095
1096
tp_dict .__extra_items__ = extra_items_type
1096
1097
return tp_dict
1097
1098
1098
- __call__ = dict # static method
1099
+ def __call__ (cls , / , * args , ** kwargs ):
1100
+ if cls is TypedDict :
1101
+ # Functional syntax, let `TypedDict.__new__` handle it:
1102
+ return super ().__call__ (* args , ** kwargs )
1103
+ return dict (* args , ** kwargs )
1099
1104
1100
1105
def __subclasscheck__ (cls , other ):
1101
1106
# Typed dicts are only for static structural subtyping.
@@ -1105,17 +1110,7 @@ def __subclasscheck__(cls, other):
1105
1110
1106
1111
_TypedDict = type .__new__ (_TypedDictMeta , 'TypedDict' , (), {})
1107
1112
1108
- @_ensure_subclassable (lambda bases : (_TypedDict ,))
1109
- def TypedDict (
1110
- typename ,
1111
- fields = _marker ,
1112
- / ,
1113
- * ,
1114
- total = True ,
1115
- closed = None ,
1116
- extra_items = NoExtraItems ,
1117
- ** kwargs
1118
- ):
1113
+ class TypedDict (metaclass = _TypedDictMeta ):
1119
1114
"""A simple typed namespace. At runtime it is equivalent to a plain dict.
1120
1115
1121
1116
TypedDict creates a dictionary type such that a type checker will expect all
@@ -1162,52 +1157,77 @@ class Point2D(TypedDict):
1162
1157
1163
1158
See PEP 655 for more details on Required and NotRequired.
1164
1159
"""
1165
- if fields is _marker or fields is None :
1166
- if fields is _marker :
1167
- deprecated_thing = "Failing to pass a value for the 'fields' parameter"
1168
- else :
1169
- deprecated_thing = "Passing `None` as the 'fields' parameter"
1170
1160
1171
- example = f"`{ typename } = TypedDict({ typename !r} , {{}})`"
1172
- deprecation_msg = (
1173
- f"{ deprecated_thing } is deprecated and will be disallowed in "
1174
- "Python 3.15. To create a TypedDict class with 0 fields "
1175
- "using the functional syntax, pass an empty dictionary, e.g. "
1176
- ) + example + "."
1177
- warnings .warn (deprecation_msg , DeprecationWarning , stacklevel = 2 )
1178
- # Support a field called "closed"
1179
- if closed is not False and closed is not True and closed is not None :
1180
- kwargs ["closed" ] = closed
1181
- closed = None
1182
- # Or "extra_items"
1183
- if extra_items is not NoExtraItems :
1184
- kwargs ["extra_items" ] = extra_items
1185
- extra_items = NoExtraItems
1186
- fields = kwargs
1187
- elif kwargs :
1188
- raise TypeError ("TypedDict takes either a dict or keyword arguments,"
1189
- " but not both" )
1190
- if kwargs :
1191
- if sys .version_info >= (3 , 13 ):
1192
- raise TypeError ("TypedDict takes no keyword arguments" )
1193
- warnings .warn (
1194
- "The kwargs-based syntax for TypedDict definitions is deprecated "
1195
- "in Python 3.11, will be removed in Python 3.13, and may not be "
1196
- "understood by third-party type checkers." ,
1197
- DeprecationWarning ,
1198
- stacklevel = 2 ,
1199
- )
1161
+ def __new__ (
1162
+ cls ,
1163
+ typename ,
1164
+ fields = _marker ,
1165
+ / ,
1166
+ * ,
1167
+ total = True ,
1168
+ closed = None ,
1169
+ extra_items = NoExtraItems ,
1170
+ ** kwargs
1171
+ ):
1172
+ if fields is _marker or fields is None :
1173
+ if fields is _marker :
1174
+ deprecated_thing = (
1175
+ "Failing to pass a value for the 'fields' parameter"
1176
+ )
1177
+ else :
1178
+ deprecated_thing = "Passing `None` as the 'fields' parameter"
1179
+
1180
+ example = f"`{ typename } = TypedDict({ typename !r} , {{}})`"
1181
+ deprecation_msg = (
1182
+ f"{ deprecated_thing } is deprecated and will be disallowed in "
1183
+ "Python 3.15. To create a TypedDict class with 0 fields "
1184
+ "using the functional syntax, pass an empty dictionary, e.g. "
1185
+ ) + example + "."
1186
+ warnings .warn (deprecation_msg , DeprecationWarning , stacklevel = 2 )
1187
+ # Support a field called "closed"
1188
+ if closed is not False and closed is not True and closed is not None :
1189
+ kwargs ["closed" ] = closed
1190
+ closed = None
1191
+ # Or "extra_items"
1192
+ if extra_items is not NoExtraItems :
1193
+ kwargs ["extra_items" ] = extra_items
1194
+ extra_items = NoExtraItems
1195
+ fields = kwargs
1196
+ elif kwargs :
1197
+ raise TypeError ("TypedDict takes either a dict or keyword arguments,"
1198
+ " but not both" )
1199
+ if kwargs :
1200
+ if sys .version_info >= (3 , 13 ):
1201
+ raise TypeError ("TypedDict takes no keyword arguments" )
1202
+ warnings .warn (
1203
+ "The kwargs-based syntax for TypedDict definitions is deprecated "
1204
+ "in Python 3.11, will be removed in Python 3.13, and may not be "
1205
+ "understood by third-party type checkers." ,
1206
+ DeprecationWarning ,
1207
+ stacklevel = 2 ,
1208
+ )
1200
1209
1201
- ns = {'__annotations__' : dict (fields )}
1202
- module = _caller ()
1203
- if module is not None :
1204
- # Setting correct module is necessary to make typed dict classes pickleable.
1205
- ns ['__module__' ] = module
1210
+ ns = {'__annotations__' : dict (fields )}
1211
+ module = _caller (depth = 3 )
1212
+ if module is not None :
1213
+ # Setting correct module is necessary to make typed dict classes
1214
+ # pickleable.
1215
+ ns ['__module__' ] = module
1206
1216
1207
- td = _TypedDictMeta (typename , (), ns , total = total , closed = closed ,
1208
- extra_items = extra_items )
1209
- td .__orig_bases__ = (TypedDict ,)
1210
- return td
1217
+ td = _TypedDictMeta (typename , (), ns , total = total , closed = closed ,
1218
+ extra_items = extra_items )
1219
+ td .__orig_bases__ = (TypedDict ,)
1220
+ return td
1221
+
1222
+ def __class_getitem__ (cls , args ):
1223
+ if not isinstance (args , tuple ):
1224
+ args = (args ,)
1225
+ if len (args ) != 1 or not isinstance (args [0 ], dict):
1226
+ raise TypeError (
1227
+ "TypedDict[...] should be used with a single dict argument"
1228
+ )
1229
+
1230
+ return cls .__new__ (cls , "<inlined TypedDict>" , args [0 ])
1211
1231
1212
1232
if hasattr (typing , "_TypedDictMeta" ):
1213
1233
_TYPEDDICT_TYPES = (typing ._TypedDictMeta , _TypedDictMeta )
@@ -1225,10 +1245,11 @@ class Film(TypedDict):
1225
1245
is_typeddict(Film) # => True
1226
1246
is_typeddict(Union[list, str]) # => False
1227
1247
"""
1228
- # On 3.8, this would otherwise return True
1229
- if hasattr (typing , "TypedDict" ) and tp is typing .TypedDict :
1230
- return False
1231
- return isinstance (tp , _TYPEDDICT_TYPES )
1248
+ return (
1249
+ tp is not TypedDict
1250
+ and tp is not typing .TypedDict
1251
+ and isinstance (tp , _TYPEDDICT_TYPES )
1252
+ )
1232
1253
1233
1254
1234
1255
if hasattr (typing , "assert_type" ):
0 commit comments