Skip to content

Commit 24c5048

Browse files
authored
MNT: Cleanup docstring substitution mechanisms (matplotlib#28795)
* MNT: Make Substitution and _ArtistPropertiesSubstitution independent They do not have relevant functional overlap. Thus, it's simpler to keep them completely separated. * Rename _ArtistPropertiesSubstitution.update() to register() While it's internally a dict.update. The logical process is a registration to make the names publically available. Also, remove the possibility to pass a dict. Passing kwargs is enough and we can simplify the API to only one type of usage.
1 parent 6404c95 commit 24c5048

File tree

15 files changed

+56
-37
lines changed

15 files changed

+56
-37
lines changed

lib/matplotlib/_docstring.py

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -68,12 +68,6 @@ def __call__(self, func):
6868
func.__doc__ = inspect.cleandoc(func.__doc__) % self.params
6969
return func
7070

71-
def update(self, *args, **kwargs):
72-
"""
73-
Update ``self.params`` (which must be a dict) with the supplied args.
74-
"""
75-
self.params.update(*args, **kwargs)
76-
7771

7872
class _ArtistKwdocLoader(dict):
7973
def __missing__(self, key):
@@ -89,23 +83,45 @@ def __missing__(self, key):
8983
return self.setdefault(key, kwdoc(cls))
9084

9185

92-
class _ArtistPropertiesSubstitution(Substitution):
86+
class _ArtistPropertiesSubstitution:
9387
"""
94-
A `.Substitution` with two additional features:
95-
96-
- Substitutions of the form ``%(classname:kwdoc)s`` (ending with the
97-
literal ":kwdoc" suffix) trigger lookup of an Artist subclass with the
98-
given *classname*, and are substituted with the `.kwdoc` of that class.
99-
- Decorating a class triggers substitution both on the class docstring and
100-
on the class' ``__init__`` docstring (which is a commonly required
101-
pattern for Artist subclasses).
88+
A class to substitute formatted placeholders in docstrings.
89+
90+
This is realized in a single instance ``_docstring.interpd``.
91+
92+
Use `~._ArtistPropertiesSubstition.register` to define placeholders and
93+
their substitution, e.g. ``_docstring.interpd.register(name="some value")``.
94+
95+
Use this as a decorator to apply the substitution::
96+
97+
@_docstring.interpd
98+
def some_func():
99+
'''Replace %(name)s.'''
100+
101+
Decorating a class triggers substitution both on the class docstring and
102+
on the class' ``__init__`` docstring (which is a commonly required
103+
pattern for Artist subclasses).
104+
105+
Substitutions of the form ``%(classname:kwdoc)s`` (ending with the
106+
literal ":kwdoc" suffix) trigger lookup of an Artist subclass with the
107+
given *classname*, and are substituted with the `.kwdoc` of that class.
102108
"""
103109

104110
def __init__(self):
105111
self.params = _ArtistKwdocLoader()
106112

113+
def register(self, **kwargs):
114+
"""
115+
Register substitutions.
116+
117+
``_docstring.interpd.register(name="some value")`` makes "name" available
118+
as a named parameter that will be replaced by "some value".
119+
"""
120+
self.params.update(**kwargs)
121+
107122
def __call__(self, obj):
108-
super().__call__(obj)
123+
if obj.__doc__:
124+
obj.__doc__ = inspect.cleandoc(obj.__doc__) % self.params
109125
if isinstance(obj, type) and obj.__init__ != object.__init__:
110126
self(obj.__init__)
111127
return obj

lib/matplotlib/_docstring.pyi

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,9 @@ class _ArtistKwdocLoader(dict[str, str]):
2121
def __missing__(self, key: str) -> str: ...
2222

2323

24-
class _ArtistPropertiesSubstitution(Substitution):
24+
class _ArtistPropertiesSubstitution:
2525
def __init__(self) -> None: ...
26+
def register(self, **kwargs) -> None: ...
2627
def __call__(self, obj: _T) -> _T: ...
2728

2829

lib/matplotlib/_enums.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -181,5 +181,7 @@ def demo():
181181
+ ", ".join([f"'{cs.name}'" for cs in CapStyle]) \
182182
+ "}"
183183

184-
_docstring.interpd.update({'JoinStyle': JoinStyle.input_description,
185-
'CapStyle': CapStyle.input_description})
184+
_docstring.interpd.register(
185+
JoinStyle=JoinStyle.input_description,
186+
CapStyle=CapStyle.input_description,
187+
)

lib/matplotlib/axes/_secondary_axes.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -319,4 +319,4 @@ def set_color(self, color):
319319
**kwargs : `~matplotlib.axes.Axes` properties.
320320
Other miscellaneous Axes parameters.
321321
'''
322-
_docstring.interpd.update(_secax_docstring=_secax_docstring)
322+
_docstring.interpd.register(_secax_docstring=_secax_docstring)

lib/matplotlib/cm.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -651,7 +651,7 @@ def _format_cursor_data_override(self, data):
651651

652652

653653
# The docstrings here must be generic enough to apply to all relevant methods.
654-
mpl._docstring.interpd.update(
654+
mpl._docstring.interpd.register(
655655
cmap_doc="""\
656656
cmap : str or `~matplotlib.colors.Colormap`, default: :rc:`image.cmap`
657657
The Colormap instance or registered colormap name used to map scalar data

lib/matplotlib/colorbar.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626

2727
_log = logging.getLogger(__name__)
2828

29-
_docstring.interpd.update(
29+
_docstring.interpd.register(
3030
_make_axes_kw_doc="""
3131
location : None or {'left', 'right', 'top', 'bottom'}
3232
The location, relative to the parent Axes, where the colorbar Axes

lib/matplotlib/contour.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -536,7 +536,7 @@ def _find_closest_point_on_path(xys, p):
536536
return (d2s[imin], projs[imin], (imin, imin+1))
537537

538538

539-
_docstring.interpd.update(contour_set_attributes=r"""
539+
_docstring.interpd.register(contour_set_attributes=r"""
540540
Attributes
541541
----------
542542
ax : `~matplotlib.axes.Axes`
@@ -1450,7 +1450,7 @@ def _initialize_x_y(self, z):
14501450
return np.meshgrid(x, y)
14511451

14521452

1453-
_docstring.interpd.update(contour_doc="""
1453+
_docstring.interpd.register(contour_doc="""
14541454
`.contour` and `.contourf` draw contour lines and filled contours,
14551455
respectively. Except as noted, function signatures and return values
14561456
are the same for both versions.

lib/matplotlib/legend.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,7 @@ def _update_bbox_to_anchor(self, loc_in_canvas):
305305
_loc_doc_base.format(parent='axes', default=':rc:`legend.loc`',
306306
best=_loc_doc_best, outside='') +
307307
_legend_kw_doc_base)
308-
_docstring.interpd.update(_legend_kw_axes=_legend_kw_axes_st)
308+
_docstring.interpd.register(_legend_kw_axes=_legend_kw_axes_st)
309309

310310
_outside_doc = """
311311
If a figure is using the constrained layout manager, the string codes
@@ -323,20 +323,20 @@ def _update_bbox_to_anchor(self, loc_in_canvas):
323323
_loc_doc_base.format(parent='figure', default="'upper right'",
324324
best='', outside=_outside_doc) +
325325
_legend_kw_doc_base)
326-
_docstring.interpd.update(_legend_kw_figure=_legend_kw_figure_st)
326+
_docstring.interpd.register(_legend_kw_figure=_legend_kw_figure_st)
327327

328328
_legend_kw_both_st = (
329329
_loc_doc_base.format(parent='axes/figure',
330330
default=":rc:`legend.loc` for Axes, 'upper right' for Figure",
331331
best=_loc_doc_best, outside=_outside_doc) +
332332
_legend_kw_doc_base)
333-
_docstring.interpd.update(_legend_kw_doc=_legend_kw_both_st)
333+
_docstring.interpd.register(_legend_kw_doc=_legend_kw_both_st)
334334

335335
_legend_kw_set_loc_st = (
336336
_loc_doc_base.format(parent='axes/figure',
337337
default=":rc:`legend.loc` for Axes, 'upper right' for Figure",
338338
best=_loc_doc_best, outside=_outside_doc))
339-
_docstring.interpd.update(_legend_kw_set_loc_doc=_legend_kw_set_loc_st)
339+
_docstring.interpd.register(_legend_kw_set_loc_doc=_legend_kw_set_loc_st)
340340

341341

342342
class Legend(Artist):

lib/matplotlib/mlab.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -400,7 +400,7 @@ def _single_spectrum_helper(
400400

401401

402402
# Split out these keyword docs so that they can be used elsewhere
403-
_docstring.interpd.update(
403+
_docstring.interpd.register(
404404
Spectral="""\
405405
Fs : float, default: 2
406406
The sampling frequency (samples per time unit). It is used to calculate

lib/matplotlib/patches.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1552,7 +1552,7 @@ def _make_verts(self):
15521552
]
15531553

15541554

1555-
_docstring.interpd.update(
1555+
_docstring.interpd.register(
15561556
FancyArrow="\n".join(
15571557
(inspect.getdoc(FancyArrow.__init__) or "").splitlines()[2:]))
15581558

@@ -2290,7 +2290,7 @@ def __init_subclass__(cls):
22902290
# - %(BoxStyle:table_and_accepts)s
22912291
# - %(ConnectionStyle:table_and_accepts)s
22922292
# - %(ArrowStyle:table_and_accepts)s
2293-
_docstring.interpd.update({
2293+
_docstring.interpd.register(**{
22942294
f"{cls.__name__}:table": cls.pprint_styles(),
22952295
f"{cls.__name__}:table_and_accepts": (
22962296
cls.pprint_styles()

0 commit comments

Comments
 (0)