Skip to content

Use kwonlyargs instead of popping from kwargs #11145

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 1 commit into from
May 2, 2018
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
13 changes: 13 additions & 0 deletions doc/api/next_api_changes/2018-04-30-ZHD.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Explicit arguments instead of \*args, \*\*kwargs
------------------------------------------------

:PEP:`3102` describes keyword-only arguments, which allow Matplotlib
to provide explicit call signatures - where we previously used
``*args, **kwargs`` and ``kwargs.pop``, we can now expose named
arguments. In some places, unknown kwargs were previously ignored but
now raise ``TypeError`` because ``**kwargs`` has been removed.

- :meth:`matplotlib.axes.Axes.stem` no longer accepts unknown keywords,
and raises ``TypeError`` instead of emitting a deprecation.
- :meth:`mpl_toolkits.axes_grid1.axes_divider.SubPlotDivider` raises
``TypeError`` instead of ``Exception`` when passed unknown kwargs.
11 changes: 5 additions & 6 deletions doc/devel/contributing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -394,17 +394,16 @@ on, use the key/value keyword args in the function definition rather
than the ``**kwargs`` idiom.

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

# in axes/_axes.py
def plot(self, *args, **kwargs):
scalex = kwargs.pop('scalex', True)
scaley = kwargs.pop('scaley', True)
if not self._hold: self.cla()
def plot(self, *args, scalex=True, scaley=True, **kwargs):
lines = []
for line in self._get_lines(*args, **kwargs):
self.add_line(line)
Expand Down
81 changes: 16 additions & 65 deletions lib/matplotlib/axes/_axes.py
Original file line number Diff line number Diff line change
Expand Up @@ -1114,7 +1114,7 @@ def eventplot(self, positions, orientation='horizontal', lineoffsets=1,
positional_parameter_names=_plot_args_replacer,
label_namer=None)
@docstring.dedent_interpd
def plot(self, *args, **kwargs):
def plot(self, *args, scalex=True, scaley=True, **kwargs):
"""
Plot y versus x as lines and/or markers.

Expand Down Expand Up @@ -1341,8 +1341,6 @@ def plot(self, *args, **kwargs):
'k^:' # black triangle_up markers connected by a dotted line

"""
scalex = kwargs.pop('scalex', True)
scaley = kwargs.pop('scaley', True)
lines = []

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

@_preprocess_data(replace_names=["x", "y"], label_namer="y")
def step(self, x, y, *args, **kwargs):
def step(self, x, y, *args, where='pre', linestyle='', **kwargs):
"""
Make a step plot.

Expand Down Expand Up @@ -1795,12 +1793,10 @@ def step(self, x, y, *args, **kwargs):
-----
.. [notes section required to get data note injection right]
"""
where = kwargs.pop('where', 'pre')
if where not in ('pre', 'post', 'mid'):
raise ValueError("'where' argument to step must be "
"'pre', 'post' or 'mid'")
usr_linestyle = kwargs.pop('linestyle', '')
kwargs['linestyle'] = 'steps-' + where + usr_linestyle
kwargs['linestyle'] = 'steps-' + where + linestyle

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

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

@_preprocess_data(replace_all_args=True, label_namer=None)
def stem(self, *args, **kwargs):
def stem(self, *args, linefmt=None, markerfmt=None, basefmt=None,
bottom=0, label=None):
"""
Create a stem plot.

Expand Down Expand Up @@ -2328,15 +2325,6 @@ def stem(self, *args, **kwargs):
The label to use for the stems in legends.


Other Parameters
----------------
**kwargs
No other parameters are supported. They are currently ignored
silently for backward compatibility. This behavior is deprecated.
Future versions will not accept any other parameters and will
raise a TypeError instead.


Returns
-------
:class:`~matplotlib.container.StemContainer`
Expand All @@ -2353,41 +2341,18 @@ def stem(self, *args, **kwargs):
which inspired this method.

"""

# kwargs handling
# We would like to have a signature with explicit kewords:
# stem(*args, linefmt=None, markerfmt=None, basefmt=None,
# bottom=0, label=None)
# Unfortunately, this is not supported in Python 2.x. There, *args
# can only exist after keyword arguments.
linefmt = kwargs.pop('linefmt', None)
markerfmt = kwargs.pop('markerfmt', None)
basefmt = kwargs.pop('basefmt', None)
bottom = kwargs.pop('bottom', None)
if bottom is None:
bottom = 0
label = kwargs.pop('label', None)
if kwargs:
warn_deprecated(since='2.2',
message="stem() got an unexpected keyword "
"argument '%s'. This will raise a "
"TypeError in future versions." % (
next(k for k in kwargs), )
)

# Assume there's at least one data array
y = np.asarray(args[0])
args = args[1:]

# Try a second one
try:
second = np.asarray(args[0], dtype=float)
x, y = y, second
args = args[1:]
x, y = y, np.asarray(args[0], dtype=float)
except (IndexError, ValueError):
# The second array doesn't make sense, or it doesn't exist
second = np.arange(len(y))
x = second
x = np.arange(len(y))
else:
args = args[1:]

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

@_preprocess_data(label_namer=None)
@docstring.dedent_interpd
def pcolor(self, *args, **kwargs):
def pcolor(self, *args, alpha=None, norm=None, cmap=None, vmin=None,
vmax=None, **kwargs):
"""
Create a pseudocolor plot of a 2-D array.

Expand Down Expand Up @@ -5381,12 +5347,6 @@ def pcolor(self, *args, **kwargs):
not specified, or if ``X`` and ``Y`` have one more row and column than
``C``.
"""
alpha = kwargs.pop('alpha', None)
norm = kwargs.pop('norm', None)
cmap = kwargs.pop('cmap', None)
vmin = kwargs.pop('vmin', None)
vmax = kwargs.pop('vmax', None)

X, Y, C = self._pcolorargs('pcolor', *args, allmatch=False)
Ny, Nx = X.shape

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

@_preprocess_data(label_namer=None)
@docstring.dedent_interpd
def pcolormesh(self, *args, **kwargs):
def pcolormesh(self, *args, alpha=None, norm=None, cmap=None, vmin=None,
vmax=None, shading='flat', antialiased=False, **kwargs):
"""
Plot a quadrilateral mesh.

Expand Down Expand Up @@ -5564,13 +5525,7 @@ def pcolormesh(self, *args, **kwargs):

%(QuadMesh)s
"""
alpha = kwargs.pop('alpha', None)
norm = kwargs.pop('norm', None)
cmap = kwargs.pop('cmap', None)
vmin = kwargs.pop('vmin', None)
vmax = kwargs.pop('vmax', None)
shading = kwargs.pop('shading', 'flat').lower()
antialiased = kwargs.pop('antialiased', False)
shading = shading.lower()
kwargs.setdefault('edgecolors', 'None')

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

@_preprocess_data(label_namer=None)
@docstring.dedent_interpd
def pcolorfast(self, *args, **kwargs):
def pcolorfast(self, *args, alpha=None, norm=None, cmap=None, vmin=None,
vmax=None, **kwargs):
"""
pseudocolor plot of a 2-D array

Expand Down Expand Up @@ -5707,11 +5663,6 @@ def pcolorfast(self, *args, **kwargs):
collection in the general quadrilateral case.

"""
alpha = kwargs.pop('alpha', None)
norm = kwargs.pop('norm', None)
cmap = kwargs.pop('cmap', None)
vmin = kwargs.pop('vmin', None)
vmax = kwargs.pop('vmax', None)
if norm is not None and not isinstance(norm, mcolors.Normalize):
raise ValueError(
"'norm' must be an instance of 'mcolors.Normalize'")
Expand Down
4 changes: 2 additions & 2 deletions lib/matplotlib/backend_bases.py
Original file line number Diff line number Diff line change
Expand Up @@ -2084,7 +2084,8 @@ def _get_output_canvas(self, fmt):
.format(fmt, ", ".join(sorted(self.get_supported_filetypes()))))

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

bbox_inches = kwargs.pop("bbox_inches", None)
if bbox_inches is None:
bbox_inches = rcParams['savefig.bbox']

Expand Down
17 changes: 9 additions & 8 deletions lib/matplotlib/backends/backend_ps.py
Original file line number Diff line number Diff line change
Expand Up @@ -930,31 +930,32 @@ def print_ps(self, outfile, *args, **kwargs):
def print_eps(self, outfile, *args, **kwargs):
return self._print_ps(outfile, 'eps', *args, **kwargs)

def _print_ps(self, outfile, format, *args, **kwargs):
papertype = kwargs.pop("papertype", rcParams['ps.papersize'])
def _print_ps(self, outfile, format, *args,
papertype=None, dpi=72, facecolor='w', edgecolor='w',
orientation='portrait',
**kwargs):
if papertype is None:
papertype = rcParams['ps.papersize']
papertype = papertype.lower()
if papertype == 'auto':
pass
elif papertype not in papersize:
raise RuntimeError('%s is not a valid papertype. Use one of %s' %
(papertype, ', '.join(papersize)))

orientation = kwargs.pop("orientation", "portrait").lower()
orientation = orientation.lower()
if orientation == 'landscape': isLandscape = True
elif orientation == 'portrait': isLandscape = False
else: raise RuntimeError('Orientation must be "portrait" or "landscape"')

self.figure.set_dpi(72) # Override the dpi kwarg
imagedpi = kwargs.pop("dpi", 72)
facecolor = kwargs.pop("facecolor", "w")
edgecolor = kwargs.pop("edgecolor", "w")

if rcParams['text.usetex']:
self._print_figure_tex(outfile, format, imagedpi, facecolor, edgecolor,
self._print_figure_tex(outfile, format, dpi, facecolor, edgecolor,
orientation, isLandscape, papertype,
**kwargs)
else:
self._print_figure(outfile, format, imagedpi, facecolor, edgecolor,
self._print_figure(outfile, format, dpi, facecolor, edgecolor,
orientation, isLandscape, papertype,
**kwargs)

Expand Down
6 changes: 1 addition & 5 deletions lib/matplotlib/colorbar.py
Original file line number Diff line number Diff line change
Expand Up @@ -1323,7 +1323,7 @@ def make_axes(parents, location=None, orientation=None, fraction=0.15,


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

fraction = kw.pop('fraction', 0.15)
shrink = kw.pop('shrink', 1.0)
aspect = kw.pop('aspect', 20)

x1 = 1 - fraction

# for shrinking
Expand Down
33 changes: 16 additions & 17 deletions lib/matplotlib/contour.py
Original file line number Diff line number Diff line change
Expand Up @@ -791,7 +791,12 @@ class ContourSet(cm.ScalarMappable, ContourLabeler):
levels for filled contours. See :meth:`_process_colors`.
"""

def __init__(self, ax, *args, **kwargs):
def __init__(self, ax, *args,
levels=None, filled=False, linewidths=None, linestyles=None,
alpha=None, origin=None, extent=None,
cmap=None, colors=None, norm=None, vmin=None, vmax=None,
extend='neither', antialiased=None,
**kwargs):
"""
Draw contour lines or filled regions, depending on
whether keyword arg *filled* is ``False`` (default) or ``True``.
Expand Down Expand Up @@ -837,23 +842,17 @@ def __init__(self, ax, *args, **kwargs):
`~axes.Axes.contour`.
"""
self.ax = ax
self.levels = kwargs.pop('levels', None)
self.filled = kwargs.pop('filled', False)
self.linewidths = kwargs.pop('linewidths', None)
self.linestyles = kwargs.pop('linestyles', None)

self.levels = levels
self.filled = filled
self.linewidths = linewidths
self.linestyles = linestyles
self.hatches = kwargs.pop('hatches', [None])

self.alpha = kwargs.pop('alpha', None)
self.origin = kwargs.pop('origin', None)
self.extent = kwargs.pop('extent', None)
cmap = kwargs.pop('cmap', None)
self.colors = kwargs.pop('colors', None)
norm = kwargs.pop('norm', None)
vmin = kwargs.pop('vmin', None)
vmax = kwargs.pop('vmax', None)
self.extend = kwargs.pop('extend', 'neither')
self.antialiased = kwargs.pop('antialiased', None)
self.alpha = alpha
self.origin = origin
self.extent = extent
self.colors = colors
self.extend = extend
self.antialiased = antialiased
if self.antialiased is None and self.filled:
self.antialiased = False # eliminate artifacts; we are not
# stroking the boundaries.
Expand Down
9 changes: 5 additions & 4 deletions lib/matplotlib/figure.py
Original file line number Diff line number Diff line change
Expand Up @@ -1758,7 +1758,7 @@ def add_axobserver(self, func):
"""Whenever the axes state change, ``func(self)`` will be called."""
self._axobservers.append(func)

def savefig(self, fname, **kwargs):
def savefig(self, fname, *, frameon=None, transparent=None, **kwargs):
"""
Save the current figure.

Expand Down Expand Up @@ -1842,9 +1842,10 @@ def savefig(self, fname, **kwargs):

"""
kwargs.setdefault('dpi', rcParams['savefig.dpi'])
frameon = kwargs.pop('frameon', rcParams['savefig.frameon'])
transparent = kwargs.pop('transparent',
rcParams['savefig.transparent'])
if frameon is None:
frameon = rcParams['savefig.frameon']
if transparent is None:
transparent = rcParams['savefig.transparent']

if transparent:
kwargs.setdefault('facecolor', 'none')
Expand Down
Loading