|
| 1 | +# pyright: ignore |
1 | 2 | import abc
|
2 | 3 | import builtins
|
3 | 4 | import collections
|
@@ -1105,17 +1106,73 @@ def __subclasscheck__(cls, other):
|
1105 | 1106 |
|
1106 | 1107 | _TypedDict = type.__new__(_TypedDictMeta, 'TypedDict', (), {})
|
1107 | 1108 |
|
| 1109 | + |
| 1110 | + class _TypedDictSpecialForm(_ExtensionsSpecialForm, _root=True): |
| 1111 | + def __call__( |
| 1112 | + self, |
| 1113 | + typename, |
| 1114 | + fields=_marker, |
| 1115 | + /, |
| 1116 | + *, |
| 1117 | + total=True, |
| 1118 | + closed=None, |
| 1119 | + extra_items=NoExtraItems, |
| 1120 | + __typing_is_inline__=False, |
| 1121 | + **kwargs |
| 1122 | + ): |
| 1123 | + if fields is _marker or fields is None: |
| 1124 | + if fields is _marker: |
| 1125 | + deprecated_thing = ( |
| 1126 | + "Failing to pass a value for the 'fields' parameter" |
| 1127 | + ) |
| 1128 | + else: |
| 1129 | + deprecated_thing = "Passing `None` as the 'fields' parameter" |
| 1130 | + |
| 1131 | + example = f"`{typename} = TypedDict({typename!r}, {{}})`" |
| 1132 | + deprecation_msg = ( |
| 1133 | + f"{deprecated_thing} is deprecated and will be disallowed in " |
| 1134 | + "Python 3.15. To create a TypedDict class with 0 fields " |
| 1135 | + "using the functional syntax, pass an empty dictionary, e.g. " |
| 1136 | + ) + example + "." |
| 1137 | + warnings.warn(deprecation_msg, DeprecationWarning, stacklevel=2) |
| 1138 | + # Support a field called "closed" |
| 1139 | + if closed is not False and closed is not True and closed is not None: |
| 1140 | + kwargs["closed"] = closed |
| 1141 | + closed = None |
| 1142 | + # Or "extra_items" |
| 1143 | + if extra_items is not NoExtraItems: |
| 1144 | + kwargs["extra_items"] = extra_items |
| 1145 | + extra_items = NoExtraItems |
| 1146 | + fields = kwargs |
| 1147 | + elif kwargs: |
| 1148 | + raise TypeError("TypedDict takes either a dict or keyword arguments," |
| 1149 | + " but not both") |
| 1150 | + if kwargs: |
| 1151 | + if sys.version_info >= (3, 13): |
| 1152 | + raise TypeError("TypedDict takes no keyword arguments") |
| 1153 | + warnings.warn( |
| 1154 | + "The kwargs-based syntax for TypedDict definitions is deprecated " |
| 1155 | + "in Python 3.11, will be removed in Python 3.13, and may not be " |
| 1156 | + "understood by third-party type checkers.", |
| 1157 | + DeprecationWarning, |
| 1158 | + stacklevel=2, |
| 1159 | + ) |
| 1160 | + |
| 1161 | + ns = {'__annotations__': dict(fields)} |
| 1162 | + module = _caller(depth=5 if __typing_is_inline__ else 2) |
| 1163 | + if module is not None: |
| 1164 | + # Setting correct module is necessary to make typed dict classes |
| 1165 | + # pickleable. |
| 1166 | + ns['__module__'] = module |
| 1167 | + |
| 1168 | + td = _TypedDictMeta(typename, (), ns, total=total, closed=closed, |
| 1169 | + extra_items=extra_items) |
| 1170 | + td.__orig_bases__ = (TypedDict,) |
| 1171 | + return td |
| 1172 | + |
1108 | 1173 | @_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 |
| - ): |
| 1174 | + @_TypedDictSpecialForm |
| 1175 | + def TypedDict(self, args): |
1119 | 1176 | """A simple typed namespace. At runtime it is equivalent to a plain dict.
|
1120 | 1177 |
|
1121 | 1178 | TypedDict creates a dictionary type such that a type checker will expect all
|
@@ -1162,52 +1219,16 @@ class Point2D(TypedDict):
|
1162 | 1219 |
|
1163 | 1220 | See PEP 655 for more details on Required and NotRequired.
|
1164 | 1221 | """
|
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 |
| - |
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, |
| 1222 | + # This runs when creating inline TypedDicts: |
| 1223 | +
B445
span> 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" |
1199 | 1228 | )
|
1200 | 1229 |
|
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 |
1206 |
| - |
1207 |
| - td = _TypedDictMeta(typename, (), ns, total=total, closed=closed, |
1208 |
| - extra_items=extra_items) |
1209 |
| - td.__orig_bases__ = (TypedDict,) |
1210 |
| - return td |
| 1230 | + # Delegate to _TypedDictSpecialForm.__call__: |
| 1231 | + return self("<inlined TypedDict>", args[0], __typing_is_inline__=True) |
1211 | 1232 |
|
1212 | 1233 | if hasattr(typing, "_TypedDictMeta"):
|
1213 | 1234 | _TYPEDDICT_TYPES = (typing._TypedDictMeta, _TypedDictMeta)
|
|
0 commit comments