From b100c00f5224ee76f4af99dd654cc1f795363490 Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Wed, 23 May 2018 17:00:36 -0700 Subject: [PATCH] Prefer warn_deprecated instead of warnings.warn. warn_deprecated has the advantage of always listing the deprecation version and removal version. Hopefully, in the future it will also be able to set the stacklevel more systematically. Redesign the way deprecation of rcParams is done to make it use warn_deprecated. Merge obsolete_set into deprecated_ignore_map as they are semantically similar, it's just that there's no alternative rcParam for obsolete_set. Rename deprecated_set to deprecated_remain_as_none as the former name really doesn't say anything about the deprecation semantics. text.dvipnghack and axes.hold should be completely removed but that'll be another PR. --- .../2018-02-15-AL-deprecations.rst | 3 + lib/matplotlib/__init__.py | 148 ++++++++++-------- lib/matplotlib/axes/_base.py | 4 +- lib/matplotlib/axes/_subplots.py | 1 - lib/matplotlib/cbook/deprecation.py | 9 +- lib/matplotlib/gridspec.py | 9 +- lib/matplotlib/tests/test_rcparams.py | 6 +- 7 files changed, 97 insertions(+), 83 deletions(-) diff --git a/doc/api/next_api_changes/2018-02-15-AL-deprecations.rst b/doc/api/next_api_changes/2018-02-15-AL-deprecations.rst index 5d799c5587ec..df34bd47dab4 100644 --- a/doc/api/next_api_changes/2018-02-15-AL-deprecations.rst +++ b/doc/api/next_api_changes/2018-02-15-AL-deprecations.rst @@ -10,6 +10,9 @@ The following modules are deprecated: The following classes, methods, functions, and attributes are deprecated: +- ``RcParams.msg_depr``, ``RcParams.msg_depr_ignore``, + ``RcParams.msg_depr_set``, ``RcParams.msg_obsolete``, + ``RcParams.msg_backend_obsolete``, - ``afm.parse_afm``, - ``backend_pgf.get_texcommand``, - ``backend_ps.get_bbox``, diff --git a/lib/matplotlib/__init__.py b/lib/matplotlib/__init__.py index 2019eebfe8cb..52205228271e 100644 --- a/lib/matplotlib/__init__.py +++ b/lib/matplotlib/__init__.py @@ -123,11 +123,11 @@ import importlib import inspect from inspect import Parameter -import itertools import locale import logging import os from pathlib import Path +import pprint import re import shutil import stat @@ -800,23 +800,29 @@ def gen_candidates(): return fname -# names of keys to deprecate -# the values are a tuple of (new_name, f_old_2_new, f_new_2_old) -# the inverse function may be `None` +# rcParams deprecated and automatically mapped to another key. +# Values are tuples of (version, new_name, f_old2new, f_new2old). _deprecated_map = {} -_deprecated_ignore_map = {'nbagg.transparent': 'figure.facecolor'} +# rcParams deprecated; some can manually be mapped to another key. +# Values are tuples of (version, new_name_or_None). +_deprecated_ignore_map = { + 'text.dvipnghack': ('2.1', None), + 'nbagg.transparent': ('2.2', 'figure.facecolor'), + 'plugins.directory': ('2.2', None), + 'pgf.debug': ('3.0', None), +} -_obsolete_set = {'pgf.debug', 'plugins.directory', 'text.dvipnghack'} +# rcParams deprecated; can use None to suppress warnings; remain actually +# listed in the rcParams (not included in _all_deprecated). +# Values are typles of (version,) +_deprecated_remain_as_none = { + 'axes.hold': ('2.1',), + 'backend.qt4': ('2.2',), + 'backend.qt5': ('2.2',), +} -# The following may use a value of None to suppress the warning. -# do NOT include in _all_deprecated -_deprecated_set = {'axes.hold', - 'backend.qt4', - 'backend.qt5'} - -_all_deprecated = set(itertools.chain( - _deprecated_ignore_map, _deprecated_map, _obsolete_set)) +_all_deprecated = {*_deprecated_map, *_deprecated_ignore_map} class RcParams(MutableMapping, dict): @@ -831,16 +837,35 @@ class RcParams(MutableMapping, dict): validate = {key: converter for key, (default, converter) in defaultParams.items() if key not in _all_deprecated} - msg_depr = "%s is deprecated and replaced with %s; please use the latter." - msg_depr_set = ("%s is deprecated. Please remove it from your " - "matplotlibrc and/or style files.") - msg_depr_ignore = "%s is deprecated and ignored. Use %s instead." - msg_obsolete = ("%s is obsolete. Please remove it from your matplotlibrc " - "and/or style files.") - msg_backend_obsolete = ("The {} rcParam was deprecated in version 2.2. In" - " order to force the use of a specific Qt binding," - " either import that binding first, or set the " - "QT_API environment variable.") + + @property + @cbook.deprecated("3.0") + def msg_depr(self): + return "%s is deprecated and replaced with %s; please use the latter." + + @property + @cbook.deprecated("3.0") + def msg_depr_ignore(self): + return "%s is deprecated and ignored. Use %s instead." + + @property + @cbook.deprecated("3.0") + def msg_depr_set(self): + return ("%s is deprecated. Please remove it from your matplotlibrc " + "and/or style files.") + + @property + @cbook.deprecated("3.0") + def msg_obsolete(self): + return ("%s is obsolete. Please remove it from your matplotlibrc " + "and/or style files.") + + @property + @cbook.deprecated("3.0") + def msg_backend_obsolete(self): + return ("The {} rcParam was deprecated in version 2.2. In order to " + "force the use of a specific Qt binding, either import that " + "binding first, or set the QT_API environment variable.") # validate values on the way in def __init__(self, *args, **kwargs): @@ -849,26 +874,25 @@ def __init__(self, *args, **kwargs): def __setitem__(self, key, val): try: if key in _deprecated_map: - alt_key, alt_val, inverse_alt = _deprecated_map[key] - warnings.warn(self.msg_depr % (key, alt_key), - mplDeprecation) + version, alt_key, alt_val, inverse_alt = _deprecated_map[key] + cbook.warn_deprecated( + version, key, obj_type="rcparam", alternative=alt_key) key = alt_key val = alt_val(val) - elif key in _deprecated_set and val is not None: + elif key in _deprecated_remain_as_none and val is not None: + version, = _deprecated_remain_as_none[key] + addendum = None if key.startswith('backend'): - warnings.warn(self.msg_backend_obsolete.format(key), - mplDeprecation) - else: - warnings.warn(self.msg_depr_set % key, - mplDeprecation) + addendum = ( + "In order to force the use of a specific Qt binding, " + "either import that binding first, or set the QT_API " + "environment variable.") + cbook.warn_deprecated( + "2.2", key, obj_type="rcparam", addendum=addendum) elif key in _deprecated_ignore_map: - alt = _deprecated_ignore_map[key] - warnings.warn(self.msg_depr_ignore % (key, alt), - mplDeprecation) - return - elif key in _obsolete_set: - warnings.warn(self.msg_obsolete % (key, ), - mplDeprecation) + version, alt_key = _deprecated_ignore_map[key] + cbook.warn_deprecated( + version, key, obj_type="rcparam", alternative=alt_key) return try: cval = self.validate[key](val) @@ -881,42 +905,30 @@ def __setitem__(self, key, val): 'list of valid parameters.' % (key,)) def __getitem__(self, key): - inverse_alt = None if key in _deprecated_map: - alt_key, alt_val, inverse_alt = _deprecated_map[key] - warnings.warn(self.msg_depr % (key, alt_key), - mplDeprecation) - key = alt_key + version, alt_key, alt_val, inverse_alt = _deprecated_map[key] + cbook.warn_deprecated( + version, key, obj_type="rcparam", alternative=alt_key) + return inverse_alt(dict.__getitem__(self, alt_key)) elif key in _deprecated_ignore_map: - alt = _deprecated_ignore_map[key] - warnings.warn(self.msg_depr_ignore % (key, alt), - mplDeprecation) - key = alt - - elif key in _obsolete_set: - warnings.warn(self.msg_obsolete % (key, ), - mplDeprecation) - return None - - val = dict.__getitem__(self, key) - if inverse_alt is not None: - return inverse_alt(val) - else: - return val + version, alt_key = _deprecated_ignore_map[key] + cbook.warn_deprecated( + version, key, obj_type, alternative=alt_key) + return dict.__getitem__(self, alt_key) if alt_key else None + + return dict.__getitem__(self, key) def __repr__(self): - import pprint class_name = self.__class__.__name__ indent = len(class_name) + 1 repr_split = pprint.pformat(dict(self), indent=1, width=80 - indent).split('\n') repr_indented = ('\n' + ' ' * indent).join(repr_split) - return '{0}({1})'.format(class_name, repr_indented) + return '{}({})'.format(class_name, repr_indented) def __str__(self): - return '\n'.join('{0}: {1}'.format(k, v) - for k, v in sorted(self.items())) + return '\n'.join(map('{0[0]}: {0[1]}'.format, sorted(self.items()))) def __iter__(self): """Yield sorted list of keys.""" @@ -1043,10 +1055,10 @@ def _rc_params_in_file(fname, fail_on_error=False): warnings.warn('Bad val "%s" on %s\n\t%s' % (val, error_details, msg)) elif key in _deprecated_ignore_map: - warnings.warn('%s is deprecated. Update your matplotlibrc to use ' - '%s instead.' % (key, _deprecated_ignore_map[key]), - mplDeprecation) - + version, alt_key = _deprecated_ignore_map[key] + cbook.warn_deprecated( + version, key, alternative=alt_key, + addendum="Please update your matplotlibrc.") else: print(""" Bad key "%s" on line %d in diff --git a/lib/matplotlib/axes/_base.py b/lib/matplotlib/axes/_base.py index 181293b7983c..60d2cea20ad8 100644 --- a/lib/matplotlib/axes/_base.py +++ b/lib/matplotlib/axes/_base.py @@ -1310,8 +1310,8 @@ def set_adjustable(self, adjustable, share=False): and independently on each Axes as it is drawn. """ if adjustable == 'box-forced': - warnings.warn("The 'box-forced' keyword argument is deprecated" - " since 2.2.", cbook.mplDeprecation, stacklevel=2) + cbook.warn_deprecated( + "2.2", "box-forced", obj_type="keyword argument") if adjustable not in ('box', 'datalim', 'box-forced'): raise ValueError("argument must be 'box', or 'datalim'") if share: diff --git a/lib/matplotlib/axes/_subplots.py b/lib/matplotlib/axes/_subplots.py index accdeb456f1b..725fcb59b12f 100644 --- a/lib/matplotlib/axes/_subplots.py +++ b/lib/matplotlib/axes/_subplots.py @@ -4,7 +4,6 @@ from matplotlib import docstring import matplotlib.artist as martist from matplotlib.axes._axes import Axes -from matplotlib.cbook import mplDeprecation from matplotlib.gridspec import GridSpec, SubplotSpec import matplotlib._layoutbox as layoutbox diff --git a/lib/matplotlib/cbook/deprecation.py b/lib/matplotlib/cbook/deprecation.py index ae7f51d598c6..6ba7ba589ec3 100644 --- a/lib/matplotlib/cbook/deprecation.py +++ b/lib/matplotlib/cbook/deprecation.py @@ -42,7 +42,8 @@ def _generate_deprecation_message( if removal else ""))) + "." - + (" Use %(alternative)s instead." if alternative else "")) + + (" Use %(alternative)s instead." if alternative else "") + + (" %(addendum)s" if addendum else "")) return ( message % dict(func=name, name=name, obj_type=obj_type, since=since, @@ -103,9 +104,9 @@ def warn_deprecated( obj_type='module') """ - message = _generate_deprecation_message( - since, message, name, alternative, pending, obj_type, removal=removal) - message = '\n' + message + message = '\n' + _generate_deprecation_message( + since, message, name, alternative, pending, obj_type, addendum, + removal=removal) category = (PendingDeprecationWarning if pending else MatplotlibDeprecationWarning) warnings.warn(message, category, stacklevel=2) diff --git a/lib/matplotlib/gridspec.py b/lib/matplotlib/gridspec.py index efcfb1e879c8..baaab83a217e 100644 --- a/lib/matplotlib/gridspec.py +++ b/lib/matplotlib/gridspec.py @@ -23,7 +23,6 @@ from matplotlib import _pylab_helpers, tight_layout, rcParams from matplotlib.transforms import Bbox import matplotlib._layoutbox as layoutbox -from matplotlib.cbook import mplDeprecation _log = logging.getLogger(__name__) @@ -277,8 +276,8 @@ def get_subplot_params(self, figure=None, fig=None): parameters are from rcParams unless a figure attribute is set. """ if fig is not None: - warnings.warn("the 'fig' kwarg is deprecated " - "use 'figure' instead", mplDeprecation) + cbook.warn_deprecated("2.2", "fig", obj_type="keyword argument", + alternative="figure") if figure is None: figure = fig @@ -367,8 +366,8 @@ def get_subplot_params(self, figure=None, fig=None): """Return a dictionary of subplot layout parameters. """ if fig is not None: - warnings.warn("the 'fig' kwarg is deprecated " - "use 'figure' instead", mplDeprecation) + cbook.warn_deprecated("2.2", "fig", obj_type="keyword argument", + alternative="figure") if figure is None: figure = fig diff --git a/lib/matplotlib/tests/test_rcparams.py b/lib/matplotlib/tests/test_rcparams.py index d78c033b53da..8b28f0a1af1f 100644 --- a/lib/matplotlib/tests/test_rcparams.py +++ b/lib/matplotlib/tests/test_rcparams.py @@ -453,7 +453,7 @@ def test_rcparams_reset_after_fail(): def test_if_rctemplate_is_up_to_date(): # This tests if the matplotlibrc.template file contains all valid rcParams. - deprecated = {*mpl._all_deprecated, *mpl._deprecated_set} + deprecated = {*mpl._all_deprecated, *mpl._deprecated_remain_as_none} path_to_rc = os.path.join(mpl.get_data_path(), 'matplotlibrc') with open(path_to_rc, "r") as f: rclines = f.readlines() @@ -472,8 +472,8 @@ def test_if_rctemplate_is_up_to_date(): if not found: missing.update({k: v}) if missing: - raise ValueError("The following params are missing " + - "in the matplotlibrc.template file: {}" + raise ValueError("The following params are missing in the " + "matplotlibrc.template file: {}" .format(missing.items()))