Coverage for src / basanos / _deprecation.py: 100%
7 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-02 17:47 +0000
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-02 17:47 +0000
1"""Deprecation warning utilities for the Basanos package.
3Use :func:`warn_deprecated` whenever a public API is scheduled for removal.
4The standard policy (documented in ``SECURITY.md``) is:
6- Deprecated in ``0.x`` → removed no earlier than ``0.x+2``.
7- A ``DeprecationWarning`` is issued on every call to the deprecated code path.
9Examples:
10 >>> import warnings
11 >>> from basanos._deprecation import warn_deprecated
12 >>> with warnings.catch_warnings(record=True) as w:
13 ... warnings.simplefilter("always")
14 ... warn_deprecated("old_func", since="0.6", remove_in="0.8")
15 ... assert len(w) == 1
16 ... assert issubclass(w[0].category, DeprecationWarning)
17 ... assert "old_func" in str(w[0].message)
18 ... assert "0.6" in str(w[0].message)
19 ... assert "0.8" in str(w[0].message)
20"""
22from __future__ import annotations
24import warnings
27def warn_deprecated(
28 name: str,
29 *,
30 since: str,
31 remove_in: str,
32 replacement: str | None = None,
33 stacklevel: int = 2,
34) -> None:
35 """Emit a :class:`DeprecationWarning` for a deprecated public API.
37 Call this function at the top of any deprecated function, method, or
38 property so users see the warning on the first call.
40 Args:
41 name: The name of the deprecated symbol (e.g. ``"BasanosEngine.old_method"``).
42 since: The version in which the deprecation was introduced (e.g. ``"0.6"``).
43 remove_in: The earliest version in which the symbol may be removed (e.g. ``"0.8"``).
44 replacement: Optional name of the recommended replacement. If provided it is
45 included in the warning message.
46 stacklevel: Passed directly to :func:`warnings.warn`. The default of ``2``
47 means the warning points at the *caller* of the deprecated code rather than
48 at this helper function.
50 Examples:
51 >>> import warnings
52 >>> with warnings.catch_warnings(record=True) as w:
53 ... warnings.simplefilter("always")
54 ... warn_deprecated("foo", since="0.6", remove_in="0.8")
55 ... assert len(w) == 1
56 ... assert issubclass(w[0].category, DeprecationWarning)
58 >>> with warnings.catch_warnings(record=True) as w:
59 ... warnings.simplefilter("always")
60 ... warn_deprecated(
61 ... "foo",
62 ... since="0.6",
63 ... remove_in="0.8",
64 ... replacement="bar",
65 ... )
66 ... assert "bar" in str(w[0].message)
67 """
68 msg = f"{name} is deprecated since {since} and will be removed in {remove_in}."
69 if replacement is not None:
70 msg = f"{msg} Use {replacement} instead."
71 warnings.warn(msg, DeprecationWarning, stacklevel=stacklevel)