Warnings & Deprecations
The warnings module signals recoverable issues and API deprecations without raising exceptions. Configure filters to show, ignore, or escalate warnings - libraries use DeprecationWarning for scheduled removals.
Recipe
import warnings
warnings.warn("old_api is deprecated; use new_api", DeprecationWarning, stacklevel=2)When to reach for this:
- Deprecating functions/classes before removal
- Runtime notices about suboptimal usage (not errors)
- Library maintainers warn without breaking callers immediately
- CI
-W errorturns warnings into test failures - Distinguish user code (
UserWarning) from internal (DeprecationWarning)
Working Example
import warnings
warnings.simplefilter("default", DeprecationWarning)
def old_price(amount: float) -> float:
warnings.warn(
"old_price deprecated; use compute_price",
DeprecationWarning,
stacklevel=2,
)
return amount * 1.1
def compute_price(amount: float) -> float:
return amount * 1.1
warnings.filterwarnings("once", category=UserWarning, module=__name__)
def maybe_risky(flag: bool) -> None:
if flag:
warnings.warn("experimental path enabled", UserWarning, stacklevel=2)
old_price(10)
maybe_risky(True)
maybe_risky(True) # once filter suppresses duplicateWhat this demonstrates:
stacklevel=2points warning at caller, not wrapperDeprecationWarningcategory for API sunsetfilterwarnings("once")avoids log spam- Filters scoped by category and module
Deep Dive
How It Works
warnings.warn(message, category, stacklevel)emitsWarningMessage- Default: show each warning once per location to stderr
warnings.filterwarnings(action, category, ...)controls behaviorpytest.warnsasserts warnings in tests@warnings.deprecateddecorator (3.13+) for functions
Common Categories
| Category | Audience |
|---|---|
DeprecationWarning | Developers (hidden from users by default) |
UserWarning | End users of API |
PendingDeprecationWarning | Early notice |
Gotchas
- Wrong stacklevel - warning blames library line. Fix: increment stacklevel for each wrapper layer.
- DeprecationWarning invisible in REPL - default filters hide from non-main. Fix: document
warnings.simplefilterfor app entry or run tests with-W default::DeprecationWarning. - Using warnings for control flow - not exceptions, easy to miss. Fix: warnings for deprecations only, not business logic.
- Breaking CI without policy -
-W errorfails on any warning. Fix: treat deprecations as errors, allowlist third-party noise temporarily. - No removal timeline in message - users cannot plan. Fix: include version removal target in warn text.
Alternatives
| Alternative | Use When | Don't Use When |
|---|---|---|
| Raise exception | Hard breaking change now | Gradual migration needed |
| Logging only | Ops events | API contract deprecation |
Typing @deprecated | Static analysis hints | Runtime notice required |
FAQs
How do I test deprecations?
pytest.deprecated_call() or with warnings.catch_warnings(record=True).
Should deprecations be errors in CI?
Yes for your code - PYTHONWARNINGS=error::DeprecationWarning catches stragglers before removal.
What is warnings.deprecated?
Python 3.13+ decorator marking callables deprecated with consistent messaging.
How long to keep deprecated APIs?
Document policy (e.g., two minor releases) and log usage metrics if possible.
Do warnings go to logging?
logging.captureWarnings(True) routes warnings to logging subsystem.
How do I silence third-party warnings?
filterwarnings("ignore", module="noisy_lib") - narrow scope, add comment with issue link.
DeprecationWarning vs FutureWarning?
FutureWarning for end-user visible behavior changes; DeprecationWarning for developer APIs.
Can I warn from __init_subclass__?
Yes - warn when subclasses override removed hooks.
How does this relate to PEP 702?
PEP 702 formalizes @deprecated metadata for type checkers and runtime in 3.13+.
Should libraries configure filters?
Libraries warn; applications configure filters. Never simplefilter("ignore") globally in libraries.
Related
- The logging Module - captureWarnings integration
- Custom Exception Hierarchies - hard breaks vs soft warns
- Errors & Logging Best Practices - deprecation policy
- Raising & Chaining - when to raise instead
Stack versions: This page was written for Python 3.14.0 (stable 3.14, maintenance 3.13), FastAPI 0.115+, Django 5.2, Flask 3.1, Pydantic 2, PyTorch 2.6+, pandas 2.2+, Polars 1.x, ruff 0.9+, and uv 0.6+.