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

1"""Deprecation warning utilities for the Basanos package. 

2 

3Use :func:`warn_deprecated` whenever a public API is scheduled for removal. 

4The standard policy (documented in ``SECURITY.md``) is: 

5 

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. 

8 

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""" 

21 

22from __future__ import annotations 

23 

24import warnings 

25 

26 

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. 

36 

37 Call this function at the top of any deprecated function, method, or 

38 property so users see the warning on the first call. 

39 

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. 

49 

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) 

57 

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)