[Python-ideas] Deprecation utilities for the warnings module

Ilya Kulakov kulakov.ilya at gmail.com
Thu Sep 13 20:18:01 EDT 2018

(Apologies if it's a duplicate. I originally posted to python-ideas at googlegroups.com)

I've been recently working on an internal library written
entirely in Python. The library while being under development
was as actively used by other teams. The product was under
pressure and hasty design decisions were made.
Certain  interfaces were exposed before scope of the problem
was entirely clear.

Didn't take long before the code started to beg for refactoring.
But compatibility needed to be preserved. As a result a set of utilities,
which I'd like to share, came to life.


The warnings module is a robust foundation. Authors can warn
what should be avoided and users can choose how to act.
However in its current form it still requires utilities
to be useful. E.g. it's non-trivial to properly replace
a deprecated class.

I'd like to propose an extension for the warnings module
to address this problem.

The extensions consists of 4 decorators:
- @deprecated
- @obsolete
- @deprecated_arg
- @obsolete_arg

The @deprecated decorator marks an object to issue a warning
if it's used:
- Callable objects issue a warning upon a call
- Property attributes issue a warning upon an access
- Classes issue a warning upon instantiation and subclassing
  (directly or via a metaclass)

The @obsolete decorator marks an object in the same way
as @deprecated does but forwards usage to the replacement:
- Callable object redirect the call
- Property attribute redirect the access (get / set / del)
- Class is replaced in a way that during both instantiation
  and subclassing replacement is used

In case of classes extra care is taken to preserve validity
of existing isinstance and issubclass checks.

The @deprecated_arg and @obsolete_arg work with signatures
of callable objects. Upon a call either a warning is issued
or an argument mapping is performed.

Please take a look at the implementation and a few examples:

Why I think it should be a part of stdlib:
- Library authors are reluctant to add dependencies
  especially when it's for internal usage
- Ease of use will reduce compatibility problems
  and ease migration burden since the soltion will be
  readily available
- IDEs and static analyzers are more likely
  to support it


Joshua Harlow shared a link to OpenStack's debtcollector:
Certain aspects of my implementation are inspired by it.

Please let me know what you think about the idea in general
and implementation in particular. If that's something the community
is interested in, I'm willing to work on it.

More information about the Python-ideas mailing list