Skip to content

Commit c10a80d

Browse files
committed
Use kwonlyargs instead of popping from kwargs
1 parent 213f399 commit c10a80d

File tree

15 files changed

+137
-202
lines changed

15 files changed

+137
-202
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
Explicit arguments instead of \*args, \*\*kwargs
2+
------------------------------------------------
3+
4+
:PEP:`3102` describes keyword-only arguments, which allow Matplotlib
5+
to provide explicit call signatures - where we previously used
6+
``*args, **kwargs`` and ``kwargs.pop``, we can now expose named
7+
arguments. In some places, unknown kwargs were previously ignored but
8+
now raise ``TypeError`` because ``**kwargs`` has been removed.
9+
10+
- :meth:`matplotlib.axes.Axes.stem` no longer accepts unknown keywords,
11+
and raises ``TypeError`` instead of emitting a deprecation.
12+
- :meth:`mpl_toolkits.axes_grid1.axes_divider.SubPlotDivider` raises
13+
``TypeError`` instead of ``Exception`` when passed unknown kwargs.

doc/devel/contributing.rst

+5-6
Original file line numberDiff line numberDiff line change
@@ -394,17 +394,16 @@ on, use the key/value keyword args in the function definition rather
394394
than the ``**kwargs`` idiom.
395395

396396
In some cases, you may want to consume some keys in the local
397-
function, and let others pass through. You can ``pop`` the ones to be
398-
used locally and pass on the rest. For example, in
397+
function, and let others pass through. Instead of ``pop``ing the
398+
arguments to use, specify them as keyword-only arguments to the local
399+
function. This makes it obvious at a glance which arguments will be
400+
consumed in the function. For example, in
399401
:meth:`~matplotlib.axes.Axes.plot`, ``scalex`` and ``scaley`` are
400402
local arguments and the rest are passed on as
401403
:meth:`~matplotlib.lines.Line2D` keyword arguments::
402404

403405
# in axes/_axes.py
404-
def plot(self, *args, **kwargs):
405-
scalex = kwargs.pop('scalex', True)
406-
scaley = kwargs.pop('scaley', True)
407-
if not self._hold: self.cla()
406+
def plot(self, *args, scalex=True, scaley=True, **kwargs):
408407
lines = []
409408
for line in self._get_lines(*args, **kwargs):
410409
self.add_line(line)

lib/matplotlib/axes/_axes.py

+16-65
Original file line numberDiff line numberDiff line change
@@ -1114,7 +1114,7 @@ def eventplot(self, positions, orientation='horizontal', lineoffsets=1,
11141114
positional_parameter_names=_plot_args_replacer,
11151115
label_namer=None)
11161116
@docstring.dedent_interpd
1117-
def plot(self, *args, **kwargs):
1117+
def plot(self, *args, scalex=True, scaley=True, **kwargs):
11181118
"""
11191119
Plot y versus x as lines and/or markers.
11201120
@@ -1341,8 +1341,6 @@ def plot(self, *args, **kwargs):
13411341
'k^:' # black triangle_up markers connected by a dotted line
13421342
13431343
"""
1344-
scalex = kwargs.pop('scalex', True)
1345-
scaley = kwargs.pop('scaley', True)
13461344
lines = []
13471345

13481346
kwargs = cbook.normalize_kwargs(kwargs, mlines.Line2D._alias_map)
@@ -1734,7 +1732,7 @@ def xcorr(self, x, y, normed=True, detrend=mlab.detrend_none,
17341732
#### Specialized plotting
17351733

17361734
@_preprocess_data(replace_names=["x", "y"], label_namer="y")
1737-
def step(self, x, y, *args, **kwargs):
1735+
def step(self, x, y, *args, where='pre', linestyle='', **kwargs):
17381736
"""
17391737
Make a step plot.
17401738
@@ -1795,12 +1793,10 @@ def step(self, x, y, *args, **kwargs):
17951793
-----
17961794
.. [notes section required to get data note injection right]
17971795
"""
1798-
where = kwargs.pop('where', 'pre')
17991796
if where not in ('pre', 'post', 'mid'):
18001797
raise ValueError("'where' argument to step must be "
18011798
"'pre', 'post' or 'mid'")
1802-
usr_linestyle = kwargs.pop('linestyle', '')
1803-
kwargs['linestyle'] = 'steps-' + where + usr_linestyle
1799+
kwargs['linestyle'] = 'steps-' + where + linestyle
18041800

18051801
return self.plot(x, y, *args, **kwargs)
18061802

@@ -2268,7 +2264,8 @@ def broken_barh(self, xranges, yrange, **kwargs):
22682264
return col
22692265

22702266
@_preprocess_data(replace_all_args=True, label_namer=None)
2271-
def stem(self, *args, **kwargs):
2267+
def stem(self, *args, linefmt=None, markerfmt=None, basefmt=None,
2268+
bottom=0, label=None):
22722269
"""
22732270
Create a stem plot.
22742271
@@ -2328,15 +2325,6 @@ def stem(self, *args, **kwargs):
23282325
The label to use for the stems in legends.
23292326
23302327
2331-
Other Parameters
2332-
----------------
2333-
**kwargs
2334-
No other parameters are supported. They are currently ignored
2335-
silently for backward compatibility. This behavior is deprecated.
2336-
Future versions will not accept any other parameters and will
2337-
raise a TypeError instead.
2338-
2339-
23402328
Returns
23412329
-------
23422330
:class:`~matplotlib.container.StemContainer`
@@ -2353,41 +2341,18 @@ def stem(self, *args, **kwargs):
23532341
which inspired this method.
23542342
23552343
"""
2356-
2357-
# kwargs handling
2358-
# We would like to have a signature with explicit kewords:
2359-
# stem(*args, linefmt=None, markerfmt=None, basefmt=None,
2360-
# bottom=0, label=None)
2361-
# Unfortunately, this is not supported in Python 2.x. There, *args
2362-
# can only exist after keyword arguments.
2363-
linefmt = kwargs.pop('linefmt', None)
2364-
markerfmt = kwargs.pop('markerfmt', None)
2365-
basefmt = kwargs.pop('basefmt', None)
2366-
bottom = kwargs.pop('bottom', None)
2367-
if bottom is None:
2368-
bottom = 0
2369-
label = kwargs.pop('label', None)
2370-
if kwargs:
2371-
warn_deprecated(since='2.2',
2372-
message="stem() got an unexpected keyword "
2373-
"argument '%s'. This will raise a "
2374-
"TypeError in future versions." % (
2375-
next(k for k in kwargs), )
2376-
)
2377-
23782344
# Assume there's at least one data array
23792345
y = np.asarray(args[0])
23802346
args = args[1:]
23812347

23822348
# Try a second one
23832349
try:
2384-
second = np.asarray(args[0], dtype=float)
2385-
x, y = y, second
2386-
args = args[1:]
2350+
x, y = y, np.asarray(args[0], dtype=float)
23872351
except (IndexError, ValueError):
23882352
# The second array doesn't make sense, or it doesn't exist
2389-
second = np.arange(len(y))
2390-
x = second
2353+
x = np.arange(len(y))
2354+
else:
2355+
args = args[1:]
23912356

23922357
# defaults for formats
23932358
if linefmt is None:
@@ -5242,7 +5207,8 @@ def _pcolorargs(funcname, *args, allmatch=False):
52425207

52435208
@_preprocess_data(label_namer=None)
52445209
@docstring.dedent_interpd
5245-
def pcolor(self, *args, **kwargs):
5210+
def pcolor(self, *args, alpha=None, norm=None, cmap=None, vmin=None,
5211+
vmax=None, **kwargs):
52465212
"""
52475213
Create a pseudocolor plot of a 2-D array.
52485214
@@ -5381,12 +5347,6 @@ def pcolor(self, *args, **kwargs):
53815347
not specified, or if ``X`` and ``Y`` have one more row and column than
53825348
``C``.
53835349
"""
5384-
alpha = kwargs.pop('alpha', None)
5385-
norm = kwargs.pop('norm', None)
5386-
cmap = kwargs.pop('cmap', None)
5387-
vmin = kwargs.pop('vmin', None)
5388-
vmax = kwargs.pop('vmax', None)
5389-
53905350
X, Y, C = self._pcolorargs('pcolor', *args, allmatch=False)
53915351
Ny, Nx = X.shape
53925352

@@ -5488,7 +5448,8 @@ def pcolor(self, *args, **kwargs):
54885448

54895449
@_preprocess_data(label_namer=None)
54905450
@docstring.dedent_interpd
5491-
def pcolormesh(self, *args, **kwargs):
5451+
def pcolormesh(self, *args, alpha=None, norm=None, cmap=None, vmin=None,
5452+
vmax=None, shading='flat', antialiased=False, **kwargs):
54925453
"""
54935454
Plot a quadrilateral mesh.
54945455
@@ -5564,13 +5525,7 @@ def pcolormesh(self, *args, **kwargs):
55645525
55655526
%(QuadMesh)s
55665527
"""
5567-
alpha = kwargs.pop('alpha', None)
5568-
norm = kwargs.pop('norm', None)
5569-
cmap = kwargs.pop('cmap', None)
5570-
vmin = kwargs.pop('vmin', None)
5571-
vmax = kwargs.pop('vmax', None)
5572-
shading = kwargs.pop('shading', 'flat').lower()
5573-
antialiased = kwargs.pop('antialiased', False)
5528+
shading = shading.lower()
55745529
kwargs.setdefault('edgecolors', 'None')
55755530

55765531
allmatch = (shading == 'gouraud')
@@ -5625,7 +5580,8 @@ def pcolormesh(self, *args, **kwargs):
56255580

56265581
@_preprocess_data(label_namer=None)
56275582
@docstring.dedent_interpd
5628-
def pcolorfast(self, *args, **kwargs):
5583+
def pcolorfast(self, *args, alpha=None, norm=None, cmap=None, vmin=None,
5584+
vmax=None, **kwargs):
56295585
"""
56305586
pseudocolor plot of a 2-D array
56315587
@@ -5707,11 +5663,6 @@ def pcolorfast(self, *args, **kwargs):
57075663
collection in the general quadrilateral case.
57085664
57095665
"""
5710-
alpha = kwargs.pop('alpha', None)
5711-
norm = kwargs.pop('norm', None)
5712-
cmap = kwargs.pop('cmap', None)
5713-
vmin = kwargs.pop('vmin', None)
5714-
vmax = kwargs.pop('vmax', None)
57155666
if norm is not None and not isinstance(norm, mcolors.Normalize):
57165667
raise ValueError(
57175668
"'norm' must be an instance of 'mcolors.Normalize'")

lib/matplotlib/backend_bases.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -2084,7 +2084,8 @@ def _get_output_canvas(self, fmt):
20842084
.format(fmt, ", ".join(sorted(self.get_supported_filetypes()))))
20852085

20862086
def print_figure(self, filename, dpi=None, facecolor=None, edgecolor=None,
2087-
orientation='portrait', format=None, **kwargs):
2087+
orientation='portrait', format=None,
2088+
*, bbox_inches=None, **kwargs):
20882089
"""
20892090
Render the figure to hardcopy. Set the figure patch face and edge
20902091
colors. This is useful because some of the GUIs have a gray figure
@@ -2165,7 +2166,6 @@ def print_figure(self, filename, dpi=None, facecolor=None, edgecolor=None,
21652166
self.figure.set_facecolor(facecolor)
21662167
self.figure.set_edgecolor(edgecolor)
21672168

2168-
bbox_inches = kwargs.pop("bbox_inches", None)
21692169
if bbox_inches is None:
21702170
bbox_inches = rcParams['savefig.bbox']
21712171

lib/matplotlib/backends/backend_ps.py

+9-8
Original file line numberDiff line numberDiff line change
@@ -930,31 +930,32 @@ def print_ps(self, outfile, *args, **kwargs):
930930
def print_eps(self, outfile, *args, **kwargs):
931931
return self._print_ps(outfile, 'eps', *args, **kwargs)
932932

933-
def _print_ps(self, outfile, format, *args, **kwargs):
934-
papertype = kwargs.pop("papertype", rcParams['ps.papersize'])
933+
def _print_ps(self, outfile, format, *args,
934+
papertype=None, dpi=72, facecolor='w', edgecolor='w',
935+
orientation='portrait',
936+
**kwargs):
937+
if papertype is None:
938+
papertype = rcParams['ps.papersize']
935939
papertype = papertype.lower()
936940
if papertype == 'auto':
937941
pass
938942
elif papertype not in papersize:
939943
raise RuntimeError('%s is not a valid papertype. Use one of %s' %
940944
(papertype, ', '.join(papersize)))
941945

942-
orientation = kwargs.pop("orientation", "portrait").lower()
946+
orientation = orientation.lower()
943947
if orientation == 'landscape': isLandscape = True
944948
elif orientation == 'portrait': isLandscape = False
945949
else: raise RuntimeError('Orientation must be "portrait" or "landscape"')
946950

947951
self.figure.set_dpi(72) # Override the dpi kwarg
948-
imagedpi = kwargs.pop("dpi", 72)
949-
facecolor = kwargs.pop("facecolor", "w")
950-
edgecolor = kwargs.pop("edgecolor", "w")
951952

952953
if rcParams['text.usetex']:
953-
self._print_figure_tex(outfile, format, imagedpi, facecolor, edgecolor,
954+
self._print_figure_tex(outfile, format, dpi, facecolor, edgecolor,
954955
orientation, isLandscape, papertype,
955956
**kwargs)
956957
else:
957-
self._print_figure(outfile, format, imagedpi, facecolor, edgecolor,
958+
self._print_figure(outfile, format, dpi, facecolor, edgecolor,
958959
orientation, isLandscape, papertype,
959960
**kwargs)
960961

lib/matplotlib/colorbar.py

+1-5
Original file line numberDiff line numberDiff line change
@@ -1323,7 +1323,7 @@ def make_axes(parents, location=None, orientation=None, fraction=0.15,
13231323

13241324

13251325
@docstring.Substitution(make_axes_kw_doc)
1326-
def make_axes_gridspec(parent, **kw):
1326+
def make_axes_gridspec(parent, *, fraction=0.15, shrink=1.0, aspect=20, **kw):
13271327
'''
13281328
Resize and reposition a parent axes, and return a child axes
13291329
suitable for a colorbar. This function is similar to
@@ -1360,10 +1360,6 @@ def make_axes_gridspec(parent, **kw):
13601360
orientation = kw.setdefault('orientation', 'vertical')
13611361
kw['ticklocation'] = 'auto'
13621362

1363-
fraction = kw.pop('fraction', 0.15)
1364-
shrink = kw.pop('shrink', 1.0)
1365-
aspect = kw.pop('aspect', 20)
1366-
13671363
x1 = 1 - fraction
13681364

13691365
# for shrinking

lib/matplotlib/contour.py

+17-18
Original file line numberDiff line numberDiff line change
@@ -791,7 +791,12 @@ class ContourSet(cm.ScalarMappable, ContourLabeler):
791791
levels for filled contours. See :meth:`_process_colors`.
792792
"""
793793

794-
def __init__(self, ax, *args, **kwargs):
794+
def __init__(self, ax, *args,
795+
levels=None, filled=False, linewidths=None, linestyles=None,
796+
hatches=(None,), alpha=None, origin=None, extent=None,
797+
cmap=None, colors=None, norm=None, vmin=None, vmax=None,
798+
extend='neither', antialiased=False,
799+
**kwargs):
795800
"""
796801
Draw contour lines or filled regions, depending on
797802
whether keyword arg *filled* is ``False`` (default) or ``True``.
@@ -837,23 +842,17 @@ def __init__(self, ax, *args, **kwargs):
837842
`~.Axes.contour`.
838843
"""
839844
self.ax = ax
840-
self.levels = kwargs.pop('levels', None)
841-
self.filled = kwargs.pop('filled', False)
842-
self.linewidths = kwargs.pop('linewidths', None)
843-
self.linestyles = kwargs.pop('linestyles', None)
844-
845-
self.hatches = kwargs.pop('hatches', [None])
846-
847-
self.alpha = kwargs.pop('alpha', None)
848-
self.origin = kwargs.pop('origin', None)
849-
self.extent = kwargs.pop('extent', None)
850-
cmap = kwargs.pop('cmap', None)
851-
self.colors = kwargs.pop('colors', None)
852-
norm = kwargs.pop('norm', None)
853-
vmin = kwargs.pop('vmin', None)
854-
vmax = kwargs.pop('vmax', None)
855-
self.extend = kwargs.pop('extend', 'neither')
856-
self.antialiased = kwargs.pop('antialiased', None)
845+
self.levels = levels
846+
self.filled = filled
847+
self.linewidths = linewidths
848+
self.linestyles = linestyles
849+
self.hatches = hatches
850+
self.alpha = alpha
851+
self.origin = origin
852+
self.extent = extent
853+
self.colors = colors
854+
self.extend = extend
855+
self.antialiased = antialiased
857856
if self.antialiased is None and self.filled:
858857
self.antialiased = False # eliminate artifacts; we are not
859858
# stroking the boundaries.

lib/matplotlib/figure.py

+5-4
Original file line numberDiff line numberDiff line change
@@ -1756,7 +1756,7 @@ def add_axobserver(self, func):
17561756
"""Whenever the axes state change, ``func(self)`` will be called."""
17571757
self._axobservers.append(func)
17581758

1759-
def savefig(self, fname, **kwargs):
1759+
def savefig(self, fname, *, frameon=None, transparent=None, **kwargs):
17601760
"""
17611761
Save the current figure.
17621762
@@ -1840,9 +1840,10 @@ def savefig(self, fname, **kwargs):
18401840
18411841
"""
18421842
kwargs.setdefault('dpi', rcParams['savefig.dpi'])
1843-
frameon = kwargs.pop('frameon', rcParams['savefig.frameon'])
1844-
transparent = kwargs.pop('transparent',
1845-
rcParams['savefig.transparent'])
1843+
if frameon is None:
1844+
frameon = rcParams['savefig.frameon']
1845+
if transparent is None:
1846+
transparent = rcParams['savefig.transparent']
18461847

18471848
if transparent:
18481849
kwargs.setdefault('facecolor', 'none')

0 commit comments

Comments
 (0)