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