22import contextlib
33from functools import wraps
44import inspect
5+ from inspect import Signature , Parameter
56import logging
67from numbers import Number
78import re
@@ -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+
8794class Artist :
8895 """
8996 Abstract base class for objects that render into a FigureCanvas.
@@ -93,6 +100,51 @@ 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 hierarchy of auto-generated set methods, which hold the
112+ # flag _autogenerated_signature.
113+ return
114+
115+ cls .set = lambda self , ** kwargs : Artist .set (self , ** kwargs )
116+ cls .set .__name__ = "set"
117+ cls .set .__qualname__ = f"{ cls .__qualname__ } .set"
118+ cls ._update_set_signature_and_docstring ()
119+
120+ _PROPERTIES_EXCLUDED_FROM_SET = [
121+ 'navigate_mode' , # not a user-facing function
122+ 'figure' , # changing the figure is such a profound operation
123+ # that we don't want this in set()
124+ '3d_properties' , # cannot be used as a keyword due to leading digit
125+ ]
126+
127+ @classmethod
128+ def _update_set_signature_and_docstring (cls ):
129+ """
130+ Update the signature of the set function to list all properties
131+ as keyword arguments.
132+
133+ Property aliases are not listed in the signature for brevity, but
134+ are still accepted as keyword arguments.
135+ """
136+ cls .set .__signature__ = Signature (
137+ [Parameter ("self" , Parameter .POSITIONAL_OR_KEYWORD ),
138+ * [Parameter (prop , Parameter .KEYWORD_ONLY , default = _UNSET )
139+ for prop in ArtistInspector (cls ).get_setters ()
140+ if prop not in Artist ._PROPERTIES_EXCLUDED_FROM_SET ]])
141+ cls .set ._autogenerated_signature = True
142+
143+ cls .set .__doc__ = (
144+ "Set multiple properties at once.\n \n "
145+ "Supported properties are\n \n "
146+ + kwdoc (cls ))
147+
96148 def __init__ (self ):
97149 self ._stale = True
98150 self .stale_callback = None
@@ -1096,7 +1148,9 @@ def properties(self):
10961148 return ArtistInspector (self ).properties ()
10971149
10981150 def set (self , ** kwargs ):
1099- """A property batch setter. Pass *kwargs* to set properties."""
1151+ # docstring and signature are auto-generated via
1152+ # Artist._update_set_signature_and_docstring() at the end of the
1153+ # module.
11001154 kwargs = cbook .normalize_kwargs (kwargs , self )
11011155 return self .update (kwargs )
11021156
@@ -1656,3 +1710,7 @@ def kwdoc(artist):
16561710 return ('\n ' .join (ai .pprint_setters_rest (leadingspace = 4 ))
16571711 if mpl .rcParams ['docstring.hardcopy' ] else
16581712 'Properties:\n ' + '\n ' .join (ai .pprint_setters (leadingspace = 4 )))
1713+
1714+ # We defer this to the end of them module, because it needs ArtistInspector
1715+ # to be defined.
1716+ Artist ._update_set_signature_and_docstring ()
0 commit comments