Changelog🔗
[0.8.0] — 2026-05-21 — Default TargetMode enum & CLI audit tools🔗
Added🔗
TargetModeenum exported fromdeprecate.TargetMode.NOTIFYreplacestarget=NoneandTargetMode.ARGS_REMAPreplacestarget=True. Both are public API. (#150)args_extraparameter fordeprecated_class()anddeprecated_instance(). Injects fixed keyword arguments into forwarded calls afterargs_mappinghas been applied, matching the same semantics as@deprecated(args_extra=...). Ignored (with a construction-timeUserWarning) whentargetisTargetMode.NOTIFY. (#150)template_mgsparameter fordeprecated_class()anddeprecated_instance(). Overrides the built-in warning message template with a%-style format string, matching the same semantics as@deprecated(template_mgs=...). Available placeholders:%(source_name)s,%(deprecated_in)s,%(remove_in)s,%(target_name)s(callable target only),%(target_path)s(callable target only),%(argument_map)s(args_mappingwarnings only). (#150)DeprecationConfig.misconfiguredfield. Boolean field on the shared metadata dataclass;Truewhen an invalid raw target sentinel (False) was passed at decoration time. Audit tools surface this viaDeprecationWrapperInfo.misconfigured_target. (#150)- Multi-page topic documentation site. Replaced the monolithic README-copy home page with a curated 7-page MkDocs Material site: Home, Getting Started, User Guide (Use Cases / void() Helper / Audit Tools), Troubleshooting, and demo links. Switched theme to Material, added Open Graph tags, JSON-LD structured data (SoftwareApplication / FAQPage / TechArticle per page), spec-compliant
llms.txt, andgit-revision-date-localizedplugin. README is unchanged (still the PyPI cover page). (#146) pydeprecateCLI command. Runpydeprecate <subcommand> path/to/your/packageto scan any package or module for misconfigured@deprecatedwrappers — reports invalid argument mappings, identity mappings, and no-effect wrappers with rich-formatted output whenrichis available. Also available aspython -m deprecate. (#76)- Four CLI subcommands:
check,expiry,chains,all.checkvalidates wrapper configuration;expiryreports wrappers past theirremove_indeadline (requirespip install 'pyDeprecate[audit]');chainsdetects deprecated-to-deprecated forwarding chains;allruns all three in a single scan pass. Flags:--norecursive,--skip_errors. (#149) - New
DeprecationWrapperInfo.empty_deprecated_infield.Truewhendeprecated_inis absent on a wrapper; intended for CI pipeline introspection.dataclasses.asdict()output andrepr()now include this field. (#166) template_mgsvalidated at decoration time. Malformed%-style format strings now raiseValueErrorimmediately at decoration time — not silently at call time. Applies to@deprecatedand thedeprecated_class()/deprecated_instance()proxy factories. (#169)- Stacked-callable-target guard. Applying
@deprecated(target=fn_a)on a callable whose target is itself a callable-target@deprecatedwrapper now emitsUserWarningat decoration time instead of crashing withTypeErrorat call time. (#169)
Deprecated🔗
target=Nonesentinel — useTargetMode.NOTIFY. Passingtarget=Nonenow emits aFutureWarningat decoration time. The sentinel remains accepted but will be removed in v1.0. Migrate totarget=TargetMode.NOTIFY. (#150)target=Truesentinel — useTargetMode.ARGS_REMAP. Passingtarget=Truenow emits aFutureWarningat decoration time. The sentinel remains accepted but will be removed in v1.0. Migrate totarget=TargetMode.ARGS_REMAP. (#150)DeprecationWrapperInfoattributesempty_mapping→empty_args_mappingandidentity_mapping→identity_args_mapping. Old names are kept as deprecated@propertyaliases that emitDeprecationWarningon access and will be removed in v1.0. (#166)
Changed🔗
- Misconfigured
TargetModecombinations now warn at construction time.TargetMode.ARGS_REMAPwithoutargs_mapping,TargetMode.NOTIFYwithargs_mapping, andTargetMode.NOTIFYwithargs_extraall surface aUserWarningimmediately. (#150) DeprecationConfig.targetalways stores a normalisedTargetModeor callable. Legacy boolean sentinels (True/False) are now normalised at decoration time and are never stored verbatim inDeprecationConfig.target. Code that inspects__deprecated__.targetmust compare againstTargetMode.NOTIFY,TargetMode.ARGS_REMAP, a callable, orNone— never againstTrueorFalse. (#150)deprecated_class()withtarget=TargetMode.NOTIFYnow emitsUserWarningat decoration time whenargs_mappingorargs_extrais supplied. These parameters are ignored inNOTIFYmode; passing them has always been a misconfiguration. The warning will becomeTypeErrorin v1.0. (#150)- Docs site URL layout is now versioned. Content is published under
https://borda.github.io/pyDeprecate/stable/(for the stable alias) andhttps://borda.github.io/pyDeprecate/<tag>/(for release tags). The root URL (https://borda.github.io/pyDeprecate/) redirects tostable/. External bookmarks to flat paths like.../pyDeprecate/troubleshooting.htmlwill break on first deploy — update them to.../pyDeprecate/stable/troubleshooting.html. (#148) targetparameter of@deprecatednow defaults toTargetMode.NOTIFY. Callers can omittargetentirely for warn-only deprecation:@deprecated(deprecated_in="1.0", remove_in="2.0")is now the canonical form. Passingtarget=TargetMode.NOTIFYexplicitly remains valid. This default is permanent and will not change in future releases. (#162)- Decoration-time
UserWarningwhen@deprecatedomitsdeprecated_in. Whendeprecated_inis absent aUserWarningis emitted immediately at decoration time (not at call time) regardless oftargetshape (TargetMode.NOTIFY, callable, orARGS_REMAP), even ifremove_inis set. Applies to functions and methods (not classes). Suppressed whenstream=Noneor when a customtemplate_mgsis provided. (#162) - CLI chains reporting split.
checksubcommand reports deprecated-to-deprecated chains as warnings (exit 0);chainsandallsubcommands report chains as errors (exit 1). (#149)
Fixed🔗
- PEP 702 compatibility crash fixed. When
@deprecatedwas stacked under a PEP 702@typing.deprecateddecorator,wrapped_fnattempted to look up__deprecated__on the outer wrapper and raisedAttributeError. Fixed by capturingdep_metaas a closure variable at decoration time instead of re-reading it from the wrapper. (#169) - Double
FutureWarningemission ondeprecated_class()in NOTIFY mode fixed. Usingdeprecated_class()withtarget=TargetMode.NOTIFYtriggered twoFutureWarningemissions per construction call. (#162) - Cross-class guard false positives resolved;
TypeErrorsemantics preserved. Two previously documented "irresolvable" false-positive scenarios are now handled: (1) targets with metaclass/dynamic-class qualnames (e.g.type("Name", bases, ns)or manualfn.__qualname__ = "FakeOwner.method") — guard now skips silently when the named class is absent from the target's module globals; (2) pre-applied decorators that rewrite the source's__qualname__— guard reads the true enclosing class from the Python class-body frame, which cannot be mutated by user decorators. The guard continues to raiseTypeErrorat decoration time for genuine cross-class forwarding. (#169) args_mappingrename no longer clobbers source default when both old and new parameter names are present. Previously, calling a deprecated wrapper with the old argument name while the source also accepted the new name could silently overwrite the new-name value. The remapping now correctly renamesold=Xtonew=Xwithout discarding a separately suppliednewvalue. (#150)target=Falsesentinel now emitsUserWarningat decoration time.target=Falsewas never a valid configuration; previously the behavior was undefined. The sentinel now surfaces aUserWarningimmediately and will raiseTypeErrorin v1.0. (#150)
[0.7.0] — 2026-03-31 — Docstring Tooling🔗
Added🔗
- MkDocs admonition output.
@deprecatednow acceptsdocstring_style="mkdocs"(alias:"markdown"). Whenupdate_docstring=True, the deprecation notice is injected as a!!! warning "Deprecated in X"admonition instead of a Sphinx.. deprecated::directive. Usedocstring_style="auto"to detect style automatically from existing docstring content. (#134) - Google / NumPy section-aware docstring injection.
update_docstring=Truenow inserts the deprecation notice before the first section (Args:,Returns:,Parameters, …) rather than appending it at the end. (#134) - Inline arg deprecation in docstrings. When
args_mappingis set andupdate_docstring=True, each renamed or removed argument is annotated directly in theArgs:/:paramsection of the docstring. (#136) - Griffe extension for mkdocstrings (
deprecate.docstring.griffe_ext, beta) and Sphinx autodoc extension for deprecated classes (deprecate.docstring.sphinx_ext, beta). (#134) - Live demo documentation published to GitHub Pages — MkDocs demo, Sphinx demo, and portal landing page. (#134, #137)
Fixed🔗
- Fixed
getattr/setattrstring-literal calls (B009/B010) replaced with direct attribute access. (#139) - Fixed proxy swap skipped correctly when
super().import_object()returnsFalsein the Griffe extension; empty_proxy_docnow delegates tosuper().get_doc()in the Sphinx extension. (#139)
[0.6.0.post0] — 2026-03-14 — Deprecation Proxy for class/instances🔗
Changed🔗
- Softer class-deprecation fallback.
@deprecatedapplied directly to a class (Enum, dataclass, or plain class) now emits aUserWarningat decoration time and delegates todeprecated_class()internally, instead of raisingTypeError. Code using the old pattern continues to work; the warning points to the recommended API. (#132)
[0.6.0] — 2026-03-13🔗
Added🔗
deprecated_class()anddeprecated_instance()— full proxy support. Enum, dataclass, and built-in types can now be wrapped in a transparent proxy. Attribute access, item access, method calls, and class behaviour all forward to the underlying type with aFutureWarningemitted on first access. (#114)- Correct
isinstance()/issubclass()semantics on proxy classes.isinstance(x, proxy)andissubclass(Sub, proxy)now work as expected — previously raisedTypeError. Type checks do not consume the warning budget. (#126)
Changed🔗
@deprecatedon a class raisesTypeError. Applying@deprecateddirectly to a class now raisesTypeErrorat decoration time instead of silently misbehaving. Superseded inv0.6.0.post0by aUserWarning+ delegation todeprecated_class(). Use@deprecated_class()for class-level deprecation. (#120)
Deprecated🔗
- Audit API renamed for consistency. Old names remain as
@deprecatedshims until v1.0. (#125)
| Old name | New name |
|---|---|
find_deprecated_callables |
find_deprecation_wrappers |
validate_deprecated_callable |
validate_deprecation_wrapper |
DeprecatedCallableInfo |
DeprecationWrapperInfo |
no_warning_callrenamed toassert_no_warnings. The new name mirrorsassertWarns/assertRaisesfrom the standard library, making test intent immediately obvious. Old name kept as a deprecated alias until v1.0. (#131)
Fixed🔗
- Cross-class method forwarding now fails at decoration time. Passing a class as
targeton a non-__init__method previously silently forwardedselfof the wrong type — always a runtime bug, never a valid pattern. The guard now raisesTypeErrorat decoration time so the misconfiguration is caught immediately. (#121) find_deprecation_wrappers()no longer reports falseinvalid_argsfor proxy objects. The proxy__call__catch-all signature previously caused allargs_mappingkeys to be flagged as invalid; signature validation is now skipped for proxy objects. (#124)
[0.5.0] — 2026-02-23 — Deprecation Lifecycle Management🔗
Added🔗
deprecate.auditmodule — deprecation lifecycle management. A dedicated module grouping all inspection and enforcement utilities, designed to be called from pytest or CI scripts. Requires the optional[audit]extra:pip install pyDeprecate[audit]. (#111)find_deprecated_callables()/validate_deprecated_callable()— zero-impact wrapper detection. Scans a module or package for@deprecatedwrappers that have no real effect: invalidargs_mappingkeys, identity mappings, self-referencing targets, or missing version fields. ReturnsDeprecatedCallableInfodataclasses. (#72)validate_deprecation_expiry()— enforce removal deadlines in CI. Scans a module or package and returns all wrappers whoseremove_inversion has been reached or passed. Auto-detects the installed package version. Integrate as a pytest fixture or CI step to prevent zombie code from shipping past its scheduled removal. (#89)validate_deprecation_chains()— detect deprecated-to-deprecated forwarding. Identifies wrappers whosetargetis itself a deprecated callable, forming chains that users traverse unnecessarily. Reports two chain kinds via theChainTypeenum:TARGET(forwarding chain) andSTACKED(composed argument mappings). (#90)
Fixed🔗
@deprecatedwrappers now correctly handle var-positional Enum signatures. A subtle edge case where callables with var-positional parameters in their Enum signature caused incorrect argument forwarding is now resolved. (#104)
[0.4.0] — 2025-12-03 — Enhanced Documentation & Modernization🔗
Added🔗
update_docstringparameter — automatic Sphinx deprecation notices. Setupdate_docstring=Trueon@deprecatedto automatically append a.. deprecated::reStructuredText block to the function's docstring. IDE tooltips and Sphinx-generated API docs show the notice without any manual edits. (#31)
Changed🔗
- Deprecation warnings now use
FutureWarninginstead ofDeprecationWarning.DeprecationWarningis silenced by Python's default warning filters outside of test contexts, making it invisible to most end-users.FutureWarningis shown by default, ensuring callers actually see the migration message. (#16) - Minimum Python version raised to 3.9. Python 3.8 reached end-of-life in October 2024. (#73)
- License changed from MIT to Apache-2.0.
- Error messages now include the originating class or function name for easier debugging when a mapping fails. (#11)
[0.3.2] — 2021-06-11 — Support containing kwargs in target function🔗
Added🔗
targetfunctions using**kwargsare now supported. Previously, forwarding to a target that accepted**kwargsand accessed them viakwargs.get(...)raisedTypeErrorfor unrecognised argument names. Extra arguments from the deprecated call are now forwarded correctly. (#6)
[0.3.1] — 2021-05-31 — Fixed void typing🔗
Fixed🔗
void()type annotation corrected to satisfy mypy. The return type ofvoid()is now properly annotated — IDE and type checker warnings about unused parameters in deprecated function bodies are suppressed correctly.
[0.3.0] — 2021-04-21 — Conditional skip🔗
Added🔗
skip_ifparameter — conditional deprecation. Pass aboolor a zero-argument callable returningboolto skip the warning and forwarding when a runtime condition is true. Useful for gating deprecation behaviour on package version checks or feature flags. (#4)
[0.2.0] — 2021-03-29 — Improved self arg deprecations🔗
Added🔗
target=True— self-deprecation mode. Deprecate and remap arguments within the same function without forwarding to a separate callable. Use withargs_mappingto rename a parameter while keeping the function body intact. (#3)void()helper. Accepts any arguments and returnsNone. Silences IDE "unused parameter" warnings in deprecated function bodies where the body is never reached.no_warning_call()context manager. Assert that a block of code raises no deprecation warning — useful for verifying that new API paths are clean in tests. Renamed toassert_no_warnings()in v0.6.0. (#2)- Stacked
@deprecateddecorators. Multiple@deprecated(True, ...)decorators can be stacked on the same function for multi-hop argument migrations across versions, each with independent warning counts and version metadata.
[0.1.1] — 2021-03-21 — Allow infinite warning🔗
Added🔗
num_warns=-1— always-on warnings. Settingnum_warnsto-1causes the deprecation warning to fire on every call rather than stopping after N times.target=None— warn-only mode. The original function body still executes;@deprecatedadds only a warning with no call forwarding. Useful when you want to signal deprecation without changing any call behaviour.
[0.1.0] — 2021-03-20 — Initial release🔗
Added🔗
@deprecated(target=callable)decorator. Marks a function as deprecated and automatically forwards all calls — including argument mapping — to a replacement function. The deprecated function body is never executed whentargetis a callable.- Automatic argument mapping. Positional arguments are resolved to keyword arguments and forwarded to the target's signature.
args_mappingrenames ({"old": "new"}) or drops ({"old": None}) individual arguments during forwarding. args_extra— inject additional kwargs into the target call. Pass adictof extra keyword arguments to merge into every forwarded call. Useful for providing default values or adapter arguments that the deprecated API never accepted.- Configurable warning count (
num_warns). Warnings fire once per function by default; set to any positive integer to limit the total count per function lifetime. - Custom warning message template (
template_mgs). Format string with%(source_name)s,%(target_path)s,%(deprecated_in)s,%(remove_in)s, and%(argument_map)splaceholders. - Custom warning stream (
stream). Route warnings tologging.warning,warnings.warn, or any callable.