diff --git a/CHANGELOG.md b/CHANGELOG.md index 79e36891..92587752 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ # Unreleased +- Runtime support for PEP 702, adding `typing_extensions.deprecated`. Patch + by Jelle Zijlstra. - Add better default value for TypeVar `default` parameter, PEP 696. Enables runtime check if `None` was passed as default. Patch by Marc Mueller (@cdce8p). - The `@typing_extensions.override` decorator now sets the `.__override__` diff --git a/README.md b/README.md index 55314d46..15200c35 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,7 @@ This module currently contains the following: - `override` (see [PEP 698](https://peps.python.org/pep-0698/)) - The `default=` argument to `TypeVar`, `ParamSpec`, and `TypeVarTuple` (see [PEP 696](https://peps.python.org/pep-0696/)) - The `infer_variance=` argument to `TypeVar` (see [PEP 695](https://peps.python.org/pep-0695/)) + - The `@deprecated` decorator (see [PEP 702](https://peps.python.org/pep-0698/)) - In `typing` since Python 3.11 diff --git a/src/test_typing_extensions.py b/src/test_typing_extensions.py index 913b4901..79c0274d 100644 --- a/src/test_typing_extensions.py +++ b/src/test_typing_extensions.py @@ -29,7 +29,7 @@ from typing_extensions import assert_type, get_type_hints, get_origin, get_args from typing_extensions import clear_overloads, get_overloads, overload from typing_extensions import NamedTuple -from typing_extensions import override +from typing_extensions import override, deprecated from _typed_dict_test_helper import Foo, FooGeneric # Flags used to mark tests that only apply after a specific @@ -202,6 +202,35 @@ def static_method_bad_order(): self.assertIs(False, hasattr(Derived.static_method_bad_order, "__override__")) +class DeprecatedTests(BaseTestCase): + def test_deprecated(self): + @deprecated("A will go away soon") + class A: + pass + + self.assertEqual(A.__deprecated__, "A will go away soon") + self.assertIsInstance(A, type) + + @deprecated("b will go away soon") + def b(): + pass + + self.assertEqual(b.__deprecated__, "b will go away soon") + self.assertIsInstance(b, types.FunctionType) + + @overload + @deprecated("no more ints") + def h(x: int) -> int: ... + @overload + def h(x: str) -> str: ... + def h(x): + return x + + overloads = get_overloads(h) + self.assertEqual(len(overloads), 2) + self.assertEqual(overloads[0].__deprecated__, "no more ints") + + class AnyTests(BaseTestCase): def test_can_subclass(self): class Mock(Any): pass diff --git a/src/typing_extensions.py b/src/typing_extensions.py index 37efdd09..c32c63d1 100644 --- a/src/typing_extensions.py +++ b/src/typing_extensions.py @@ -52,6 +52,7 @@ 'assert_type', 'clear_overloads', 'dataclass_transform', + 'deprecated', 'get_overloads', 'final', 'get_args', @@ -2129,6 +2130,49 @@ def method(self) -> None: return __arg +if hasattr(typing, "deprecated"): + deprecated = typing.deprecated +else: + _T = typing.TypeVar("_T") + + def deprecated(__msg: str) -> typing.Callable[[_T], _T]: + """Indicate that a class, function or overload is deprecated. + + Usage: + + @deprecated("Use B instead") + class A: + pass + + @deprecated("Use g instead") + def f(): + pass + + @overload + @deprecated("int support is deprecated") + def g(x: int) -> int: ... + @overload + def g(x: str) -> int: ... + + When this decorator is applied to an object, the type checker + will generate a diagnostic on usage of the deprecated object. + + No runtime warning is issued. The decorator sets the ``__deprecated__`` + attribute on the decorated object to the deprecation message + passed to the decorator. If applied to an overload, the decorator + must be after the ``@overload`` decorator for the attribute to + exist on the overload as returned by ``get_overloads()``. + + See PEP 702 for details. + + """ + def decorator(__arg: _T) -> _T: + __arg.__deprecated__ = __msg + return __arg + + return decorator + + # We have to do some monkey patching to deal with the dual nature of # Unpack/TypeVarTuple: # - We want Unpack to be a kind of TypeVar so it gets accepted in
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: