Getting Started¶
Quick Start (5 minutes)¶
Get up and running with deprecator quickly:
1. Install¶
2. Initialize¶
Run the initialization command in your project:
This creates _deprecations.py in your package:
3. Define Your First Deprecation¶
Add to _deprecations.py:
"""Basic deprecation example.
This example demonstrates the core deprecator workflow:
1. Get a deprecator for your package
2. Define a deprecation with version boundaries
3. Use it in your code
"""
from packaging.version import Version
from deprecator import for_package
# Get a deprecator for your package
# NOTE: In real code, just use: deprecator = for_package("mypackage")
# The _version parameter is only used here because "mypackage" isn't installed.
deprecator = for_package("mypackage", _version=Version("2.0.0"))
# Define a deprecation with version boundaries
OLD_API_DEPRECATION = deprecator.define(
"old_api is deprecated, use new_api instead",
warn_in="1.0.0", # Start warning at this version
gone_in="3.0.0", # Should be removed at this version
)
def old_api() -> str:
"""Deprecated API function."""
OLD_API_DEPRECATION.warn()
return new_api()
def new_api() -> str:
"""New API function that replaces old_api."""
return "new implementation"
4. Test It¶
"""Example tests for deprecations.
These tests demonstrate how to verify that:
1. Deprecated functions emit the correct warnings
2. New replacement functions don't emit warnings
"""
import pytest
from basic_deprecation import new_api, old_api
def test_deprecation_warning() -> None:
"""Test that deprecated functions emit warnings."""
with pytest.warns(DeprecationWarning, match="old_api is deprecated"):
result = old_api()
assert result == "new implementation"
def test_new_api_no_warning() -> None:
"""Test that new API doesn't emit warnings."""
import warnings
with warnings.catch_warnings():
warnings.simplefilter("error") # Turn warnings into errors
result = new_api() # Should not raise
assert result == "new implementation"
Detailed Installation Options¶
Basic Installation¶
Install deprecator using pip:
With CLI Support¶
To use the command-line tools, install with the CLI extra:
Development Installation¶
For development, clone the repository:
git clone https://github.com/RonnyPfannschmidt/deprecator.git
cd deprecator
# Use uv run for all development commands
Project Setup¶
Automatic Setup with CLI¶
The easiest way to set up deprecator in your project is using the CLI:
This command will:
1. Create a _deprecations.py module in your package
2. Configure your pyproject.toml with entry points
3. Set up the deprecator instance for your package
Manual Setup¶
If you prefer manual setup or need custom configuration:
- Create a deprecations module (
_deprecations.py):
"""Example of package-level deprecation setup.
This is how you'd typically set up deprecator in your package's
_deprecations.py file. All deprecations are defined in one place.
"""
from packaging.version import Version
from deprecator import for_package
# Create a deprecator instance for your package
# NOTE: In real code, just use: deprecator = for_package(__package__)
# The _version parameter is only used here because this isn't a real package.
deprecator = for_package(__package__ or "mypackage", _version=Version("1.8.0"))
# Define package-wide deprecations as module-level constants
OLD_FEATURE_DEPRECATION = deprecator.define(
"old_feature is deprecated, use new_feature instead",
warn_in="1.5.0",
gone_in="2.0.0",
)
PROCESS_DATA_DEPRECATION = deprecator.define(
"process_data() is deprecated, use transform_data() instead",
warn_in="1.5.0",
gone_in="2.0.0",
)
- Configure entry points in
pyproject.toml:
Basic Usage Patterns¶
Deprecating a Function¶
See the basic example from earlier, or use the decorator pattern:
"""Example of using deprecation decorators.
The @deprecation.apply decorator automatically emits the warning
when the decorated function or class is called.
"""
from package_setup import PROCESS_DATA_DEPRECATION
@PROCESS_DATA_DEPRECATION.apply
def process_data(data: str) -> str:
"""Old data processing function - deprecated."""
return transform_data(data)
def transform_data(data: str) -> str:
"""New data transformation function - use this instead."""
return data.upper()
Deprecating a Class¶
"""Example of deprecating a class.
Use @deprecation.apply on classes to warn when they are instantiated.
"""
from package_setup import OLD_FEATURE_DEPRECATION
@OLD_FEATURE_DEPRECATION.apply
class LegacyProcessor:
"""This class is deprecated - use ModernProcessor instead."""
def process(self, data: str) -> str:
return data.lower()
class ModernProcessor:
"""The modern replacement for LegacyProcessor."""
def process(self, data: str) -> str:
return data.lower()
Manual Warning Emission¶
"""Example of manual warning emission.
Use deprecation.warn() when you need conditional deprecation warnings,
such as warning only when specific parameters or code paths are used.
"""
from package_setup import OLD_FEATURE_DEPRECATION
def complex_deprecation(use_old_logic: bool = False) -> str:
"""Function with conditional deprecation.
Args:
use_old_logic: If True, uses deprecated code path and emits warning.
Returns:
Result from either old or new implementation.
"""
if use_old_logic:
# Only warn when the deprecated code path is actually used
OLD_FEATURE_DEPRECATION.warn()
return "old result"
return "new result"
Version Management¶
Deprecator automatically determines the warning type based on your package version:
| Current Version | warn_in | gone_in | Warning Type |
|---|---|---|---|
| 1.0.0 | 2.0.0 | 3.0.0 | PendingDeprecationWarning |
| 2.0.0 | 2.0.0 | 3.0.0 | DeprecationWarning |
| 3.0.0 | 2.0.0 | 3.0.0 | ExpiredDeprecationWarning |
Complete Example¶
Here's a complete example of deprecating an old function:
mypackage/_deprecations.py¶
"""Example of package-level deprecation setup.
This is how you'd typically set up deprecator in your package's
_deprecations.py file. All deprecations are defined in one place.
"""
from packaging.version import Version
from deprecator import for_package
# Create a deprecator instance for your package
# NOTE: In real code, just use: deprecator = for_package(__package__)
# The _version parameter is only used here because this isn't a real package.
deprecator = for_package(__package__ or "mypackage", _version=Version("1.8.0"))
# Define package-wide deprecations as module-level constants
OLD_FEATURE_DEPRECATION = deprecator.define(
"old_feature is deprecated, use new_feature instead",
warn_in="1.5.0",
gone_in="2.0.0",
)
PROCESS_DATA_DEPRECATION = deprecator.define(
"process_data() is deprecated, use transform_data() instead",
warn_in="1.5.0",
gone_in="2.0.0",
)
mypackage/api.py¶
"""Example of using deprecation decorators.
The @deprecation.apply decorator automatically emits the warning
when the decorated function or class is called.
"""
from package_setup import PROCESS_DATA_DEPRECATION
@PROCESS_DATA_DEPRECATION.apply
def process_data(data: str) -> str:
"""Old data processing function - deprecated."""
return transform_data(data)
def transform_data(data: str) -> str:
"""New data transformation function - use this instead."""
return data.upper()
tests/test_deprecations.py¶
"""Complete test example for deprecations.
A more comprehensive example showing how to test:
- Decorator-based deprecations
- The deprecation message content
- That new APIs remain warning-free
"""
import warnings
from decorator_usage import process_data, transform_data
def test_process_data_deprecated() -> None:
"""Test that process_data emits deprecation warning."""
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
result = process_data("hello")
# Check that we got exactly one warning
assert len(w) == 1
assert "deprecated" in str(w[0].message).lower()
assert result == "HELLO"
def test_transform_data_no_warning() -> None:
"""Test that transform_data doesn't emit warnings."""
with warnings.catch_warnings():
warnings.simplefilter("error")
result = transform_data("hello") # Should not raise
assert result == "HELLO"
Next Steps¶
- Check the Cookbook for more advanced patterns
- Learn about testing deprecations in detail
- Set up CI/CD integration
- Explore the full API Reference