Skip to content

Migration Guide🔗

The current development target is v0.12. This guide contains only rewrites, deprecations, and observable changes that existing users need to handle when upgrading. New APIs and capabilities belong in the Changelog and topic guides.

Migrate Legacy Target Values🔗

v0.8 introduced TargetMode so deprecation intent no longer depends on the legacy None, True, and False sentinels. These examples show the current form and the caller behavior to preserve during migration.

target=NoneTargetMode.NOTIFY🔗

target=None means "warn, then run the decorated body". It still works, but emits FutureWarning at decoration time. Omit target for the shortest current form; the TargetMode.AUTO default resolves to TargetMode.NOTIFY when no mapping is present. Use target=TargetMode.NOTIFY when being explicit helps the reader.

- # DEPRECATED API — legacy sentinel
- @deprecated(target=None, deprecated_in="1.0", remove_in="2.0")
+ # DEPRECATED API — current warn-only form
+ @deprecated(deprecated_in="1.0", remove_in="2.0")
from deprecate import deprecated


@deprecated(deprecated_in="1.0", remove_in="2.0")
def refresh_cache(cache_key: str) -> str:
    """Refresh one cached value."""
    return f"refreshed:{cache_key}"


print(refresh_cache("products"))
Output: refresh_cache("products")
refreshed:products

The notice respects num_warns (once by default); the function body still executes normally.

target=TrueTargetMode.ARGS_REMAP🔗

target=True remaps deprecated keyword names within the same function. Replace it with TargetMode.ARGS_REMAP; existing callers can keep the old keyword during the migration window while new callers use the replacement.

- target=True,
+ target=TargetMode.ARGS_REMAP,
from deprecate import TargetMode, deprecated


@deprecated(
    target=TargetMode.ARGS_REMAP,
    args_mapping={"ttl": "cache_ttl"},
    deprecated_in="1.0",
    remove_in="2.0",
)
def configure_cache(cache_ttl: int = 60) -> int:
    """Return the configured cache lifetime."""
    return cache_ttl


# DEPRECATED API — old callers are remapped and warned.
print(configure_cache(ttl=30))
# NEW API — callers use the replacement keyword directly.
print(configure_cache(cache_ttl=45))
Output: configure_cache(...)
30
45

target=FalseTargetMode.NOTIFY or a callable target🔗

target=False was never a valid target. On a callable it now emits UserWarning at decoration time and behaves like warn-only mode. Proxy factories treat it like an omitted target while marking the configuration as misconfigured, so a supplied mapping may still be inferred; do not rely on either compatibility path. Choose the behavior you actually need:

- # DEPRECATED API — invalid legacy sentinel
- @deprecated(target=False, deprecated_in="1.0", remove_in="2.0")
+ # DEPRECATED API — keep running this body after warning
+ @deprecated(target=TargetMode.NOTIFY, deprecated_in="1.0", remove_in="2.0")
from deprecate import TargetMode, deprecated


@deprecated(
    target=TargetMode.NOTIFY,
    deprecated_in="1.0",
    remove_in="2.0",
)
def legacy_checksum(payload: str) -> int:
    """Compute the retained legacy checksum."""
    return len(payload)


print(legacy_checksum("abc"))
Output: legacy_checksum("abc")
3

If the old API should forward to a replacement, pass that callable instead. The deprecated body is then not executed:

from deprecate import deprecated


def checksum_v2(payload: bytes) -> int:
    """Compute the replacement checksum."""
    return sum(payload)


@deprecated(
    target=checksum_v2,
    args_mapping={"text": "payload"},
    deprecated_in="1.0",
    remove_in="2.0",
)
def checksum(text: bytes) -> int:
    """Retain the deprecated signature during migration."""
    ...


# DEPRECATED API — forwards to checksum_v2 and warns.
print(checksum(text=b"abc"))
# NEW API — callers move directly to the replacement.
print(checksum_v2(payload=b"abc"))
Output: checksum(...) and checksum_v2(...)
294
294

The same rule applies to deprecated_class() and deprecated_instance(): target=False is not a valid mode.

Misconfigured TargetMode combinations🔗

Contradictory combinations emit UserWarning at decoration time. The warning is a migration task: the ignored configuration is scheduled to become an error in v1.0.

Combination Migration
TargetMode.ARGS_REMAP without args_mapping Add a real mapping, or use TargetMode.NOTIFY for warn-only behavior.
Explicit TargetMode.NOTIFY with args_mapping Omit target so AUTO infers ARGS_REMAP, select ARGS_REMAP explicitly, or remove the mapping.
Explicit TargetMode.NOTIFY with args_extra Use a callable target if extra kwargs must reach a replacement, or remove args_extra.
deprecated_class(target=TargetMode.NOTIFY, attrs_mapping=...) Omit target so the proxy infers ATTRS_REMAP, select ATTRS_REMAP explicitly, or remove the mapping.
deprecated_class(target=TargetMode.ATTRS_REMAP) without a mapping Add attrs_mapping={"old": "new"}, or use NOTIFY for class-wide warnings.
@deprecated(target=TargetMode.ATTRS_REMAP) Use deprecated_class(attrs_mapping=...); the common front door does not expose class-only attrs_mapping.

An explicitly supplied NOTIFY is never rewritten: its mapping stays inert. Inference happens only when target is omitted.

DeprecationWrapperInfo field renames🔗

Two audit fields were renamed in v0.8. The old properties still work but emit DeprecationWarning and will be removed in v1.0:

- # DEPRECATED API — compatibility properties
- info.empty_mapping
- info.identity_mapping
- dataclasses.replace(info, empty_mapping=True)
+ # NEW API — stored field names
+ info.empty_args_mapping
+ info.identity_args_mapping
+ dataclasses.replace(info, empty_args_mapping=True)

The replacement fields are regular dataclass fields, so introspection and dataclasses.replace() use them directly:

from dataclasses import replace

from deprecate.audit import DeprecationWrapperInfo


info = DeprecationWrapperInfo(
    empty_args_mapping=True,
    identity_args_mapping=["timeout"],
)
updated = replace(info, empty_args_mapping=False)

print(info.empty_args_mapping)
print(info.identity_args_mapping)
print(updated.empty_args_mapping)
Output: info fields and updated.empty_args_mapping
True
['timeout']
False

Pick Your Upgrade Path🔗

Find the section matching the version you are upgrading from. Each section aggregates every later migration-relevant compatibility change into two tabs:

  1. Apply every item under Breaking changes.
  2. Review changed warnings, errors, audit scope, and proxy behavior under Behavior changes.
  3. Run your suite with FutureWarning promoted to an error, then run your pyDeprecate audit/expiry CI checks.

This guide works at minor-line granularity. v0.N.x means the latest available bugfix release in that feature line. The paths assume your dependency constraint allows bugfix updates and that you update within v0.N.x before crossing to the next feature line. Patch and post releases are folded into their minor interval rather than receiving separate sections.

Releases with no migration work are skipped. Where a later release superseded an intermediate behavior, the section describes the final v0.12.x development behavior.

Coming from v0.11.x🔗

  • @deprecated(target=TargetMode.ATTRS_REMAP) now raises TypeError for a class source. It already raised for functions. ATTRS_REMAP needs the class-only attrs_mapping keyword, which the common front door does not expose, so a class source previously built a proxy that remapped nothing. Use deprecated_class(attrs_mapping=...).
  • Rename template_mgs to message_template on deprecated(), deprecated_callable(), deprecated_class(), and deprecated_instance(). The typo remains a warning alias until v1.0; supplying both names raises TypeError.
  • @deprecated now defaults to TargetMode.AUTO. It resolves at decoration time: a function/class with args_mapping becomes ARGS_REMAP; a source without a mapping becomes warn-only. AUTO is never stored in DeprecationConfig; do not pass it explicitly because it exists only as the front-door default.
  • Existing @deprecated use on a class remains supported; no code change or decorator rewrite is required. It permanently delegates to deprecated_class() and emits one informational UserWarning per module-qualified class. stream=None suppresses the notice. Only the notice, not backward support or delegation, is removed in v1.0.
  • message_template and skip_if supplied through @deprecated on a class now reach the proxy. message_template was previously dropped on that path.
  • Non-callable sources now raise a direct TypeError pointing users to deprecated_instance() instead of failing later on __name__.
  • Explicit target=TargetMode.NOTIFY together with a mapping still emits UserWarning, stays NOTIFY, leaves the mapping inert, and is marked misconfigured — unchanged from v0.11.0, and a TypeError in v1.0. What changed is that an omitted target no longer lands here: it auto-resolves instead. Omit target to infer remapping, or select the matching remap mode explicitly.

Coming from v0.10.x🔗

  • Update proxy detection. proxy.__class__ reports the wrapped object's type for isinstance transparency. Use type(proxy) when you need to detect _DeprecatedProxy itself.
  • Do not use an instance proxy as the second argument to isinstance() or issubclass(). This misuse now raises TypeError instead of returning False. Class-alias proxies remain valid there.
  • Review expiry CI scope. validate_deprecation_expiry() now defaults to include_members=True, so expired methods, constructors, descriptors, and properties can newly fail the gate. Pass include_members=False only when the old narrower scope is intentional.
  • Fix invalid remove_in versions. An unparsable remove_in now emits UserWarning during batch expiry instead of being skipped silently.
  • Fix misspelled CLI flags. Unknown flags now fail instead of being silently ignored.
  • Use named % fields in custom message templates. Bare %s or %d conversions now raise ValueError when the decorator is applied.

  • @deprecated(target=TargetMode.ATTRS_REMAP) now raises TypeError for a class source. It already raised for functions. ATTRS_REMAP needs the class-only attrs_mapping keyword, which the common front door does not expose, so a class source previously built a proxy that remapped nothing. Use deprecated_class(attrs_mapping=...).

  • Rename template_mgs to message_template on deprecated(), deprecated_callable(), deprecated_class(), and deprecated_instance(). The typo remains a warning alias until v1.0; supplying both names raises TypeError.
  • repr(), str(), equality, and hashing on a target-forwarding proxy now reflect the active target rather than the deprecated source.
  • In-place operators such as proxy += 1 rebind the name to the unwrapped result. Later uses are silent; avoid in-place operators if the proxy must retain its warning budget.
  • args_mapping, args_extra, and attrs_mapping are copied at decoration time. Mutating the original dict later no longer changes forwarding behavior.
  • Constructing an attrs_mapping-only class proxy is now silent; only access to a listed deprecated attribute warns.
  • Concurrent calls now respect exactly the configured num_warns budget. Tests that accidentally relied on one warning per racing thread will see fewer warnings.
  • Recursive audits deduplicate re-exports, include deprecated private and dunder members, warn and skip submodules that fail to import, and ignore unrelated foreign objects that raise during metadata probing. Counts and rows can therefore change in both directions.

  • @deprecated now defaults to TargetMode.AUTO. It resolves at decoration time: a function/class with args_mapping becomes ARGS_REMAP; a source without a mapping becomes warn-only. AUTO is never stored in DeprecationConfig; do not pass it explicitly because it exists only as the front-door default.

  • Existing @deprecated use on a class remains supported; no code change or decorator rewrite is required. It permanently delegates to deprecated_class() and emits one informational UserWarning per module-qualified class. stream=None suppresses the notice. Only the notice, not backward support or delegation, is removed in v1.0.
  • message_template and skip_if supplied through @deprecated on a class now reach the proxy. message_template was previously dropped on that path.
  • Non-callable sources now raise a direct TypeError pointing users to deprecated_instance() instead of failing later on __name__.
  • Explicit target=TargetMode.NOTIFY together with a mapping still emits UserWarning, stays NOTIFY, leaves the mapping inert, and is marked misconfigured — unchanged from v0.11.0, and a TypeError in v1.0. What changed is that an omitted target no longer lands here: it auto-resolves instead. Omit target to infer remapping, or select the matching remap mode explicitly.

Coming from v0.9.x🔗

  • Outer-order deprecated properties now warn on read, write, and delete. Under filterwarnings=error::FutureWarning, a setter or deleter that was previously silent now raises. If only reads should warn, keep inner order (@property outside @deprecated) or decorate only fget.

  • Update proxy detection. proxy.__class__ reports the wrapped object's type for isinstance transparency. Use type(proxy) when you need to detect _DeprecatedProxy itself.

  • Do not use an instance proxy as the second argument to isinstance() or issubclass(). This misuse now raises TypeError instead of returning False. Class-alias proxies remain valid there.
  • Review expiry CI scope. validate_deprecation_expiry() now defaults to include_members=True, so expired methods, constructors, descriptors, and properties can newly fail the gate. Pass include_members=False only when the old narrower scope is intentional.
  • Fix invalid remove_in versions. An unparsable remove_in now emits UserWarning during batch expiry instead of being skipped silently.
  • Fix misspelled CLI flags. Unknown flags now fail instead of being silently ignored.
  • Use named % fields in custom message templates. Bare %s or %d conversions now raise ValueError when the decorator is applied.

  • @deprecated(target=TargetMode.ATTRS_REMAP) now raises TypeError for a class source. It already raised for functions. ATTRS_REMAP needs the class-only attrs_mapping keyword, which the common front door does not expose, so a class source previously built a proxy that remapped nothing. Use deprecated_class(attrs_mapping=...).

  • Rename template_mgs to message_template on deprecated(), deprecated_callable(), deprecated_class(), and deprecated_instance(). The typo remains a warning alias until v1.0; supplying both names raises TypeError.
  • When a caller supplies both deprecated and replacement keyword names, the explicit replacement value now wins regardless of call-site order.
  • Circular callable-target chains now raise a named RuntimeError instead of ending in RecursionError.

  • repr(), str(), equality, and hashing on a target-forwarding proxy now reflect the active target rather than the deprecated source.

  • In-place operators such as proxy += 1 rebind the name to the unwrapped result. Later uses are silent; avoid in-place operators if the proxy must retain its warning budget.
  • args_mapping, args_extra, and attrs_mapping are copied at decoration time. Mutating the original dict later no longer changes forwarding behavior.
  • Constructing an attrs_mapping-only class proxy is now silent; only access to a listed deprecated attribute warns.
  • Concurrent calls now respect exactly the configured num_warns budget. Tests that accidentally relied on one warning per racing thread will see fewer warnings.
  • Recursive audits deduplicate re-exports, include deprecated private and dunder members, warn and skip submodules that fail to import, and ignore unrelated foreign objects that raise during metadata probing. Counts and rows can therefore change in both directions.

  • @deprecated now defaults to TargetMode.AUTO. It resolves at decoration time: a function/class with args_mapping becomes ARGS_REMAP; a source without a mapping becomes warn-only. AUTO is never stored in DeprecationConfig; do not pass it explicitly because it exists only as the front-door default.

  • Existing @deprecated use on a class remains supported; no code change or decorator rewrite is required. It permanently delegates to deprecated_class() and emits one informational UserWarning per module-qualified class. stream=None suppresses the notice. Only the notice, not backward support or delegation, is removed in v1.0.
  • message_template and skip_if supplied through @deprecated on a class now reach the proxy. message_template was previously dropped on that path.
  • Non-callable sources now raise a direct TypeError pointing users to deprecated_instance() instead of failing later on __name__.
  • Explicit target=TargetMode.NOTIFY together with a mapping still emits UserWarning, stays NOTIFY, leaves the mapping inert, and is marked misconfigured — unchanged from v0.11.0, and a TypeError in v1.0. What changed is that an omitted target no longer lands here: it auto-resolves instead. Omit target to infer remapping, or select the matching remap mode explicitly.

Coming from v0.8.x🔗

  • Rename the CLI flag --skip_errors to --exit-zero in every check, expiry, chains, and all command. The old flag is rejected. --exit_zero remains an underscore alias, but the dashed spelling is canonical.
  • Fix unsupported stacked decorators. Six shapes, including callable-over-callable, now emit UserWarning at decoration time and become TypeError in v1.0. The supported lifecycle stack is outer ARGS_REMAP plus inner NOTIFY.

  • Outer-order deprecated properties now warn on read, write, and delete. Under filterwarnings=error::FutureWarning, a setter or deleter that was previously silent now raises. If only reads should warn, keep inner order (@property outside @deprecated) or decorate only fget.

  • Update proxy detection. proxy.__class__ reports the wrapped object's type for isinstance transparency. Use type(proxy) when you need to detect _DeprecatedProxy itself.

  • Do not use an instance proxy as the second argument to isinstance() or issubclass(). This misuse now raises TypeError instead of returning False. Class-alias proxies remain valid there.
  • Review expiry CI scope. validate_deprecation_expiry() now defaults to include_members=True, so expired methods, constructors, descriptors, and properties can newly fail the gate. Pass include_members=False only when the old narrower scope is intentional.
  • Fix invalid remove_in versions. An unparsable remove_in now emits UserWarning during batch expiry instead of being skipped silently.
  • Fix misspelled CLI flags. Unknown flags now fail instead of being silently ignored.
  • Use named % fields in custom message templates. Bare %s or %d conversions now raise ValueError when the decorator is applied.

  • @deprecated(target=TargetMode.ATTRS_REMAP) now raises TypeError for a class source. It already raised for functions. ATTRS_REMAP needs the class-only attrs_mapping keyword, which the common front door does not expose, so a class source previously built a proxy that remapped nothing. Use deprecated_class(attrs_mapping=...).

  • Rename template_mgs to message_template on deprecated(), deprecated_callable(), deprecated_class(), and deprecated_instance(). The typo remains a warning alias until v1.0; supplying both names raises TypeError.
  • CLI scans suppress only warnings from deprecate.*; third-party warnings are now visible. CI that treats all warnings as errors may start failing on dependencies imported during a scan.
  • Audit code sees the supported ARGS_REMAP + NOTIFY chain as ChainType.STACKED, not ChainType.TARGET.

  • When a caller supplies both deprecated and replacement keyword names, the explicit replacement value now wins regardless of call-site order.

  • Circular callable-target chains now raise a named RuntimeError instead of ending in RecursionError.

  • repr(), str(), equality, and hashing on a target-forwarding proxy now reflect the active target rather than the deprecated source.

  • In-place operators such as proxy += 1 rebind the name to the unwrapped result. Later uses are silent; avoid in-place operators if the proxy must retain its warning budget.
  • args_mapping, args_extra, and attrs_mapping are copied at decoration time. Mutating the original dict later no longer changes forwarding behavior.
  • Constructing an attrs_mapping-only class proxy is now silent; only access to a listed deprecated attribute warns.
  • Concurrent calls now respect exactly the configured num_warns budget. Tests that accidentally relied on one warning per racing thread will see fewer warnings.
  • Recursive audits deduplicate re-exports, include deprecated private and dunder members, warn and skip submodules that fail to import, and ignore unrelated foreign objects that raise during metadata probing. Counts and rows can therefore change in both directions.

  • @deprecated now defaults to TargetMode.AUTO. It resolves at decoration time: a function/class with args_mapping becomes ARGS_REMAP; a source without a mapping becomes warn-only. AUTO is never stored in DeprecationConfig; do not pass it explicitly because it exists only as the front-door default.

  • Existing @deprecated use on a class remains supported; no code change or decorator rewrite is required. It permanently delegates to deprecated_class() and emits one informational UserWarning per module-qualified class. stream=None suppresses the notice. Only the notice, not backward support or delegation, is removed in v1.0.
  • message_template and skip_if supplied through @deprecated on a class now reach the proxy. message_template was previously dropped on that path.
  • Non-callable sources now raise a direct TypeError pointing users to deprecated_instance() instead of failing later on __name__.
  • Explicit target=TargetMode.NOTIFY together with a mapping still emits UserWarning, stays NOTIFY, leaves the mapping inert, and is marked misconfigured — unchanged from v0.11.0, and a TypeError in v1.0. What changed is that an omitted target no longer lands here: it auto-resolves instead. Omit target to infer remapping, or select the matching remap mode explicitly.

Coming from v0.7.x🔗

  • Replace target=None with TargetMode.NOTIFY or omit target for a warn-only decorator.
  • Replace target=True with TargetMode.ARGS_REMAP.
  • Replace DeprecationWrapperInfo.empty_mapping with empty_args_mapping, and identity_mapping with identity_args_mapping. The old properties warn and are removed in v1.0.
  • If code inspects wrapper.__deprecated__.target, compare with a TargetMode, callable, or None. DeprecationConfig.target stores a normalized value, never legacy True or False.
  • Update external documentation bookmarks from flat paths such as /pyDeprecate/troubleshooting.html to the versioned /pyDeprecate/stable/troubleshooting.html layout.

  • Rename the CLI flag --skip_errors to --exit-zero in every check, expiry, chains, and all command. The old flag is rejected. --exit_zero remains an underscore alias, but the dashed spelling is canonical.

  • Fix unsupported stacked decorators. Six shapes, including callable-over-callable, now emit UserWarning at decoration time and become TypeError in v1.0. The supported lifecycle stack is outer ARGS_REMAP plus inner NOTIFY.

  • Outer-order deprecated properties now warn on read, write, and delete. Under filterwarnings=error::FutureWarning, a setter or deleter that was previously silent now raises. If only reads should warn, keep inner order (@property outside @deprecated) or decorate only fget.

  • Update proxy detection. proxy.__class__ reports the wrapped object's type for isinstance transparency. Use type(proxy) when you need to detect _DeprecatedProxy itself.

  • Do not use an instance proxy as the second argument to isinstance() or issubclass(). This misuse now raises TypeError instead of returning False. Class-alias proxies remain valid there.
  • Review expiry CI scope. validate_deprecation_expiry() now defaults to include_members=True, so expired methods, constructors, descriptors, and properties can newly fail the gate. Pass include_members=False only when the old narrower scope is intentional.
  • Fix invalid remove_in versions. An unparsable remove_in now emits UserWarning during batch expiry instead of being skipped silently.
  • Fix misspelled CLI flags. Unknown flags now fail instead of being silently ignored.
  • Use named % fields in custom message templates. Bare %s or %d conversions now raise ValueError when the decorator is applied.

  • @deprecated(target=TargetMode.ATTRS_REMAP) now raises TypeError for a class source. It already raised for functions. ATTRS_REMAP needs the class-only attrs_mapping keyword, which the common front door does not expose, so a class source previously built a proxy that remapped nothing. Use deprecated_class(attrs_mapping=...).

  • Rename template_mgs to message_template on deprecated(), deprecated_callable(), deprecated_class(), and deprecated_instance(). The typo remains a warning alias until v1.0; supplying both names raises TypeError.
  • Omitting deprecated_in on a function or method emits UserWarning at decoration time. Add the version as part of every deprecation lifecycle.
  • ARGS_REMAP without args_mapping, NOTIFY with args_mapping or args_extra, and invalid target=False now warn immediately. These are migration failures, not harmless diagnostics; correct them before v1.0.
  • Omitting target is the canonical warn-only form. Its v0.12 default is TargetMode.AUTO, which resolves to NOTIFY when no mapping is present, so the user-visible result is unchanged.

  • CLI scans suppress only warnings from deprecate.*; third-party warnings are now visible. CI that treats all warnings as errors may start failing on dependencies imported during a scan.

  • Audit code sees the supported ARGS_REMAP + NOTIFY chain as ChainType.STACKED, not ChainType.TARGET.

  • When a caller supplies both deprecated and replacement keyword names, the explicit replacement value now wins regardless of call-site order.

  • Circular callable-target chains now raise a named RuntimeError instead of ending in RecursionError.

  • repr(), str(), equality, and hashing on a target-forwarding proxy now reflect the active target rather than the deprecated source.

  • In-place operators such as proxy += 1 rebind the name to the unwrapped result. Later uses are silent; avoid in-place operators if the proxy must retain its warning budget.
  • args_mapping, args_extra, and attrs_mapping are copied at decoration time. Mutating the original dict later no longer changes forwarding behavior.
  • Constructing an attrs_mapping-only class proxy is now silent; only access to a listed deprecated attribute warns.
  • Concurrent calls now respect exactly the configured num_warns budget. Tests that accidentally relied on one warning per racing thread will see fewer warnings.
  • Recursive audits deduplicate re-exports, include deprecated private and dunder members, warn and skip submodules that fail to import, and ignore unrelated foreign objects that raise during metadata probing. Counts and rows can therefore change in both directions.

  • @deprecated now defaults to TargetMode.AUTO. It resolves at decoration time: a function/class with args_mapping becomes ARGS_REMAP; a source without a mapping becomes warn-only. AUTO is never stored in DeprecationConfig; do not pass it explicitly because it exists only as the front-door default.

  • Existing @deprecated use on a class remains supported; no code change or decorator rewrite is required. It permanently delegates to deprecated_class() and emits one informational UserWarning per module-qualified class. stream=None suppresses the notice. Only the notice, not backward support or delegation, is removed in v1.0.
  • message_template and skip_if supplied through @deprecated on a class now reach the proxy. message_template was previously dropped on that path.
  • Non-callable sources now raise a direct TypeError pointing users to deprecated_instance() instead of failing later on __name__.
  • Explicit target=TargetMode.NOTIFY together with a mapping still emits UserWarning, stays NOTIFY, leaves the mapping inert, and is marked misconfigured — unchanged from v0.11.0, and a TypeError in v1.0. What changed is that an omitted target no longer lands here: it auto-resolves instead. Omit target to infer remapping, or select the matching remap mode explicitly.

Coming from v0.6.x🔗

  • Replace target=None with TargetMode.NOTIFY or omit target for a warn-only decorator.
  • Replace target=True with TargetMode.ARGS_REMAP.
  • Replace DeprecationWrapperInfo.empty_mapping with empty_args_mapping, and identity_mapping with identity_args_mapping. The old properties warn and are removed in v1.0.
  • If code inspects wrapper.__deprecated__.target, compare with a TargetMode, callable, or None. DeprecationConfig.target stores a normalized value, never legacy True or False.
  • Update external documentation bookmarks from flat paths such as /pyDeprecate/troubleshooting.html to the versioned /pyDeprecate/stable/troubleshooting.html layout.

  • Rename the CLI flag --skip_errors to --exit-zero in every check, expiry, chains, and all command. The old flag is rejected. --exit_zero remains an underscore alias, but the dashed spelling is canonical.

  • Fix unsupported stacked decorators. Six shapes, including callable-over-callable, now emit UserWarning at decoration time and become TypeError in v1.0. The supported lifecycle stack is outer ARGS_REMAP plus inner NOTIFY.

  • Outer-order deprecated properties now warn on read, write, and delete. Under filterwarnings=error::FutureWarning, a setter or deleter that was previously silent now raises. If only reads should warn, keep inner order (@property outside @deprecated) or decorate only fget.

  • Update proxy detection. proxy.__class__ reports the wrapped object's type for isinstance transparency. Use type(proxy) when you need to detect _DeprecatedProxy itself.

  • Do not use an instance proxy as the second argument to isinstance() or issubclass(). This misuse now raises TypeError instead of returning False. Class-alias proxies remain valid there.
  • Review expiry CI scope. validate_deprecation_expiry() now defaults to include_members=True, so expired methods, constructors, descriptors, and properties can newly fail the gate. Pass include_members=False only when the old narrower scope is intentional.
  • Fix invalid remove_in versions. An unparsable remove_in now emits UserWarning during batch expiry instead of being skipped silently.
  • Fix misspelled CLI flags. Unknown flags now fail instead of being silently ignored.
  • Use named % fields in custom message templates. Bare %s or %d conversions now raise ValueError when the decorator is applied.

  • @deprecated(target=TargetMode.ATTRS_REMAP) now raises TypeError for a class source. It already raised for functions. ATTRS_REMAP needs the class-only attrs_mapping keyword, which the common front door does not expose, so a class source previously built a proxy that remapped nothing. Use deprecated_class(attrs_mapping=...).

  • Rename template_mgs to message_template on deprecated(), deprecated_callable(), deprecated_class(), and deprecated_instance(). The typo remains a warning alias until v1.0; supplying both names raises TypeError.
  • Omitting deprecated_in on a function or method emits UserWarning at decoration time. Add the version as part of every deprecation lifecycle.
  • ARGS_REMAP without args_mapping, NOTIFY with args_mapping or args_extra, and invalid target=False now warn immediately. These are migration failures, not harmless diagnostics; correct them before v1.0.
  • Omitting target is the canonical warn-only form. Its v0.12 default is TargetMode.AUTO, which resolves to NOTIFY when no mapping is present, so the user-visible result is unchanged.

  • CLI scans suppress only warnings from deprecate.*; third-party warnings are now visible. CI that treats all warnings as errors may start failing on dependencies imported during a scan.

  • Audit code sees the supported ARGS_REMAP + NOTIFY chain as ChainType.STACKED, not ChainType.TARGET.

  • When a caller supplies both deprecated and replacement keyword names, the explicit replacement value now wins regardless of call-site order.

  • Circular callable-target chains now raise a named RuntimeError instead of ending in RecursionError.

  • repr(), str(), equality, and hashing on a target-forwarding proxy now reflect the active target rather than the deprecated source.

  • In-place operators such as proxy += 1 rebind the name to the unwrapped result. Later uses are silent; avoid in-place operators if the proxy must retain its warning budget.
  • args_mapping, args_extra, and attrs_mapping are copied at decoration time. Mutating the original dict later no longer changes forwarding behavior.
  • Constructing an attrs_mapping-only class proxy is now silent; only access to a listed deprecated attribute warns.
  • Concurrent calls now respect exactly the configured num_warns budget. Tests that accidentally relied on one warning per racing thread will see fewer warnings.
  • Recursive audits deduplicate re-exports, include deprecated private and dunder members, warn and skip submodules that fail to import, and ignore unrelated foreign objects that raise during metadata probing. Counts and rows can therefore change in both directions.

  • @deprecated now defaults to TargetMode.AUTO. It resolves at decoration time: a function/class with args_mapping becomes ARGS_REMAP; a source without a mapping becomes warn-only. AUTO is never stored in DeprecationConfig; do not pass it explicitly because it exists only as the front-door default.

  • Existing @deprecated use on a class remains supported; no code change or decorator rewrite is required. It permanently delegates to deprecated_class() and emits one informational UserWarning per module-qualified class. stream=None suppresses the notice. Only the notice, not backward support or delegation, is removed in v1.0.
  • message_template and skip_if supplied through @deprecated on a class now reach the proxy. message_template was previously dropped on that path.
  • Non-callable sources now raise a direct TypeError pointing users to deprecated_instance() instead of failing later on __name__.
  • Explicit target=TargetMode.NOTIFY together with a mapping still emits UserWarning, stays NOTIFY, leaves the mapping inert, and is marked misconfigured — unchanged from v0.11.0, and a TypeError in v1.0. What changed is that an omitted target no longer lands here: it auto-resolves instead. Omit target to infer remapping, or select the matching remap mode explicitly.

Coming from v0.5.x🔗

  • Fix cross-class method forwarding. Passing a class target to a non-__init__ instance method now raises TypeError at decoration time instead of forwarding a self of the wrong type.

  • Replace API names deprecated until v1.0:

    Deprecated API Replacement
    find_deprecated_callables find_deprecation_wrappers
    validate_deprecated_callable validate_deprecation_wrapper
    DeprecatedCallableInfo DeprecationWrapperInfo
    no_warning_call assert_no_warnings
  • Replace target=None with TargetMode.NOTIFY or omit target for a warn-only decorator.

  • Replace target=True with TargetMode.ARGS_REMAP.
  • Replace DeprecationWrapperInfo.empty_mapping with empty_args_mapping, and identity_mapping with identity_args_mapping. The old properties warn and are removed in v1.0.
  • If code inspects wrapper.__deprecated__.target, compare with a TargetMode, callable, or None. DeprecationConfig.target stores a normalized value, never legacy True or False.
  • Update external documentation bookmarks from flat paths such as /pyDeprecate/troubleshooting.html to the versioned /pyDeprecate/stable/troubleshooting.html layout.

  • Rename the CLI flag --skip_errors to --exit-zero in every check, expiry, chains, and all command. The old flag is rejected. --exit_zero remains an underscore alias, but the dashed spelling is canonical.

  • Fix unsupported stacked decorators. Six shapes, including callable-over-callable, now emit UserWarning at decoration time and become TypeError in v1.0. The supported lifecycle stack is outer ARGS_REMAP plus inner NOTIFY.

  • Outer-order deprecated properties now warn on read, write, and delete. Under filterwarnings=error::FutureWarning, a setter or deleter that was previously silent now raises. If only reads should warn, keep inner order (@property outside @deprecated) or decorate only fget.

  • Update proxy detection. proxy.__class__ reports the wrapped object's type for isinstance transparency. Use type(proxy) when you need to detect _DeprecatedProxy itself.

  • Do not use an instance proxy as the second argument to isinstance() or issubclass(). This misuse now raises TypeError instead of returning False. Class-alias proxies remain valid there.
  • Review expiry CI scope. validate_deprecation_expiry() now defaults to include_members=True, so expired methods, constructors, descriptors, and properties can newly fail the gate. Pass include_members=False only when the old narrower scope is intentional.
  • Fix invalid remove_in versions. An unparsable remove_in now emits UserWarning during batch expiry instead of being skipped silently.
  • Fix misspelled CLI flags. Unknown flags now fail instead of being silently ignored.
  • Use named % fields in custom message templates. Bare %s or %d conversions now raise ValueError when the decorator is applied.

  • @deprecated(target=TargetMode.ATTRS_REMAP) now raises TypeError for a class source. It already raised for functions. ATTRS_REMAP needs the class-only attrs_mapping keyword, which the common front door does not expose, so a class source previously built a proxy that remapped nothing. Use deprecated_class(attrs_mapping=...).

  • Rename template_mgs to message_template on deprecated(), deprecated_callable(), deprecated_class(), and deprecated_instance(). The typo remains a warning alias until v1.0; supplying both names raises TypeError.
  • Across the v0.6.x line, backward support for @deprecated on a class was restored through delegation to deprecated_class(). Existing class decorators need no rewrite for v0.12; delegation remains permanent and only its informational notice is scheduled for removal.

  • Omitting deprecated_in on a function or method emits UserWarning at decoration time. Add the version as part of every deprecation lifecycle.

  • ARGS_REMAP without args_mapping, NOTIFY with args_mapping or args_extra, and invalid target=False now warn immediately. These are migration failures, not harmless diagnostics; correct them before v1.0.
  • Omitting target is the canonical warn-only form. Its v0.12 default is TargetMode.AUTO, which resolves to NOTIFY when no mapping is present, so the user-visible result is unchanged.

  • CLI scans suppress only warnings from deprecate.*; third-party warnings are now visible. CI that treats all warnings as errors may start failing on dependencies imported during a scan.

  • Audit code sees the supported ARGS_REMAP + NOTIFY chain as ChainType.STACKED, not ChainType.TARGET.

  • When a caller supplies both deprecated and replacement keyword names, the explicit replacement value now wins regardless of call-site order.

  • Circular callable-target chains now raise a named RuntimeError instead of ending in RecursionError.

  • repr(), str(), equality, and hashing on a target-forwarding proxy now reflect the active target rather than the deprecated source.

  • In-place operators such as proxy += 1 rebind the name to the unwrapped result. Later uses are silent; avoid in-place operators if the proxy must retain its warning budget.
  • args_mapping, args_extra, and attrs_mapping are copied at decoration time. Mutating the original dict later no longer changes forwarding behavior.
  • Constructing an attrs_mapping-only class proxy is now silent; only access to a listed deprecated attribute warns.
  • Concurrent calls now respect exactly the configured num_warns budget. Tests that accidentally relied on one warning per racing thread will see fewer warnings.
  • Recursive audits deduplicate re-exports, include deprecated private and dunder members, warn and skip submodules that fail to import, and ignore unrelated foreign objects that raise during metadata probing. Counts and rows can therefore change in both directions.

  • @deprecated now defaults to TargetMode.AUTO. It resolves at decoration time: a function/class with args_mapping becomes ARGS_REMAP; a source without a mapping becomes warn-only. AUTO is never stored in DeprecationConfig; do not pass it explicitly because it exists only as the front-door default.

  • Existing @deprecated use on a class remains supported; no code change or decorator rewrite is required. It permanently delegates to deprecated_class() and emits one informational UserWarning per module-qualified class. stream=None suppresses the notice. Only the notice, not backward support or delegation, is removed in v1.0.
  • message_template and skip_if supplied through @deprecated on a class now reach the proxy. message_template was previously dropped on that path.
  • Non-callable sources now raise a direct TypeError pointing users to deprecated_instance() instead of failing later on __name__.
  • Explicit target=TargetMode.NOTIFY together with a mapping still emits UserWarning, stays NOTIFY, leaves the mapping inert, and is marked misconfigured — unchanged from v0.11.0, and a TypeError in v1.0. What changed is that an omitted target no longer lands here: it auto-resolves instead. Omit target to infer remapping, or select the matching remap mode explicitly.

Coming from v0.4.x🔗

  • Fix cross-class method forwarding. Passing a class target to a non-__init__ instance method now raises TypeError at decoration time instead of forwarding a self of the wrong type.

  • Replace API names deprecated until v1.0:

    Deprecated API Replacement
    find_deprecated_callables find_deprecation_wrappers
    validate_deprecated_callable validate_deprecation_wrapper
    DeprecatedCallableInfo DeprecationWrapperInfo
    no_warning_call assert_no_warnings
  • Replace target=None with TargetMode.NOTIFY or omit target for a warn-only decorator.

  • Replace target=True with TargetMode.ARGS_REMAP.
  • Replace DeprecationWrapperInfo.empty_mapping with empty_args_mapping, and identity_mapping with identity_args_mapping. The old properties warn and are removed in v1.0.
  • If code inspects wrapper.__deprecated__.target, compare with a TargetMode, callable, or None. DeprecationConfig.target stores a normalized value, never legacy True or False.
  • Update external documentation bookmarks from flat paths such as /pyDeprecate/troubleshooting.html to the versioned /pyDeprecate/stable/troubleshooting.html layout.

  • Rename the CLI flag --skip_errors to --exit-zero in every check, expiry, chains, and all command. The old flag is rejected. --exit_zero remains an underscore alias, but the dashed spelling is canonical.

  • Fix unsupported stacked decorators. Six shapes, including callable-over-callable, now emit UserWarning at decoration time and become TypeError in v1.0. The supported lifecycle stack is outer ARGS_REMAP plus inner NOTIFY.

  • Outer-order deprecated properties now warn on read, write, and delete. Under filterwarnings=error::FutureWarning, a setter or deleter that was previously silent now raises. If only reads should warn, keep inner order (@property outside @deprecated) or decorate only fget.

  • Update proxy detection. proxy.__class__ reports the wrapped object's type for isinstance transparency. Use type(proxy) when you need to detect _DeprecatedProxy itself.

  • Do not use an instance proxy as the second argument to isinstance() or issubclass(). This misuse now raises TypeError instead of returning False. Class-alias proxies remain valid there.
  • Review expiry CI scope. validate_deprecation_expiry() now defaults to include_members=True, so expired methods, constructors, descriptors, and properties can newly fail the gate. Pass include_members=False only when the old narrower scope is intentional.
  • Fix invalid remove_in versions. An unparsable remove_in now emits UserWarning during batch expiry instead of being skipped silently.
  • Fix misspelled CLI flags. Unknown flags now fail instead of being silently ignored.
  • Use named % fields in custom message templates. Bare %s or %d conversions now raise ValueError when the decorator is applied.

  • @deprecated(target=TargetMode.ATTRS_REMAP) now raises TypeError for a class source. It already raised for functions. ATTRS_REMAP needs the class-only attrs_mapping keyword, which the common front door does not expose, so a class source previously built a proxy that remapped nothing. Use deprecated_class(attrs_mapping=...).

  • Rename template_mgs to message_template on deprecated(), deprecated_callable(), deprecated_class(), and deprecated_instance(). The typo remains a warning alias until v1.0; supplying both names raises TypeError.
  • Across the v0.6.x line, backward support for @deprecated on a class was restored through delegation to deprecated_class(). Existing class decorators need no rewrite for v0.12; delegation remains permanent and only its informational notice is scheduled for removal.

  • Omitting deprecated_in on a function or method emits UserWarning at decoration time. Add the version as part of every deprecation lifecycle.

  • ARGS_REMAP without args_mapping, NOTIFY with args_mapping or args_extra, and invalid target=False now warn immediately. These are migration failures, not harmless diagnostics; correct them before v1.0.
  • Omitting target is the canonical warn-only form. Its v0.12 default is TargetMode.AUTO, which resolves to NOTIFY when no mapping is present, so the user-visible result is unchanged.

  • CLI scans suppress only warnings from deprecate.*; third-party warnings are now visible. CI that treats all warnings as errors may start failing on dependencies imported during a scan.

  • Audit code sees the supported ARGS_REMAP + NOTIFY chain as ChainType.STACKED, not ChainType.TARGET.

  • When a caller supplies both deprecated and replacement keyword names, the explicit replacement value now wins regardless of call-site order.

  • Circular callable-target chains now raise a named RuntimeError instead of ending in RecursionError.

  • repr(), str(), equality, and hashing on a target-forwarding proxy now reflect the active target rather than the deprecated source.

  • In-place operators such as proxy += 1 rebind the name to the unwrapped result. Later uses are silent; avoid in-place operators if the proxy must retain its warning budget.
  • args_mapping, args_extra, and attrs_mapping are copied at decoration time. Mutating the original dict later no longer changes forwarding behavior.
  • Constructing an attrs_mapping-only class proxy is now silent; only access to a listed deprecated attribute warns.
  • Concurrent calls now respect exactly the configured num_warns budget. Tests that accidentally relied on one warning per racing thread will see fewer warnings.
  • Recursive audits deduplicate re-exports, include deprecated private and dunder members, warn and skip submodules that fail to import, and ignore unrelated foreign objects that raise during metadata probing. Counts and rows can therefore change in both directions.

  • @deprecated now defaults to TargetMode.AUTO. It resolves at decoration time: a function/class with args_mapping becomes ARGS_REMAP; a source without a mapping becomes warn-only. AUTO is never stored in DeprecationConfig; do not pass it explicitly because it exists only as the front-door default.

  • Existing @deprecated use on a class remains supported; no code change or decorator rewrite is required. It permanently delegates to deprecated_class() and emits one informational UserWarning per module-qualified class. stream=None suppresses the notice. Only the notice, not backward support or delegation, is removed in v1.0.
  • message_template and skip_if supplied through @deprecated on a class now reach the proxy. message_template was previously dropped on that path.
  • Non-callable sources now raise a direct TypeError pointing users to deprecated_instance() instead of failing later on __name__.
  • Explicit target=TargetMode.NOTIFY together with a mapping still emits UserWarning, stays NOTIFY, leaves the mapping inert, and is marked misconfigured — unchanged from v0.11.0, and a TypeError in v1.0. What changed is that an omitted target no longer lands here: it auto-resolves instead. Omit target to infer remapping, or select the matching remap mode explicitly.

Coming from v0.3.x🔗

  • Update warning filters and assertions from DeprecationWarning to FutureWarning. Application users now see the warnings under Python's default filters.
  • Run on Python 3.9 or newer. Python 3.8 support was removed.
  • Review the license change from MIT to Apache-2.0 if your distribution or compliance process records dependency licenses.

  • Fix cross-class method forwarding. Passing a class target to a non-__init__ instance method now raises TypeError at decoration time instead of forwarding a self of the wrong type.

  • Replace API names deprecated until v1.0:

    Deprecated API Replacement
    find_deprecated_callables find_deprecation_wrappers
    validate_deprecated_callable validate_deprecation_wrapper
    DeprecatedCallableInfo DeprecationWrapperInfo
    no_warning_call assert_no_warnings
  • Replace target=None with TargetMode.NOTIFY or omit target for a warn-only decorator.

  • Replace target=True with TargetMode.ARGS_REMAP.
  • Replace DeprecationWrapperInfo.empty_mapping with empty_args_mapping, and identity_mapping with identity_args_mapping. The old properties warn and are removed in v1.0.
  • If code inspects wrapper.__deprecated__.target, compare with a TargetMode, callable, or None. DeprecationConfig.target stores a normalized value, never legacy True or False.
  • Update external documentation bookmarks from flat paths such as /pyDeprecate/troubleshooting.html to the versioned /pyDeprecate/stable/troubleshooting.html layout.

  • Rename the CLI flag --skip_errors to --exit-zero in every check, expiry, chains, and all command. The old flag is rejected. --exit_zero remains an underscore alias, but the dashed spelling is canonical.

  • Fix unsupported stacked decorators. Six shapes, including callable-over-callable, now emit UserWarning at decoration time and become TypeError in v1.0. The supported lifecycle stack is outer ARGS_REMAP plus inner NOTIFY.

  • Outer-order deprecated properties now warn on read, write, and delete. Under filterwarnings=error::FutureWarning, a setter or deleter that was previously silent now raises. If only reads should warn, keep inner order (@property outside @deprecated) or decorate only fget.

  • Update proxy detection. proxy.__class__ reports the wrapped object's type for isinstance transparency. Use type(proxy) when you need to detect _DeprecatedProxy itself.

  • Do not use an instance proxy as the second argument to isinstance() or issubclass(). This misuse now raises TypeError instead of returning False. Class-alias proxies remain valid there.
  • Review expiry CI scope. validate_deprecation_expiry() now defaults to include_members=True, so expired methods, constructors, descriptors, and properties can newly fail the gate. Pass include_members=False only when the old narrower scope is intentional.
  • Fix invalid remove_in versions. An unparsable remove_in now emits UserWarning during batch expiry instead of being skipped silently.
  • Fix misspelled CLI flags. Unknown flags now fail instead of being silently ignored.
  • Use named % fields in custom message templates. Bare %s or %d conversions now raise ValueError when the decorator is applied.

  • @deprecated(target=TargetMode.ATTRS_REMAP) now raises TypeError for a class source. It already raised for functions. ATTRS_REMAP needs the class-only attrs_mapping keyword, which the common front door does not expose, so a class source previously built a proxy that remapped nothing. Use deprecated_class(attrs_mapping=...).

  • Rename template_mgs to message_template on deprecated(), deprecated_callable(), deprecated_class(), and deprecated_instance(). The typo remains a warning alias until v1.0; supplying both names raises TypeError.
  • Mapping errors now include the originating class or function name. Tests that assert complete error strings may need updated expected text.

  • Across the v0.6.x line, backward support for @deprecated on a class was restored through delegation to deprecated_class(). Existing class decorators need no rewrite for v0.12; delegation remains permanent and only its informational notice is scheduled for removal.

  • Omitting deprecated_in on a function or method emits UserWarning at decoration time. Add the version as part of every deprecation lifecycle.

  • ARGS_REMAP without args_mapping, NOTIFY with args_mapping or args_extra, and invalid target=False now warn immediately. These are migration failures, not harmless diagnostics; correct them before v1.0.
  • Omitting target is the canonical warn-only form. Its v0.12 default is TargetMode.AUTO, which resolves to NOTIFY when no mapping is present, so the user-visible result is unchanged.

  • CLI scans suppress only warnings from deprecate.*; third-party warnings are now visible. CI that treats all warnings as errors may start failing on dependencies imported during a scan.

  • Audit code sees the supported ARGS_REMAP + NOTIFY chain as ChainType.STACKED, not ChainType.TARGET.

  • When a caller supplies both deprecated and replacement keyword names, the explicit replacement value now wins regardless of call-site order.

  • Circular callable-target chains now raise a named RuntimeError instead of ending in RecursionError.

  • repr(), str(), equality, and hashing on a target-forwarding proxy now reflect the active target rather than the deprecated source.

  • In-place operators such as proxy += 1 rebind the name to the unwrapped result. Later uses are silent; avoid in-place operators if the proxy must retain its warning budget.
  • args_mapping, args_extra, and attrs_mapping are copied at decoration time. Mutating the original dict later no longer changes forwarding behavior.
  • Constructing an attrs_mapping-only class proxy is now silent; only access to a listed deprecated attribute warns.
  • Concurrent calls now respect exactly the configured num_warns budget. Tests that accidentally relied on one warning per racing thread will see fewer warnings.
  • Recursive audits deduplicate re-exports, include deprecated private and dunder members, warn and skip submodules that fail to import, and ignore unrelated foreign objects that raise during metadata probing. Counts and rows can therefore change in both directions.

  • @deprecated now defaults to TargetMode.AUTO. It resolves at decoration time: a function/class with args_mapping becomes ARGS_REMAP; a source without a mapping becomes warn-only. AUTO is never stored in DeprecationConfig; do not pass it explicitly because it exists only as the front-door default.

  • Existing @deprecated use on a class remains supported; no code change or decorator rewrite is required. It permanently delegates to deprecated_class() and emits one informational UserWarning per module-qualified class. stream=None suppresses the notice. Only the notice, not backward support or delegation, is removed in v1.0.
  • message_template and skip_if supplied through @deprecated on a class now reach the proxy. message_template was previously dropped on that path.
  • Non-callable sources now raise a direct TypeError pointing users to deprecated_instance() instead of failing later on __name__.
  • Explicit target=TargetMode.NOTIFY together with a mapping still emits UserWarning, stays NOTIFY, leaves the mapping inert, and is marked misconfigured — unchanged from v0.11.0, and a TypeError in v1.0. What changed is that an omitted target no longer lands here: it auto-resolves instead. Omit target to infer remapping, or select the matching remap mode explicitly.

Coming from v0.2.x🔗

  • Update warning filters and assertions from DeprecationWarning to FutureWarning. Application users now see the warnings under Python's default filters.
  • Run on Python 3.9 or newer. Python 3.8 support was removed.
  • Review the license change from MIT to Apache-2.0 if your distribution or compliance process records dependency licenses.

  • Fix cross-class method forwarding. Passing a class target to a non-__init__ instance method now raises TypeError at decoration time instead of forwarding a self of the wrong type.

  • Replace API names deprecated until v1.0:

    Deprecated API Replacement
    find_deprecated_callables find_deprecation_wrappers
    validate_deprecated_callable validate_deprecation_wrapper
    DeprecatedCallableInfo DeprecationWrapperInfo
    no_warning_call assert_no_warnings
  • Replace target=None with TargetMode.NOTIFY or omit target for a warn-only decorator.

  • Replace target=True with TargetMode.ARGS_REMAP.
  • Replace DeprecationWrapperInfo.empty_mapping with empty_args_mapping, and identity_mapping with identity_args_mapping. The old properties warn and are removed in v1.0.
  • If code inspects wrapper.__deprecated__.target, compare with a TargetMode, callable, or None. DeprecationConfig.target stores a normalized value, never legacy True or False.
  • Update external documentation bookmarks from flat paths such as /pyDeprecate/troubleshooting.html to the versioned /pyDeprecate/stable/troubleshooting.html layout.

  • Rename the CLI flag --skip_errors to --exit-zero in every check, expiry, chains, and all command. The old flag is rejected. --exit_zero remains an underscore alias, but the dashed spelling is canonical.

  • Fix unsupported stacked decorators. Six shapes, including callable-over-callable, now emit UserWarning at decoration time and become TypeError in v1.0. The supported lifecycle stack is outer ARGS_REMAP plus inner NOTIFY.

  • Outer-order deprecated properties now warn on read, write, and delete. Under filterwarnings=error::FutureWarning, a setter or deleter that was previously silent now raises. If only reads should warn, keep inner order (@property outside @deprecated) or decorate only fget.

  • Update proxy detection. proxy.__class__ reports the wrapped object's type for isinstance transparency. Use type(proxy) when you need to detect _DeprecatedProxy itself.

  • Do not use an instance proxy as the second argument to isinstance() or issubclass(). This misuse now raises TypeError instead of returning False. Class-alias proxies remain valid there.
  • Review expiry CI scope. validate_deprecation_expiry() now defaults to include_members=True, so expired methods, constructors, descriptors, and properties can newly fail the gate. Pass include_members=False only when the old narrower scope is intentional.
  • Fix invalid remove_in versions. An unparsable remove_in now emits UserWarning during batch expiry instead of being skipped silently.
  • Fix misspelled CLI flags. Unknown flags now fail instead of being silently ignored.
  • Use named % fields in custom message templates. Bare %s or %d conversions now raise ValueError when the decorator is applied.

  • @deprecated(target=TargetMode.ATTRS_REMAP) now raises TypeError for a class source. It already raised for functions. ATTRS_REMAP needs the class-only attrs_mapping keyword, which the common front door does not expose, so a class source previously built a proxy that remapped nothing. Use deprecated_class(attrs_mapping=...).

  • Rename template_mgs to message_template on deprecated(), deprecated_callable(), deprecated_class(), and deprecated_instance(). The typo remains a warning alias until v1.0; supplying both names raises TypeError.
  • Mapping errors now include the originating class or function name. Tests that assert complete error strings may need updated expected text.

  • Across the v0.6.x line, backward support for @deprecated on a class was restored through delegation to deprecated_class(). Existing class decorators need no rewrite for v0.12; delegation remains permanent and only its informational notice is scheduled for removal.

  • Omitting deprecated_in on a function or method emits UserWarning at decoration time. Add the version as part of every deprecation lifecycle.

  • ARGS_REMAP without args_mapping, NOTIFY with args_mapping or args_extra, and invalid target=False now warn immediately. These are migration failures, not harmless diagnostics; correct them before v1.0.
  • Omitting target is the canonical warn-only form. Its v0.12 default is TargetMode.AUTO, which resolves to NOTIFY when no mapping is present, so the user-visible result is unchanged.

  • CLI scans suppress only warnings from deprecate.*; third-party warnings are now visible. CI that treats all warnings as errors may start failing on dependencies imported during a scan.

  • Audit code sees the supported ARGS_REMAP + NOTIFY chain as ChainType.STACKED, not ChainType.TARGET.

  • When a caller supplies both deprecated and replacement keyword names, the explicit replacement value now wins regardless of call-site order.

  • Circular callable-target chains now raise a named RuntimeError instead of ending in RecursionError.

  • repr(), str(), equality, and hashing on a target-forwarding proxy now reflect the active target rather than the deprecated source.

  • In-place operators such as proxy += 1 rebind the name to the unwrapped result. Later uses are silent; avoid in-place operators if the proxy must retain its warning budget.
  • args_mapping, args_extra, and attrs_mapping are copied at decoration time. Mutating the original dict later no longer changes forwarding behavior.
  • Constructing an attrs_mapping-only class proxy is now silent; only access to a listed deprecated attribute warns.
  • Concurrent calls now respect exactly the configured num_warns budget. Tests that accidentally relied on one warning per racing thread will see fewer warnings.
  • Recursive audits deduplicate re-exports, include deprecated private and dunder members, warn and skip submodules that fail to import, and ignore unrelated foreign objects that raise during metadata probing. Counts and rows can therefore change in both directions.

  • @deprecated now defaults to TargetMode.AUTO. It resolves at decoration time: a function/class with args_mapping becomes ARGS_REMAP; a source without a mapping becomes warn-only. AUTO is never stored in DeprecationConfig; do not pass it explicitly because it exists only as the front-door default.

  • Existing @deprecated use on a class remains supported; no code change or decorator rewrite is required. It permanently delegates to deprecated_class() and emits one informational UserWarning per module-qualified class. stream=None suppresses the notice. Only the notice, not backward support or delegation, is removed in v1.0.
  • message_template and skip_if supplied through @deprecated on a class now reach the proxy. message_template was previously dropped on that path.
  • Non-callable sources now raise a direct TypeError pointing users to deprecated_instance() instead of failing later on __name__.
  • Explicit target=TargetMode.NOTIFY together with a mapping still emits UserWarning, stays NOTIFY, leaves the mapping inert, and is marked misconfigured — unchanged from v0.11.0, and a TypeError in v1.0. What changed is that an omitted target no longer lands here: it auto-resolves instead. Omit target to infer remapping, or select the matching remap mode explicitly.

Coming from v0.1.x🔗

  • Update warning filters and assertions from DeprecationWarning to FutureWarning. Application users now see the warnings under Python's default filters.
  • Run on Python 3.9 or newer. Python 3.8 support was removed.
  • Review the license change from MIT to Apache-2.0 if your distribution or compliance process records dependency licenses.

  • Fix cross-class method forwarding. Passing a class target to a non-__init__ instance method now raises TypeError at decoration time instead of forwarding a self of the wrong type.

  • Replace API names deprecated until v1.0:

    Deprecated API Replacement
    find_deprecated_callables find_deprecation_wrappers
    validate_deprecated_callable validate_deprecation_wrapper
    DeprecatedCallableInfo DeprecationWrapperInfo
    no_warning_call assert_no_warnings
  • Replace target=None with TargetMode.NOTIFY or omit target for a warn-only decorator.

  • Replace target=True with TargetMode.ARGS_REMAP.
  • Replace DeprecationWrapperInfo.empty_mapping with empty_args_mapping, and identity_mapping with identity_args_mapping. The old properties warn and are removed in v1.0.
  • If code inspects wrapper.__deprecated__.target, compare with a TargetMode, callable, or None. DeprecationConfig.target stores a normalized value, never legacy True or False.
  • Update external documentation bookmarks from flat paths such as /pyDeprecate/troubleshooting.html to the versioned /pyDeprecate/stable/troubleshooting.html layout.

  • Rename the CLI flag --skip_errors to --exit-zero in every check, expiry, chains, and all command. The old flag is rejected. --exit_zero remains an underscore alias, but the dashed spelling is canonical.

  • Fix unsupported stacked decorators. Six shapes, including callable-over-callable, now emit UserWarning at decoration time and become TypeError in v1.0. The supported lifecycle stack is outer ARGS_REMAP plus inner NOTIFY.

  • Outer-order deprecated properties now warn on read, write, and delete. Under filterwarnings=error::FutureWarning, a setter or deleter that was previously silent now raises. If only reads should warn, keep inner order (@property outside @deprecated) or decorate only fget.

  • Update proxy detection. proxy.__class__ reports the wrapped object's type for isinstance transparency. Use type(proxy) when you need to detect _DeprecatedProxy itself.

  • Do not use an instance proxy as the second argument to isinstance() or issubclass(). This misuse now raises TypeError instead of returning False. Class-alias proxies remain valid there.
  • Review expiry CI scope. validate_deprecation_expiry() now defaults to include_members=True, so expired methods, constructors, descriptors, and properties can newly fail the gate. Pass include_members=False only when the old narrower scope is intentional.
  • Fix invalid remove_in versions. An unparsable remove_in now emits UserWarning during batch expiry instead of being skipped silently.
  • Fix misspelled CLI flags. Unknown flags now fail instead of being silently ignored.
  • Use named % fields in custom message templates. Bare %s or %d conversions now raise ValueError when the decorator is applied.

  • @deprecated(target=TargetMode.ATTRS_REMAP) now raises TypeError for a class source. It already raised for functions. ATTRS_REMAP needs the class-only attrs_mapping keyword, which the common front door does not expose, so a class source previously built a proxy that remapped nothing. Use deprecated_class(attrs_mapping=...).

  • Rename template_mgs to message_template on deprecated(), deprecated_callable(), deprecated_class(), and deprecated_instance(). The typo remains a warning alias until v1.0; supplying both names raises TypeError.
  • Mapping errors now include the originating class or function name. Tests that assert complete error strings may need updated expected text.

  • Across the v0.6.x line, backward support for @deprecated on a class was restored through delegation to deprecated_class(). Existing class decorators need no rewrite for v0.12; delegation remains permanent and only its informational notice is scheduled for removal.

  • Omitting deprecated_in on a function or method emits UserWarning at decoration time. Add the version as part of every deprecation lifecycle.

  • ARGS_REMAP without args_mapping, NOTIFY with args_mapping or args_extra, and invalid target=False now warn immediately. These are migration failures, not harmless diagnostics; correct them before v1.0.
  • Omitting target is the canonical warn-only form. Its v0.12 default is TargetMode.AUTO, which resolves to NOTIFY when no mapping is present, so the user-visible result is unchanged.

  • CLI scans suppress only warnings from deprecate.*; third-party warnings are now visible. CI that treats all warnings as errors may start failing on dependencies imported during a scan.

  • Audit code sees the supported ARGS_REMAP + NOTIFY chain as ChainType.STACKED, not ChainType.TARGET.

  • When a caller supplies both deprecated and replacement keyword names, the explicit replacement value now wins regardless of call-site order.

  • Circular callable-target chains now raise a named RuntimeError instead of ending in RecursionError.

  • repr(), str(), equality, and hashing on a target-forwarding proxy now reflect the active target rather than the deprecated source.

  • In-place operators such as proxy += 1 rebind the name to the unwrapped result. Later uses are silent; avoid in-place operators if the proxy must retain its warning budget.
  • args_mapping, args_extra, and attrs_mapping are copied at decoration time. Mutating the original dict later no longer changes forwarding behavior.
  • Constructing an attrs_mapping-only class proxy is now silent; only access to a listed deprecated attribute warns.
  • Concurrent calls now respect exactly the configured num_warns budget. Tests that accidentally relied on one warning per racing thread will see fewer warnings.
  • Recursive audits deduplicate re-exports, include deprecated private and dunder members, warn and skip submodules that fail to import, and ignore unrelated foreign objects that raise during metadata probing. Counts and rows can therefore change in both directions.

  • @deprecated now defaults to TargetMode.AUTO. It resolves at decoration time: a function/class with args_mapping becomes ARGS_REMAP; a source without a mapping becomes warn-only. AUTO is never stored in DeprecationConfig; do not pass it explicitly because it exists only as the front-door default.

  • Existing @deprecated use on a class remains supported; no code change or decorator rewrite is required. It permanently delegates to deprecated_class() and emits one informational UserWarning per module-qualified class. stream=None suppresses the notice. Only the notice, not backward support or delegation, is removed in v1.0.
  • message_template and skip_if supplied through @deprecated on a class now reach the proxy. message_template was previously dropped on that path.
  • Non-callable sources now raise a direct TypeError pointing users to deprecated_instance() instead of failing later on __name__.
  • Explicit target=TargetMode.NOTIFY together with a mapping still emits UserWarning, stays NOTIFY, leaves the mapping inert, and is marked misconfigured — unchanged from v0.11.0, and a TypeError in v1.0. What changed is that an omitted target no longer lands here: it auto-resolves instead. Omit target to infer remapping, or select the matching remap mode explicitly.

If you hit anything not covered here, open an issue — we are happy to help.