formerly renames a class that users inherit from, without breaking them.
Install with:
pip install formerly
Usage
Rename the class, and leave the old name behind as an alias:
from formerly import deprecated_class
class NewName(SomeClass): ...
OldName = deprecated_class("OldName", NewName)
Now:
Subclassing OldName warns, pointing at the class statement.
Instantiating OldName warns, but instantiating a subclass does not: the subclass author gets one warning where the problem is, not one per object.
issubclass() and isinstance() checks against OldName accept subclasses of NewName, so code that has already migrated keeps passing the checks of code that has not.
OldName is a real class: it pickles, survives copy.deepcopy(), passes inspect.isclass(), and can be registered with an abc.ABCMeta interface.
Type checkers reject a base class that comes from a variable, so users subclassing the alias need OldName: Any = ... on their side, or a per-statement ignore comment.
Warnings use DeprecationWarning and report the paths of the classes involved. Both are configurable, along with the messages themselves:
OldName = deprecated_class(
"OldName",
NewName,
category=MyLibraryDeprecationWarning,
new_path="mylibrary.NewName",
subclass_message="{cls} inherits from {old}, which is going away in 3.0.",
)
By default only the first subclass warns, since one warning is enough to tell users to migrate. Pass warn_once=False to warn on every subclass.
See the deprecated_class() docstring for the full signature.
Alternatives
Renaming a base class asks more of a deprecation helper than renaming a function does. Each row below is a behavior that a class users inherit from needs:
formerly |
|||||
|---|---|---|---|---|---|
Warns where the subclass is defined |
✔ |
✔ |
✘ |
✘ |
✘ |
Stays quiet when a subclass is instantiated |
✔ |
✔ |
✘ |
✘ |
✘ |
Warns when the old name is instantiated |
✔ |
✔ |
✔ |
✔ |
✔ |
Accepts migrated classes in issubclass() and isinstance() |
✔ |
✘ |
✘ |
✘ |
✔ |
Is a class: pickle, deepcopy, inspect.isclass(), abc |
✔ |
✔ |
✔ |
✔ |
✘ |
Reported by type checkers |
✘ |
✔ |
✘ |
✘ |
✘ |
Only the fourth row is unique to formerly: the old name keeps accepting classes that already inherit from the new one, so a library can rename a base class without breaking the isinstance() checks that its own code, or its users’ code, runs against the old name.
If nothing checks types against the old name, warnings.deprecated covers the rest, and adds what formerly cannot: type checkers report the deprecation before the code runs. It needs Python 3.13, or typing_extensions for older versions, which behaves identically.
Measured on Python 3.13 against Deprecated 1.3.1, debtcollector 3.1.0 and pyDeprecate 0.11.0. pyDeprecate wraps the class in a proxy object rather than a class, so subclassing it raises TypeError.
Release files for formerly 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| formerly-0.1.0.tar.gz | 8.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| formerly-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 14.2 kB
Release files / formerly-0.1.0.tar.gz
| Download URL | formerly-0.1.0.tar.gz |
|---|---|
| Size | 8.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e30ce1f317b3a05689aea057faa3bc4ec89a105ba5a48433ca9899ac1bf69a62
|
|
BLAKE2b-256 checksum How to use checksums |
7f7b7bab9bed04fb9f08e0e8c9081e5ca0068d40bb913260f09b28b643876528
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 5, 2026.
Transparency logRelease files / formerly-0.1.0-py3-none-any.whl
| Download URL | formerly-0.1.0-py3-none-any.whl |
|---|---|
| Size | 5.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
96dc14b85d8288eda824fa1f1521a1b070252fea9fb17d2bc7134c6661b7c556
|
|
BLAKE2b-256 checksum How to use checksums |
9c2199cb05c0928fce1bd1b22a873d7ac94847af789ca35a43e34e9c34ded0f4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 5, 2026.
Transparency log