Skip to content

Don't pretend @deprecated applies to classmethods. #12151

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Sep 21, 2018
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 20 additions & 22 deletions lib/matplotlib/cbook/deprecation.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import functools
import textwrap
import inspect
import warnings


Expand Down Expand Up @@ -117,6 +117,11 @@ def deprecated(since, message='', name='', alternative='', pending=False,
"""
Decorator to mark a function or a class as deprecated.

When deprecating a classmethod, a staticmethod, or a property, the
``@deprecated`` decorator should go *under* the ``@classmethod``, etc.
decorator (i.e., `deprecated` should directly decorate the underlying
callable).

Parameters
----------
since : str
Expand Down Expand Up @@ -183,31 +188,22 @@ def deprecate(obj, message=message, name=name, alternative=alternative,

if isinstance(obj, type):
obj_type = "class"
old_doc = obj.__doc__
func = obj.__init__
old_doc = obj.__doc__

def finalize(wrapper, new_doc):
obj.__doc__ = new_doc
obj.__init__ = wrapper
return obj
else:
obj_type = "function"
if isinstance(obj, classmethod):
func = obj.__func__
old_doc = func.__doc__

def finalize(wrapper, new_doc):
wrapper = functools.wraps(func)(wrapper)
wrapper.__doc__ = new_doc
return classmethod(wrapper)
else:
func = obj
old_doc = func.__doc__

def finalize(wrapper, new_doc):
wrapper = functools.wraps(func)(wrapper)
wrapper.__doc__ = new_doc
return wrapper
func = obj
old_doc = func.__doc__

def finalize(wrapper, new_doc):
wrapper = functools.wraps(func)(wrapper)
wrapper.__doc__ = new_doc
return wrapper

message = _generate_deprecation_message(
since, message, name, alternative, pending, obj_type, addendum,
Expand All @@ -219,11 +215,13 @@ def wrapper(*args, **kwargs):
warnings.warn(message, category, stacklevel=2)
return func(*args, **kwargs)

old_doc = textwrap.dedent(old_doc or '').strip('\n')
old_doc = inspect.cleandoc(old_doc or '').strip('\n')
message = message.strip()
new_doc = (('\n.. deprecated:: %(since)s'
'\n %(message)s\n\n' %
{'since': since, 'message': message}) + old_doc)
new_doc = ('.. deprecated:: {since}\n'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happened to the leading newline?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's at the beginning of the docstring so it doesn't matter.

OTOH I realized that we should dedent old_doc with inspect.cleandoc instead of textwrap.dedent, as the first line may not be indented... e.g. right now (before this PR) the docstring of backend_cairo.ArrayWrapper.__init__ is

.. deprecated:: 3.0
    The ArrayWrapper class was deprecated in Matplotlib 3.0 and will be removed in 3.2.

Thin wrapper around numpy ndarray to expose the interface
       expected by cairocffi. Basically replicates the
       array.array interface.

' {message}\n'
'\n'
'{old_doc}'
.format(since=since, message=message, old_doc=old_doc))
if not old_doc:
# This is to prevent a spurious 'unexected unindent' warning from
# docutils when the original docstring was blank.
Expand Down