Skip to content

Commit

Permalink
Merge pull request #11 from mjhajharia/remove_version
Browse files Browse the repository at this point in the history
add feature for remove_version
  • Loading branch information
mjhajharia authored Jan 18, 2024
2 parents 96530a7 + 6cea526 commit f8c7501
Showing 5 changed files with 103 additions and 42 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/python-package.yml
Original file line number Diff line number Diff line change
@@ -16,7 +16,7 @@ jobs:
strategy:
matrix:
platform: [ ubuntu-latest, macos-latest, windows-latest ]
python-version: [ "3.6", "3.7", "3.8", "3.9", "3.10" ]
python-version: [ "3.7", "3.8", "3.9", "3.10" ]

steps:
- uses: actions/checkout@v2
41 changes: 29 additions & 12 deletions deprecat/classic.py
Original file line number Diff line number Diff line change
@@ -44,6 +44,9 @@ class ClassicAdapter(wrapt.AdapterFactory):
version: str
Version of your project which deprecates this method or class.
remove_version: str
Version of your project which removes this method or class.
action: str
A warning filter used to specify the deprecation warning.
Can be one of "error", "ignore", "always", "default", "module", or "once".
@@ -60,9 +63,10 @@ class ClassicAdapter(wrapt.AdapterFactory):
"""

def __init__(self, reason="", version="", action=None, deprecated_args=None, category=DeprecationWarning):
self.reason = reason or ""
self.version = version or ""
def __init__(self, reason="", version="", remove_version="", action=None, deprecated_args=None, category=DeprecationWarning):
self.reason = reason
self.version = version
self.remove_version = remove_version
self.action = action
self.category = category
self.deprecated_args = deprecated_args
@@ -99,14 +103,18 @@ def get_deprecated_msg(self, wrapped, instance, kwargs):
else:
fmt = "Call to deprecated method {name}."


if self.deprecated_args is None:
name = wrapped.__name__
if self.reason:
if self.reason != "":
fmt += " ({reason})"
if self.version:
fmt += " -- Deprecated since version {version}."
if self.version != "":
fmt += "\n-- Deprecated since version {version}."

if self.remove_version != "":
fmt += "\n-- Will be removed in version {remove_version}."

return {f'{name}': fmt.format(name=name, reason=self.reason or "", version=self.version or "")}
return {f'{name}': fmt.format(name=name, reason=self.reason, version=self.version, remove_version=self.remove_version)}


if self.deprecated_args is not None:
@@ -117,11 +125,20 @@ def get_deprecated_msg(self, wrapped, instance, kwargs):
for arg in self.argstodeprecate:
name = arg
fmt = "Call to deprecated Parameter {name}."
if self.deprecated_args[arg]['reason']:
fmt += " ({reason})"
if self.deprecated_args[arg]['version']:
fmt += " -- Deprecated since v{version}."
warningargs[arg] = fmt.format(name=name, reason=self.deprecated_args[arg]['reason'] or "", version=self.deprecated_args[arg]['version'] or "")
r=''
v=''
rv=''
if self.deprecated_args[arg].get('reason') is not None:
r = self.deprecated_args[arg]['reason']
fmt += " {reason}"
if self.deprecated_args[arg].get('version') is not None:
v = self.deprecated_args[arg]['version']
fmt += "\n-- Deprecated since v{version}."
if self.deprecated_args[arg].get('remove_version') is not None:
rv = self.deprecated_args[arg]['remove_version']
fmt += "\n-- Will be removed in version {remove_version}."

warningargs[arg] = fmt.format(name=name, reason=r, version=v, remove_version=rv)
else:
name=""

13 changes: 8 additions & 5 deletions deprecat/example.py
Original file line number Diff line number Diff line change
@@ -12,10 +12,10 @@

from deprecat.sphinx import deprecat

@deprecat(reason="useless", version = 2.0)
@deprecat(reason="useless", version = "2.0")
class test_deprecat_on_class:
"""
Here we test deprecation on a class, like this one.
Here we test deprecation on a class, like this one.
"""
def __init__(self):
pass
@@ -26,17 +26,20 @@ class test_deprecat_on_class_method:
def __init__(self):
pass

@deprecat(reason="useless", version = 2.0)
@deprecat(reason="useless", version = "2.0", remove_version = "3.0")
def randomfunction(self, a, b):
"""
Here we test deprecation on a method of a class, like this one.
Here we test deprecation on a method of a class, like this one.
Note that you can also add `remove_version` to the decorator
to specify the version when the class/function/kwarg/feature will be removed.
"""
return a + b

x = test_deprecat_on_class_method()
x.randomfunction(1,2)

@deprecat(reason="useless", version = 2.0)
@deprecat(reason="useless", version = "2.0")
def test_deprecat_on_function(a, b):
"""
Here we test deprecation on a function.
48 changes: 30 additions & 18 deletions deprecat/sphinx.py
Original file line number Diff line number Diff line change
@@ -51,6 +51,9 @@ class SphinxAdapter(ClassicAdapter):
version: str
Version of your project which deprecates this feature.
remove_version: str
Version of your project which removes this method or class.
action: str
A warning filter used to specify the deprecation warning.
Can be one of "error", "ignore", "always", "default", "module", or "once".
@@ -97,6 +100,7 @@ def __init__(
directive,
reason="",
version="",
remove_version="",
action=None,
category=DeprecationWarning,
line_length=70,
@@ -105,7 +109,7 @@ def __init__(
self.deprecated_args = deprecated_args
self.directive = directive
self.line_length = line_length
super(SphinxAdapter, self).__init__(reason=reason, version=version, action=action, category=category, deprecated_args=deprecated_args)
super(SphinxAdapter, self).__init__(reason=reason, version=version, remove_version=remove_version, action=action, category=category, deprecated_args=deprecated_args)

def __call__(self, wrapped):
"""
@@ -130,7 +134,10 @@ def __call__(self, wrapped):
docstring = "\n"

width = self.line_length - 3 if self.line_length > 3 else 2 ** 16
reason = textwrap.dedent(self.reason).strip()
reason=self.reason
if self.remove_version!="":
reason += f'\n\n Warning: This deprecated feature will be removed in version {self.remove_version}'
reason = textwrap.dedent(reason).strip()

if self.deprecated_args is None:
fmt = ".. {directive}:: {version}" if self.version else ".. {directive}::"
@@ -149,7 +156,6 @@ def __call__(self, wrapped):
)
else:
div_lines.append("")

# -- append the directive division to the docstring
docstring += "".join("{}\n".format(line) for line in div_lines)

@@ -192,29 +198,31 @@ def __call__(self, wrapped):
insert_pos = len(params_section[description_start:])

#finally we store the warning fmt string
if self.deprecated_args[arg]['version']!="":
if self.deprecated_args[arg].get('version') is not None:
#the spaces are specifically cherrypicked for numpydoc docstrings
fmt = "\n\n .. admonition:: Deprecated\n :class: warning\n\n Parameter {arg} deprecated since {version}"
div_lines = [fmt.format(version=self.deprecated_args[arg]['version'],arg=arg)]
if self.deprecated_args[arg].get('remove_version') is not None:
fmt += " and will be removed in version {remove_version}."
div_lines = [fmt.format(version=self.deprecated_args[arg]['version'],arg=arg, remove_version=self.deprecated_args[arg]['remove_version'])]
else:
div_lines = [fmt.format(version=self.deprecated_args[arg]['version'],arg=arg)]
else:
fmt = "\n\n .. admonition:: Deprecated\n :class: warning\n\n Parameter {arg} deprecated"
div_lines = [fmt.format(version=self.deprecated_args[arg]['version'],arg=arg)]
width = 2**16
if self.remove_version!="":
self.reason += f'\n\n Warning: This deprecated feature will be removed in version {self.remove_version}'
reason = textwrap.dedent(self.reason).strip()
#formatting for docstring
for paragraph in reason.splitlines():
if paragraph:
div_lines.extend(
textwrap.fill(
paragraph,
width=width,
initial_indent=indent,
subsequent_indent=indent,
).splitlines()
)
else:
div_lines.append("")

div_lines.extend(
textwrap.fill(
paragraph,
width=width,
initial_indent=indent,
subsequent_indent=indent,
).splitlines()
)
# -- append the directive division to the docstring
a=''
a += "".join("{}\n".format(line) for line in div_lines)
@@ -326,7 +334,7 @@ def versionchanged(reason="", version="", line_length=70):
return adapter


def deprecat(reason="", directive="deprecated", version="", line_length=70, deprecated_args=None, **kwargs):
def deprecat(reason="", directive="deprecated", version="", remove_version="", line_length=70, deprecated_args=None, **kwargs):
"""
This decorator can be used to insert a "deprecated" directive
in your function/class docstring in order to documents the
@@ -340,6 +348,9 @@ def deprecat(reason="", directive="deprecated", version="", line_length=70, depr
version: str
Version of your project which deprecates this method or class.
remove_version: str
Version of your project which removes this method or class.
action: str
A warning filter used to specify the deprecation warning.
Can be one of "error", "ignore", "always", "default", "module", or "once".
@@ -369,6 +380,7 @@ def deprecat(reason="", directive="deprecated", version="", line_length=70, depr
adapter_cls = kwargs.pop('adapter_cls', SphinxAdapter)
kwargs["reason"] = reason
kwargs["version"] = version
kwargs["remove_version"] = remove_version
kwargs["line_length"] = line_length
kwargs["deprecated_args"] = deprecated_args

41 changes: 35 additions & 6 deletions docs/source/usage.rst
Original file line number Diff line number Diff line change
@@ -11,7 +11,7 @@ Deprecated function
from deprecat import deprecat
@deprecat(reason="this is a bad function", version = '2.0')
@deprecat(reason="this is a bad function", version = "2.0")
def some_deprecated_function(x, y):
return x+y
@@ -39,7 +39,7 @@ Deprecated method
def __init__(self,value):
self.value = value
@deprecat(reason="this is a bad method", version = 2.0)
@deprecat(reason="this is a bad method", version = "2.0")
def some_deprecated_function(self):
print(self.value)
@@ -68,7 +68,7 @@ Deprecated class
from deprecat import deprecat
@deprecat(reason="useless", version = 2.0)
@deprecat(reason="useless", version = "2.0")
class badclass:
def __init__(self):
@@ -169,6 +169,35 @@ This is the output we get when we try to run ``multiply(a=1,b=2,c=3)``
6
Examples
--------
`Check here for live examples <https://deprecat.readthedocs.io/en/latest/source/api.html#examples>`__
Adding Removal Version
----------------------

You can add a removal version to the deprecation warning by adding the ``removal_version`` parameter to the decorator. This will add a warning to the user that the function will be removed in the next versions.

.. code-block:: python
from deprecat.sphinx import deprecat
@deprecat(reason="this is a bad function", version = "2.0", remove_version = "3.0")
def some_deprecated_function(x, y):
"""
Parameters
----------
x: float
x is a nice number
y: float
y is also a nice number
"""
return x+y
This is the output we get when we try to run ``some_deprecated_function(x=2, y=3)``

.. code-block:: sh
DeprecationWarning: Call to deprecated method randomfunction. useless
Warning: This deprecated feature will be removed in version 3.0 -- Deprecated since version 2.0. -- Will be removed in version 3.0.
Live Examples
-------------
If you want to see the sphinx admonitions in action, `check this out <https://deprecat.readthedocs.io/en/latest/source/api.html#examples>`__

0 comments on commit f8c7501

Please sign in to comment.