How to Emit Deprecation Warnings in Python
Use the warnings module to mark legacy classes and methods as deprecated, letting users know to switch to newer APIs.
Python code
40 linesimport warnings
class OldAPI:
def __init__(self):
warnings.warn(
"OldAPI is deprecated; use NewAPI instead.",
DeprecationWarning,
stacklevel=2,
)
self.data = []
def add(self, item):
warnings.warn(
"OldAPI.add() is deprecated; use NewAPI.append() instead.",
DeprecationWarning,
stacklevel=2,
)
self.data.append(item)
class NewAPI:
def __init__(self):
self.data = []
def append(self, item):
self.data.append(item)
if __name__ == "__main__":
with warnings.catch_warnings(record=True) as caught:
warnings.simplefilter("always")
old = OldAPI()
old.add("item1")
for warning in caught:
print(f"Warning: {warning.message}")
new = NewAPI()
new.append("item1")
print("NewAPI data:", new.data)
Output
Warning: OldAPI is deprecated; use NewAPI instead.
Warning: OldAPI.add() is deprecated; use NewAPI.append() instead.
NewAPI data: ['item1']
How it works
The warnings.warn call raises a DeprecationWarning without stopping execution, so the old API still works for backward compatibility. The stacklevel=2 argument points the warning at the caller's line, not the line inside the library. Using catch_warnings with simplefilter("always") ensures all warnings are captured in tests or demos, even if the default filter would suppress them. Filtering by warning category lets library users silence or escalate deprecation messages as needed.
Common mistakes
- Forgetting stacklevel=2, so the warning points inside your library instead of at the user's code
- Using print() instead of warnings.warn, which bypasses Python's warning filter system
- Wrapping warn calls in try/except, which is unnecessary because warnings don't raise exceptions
- Calling deprecation warnings on every access instead of only in the constructor or slow paths
Variations
- Use warnings.warn(..., FutureWarning) for changes that will become errors in a future release
- Decorate a function with @warnings.deprecated from the deprecated third-party package for a simpler syntax
Real-world use cases
- Marking outdated library functions as deprecated so users migrate to newer signatures without breaking existing code.
- Notifying internal teams about upcoming breaking changes in shared utility functions during a codebase transition.
- Flagging legacy database model methods in a Django app that will be removed in the next major version.
Sponsored
More from Errors & debugging
- Catch RecursionError and Fail Gracefully in Python easy
- Catch ValueError and print friendly message in Python easy
- Collect Multiple Validation Errors in Python Before Raising medium
- Handle ValueError and ZeroDivisionError in Python with try except easy
- How to Add a Correlation ID to Logging Records in Python medium
- How to Assert Preconditions with Descriptive Messages in Python easy
Keep learning
Related tutorials and quizzes for this topic.