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.

Easy Python 3.9+ Aug 9, 2026 Errors & debugging 15 views 0 copies

Python code

40 lines
Python 3.9+
import 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

stdout
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

  1. Use warnings.warn(..., FutureWarning) for changes that will become errors in a future release
  2. 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

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from Errors & debugging

Related tutorials and quizzes for this topic.