Skip to content

MNT: Deprecate docstring #22148

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
Mar 15, 2022
Merged
Show file tree
Hide file tree
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
5 changes: 5 additions & 0 deletions doc/api/next_api_changes/deprecations/22148-OG.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Module ``docstring`` deprecated
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The module ``matplotlib.docstring`` is considered internal and public access
is deprecated.
2 changes: 1 addition & 1 deletion doc/api/prev_api_changes/api_changes_3.5.0/removals.rst
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ The following class methods have been removed:
- ``Colorbar.on_mappable_changed`` and ``Colorbar.update_bruteforce``; use
``Colorbar.update_normal()`` instead
- ``docstring.Substitution.from_params`` has been removed; directly assign to
``params`` of `.Substitution` instead
``params`` of ``docstring.Substitution`` instead
- ``DraggableBase.artist_picker``; set the artist's picker instead
- ``DraggableBase.on_motion_blit``; use `.DraggableBase.on_motion` instead
- ``FigureCanvasGTK3._renderer_init``
Expand Down
6 changes: 3 additions & 3 deletions doc/devel/documenting_mpl.rst
Original file line number Diff line number Diff line change
Expand Up @@ -684,14 +684,14 @@ are:
2. as automated as possible so that as properties change, the docs
are updated automatically.

The ``@docstring.interpd`` decorator implements this. Any function accepting
The ``@_docstring.interpd`` decorator implements this. Any function accepting
`.Line2D` pass-through ``kwargs``, e.g., `matplotlib.axes.Axes.plot`, can list
a summary of the `.Line2D` properties, as follows:

.. code-block:: python

# in axes.py
@docstring.interpd
@_docstring.interpd
def plot(self, *args, **kwargs):
"""
Some stuff omitted
Expand Down Expand Up @@ -726,7 +726,7 @@ gets interpolated into the docstring.

Note that this scheme does not work for decorating an Artist's ``__init__``, as
the subclass and its properties are not defined yet at that point. Instead,
``@docstring.interpd`` can be used to decorate the class itself -- at that
``@_docstring.interpd`` can be used to decorate the class itself -- at that
point, `.kwdoc` can list the properties and interpolate them into
``__init__.__doc__``.

Expand Down
4 changes: 2 additions & 2 deletions lib/matplotlib/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@

# cbook must import matplotlib only within function
# definitions, so it is safe to import from it here.
from . import _api, _version, cbook, docstring, rcsetup
from . import _api, _version, cbook, _docstring, rcsetup
from matplotlib.cbook import sanitize_sequence
from matplotlib._api import MatplotlibDeprecationWarning
from matplotlib.rcsetup import validate_backend, cycler
Expand Down Expand Up @@ -593,7 +593,7 @@ def gen_candidates():
_deprecated_remain_as_none = {}


@docstring.Substitution(
@_docstring.Substitution(
"\n".join(map("- {}".format, sorted(rcsetup._validators, key=str.lower)))
)
class RcParams(MutableMapping, dict):
Expand Down
97 changes: 97 additions & 0 deletions lib/matplotlib/_docstring.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import inspect

from . import _api


class Substitution:
"""
A decorator that performs %-substitution on an object's docstring.

This decorator should be robust even if ``obj.__doc__`` is None (for
example, if -OO was passed to the interpreter).

Usage: construct a docstring.Substitution with a sequence or dictionary
suitable for performing substitution; then decorate a suitable function
with the constructed object, e.g.::

sub_author_name = Substitution(author='Jason')

@sub_author_name
def some_function(x):
"%(author)s wrote this function"

# note that some_function.__doc__ is now "Jason wrote this function"

One can also use positional arguments::

sub_first_last_names = Substitution('Edgar Allen', 'Poe')

@sub_first_last_names
def some_function(x):
"%s %s wrote the Raven"
"""
def __init__(self, *args, **kwargs):
if args and kwargs:
raise TypeError("Only positional or keyword args are allowed")
self.params = params = args or kwargs

def __call__(self, func):
if func.__doc__:
func.__doc__ = inspect.cleandoc(func.__doc__) % self.params
return func

def update(self, *args, **kwargs):
"""
Update ``self.params`` (which must be a dict) with the supplied args.
"""
self.params.update(*args, **kwargs)


class _ArtistKwdocLoader(dict):
def __missing__(self, key):
if not key.endswith(":kwdoc"):
raise KeyError(key)
name = key[:-len(":kwdoc")]
from matplotlib.artist import Artist, kwdoc
try:
cls, = [cls for cls in _api.recursive_subclasses(Artist)
if cls.__name__ == name]
except ValueError as e:
raise KeyError(key) from e
return self.setdefault(key, kwdoc(cls))


class _ArtistPropertiesSubstitution(Substitution):
"""
A `.Substitution` with two additional features:

- Substitutions of the form ``%(classname:kwdoc)s`` (ending with the
literal ":kwdoc" suffix) trigger lookup of an Artist subclass with the
given *classname*, and are substituted with the `.kwdoc` of that class.
- Decorating a class triggers substitution both on the class docstring and
on the class' ``__init__`` docstring (which is a commonly required
pattern for Artist subclasses).
"""

def __init__(self):
self.params = _ArtistKwdocLoader()

def __call__(self, obj):
super().__call__(obj)
if isinstance(obj, type) and obj.__init__ != object.__init__:
self(obj.__init__)
return obj


def copy(source):
"""Copy a docstring from another source function (if present)."""
def do_copy(target):
if source.__doc__:
target.__doc__ = source.__doc__
return target
return do_copy


# Create a decorator that will house the various docstring snippets reused
# throughout Matplotlib.
dedent_interpd = interpd = _ArtistPropertiesSubstitution()
4 changes: 2 additions & 2 deletions lib/matplotlib/_enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"""

from enum import Enum, auto
from matplotlib import docstring
from matplotlib import _docstring


class _AutoStringNameEnum(Enum):
Expand Down Expand Up @@ -181,5 +181,5 @@ def demo():
+ ", ".join([f"'{cs.name}'" for cs in CapStyle]) \
+ "}"

docstring.interpd.update({'JoinStyle': JoinStyle.input_description,
_docstring.interpd.update({'JoinStyle': JoinStyle.input_description,
'CapStyle': CapStyle.input_description})
Loading