diff --git a/doc/api/next_api_changes/2018-09-18-AL-deprecation-machinery.rst b/doc/api/next_api_changes/2018-09-18-AL-deprecation-machinery.rst new file mode 100644 index 000000000000..78e313ed6bda --- /dev/null +++ b/doc/api/next_api_changes/2018-09-18-AL-deprecation-machinery.rst @@ -0,0 +1,8 @@ +Changes to the signatures of `cbook.deprecated` and `cbook.warn_deprecated` +``````````````````````````````````````````````````````````````````````````` + +All arguments to the `cbook.deprecated` decorator and `cbook.warn_deprecated` +function, except the first one (the version where the deprecation occurred), +are now keyword-only. The goal is to avoid accidentally setting the "message" +argument when the "name" (or "alternative") argument was intended, as this has +repeatedly occurred in the past. diff --git a/lib/matplotlib/__init__.py b/lib/matplotlib/__init__.py index 7b26604632ea..a294755d9333 100644 --- a/lib/matplotlib/__init__.py +++ b/lib/matplotlib/__init__.py @@ -172,11 +172,11 @@ def compare_versions(a, b): "return True if a is greater than or equal to b" if isinstance(a, bytes): cbook.warn_deprecated( - "3.0", "compare_versions arguments should be strs.") + "3.0", message="compare_versions arguments should be strs.") a = a.decode('ascii') if isinstance(b, bytes): cbook.warn_deprecated( - "3.0", "compare_versions arguments should be strs.") + "3.0", message="compare_versions arguments should be strs.") b = b.decode('ascii') if a: a = distutils.version.LooseVersion(a) @@ -819,7 +819,7 @@ def __setitem__(self, key, val): if key in _deprecated_map: version, alt_key, alt_val, inverse_alt = _deprecated_map[key] cbook.warn_deprecated( - version, key, obj_type="rcparam", alternative=alt_key) + version, name=key, obj_type="rcparam", alternative=alt_key) key = alt_key val = alt_val(val) elif key in _deprecated_remain_as_none and val is not None: @@ -839,8 +839,9 @@ def __setitem__(self, key, val): return elif key == 'examples.directory': cbook.warn_deprecated( - "3.0", "{} is deprecated; in the future, examples will be " - "found relative to the 'datapath' directory.".format(key)) + "3.0", name=key, obj_type="rcparam", addendum="In the " + "future, examples will be found relative to the " + "'datapath' directory.") elif key == 'backend': if val is rcsetup._auto_backend_sentinel: if 'backend' in self: @@ -859,19 +860,19 @@ def __getitem__(self, key): if key in _deprecated_map: version, alt_key, alt_val, inverse_alt = _deprecated_map[key] cbook.warn_deprecated( - version, key, obj_type="rcparam", alternative=alt_key) + version, name=key, obj_type="rcparam", alternative=alt_key) return inverse_alt(dict.__getitem__(self, alt_key)) elif key in _deprecated_ignore_map: version, alt_key = _deprecated_ignore_map[key] cbook.warn_deprecated( - version, key, obj_type="rcparam", alternative=alt_key) + version, name=key, obj_type="rcparam", alternative=alt_key) return dict.__getitem__(self, alt_key) if alt_key else None elif key == 'examples.directory': cbook.warn_deprecated( - "3.0", "{} is deprecated; in the future, examples will be " - "found relative to the 'datapath' directory.".format(key)) + "3.0", name=key, obj_type="rcparam", addendum="In the future, " + "examples will be found relative to the 'datapath' directory.") elif key == "backend": val = dict.__getitem__(self, key) @@ -1019,7 +1020,7 @@ def _rc_params_in_file(fname, fail_on_error=False): elif key in _deprecated_ignore_map: version, alt_key = _deprecated_ignore_map[key] cbook.warn_deprecated( - version, key, alternative=alt_key, + version, name=key, alternative=alt_key, addendum="Please update your matplotlibrc.") else: print(""" diff --git a/lib/matplotlib/afm.py b/lib/matplotlib/afm.py index df8fe8010867..9b93ed540072 100644 --- a/lib/matplotlib/afm.py +++ b/lib/matplotlib/afm.py @@ -357,7 +357,7 @@ def _parse_optional(fh): return d[b'StartKernData'], d[b'StartComposites'] -@deprecated("3.0", "Use the class AFM instead.") +@deprecated("3.0", alternative="the AFM class") def parse_afm(fh): return _parse_afm(fh) diff --git a/lib/matplotlib/animation.py b/lib/matplotlib/animation.py index 1f50f9c7ac11..e27a9a9f9bc9 100644 --- a/lib/matplotlib/animation.py +++ b/lib/matplotlib/animation.py @@ -1692,10 +1692,10 @@ def gen(): pass else: cbook.warn_deprecated( - "2.2", "FuncAnimation.save has truncated your " - "animation to 100 frames. In the future, no such " - "truncation will occur; please pass 'save_count' " - "accordingly.") + "2.2", message="FuncAnimation.save has truncated " + "your animation to 100 frames. In the future, no " + "such truncation will occur; please pass " + "'save_count' accordingly.") return gen() diff --git a/lib/matplotlib/artist.py b/lib/matplotlib/artist.py index c7524c09b528..77c518dc56df 100644 --- a/lib/matplotlib/artist.py +++ b/lib/matplotlib/artist.py @@ -533,7 +533,7 @@ def get_picker(self): """ return self._picker - @cbook.deprecated("2.2", "artist.figure is not None") + @cbook.deprecated("2.2", alternative="artist.figure is not None") def is_figure_set(self): """Returns whether the artist is assigned to a `.Figure`.""" return self.figure is not None diff --git a/lib/matplotlib/axes/_base.py b/lib/matplotlib/axes/_base.py index 809342490b84..d28740ff19c3 100644 --- a/lib/matplotlib/axes/_base.py +++ b/lib/matplotlib/axes/_base.py @@ -374,8 +374,9 @@ def _plot_args(self, tup, kwargs): ncx, ncy = x.shape[1], y.shape[1] if ncx > 1 and ncy > 1 and ncx != ncy: - cbook.warn_deprecated("2.2", "cycling among columns of inputs " - "with non-matching shapes is deprecated.") + cbook.warn_deprecated( + "2.2", message="cycling among columns of inputs with " + "non-matching shapes is deprecated.") for j in range(max(ncx, ncy)): seg = func(x[:, j % ncx], y[:, j % ncy], kw, kwargs) ret.append(seg) @@ -1653,7 +1654,7 @@ def axis(self, *v, **kwargs): if s == 'normal': cbook.warn_deprecated( "3.1", "Passing 'normal' to axis() is deprecated " - "since %(version)s; use 'auto' instead.") + "since %(since)s; use 'auto' instead.") self.set_autoscale_on(True) self.set_aspect('auto') self.autoscale_view(tight=False) diff --git a/lib/matplotlib/backend_bases.py b/lib/matplotlib/backend_bases.py index a6661ed5b417..0ffee9bb67af 100644 --- a/lib/matplotlib/backend_bases.py +++ b/lib/matplotlib/backend_bases.py @@ -1859,9 +1859,9 @@ def enter_notify_event(self, guiEvent=None, xy=None): else: x = None y = None - cbook.warn_deprecated('3.0', 'enter_notify_event expects a ' - 'location but ' - 'your backend did not pass one.') + cbook.warn_deprecated( + '3.0', message='enter_notify_event expects a location but ' + 'your backend did not pass one.') event = LocationEvent('figure_enter_event', self, x, y, guiEvent) self.callbacks.process('figure_enter_event', event) diff --git a/lib/matplotlib/backends/backend_wx.py b/lib/matplotlib/backends/backend_wx.py index 6f836db94a1f..ee593bdf6ae9 100644 --- a/lib/matplotlib/backends/backend_wx.py +++ b/lib/matplotlib/backends/backend_wx.py @@ -123,8 +123,8 @@ class TimerWx(TimerBase): def __init__(self, *args, **kwargs): if args and isinstance(args[0], wx.EvtHandler): cbook.warn_deprecated( - "3.0", "Passing a wx.EvtHandler as first argument to the " - "TimerWx constructor is deprecated since %(version)s.") + "3.0", message="Passing a wx.EvtHandler as first argument to " + "the TimerWx constructor is deprecated since %(since)s.") args = args[1:] TimerBase.__init__(self, *args, **kwargs) self._timer = wx.Timer() diff --git a/lib/matplotlib/backends/tkagg.py b/lib/matplotlib/backends/tkagg.py index 2aa43bf0b3b1..754bfff2f989 100644 --- a/lib/matplotlib/backends/tkagg.py +++ b/lib/matplotlib/backends/tkagg.py @@ -6,8 +6,7 @@ from matplotlib.backends import _tkagg -cbook.warn_deprecated( - "3.0", "The matplotlib.backends.tkagg module is deprecated.") +cbook.warn_deprecated("3.0", name=__name__, obj_type="module") def blit(photoimage, aggimage, bbox=None, colormode=1): diff --git a/lib/matplotlib/backends/wx_compat.py b/lib/matplotlib/backends/wx_compat.py index 78bc34511e3a..0b3d21d56b6b 100644 --- a/lib/matplotlib/backends/wx_compat.py +++ b/lib/matplotlib/backends/wx_compat.py @@ -12,7 +12,7 @@ from .backend_wx import RendererWx -cbook.warn_deprecated("3.0", "{} is deprecated.".format(__name__)) +cbook.warn_deprecated("3.0", name=__name__, obj_type="module") backend_version = wx.VERSION_STRING is_phoenix = 'phoenix' in wx.PlatformInfo diff --git a/lib/matplotlib/cbook/__init__.py b/lib/matplotlib/cbook/__init__.py index 554abe8d6677..cda0836d0c62 100644 --- a/lib/matplotlib/cbook/__init__.py +++ b/lib/matplotlib/cbook/__init__.py @@ -361,7 +361,7 @@ def file_requires_unicode(x): return False -@deprecated('3.0', 'isinstance(..., numbers.Number)') +@deprecated('3.0', alternative='isinstance(..., numbers.Number)') def is_numlike(obj): """return true if *obj* looks like a number""" return isinstance(obj, (numbers.Number, np.number)) diff --git a/lib/matplotlib/cbook/deprecation.py b/lib/matplotlib/cbook/deprecation.py index 43de50858cd5..69b41e48fe98 100644 --- a/lib/matplotlib/cbook/deprecation.py +++ b/lib/matplotlib/cbook/deprecation.py @@ -25,7 +25,7 @@ def _generate_deprecation_message( obj_type='attribute', addendum='', *, removal=''): if removal == "": - removal = {"2.2": "in 3.1", "3.0": "in 3.2"}.get( + removal = {"2.2": "in 3.1", "3.0": "in 3.2", "3.1": "in 3.3"}.get( since, "two minor releases later") elif removal: if pending: @@ -52,8 +52,8 @@ def _generate_deprecation_message( def warn_deprecated( - since, message='', name='', alternative='', pending=False, - obj_type='attribute', addendum='', *, removal=''): + since, *, message='', name='', alternative='', pending=False, + obj_type='attribute', addendum='', removal=''): """ Used to display deprecation in a standard way. @@ -113,8 +113,8 @@ def warn_deprecated( _warn_external(message, category) -def deprecated(since, message='', name='', alternative='', pending=False, - obj_type=None, addendum='', *, removal=''): +def deprecated(since, *, message='', name='', alternative='', pending=False, + obj_type=None, addendum='', removal=''): """ Decorator to mark a function, a class, or a property as deprecated. diff --git a/lib/matplotlib/collections.py b/lib/matplotlib/collections.py index e80be08764db..fb15123f586a 100644 --- a/lib/matplotlib/collections.py +++ b/lib/matplotlib/collections.py @@ -270,8 +270,8 @@ def draw(self, renderer): except AttributeError: # if we end up with a GC that does not have this method cbook.warn_deprecated( - "3.1", "Your backend does not support setting the hatch " - "color; such backends will become unsupported in " + "3.1", message="Your backend does not support setting the " + "hatch color; such backends will become unsupported in " "Matplotlib 3.3.") if self.get_sketch_params() is not None: diff --git a/lib/matplotlib/figure.py b/lib/matplotlib/figure.py index 819525482cb7..80d204e2b8be 100644 --- a/lib/matplotlib/figure.py +++ b/lib/matplotlib/figure.py @@ -89,11 +89,12 @@ def get(self, key): return None cbook.warn_deprecated( "2.1", - "Adding an axes using the same arguments as a previous axes " - "currently reuses the earlier instance. In a future version, " - "a new instance will always be created and returned. Meanwhile, " - "this warning can be suppressed, and the future behavior ensured, " - "by passing a unique label to each axes instance.") + message="Adding an axes using the same arguments as a previous " + "axes currently reuses the earlier instance. In a future " + "version, a new instance will always be created and returned. " + "Meanwhile, this warning can be suppressed, and the future " + "behavior ensured, by passing a unique label to each axes " + "instance.") return item[1] def _entry_from_axes(self, e): @@ -1745,7 +1746,7 @@ def legend(self, *args, **kwargs): if len(extra_args): # cbook.warn_deprecated( # "2.1", - # "Figure.legend will accept no more than two " + # message="Figure.legend will accept no more than two " # "positional arguments in the future. Use " # "'fig.legend(handles, labels, loc=location)' " # "instead.") diff --git a/lib/matplotlib/markers.py b/lib/matplotlib/markers.py index a2088c81de9c..e27e9e6812b6 100644 --- a/lib/matplotlib/markers.py +++ b/lib/matplotlib/markers.py @@ -375,16 +375,16 @@ def _set_tuple_marker(self): self._joinstyle = 'bevel' elif symstyle == 3: cbook.warn_deprecated( - "3.0", "Setting a circle marker using `(..., 3)` is " - "deprecated since Matplotlib 3.0, and support for it will " - "be removed in 3.2. Directly pass 'o' instead.") + "3.0", message="Setting a circle marker using `(..., 3)` " + "is deprecated since Matplotlib 3.0, and support for it " + "will be removed in 3.2. Directly pass 'o' instead.") self._path = Path.unit_circle() self._transform = Affine2D().scale(0.5).rotate_deg(rotation) else: cbook.warn_deprecated( - "3.0", "Passing vertices as `(verts, 0)` is deprecated since " - "Matplotlib 3.0, and support for it will be removed in 3.2. " - "Directly pass `verts` instead.") + "3.0", message="Passing vertices as `(verts, 0)` is " + "deprecated since Matplotlib 3.0, and support for it will be " + "removed in 3.2. Directly pass `verts` instead.") verts = np.asarray(marker[0]) path = Path(verts) self._set_custom_marker(path) diff --git a/lib/matplotlib/patches.py b/lib/matplotlib/patches.py index 53590cbd92cf..b7f1a9b41178 100644 --- a/lib/matplotlib/patches.py +++ b/lib/matplotlib/patches.py @@ -522,8 +522,8 @@ def _bind_draw_path_function(self, renderer): except AttributeError: # if we end up with a GC that does not have this method cbook.warn_deprecated( - "3.1", "Your backend does not support setting the hatch " - "color; such backends will become unsupported in " + "3.1", message="Your backend does not support setting the " + "hatch color; such backends will become unsupported in " "Matplotlib 3.3.") if self.get_sketch_params() is not None: diff --git a/lib/mpl_toolkits/mplot3d/art3d.py b/lib/mpl_toolkits/mplot3d/art3d.py index 7777b66c14de..85c4f45cc4d8 100644 --- a/lib/mpl_toolkits/mplot3d/art3d.py +++ b/lib/mpl_toolkits/mplot3d/art3d.py @@ -533,8 +533,8 @@ def set_zsort(self, zsort): """ if zsort is True: cbook.warn_deprecated( - "3.1", "Passing True to mean 'average' for set_zsort is " - "deprecated and support will be removed in Matplotlib 3.3; " + "3.1", message="Passing True to mean 'average' for set_zsort " + "is deprecated and support will be removed in Matplotlib 3.3; " "pass 'average' instead.") zsort = 'average' self._zsortfunc = self._zsort_functions[zsort]