Skip to content

Commit 08c71eb

Browse files
committed
Improve deprecated decorator
Allow optional arguments replace and version
1 parent da7a12c commit 08c71eb

File tree

1 file changed

+55
-25
lines changed

1 file changed

+55
-25
lines changed

semver.py

Lines changed: 55 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33

44
import argparse
55
import collections
6-
from functools import wraps
6+
from functools import wraps, partial
7+
import inspect
78
import re
89
import sys
910
import warnings
@@ -28,35 +29,62 @@ def cmp(a, b):
2829
return (a > b) - (a < b)
2930

3031

31-
def deprecated(replace=None):
32+
def deprecated(func=None, replace=None, version=None, category=DeprecationWarning):
3233
"""
3334
Decorates a function to output a deprecation warning.
3435
35-
:param str replace: the name of the function which the deprecated
36-
function should be replaced with
37-
3836
This function will be removed once major version 4 of semver is
3937
released.
40-
"""
4138
42-
def decorator(func):
43-
r = replace or func.__name__ # __qualname__
39+
:param str replace: the function to replace (use the full qualified
40+
name like ``semver.VersionInfo.bump_major``.
41+
:param str version: the first version when this function was deprecated.
42+
:param category: allow you to specify the deprecation warning class
43+
of your choice. By default, it's :class:`DeprecationWarning`, but
44+
you can choose :class:`PendingDeprecationWarning``or a custom class.
45+
"""
4446

47+
def decorator():
4548
@wraps(func)
4649
def wrapper(*args, **kwargs):
47-
msg = (
48-
"Function 'semver.{f}' is deprecated. "
49-
"Use the respective 'semver.VersionInfo.{r}' instead."
50+
msg = ["Function 'semver.{f}' is deprecated."]
51+
52+
if version:
53+
msg.append("Deprecated since version {v}.")
54+
55+
if replace:
56+
msg.append("Use {r!r} instead.")
57+
else:
58+
msg.append("Use the respective 'semver.VersionInfo.{r}' instead.")
59+
60+
# warnings.simplefilter('always', category)
61+
frame = inspect.currentframe().f_back
62+
63+
msg = " ".join(msg)
64+
msg = msg.format(f=func.__name__, r=replace, v=version)
65+
warnings.warn_explicit(
66+
msg,
67+
category=category,
68+
# stacklevel=2,
69+
filename=inspect.getfile(frame.f_code),
70+
lineno=frame.f_lineno,
5071
)
51-
warnings.warn(msg.format(f=func.__name__, r=r), category=DeprecationWarning)
72+
# warnings.simplefilter('default', category)
73+
# As recommended in the Python documentation
74+
# https://docs.python.org/3/library/inspect.html#the-interpreter-stack
75+
# better remove the interpreter stack:
76+
del frame
5277
return func(*args, **kwargs)
5378

5479
return wrapper
5580

56-
return decorator
81+
if callable(func):
82+
return decorator()
83+
else:
84+
return partial(deprecated, replace=replace, version=version, category=category)
5785

5886

59-
@deprecated()
87+
@deprecated(version="2.9.2")
6088
def parse(version):
6189
"""
6290
Parse version to major, minor, patch, pre-release, build parts.
@@ -229,8 +257,10 @@ def to_dict(self):
229257
)
230258

231259
# For compatibility reasons:
232-
_astuple = deprecated("to_tuple")(to_tuple)
233-
_asdict = deprecated("to_dict")(to_dict)
260+
_astuple = deprecated(replace="semver.VersionInfo.to_tuple", version="2.9.2")(
261+
to_tuple
262+
)
263+
_asdict = deprecated(replace="semver.VersionInfo.to_dict", version="2.9.2")(to_dict)
234264

235265
def __iter__(self):
236266
"""Implement iter(self)."""
@@ -450,7 +480,7 @@ def _to_dict(obj):
450480
return obj
451481

452482

453-
@deprecated("parse")
483+
@deprecated(replace="semver.VersionInfo.parse", version="2.9.2")
454484
def parse_version_info(version):
455485
"""
456486
Parse version string to a VersionInfo instance.
@@ -640,7 +670,7 @@ def min_ver(ver1, ver2):
640670
return ver2
641671

642672

643-
@deprecated()
673+
@deprecated(version="2.9.2")
644674
def format_version(major, minor, patch, prerelease=None, build=None):
645675
"""
646676
Format a version string according to the Semantic Versioning specification.
@@ -676,7 +706,7 @@ def _increment_string(string):
676706
return string
677707

678708

679-
@deprecated()
709+
@deprecated(version="2.9.2")
680710
def bump_major(version):
681711
"""
682712
Raise the major part of the version string.
@@ -694,7 +724,7 @@ def bump_major(version):
694724
return str(VersionInfo.parse(version).bump_major())
695725

696726

697-
@deprecated()
727+
@deprecated(version="2.9.2")
698728
def bump_minor(version):
699729
"""
700730
Raise the minor part of the version string.
@@ -712,7 +742,7 @@ def bump_minor(version):
712742
return str(VersionInfo.parse(version).bump_minor())
713743

714744

715-
@deprecated()
745+
@deprecated(version="2.9.2")
716746
def bump_patch(version):
717747
"""
718748
Raise the patch part of the version string.
@@ -730,7 +760,7 @@ def bump_patch(version):
730760
return str(VersionInfo.parse(version).bump_patch())
731761

732762

733-
@deprecated()
763+
@deprecated(version="2.9.2")
734764
def bump_prerelease(version, token="rc"):
735765
"""
736766
Raise the prerelease part of the version string.
@@ -749,7 +779,7 @@ def bump_prerelease(version, token="rc"):
749779
return str(VersionInfo.parse(version).bump_prerelease(token))
750780

751781

752-
@deprecated()
782+
@deprecated(version="2.9.2")
753783
def bump_build(version, token="build"):
754784
"""
755785
Raise the build part of the version string.
@@ -768,7 +798,7 @@ def bump_build(version, token="build"):
768798
return str(VersionInfo.parse(version).bump_build(token))
769799

770800

771-
@deprecated()
801+
@deprecated(version="2.9.2")
772802
def finalize_version(version):
773803
"""
774804
Remove any prerelease and build metadata from the version string.
@@ -790,7 +820,7 @@ def finalize_version(version):
790820
return str(verinfo.finalize_version())
791821

792822

793-
@deprecated()
823+
@deprecated(version="2.9.2")
794824
def replace(version, **parts):
795825
"""
796826
Replace one or more parts of a version and return the new string.

0 commit comments

Comments
 (0)