| name | warnings-control |
| description | Handle python warnings properly by emitting them with warnings.warn, catching them in tests with catch_warnings, and translating them to errors if running in strict mode or via filterwarnings. |
Python Warnings Control
Use this skill when you need to raise a warning to the user (instead of logging or raising an exception), when testing code that emits warnings, or when implementing --strict modes where warnings should become errors.
Understanding Custom Warning Classes
When working on a library or a CLI tool, you should almost always define a custom base warning class (and potentially subclasses) instead of emitting a bare UserWarning.
Why?
- Targeted Filtering: If a user runs your tool in
--strict mode to catch configuration mistakes, you only want to turn your project's warnings into errors. If you use a global warnings.simplefilter('error'), any minor DeprecationWarning from a third-party dependency (like httpx or tomlkit) will crash your application.
- User Experience: Users can easily choose to ignore only your project's warnings if they want to.
class ProjectWarning(UserWarning):
"""Base category for warnings related to this project."""
pass
class ConfigWarning(ProjectWarning):
"""Category for configuration-related warnings."""
pass
Quick Start: Emitting Warnings
To emit a warning to the user, use warnings.warn targeting your custom class:
import warnings
from my_project.exceptions import ConfigWarning
warnings.warn(
"Some configuration option is obsolete.",
category=ConfigWarning,
stacklevel=2,
)
Quick Start: Promoting Project Warnings to Errors (Strict Mode)
When implementing a --strict mode, use warnings.filterwarnings to target only your custom base class, rather than warnings.simplefilter.
import warnings
from my_project.exceptions import ProjectWarning
def enable_strict_mode():
"""Convert only this project's warnings into exceptions."""
warnings.filterwarnings("error", category=ProjectWarning)
A Warning on PYTHONWARNINGS
Do NOT use PYTHONWARNINGS to filter custom project warning classes.
Since Python parses PYTHONWARNINGS flags before user code is imported, trying to set PYTHONWARNINGS="error::my_project.exceptions.ProjectWarning" will fail with Invalid -W option ignored: unknown warning category.
Additionally, the module field in PYTHONWARNINGS matches exact literal module paths only (not regex). error:::my_project will not match warnings emitted from my_project.core.
If you need to enforce strict warnings in a subprocess, use an application-specific environment variable that configures warnings.filterwarnings directly in the child process's initialization:
import os
import subprocess
env = os.environ.copy()
env["MY_PROJECT_STRICT"] = "1"
subprocess.run(["sys_command"], env=env)
Quick Start: Testing Warnings
When testing code that raises warnings, wrap the operation in warnings.catch_warnings(record=True).
import warnings
def test_deprecated_feature():
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
my_function_that_warns()
assert len(w) == 1
assert issubclass(w[-1].category, UserWarning)
assert "deprecated" in str(w[-1].message)
Gotchas & Rules
- Do NOT raise standard exceptions (like
ValueError or RuntimeError) for non-fatal issues. If the user's config is slightly odd but still functionally valid, use warnings.warn().
- Always use
stacklevel=2 or higher so the printed warning references the caller's code rather than internal library logic.
- Do NOT globally suppress warnings (e.g.,
warnings.simplefilter("ignore")) in library functions, because users may be relying on them.