2
2
import collections
3
3
import collections .abc
4
4
import functools
5
+ import inspect
5
6
import operator
6
7
import sys
7
8
import types as _types
8
9
import typing
10
+ import warnings
9
11
10
12
11
13
__all__ = [
51
53
'assert_type' ,
52
54
'clear_overloads' ,
53
55
'dataclass_transform' ,
56
+ 'deprecated' ,
54
57
'get_overloads' ,
55
58
'final' ,
56
59
'get_args' ,
@@ -728,6 +731,8 @@ def _typeddict_new(*args, total=True, **kwargs):
728
731
_typeddict_new .__text_signature__ = ('($cls, _typename, _fields=None,'
729
732
' /, *, total=True, **kwargs)' )
730
733
734
+ _TAKES_MODULE = "module" in inspect .signature (typing ._type_check ).parameters
735
+
731
736
class _TypedDictMeta (type ):
732
737
def __init__ (cls , name , bases , ns , total = True ):
733
738
super ().__init__ (name , bases , ns )
@@ -753,8 +758,10 @@ def __new__(cls, name, bases, ns, total=True):
753
758
annotations = {}
754
759
own_annotations = ns .get ('__annotations__' , {})
755
760
msg = "TypedDict('Name', {f0: t0, f1: t1, ...}); each t must be a type"
761
+ kwds = {"module" : tp_dict .__module__ } if _TAKES_MODULE else {}
756
762
own_annotations = {
757
- n : typing ._type_check (tp , msg ) for n , tp in own_annotations .items ()
763
+ n : typing ._type_check (tp , msg , ** kwds )
764
+ for n , tp in own_annotations .items ()
758
765
}
759
766
required_keys = set ()
760
767
optional_keys = set ()
@@ -1157,7 +1164,7 @@ def __init__(self, default):
1157
1164
if isinstance (default , (tuple , list )):
1158
1165
self .__default__ = tuple ((typing ._type_check (d , "Default must be a type" )
1159
1166
for d in default ))
1160
- elif default :
1167
+ elif default != _marker :
1161
1168
self .__default__ = typing ._type_check (default , "Default must be a type" )
1162
1169
else :
1163
1170
self .__default__ = None
@@ -1171,7 +1178,7 @@ class TypeVar(typing.TypeVar, _DefaultMixin, _root=True):
1171
1178
1172
1179
def __init__ (self , name , * constraints , bound = None ,
1173
1180
covariant = False , contravariant = False ,
1174
- default = None , infer_variance = False ):
1181
+ default = _marker , infer_variance = False ):
1175
1182
super ().__init__ (name , * constraints , bound = bound , covariant = covariant ,
1176
1183
contravariant = contravariant )
1177
1184
_DefaultMixin .__init__ (self , default )
@@ -1258,7 +1265,7 @@ class ParamSpec(typing.ParamSpec, _DefaultMixin, _root=True):
1258
1265
__module__ = 'typing'
1259
1266
1260
1267
def __init__ (self , name , * , bound = None , covariant = False , contravariant = False ,
1261
- default = None ):
1268
+ default = _marker ):
1262
1269
super ().__init__ (name , bound = bound , covariant = covariant ,
1263
1270
contravariant = contravariant )
1264
1271
_DefaultMixin .__init__ (self , default )
@@ -1334,7 +1341,7 @@ def kwargs(self):
1334
1341
return ParamSpecKwargs (self )
1335
1342
1336
1343
def __init__ (self , name , * , bound = None , covariant = False , contravariant = False ,
1337
- default = None ):
1344
+ default = _marker ):
1338
1345
super ().__init__ ([self ])
1339
1346
self .__name__ = name
1340
1347
self .__covariant__ = bool (covariant )
@@ -1850,7 +1857,7 @@ def _is_unpack(obj):
1850
1857
class TypeVarTuple (typing .TypeVarTuple , _DefaultMixin , _root = True ):
1851
1858
"""Type variable tuple."""
1852
1859
1853
- def __init__ (self , name , * , default = None ):
1860
+ def __init__ (self , name , * , default = _marker ):
1854
1861
super ().__init__ (name )
1855
1862
_DefaultMixin .__init__ (self , default )
1856
1863
@@ -1913,7 +1920,7 @@ def get_shape(self) -> Tuple[*Ts]:
1913
1920
def __iter__ (self ):
1914
1921
yield self .__unpacked__
1915
1922
1916
- def __init__ (self , name , * , default = None ):
1923
+ def __init__ (self , name , * , default = _marker ):
1917
1924
self .__name__ = name
1918
1925
_DefaultMixin .__init__ (self , default )
1919
1926
@@ -1993,14 +2000,16 @@ def int_or_str(arg: int | str) -> None:
1993
2000
raise AssertionError ("Expected code to be unreachable" )
1994
2001
1995
2002
1996
- if hasattr (typing , 'dataclass_transform' ):
2003
+ if sys .version_info >= (3 , 12 ):
2004
+ # dataclass_transform exists in 3.11 but lacks the frozen_default parameter
1997
2005
dataclass_transform = typing .dataclass_transform
1998
2006
else :
1999
2007
def dataclass_transform (
2000
2008
* ,
2001
2009
eq_default : bool = True ,
2002
2010
order_default : bool = False ,
2003
2011
kw_only_default : bool = False ,
2012
+ frozen_default : bool = False ,
2004
2013
field_specifiers : typing .Tuple [
2005
2014
typing .Union [typing .Type [typing .Any ], typing .Callable [..., typing .Any ]],
2006
2015
...
@@ -2057,6 +2066,8 @@ class CustomerModel(ModelBase):
2057
2066
assumed to be True or False if it is omitted by the caller.
2058
2067
- ``kw_only_default`` indicates whether the ``kw_only`` parameter is
2059
2068
assumed to be True or False if it is omitted by the caller.
2069
+ - ``frozen_default`` indicates whether the ``frozen`` parameter is
2070
+ assumed to be True or False if it is omitted by the caller.
2060
2071
- ``field_specifiers`` specifies a static list of supported classes
2061
2072
or functions that describe fields, similar to ``dataclasses.field()``.
2062
2073
@@ -2071,6 +2082,7 @@ def decorator(cls_or_fn):
2071
2082
"eq_default" : eq_default ,
2072
2083
"order_default" : order_default ,
2073
2084
"kw_only_default" : kw_only_default ,
2085
+ "frozen_default" : frozen_default ,
2074
2086
"field_specifiers" : field_specifiers ,
2075
2087
"kwargs" : kwargs ,
2076
2088
}
@@ -2102,12 +2114,103 @@ def method(self) -> None:
2102
2114
This helps prevent bugs that may occur when a base class is changed
2103
2115
without an equivalent change to a child class.
2104
2116
2117
+ There is no runtime checking of these properties. The decorator
2118
+ sets the ``__override__`` attribute to ``True`` on the decorated object
2119
+ to allow runtime introspection.
2120
+
2105
2121
See PEP 698 for details.
2106
2122
2107
2123
"""
2124
+ try :
2125
+ __arg .__override__ = True
2126
+ except (AttributeError , TypeError ):
2127
+ # Skip the attribute silently if it is not writable.
2128
+ # AttributeError happens if the object has __slots__ or a
2129
+ # read-only property, TypeError if it's a builtin class.
2130
+ pass
2108
2131
return __arg
2109
2132
2110
2133
2134
+ if hasattr (typing , "deprecated" ):
2135
+ deprecated = typing .deprecated
2136
+ else :
2137
+ _T = typing .TypeVar ("_T" )
2138
+
2139
+ def deprecated (
2140
+ __msg : str ,
2141
+ * ,
2142
+ category : typing .Optional [typing .Type [Warning ]] = DeprecationWarning ,
2143
+ stacklevel : int = 1 ,
2144
+ ) -> typing .Callable [[_T ], _T ]:
2145
+ """Indicate that a class, function or overload is deprecated.
2146
+
2147
+ Usage:
2148
+
2149
+ @deprecated("Use B instead")
2150
+ class A:
2151
+ pass
2152
+
2153
+ @deprecated("Use g instead")
2154
+ def f():
2155
+ pass
2156
+
2157
+ @overload
2158
+ @deprecated("int support is deprecated")
2159
+ def g(x: int) -> int: ...
2160
+ @overload
2161
+ def g(x: str) -> int: ...
2162
+
2163
+ When this decorator is applied to an object, the type checker
2164
+ will generate a diagnostic on usage of the deprecated object.
2165
+
2166
+ No runtime warning is issued. The decorator sets the ``__deprecated__``
2167
+ attribute on the decorated object to the deprecation message
2168
+ passed to the decorator. If applied to an overload, the decorator
2169
+ must be after the ``@overload`` decorator for the attribute to
2170
+ exist on the overload as returned by ``get_overloads()``.
2171
+
2172
+ See PEP 702 for details.
2173
+
2174
+ """
2175
+ def decorator (__arg : _T ) -> _T :
2176
+ if category is None :
2177
+ __arg .__deprecated__ = __msg
2178
+ return __arg
2179
+ elif isinstance (__arg , type ):
2180
+ original_new = __arg .__new__
2181
+ has_init = __arg .__init__ is not object .__init__
2182
+
2183
+ @functools .wraps (original_new )
2184
+ def __new__ (cls , * args , ** kwargs ):
2185
+ warnings .warn (__msg , category = category , stacklevel = stacklevel + 1 )
2186
+ # Mirrors a similar check in object.__new__.
2187
+ if not has_init and (args or kwargs ):
2188
+ raise TypeError (f"{ cls .__name__ } () takes no arguments" )
2189
+ if original_new is not object .__new__ :
2190
+ return original_new (cls , * args , ** kwargs )
2191
+ else :
2192
+ return original_new (cls )
2193
+
2194
+ __arg .__new__ = staticmethod (__new__ )
2195
+ __arg .__deprecated__ = __new__ .__deprecated__ = __msg
2196
+ return __arg
2197
+ elif callable (__arg ):
2198
+ @functools .wraps (__arg )
2199
+ def wrapper (* args , ** kwargs ):
2200
+ warnings .warn (__msg , category = category , stacklevel = stacklevel + 1 )
2201
+ return __arg (* args , ** kwargs )
2202
+
2203
+ __arg .__deprecated__ = wrapper .__deprecated__ = __msg
2204
+ return wrapper
2205
+ else :
2206
+ raise TypeError (
2207
+ "@deprecated decorator with non-None category must be applied to "
2208
+ f"a class or callable, not { __arg !r} "
2209
+ )
2210
+
2211
+ return decorator
2212
+
2213
+
2111
2214
# We have to do some monkey patching to deal with the dual nature of
2112
2215
# Unpack/TypeVarTuple:
2113
2216
# - We want Unpack to be a kind of TypeVar so it gets accepted in
0 commit comments