Many projects have function/class deprecation decorators that add additional metadata other than just a deprecation message.
Unfortunately, it’s not really possible to get both that metadata and also warnings.deprecated’s type checker integration in one decorator invocation:
-
you can replace
warnings.deprecatedat runtime while making the type system it’s being used, but that requires a decorator that has a compatible signature.if TYPE_CHECKING: from warnings import deprecated else: class deprecated: ... # same `__init__` signature -
you can add a custom decorator to be applied in addition to it, but that is easy to forget and hard to enforce, whereas configuring a static checker to ban
warnings.deprecatedin favor of a custom decorator is easy.
I therefore propose to slightly amend the spec:
- define
warnings.deprecatedto be a class (it already is in practice, but let’s make that official) - explicitly allow sub-classing it: define that type checkers should mark as deprecated not only each item decorated with an instance of
deprecated, but alternatively also an instance of one of its sub-classes - define the first argument of a
deprecated/ sub-class instantiation as to be interpreted as deprecation message if it is a static string /LiteralString(type checkers are supposed to display this deprecation message, and this would define what “deprecation” message means in the context of subclasses. Maybe also specify that type checkers / language servers shouldn’t be limited to display only that deprecation message)
This way people can make sub-classes of deprecated, add more arguments to it, and still have static checks work.
I think it would be smart if language servers and type checkers just display the added keyword arguments after the deprecation message, e.g. using this function @my_deprecated("Old and busted", version=(1, 3), replacement="pkg.bar") def foo(...): ... would show something like
pkg.foois deprecated: “Old and busted” (version: (1, 3), replacement: pkg.bar)
See also:
- Original PEP discussion: PEP 702: Marking deprecations using the type system
- People with the same use case: Wrapping `warnings.deprecated`?
- Partially related: More deprecation decorators
cc @Jelle