From 92095c272ed63216ffe994ac006fbf667a98d1ea Mon Sep 17 00:00:00 2001 From: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> Date: Mon, 5 Oct 2020 00:11:29 +0200 Subject: [PATCH 1/6] Make _api a subpackage --- lib/matplotlib/{_api.py => _api/__init__.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename lib/matplotlib/{_api.py => _api/__init__.py} (100%) diff --git a/lib/matplotlib/_api.py b/lib/matplotlib/_api/__init__.py similarity index 100% rename from lib/matplotlib/_api.py rename to lib/matplotlib/_api/__init__.py From 9330e5c7763a2a6b5bddaccc739ea91323330e24 Mon Sep 17 00:00:00 2001 From: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> Date: Mon, 5 Oct 2020 00:19:06 +0200 Subject: [PATCH 2/6] Move module cbook.deprecation to _api.deprecation --- lib/matplotlib/{cbook => _api}/deprecation.py | 0 lib/matplotlib/cbook/__init__.py | 2 +- lib/matplotlib/pyplot.py | 3 ++- lib/matplotlib/tests/test_cbook.py | 3 ++- tools/boilerplate.py | 6 +++--- 5 files changed, 8 insertions(+), 6 deletions(-) rename lib/matplotlib/{cbook => _api}/deprecation.py (100%) diff --git a/lib/matplotlib/cbook/deprecation.py b/lib/matplotlib/_api/deprecation.py similarity index 100% rename from lib/matplotlib/cbook/deprecation.py rename to lib/matplotlib/_api/deprecation.py diff --git a/lib/matplotlib/cbook/__init__.py b/lib/matplotlib/cbook/__init__.py index b34c98f66b0f..c5fc7f5420b9 100644 --- a/lib/matplotlib/cbook/__init__.py +++ b/lib/matplotlib/cbook/__init__.py @@ -29,7 +29,7 @@ import matplotlib from matplotlib import _c_internal_utils -from .deprecation import ( +from matplotlib._api.deprecation import ( deprecated, warn_deprecated, _rename_parameter, _delete_parameter, _make_keyword_only, _deprecate_method_override, _deprecate_privatize_attribute, diff --git a/lib/matplotlib/pyplot.py b/lib/matplotlib/pyplot.py index 04feb22a94ab..c2b0ddd2217c 100644 --- a/lib/matplotlib/pyplot.py +++ b/lib/matplotlib/pyplot.py @@ -35,6 +35,7 @@ import matplotlib import matplotlib.colorbar import matplotlib.image +from matplotlib import _api from matplotlib import rcsetup, style from matplotlib import _pylab_helpers, interactive from matplotlib import cbook @@ -2986,7 +2987,7 @@ def quiverkey(Q, X, Y, U, label, **kw): def scatter( x, y, s=None, c=None, marker=None, cmap=None, norm=None, vmin=None, vmax=None, alpha=None, linewidths=None, - verts=cbook.deprecation._deprecated_parameter, + verts=_api.deprecation._deprecated_parameter, edgecolors=None, *, plotnonfinite=False, data=None, **kwargs): __ret = gca().scatter( x, y, s=s, c=c, marker=marker, cmap=cmap, norm=norm, diff --git a/lib/matplotlib/tests/test_cbook.py b/lib/matplotlib/tests/test_cbook.py index 357fc2bb50c6..8158333cfd35 100644 --- a/lib/matplotlib/tests/test_cbook.py +++ b/lib/matplotlib/tests/test_cbook.py @@ -11,6 +11,7 @@ assert_array_almost_equal) import pytest +from matplotlib import _api import matplotlib.cbook as cbook import matplotlib.colors as mcolors from matplotlib.cbook import MatplotlibDeprecationWarning, delete_masked_points @@ -618,7 +619,7 @@ def func2(**kwargs): with pytest.warns(MatplotlibDeprecationWarning): func(foo="bar") - def pyplot_wrapper(foo=cbook.deprecation._deprecated_parameter): + def pyplot_wrapper(foo=_api.deprecation._deprecated_parameter): func1(foo) pyplot_wrapper() # No warning. diff --git a/tools/boilerplate.py b/tools/boilerplate.py index fa75a1403c8c..477665625085 100644 --- a/tools/boilerplate.py +++ b/tools/boilerplate.py @@ -22,7 +22,7 @@ # This line imports the installed copy of matplotlib, and not the local copy. import numpy as np -from matplotlib import cbook, mlab +from matplotlib import _api, mlab from matplotlib.axes import Axes from matplotlib.figure import Figure @@ -74,8 +74,8 @@ def __init__(self, value): self._repr = "mlab.window_hanning" elif value is np.mean: self._repr = "np.mean" - elif value is cbook.deprecation._deprecated_parameter: - self._repr = "cbook.deprecation._deprecated_parameter" + elif value is _api.deprecation._deprecated_parameter: + self._repr = "_api.deprecation._deprecated_parameter" elif isinstance(value, Enum): # Enum str is Class.Name whereas their repr is . self._repr = str(value) From acdd529b5f73d1cfc4c8e6d1741b8bc090b74329 Mon Sep 17 00:00:00 2001 From: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> Date: Mon, 5 Oct 2020 00:26:53 +0200 Subject: [PATCH 3/6] Re-add a deprecated cbook.deprecation module for backward compatibility --- .flake8 | 1 + doc/api/next_api_changes/deprecations/18657-TH.rst | 3 +++ lib/matplotlib/_api/deprecation.py | 2 +- lib/matplotlib/cbook/deprecation.py | 7 +++++++ 4 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 doc/api/next_api_changes/deprecations/18657-TH.rst create mode 100644 lib/matplotlib/cbook/deprecation.py diff --git a/.flake8 b/.flake8 index f08feffa7a55..60d0a5518674 100644 --- a/.flake8 +++ b/.flake8 @@ -58,6 +58,7 @@ per-file-ignores = lib/matplotlib/backends/backend_*.py: F401 lib/matplotlib/backends/qt_editor/formlayout.py: F401, F403 lib/matplotlib/cbook/__init__.py: F401 + lib/matplotlib/cbook/deprecation.py: F401 lib/matplotlib/font_manager.py: E221, E251, E501 lib/matplotlib/image.py: F401, F403 lib/matplotlib/lines.py: F401 diff --git a/doc/api/next_api_changes/deprecations/18657-TH.rst b/doc/api/next_api_changes/deprecations/18657-TH.rst new file mode 100644 index 000000000000..6465b52f0074 --- /dev/null +++ b/doc/api/next_api_changes/deprecations/18657-TH.rst @@ -0,0 +1,3 @@ +``matplotlib.cbook.deprecation`` is deprecated +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The module is considered internal and will be removed from the public API. diff --git a/lib/matplotlib/_api/deprecation.py b/lib/matplotlib/_api/deprecation.py index 2c0a5bb72ecd..0a012bac6e81 100644 --- a/lib/matplotlib/_api/deprecation.py +++ b/lib/matplotlib/_api/deprecation.py @@ -105,7 +105,7 @@ def warn_deprecated( warning = _generate_deprecation_warning( since, message, name, alternative, pending, obj_type, addendum, removal=removal) - from . import _warn_external + from ..cbook import _warn_external _warn_external(warning, category=MatplotlibDeprecationWarning) diff --git a/lib/matplotlib/cbook/deprecation.py b/lib/matplotlib/cbook/deprecation.py new file mode 100644 index 000000000000..ba15795fda0f --- /dev/null +++ b/lib/matplotlib/cbook/deprecation.py @@ -0,0 +1,7 @@ +# imports are for backward compatibility +from matplotlib._api.deprecation import ( + MatplotlibDeprecationWarning, mplDeprecation, warn_deprecated, deprecated) + +warn_deprecated("3.4", + "The module matplotlib.cbook.deprecation is considered " + "internal and it will be made private in the future.") From 5a45fc2aa47052ee55f0d2bdd80e81d093f90069 Mon Sep 17 00:00:00 2001 From: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> Date: Thu, 8 Oct 2020 22:27:12 +0200 Subject: [PATCH 4/6] Move cbook._warn_external to _api.warn_external. This is needed right now to not re-import cbook from _api.deprecation. It's intended anyway, but changing all occurences in the code is left for another time to keep this PR reasonably sized. --- lib/matplotlib/_api/__init__.py | 25 +++++++++++++++++++++++++ lib/matplotlib/_api/deprecation.py | 4 ++-- lib/matplotlib/cbook/__init__.py | 25 +------------------------ lib/matplotlib/cm.py | 3 +-- lib/matplotlib/pyplot.py | 4 ++-- 5 files changed, 31 insertions(+), 30 deletions(-) diff --git a/lib/matplotlib/_api/__init__.py b/lib/matplotlib/_api/__init__.py index 856a7e0a063a..24f466a4d2d3 100644 --- a/lib/matplotlib/_api/__init__.py +++ b/lib/matplotlib/_api/__init__.py @@ -1,4 +1,7 @@ import itertools +import re +import sys +import warnings def check_in_list(_values, *, _print_supported_values=True, **kwargs): @@ -93,3 +96,25 @@ def check_getitem(_mapping, **kwargs): raise ValueError( "{!r} is not a valid value for {}; supported values are {}" .format(v, k, ', '.join(map(repr, mapping)))) from None + + +def warn_external(message, category=None): + """ + `warnings.warn` wrapper that sets *stacklevel* to "outside Matplotlib". + + The original emitter of the warning can be obtained by patching this + function back to `warnings.warn`, i.e. ``_api.warn_external = + warnings.warn`` (or ``functools.partial(warnings.warn, stacklevel=2)``, + etc.). + """ + frame = sys._getframe() + for stacklevel in itertools.count(1): # lgtm[py/unused-loop-variable] + if frame is None: + # when called in embedded context may hit frame is None + break + if not re.match(r"\A(matplotlib|mpl_toolkits)(\Z|\.(?!tests\.))", + # Work around sphinx-gallery not setting __name__. + frame.f_globals.get("__name__", "")): + break + frame = frame.f_back + warnings.warn(message, category, stacklevel) diff --git a/lib/matplotlib/_api/deprecation.py b/lib/matplotlib/_api/deprecation.py index 0a012bac6e81..46bbe47032d7 100644 --- a/lib/matplotlib/_api/deprecation.py +++ b/lib/matplotlib/_api/deprecation.py @@ -105,8 +105,8 @@ def warn_deprecated( warning = _generate_deprecation_warning( since, message, name, alternative, pending, obj_type, addendum, removal=removal) - from ..cbook import _warn_external - _warn_external(warning, category=MatplotlibDeprecationWarning) + from . import warn_external + warn_external(warning, category=MatplotlibDeprecationWarning) def deprecated(since, *, message='', name='', alternative='', pending=False, diff --git a/lib/matplotlib/cbook/__init__.py b/lib/matplotlib/cbook/__init__.py index c5fc7f5420b9..d673f6597a67 100644 --- a/lib/matplotlib/cbook/__init__.py +++ b/lib/matplotlib/cbook/__init__.py @@ -29,6 +29,7 @@ import matplotlib from matplotlib import _c_internal_utils +from matplotlib._api import warn_external as _warn_external from matplotlib._api.deprecation import ( deprecated, warn_deprecated, _rename_parameter, _delete_parameter, _make_keyword_only, @@ -2096,30 +2097,6 @@ def _setattr_cm(obj, **kwargs): setattr(obj, attr, orig) -def _warn_external(message, category=None): - """ - `warnings.warn` wrapper that sets *stacklevel* to "outside Matplotlib". - - The original emitter of the warning can be obtained by patching this - function back to `warnings.warn`, i.e. ``cbook._warn_external = - warnings.warn`` (or ``functools.partial(warnings.warn, stacklevel=2)``, - etc.). - - :meta public: - """ - frame = sys._getframe() - for stacklevel in itertools.count(1): # lgtm[py/unused-loop-variable] - if frame is None: - # when called in embedded context may hit frame is None - break - if not re.match(r"\A(matplotlib|mpl_toolkits)(\Z|\.(?!tests\.))", - # Work around sphinx-gallery not setting __name__. - frame.f_globals.get("__name__", "")): - break - frame = frame.f_back - warnings.warn(message, category, stacklevel) - - class _OrderedSet(collections.abc.MutableSet): def __init__(self): self._od = collections.OrderedDict() diff --git a/lib/matplotlib/cm.py b/lib/matplotlib/cm.py index e87dd728440d..ab06984e9479 100644 --- a/lib/matplotlib/cm.py +++ b/lib/matplotlib/cm.py @@ -24,7 +24,6 @@ from matplotlib import _api, colors, cbook from matplotlib._cm import datad from matplotlib._cm_listed import cmaps as cmaps_listed -from matplotlib.cbook import _warn_external LUTSIZE = mpl.rcParams['image.lut'] @@ -150,7 +149,7 @@ def register_cmap(name=None, cmap=None, *, override_builtin=False): raise ValueError(msg) else: msg = f"Trying to register the cmap {name!r} which already exists." - _warn_external(msg) + _api.warn_external(msg) if not isinstance(cmap, colors.Colormap): raise ValueError("You must pass a Colormap instance. " diff --git a/lib/matplotlib/pyplot.py b/lib/matplotlib/pyplot.py index c2b0ddd2217c..935d364ff461 100644 --- a/lib/matplotlib/pyplot.py +++ b/lib/matplotlib/pyplot.py @@ -2987,8 +2987,8 @@ def quiverkey(Q, X, Y, U, label, **kw): def scatter( x, y, s=None, c=None, marker=None, cmap=None, norm=None, vmin=None, vmax=None, alpha=None, linewidths=None, - verts=_api.deprecation._deprecated_parameter, - edgecolors=None, *, plotnonfinite=False, data=None, **kwargs): + verts=_api.deprecation._deprecated_parameter, edgecolors=None, + *, plotnonfinite=False, data=None, **kwargs): __ret = gca().scatter( x, y, s=s, c=c, marker=marker, cmap=cmap, norm=norm, vmin=vmin, vmax=vmax, alpha=alpha, linewidths=linewidths, From 644872bceae1b8f86fc22b65fdab0aa0b5d468d0 Mon Sep 17 00:00:00 2001 From: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> Date: Sat, 10 Oct 2020 12:02:26 +0200 Subject: [PATCH 5/6] Add documentation for _api module --- doc/api/_api_api.rst | 13 +++++++++++++ doc/api/cbook_api.rst | 5 ----- doc/api/index.rst | 1 + doc/api/prev_api_changes/api_changes_3.0.0.rst | 2 +- doc/api/prev_api_changes/api_changes_3.1.0.rst | 16 ++++++++-------- doc/devel/contributing.rst | 16 ++++++++-------- lib/matplotlib/_api/__init__.py | 9 +++++++++ 7 files changed, 40 insertions(+), 22 deletions(-) create mode 100644 doc/api/_api_api.rst diff --git a/doc/api/_api_api.rst b/doc/api/_api_api.rst new file mode 100644 index 000000000000..a41af9009bcf --- /dev/null +++ b/doc/api/_api_api.rst @@ -0,0 +1,13 @@ +******************* +``matplotlib._api`` +******************* + +.. automodule:: matplotlib._api + :members: + :undoc-members: + :show-inheritance: + +.. automodule:: matplotlib._api.deprecation + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/api/cbook_api.rst b/doc/api/cbook_api.rst index f434fb9c6a26..4c8ef9cc50fa 100644 --- a/doc/api/cbook_api.rst +++ b/doc/api/cbook_api.rst @@ -6,8 +6,3 @@ :members: :undoc-members: :show-inheritance: - -.. automodule:: matplotlib.cbook.deprecation - :members: - :undoc-members: - :show-inheritance: diff --git a/doc/api/index.rst b/doc/api/index.rst index cd1d120335ce..dba86c35ad0a 100644 --- a/doc/api/index.rst +++ b/doc/api/index.rst @@ -126,6 +126,7 @@ Matplotlib consists of the following submodules: type1font.rst units_api.rst widgets_api.rst + _api_api.rst Toolkits -------- diff --git a/doc/api/prev_api_changes/api_changes_3.0.0.rst b/doc/api/prev_api_changes/api_changes_3.0.0.rst index b0153c50d884..a6224c352179 100644 --- a/doc/api/prev_api_changes/api_changes_3.0.0.rst +++ b/doc/api/prev_api_changes/api_changes_3.0.0.rst @@ -405,7 +405,7 @@ The following classes, methods, functions, and attributes are deprecated: - ``textpath.TextToPath.tex_font_map`` - ``matplotlib.cbook.deprecation.mplDeprecation`` will be removed in future versions. It is just an alias for - :class:`matplotlib.cbook.deprecation.MatplotlibDeprecationWarning`. Please + ``matplotlib.cbook.deprecation.MatplotlibDeprecationWarning``. Please use ``matplotlib.cbook.MatplotlibDeprecationWarning`` directly if necessary. - The ``matplotlib.cbook.Bunch`` class has been deprecated. Instead, use `types.SimpleNamespace` from the standard library which provides the same diff --git a/doc/api/prev_api_changes/api_changes_3.1.0.rst b/doc/api/prev_api_changes/api_changes_3.1.0.rst index 0504f954ca2e..f3737889841f 100644 --- a/doc/api/prev_api_changes/api_changes_3.1.0.rst +++ b/doc/api/prev_api_changes/api_changes_3.1.0.rst @@ -767,12 +767,12 @@ The following signature related behaviours are deprecated: keyword. - The *interp_at_native* parameter to `.BboxImage`, which has had no effect since Matplotlib 2.0, is deprecated. -- All arguments to the `~.cbook.deprecation.deprecated` decorator and - `~.cbook.deprecation.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. +- All arguments to the ``matplotlib.cbook.deprecation.deprecated`` decorator + and ``matplotlib.cbook.deprecation.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. - The arguments of `matplotlib.testing.compare.calculate_rms` have been renamed from ``expectedImage, actualImage``, to ``expected_image, actual_image``. - Passing positional arguments to `.Axis.set_ticklabels` beyond *ticklabels* @@ -1076,8 +1076,8 @@ Undeprecations -------------- The following API elements have been un-deprecated: -- The *obj_type* keyword argument to the `~.cbook.deprecation.deprecated` - decorator. +- The *obj_type* keyword argument to the + ``matplotlib.cbook.deprecation.deprecated`` decorator. - *xmin*, *xmax* keyword arguments to `.Axes.set_xlim` and *ymin*, *ymax* keyword arguments to `.Axes.set_ylim` diff --git a/doc/devel/contributing.rst b/doc/devel/contributing.rst index 9a8cf50ab546..021d46190f3b 100644 --- a/doc/devel/contributing.rst +++ b/doc/devel/contributing.rst @@ -511,7 +511,7 @@ There are five levels at which you can emit messages. - `logging.critical` and `logging.error` are really only there for errors that will end the use of the library but not kill the interpreter. -- `logging.warning` and `.cbook._warn_external` are used to warn the user, +- `logging.warning` and `._api.warn_external` are used to warn the user, see below. - `logging.info` is for information that the user may want to know if the program behaves oddly. They are not displayed by default. For instance, if @@ -527,16 +527,16 @@ By default, `logging` displays all log messages at levels higher than ``logging.WARNING`` to `sys.stderr`. The `logging tutorial`_ suggests that the difference between `logging.warning` -and `.cbook._warn_external` (which uses `warnings.warn`) is that -`.cbook._warn_external` should be used for things the user must change to stop +and `._api.warn_external` (which uses `warnings.warn`) is that +`._api.warn_external` should be used for things the user must change to stop the warning (typically in the source), whereas `logging.warning` can be more -persistent. Moreover, note that `.cbook._warn_external` will by default only +persistent. Moreover, note that `._api.warn_external` will by default only emit a given warning *once* for each line of user code, whereas `logging.warning` will display the message every time it is called. By default, `warnings.warn` displays the line of code that has the ``warn`` call. This usually isn't more informative than the warning message itself. -Therefore, Matplotlib uses `.cbook._warn_external` which uses `warnings.warn`, +Therefore, Matplotlib uses `._api.warn_external` which uses `warnings.warn`, but goes up the stack and displays the first line of code outside of Matplotlib. For example, for the module:: @@ -559,13 +559,13 @@ will display:: UserWarning: Attempting to set identical bottom==top warnings.warn('Attempting to set identical bottom==top') -Modifying the module to use `.cbook._warn_external`:: +Modifying the module to use `._api.warn_external`:: - from matplotlib import cbook + from matplotlib import _api def set_range(bottom, top): if bottom == top: - cbook._warn_external('Attempting to set identical bottom==top') + _api.warn_external('Attempting to set identical bottom==top') and running the same script will display:: diff --git a/lib/matplotlib/_api/__init__.py b/lib/matplotlib/_api/__init__.py index 24f466a4d2d3..656c24d07028 100644 --- a/lib/matplotlib/_api/__init__.py +++ b/lib/matplotlib/_api/__init__.py @@ -1,3 +1,12 @@ +""" +Helper functions for managing the Matplotlib API. + +.. warning: + + This module and its submodules is for internal use only. + +""" + import itertools import re import sys From aec68414245163393d3a30afe495ecfa51792435 Mon Sep 17 00:00:00 2001 From: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> Date: Wed, 14 Oct 2020 23:50:02 +0200 Subject: [PATCH 6/6] Fix import errors and extend module docs --- lib/matplotlib/_api/__init__.py | 5 ++++- lib/matplotlib/_api/deprecation.py | 12 ++++++++++++ lib/matplotlib/patches.py | 6 +++--- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/lib/matplotlib/_api/__init__.py b/lib/matplotlib/_api/__init__.py index 656c24d07028..b2778410e0cd 100644 --- a/lib/matplotlib/_api/__init__.py +++ b/lib/matplotlib/_api/__init__.py @@ -1,9 +1,12 @@ """ Helper functions for managing the Matplotlib API. +This documentation is only relevant for Matplotlib developers, not for users. + .. warning: - This module and its submodules is for internal use only. + This module and its submodules are for internal use only. Do not use them + in your own code. We may change the API at any time with no warning. """ diff --git a/lib/matplotlib/_api/deprecation.py b/lib/matplotlib/_api/deprecation.py index 46bbe47032d7..c94b76c741c1 100644 --- a/lib/matplotlib/_api/deprecation.py +++ b/lib/matplotlib/_api/deprecation.py @@ -1,3 +1,15 @@ +""" +Helper functions for deprecating parts of the Matplotlib API. + +This documentation is only relevant for Matplotlib developers, not for users. + +.. warning: + + This module is for internal use only. Do not use it in your own code. + We may change the API at any time with no warning. + +""" + import contextlib import functools import inspect diff --git a/lib/matplotlib/patches.py b/lib/matplotlib/patches.py index 3338fb3de44c..d62b54015c47 100644 --- a/lib/matplotlib/patches.py +++ b/lib/matplotlib/patches.py @@ -9,7 +9,7 @@ import numpy as np import matplotlib as mpl -from . import (artist, cbook, colors, docstring, hatch as mhatch, +from . import (_api, artist, cbook, colors, docstring, hatch as mhatch, lines as mlines, transforms) from .bezier import ( NonIntersectingPathException, get_cos_sin, get_intersection, @@ -2007,8 +2007,8 @@ def __init_subclass__(cls): @cbook._delete_parameter("3.4", "mutation_aspect") def call_wrapper( self, x0, y0, width, height, mutation_size, - mutation_aspect=cbook.deprecation._deprecated_parameter): - if mutation_aspect is cbook.deprecation._deprecated_parameter: + mutation_aspect=_api.deprecation._deprecated_parameter): + if mutation_aspect is _api.deprecation._deprecated_parameter: # Don't trigger deprecation warning internally. return __call__(self, x0, y0, width, height, mutation_size) else: