Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 6102de5

Browse filesBrowse files
committed
Better signature and docstring for Artist.set
1 parent 831a13c commit 6102de5
Copy full SHA for 6102de5

File tree

3 files changed

+100
-2
lines changed
Filter options

3 files changed

+100
-2
lines changed

‎doc/api/axes_api.rst

Copy file name to clipboardExpand all lines: doc/api/axes_api.rst
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -606,3 +606,4 @@ Other
606606
Axes.get_default_bbox_extra_artists
607607
Axes.get_transformed_clip_path_and_affine
608608
Axes.has_data
609+
Axes.set

‎lib/matplotlib/artist.py

Copy file name to clipboardExpand all lines: lib/matplotlib/artist.py
+64-2Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import contextlib
33
from functools import wraps
44
import inspect
5+
from inspect import Signature, Parameter
56
import logging
67
from numbers import Number
78
import re
@@ -10,7 +11,7 @@
1011
import numpy as np
1112

1213
import matplotlib as mpl
13-
from . import _api, cbook
14+
from . import _api, cbook, docstring
1415
from .path import Path
1516
from .transforms import (Bbox, IdentityTransform, Transform, TransformedBbox,
1617
TransformedPatchPath, TransformedPath)
@@ -84,6 +85,12 @@ def _stale_axes_callback(self, val):
8485
_XYPair = namedtuple("_XYPair", "x y")
8586

8687

88+
class _Unset:
89+
def __repr__(self):
90+
return "<UNSET>"
91+
UNSET = _Unset()
92+
93+
8794
class Artist:
8895
"""
8996
Abstract base class for objects that render into a FigureCanvas.
@@ -93,6 +100,55 @@ class Artist:
93100

94101
zorder = 0
95102

103+
def __init_subclass__(cls):
104+
# Inject custom set() methods into the subclass with signature and
105+
# docstring based on the subclasses' properties.
106+
107+
if not hasattr(cls.set, '_autogenerated_signature'):
108+
# Don't overwrite cls.set if the subclass or one of its parents
109+
# has defined a set method set itself.
110+
# If there was no explicit definition, cls.set is inherited from
111+
# the hierarchie of auto-generated set methods, which hold the
112+
# flag _autogenerated_signature.
113+
return
114+
115+
def set(self, **kwargs):
116+
Artist.set(self, **kwargs)
117+
118+
cls.set = set
119+
cls._update_set_signature_and_docstring()
120+
121+
_PROPERTIES_EXCLUDED_FROM_SET = [
122+
'navigate_mode', # not a user-facing function
123+
'figure', # changing the figure is such a profound operation
124+
# that we don't want this in set()
125+
'3d_properties', # cannot be used as a keyword do to leading digit
126+
]
127+
128+
@classmethod
129+
def _update_set_signature_and_docstring(cls):
130+
"""
131+
Update the signature of the set function to list all properties
132+
as keyword arguments.
133+
134+
Property aliases are not listed in the signature for brevity, but
135+
are still accepted as keyword arguments.
136+
"""
137+
cls.set.__signature__ = Signature(
138+
[Parameter("self", Parameter.POSITIONAL_OR_KEYWORD),
139+
*[Parameter(prop, Parameter.KEYWORD_ONLY, default=UNSET)
140+
for prop in ArtistInspector(cls).get_setters()
141+
if prop not in Artist._PROPERTIES_EXCLUDED_FROM_SET]])
142+
cls.set._autogenerated_signature = True
143+
144+
cls.set.__doc__ = "\n".join([
145+
"Set multiple properties at once.",
146+
"",
147+
"Supported properties are:",
148+
"",
149+
f"%({cls.__name__}:kwdoc)s"])
150+
docstring.dedent_interpd(cls.set)
151+
96152
def __init__(self):
97153
self._stale = True
98154
self.stale_callback = None
@@ -1096,7 +1152,9 @@ def properties(self):
10961152
return ArtistInspector(self).properties()
10971153

10981154
def set(self, **kwargs):
1099-
"""A property batch setter. Pass *kwargs* to set properties."""
1155+
# docstring and signature are auto-generated via
1156+
# Artist._update_set_signature_and_docstring() at the end of the
1157+
# module.
11001158
kwargs = cbook.normalize_kwargs(kwargs, self)
11011159
return self.update(kwargs)
11021160

@@ -1656,3 +1714,7 @@ def kwdoc(artist):
16561714
return ('\n'.join(ai.pprint_setters_rest(leadingspace=4))
16571715
if mpl.rcParams['docstring.hardcopy'] else
16581716
'Properties:\n' + '\n'.join(ai.pprint_setters(leadingspace=4)))
1717+
1718+
# We defer this to the end of them module, because it needs ArtistInspector
1719+
# to be defined.
1720+
Artist._update_set_signature_and_docstring()

‎lib/matplotlib/tests/test_artist.py

Copy file name to clipboardExpand all lines: lib/matplotlib/tests/test_artist.py
+35Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,3 +340,38 @@ def func(artist):
340340
art.remove_callback(oid)
341341
art.pchanged() # must not call the callback anymore
342342
assert func.counter == 2
343+
344+
345+
def test_set_signature():
346+
"""Test autogenerated ``set()`` for Artist subclasses."""
347+
class MyArtist1(martist.Artist):
348+
def set_myparam1(self, val):
349+
pass
350+
351+
assert hasattr(MyArtist1.set, '_autogenerated_signature')
352+
assert 'myparam1' in MyArtist1.set.__doc__
353+
354+
class MyArtist2(MyArtist1):
355+
def set_myparam2(self, val):
356+
pass
357+
358+
assert hasattr(MyArtist2.set, '_autogenerated_signature')
359+
assert 'myparam1' in MyArtist2.set.__doc__
360+
assert 'myparam2' in MyArtist2.set.__doc__
361+
362+
363+
def test_set_is_overwritten():
364+
"""set() defined in Artist subclasses should not be overwritten."""
365+
class MyArtist3(martist.Artist):
366+
367+
def set(self, **kwargs):
368+
"""Not overwritten."""
369+
pass
370+
371+
assert not hasattr(MyArtist3.set, '_autogenerated_signature')
372+
assert MyArtist3.set.__doc__ == "Not overwritten."
373+
374+
class MyArtist4(MyArtist3):
375+
pass
376+
377+
assert MyArtist4.set is MyArtist3.set

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.