@@ -2292,15 +2292,12 @@ def method(self) -> None:
2292
2292
else :
2293
2293
_T = typing .TypeVar ("_T" )
2294
2294
2295
- def deprecated (
2296
- msg : str ,
2297
- / ,
2298
- * ,
2299
- category : typing .Optional [typing .Type [Warning ]] = DeprecationWarning ,
2300
- stacklevel : int = 1 ,
2301
- ) -> typing .Callable [[_T ], _T ]:
2295
+ class deprecated :
2302
2296
"""Indicate that a class, function or overload is deprecated.
2303
2297
2298
+ When this decorator is applied to an object, the type checker
2299
+ will generate a diagnostic on usage of the deprecated object.
2300
+
2304
2301
Usage:
2305
2302
2306
2303
@deprecated("Use B instead")
@@ -2317,36 +2314,56 @@ def g(x: int) -> int: ...
2317
2314
@overload
2318
2315
def g(x: str) -> int: ...
2319
2316
2320
- When this decorator is applied to an object, the type checker
2321
- will generate a diagnostic on usage of the deprecated object.
2322
-
2323
- The warning specified by ``category`` will be emitted on use
2324
- of deprecated objects. For functions, that happens on calls;
2325
- for classes, on instantiation. If the ``category`` is ``None``,
2326
- no warning is emitted. The ``stacklevel`` determines where the
2317
+ The warning specified by *category* will be emitted at runtime
2318
+ on use of deprecated objects. For functions, that happens on calls;
2319
+ for classes, on instantiation and on creation of subclasses.
2320
+ If the *category* is ``None``, no warning is emitted at runtime.
2321
+ The *stacklevel* determines where the
2327
2322
warning is emitted. If it is ``1`` (the default), the warning
2328
2323
is emitted at the direct caller of the deprecated object; if it
2329
2324
is higher, it is emitted further up the stack.
2325
+ Static type checker behavior is not affected by the *category*
2326
+ and *stacklevel* arguments.
2330
2327
2331
- The decorator sets the ``__deprecated__``
2332
- attribute on the decorated object to the deprecation message
2333
- passed to the decorator. If applied to an overload, the decorator
2328
+ The deprecation message passed to the decorator is saved in the
2329
+ ``__deprecated__`` attribute on the decorated object.
2330
+ If applied to an overload, the decorator
2334
2331
must be after the ``@overload`` decorator for the attribute to
2335
2332
exist on the overload as returned by ``get_overloads()``.
2336
2333
2337
2334
See PEP 702 for details.
2338
2335
2339
2336
"""
2340
- if not isinstance (msg , str ):
2341
- raise TypeError (
2342
- f"Expected an object of type str for 'msg', not { type (msg ).__name__ !r} "
2343
- )
2344
-
2345
- def decorator (arg : _T , / ) -> _T :
2337
+ def __init__ (
2338
+ self ,
2339
+ message : str ,
2340
+ / ,
2341
+ * ,
2342
+ category : typing .Optional [typing .Type [Warning ]] = DeprecationWarning ,
2343
+ stacklevel : int = 1 ,
2344
+ ) -> None :
2345
+ if not isinstance (message , str ):
2346
+ raise TypeError (
2347
+ "Expected an object of type str for 'message', not "
2348
+ f"{ type (message ).__name__ !r} "
2349
+ )
2350
+ self .message = message
2351
+ self .category = category
2352
+ self .stacklevel = stacklevel
2353
+
2354
+ def __call__ (self , arg : _T , / ) -> _T :
2355
+ # Make sure the inner functions created below don't
2356
+ # retain a reference to self.
2357
+ msg = self .message
2358
+ category = self .category
2359
+ stacklevel = self .stacklevel
2346
2360
if category is None :
2347
2361
arg .__deprecated__ = msg
2348
2362
return arg
2349
2363
elif isinstance (arg , type ):
2364
+ import functools
2365
+ from types import MethodType
2366
+
2350
2367
original_new = arg .__new__
2351
2368
2352
2369
@functools .wraps (original_new )
@@ -2366,7 +2383,7 @@ def __new__(cls, *args, **kwargs):
2366
2383
original_init_subclass = arg .__init_subclass__
2367
2384
# We need slightly different behavior if __init_subclass__
2368
2385
# is a bound method (likely if it was implemented in Python)
2369
- if isinstance (original_init_subclass , _types . MethodType ):
2386
+ if isinstance (original_init_subclass , MethodType ):
2370
2387
original_init_subclass = original_init_subclass .__func__
2371
2388
2372
2389
@functools .wraps (original_init_subclass )
@@ -2389,6 +2406,8 @@ def __init_subclass__(*args, **kwargs):
2389
2406
__init_subclass__ .__deprecated__ = msg
2390
2407
return arg
2391
2408
elif callable (arg ):
2409
+ import functools
2410
+
2392
2411
@functools .wraps (arg )
2393
2412
def wrapper (* args , ** kwargs ):
2394
2413
warnings .warn (msg , category = category , stacklevel = stacklevel + 1 )
@@ -2402,8 +2421,6 @@ def wrapper(*args, **kwargs):
2402
2421
f"a class or callable, not { arg !r} "
2403
2422
)
2404
2423
2405
- return decorator
2406
-
2407
2424
2408
2425
# We have to do some monkey patching to deal with the dual nature of
2409
2426
# Unpack/TypeVarTuple:
0 commit comments