Skip to content

v0.8.0: Default TargetMode enum & CLI audit tools

Choose a tag to compare

@Borda Borda released this 21 May 08:13
· 66 commits to main since this release

🎉 pyDeprecate 0.8.0

pyDeprecate 0.8.0 is the TargetMode enum & CLI tooling release — deprecation intent is now typed and explicit, warn-only deprecation is the default, and a new pydeprecate CLI lets you scan any package for misconfigured wrappers without writing a single audit script.


Summary

v0.8.0 centers on TargetMode: a proper enum (TargetMode.NOTIFY, TargetMode.ARGS_REMAP) replacing the target=None / target=True boolean sentinels. The old sentinels still work — they emit FutureWarning at decoration time — so you've got a full release cycle to migrate before they're removed in v1.0.

target now defaults to TargetMode.NOTIFY, so the most common pattern — warn callers and run the original body unchanged — needs nothing more than deprecated_in and remove_in:

@deprecated(deprecated_in="1.0", remove_in="2.0")
def old_fn(): ...

A new pydeprecate CLI (four subcommands) rounds out the release. Run pydeprecate check path/to/mypackage to surface misconfigured wrappers across a whole codebase in seconds.


🚀 Spotlights

TargetMode enum

from deprecate import deprecated, TargetMode


# Warn-only: source body executes unchanged
@deprecated(target=TargetMode.NOTIFY, deprecated_in="0.8", remove_in="1.0")
def old_api(): ...


# Argument-rename: warns only when old arg name is passed
@deprecated(
    target=TargetMode.ARGS_REMAP,
    deprecated_in="0.8",
    remove_in="1.0",
    args_mapping={"old_param": "new_param"},
)
def new_api(new_param): ...

TargetMode is exported from deprecate and works everywhere target= is accepted: @deprecated, deprecated_class(), and deprecated_instance().

Zero-boilerplate warn-only deprecation

target is now optional — TargetMode.NOTIFY is the default. Drop the target= entirely:

@deprecated(deprecated_in="0.8", remove_in="1.0")
def old_fn(): ...

Omitting deprecated_in now surfaces a UserWarning at decoration time, not silently at call time, so misconfiguration is visible immediately.

pydeprecate CLI

pydeprecate check path/to/mypackage    # validate wrapper configuration
pydeprecate expiry path/to/mypackage   # find wrappers past remove_in date
pydeprecate chains path/to/mypackage   # detect deprecated→deprecated chains
pydeprecate all path/to/mypackage      # run all three in one pass

Also available as python -m deprecate. Requires pip install 'pyDeprecate[cli]' for all subcommands (fire dependency). expiry additionally needs pip install 'pyDeprecate[audit]'. Or install both: pip install 'pyDeprecate[cli,audit]'.


Migration guide

No breaking changes. All v0.7.x code continues to run. The items below emit deprecation warnings now and will be removed in v1.0.

target=NoneTargetMode.NOTIFY

# before — emits FutureWarning at decoration time
@deprecated(target=None, deprecated_in="0.8", remove_in="1.0")
def old_fn(): ...


# after — explicit or implicit (default)
@deprecated(target=TargetMode.NOTIFY, deprecated_in="0.8", remove_in="1.0")
def old_fn(): ...


# simplest form — NOTIFY is the default
@deprecated(deprecated_in="0.8", remove_in="1.0")
def old_fn(): ...

target=TrueTargetMode.ARGS_REMAP

# before — emits FutureWarning at decoration time
@deprecated(target=True, deprecated_in="0.8", remove_in="1.0", args_mapping={"old_arg": "new_arg"})
def new_fn(new_arg): ...


# after
@deprecated(target=TargetMode.ARGS_REMAP, deprecated_in="0.8", remove_in="1.0", args_mapping={"old_arg": "new_arg"})
def new_fn(new_arg): ...

DeprecationWrapperInfo field renames

Old name New name Removed in
empty_mapping empty_args_mapping v1.0
identity_mapping identity_args_mapping v1.0
# before
if info.empty_mapping or info.identity_mapping:
    ...

# after
if info.empty_args_mapping or info.identity_args_mapping:
    ...

DeprecationConfig.target no longer stores raw sentinels

Code that inspects wrapper.__deprecated__.target and compares against None or True must update:

# before
assert fn.__deprecated__.target is None

# after
from deprecate import TargetMode

assert fn.__deprecated__.target is TargetMode.NOTIFY

Notable changes

Added

  • TargetMode enum (NOTIFY, ARGS_REMAP) exported from deprecate — typed replacement for target=None / target=True sentinels. (#150)
  • target defaults to TargetMode.NOTIFY on @deprecated — warn-only deprecation now requires only deprecated_in and remove_in. (#162)
  • pydeprecate CLIcheck, expiry, chains, all subcommands.
    • initial CLI scaffolding (#76)
    • check, expiry, chains, all subcommands (#149)
  • template_mgs and args_extra on deprecated_class() and deprecated_instance() — proxy factories now at full parity with @deprecated. (#150)
  • DeprecationWrapperInfo.empty_deprecated_inTrue when deprecated_in is absent; for CI pipeline use. (#166)
  • DeprecationConfig.misconfiguredTrue when an invalid raw target sentinel (False) was passed at decoration time; surfaced via DeprecationWrapperInfo.misconfigured_target. (#150)
  • num_warns=0 documented — equivalent to stream=None; suppresses all warnings. (#150)
  • Stacked-callable-target guard@deprecated(target=callable_a) stacked over another callable-target wrapper now emits UserWarning at decoration time instead of crashing with TypeError at call time. (#169)
  • template_mgs validated at decoration time — malformed %-style placeholders raise ValueError immediately. (#169)

Changed

  • DeprecationConfig.target normalized at decoration time — stores TargetMode or Callable, never raw None/True/False. (#150)
  • Misconfigured TargetMode combos warn at construction timeARGS_REMAP without args_mapping, NOTIFY with args_mapping or args_extra all emit UserWarning immediately. (#150)
  • Docs site URL layout versioned — content now at https://borda.github.io/pyDeprecate/stable/ (and /<tag>/); the bare root redirects to stable/. Existing bookmarks to flat paths will break on first deploy. (#148)
  • CLI chains reportingcheck subcommand reports chains as warnings; chains/all subcommands report chains as errors. (#149)

Deprecated

  • target=None — use TargetMode.NOTIFY. Emits FutureWarning. Removed in v1.0. (#150)
  • target=True — use TargetMode.ARGS_REMAP. Emits FutureWarning. Removed in v1.0. (#150)
  • target=False — never valid; now emits UserWarning, treated as TargetMode.NOTIFY. Raises TypeError in v1.0. (#150)
  • DeprecationWrapperInfo.empty_mappingempty_args_mapping. Emits DeprecationWarning. Removed in v1.0. (#166)
  • DeprecationWrapperInfo.identity_mappingidentity_args_mapping. Emits DeprecationWarning. Removed in v1.0. (#166)

Fixed

  • PEP 702 stacking crash@deprecated stacked under @typing.deprecated no longer raises AttributeError on __deprecated__ lookup. (#169)
  • Double FutureWarning on deprecated_class() in NOTIFY mode. (#162)
  • Cross-class guard false positives — metaclass/dynamic-class qualnames and pre-applied decorators that rewrite __qualname__ no longer trigger spurious TypeError at decoration time; the guard still raises for genuine cross-class forwarding. (#169)
  • args_mapping rename no longer clobbers source default when both old and new parameter names are supplied simultaneously. (#150)

🏆 Contributors

  • Onuralp SEZER (@onuralpszr) — initial CLI scaffolding (#76)
  • Jiri Borovec (@Borda) — TargetMode enum, CLI subcommands, proxy parity, cross-class guard hardening, docs site restructure

Full changelog: v0.7.0...v0.8.0