Proposal: allow extending `warnings.deprecated`

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.deprecated at 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.deprecated in favor of a custom decorator is easy.

I therefore propose to slightly amend the spec:

  1. define warnings.deprecated to be a class (it already is in practice, but let’s make that official)
  2. 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
  3. 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.foo is deprecated: “Old and busted” (version: (1, 3), replacement: pkg.bar)

See also:

cc @Jelle

1 Like

This seems like a decent first step to make this feature a little bit more flexible, however, I would like to eventually see something even more flexible and generally useful akin to typing.dataclass_transform and also not necessarily limited to just deprecation warnings, but being designed for other kinds of statically detectable type errors and warnings as well, including completely custom ones.

I outlined some of my thoughts about this in a previous topic about a new SpecialForm: "Wrong" Special Form - #28 by Daverball

That is an idea. A general enough implementation also grants us the the @experimental decorator that was proposed not long ago