Skip to content

API Reference🔗

Auto-generated from source docstrings. For usage examples see the User Guide.

Decorator🔗

deprecate.deprecation.deprecated(target=TargetMode.AUTO, deprecated_in='', remove_in='', stream=deprecation_warning, num_warns=1, message_template=None, args_mapping=None, args_extra=None, skip_if=False, update_docstring=False, docstring_style='auto', template_mgs=None) 🔗

Deprecate a function, method, or class — the friendly front door.

For a callable source (function, method, lambda, or descriptor) this forwards to the strict :func:deprecated_callable implementation: identical call forwarding, argument mapping, warning control, and __deprecated__ metadata. For a class source it delegates to :func:~deprecate.proxy.deprecated_class, emitting a UserWarning (suppressed when stream=None); prefer @deprecated_class() directly for classes.

deprecated() deliberately exposes only the arguments common to both shapes. The one shape-specific option, attrs_mapping (selective attribute deprecation, class-only), lives on :func:~deprecate.proxy.deprecated_class — reach for it directly when you need the full class scope.

Parameters:

Name Type Description Default
target Union[bool, None, Callable, TargetMode, staticmethod, classmethod]

How to handle the deprecation. Defaults to :attr:~deprecate.TargetMode.AUTO, a decoration-time inference value that is resolved before metadata is stored. Pass an explicit value to forward calls or select a fixed mode:

  • Callable: Forward all calls to this callable (function, method, or class). The decorated source's body is not executed under normal forwarding — use pass or ... as the body.
  • :attr:~deprecate.TargetMode.ARGS_REMAP (or legacy True): Self-deprecation — deprecate argument names only, remapping them within the same function body (callable source) or constructor (class source).
  • :attr:~deprecate.TargetMode.NOTIFY: Warning-only mode — no forwarding. The source body executes unchanged for a callable; a class proxy emits class-wide warnings. An explicitly selected NOTIFY is never rewritten: combining it with args_mapping is a misconfiguration, leaves the mapping inert, and emits :class:UserWarning.
  • :attr:~deprecate.TargetMode.AUTO (default): Infer the mode only when target is omitted. args_mapping resolves to :attr:~deprecate.TargetMode.ARGS_REMAP; no mapping resolves to warning-only behavior. The resolved value, never AUTO, is stored in :class:~deprecate.DeprecationConfig.

Passing target=None is a legacy warn-only synonym that emits :class:FutureWarning directing callers to use :attr:~deprecate.TargetMode.NOTIFY.

AUTO
deprecated_in str

Version when the source was deprecated (e.g., "1.0.0"). Default is empty string.

''
remove_in str

Version when the source will be removed (e.g., "2.0.0"). Default is empty string.

''
stream Optional[Callable]

Function to output warnings (default: :func:~deprecate.deprecation.deprecation_warning, which is :func:warnings.warn with FutureWarning category). Set to None to disable warnings entirely — this also silences the one-time class-dispatch notice described under Warns below.

deprecation_warning
num_warns int

Number of times to show the warning, per callable/attribute name or per proxy access: - 1 (default): Show warning once - -1: Show warning on every call/access - 0: Suppress deprecation warnings - N > 1: Show warning N times total

1
message_template Optional[str]

Custom warning message template with format specifiers (source_name, source_path, target_name, target_path, deprecated_in, remove_in, argument_map); see :func:deprecated_callable for the full specifier reference.

None
args_mapping Optional[dict[str, Optional[str]]]

Map or skip arguments when forwarding — {"old_arg": "new_arg"} renames, {"old_arg": None} drops. When target is omitted, a mapping auto-resolves a callable or class source to :attr:~deprecate.TargetMode.ARGS_REMAP. An explicit :attr:~deprecate.TargetMode.NOTIFY leaves the mapping inert and emits :class:UserWarning.

None
args_extra Optional[dict[str, Any]]

Additional keyword arguments merged into the forwarded call after args_mapping is applied. Ignored under :attr:~deprecate.TargetMode.NOTIFY.

None
skip_if Union[bool, Callable]

Conditionally deactivate the deprecation machinery — a bool, or a zero-argument Callable returning bool. When it evaluates True, a callable source executes its body with no warning and no forwarding; a class source is served as-is by the proxy with no warning, no mapping, and no target forwarding.

False
update_docstring bool

If True, inject a deprecation notice into the docstring — function or class — at decoration time.

False
docstring_style Literal['auto', 'rst', 'mkdocs', 'markdown']

Output style for the injected notice when update_docstring=True"auto" (default, chosen from the active doc engine), "rst", or "mkdocs" / "markdown".

'auto'
template_mgs Optional[str]

Deprecated alias for message_template (renamed in v0.12; the old spelling was a typo). Supplying it emits a :class:FutureWarning and its value is used as message_template; supplying both raises :class:TypeError. Removed in v1.0.

None

Returns:

Type Description
Callable[[Callable[..., Any]], Callable[..., Any]]

Decorator that wraps the source callable, or the class proxy for a class source.

Warns:

Type Description
UserWarning

If applied directly to a class. The decorator delegates to :func:~deprecate.proxy.deprecated_class and emits this informational notice once per class qualname per process. Use @deprecated_class() directly to skip it entirely. Suppressed when stream=None.

UserWarning

If deprecated_in is absent, stream is not None, no message_template is set, and the decorated source is not a class. Fired at decoration time (not call time) to catch missing version metadata early. Suppressed by passing stream=None or message_template.

Example

Basic forwarding🔗

def new_func(x: int) -> int: ... return x * 2 @deprecated(target=new_func, deprecated_in="1.0", remove_in="2.0") ... def old_func(x: int) -> int: ... pass

Warn-only (default — no target needed)🔗

@deprecated(deprecated_in="1.0", remove_in="2.0") ... def legacy_func(x: int) -> int: ... return x

deprecate.routine.deprecated_callable(target=TargetMode.NOTIFY, deprecated_in='', remove_in='', stream=deprecation_warning, num_warns=1, message_template=None, args_mapping=None, args_extra=None, skip_if=False, update_docstring=False, docstring_style='auto', template_mgs=None) 🔗

Decorate a function/method with warning message and forward calls to target — the strict callable form.

This is the canonical callable-only implementation. It behaves like :func:deprecated for functions, methods, lambdas, and descriptors (classmethod / staticmethod / property): same call forwarding, argument mapping, warning control, and __deprecated__ metadata. It differs in one way: applying it to a class raises :class:TypeError at decoration time instead of delegating to :func:~deprecate.proxy.deprecated_class. :func:deprecated is the friendly front door that dispatches classes for you and routes callables here; reach for deprecated_callable at a call site that must never silently accept a class.

This decorator marks a function or method as deprecated and can automatically forward all calls to a replacement implementation. It supports argument mapping, custom warning messages, and flexible warning control.

For generator functions (def gen(): yield) and async generator functions (async def gen(): yield), the deprecation warning fires at call time — when the (async) generator object is created — not at first iteration. The generator body executes lazily as normal when iterated (next() / async for).

Parameters:

Name Type Description Default
target Union[bool, None, Callable, TargetMode, staticmethod, classmethod]

How to handle the deprecation. Defaults to :attr:~deprecate.TargetMode.NOTIFY (warn-only; source body executes unchanged) — the strict form always uses an explicit mode and rejects :attr:~deprecate.TargetMode.AUTO (front-door-only inference) with :class:TypeError. Pass an explicit value to forward calls or remap arguments:

  • Callable: Forward all calls to this callable (function, method, or class target). The decorated function's body is not executed under normal forwarding — use pass or ... as the body. Exception: when skip_if evaluates True at call time, the source body executes as a fallback, so keep a working implementation if you combine target=Callable with skip_if.
  • :attr:~deprecate.TargetMode.ARGS_REMAP (or legacy True): Self-deprecation — deprecate argument names only, remapping them within the same function body
  • :attr:~deprecate.TargetMode.NOTIFY (default): Warning-only mode — no forwarding, source body executes normally. Combining it with args_mapping is contradictory: the mapping is ignored and a :class:UserWarning fires (:class:TypeError in v1.0).

Passing target=None is a legacy synonym that also resolves to :attr:~deprecate.TargetMode.NOTIFY but emits a :class:FutureWarning directing you to use the enum form.

NOTIFY
deprecated_in str

Version when the function was deprecated (e.g., "1.0.0"). Default is empty string.

''
remove_in str

Version when the function will be removed (e.g., "2.0.0"). Default is empty string.

''
stream Optional[Callable]

Function to output warnings (default: :func:~deprecate.deprecation.deprecation_warning, which is :func:warnings.warn with FutureWarning category). Set to None to disable warnings entirely.

deprecation_warning
num_warns int

Number of times to show warning per function or per deprecated argument: - 1 (default): Show warning once per function/argument - -1: Show warning on every call - 0: Suppress deprecation warnings emitted for the decorated function/argument - N > 1: Show warning N times total

1
message_template Optional[str]

Custom warning message template with format specifiers: - source_name: Function name (e.g., "my_func") - source_path: Full path (e.g., "module.my_func") - target_name: Target function name (only for callable targets) - target_path: Full target path (only for callable targets) - deprecated_in: Value of deprecated_in parameter - remove_in: Value of remove_in parameter - argument_map: String showing argument mapping (for args deprecation only) Example: "v%(deprecated_in)s: `%(source_name)s` was deprecated."

None
args_mapping Optional[dict[str, Optional[str]]]

Map or skip arguments when forwarding: - {'old_arg': 'new_arg'}: Rename argument - {'old_arg': None}: Skip argument (don't forward it) - {}: Empty mapping (no remapping) Works with both target=Callable and target=True.

None
args_extra Optional[dict[str, Any]]

Additional arguments merged into kwargs before the call. Used when target is a Callable or :attr:~deprecate._types.TargetMode.ARGS_REMAP (with args_mapping). Ignored when target is :attr:~deprecate._types.TargetMode.NOTIFY. Example: {'new_required_arg': 42}

None
skip_if Union[bool, Callable]

Conditionally skip deprecation warning and forwarding: - bool: Static condition (True = skip deprecation) - Callable: Function returning bool (checked at runtime, must return bool) If condition is True, original function executes without warning.

False
update_docstring bool

If True, automatically inject a deprecation notice into the function's docstring (inserted before Google/NumPy-style sections when present, otherwise appended at the end).

False
docstring_style Literal['auto', 'rst', 'mkdocs', 'markdown']

Output style for injected deprecation notice when update_docstring=True. Supported values: - "auto" (default): Automatically choose a style based on the current environment (e.g., loaded modules, CLI/tooling context). This may resolve to either "rst" or "mkdocs"/"markdown" at decoration time. - "rst": Explicitly force Sphinx-style .. deprecated:: directive. - "mkdocs" or "markdown": Explicitly force a Markdown admonition of the form !!! warning "Deprecated in X". Validated eagerly at decoration time regardless of update_docstring.

'auto'
template_mgs Optional[str]

Deprecated alias for message_template (renamed in v0.12; the old spelling was a typo). Supplying it emits a :class:FutureWarning and its value is used as message_template; supplying both raises :class:TypeError. Removed in v1.0.

None

Returns:

Type Description
Callable[[Callable[..., Any]], Callable[..., Any]]

Decorator function that wraps the source function/method.

Warns:

Type Description
UserWarning

If deprecated_in is absent, stream is not None, and no message_template is set. Fired at decoration time (not call time) to catch missing version metadata early. Suppressed by passing stream=None or message_template.

Raises:

Type Description
TypeError

If applied to a class. The strict form rejects a class source at decoration time (naming deprecated_class and deprecated as the alternatives) instead of delegating to :func:~deprecate.proxy.deprecated_class.

TypeError

If the source is a class method and target is a method on a different class (cross-class method forwarding detected at decoration time via __qualname__ comparison). Skipped silently when the target's qualname prefix names a class absent from the target's module globals.

TypeError

If skip_if is a callable that doesn't return a bool.

TypeError

If arguments in args_mapping don't exist in target function and target doesn't accept **kwargs.

Example

Basic forwarding🔗

def new_func(x: int) -> int: ... return x * 2 @deprecated_callable(target=new_func, deprecated_in="1.0", remove_in="2.0") ... def old_func(x: int) -> int: ... pass

Argument mapping🔗

@deprecated_callable( ... target=new_func, ... args_mapping={'old_name': 'new_name', 'unused': None} ... ) ... def old_func(old_name: int, unused: str) -> int: ... pass

Self-deprecation🔗

from deprecate import TargetMode @deprecated_callable(target=TargetMode.ARGS_REMAP, args_mapping={'old_arg': 'new_arg'}) ... def my_func(old_arg: int = 0, new_arg: int = 0) -> int: ... return new_arg * 2

Warn-only (default — no target needed)🔗

@deprecated_callable(deprecated_in="1.0", remove_in="2.0") ... def legacy_func(x: int) -> int: ... return x

A class source is rejected up front (use deprecated_class or deprecated instead)🔗

@deprecated_callable(deprecated_in="1.0", remove_in="2.0") # doctest: +IGNORE_EXCEPTION_DETAIL ... class OldClass: ... pass Traceback (most recent call last): TypeError: @deprecated_callable cannot decorate class OldClass ...

Proxy🔗

deprecate.proxy.deprecated_class(target=None, *, deprecated_in='', remove_in='', num_warns=1, stream=deprecation_warning, message_template=None, args_mapping=None, args_extra=None, attrs_mapping=None, skip_if=False, update_docstring=False, docstring_style='auto', template_mgs=None, _misconfigured_override=False, _stacklevel_extra=0) 🔗

Decorator factory for deprecating class definitions with optional target redirection.

Apply @deprecated_class(...) to an Enum or dataclass to wrap the class in a :class:~deprecate.proxy._DeprecatedProxy. All attribute, item, and call access on the resulting object will emit a deprecation warning and, if target is provided, will be forwarded to the replacement class.

Parameters:

Name Type Description Default
target Any

Optional replacement class to redirect all access to.

None
deprecated_in str

Version string when the class was deprecated.

''
remove_in str

Version string when the class will be removed.

''
num_warns int

Maximum number of warnings to emit per proxy instance. 1 warns once; -1 warns on every access.

1
stream Optional[Callable[..., None]]

Callable used to emit warnings. Defaults to :data:~deprecate.deprecation.deprecation_warning.

deprecation_warning
message_template Optional[str]

Optional custom warning message template that overrides the built-in templates. When None (default), the built-in template for the active scenario is used (callable-target, no-target, or per-argument for args_mapping). Available %-style placeholders:

  • %(source_name)s — the deprecated class name (taken from cls.__name__)
  • %(deprecated_in)s — value of the deprecated_in argument
  • %(remove_in)s — value of the remove_in argument
  • %(target_name)s — target class name (only when target is callable)
  • %(target_path)s — fully-qualified target path (only when target is callable)
  • %(argument_map)s — formatted \`old\` -> \`new\``` string (only for per-argument warnings emitted byargs_mapping``)

Example: "v%(deprecated_in)s:%(source_name)s->%(target_name)s".

None
args_mapping Optional[dict[str, Optional[str]]]

Optional dict remapping keyword argument names when the decorated class is called. Keys are old argument names; values are new names, or None to drop the argument entirely. When provided without an explicit callable target, the mode auto-resolves to :attr:~deprecate._types.TargetMode.ARGS_REMAP: the proxy warns only when an old argument name is actually used in the call, matching the per-argument warning behaviour of @deprecated(target=TargetMode.ARGS_REMAP, args_mapping=...). Passing args_mapping with no explicit target (the default) auto-resolves to ARGS_REMAP; an explicit target=TargetMode.NOTIFY combined with args_mapping is contradictory — the mapping is ignored and a :class:UserWarning fires (:class:TypeError in v1.0). target=TargetMode.ARGS_REMAP without args_mapping still emits a :class:UserWarning at decoration time (will be :class:TypeError in v1.0).

None
args_extra Optional[dict[str, Any]]

Optional dict of extra keyword arguments merged into the forwarded call after args_mapping has been applied. args_extra values win over any caller-supplied value with the same key (i.e. args_extra > explicit new-name kwarg > remapped old-name value > source defaults). Ignored when target is :attr:~deprecate._types.TargetMode.NOTIFY (passing both emits a :class:UserWarning at decoration time; will be :class:TypeError in v1.0).

None
attrs_mapping Optional[dict[str, Optional[str]]]

Optional dict mapping deprecated attribute names to canonical names (or None for warn-only). When set, only the listed attribute names emit a deprecation warning on access; all other attributes are forwarded silently. The redirect applies to reads (__getattr__), writes (__setattr__), and deletes (__delattr__). Every non-None value must be an existing attribute on the target class when target is provided, or on the wrapped source class otherwise. None values keep the same attribute name but still resolve against the active class, so with target=SomeClass a warn-only mapping such as {"size": None} reads, writes, and deletes SomeClass.size. Redirect chains such as {"a": "b", "b": "c"} are allowed at decoration time and reported by audit as :attr:~deprecate.audit.ChainType.STACKED. Cycles such as {"a": "b", "b": "a"} raise :class:ValueError at decoration time.

Example: attrs_mapping={"color": "colour", "txt": "text"} warns on proxy.color access and returns proxy.colour; proxy.colour is forwarded silently.

When attrs_mapping is None (default), the existing behaviour is preserved: a warning is emitted on every attribute access through the proxy.

Callable target interaction: when target=SomeClass is also provided, listed attribute aliases resolve against SomeClass. A None mapping keeps the original attribute name on SomeClass. Unlisted attributes and calls continue to use the normal target-forwarding behaviour.

Validation limitation: attribute existence is checked using :func:inspect.getattr_static, which detects class-level attributes and __slots__ entries but not instance-only attributes set in __init__ via self.x = .... For dataclass targets without defaults, the field name appears in __dataclass_fields__ but the attribute itself is instance-only — decoration-time validation will raise :class:ValueError even though access would succeed at runtime. As a workaround, add a class-level default or use a None (warn-only) entry.

The mode can also be set explicitly as target=TargetMode.ATTRS_REMAP — both forms are equivalent; the explicit form is self-documenting and enables validation at decoration time. Passing target=TargetMode.ATTRS_REMAP without attrs_mapping, or passing an empty attrs_mapping={}, emits a :class:UserWarning at decoration time (will be :class:TypeError in v1.0). Passing attrs_mapping with no explicit target (the default) auto-resolves to ATTRS_REMAP and applies the mapping.

None
skip_if Union[bool, Callable[[], bool]]

Conditionally deactivate the deprecation machinery — a bool, or a zero-argument Callable returning bool, evaluated at access time. When it evaluates True, the proxy transparently serves the wrapped source class with no warning, no attrs_mapping redirect, no args_mapping/args_extra handling, and no target forwarding — parity with deprecated_callable(skip_if=...), where a skipped call executes the source body unchanged. The condition may be consulted more than once per proxy operation, so keep the callable cheap and stable; a callable that returns a non-bool raises :class:TypeError at access time.

False
update_docstring bool

If True, inject a deprecation notice into the class docstring at decoration time (same behaviour as @deprecated(update_docstring=True)).

False
docstring_style Literal['auto', 'rst', 'mkdocs', 'markdown']

Output style for the injected notice when update_docstring=True. "auto" detects the doc engine at decoration time; "rst" emits a .. deprecated:: directive; "mkdocs" / "markdown" emit a !!! warning admonition.

'auto'
template_mgs Optional[str]

Deprecated alias for message_template (renamed in v0.12; the old spelling was a typo). Supplying it emits a :class:FutureWarning and its value is used as message_template; supplying both raises :class:TypeError. Removed in v1.0.

None

Returns:

Name Type Description
Callable[[_ClassOrProxy], _DeprecatedProxy]

A decorator that wraps the class in a :class:~deprecate.proxy._DeprecatedProxy, which satisfies the public

Callable[[_ClassOrProxy], _DeprecatedProxy]
deliberately Callable[[_ClassOrProxy], _DeprecatedProxy]

it is what keeps the forwarded dunders (int(), with, await) visible to type

Callable[[_ClassOrProxy], _DeprecatedProxy]

checkers, which the narrow Protocol would hide. To let the target type flow into call sites, annotate the

Callable[[_ClassOrProxy], _DeprecatedProxy]

one site that needs it — Old: DeprecationProxy[NewCls] = deprecated_class(target=NewCls, ...)(_OldSource).

Note

Subclassing (PEP 560): the proxy implements __mro_entries__ so class Child(deprecated_alias): resolves to class Child(target_or_source_class): in the MRO — issubclass(Child, target_class) returns True and standard inheritance semantics are preserved. One FutureWarning fires at class-definition time (not per instance). With :attr:~deprecate._types.TargetMode.ATTRS_REMAP aliases (attrs_mapping without a callable target) and :attr:~deprecate._types.TargetMode.ARGS_REMAP aliases (args_mapping without a callable target) subclassing stays silent — both modes scope deprecation to specific axes (attribute names or argument names), not the class name.

Examples:

>>> from enum import Enum
>>> class NewColor(Enum):
...     RED = 1
>>> @deprecated_class(target=NewColor, deprecated_in="1.0", remove_in="2.0", stream=None)
... class OldColor(Enum):
...     RED = 1
>>> OldColor.RED is NewColor.RED
True
>>> OldColor(1) is NewColor.RED
True

When only argument names changed, omit target and supply args_mapping. The proxy auto-resolves to :attr:~deprecate._types.TargetMode.ARGS_REMAP and warns only when the old argument name is passed:

>>> class Config:
...     def __init__(self, timeout: int = 0) -> None:
...         self.timeout = timeout
>>> LegacyConfig = deprecated_class(
...     args_mapping={"time_limit": "timeout"},
...     deprecated_in="1.5", remove_in="2.0", stream=None,
... )(Config)
>>> LegacyConfig(timeout=30).timeout     # new name — no remap needed
30
>>> LegacyConfig(time_limit=30).timeout  # old name — remapped to timeout
30

Selective per-attribute deprecation via attrs_mapping: only the listed attribute aliases emit a warning; other attribute accesses pass through silently.

>>> @deprecated_class(
...     attrs_mapping={"color": "colour"},
...     deprecated_in="1.0",
...     remove_in="2.0",
...     stream=None,
... )
... class Palette:
...     colour = "red"
...     color = colour  # deprecated alias for ``colour``
>>> Palette.colour     # canonical name — silent passthrough
'red'
>>> Palette.color      # deprecated alias — warns (suppressed by ``stream=None``)
'red'

deprecate.proxy.deprecated_instance(obj, *, name='', deprecated_in='', remove_in='', num_warns=1, stream=deprecation_warning, message_template=None, skip_if=False, read_only=False, args_extra=None, template_mgs=None) 🔗

Wrap any Python object with deprecation warnings.

Returns a :class:~deprecate.proxy._DeprecatedProxy that transparently forwards all read access to obj while emitting a :class:FutureWarning. In read-only mode any write attempt through the proxy raises :class:AttributeError.

Parameters:

Name Type Description Default
obj Any

The object to deprecate (dict, list, custom object, …).

required
name str

Display name for obj used in the warning message. When omitted, the type name of obj is used (e.g. "dict").

''
deprecated_in str

Version string when obj was deprecated.

''
remove_in str

Version string when obj will be removed.

''
num_warns int

Maximum number of warnings to emit. 1 (default) warns once; -1 warns on every access.

1
stream Optional[Callable[..., None]]

Callable used to emit warnings. Defaults to :data:~deprecate.deprecation.deprecation_warning (:class:FutureWarning). Pass None to suppress warnings.

deprecation_warning
message_template Optional[str]

Optional custom warning message template that overrides the built-in templates. When None (default), the built-in template for the active scenario is used. See :func:~deprecate.proxy.deprecated_class for the available %-style placeholders.

None
skip_if Union[bool, Callable[[], bool]]

Conditionally deactivate the deprecation machinery — a bool, or a zero-argument Callable returning bool, evaluated at access time. When it evaluates True, the proxy transparently serves obj with no warning and no read_only enforcement. The condition may be consulted more than once per proxy operation; a callable that returns a non-bool raises :class:TypeError at access time. For picklable proxies, use a module-level callable or a plain bool (same constraint as stream).

False
read_only bool

If True, raise :class:AttributeError on any write attempt through the proxy. Only the following standard collection mutator names are intercepted: append, clear, discard, extend, insert, pop, remove, setdefault, update, add. Custom method names (e.g. register(), reload(), set_value()) are not blocked.

False
args_extra Optional[dict[str, Any]]

Optional dict of extra keyword arguments merged into the forwarded call when the proxy is invoked. args_extra values win over any caller-supplied value with the same key.

None
template_mgs Optional[str]

Deprecated alias for message_template (renamed in v0.12; the old spelling was a typo). Supplying it emits a :class:FutureWarning and its value is used as message_template; supplying both raises :class:TypeError. Removed in v1.0.

None

Returns:

Name Type Description
A _DeprecatedProxy
_DeprecatedProxy
_DeprecatedProxy

__signature__ is obj's signature — or None when obj has none to introspect (a plain dict,

_DeprecatedProxy

any C-level type). Reading either emits no warning.

Note

Operator warnings: arithmetic operators (+, -, *, **, //, %, <<, >>, &, |, ^) and their reflected forms emit a deprecation warning and consume the num_warns budget. In-place operators (+=, -=, …) additionally enforce read_only. Ordering comparisons (<, <=, >, >=) and structural probes (__eq__, __len__, __bool__, __str__) are silent — they do not consume the warn budget.

Example

cfg = {"threshold": 0.5, "enabled": True} proxy = deprecated_instance( ... cfg, ... name="config_dict", ... deprecated_in="1.0", ... remove_in="2.0", ... stream=None, ... ) proxy["threshold"] 0.5 proxy.get("enabled") True

Module🔗

deprecate.module.deprecated_module(name=None, *, target=None, attrs_mapping=None, deprecated_in='', remove_in='', stream=None, message_template=None) 🔗

Mark a module as deprecated by intercepting all public attribute accesses.

Call this function once at module level (typically at the bottom of an old_module.py). It changes the module's __class__ to :class:_DeprecatedModuleWrapper so that every public attribute access emits a :class:FutureWarning — including real attributes already in __dict__. It also attaches __deprecated__ metadata to the module so that :func:~deprecate.audit.find_deprecation_wrappers can discover it.

Note

This design uses __getattribute__ rather than PEP 562 __getattr__ so real __dict__ attributes are covered too. With the default warnings path, every public access still runs the full warning machinery (stacklevel walk plus warning registry/filter checks). That overhead is intentional and not free: it is a documented tradeoff, not a bug. In tight loops, repeated reads of a deprecated-module constant can dwarf the underlying dictionary fetch by orders of magnitude. Cache the value locally instead of reading it in a hot loop.

Parameters:

Name Type Description Default
name Optional[str]

The __name__ of the module being deprecated. When omitted (or None), the caller's __name__ is detected automatically via sys._getframe(), so calling deprecated_module( deprecated_in="1.0", remove_in="2.0") from inside a module body works without explicitly passing __name__. Auto-detection reads the direct caller frame, so it must be called straight from the module body — not from a helper function (which would deprecate the helper's module) and not from a script run as __main__ (which would deprecate "__main__"). Pass name explicitly to avoid both pitfalls.

None
target Optional[ModuleType]

Optional replacement module. When given, missing-attribute access is forwarded to this module (Mode 2).

None
attrs_mapping Optional[dict[str, Optional[str]]]

Optional per-attribute mapping {"old_name": "new_name"} or {"old_name": None} to raise :class:AttributeError for that attribute. The mapping takes precedence for listed names even when the old name still exists in the module's __dict__ (the normal transition state where old and new bodies coexist): a listed name is always resolved via the mapping, never returned as its stale local value. When supplied alongside target, listed names resolve via the mapping and all other names fall through to target.

None
deprecated_in str

Version string when this module was deprecated (e.g. "1.0"). Defaults to ""; when omitted a decoration-time :class:UserWarning fires (the notice omits the version and expiry audits cannot gate the module), matching :func:~deprecate.deprecated.

''
remove_in str

Version string when this module will be removed (e.g. "2.0"). Defaults to "".

''
stream Optional[Callable[..., Any]]

Callable used to emit the warning instead of :func:warnings.warn. Pass None (default) to use the standard :mod:warnings machinery. Note: there is no warn budget — unlike @deprecated's num_warns, a warning fires on every public attribute access. The default warnings path is de-duplicated per call site by Python's __warningregistry__, but a custom stream (e.g. logging.warning) is invoked on every access; cap or throttle it on your side if a hot loop reads a deprecated-module attribute repeatedly.

None
message_template Optional[str]

Optional custom warning message. When supplied it replaces the built-in redirect/version notice entirely — it is not appended to it. Plain text without any % renders verbatim; a literal % must be escaped as %%. The %-style placeholders %(source_name)s (the module name), %(deprecated_in)s, %(remove_in)s, and %(target_name)s (empty when no target) are substituted. A malformed conversion or an unknown placeholder raises :class:ValueError at decoration time, matching the other four factories exactly (this call goes through the same _validate_message_template validator). None (default) keeps the built-in notice.

None

Raises:

Type Description
ValueError

If the resolved module name is not found in :data:sys.modules; if name is omitted and the caller frame's __name__ cannot be determined; if target points at the module being deprecated itself (a self-redirect would recurse indefinitely on every missing-attribute lookup); or if message_template contains a bare %-conversion or an unknown %(name)s placeholder.

TypeError

If name is omitted and the call is made from inside a function or class body rather than at module top level (auto-detection would otherwise deprecate the enclosing module); pass name explicitly to call from a non-module scope. Also raised if the module's type declares __slots__ (incompatible memory layout prevents __class__ reassignment) — wrap in a plain :class:types.ModuleType first if needed.

Examples:

>>> import sys, types
>>> _m = types.ModuleType("demo_old")
>>> sys.modules["demo_old"] = _m
>>> import deprecate
>>> deprecate.deprecated_module("demo_old", deprecated_in="1.0", remove_in="2.0")
>>> import warnings
>>> with warnings.catch_warnings(record=True) as _w:
...     warnings.simplefilter("always")
...     _ = getattr(sys.modules["demo_old"], "any_attr", None)
>>> print(len(_w) == 1 and issubclass(_w[0].category, FutureWarning))
True
>>> del sys.modules["demo_old"]

Audit🔗

deprecate.audit.find_deprecation_wrappers(module, recursive=True, include_members=True) 🔗

Scan a module or package for deprecated wrappers and validate them.

This is a development/CI tool to scan a codebase for all wrappers created with :func:~deprecate.deprecated, :func:~deprecate.deprecated_class, :func:~deprecate.deprecated_instance, or :func:~deprecate.module.deprecated_module (module-level deprecation) and validate that each wrapper configuration is meaningful. Returns comprehensive information about each deprecated wrapper including validation results that help identify misconfigured wrappers.

Parameters:

Name Type Description Default
module Union[Any, str]

A Python module or package to scan for deprecated wrappers. Can be: - Imported module object (e.g., import my_package; find_deprecation_wrappers(my_package)) - String module path (e.g., find_deprecation_wrappers("my_package.submodule"))

required
recursive bool

If True (default), recursively scan submodules. If False, only scan the top-level module.

True
include_members bool

If True, also scan deprecated methods and constructors defined on classes.

True

Returns:

Type Description
list[DeprecationWrapperInfo]

List of :class:~deprecate.audit.DeprecationWrapperInfo dataclasses, one per deprecated wrapper found.

list[DeprecationWrapperInfo]

Each contains: - module: Module name where the wrapper is defined - function: Wrapper name - deprecated_info: DeprecationConfig metadata from the decorator (__deprecated__ attribute) - invalid_args: List of args_mapping keys not in wrapper signature - empty_args_mapping: True if args_mapping is None or empty - identity_args_mapping: List of identity mappings (key == value) - self_reference: True if target points to same wrapper - no_effect: True if wrapper has zero impact

Example

from deprecate import find_deprecation_wrappers from tests import collection_deprecate as my_package

results = find_deprecation_wrappers(my_package) print(len(results) > 0) # Should find deprecated wrappers True

Also works with string module paths🔗

results = find_deprecation_wrappers("tests.collection_deprecate") print(len(results) > 0) True

Filter to find only problematic wrappers🔗

problematic = [r for r in results if r.invalid_args or r.no_effect] print(len(results) > 0) # May or may not have problematic ones True

Note
  • Requires that the module be importable
  • Recursive scans import every submodule of the package, executing their module-level code; packages with heavy import-time work (GPU init, network access) make the scan correspondingly expensive
  • Skips submodules that fail to import — any exception raised by module-level code is reported as a UserWarning (audit: skipped <module>: ...) and the scan continues
  • Inspects the __deprecated__ attribute set by the :func:~deprecate.deprecated decorator
  • Skips private/magic attributes and imports from other modules
  • Uses static member inspection to avoid scan-time side effects from dynamic attribute access

deprecate.audit.validate_deprecation_wrapper(func) 🔗

Validate a deprecated callable or module wrapper and return structured metadata.

This is a development tool to check if deprecated wrappers are configured correctly and will have the intended effect. It examines the __deprecated__ attribute set by the :func:~deprecate.deprecated decorator and identifies configurations that would result in zero impact:

  • args_mapping keys that don't exist in the function's signature
  • Empty or None args_mapping (no argument remapping)
  • Identity mappings where key equals value (e.g., {'arg': 'arg'})
  • Target pointing to the same function (self-reference)
  • target=None with no args_mapping (just warns, no forwarding)

Parameters:

Name Type Description Default
func Union[Callable, ModuleType]

The deprecated wrapper to validate. Accepts either a callable decorated with @deprecated or a module object passed through :func:deprecated_module. Must have a __deprecated__ attribute.

required

Returns:

Type Description
DeprecationWrapperInfo
  • function: Name of the wrapper being validated
  • deprecated_info: The typed :class:~deprecate._types.DeprecationConfig metadata from __deprecated__
  • invalid_args: List of args_mapping keys not in wrapper signature
  • empty_args_mapping: True if args_mapping is None or empty
  • identity_args_mapping: List of args where key equals value (no effect)
  • self_reference: True if target is the same as the wrapper
  • no_effect: True if wrapper has zero impact (all checks combined)
  • empty_deprecated_in: True when deprecated_in is absent or empty

Raises:

Type Description
ValueError

If the wrapper has missing or invalid __deprecated__ metadata (expected :class:~deprecate._types.DeprecationConfig).

Example

from deprecate import TargetMode, deprecated, validate_deprecation_wrapper def new_implementation(value: int) -> int: ... return value * 2

@deprecated(target=new_implementation, deprecated_in="1.0", args_mapping={"old_val": "value"}) ... def old_func(old_val: int) -> int: ... pass

Valid mapping to different function - has effect🔗

result = validate_deprecation_wrapper(old_func) result.no_effect False result.invalid_args []

@deprecated(target=TargetMode.ARGS_REMAP, deprecated_in="1.0", args_mapping={"arg": "arg"}) ... def identity_func(arg: int) -> int: ... return arg

Identity mapping with self-deprecation - no effect🔗

result = validate_deprecation_wrapper(identity_func) result.identity_args_mapping ['arg'] result.no_effect True

Note

Use this function during development or in CI to ensure deprecation decorators are configured meaningfully. Invalid configurations won't cause runtime errors but will silently have no effect.

deprecate.audit.validate_deprecation_expiry(module, current_version=None, recursive=True, include_members=True) 🔗

Check all deprecated callables in a module/package for expired removal deadlines.

This enforcement tool scans an entire module or package for deprecated functions and checks if any have passed their scheduled removal version. It's designed for CI/CD pipelines to automatically detect and report zombie code across a codebase.

The function uses :func:~deprecate.audit.find_deprecation_wrappers to discover all deprecated wrappers, then checks each one against the current version. Any wrappers that have reached or passed their removal deadline are collected and reported.

Parameters:

Name Type Description Default
module Union[Any, str]

A Python module or package to scan. Can be: - Imported module object (e.g., import my_package; validate_deprecation_expiry(my_package, "2.0")) - String module path (e.g., validate_deprecation_expiry("my_package.submodule", "2.0"))

required
current_version Optional[str]

The current version of your package to compare against removal deadlines (e.g., "2.0.0"). If None, attempts to auto-detect the version using the package name from the module path (e.g., "mypackage" extracts mypackage as package name).

None
recursive bool

If True (default), recursively scan submodules. If False, only scan the top-level module.

True
include_members bool

If True (default), also scan deprecated class members (methods, constructors, classmethods, staticmethods, properties) — matching the discovery default of :func:~deprecate.audit.find_deprecation_wrappers, so the enforcement gate sees everything discovery and reporting see.

True

Returns:

Type Description
list[str]

List of error messages for callables that have expired (past their removal deadline).

list[str]

Empty list if all deprecated callables are still within their deprecation period.

Example

Check a specific module with version before any deadlines🔗

from deprecate import validate_deprecation_expiry expired = validate_deprecation_expiry("tests.collection_deprecate", "0.1", recursive=False) len(expired) 0

Check with version past some removal deadlines🔗

expired = validate_deprecation_expiry("tests.collection_deprecate", "0.5", recursive=False) print(len(expired)) # Some functions and class members have remove_in <= "0.5" 31

Note

  • Skips callables without a remove_in field (warnings only, no removal deadline)
  • Skips callables that cannot be imported or accessed
  • Emits a UserWarning (rather than silently skipping) for callables with an unparsable remove_in
  • Uses semantic versioning comparison (e.g., "1.2.3" vs "2.0.0")
  • Intended for automated checks in CI/CD pipelines
  • Can be integrated into test suites or pre-commit hooks

deprecate.audit.validate_deprecation_chains(module, recursive=True) 🔗

Validate that deprecated functions don't form chains with other deprecated code.

This is a developer utility that scans a module or package for deprecated functions that form chains in two ways:

  1. TARGET chains: The target argument points to another deprecated callable instead of the final non-deprecated implementation.
  2. STACKED chains: Multiple @deprecated(target=TargetMode.ARGS_REMAP, ...) decorators are stacked on the same function with argument mappings that should be collapsed, or a callable target is itself a self-deprecation (target=TargetMode.ARGS_REMAP) requiring mapping composition.

Both types are wasteful: wrappers should point directly to the final (non-deprecated) implementation with composed argument mappings.

Detection is based purely on decorator metadata (__deprecated__ attributes) — no source-code or AST inspection is performed.

Parameters:

Name Type Description Default
module Union[Any, str]

A Python module or package to scan for deprecation chains. Can be: - Imported module object (e.g., import my_package; validate_deprecation_chains(my_package)) - String module path (e.g., validate_deprecation_chains("my_package.submodule"))

required
recursive bool

If True (default), recursively scan submodules. If False, only scan the top-level module.

True

Returns:

Type Description
list[DeprecationWrapperInfo]

List of :class:~deprecate.audit.DeprecationWrapperInfo where chain_type is not None, i.e. every

list[DeprecationWrapperInfo]

deprecated wrapper that forms a chain (ChainType.TARGET or ChainType.STACKED).

Example

from deprecate import validate_deprecation_chains import tests.collection_chains as test_module

issues = validate_deprecation_chains(test_module, recursive=False) len(issues) > 0 # Should find chains True

Note
  • Only flags callees using the :func:~deprecate.deprecated decorator
  • Uses :func:~deprecate.audit.find_deprecation_wrappers and inspects chain_type to detect chains

deprecate.audit.validate_mapping_compatibility(module, recursive=True) 🔗

Return wrappers whose args_mapping remaps deprecated names to POSITIONAL_ONLY constructor params.

A non-empty args_mapping_positional_only on the returned DeprecationWrapperInfo means the proxy falls back to setattr at call time instead of forwarding the remapped kwarg. Use this validator in CI to detect :func:~deprecate.proxy.deprecated_class configurations that silently degrade to attribute assignment and may not behave as expected on all target class types.

Parameters:

Name Type Description Default
module Union[Any, str]

A Python module or package to scan. Accepts an imported module object or a dotted module path string.

required
recursive bool

When True (default) recursively scan submodules.

True

Returns:

Type Description
list[DeprecationWrapperInfo]

List of DeprecationWrapperInfo instances whose args_mapping_positional_only field is

list[DeprecationWrapperInfo]

non-empty. Returns an empty list when no incompatibilities are found.

Examples:

>>> from deprecate import validate_mapping_compatibility
>>> import tests.collection_deprecate as col
>>> results = validate_mapping_compatibility(col, recursive=False)
>>> len(results) > 0  # DepPositionalOnly remaps to a POSITIONAL_ONLY param
True
>>> results[0].function
'DepPositionalOnly'

deprecate.audit.generate_deprecation_table(module, current_version=None, recursive=True, style=TableStyle.COMPACT, include_members=True, *, _wrappers=None) 🔗

Generate a markdown table summarizing deprecated wrappers.

The table is derived from __deprecated__ metadata and includes both top-level wrappers and deprecated class members (methods/constructors).

Parameters:

Name Type Description Default
module Union[Any, str]

Imported module/package object or string module path to scan.

required
current_version Optional[str]

Optional current package version for lifecycle status evaluation in compact style. If None, auto-detection is attempted via the package name; status falls back to "⚪ Status Unknown" when packaging is not installed.

None
recursive bool

If True (default), include submodules in the scan.

True
style Union[TableStyle, str]

Table format — "compact" or "matrix". - "compact": Original API | API Type | New API | Deprecated | Remove | Current Status - "matrix": Original API | API Type | New API | <all versions...>, with markers D (deprecated) and R (remove) in version columns.

COMPACT
include_members bool

If True (default), include deprecated class members (methods, constructors).

True

Returns:

Type Description
str

Markdown string containing a formatted table. When a version is

str

resolvable (either from current_version or auto-detected), the

str

first line is an HTML comment

str

followed by the header row and alignment row. When no version can be

str

resolved, the first line is the header row directly.

Raises:

Type Description
ValueError

If style is not "compact" or "matrix", or if current_version is supplied but is not a valid PEP 440 version string and packaging is installed.

Example

from tests import collection_deprecate as pkg report = generate_deprecation_table(pkg, recursive=False) report.splitlines()[0] '| Original API | API Type | New API | Deprecated | Remove | Current Status |'

deprecate.audit.DeprecationWrapperInfo dataclass 🔗

Information about a deprecated wrapper and its validation results.

This dataclass represents a deprecated wrapper (a :func:~deprecate.deprecated-decorated function or a :func:~deprecate.proxy.deprecated_class/:func:~deprecate.proxy.deprecated_instance proxy), containing both identification info and validation results from :func:~deprecate.audit.validate_deprecation_wrapper or :func:~deprecate.audit.find_deprecation_wrappers.

Attributes:

Name Type Description
module str

Module name where the wrapper is defined (empty for direct validation).

function str

Wrapper name.

deprecated_info DeprecationConfig

The __deprecated__ attribute from the decorator, as a :class:~deprecate._types.DeprecationConfig.

invalid_args list[str]

List of args_mapping keys that don't exist in the wrapper's signature.

empty_args_mapping bool

True if args_mapping is None or empty (no argument remapping).

identity_args_mapping list[str]

List of args where key equals value (e.g., {'arg': 'arg'}).

self_reference bool

True if target points to the same wrapper.

no_effect bool

True if wrapper has zero impact (combines all checks).

all_identity bool

True when every configured mapping is an identity mapping (key == value, non-empty).

chain_type Optional[ChainType]

The kind of deprecation chain detected, or None if no chain. See :class:~deprecate.audit.ChainType for values (:attr:~deprecate.audit.ChainType.TARGET or :attr:~deprecate.audit.ChainType.STACKED).

misconfigured_target bool

True when the wrapper has an invalid target configuration: target=False, :attr:~deprecate._types.TargetMode.NOTIFY with args_mapping, or :attr:~deprecate._types.TargetMode.ARGS_REMAP with empty args_mapping.

empty_deprecated_in bool

True when deprecated_in is empty. Missing remove_in alone is a valid use case (many libraries deprecate without a scheduled removal date), so only the absence of deprecated_in is treated as a misconfiguration signal. CI pipelines can filter on this field to surface wrappers that lack the introductory version metadata without crashing callers.

api_type str

Inferred deprecated API type for report generation. Possible values: callable, args, class, dataclass, dataclass attributes, data, class constructor, class constructor args, class method, class method args, classmethod, classmethod args, staticmethod, staticmethod args.

args_mapping_auto_expanded list[str]

args_mapping keys that were automatically copied from attrs_mapping by the dataclass dual-surface expansion at decoration time. Empty list when no auto-expansion occurred. Read from :attr:~deprecate._types.DeprecationConfig.args_mapping_auto_expanded.

args_mapping_positional_only list[str]

args_mapping old-key names whose remapped target is a POSITIONAL_ONLY constructor parameter. Non-empty list signals that the proxy falls back to setattr for those keys. Use :func:~deprecate.audit.validate_mapping_compatibility to filter wrappers by this field. Read from :attr:~deprecate._types.DeprecationConfig.args_mapping_positional_only.

inner_order_property bool

True when the wrapper is a plain :class:property whose fget carries @deprecated metadata — the inner order @property @deprecated (@deprecated closer to def). In this order only fget warns; any setter or deleter added afterwards is built from the plain :class:property base and is silently unprotected. The flag fires for every inner-order property, including the getter-only shape, because the canonical order is the outer @deprecated(...) @property (which produces a :class:~deprecate._properties._DeprecatedProperty that re-wraps every rebound accessor). CI pipelines can filter on this field to reject the silent write/delete gap. False for outer-order properties, non-property wrappers, and proxies.

Example

info = DeprecationWrapperInfo( ... module="my_package.module", ... function="old_function", ... deprecated_info=DeprecationConfig(deprecated_in="1.0", remove_in="2.0"), ... invalid_args=["nonexistent"], ... no_effect=True, ... ) info.function 'old_function' info.invalid_args ['nonexistent']

__post_init__() 🔗

Derive empty_deprecated_in from deprecated_info to keep them in sync.

empty_mapping() 🔗

Deprecated alias for :attr:~deprecate.audit.DeprecationWrapperInfo.empty_args_mapping.

Deprecated in 0.8

Renamed to :attr:~deprecate.audit.DeprecationWrapperInfo.empty_args_mapping. Will be removed in v1.0.

Note

Python's default warning filter deduplicates per (message, category, module, lineno), so accessing this property in a loop from the same call site emits at most one warning.

identity_mapping() 🔗

Deprecated alias for :attr:~deprecate.audit.DeprecationWrapperInfo.identity_args_mapping.

Deprecated in 0.8

Renamed to :attr:~deprecate.audit.DeprecationWrapperInfo.identity_args_mapping. Will be removed in v1.0.

Note

Python's default warning filter deduplicates per (message, category, module, lineno), so accessing this property in a loop from the same call site emits at most one warning.

deprecate.audit.ChainType 🔗

Bases: Enum

Type of deprecation chain detected by :func:~deprecate.audit.validate_deprecation_chains.

Attributes:

Name Type Description
TARGET

The target argument is itself a callable decorated with :func:~deprecate.deprecated (a forwarding chain). Fix by pointing directly to the final non-deprecated target.

STACKED

Arg mappings chain and must be composed/collapsed. Two sub-cases: (a) Callable target is itself @deprecated(True, args_mapping=...) — the caller's mapping feeds into the target's self-renaming, so both hops must be collapsed into one. (b) Multiple @deprecated(True, args_mapping=...) decorators are stacked on the same function and should be merged into a single decorator. Also used when attrs_mapping values point at another deprecated attribute alias.

deprecate.audit.DeprecationStatus 🔗

Bases: str, Enum

Lifecycle status labels used in the deprecation report's Current Status column.

Each member's value is the full display string (emoji + text) rendered in the table. Using a str enum means members compare equal to their string values and can be returned wherever a plain string is expected.

Members are declared from least to most urgent for readability, but this enum is not orderable by urgency: because each value starts with an emoji, the inherited str ordering operators (<, >) compare Unicode codepoints of those emoji, not deprecation urgency. Do not rely on status_a > status_b to mean "more urgent" — compare members explicitly (status is DeprecationStatus.PAST_REMOVAL_DATE). The ordering operators are overridden to raise TypeError so accidental comparisons fail loudly.

Examples:

>>> DeprecationStatus.ACTIVE_WARNING.value
'📢 Deprecation Active'
>>> DeprecationStatus.PAST_REMOVAL_DATE is DeprecationStatus.PAST_REMOVAL_DATE
True

__ge__(other) 🔗

Raise TypeError — urgency ordering is not meaningful for emoji-valued status labels.

__gt__(other) 🔗

Raise TypeError — urgency ordering is not meaningful for emoji-valued status labels.

__le__(other) 🔗

Raise TypeError — urgency ordering is not meaningful for emoji-valued status labels.

__lt__(other) 🔗

Raise TypeError — urgency ordering is not meaningful for emoji-valued status labels.

deprecate.audit.TableStyle 🔗

Bases: str, Enum

Markdown table layout produced by :func:~deprecate.audit.generate_deprecation_table.

Types🔗

deprecate.TargetMode 🔗

Bases: Enum

Selects @deprecated behaviour when no callable replacement is provided.

Attributes:

Name Type Description
AUTO

Decoration-time fallback that resolves the mode when target is omitted on the :func:~deprecate.deprecated front door -- "infer the mode from the configuration". It exists only to give an omitted target a sensible default; prefer passing an explicit mode (:attr:NOTIFY, :attr:ARGS_REMAP, :attr:ATTRS_REMAP) or a callable target so the intent is visible at the call site. Resolves before the wrapper/proxy is built: a mapping present selects :attr:ARGS_REMAP (args_mapping) or :attr:ATTRS_REMAP (attrs_mapping, class path); no mapping selects :attr:NOTIFY (callable path) or the proxy's unset target (class path). Passing AUTO explicitly to @deprecated is identical to omitting target; the strict factories (:func:~deprecate.routine.deprecated_callable, :func:~deprecate.proxy.deprecated_class) reject it with :class:TypeError -- they require an explicit mode. AUTO is never stored in :class:~deprecate._types.DeprecationConfig -- audit metadata always records the resolved mode.

NOTIFY

Notify-only deprecation -- warn on every call; original body executes unchanged. Replaces target=None. Combining an explicit NOTIFY with args_mapping, attrs_mapping, or args_extra is contradictory and emits a :class:UserWarning (the mapping/extras are ignored; :class:TypeError is planned in v1.0) -- with @deprecated, omit target instead to let :attr:AUTO pick the matching remap mode.

ARGS_REMAP

Deprecate argument names only -- warn only when deprecated argument names are passed; remaps kwargs via args_mapping before calling the original body. Replaces target=True. Selected automatically by :attr:AUTO when args_mapping is provided to @deprecated without an explicit target; using this mode without args_mapping emits a :class:UserWarning today, and :class:TypeError is planned in v1.0.

ATTRS_REMAP

Selective per-attribute deprecation -- warn only when a deprecated attribute alias listed in attrs_mapping is accessed; all other attribute access is forwarded silently. Proxy-specific mode: only valid for :func:~deprecate.proxy.deprecated_class; raises :class:TypeError on :func:~deprecate.deprecated decorated functions/methods. Analogous to :attr:ARGS_REMAP but for attribute access instead of call arguments. Selected automatically by :attr:AUTO when attrs_mapping is non-empty and no explicit target is provided.

Examples:

>>> from deprecate import TargetMode
>>> TargetMode.AUTO.value
'auto'
>>> TargetMode.NOTIFY.value
'notify'
>>> TargetMode.ARGS_REMAP.value
'args_remap'
>>> TargetMode.ATTRS_REMAP.value
'attrs_remap'

deprecate.DeprecationProxy 🔗

Bases: Protocol, Generic[_T_co]

Public type produced by :func:~deprecate.proxy.deprecated_class / :func:~deprecate.proxy.deprecated_instance.

Documents the public contract that deprecated proxies satisfy:

  • __wrapped__ points back to the source object/class for static-analysis tools (Sphinx, mypy, IDEs).
  • __deprecated__ carries :class:DeprecationConfig metadata consumed by audit tools.
  • Attribute, item, and call access is transparently forwarded to the wrapped source.

The type parameter T describes the instance type returned by calling the proxy (i.e. the target type for class-forwarding proxies). It is purely a static affordance: runtime instances of :class:~deprecate.proxy._DeprecatedProxy satisfy this Protocol structurally, so no explicit isinstance check is required.

Protocol vs implementation

DeprecationProxy (public, this Protocol) describes the contract; :class:~deprecate.proxy._DeprecatedProxy (private) is the concrete runtime class that satisfies it. Annotate against the former, never import the latter.

Static-typing scope

This Protocol is the type to annotate against; it is not what the public functions declare as their return type. deprecated_class and deprecated_instance return the concrete :class:~deprecate.proxy._DeprecatedProxy, whose forwarded dunders (int(), with, await, ...) a narrow Protocol would hide from type checkers. No call shape narrows to DeprecationProxy[T] on its own, so to let the target type flow into call sites, annotate the one site that needs it — OldCls: DeprecationProxy[NewCls] = deprecated_class(target=NewCls, ...)(OldClsDef). The decorator form @deprecated_class(target=NewCls, ...) is typed as the raw source class because mypy does not rebind a class definition to an instance return type; annotating it would require returning a real class instead of a proxy.

isinstance only

This is a data Protocol (it declares attributes, not just methods), so only isinstance is supported at runtime. issubclass(SomeType, DeprecationProxy) raises :class:TypeError, as it does for every @runtime_checkable Protocol with non-method members.

Example

from deprecate import deprecated_class, DeprecationProxy class NewColor: ... def init(self, code: int) -> None: ... self.code = code @deprecated_class(target=NewColor, deprecated_in="1.0", remove_in="2.0", stream=None) ... class OldColor: ... pass isinstance(OldColor, DeprecationProxy) True OldColor.wrapped is OldColor.wrapped # breadcrumb back to the source class True

An explicit annotation on the assignment is what gives mypy the target type — spelled out as DeprecationProxy[NewColor], OldColorAlias(1) is typed as NewColor:

_decorator = deprecated_class(target=NewColor, deprecated_in="1.0", remove_in="2.0", stream=None) class _OldColorSource: ... pass OldColorAlias: DeprecationProxy[NewColor] = _decorator(_OldColorSource) isinstance(OldColorAlias(1), NewColor) True

__call__(*args, **kwargs) 🔗

Forward a call to the wrapped source (e.g. OldColor(1) -> NewColor(1)).

__getattr__(name) 🔗

Forward attribute access (e.g. OldColor.RED -> NewColor.RED).

__getitem__(key) 🔗

Forward item access (e.g. proxy['key'] -> source['key']).

Utilities🔗

deprecate.utils.void(*args, **kwargs) 🔗

Empty function that accepts any arguments and returns None.

This helper function is used to silence IDE warnings about unused parameters in deprecated functions where the body is never executed (calls are forwarded to a target function). It's purely a convenience for developers.

Parameters:

Name Type Description Default
*args Any

Any positional arguments (ignored).

()
**kwargs Any

Any keyword arguments (ignored).

{}

Returns:

Type Description
Any

None always.

Example

from deprecate import deprecated, void

def new_func(x: int) -> int: ... return x * 2

@deprecated(target=new_func, deprecated_in="1.0", remove_in="2.0") ... def old_func(x: int) -> int: ... void(x) # Silences IDE warning about unused 'x' ... # This line is never reached - call forwarded to new_func

Note

This function has no runtime effect - it's purely for developer convenience. You can also use pass or just a docstring instead of calling void().

deprecate.utils.assert_no_warnings(warning_type=None, match=None) 🔗

Context manager asserting that no warnings are raised — the inverse of pytest.warns().

Useful for testing that refactored code properly avoids deprecated functionality or that new implementations don't trigger warnings.

Parameters:

Name Type Description Default
warning_type Optional[type[Warning]]

The warning type that must NOT be raised (e.g., :class:FutureWarning, :class:DeprecationWarning). If None, asserts that no warnings of any type are raised.

None
match Optional[str]

If given, only fail if a warning message contains this string. If None, fails on any warning of the specified type.

None

Raises:

Type Description
AssertionError

If a warning of the specified type (and optionally matching the message pattern) was raised during the context.

Example

Assert new function doesn't trigger FutureWarning🔗

import warnings def new_func(x: int) -> int: ... return x * 2 with assert_no_warnings(FutureWarning): ... result = new_func(42) result 84

Assert NO warnings at all are raised🔗

def clean_function(): ... pass with assert_no_warnings(): ... clean_function()

Only fail if warning message matches pattern🔗

def some_function(): ... warnings.warn("deprecated feature", FutureWarning)

Passes because warning contains "feature", not "other"🔗

with assert_no_warnings(FutureWarning, match="other"): ... some_function()

Note

This context manager is particularly useful in pytest for testing that refactored code properly uses new APIs without triggering deprecation warnings.