From 67e57b29c71a814cdb7b3573c4585f770be437b0 Mon Sep 17 00:00:00 2001 From: Alon Hershenhorn Date: Mon, 29 Oct 2018 11:28:55 -0700 Subject: [PATCH] 1) Replaced warnings.warn with either logging.warnings or cbook._warn_external. 2) Updated contributions guidelines to use cbook._warn_external. --- doc/devel/contributing.rst | 78 ++++++++++++++----- lib/matplotlib/__init__.py | 75 +++++++++--------- lib/matplotlib/_constrained_layout.py | 15 ++-- lib/matplotlib/artist.py | 8 +- lib/matplotlib/axes/_axes.py | 5 +- lib/matplotlib/axes/_base.py | 39 +++++----- lib/matplotlib/axis.py | 21 ++--- lib/matplotlib/backend_bases.py | 7 +- lib/matplotlib/backend_managers.py | 21 ++--- lib/matplotlib/backend_tools.py | 10 ++- lib/matplotlib/backends/backend_pdf.py | 7 +- lib/matplotlib/backends/backend_pgf.py | 7 +- .../backends/backend_webagg_core.py | 7 +- lib/matplotlib/backends/backend_wx.py | 14 ++-- .../backends/qt_editor/formlayout.py | 11 +-- lib/matplotlib/bezier.py | 6 +- lib/matplotlib/cbook/__init__.py | 10 +-- lib/matplotlib/colorbar.py | 14 ++-- lib/matplotlib/contour.py | 14 ++-- lib/matplotlib/dates.py | 12 +-- lib/matplotlib/figure.py | 53 +++++++------ lib/matplotlib/font_manager.py | 12 ++- lib/matplotlib/gridspec.py | 6 +- lib/matplotlib/image.py | 7 +- lib/matplotlib/legend.py | 17 ++-- lib/matplotlib/lines.py | 6 +- lib/matplotlib/mathtext.py | 37 ++++----- lib/matplotlib/mlab.py | 6 +- lib/matplotlib/offsetbox.py | 2 - lib/matplotlib/patches.py | 5 +- lib/matplotlib/pyplot.py | 15 ++-- lib/matplotlib/sphinxext/mathmpl.py | 6 +- lib/matplotlib/spines.py | 16 ++-- lib/matplotlib/style/core.py | 10 ++- lib/matplotlib/testing/__init__.py | 5 +- lib/matplotlib/text.py | 9 +-- lib/matplotlib/textpath.py | 14 ++-- lib/matplotlib/ticker.py | 13 ++-- lib/matplotlib/tight_layout.py | 41 +++++----- lib/matplotlib/transforms.py | 8 +- lib/matplotlib/tri/triinterpolate.py | 10 +-- lib/mpl_toolkits/axes_grid1/inset_locator.py | 10 +-- lib/mpl_toolkits/axisartist/axislines.py | 7 +- lib/mpl_toolkits/axisartist/clip_path.py | 4 +- lib/mpl_toolkits/mplot3d/axes3d.py | 33 ++++---- setupext.py | 6 +- 46 files changed, 399 insertions(+), 340 deletions(-) diff --git a/doc/devel/contributing.rst b/doc/devel/contributing.rst index 428fd0b29787..5136fff6dbb5 100644 --- a/doc/devel/contributing.rst +++ b/doc/devel/contributing.rst @@ -449,29 +449,71 @@ Then they will receive messages like:: Which logging level to use? ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -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` overlaps with the -`warnings` library. The `logging tutorial`_ suggests that the difference -between `logging.warning` and `warnings.warn` is that `warnings.warn` 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 `warnings.warn` will by default only emit a given warning *once*, whereas -`logging.warning` will display the message every time it is called. +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, + 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 + an object isn't drawn because its position is ``NaN``, that can usually + be ignored, but a mystified user could call + ``logging.basicConfig(level=logging.INFO)`` and get an error message that + says why. +- `logging.debug` is the least likely to be displayed, and hence can be the + most verbose. "Expected" code paths (e.g., reporting normal intermediate + steps of layouting or rendering) should only log at this level. By default, `logging` displays all log messages at levels higher than `logging.WARNING` to `sys.stderr`. -Calls to `logging.info` are not displayed by default. They are for -information that the user may want to know if the program behaves oddly. -For instance, if an object isn't drawn because its position is ``NaN``, -that can usually be ignored, but a mystified user could call -``logging.basicConfig(level=logging.INFO)`` and get an error message that -says why. +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 the warning (typically in the source), whereas +`logging.warning` can be more persistent. Moreover, note that +`cbook._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. -`logging.debug` is the least likely to be displayed, and hence can be the most -verbose. "Expected" code paths (e.g., reporting normal intermediate steps of -layouting or rendering) should only log at this level. +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`, but goes +up the stack and displays the first line of code outside of Matplotlib. +For example, for the module:: + + # in my_matplotlib_module.py + import warnings + + def set_range(bottom, top): + if bottom == top: + warnings.warn('Attempting to set identical bottom==top') + + +running the script:: + + from matplotlib import my_matplotlib_module + my_matplotlib_module.set_range(0, 0) #set range + + +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`:: + + from matplotlib import cbook + + def set_range(bottom, top): + if bottom == top: + cbook._warn_external('Attempting to set identical bottom==top') + +and running the same script will display:: + + UserWarning: Attempting to set identical bottom==top + my_matplotlib_module.set_range(0, 0) #set range .. _logging tutorial: https://docs.python.org/3/howto/logging.html#logging-basic-tutorial diff --git a/lib/matplotlib/__init__.py b/lib/matplotlib/__init__.py index 8990602577bd..e6a0b25fb8aa 100644 --- a/lib/matplotlib/__init__.py +++ b/lib/matplotlib/__init__.py @@ -244,9 +244,8 @@ def _set_logger_verbose_level(level_str='silent', file_str='sys.stdout'): fileo = open(file_str, 'w') # if this fails, we will just write to stdout except IOError: - warnings.warn('could not open log file "{0}"' - 'for writing. Check your ' - 'matplotlibrc'.format(file_str)) + _log.warning('could not open log file "{0}" for writing. ' + 'Check your matplotlibrc'.format(file_str)) console = logging.StreamHandler(fileo) console.setLevel(newlev) _log.addHandler(console) @@ -307,8 +306,9 @@ def set_level(self, level): if self._commandLineVerbose is not None: level = self._commandLineVerbose if level not in self.levels: - warnings.warn('matplotlib: unrecognized --verbose-* string "%s".' - ' Legal values are %s' % (level, self.levels)) + cbook._warn_external('matplotlib: unrecognized --verbose-* ' + 'string "%s". Legal values are %s' % + (level, self.levels)) else: self.level = level @@ -487,9 +487,9 @@ def checkdep_ps_distiller(s): gs_exec, gs_v = checkdep_ghostscript() if not gs_exec: flag = False - warnings.warn('matplotlibrc ps.usedistiller option can not be used ' - 'unless ghostscript 9.0 or later is installed on your ' - 'system') + _log.warning('matplotlibrc ps.usedistiller option can not be used ' + 'unless ghostscript 9.0 or later is installed on your ' + 'system') if s == 'xpdf': pdftops_req = '3.0' @@ -502,9 +502,9 @@ def checkdep_ps_distiller(s): pass else: flag = False - warnings.warn(('matplotlibrc ps.usedistiller can not be set to ' - 'xpdf unless xpdf-%s or later is installed on ' - 'your system') % pdftops_req) + _log.warning(('matplotlibrc ps.usedistiller can not be set to ' + 'xpdf unless xpdf-%s or later is installed on ' + 'your system') % pdftops_req) if flag: return s @@ -522,22 +522,22 @@ def checkdep_usetex(s): if shutil.which("tex") is None: flag = False - warnings.warn('matplotlibrc text.usetex option can not be used unless ' - 'TeX is installed on your system') + _log.warning('matplotlibrc text.usetex option can not be used unless ' + 'TeX is installed on your system') dvipng_v = checkdep_dvipng() if not compare_versions(dvipng_v, dvipng_req): flag = False - warnings.warn('matplotlibrc text.usetex can not be used with *Agg ' - 'backend unless dvipng-%s or later is installed on ' - 'your system' % dvipng_req) + _log.warning('matplotlibrc text.usetex can not be used with *Agg ' + 'backend unless dvipng-%s or later is installed on ' + 'your system' % dvipng_req) gs_exec, gs_v = checkdep_ghostscript() if not compare_versions(gs_v, gs_req): flag = False - warnings.warn('matplotlibrc text.usetex can not be used unless ' - 'ghostscript-%s or later is installed on your system' - % gs_req) + _log.warning('matplotlibrc text.usetex can not be used unless ' + 'ghostscript-%s or later is installed on your system' + % gs_req) return flag @@ -961,17 +961,17 @@ def _rc_params_in_file(fname, fail_on_error=False): tup = strippedline.split(':', 1) if len(tup) != 2: error_details = _error_details_fmt % (cnt, line, fname) - warnings.warn('Illegal %s' % error_details) + _log.warning('Illegal %s' % error_details) continue key, val = tup key = key.strip() val = val.strip() if key in rc_temp: - warnings.warn('Duplicate key in file "%s", line #%d' % - (fname, cnt)) + _log.warning('Duplicate key in file "%s", line #%d' % + (fname, cnt)) rc_temp[key] = (val, line, cnt) except UnicodeDecodeError: - warnings.warn( + _log.warning( ('Cannot decode configuration file %s with ' 'encoding %s, check LANG and LC_* variables') % (fname, locale.getpreferredencoding(do_setlocale=False) or @@ -990,8 +990,8 @@ def _rc_params_in_file(fname, fail_on_error=False): config[key] = val # try to convert to proper type or skip except Exception as msg: error_details = _error_details_fmt % (cnt, line, fname) - warnings.warn('Bad val "%s" on %s\n\t%s' % - (val, error_details, msg)) + _log.warning('Bad val "%s" on %s\n\t%s' % + (val, error_details, msg)) for key, (val, line, cnt) in rc_temp.items(): if key in defaultParams: @@ -1002,8 +1002,8 @@ def _rc_params_in_file(fname, fail_on_error=False): config[key] = val # try to convert to proper type or skip except Exception as msg: error_details = _error_details_fmt % (cnt, line, fname) - warnings.warn('Bad val "%s" on %s\n\t%s' % - (val, error_details, msg)) + _log.warning('Bad val "%s" on %s\n\t%s' % + (val, error_details, msg)) elif key in _deprecated_ignore_map: version, alt_key = _deprecated_ignore_map[key] cbook.warn_deprecated( @@ -1345,10 +1345,9 @@ def use(arg, warn=True, force=False): # If we are going to force the switch, never warn, else, if warn # is True, then direct users to `plt.switch_backend` if (not force) and warn: - warnings.warn( + cbook._warn_external( ("matplotlib.pyplot as already been imported, " - "this call will have no effect."), - stacklevel=2) + "this call will have no effect.")) # if we are going to force switching the backend, pull in # `switch_backend` from pyplot. This will only happen if @@ -1428,7 +1427,7 @@ def _init_tests(): from matplotlib import ft2font if (ft2font.__freetype_version__ != LOCAL_FREETYPE_VERSION or ft2font.__freetype_build_type__ != 'local'): - warnings.warn( + _log.warning( "Matplotlib is not built with the correct FreeType version to run " "tests. Set local_freetype=True in setup.cfg and rebuild. " "Expect many image comparison failures below. " @@ -1437,9 +1436,7 @@ def _init_tests(): "Freetype build type is {2}local".format( LOCAL_FREETYPE_VERSION, ft2font.__freetype_version__, - "" if ft2font.__freetype_build_type__ == 'local' else "not " - ) - ) + "" if ft2font.__freetype_build_type__ == 'local' else "not ")) try: import pytest @@ -1769,12 +1766,12 @@ def inner(ax, *args, data=None, **kwargs): elif label_namer in kwargs: kwargs['label'] = get_label(kwargs[label_namer], label) else: - warnings.warn( + cbook._warn_external( "Tried to set a label via parameter %r in func %r but " - "couldn't find such an argument.\n" - "(This is a programming error, please report to " - "the Matplotlib list!)" % (label_namer, func.__name__), - RuntimeWarning, stacklevel=2) + "couldn't find such an argument.\n(This is a " + "programming error, please report to the Matplotlib " + "list!)" % (label_namer, func.__name__), + RuntimeWarning) return func(ax, *args, **kwargs) inner.__doc__ = _add_data_doc(inner.__doc__, diff --git a/lib/matplotlib/_constrained_layout.py b/lib/matplotlib/_constrained_layout.py index 5ebc4adf6e42..aad269145739 100644 --- a/lib/matplotlib/_constrained_layout.py +++ b/lib/matplotlib/_constrained_layout.py @@ -45,10 +45,11 @@ # Todo: AnchoredOffsetbox connected to gridspecs or axes. This would # be more general way to add extra-axes annotations. -import numpy as np import logging -import warnings +import numpy as np + +import matplotlib.cbook as cbook import matplotlib._layoutbox as layoutbox _log = logging.getLogger(__name__) @@ -153,9 +154,9 @@ def do_constrained_layout(fig, renderer, h_pad, w_pad, if gs._layoutbox is not None: gss.add(gs) if len(gss) == 0: - warnings.warn('There are no gridspecs with layoutboxes. ' - 'Possibly did not call parent GridSpec with the figure= ' - 'keyword') + cbook._warn_external('There are no gridspecs with layoutboxes. ' + 'Possibly did not call parent GridSpec with the' + ' figure= keyword') if fig._layoutbox.constrained_layout_called < 1: for gs in gss: @@ -221,8 +222,8 @@ def do_constrained_layout(fig, renderer, h_pad, w_pad, # so this does the same w/o zeroing layout. ax._set_position(newpos, which='original') else: - warnings.warn('constrained_layout not applied. At least ' - 'one axes collapsed to zero width or height.') + cbook._warn_external('constrained_layout not applied. At least ' + 'one axes collapsed to zero width or height.') def _make_ghost_gridspec_slots(fig, gs): diff --git a/lib/matplotlib/artist.py b/lib/matplotlib/artist.py index bf4bef43911b..2db3c1265970 100644 --- a/lib/matplotlib/artist.py +++ b/lib/matplotlib/artist.py @@ -1,6 +1,7 @@ from collections import OrderedDict, namedtuple from functools import wraps import inspect +import logging import re import warnings @@ -12,6 +13,8 @@ from .transforms import (Bbox, IdentityTransform, Transform, TransformedBbox, TransformedPatchPath, TransformedPath) +_log = logging.getLogger(__name__) + def allow_rasterization(draw): """ @@ -400,7 +403,7 @@ def contains(self, mouseevent): """ if callable(self._contains): return self._contains(self, mouseevent) - warnings.warn("'%s' needs 'contains' method" % self.__class__.__name__) + _log.warning("'%s' needs 'contains' method" % self.__class__.__name__) return False, {} def set_contains(self, picker): @@ -850,7 +853,8 @@ def set_rasterized(self, rasterized): rasterized : bool or None """ if rasterized and not hasattr(self.draw, "_supports_rasterization"): - warnings.warn("Rasterization of '%s' will be ignored" % self) + cbook._warn_external( + "Rasterization of '%s' will be ignored" % self) self._rasterized = rasterized diff --git a/lib/matplotlib/axes/_axes.py b/lib/matplotlib/axes/_axes.py index adbf440cb131..0d79ea223d20 100644 --- a/lib/matplotlib/axes/_axes.py +++ b/lib/matplotlib/axes/_axes.py @@ -4623,8 +4623,9 @@ def hexbin(self, x, y, C=None, gridsize=100, bins=None, # Set normalizer if bins is 'log' if bins == 'log': if norm is not None: - warnings.warn("Only one of 'bins' and 'norm' arguments can be " - "supplied, ignoring bins={}".format(bins)) + cbook._warn_external("Only one of 'bins' and 'norm' " + "arguments can be supplied, ignoring " + "bins={}".format(bins)) else: norm = mcolors.LogNorm() bins = None diff --git a/lib/matplotlib/axes/_base.py b/lib/matplotlib/axes/_base.py index d6ae00a84e77..4024941d54c8 100644 --- a/lib/matplotlib/axes/_base.py +++ b/lib/matplotlib/axes/_base.py @@ -5,7 +5,6 @@ from numbers import Real from operator import attrgetter import types -import warnings import numpy as np @@ -1462,9 +1461,9 @@ def apply_aspect(self, position=None): elif ((xscale == "linear" and yscale == "log") or (xscale == "log" and yscale == "linear")): if aspect != "auto": - warnings.warn( + cbook._warn_external( 'aspect is not supported for Axes with xscale=%s, ' - 'yscale=%s' % (xscale, yscale), stacklevel=2) + 'yscale=%s' % (xscale, yscale)) aspect = "auto" else: # some custom projections have their own scales. pass @@ -2267,8 +2266,8 @@ def margins(self, *margins, x=None, y=None, tight=True): if x is None and y is None: if tight is not True: - warnings.warn('ignoring tight=%r in get mode' % (tight,), - stacklevel=2) + cbook._warn_external( + 'ignoring tight=%r in get mode' % (tight,)) return self._xmargin, self._ymargin if x is not None: @@ -3118,24 +3117,24 @@ def set_xlim(self, left=None, right=None, emit=True, auto=False, right = old_right if left == right: - warnings.warn( + cbook._warn_external( ('Attempting to set identical left==right results\n' 'in singular transformations; automatically expanding.\n' - 'left=%s, right=%s') % (left, right), stacklevel=2) + 'left=%s, right=%s') % (left, right)) left, right = mtransforms.nonsingular(left, right, increasing=False) if self.get_xscale() == 'log': if left <= 0: - warnings.warn( + cbook._warn_external( 'Attempted to set non-positive left xlim on a ' 'log-scaled axis.\n' - 'Invalid limit will be ignored.', stacklevel=2) + 'Invalid limit will be ignored.') left = old_left if right <= 0: - warnings.warn( + cbook._warn_external( 'Attempted to set non-positive right xlim on a ' 'log-scaled axis.\n' - 'Invalid limit will be ignored.', stacklevel=2) + 'Invalid limit will be ignored.') right = old_right left, right = self.xaxis.limit_range_for_scale(left, right) @@ -3451,25 +3450,25 @@ def set_ylim(self, bottom=None, top=None, emit=True, auto=False, top = old_top if bottom == top: - warnings.warn( + cbook._warn_external( ('Attempting to set identical bottom==top results\n' 'in singular transformations; automatically expanding.\n' - 'bottom=%s, top=%s') % (bottom, top), stacklevel=2) + 'bottom=%s, top=%s') % (bottom, top)) bottom, top = mtransforms.nonsingular(bottom, top, increasing=False) if self.get_yscale() == 'log': if bottom <= 0: - warnings.warn( + cbook._warn_external( 'Attempted to set non-positive bottom ylim on a ' 'log-scaled axis.\n' - 'Invalid limit will be ignored.', stacklevel=2) + 'Invalid limit will be ignored.') bottom = old_bottom if top <= 0: - warnings.warn( + cbook._warn_external( 'Attempted to set non-positive top ylim on a ' 'log-scaled axis.\n' - 'Invalid limit will be ignored.', stacklevel=2) + 'Invalid limit will be ignored.') top = old_top bottom, top = self.yaxis.limit_range_for_scale(bottom, top) @@ -3866,9 +3865,9 @@ def _set_view_from_bbox(self, bbox, direction='in', xzc + xwidth/2./scl, yzc + ywidth/2./scl] elif len(bbox) != 4: # should be len 3 or 4 but nothing else - warnings.warn( + cbook._warn_external( "Warning in _set_view_from_bbox: bounding box is not a tuple " - "of length 3 or 4. Ignoring the view change.", stacklevel=2) + "of length 3 or 4. Ignoring the view change.") return # Just grab bounding box @@ -4055,7 +4054,7 @@ def format_deltas(key, dx, dy): result = (mtransforms.Bbox(newpoints) .transformed(p.trans_inverse)) except OverflowError: - warnings.warn('Overflow while panning', stacklevel=2) + cbook._warn_external('Overflow while panning') return else: return diff --git a/lib/matplotlib/axis.py b/lib/matplotlib/axis.py index 5de5e3174ffb..358678985883 100644 --- a/lib/matplotlib/axis.py +++ b/lib/matplotlib/axis.py @@ -4,7 +4,6 @@ import datetime import logging -import warnings import numpy as np @@ -1055,9 +1054,10 @@ def _update_ticks(self, renderer): ds1 = self._get_pixel_distance_along_axis( interval_expanded[0], -0.5) except Exception: - warnings.warn("Unable to find pixel distance along axis " - "for interval padding of ticks; assuming no " - "interval padding needed.") + cbook._warn_external("Unable to find pixel distance " + "along axis for interval padding of " + "ticks; assuming no interval " + "padding needed.") ds1 = 0.0 if np.isnan(ds1): ds1 = 0.0 @@ -1065,9 +1065,10 @@ def _update_ticks(self, renderer): ds2 = self._get_pixel_distance_along_axis( interval_expanded[1], +0.5) except Exception: - warnings.warn("Unable to find pixel distance along axis " - "for interval padding of ticks; assuming no " - "interval padding needed.") + cbook._warn_external("Unable to find pixel distance " + "along axis for interval padding of " + "ticks; assuming no interval " + "padding needed.") ds2 = 0.0 if np.isnan(ds2): ds2 = 0.0 @@ -1390,9 +1391,9 @@ def grid(self, b=None, which='major', **kwargs): """ if len(kwargs): if not b and b is not None: # something false-like but not None - warnings.warn('First parameter to grid() is false, but line ' - 'properties are supplied. The grid will be ' - 'enabled.') + cbook._warn_external('First parameter to grid() is false, ' + 'but line properties are supplied. The ' + 'grid will be enabled.') b = True which = which.lower() if which not in ['major', 'minor', 'both']: diff --git a/lib/matplotlib/backend_bases.py b/lib/matplotlib/backend_bases.py index 652e44455d7a..4e31e3cb389c 100644 --- a/lib/matplotlib/backend_bases.py +++ b/lib/matplotlib/backend_bases.py @@ -35,10 +35,10 @@ from contextlib import contextmanager import importlib import io +import logging import os import sys import time -import warnings from weakref import WeakKeyDictionary import numpy as np @@ -61,6 +61,7 @@ except ImportError: _has_pil = False +_log = logging.getLogger(__name__) _default_filetypes = { 'ps': 'Postscript', @@ -2404,7 +2405,7 @@ def _get_uniform_gridstate(ticks): try: ax.set_yscale('log') except ValueError as exc: - warnings.warn(str(exc)) + _log.warning(str(exc)) ax.set_yscale('linear') ax.figure.canvas.draw_idle() # toggle scaling of x-axes between 'log and 'linear' (default key 'k') @@ -2417,7 +2418,7 @@ def _get_uniform_gridstate(ticks): try: ax.set_xscale('log') except ValueError as exc: - warnings.warn(str(exc)) + _log.warning(str(exc)) ax.set_xscale('linear') ax.figure.canvas.draw_idle() diff --git a/lib/matplotlib/backend_managers.py b/lib/matplotlib/backend_managers.py index f5429783972f..06bdcc3ecafe 100644 --- a/lib/matplotlib/backend_managers.py +++ b/lib/matplotlib/backend_managers.py @@ -4,13 +4,15 @@ toolbar clicks, ..) and the actions in response to the user inputs. """ -import warnings +import logging import matplotlib.cbook as cbook import matplotlib.widgets as widgets from matplotlib.rcsetup import validate_stringlist import matplotlib.backend_tools as tools +_log = logging.getLogger(__name__) + class ToolEvent(object): """Event for tool manipulation (add/remove)""" @@ -54,9 +56,9 @@ class ToolManager(object): """ def __init__(self, figure=None): - warnings.warn('Treat the new Tool classes introduced in v1.5 as ' + - 'experimental for now, the API will likely change in ' + - 'version 2.1 and perhaps the rcParam as well') + _log.warning('Treat the new Tool classes introduced in v1.5 as ' + 'experimental for now, the API will likely change in ' + 'version 2.1 and perhaps the rcParam as well') self._key_press_handler_id = None @@ -202,8 +204,8 @@ def update_keymap(self, name, *keys): for key in keys: for k in validate_stringlist(key): if k in self._keys: - warnings.warn('Key %s changed from %s to %s' % - (k, self._keys[k], name)) + cbook._warn_external('Key %s changed from %s to %s' % + (k, self._keys[k], name)) self._keys[k] = name def remove_tool(self, name): @@ -260,8 +262,8 @@ def add_tool(self, name, tool, *args, **kwargs): raise ValueError('Impossible to find class for %s' % str(tool)) if name in self._tools: - warnings.warn('A "Tool class" with the same name already exists, ' - 'not added') + cbook._warn_external('A "Tool class" with the same name already ' + 'exists, not added') return self._tools[name] tool_obj = tool_cls(self, name, *args, **kwargs) @@ -428,6 +430,7 @@ def get_tool(self, name, warn=True): return name if name not in self._tools: if warn: - warnings.warn("ToolManager does not control tool %s" % name) + cbook._warn_external("ToolManager does not control tool " + "%s" % name) return None return self._tools[name] diff --git a/lib/matplotlib/backend_tools.py b/lib/matplotlib/backend_tools.py index 9cf78c038842..231820b29484 100644 --- a/lib/matplotlib/backend_tools.py +++ b/lib/matplotlib/backend_tools.py @@ -13,7 +13,7 @@ import re import time -import warnings +import logging from weakref import WeakKeyDictionary import numpy as np @@ -22,6 +22,8 @@ from matplotlib._pylab_helpers import Gcf import matplotlib.cbook as cbook +_log = logging.getLogger(__name__) + class Cursors(object): """Simple namespace for cursor reference""" @@ -75,9 +77,9 @@ class ToolBase(object): """ def __init__(self, toolmanager, name): - warnings.warn('Treat the new Tool classes introduced in v1.5 as ' + - 'experimental for now, the API will likely change in ' + - 'version 2.1, and some tools might change name') + _log.warning('Treat the new Tool classes introduced in v1.5 as ' + 'experimental for now, the API will likely change in ' + 'version 2.1, and some tools might change name') self._name = name self._toolmanager = toolmanager self._figure = None diff --git a/lib/matplotlib/backends/backend_pdf.py b/lib/matplotlib/backends/backend_pdf.py index 1f93ded4496c..d046b0cf42b7 100644 --- a/lib/matplotlib/backends/backend_pdf.py +++ b/lib/matplotlib/backends/backend_pdf.py @@ -16,7 +16,6 @@ import sys import time import types -import warnings import zlib import numpy as np @@ -1556,11 +1555,11 @@ def is_date(x): 'Trapped': check_trapped} for k in self.infoDict: if k not in keywords: - warnings.warn('Unknown infodict keyword: %s' % k, stacklevel=2) + cbook._warn_external('Unknown infodict keyword: %s' % k) else: if not keywords[k](self.infoDict[k]): - warnings.warn('Bad value for infodict keyword %s' % k, - stacklevel=2) + cbook._warn_external( + 'Bad value for infodict keyword %s' % k) self.infoObject = self.reserveObject('info') self.writeObject(self.infoObject, self.infoDict) diff --git a/lib/matplotlib/backends/backend_pgf.py b/lib/matplotlib/backends/backend_pgf.py index 0771c37ae4a2..c62dc7ec1f67 100644 --- a/lib/matplotlib/backends/backend_pgf.py +++ b/lib/matplotlib/backends/backend_pgf.py @@ -9,7 +9,6 @@ import subprocess import sys import tempfile -import warnings import weakref import matplotlib as mpl @@ -400,9 +399,9 @@ def __init__(self, figure, fh, dummy=False): else: # if fh does not belong to a filename, deactivate draw_image if not hasattr(fh, 'name') or not os.path.exists(fh.name): - warnings.warn("streamed pgf-code does not support raster " - "graphics, consider using the pgf-to-pdf option", - UserWarning, stacklevel=2) + cbook._warn_external("streamed pgf-code does not support " + "raster graphics, consider using the " + "pgf-to-pdf option", UserWarning) self.__dict__["draw_image"] = lambda *args, **kwargs: None def draw_markers(self, gc, marker_path, marker_trans, path, trans, diff --git a/lib/matplotlib/backends/backend_webagg_core.py b/lib/matplotlib/backends/backend_webagg_core.py index b30f7bd416d6..16ca41d7fdd4 100644 --- a/lib/matplotlib/backends/backend_webagg_core.py +++ b/lib/matplotlib/backends/backend_webagg_core.py @@ -13,9 +13,9 @@ import datetime from io import StringIO import json +import logging import os from pathlib import Path -import warnings import numpy as np import tornado @@ -24,6 +24,7 @@ from matplotlib.backend_bases import _Backend from matplotlib import backend_bases, _png +_log = logging.getLogger(__name__) # http://www.cambiaresearch.com/articles/15/javascript-char-codes-key-codes _SHIFT_LUT = {59: ':', @@ -241,8 +242,8 @@ def handle_event(self, event): return handler(event) def handle_unknown_event(self, event): - warnings.warn('Unhandled message type {0}. {1}'.format( - event['type'], event), stacklevel=2) + _log.warning('Unhandled message type {0}. {1}'.format( + event['type'], event)) def handle_ack(self, event): # Network latency tends to decrease if traffic is flowing diff --git a/lib/matplotlib/backends/backend_wx.py b/lib/matplotlib/backends/backend_wx.py index 3523803fc245..f6c4c576bc13 100644 --- a/lib/matplotlib/backends/backend_wx.py +++ b/lib/matplotlib/backends/backend_wx.py @@ -7,10 +7,10 @@ Copyright (C) Jeremy O'Donoghue & John Hunter, 2003-4. """ -import os.path +import logging import math +import os.path import sys -import warnings import weakref import matplotlib @@ -30,6 +30,8 @@ import wx +_log = logging.getLogger(__name__) + # Debugging settings here... # Debug level set here. If the debug level is less than 5, information # messages (progressively more info for lower value) are printed. In addition, @@ -1573,10 +1575,10 @@ def save_figure(self, *args): if ext in ('svg', 'pdf', 'ps', 'eps', 'png') and format != ext: # looks like they forgot to set the image type drop # down, going with the extension. - warnings.warn( + _log.warning( 'extension %s did not match the selected ' 'image type %s; going with %s' % - (ext, format, ext), stacklevel=2) + (ext, format, ext)) format = ext try: self.canvas.figure.savefig( @@ -1837,10 +1839,10 @@ def trigger(self, *args): if ext in ('svg', 'pdf', 'ps', 'eps', 'png') and format != ext: # looks like they forgot to set the image type drop # down, going with the extension. - warnings.warn( + _log.warning( 'extension %s did not match the selected ' 'image type %s; going with %s' % - (ext, format, ext), stacklevel=2) + (ext, format, ext)) format = ext if default_dir != "": matplotlib.rcParams['savefig.directory'] = dirname diff --git a/lib/matplotlib/backends/qt_editor/formlayout.py b/lib/matplotlib/backends/qt_editor/formlayout.py index b5e4d57b3289..cb95d029671f 100644 --- a/lib/matplotlib/backends/qt_editor/formlayout.py +++ b/lib/matplotlib/backends/qt_editor/formlayout.py @@ -42,12 +42,13 @@ import copy import datetime +import logging from numbers import Integral, Real -import warnings -from matplotlib import colors as mcolors +from matplotlib import cbook, colors as mcolors from matplotlib.backends.qt_compat import QtGui, QtWidgets, QtCore +_log = logging.getLogger(__name__) BLACKLIST = {"title", "label"} @@ -93,7 +94,7 @@ def to_qcolor(color): try: rgba = mcolors.to_rgba(color) except ValueError: - warnings.warn('Ignoring invalid color %r' % color, stacklevel=2) + cbook._warn_external('Ignoring invalid color %r' % color) return qcolor # return invalid QColor qcolor.setRgbF(*rgba) return qcolor @@ -264,9 +265,9 @@ def setup(self): elif selindex in keys: selindex = keys.index(selindex) elif not isinstance(selindex, Integral): - warnings.warn( + _log.warning( "index '%s' is invalid (label: %s, value: %s)" % - (selindex, label, value), stacklevel=2) + (selindex, label, value)) selindex = 0 field.setCurrentIndex(selindex) elif isinstance(value, bool): diff --git a/lib/matplotlib/bezier.py b/lib/matplotlib/bezier.py index 6eb42e3a86de..5040d7b59964 100644 --- a/lib/matplotlib/bezier.py +++ b/lib/matplotlib/bezier.py @@ -2,9 +2,9 @@ A module providing some utility functions regarding bezier path manipulation. """ -import warnings - import numpy as np + +import matplotlib.cbook as cbook from matplotlib.path import Path @@ -342,7 +342,7 @@ def get_parallels(bezier2, width): cmx - c2x, cmy - c2y) if parallel_test == -1: - warnings.warn( + cbook._warn_external( "Lines do not intersect. A straight line is used instead.") cos_t1, sin_t1 = get_cos_sin(c1x, c1y, c2x, c2y) cos_t2, sin_t2 = cos_t1, sin_t1 diff --git a/lib/matplotlib/cbook/__init__.py b/lib/matplotlib/cbook/__init__.py index 473c2324a7a7..2c7edda021ef 100644 --- a/lib/matplotlib/cbook/__init__.py +++ b/lib/matplotlib/cbook/__init__.py @@ -296,8 +296,8 @@ def local_over_kwdict(local_var, kwargs, *keys): if out is None: out = kwarg_val else: - warnings.warn('"%s" keyword argument will be ignored' % key, - IgnoredKeywordWarning) + _warn_external('"%s" keyword argument will be ignored' % key, + IgnoredKeywordWarning) return out @@ -1702,9 +1702,9 @@ def normalize_kwargs(kw, alias_mapping=None, required=(), forbidden=(), if tmp: ret[canonical] = tmp[-1] if len(tmp) > 1: - warnings.warn("Saw kwargs {seen!r} which are all aliases for " - "{canon!r}. Kept value from {used!r}".format( - seen=seen, canon=canonical, used=seen[-1])) + _warn_external("Saw kwargs {seen!r} which are all aliases for " + "{canon!r}. Kept value from {used!r}".format( + seen=seen, canon=canonical, used=seen[-1])) # at this point we know that all keys which are aliased are removed, update # the return dictionary from the cleaned local copy of the input diff --git a/lib/matplotlib/colorbar.py b/lib/matplotlib/colorbar.py index 8504cfbd5c33..6eeeb31628ab 100644 --- a/lib/matplotlib/colorbar.py +++ b/lib/matplotlib/colorbar.py @@ -20,12 +20,12 @@ ''' import logging -import warnings import numpy as np import matplotlib as mpl import matplotlib.artist as martist +import matplotlib.cbook as cbook import matplotlib.collections as collections import matplotlib.colors as colors import matplotlib.contour as contour @@ -211,7 +211,7 @@ def _set_ticks_on_axis_warn(*args, **kw): # a top level function which gets put in at the axes' # set_xticks set_yticks by _patch_ax - warnings.warn("Use the colorbar set_ticks() method instead.") + cbook._warn_external("Use the colorbar set_ticks() method instead.") class _ColorbarAutoLocator(ticker.MaxNLocator): @@ -586,7 +586,7 @@ def set_ticklabels(self, ticklabels, update_ticks=True): if update_ticks: self.update_ticks() else: - warnings.warn("set_ticks() must have been called.") + cbook._warn_external("set_ticks() must have been called.") self.stale = True def _config_axes(self, X, Y): @@ -1204,8 +1204,8 @@ def minorticks_on(self): long_axis = ax.yaxis if self.orientation == 'vertical' else ax.xaxis if long_axis.get_scale() == 'log': - warnings.warn('minorticks_on() has no effect on a ' - 'logarithmic colorbar axis') + cbook._warn_external('minorticks_on() has no effect on a ' + 'logarithmic colorbar axis') else: long_axis.set_minor_locator(_ColorbarAutoMinorLocator(self)) @@ -1217,8 +1217,8 @@ def minorticks_off(self): long_axis = ax.yaxis if self.orientation == 'vertical' else ax.xaxis if long_axis.get_scale() == 'log': - warnings.warn('minorticks_off() has no effect on a ' - 'logarithmic colorbar axis') + cbook._warn_external('minorticks_off() has no effect on a ' + 'logarithmic colorbar axis') else: long_axis.set_minor_locator(ticker.NullLocator()) diff --git a/lib/matplotlib/contour.py b/lib/matplotlib/contour.py index a723d44e4c9c..e411bd60338c 100644 --- a/lib/matplotlib/contour.py +++ b/lib/matplotlib/contour.py @@ -3,7 +3,6 @@ """ from numbers import Integral -import warnings import numpy as np from numpy import ma @@ -939,7 +938,7 @@ def __init__(self, ax, *args, if self.filled: if self.linewidths is not None: - warnings.warn('linewidths is ignored by contourf') + cbook._warn_external('linewidths is ignored by contourf') # Lower and upper contour levels. lowers, uppers = self._get_lowers_and_uppers() @@ -996,8 +995,8 @@ def __init__(self, ax, *args, if kwargs: s = ", ".join(map(repr, kwargs)) - warnings.warn('The following kwargs were not used by contour: ' + - s) + cbook._warn_external('The following kwargs were not used by ' + 'contour: ' + s) def get_transform(self): """ @@ -1236,8 +1235,8 @@ def _contour_level_args(self, z, args): levels_in = self.levels[inside] if len(levels_in) == 0: self.levels = [self.zmin] - warnings.warn("No contour levels were found" - " within the data range.") + cbook._warn_external( + "No contour levels were found within the data range.") if self.filled and len(self.levels) < 2: raise ValueError("Filled contours require at least 2 levels.") @@ -1554,7 +1553,8 @@ def _contour_args(self, args, kwargs): self.zmin = float(z.min()) if self.logscale and self.zmin <= 0: z = ma.masked_where(z <= 0, z) - warnings.warn('Log scale: values of z <= 0 have been masked') + cbook._warn_external('Log scale: values of z <= 0 have been ' + 'masked') self.zmin = float(z.min()) self._contour_level_args(z, args) return (x, y, z) diff --git a/lib/matplotlib/dates.py b/lib/matplotlib/dates.py index 217b9cdc3dad..37b962724687 100644 --- a/lib/matplotlib/dates.py +++ b/lib/matplotlib/dates.py @@ -1311,11 +1311,13 @@ def get_locator(self, dmin, dmax): else: # We went through the whole loop without breaking, default to # the last interval in the list and raise a warning - warnings.warn('AutoDateLocator was unable to pick an ' - 'appropriate interval for this date range. ' - 'It may be necessary to add an interval value ' - "to the AutoDateLocator's intervald dictionary." - ' Defaulting to {0}.'.format(interval)) + cbook._warn_external('AutoDateLocator was unable to pick an ' + 'appropriate interval for this date ' + 'range. It may be necessary to add an ' + 'interval value to the ' + 'AutoDateLocator\'s intervald ' + 'dictionary. Defaulting to {0}.' + .format(interval)) # Set some parameters as appropriate self._freq = freq diff --git a/lib/matplotlib/figure.py b/lib/matplotlib/figure.py index 43da72020d1f..ea60cfb66c96 100644 --- a/lib/matplotlib/figure.py +++ b/lib/matplotlib/figure.py @@ -13,7 +13,6 @@ import logging from numbers import Integral -import warnings import numpy as np @@ -132,7 +131,7 @@ def add(self, key, a): a_existing = self.get(key) if a_existing is not None: super().remove((key, a_existing)) - warnings.warn( + cbook._warn_external( "key {!r} already existed; Axes is being replaced".format(key)) # I don't think the above should ever happen. @@ -434,9 +433,9 @@ def show(self, warn=True): pass if (backends._get_running_interactive_framework() != "headless" and warn): - warnings.warn('Matplotlib is currently using %s, which is a ' - 'non-GUI backend, so cannot show the figure.' - % get_backend()) + cbook._warn_external('Matplotlib is currently using %s, which is ' + 'a non-GUI backend, so cannot show the ' + 'figure.' % get_backend()) def _get_axes(self): return self._axstack.as_list() @@ -1494,9 +1493,9 @@ def subplots(self, nrows=1, ncols=1, sharex=False, sharey=False, # will result because what was intended to be the subplot index is # instead treated as a bool for sharex. if isinstance(sharex, Integral): - warnings.warn( - "sharex argument to subplots() was an integer. " - "Did you intend to use subplot() (without 's')?") + cbook._warn_external("sharex argument to subplots() was an " + "integer. Did you intend to use " + "subplot() (without 's')?") raise ValueError("sharex [%s] must be one of %s" % (sharex, share_values)) @@ -1861,9 +1860,10 @@ def gca(self, **kwargs): if key == ckey and isinstance(cax, projection_class): return cax else: - warnings.warn('Requested projection is different from ' - 'current axis projection, creating new axis ' - 'with requested projection.', stacklevel=2) + cbook._warn_external('Requested projection is different ' + 'from current axis projection, ' + 'creating new axis with requested ' + 'projection.') # no axes found, so create one which spans the figure return self.add_subplot(1, 1, 1, **kwargs) @@ -1930,9 +1930,9 @@ def __setstate__(self, state): restore_to_pylab = state.pop('_restore_to_pylab', False) if version != _mpl_version: - warnings.warn("This figure was saved with matplotlib version %s " - "and is unlikely to function correctly." % - (version, )) + cbook._warn_external("This figure was saved with matplotlib " + "version %s and is unlikely to function " + "correctly." % (version,)) self.__dict__ = state @@ -2157,10 +2157,11 @@ def subplots_adjust(self, left=None, bottom=None, right=None, top=None, """ if self.get_constrained_layout(): self.set_constrained_layout(False) - warnings.warn("This figure was using constrained_layout==True, " - "but that is incompatible with subplots_adjust and " - "or tight_layout: setting " - "constrained_layout==False. ") + cbook._warn_external("This figure was using " + "constrained_layout==True, but that is " + "incompatible with subplots_adjust and or " + "tight_layout: setting " + "constrained_layout==False. ") self.subplotpars.update(left, bottom, right, top, wspace, hspace) for ax in self.axes: if not isinstance(ax, SubplotBase): @@ -2329,11 +2330,12 @@ def execute_constrained_layout(self, renderer=None): _log.debug('Executing constrainedlayout') if self._layoutbox is None: - warnings.warn("Calling figure.constrained_layout, but figure not " - "setup to do constrained layout. You either called " - "GridSpec without the fig keyword, you are using " - "plt.subplot, or you need to call figure or " - "subplots with the constrained_layout=True kwarg.") + cbook._warn_external("Calling figure.constrained_layout, but " + "figure not setup to do constrained layout. " + " You either called GridSpec without the " + "fig keyword, you are using plt.subplot, " + "or you need to call figure or subplots " + "with the constrained_layout=True kwarg.") return w_pad, h_pad, wspace, hspace = self.get_constrained_layout_pads() # convert to unit-relative lengths @@ -2381,8 +2383,9 @@ def tight_layout(self, renderer=None, pad=1.08, h_pad=None, w_pad=None, subplotspec_list = get_subplotspec_list(self.axes) if None in subplotspec_list: - warnings.warn("This figure includes Axes that are not compatible " - "with tight_layout, so results might be incorrect.") + cbook._warn_external("This figure includes Axes that are not " + "compatible with tight_layout, so results " + "might be incorrect.") if renderer is None: renderer = get_renderer(self) diff --git a/lib/matplotlib/font_manager.py b/lib/matplotlib/font_manager.py index a6a3b3ea83df..dcf62fffc0f7 100644 --- a/lib/matplotlib/font_manager.py +++ b/lib/matplotlib/font_manager.py @@ -34,7 +34,6 @@ from threading import Timer except ImportError: from dummy_threading import Timer -import warnings import matplotlib as mpl from matplotlib import afm, cbook, ft2font, rcParams @@ -217,7 +216,7 @@ def _call_fc_list(): """Cache and list the font filenames known to `fc-list`. """ # Delay the warning by 5s. - timer = Timer(5, lambda: warnings.warn( + timer = Timer(5, lambda: _log.warning( 'Matplotlib is building the font cache using fc-list. ' 'This may take a moment.')) timer.start() @@ -865,7 +864,7 @@ def json_dump(data, filename): try: json.dump(data, fh, cls=JSONEncoder, indent=2) except OSError as e: - warnings.warn('Could not save font_manager cache {}'.format(e)) + _log.warning('Could not save font_manager cache {}'.format(e)) def json_load(filename): @@ -1216,7 +1215,7 @@ def _findfont_cached(self, prop, fontext, directory, fallback_to_default, if best_font is None or best_score >= 10.0: if fallback_to_default: - warnings.warn( + _log.warning( 'findfont: Font family %s not found. Falling back to %s.' % (prop.get_family(), self.defaultFamily[fontext])) default_prop = prop.copy() @@ -1225,9 +1224,8 @@ def _findfont_cached(self, prop, fontext, directory, fallback_to_default, else: # This is a hard fail -- we can't find anything reasonable, # so just return the DejuVuSans.ttf - warnings.warn('findfont: Could not match %s. Returning %s.' % - (prop, self.defaultFont[fontext]), - UserWarning) + _log.warning('findfont: Could not match %s. Returning %s.' % + (prop, self.defaultFont[fontext])) result = self.defaultFont[fontext] else: _log.debug('findfont: Matching %s to %s (%r) with score of %f.', diff --git a/lib/matplotlib/gridspec.py b/lib/matplotlib/gridspec.py index ac2b77ddbe1d..8964657b049d 100644 --- a/lib/matplotlib/gridspec.py +++ b/lib/matplotlib/gridspec.py @@ -15,7 +15,6 @@ import copy import logging -import warnings import numpy as np @@ -332,8 +331,9 @@ def tight_layout(self, figure, renderer=None, subplotspec_list = tight_layout.get_subplotspec_list( figure.axes, grid_spec=self) if None in subplotspec_list: - warnings.warn("This figure includes Axes that are not compatible " - "with tight_layout, so results might be incorrect.") + cbook._warn_external("This figure includes Axes that are not " + "compatible with tight_layout, so results " + "might be incorrect.") if renderer is None: renderer = tight_layout.get_renderer(figure) diff --git a/lib/matplotlib/image.py b/lib/matplotlib/image.py index 54a670288ebc..d3ce8f4bd15e 100644 --- a/lib/matplotlib/image.py +++ b/lib/matplotlib/image.py @@ -9,7 +9,6 @@ import logging import urllib.parse import urllib.request -import warnings import numpy as np @@ -364,9 +363,9 @@ def _make_image(self, A, in_bbox, out_bbox, clip_bbox, magnification=1.0, # Cast to float64 if A.dtype not in (np.float32, np.float16): if A.dtype != np.float64: - warnings.warn( - "Casting input data from '{0}' to 'float64'" - "for imshow".format(A.dtype)) + cbook._warn_external("Casting input data from " + "'{0}' to 'float64' for " + "imshow".format(A.dtype)) scaled_dtype = np.float64 else: # probably an integer of some type. diff --git a/lib/matplotlib/legend.py b/lib/matplotlib/legend.py index a9d13d7fce2b..b9a566345612 100644 --- a/lib/matplotlib/legend.py +++ b/lib/matplotlib/legend.py @@ -22,10 +22,10 @@ """ import logging -import warnings import numpy as np +from matplotlib import cbook from matplotlib import rcParams from matplotlib import cbook, docstring from matplotlib.artist import Artist, allow_rasterization @@ -443,9 +443,9 @@ def __init__(self, parent, handles, labels, _lab, _hand = [], [] for label, handle in zip(labels, handles): if isinstance(label, str) and label.startswith('_'): - warnings.warn('The handle {!r} has a label of {!r} which ' - 'cannot be automatically added to the ' - 'legend.'.format(handle, label)) + cbook._warn_external('The handle {!r} has a label of {!r} ' + 'which cannot be automatically added to' + ' the legend.'.format(handle, label)) else: _lab.append(label) _hand.append(handle) @@ -793,13 +793,12 @@ def _init_legend_box(self, handles, labels, markerfirst=True): for orig_handle, lab in zip(handles, labels): handler = self.get_legend_handler(legend_handler_map, orig_handle) if handler is None: - warnings.warn( + cbook._warn_external( "Legend does not support {!r} instances.\nA proxy artist " "may be used instead.\nSee: " "http://matplotlib.org/users/legend_guide.html" "#creating-artists-specifically-for-adding-to-the-legend-" - "aka-proxy-artists".format(orig_handle) - ) + "aka-proxy-artists".format(orig_handle)) # We don't have a handle for this artist, so we just defer # to None. handle_list.append(None) @@ -1270,8 +1269,8 @@ def _parse_legend_args(axs, *args, handles=None, labels=None, **kwargs): extra_args = () if (handles is not None or labels is not None) and args: - warnings.warn("You have mixed positional and keyword arguments, some " - "input may be discarded.") + cbook._warn_external("You have mixed positional and keyword " + "arguments, some input may be discarded.") # if got both handles and labels as kwargs, make same length if handles and labels: diff --git a/lib/matplotlib/lines.py b/lib/matplotlib/lines.py index ee81cf9f256f..0166439bb4d2 100644 --- a/lib/matplotlib/lines.py +++ b/lib/matplotlib/lines.py @@ -5,7 +5,7 @@ # TODO: expose cap and join style attrs from numbers import Integral, Number, Real -import warnings +import logging import numpy as np @@ -25,6 +25,8 @@ CARETLEFTBASE, CARETRIGHTBASE, CARETUPBASE, CARETDOWNBASE, TICKLEFT, TICKRIGHT, TICKUP, TICKDOWN) +_log = logging.getLogger(__name__) + def _get_dash_pattern(style): """Convert linestyle -> dash pattern @@ -473,7 +475,7 @@ def contains(self, mouseevent): # Convert pick radius from points to pixels if self.figure is None: - warnings.warn('no figure set when check if mouse is on line') + _log.warning('no figure set when check if mouse is on line') pixels = self.pickradius else: pixels = self.figure.dpi / 72. * self.pickradius diff --git a/lib/matplotlib/mathtext.py b/lib/matplotlib/mathtext.py index efec64b7b7b8..eccbb73d5641 100644 --- a/lib/matplotlib/mathtext.py +++ b/lib/matplotlib/mathtext.py @@ -17,10 +17,10 @@ import functools from io import StringIO +import logging import os import types import unicodedata -import warnings import numpy as np @@ -40,6 +40,8 @@ tex2uni, latex_to_cmex, stix_virtual_fonts) +_log = logging.getLogger(__name__) + ############################################################################## # FONTS @@ -805,9 +807,8 @@ def _get_glyph(self, fontname, font_class, sym, fontsize, math=True): found_symbol = True except ValueError: uniindex = ord('?') - warnings.warn( - "No TeX to unicode mapping for {!a}.".format(sym), - MathTextWarning) + _log.warning( + "No TeX to unicode mapping for {!a}.".format(sym)) fontname, uniindex = self._map_virtual_font( fontname, font_class, uniindex) @@ -834,9 +835,8 @@ def _get_glyph(self, fontname, font_class, sym, fontsize, math=True): if not found_symbol: if self.cm_fallback: if isinstance(self.cm_fallback, BakomaFonts): - warnings.warn( - "Substituting with a symbol from Computer Modern.", - MathTextWarning) + _log.warning( + "Substituting with a symbol from Computer Modern.") if (fontname in ('it', 'regular') and isinstance(self.cm_fallback, StixFonts)): return self.cm_fallback._get_glyph( @@ -848,11 +848,9 @@ def _get_glyph(self, fontname, font_class, sym, fontsize, math=True): if (fontname in ('it', 'regular') and isinstance(self, StixFonts)): return self._get_glyph('rm', font_class, sym, fontsize) - warnings.warn( - "Font {!r} does not have a glyph for {!a} [U+{:x}], " - "substituting with a dummy symbol.".format( - new_fontname, sym, uniindex), - MathTextWarning) + _log.warning("Font {!r} does not have a glyph for {!a} " + "[U+{:x}], substituting with a dummy " + "symbol.".format(new_fontname, sym, uniindex)) fontname = 'rm' font = self._get_font(fontname) uniindex = 0xA4 # currency char, for lack of anything better @@ -1149,9 +1147,8 @@ def _get_info(self, fontname, font_class, sym, fontsize, dpi, math=True): num = ord(glyph) found_symbol = True else: - warnings.warn( - "No TeX to built-in Postscript mapping for {!r}".format(sym), - MathTextWarning) + _log.warning( + "No TeX to built-in Postscript mapping for {!r}".format(sym)) slanted = (fontname == 'it') font = self._get_font(fontname) @@ -1160,10 +1157,9 @@ def _get_info(self, fontname, font_class, sym, fontsize, dpi, math=True): try: symbol_name = font.get_name_char(glyph) except KeyError: - warnings.warn( + _log.warning( "No glyph in standard Postscript font {!r} for {!r}" - .format(font.get_fontname(), sym), - MathTextWarning) + .format(font.get_fontname(), sym)) found_symbol = False if not found_symbol: @@ -1595,9 +1591,8 @@ def _set_glue(self, x, sign, totals, error_type): self.glue_ratio = 0. if o == 0: if len(self.children): - warnings.warn( - "%s %s: %r" % (error_type, self.__class__.__name__, self), - MathTextWarning) + _log.warning( + "%s %s: %r" % (error_type, self.__class__.__name__, self)) def shrink(self): for child in self.children: diff --git a/lib/matplotlib/mlab.py b/lib/matplotlib/mlab.py index 4b5c7c6e7105..e79d13f2a53e 100644 --- a/lib/matplotlib/mlab.py +++ b/lib/matplotlib/mlab.py @@ -54,7 +54,6 @@ """ import csv -import warnings import numpy as np @@ -1115,8 +1114,9 @@ def specgram(x, NFFT=None, Fs=None, detrend=None, window=None, if NFFT is None: NFFT = 256 # same default as in _spectral_helper() if len(x) <= NFFT: - warnings.warn("Only one segment is calculated since parameter NFFT " + - "(=%d) >= signal length (=%d)." % (NFFT, len(x))) + cbook._warn_external("Only one segment is calculated since parameter " + "NFFT (=%d) >= signal length (=%d)." % + (NFFT, len(x))) spec, freqs, t = _spectral_helper(x=x, y=None, NFFT=NFFT, Fs=Fs, detrend_func=detrend, window=window, diff --git a/lib/matplotlib/offsetbox.py b/lib/matplotlib/offsetbox.py index 9e693a6396c5..bf87effa565b 100644 --- a/lib/matplotlib/offsetbox.py +++ b/lib/matplotlib/offsetbox.py @@ -14,8 +14,6 @@ width and height of the its child text. """ -import warnings - import numpy as np from matplotlib import cbook, docstring, rcParams diff --git a/lib/matplotlib/patches.py b/lib/matplotlib/patches.py index db15c1d1a148..e31b03d0163d 100644 --- a/lib/matplotlib/patches.py +++ b/lib/matplotlib/patches.py @@ -73,8 +73,9 @@ def __init__(self, self._fill = True # needed for set_facecolor call if color is not None: if edgecolor is not None or facecolor is not None: - warnings.warn("Setting the 'color' property will override" - "the edgecolor or facecolor properties.") + cbook._warn_external( + "Setting the 'color' property will override" + "the edgecolor or facecolor properties.") self.set_color(color) else: self.set_edgecolor(edgecolor) diff --git a/lib/matplotlib/pyplot.py b/lib/matplotlib/pyplot.py index 6ceced49285c..92bbf6c7b112 100644 --- a/lib/matplotlib/pyplot.py +++ b/lib/matplotlib/pyplot.py @@ -35,6 +35,7 @@ from matplotlib import _pylab_helpers, interactive from matplotlib.cbook import ( dedent, deprecated, silent_list, warn_deprecated, _string_to_bool) +from matplotlib import cbook from matplotlib import docstring from matplotlib.backend_bases import FigureCanvasBase from matplotlib.figure import Figure, figaspect @@ -491,7 +492,8 @@ def figure(num=None, # autoincrement if None, else integer from 1-N allLabels = get_figlabels() if figLabel not in allLabels: if figLabel == 'all': - warnings.warn("close('all') closes all existing figures") + cbook._warn_external( + "close('all') closes all existing figures") num = next_num else: inum = allLabels.index(figLabel) @@ -504,7 +506,7 @@ def figure(num=None, # autoincrement if None, else integer from 1-N max_open_warning = rcParams['figure.max_open_warning'] if len(allnums) >= max_open_warning >= 1: - warnings.warn( + cbook._warn_external( "More than %d figures have been opened. Figures " "created through the pyplot interface " "(`matplotlib.pyplot.figure`) are retained until " @@ -1045,8 +1047,9 @@ def subplot(*args, **kwargs): # intended to be the sharex argument is instead treated as a # subplot index for subplot() if len(args) >= 3 and isinstance(args[2], bool): - warnings.warn("The subplot index argument to subplot() appears " - "to be a boolean. Did you intend to use subplots()?") + cbook._warn_external("The subplot index argument to subplot() appears " + "to be a boolean. Did you intend to use " + "subplots()?") fig = gcf() a = fig.add_subplot(*args, **kwargs) @@ -2192,8 +2195,8 @@ def polar(*args, **kwargs): # If an axis already exists, check if it has a polar projection if gcf().get_axes(): if not isinstance(gca(), PolarAxes): - warnings.warn('Trying to create polar plot on an axis that does ' - 'not have a polar projection.') + cbook._warn_external('Trying to create polar plot on an axis ' + 'that does not have a polar projection.') ax = gca(polar=True) ret = ax.plot(*args, **kwargs) return ret diff --git a/lib/matplotlib/sphinxext/mathmpl.py b/lib/matplotlib/sphinxext/mathmpl.py index 82ee3d71888d..d0bd82352041 100644 --- a/lib/matplotlib/sphinxext/mathmpl.py +++ b/lib/matplotlib/sphinxext/mathmpl.py @@ -1,13 +1,13 @@ import hashlib import os import sys -import warnings from docutils import nodes from docutils.parsers.rst import directives import sphinx from matplotlib import rcParams +from matplotlib import cbook from matplotlib.mathtext import MathTextParser rcParams['mathtext.fontset'] = 'cm' mathtext_parser = MathTextParser("Bitmap") @@ -58,8 +58,8 @@ def latex2png(latex, filename, fontset='cm'): try: depth = mathtext_parser.to_png(filename, latex, dpi=100) except Exception: - warnings.warn("Could not render math expression %s" % latex, - Warning, stacklevel=2) + cbook._warn_external("Could not render math expression %s" % latex, + Warning) depth = 0 rcParams['mathtext.fontset'] = orig_fontset sys.stdout.write("#") diff --git a/lib/matplotlib/spines.py b/lib/matplotlib/spines.py index 677dd4edc48d..7eaa72f5c4c9 100644 --- a/lib/matplotlib/spines.py +++ b/lib/matplotlib/spines.py @@ -1,9 +1,7 @@ -import warnings - import numpy as np import matplotlib -from matplotlib import docstring, rcParams +from matplotlib import cbook, docstring, rcParams from matplotlib.artist import allow_rasterization import matplotlib.transforms as mtransforms import matplotlib.patches as mpatches @@ -347,8 +345,8 @@ def _calc_offset_transform(self): offset_y, self.figure.dpi_scale_trans)) else: - warnings.warn('unknown spine type "%s": no spine ' - 'offset performed' % self.spine_type) + cbook._warn_external('unknown spine type "%s": no spine ' + 'offset performed' % self.spine_type) self._spine_transform = ('identity', mtransforms.IdentityTransform()) elif position_type == 'axes': @@ -365,8 +363,8 @@ def _calc_offset_transform(self): # amount 1, 0, 0, 0, 0, amount)) else: - warnings.warn('unknown spine type "%s": no spine ' - 'offset performed' % self.spine_type) + cbook._warn_external('unknown spine type "%s": no spine ' + 'offset performed' % self.spine_type) self._spine_transform = ('identity', mtransforms.IdentityTransform()) elif position_type == 'data': @@ -384,8 +382,8 @@ def _calc_offset_transform(self): mtransforms.Affine2D().translate( 0, amount)) else: - warnings.warn('unknown spine type "%s": no spine ' - 'offset performed' % self.spine_type) + cbook._warn_external('unknown spine type "%s": no spine ' + 'offset performed' % self.spine_type) self._spine_transform = ('identity', mtransforms.IdentityTransform()) diff --git a/lib/matplotlib/style/core.py b/lib/matplotlib/style/core.py index a29970f4748c..05a7e660b161 100644 --- a/lib/matplotlib/style/core.py +++ b/lib/matplotlib/style/core.py @@ -12,14 +12,16 @@ """ import contextlib +import logging import os import re import warnings import matplotlib as mpl -from matplotlib import rc_params_from_file, rcParamsDefault +from matplotlib import cbook, rc_params_from_file, rcParamsDefault from matplotlib.cbook import MatplotlibDeprecationWarning +_log = logging.getLogger(__name__) __all__ = ['use', 'context', 'available', 'library', 'reload_library'] @@ -44,9 +46,9 @@ def _remove_blacklisted_style_params(d, warn=True): for key, val in d.items(): if key in STYLE_BLACKLIST: if warn: - warnings.warn( + cbook._warn_external( "Style includes a parameter, '{0}', that is not related " - "to style. Ignoring".format(key), stacklevel=3) + "to style. Ignoring".format(key)) else: o[key] = val return o @@ -189,7 +191,7 @@ def read_style_directory(style_dir): for w in warns: message = 'In %s: %s' % (path, w.message) - warnings.warn(message, stacklevel=2) + _log.warning(message) return styles diff --git a/lib/matplotlib/testing/__init__.py b/lib/matplotlib/testing/__init__.py index 580335395ce4..6331480f288a 100644 --- a/lib/matplotlib/testing/__init__.py +++ b/lib/matplotlib/testing/__init__.py @@ -1,9 +1,12 @@ import locale +import logging import warnings import matplotlib as mpl from matplotlib.cbook import MatplotlibDeprecationWarning +_log = logging.getLogger(__name__) + def is_called_from_pytest(): """Returns whether the call was done from pytest""" @@ -30,7 +33,7 @@ def setup(): try: locale.setlocale(locale.LC_ALL, 'English_United States.1252') except locale.Error: - warnings.warn( + _log.warning( "Could not set locale to English/United States. " "Some date-related tests may fail.") diff --git a/lib/matplotlib/text.py b/lib/matplotlib/text.py index 87d4f6ba5597..ba04cfe55252 100644 --- a/lib/matplotlib/text.py +++ b/lib/matplotlib/text.py @@ -5,7 +5,6 @@ import contextlib import logging import math -import warnings import weakref import numpy as np @@ -2147,9 +2146,9 @@ def transform(renderer) -> Transform if (xytext is None and textcoords is not None and textcoords != xycoords): - warnings.warn("You have used the `textcoords` kwarg, but not " - "the `xytext` kwarg. This can lead to surprising " - "results.") + cbook._warn_external("You have used the `textcoords` kwarg, but " + "not the `xytext` kwarg. This can lead to " + "surprising results.") # clean up textcoords and assign default if textcoords is None: @@ -2267,7 +2266,7 @@ def _update_position_xytext(self, renderer, xy_pixel): # Ignore frac--it is useless. frac = d.pop('frac', None) if frac is not None: - warnings.warn( + cbook._warn_external( "'frac' option in 'arrowprops' is no longer supported;" " use 'headlength' to set the head length in points.") headlength = d.pop('headlength', 12) diff --git a/lib/matplotlib/textpath.py b/lib/matplotlib/textpath.py index 97302a6ce494..e02fad57a7b3 100644 --- a/lib/matplotlib/textpath.py +++ b/lib/matplotlib/textpath.py @@ -1,7 +1,7 @@ from collections import OrderedDict import functools +import logging import urllib.parse -import warnings import numpy as np @@ -13,6 +13,8 @@ from matplotlib.path import Path from matplotlib.transforms import Affine2D +_log = logging.getLogger(__name__) + @functools.lru_cache(1) def _get_adobe_standard_encoding(): @@ -318,9 +320,9 @@ def get_glyphs_tex(self, prop, s, glyph_map=None, if charcode is not None: glyph0 = font.load_char(charcode, flags=ft2font_flag) else: - warnings.warn("The glyph (%d) of font (%s) cannot be " - "converted with the encoding. Glyph may " - "be wrong" % (glyph, font.fname)) + _log.warning("The glyph (%d) of font (%s) cannot be " + "converted with the encoding. Glyph may " + "be wrong" % (glyph, font.fname)) glyph0 = font.load_char(glyph, flags=ft2font_flag) @@ -367,8 +369,8 @@ def _get_ps_font_and_encoding(texname): break else: charmap_name = "" - warnings.warn("No supported encoding in font (%s)." % - font_bunch.filename) + _log.warning("No supported encoding in font (%s)." % + font_bunch.filename) if charmap_name == "ADOBE_STANDARD" and font_bunch.encoding: enc0 = dviread.Encoding(font_bunch.encoding) diff --git a/lib/matplotlib/ticker.py b/lib/matplotlib/ticker.py index 96ddf3279100..0efc193bbc8c 100644 --- a/lib/matplotlib/ticker.py +++ b/lib/matplotlib/ticker.py @@ -173,8 +173,6 @@ from matplotlib import cbook from matplotlib import transforms as mtransforms -import warnings - _log = logging.getLogger(__name__) __all__ = ('TickHelper', 'Formatter', 'FixedFormatter', @@ -1441,8 +1439,9 @@ def set_params(self, **kwargs): Do nothing, and rase a warning. Any locator class not supporting the set_params() function will call this. """ - warnings.warn("'set_params()' not defined for locator of type " + - str(type(self))) + cbook._warn_external( + "'set_params()' not defined for locator of type " + + str(type(self))) def __call__(self): """Return the locations of the ticks""" @@ -2241,7 +2240,7 @@ def nonsingular(self, vmin, vmax): if vmin > vmax: vmin, vmax = vmax, vmin if vmax <= 0: - warnings.warn( + cbook._warn_external( "Data has no positive values, and therefore cannot be " "log-scaled.") return 1, 10 @@ -2560,8 +2559,8 @@ def __init__(self, n=None): def __call__(self): 'Return the locations of the ticks' if self.axis.get_scale() == 'log': - warnings.warn('AutoMinorLocator does not work with logarithmic ' - 'scale') + cbook._warn_external('AutoMinorLocator does not work with ' + 'logarithmic scale') return [] majorlocs = self.axis.get_majorticklocs() diff --git a/lib/matplotlib/tight_layout.py b/lib/matplotlib/tight_layout.py index 0b3b40e1cd98..06ab3927ec57 100644 --- a/lib/matplotlib/tight_layout.py +++ b/lib/matplotlib/tight_layout.py @@ -9,9 +9,8 @@ for some cases (for example, left or right margin is affected by xlabel). """ -import warnings - import matplotlib +from matplotlib import cbook from matplotlib.transforms import TransformedBbox, Bbox from matplotlib.font_manager import FontProperties @@ -173,14 +172,14 @@ def auto_adjust_subplotpars( margin_bottom += pad_inches / fig_height_inch if margin_left + margin_right >= 1: - warnings.warn('Tight layout not applied. The left and right margins ' - 'cannot be made large ' - 'enough to accommodate all axes decorations. ') + cbook._warn_external('Tight layout not applied. The left and right ' + 'margins cannot be made large enough to ' + 'accommodate all axes decorations. ') return None if margin_bottom + margin_top >= 1: - warnings.warn('Tight layout not applied. ' - 'The bottom and top margins cannot be made large ' - 'enough to accommodate all axes decorations. ') + cbook._warn_external('Tight layout not applied. The bottom and top ' + 'margins cannot be made large enough to ' + 'accommodate all axes decorations. ') return None kwargs = dict(left=margin_left, @@ -196,9 +195,9 @@ def auto_adjust_subplotpars( # axes widths: h_axes = (1 - margin_right - margin_left - hspace * (cols - 1)) / cols if h_axes < 0: - warnings.warn('Tight layout not applied. ' - 'tight_layout cannot make axes width small enough ' - 'to accommodate all axes decorations') + cbook._warn_external('Tight layout not applied. tight_layout ' + 'cannot make axes width small enough to ' + 'accommodate all axes decorations') return None else: kwargs["wspace"] = hspace / h_axes @@ -208,9 +207,9 @@ def auto_adjust_subplotpars( + vpad_inches / fig_height_inch) v_axes = (1 - margin_top - margin_bottom - vspace * (rows - 1)) / rows if v_axes < 0: - warnings.warn('Tight layout not applied. ' - 'tight_layout cannot make axes height small enough ' - 'to accommodate all axes decorations') + cbook._warn_external('Tight layout not applied. tight_layout ' + 'cannot make axes height small enough to ' + 'accommodate all axes decorations') return None else: kwargs["hspace"] = vspace / v_axes @@ -228,7 +227,7 @@ def get_renderer(fig): renderer = canvas.get_renderer() else: # not sure if this can happen - warnings.warn("tight_layout : falling back to Agg renderer") + cbook._warn_external("tight_layout : falling back to Agg renderer") from matplotlib.backends.backend_agg import FigureCanvasAgg canvas = FigureCanvasAgg(fig) renderer = canvas.get_renderer() @@ -337,14 +336,14 @@ def get_tight_layout_figure(fig, axes_list, subplotspec_list, renderer, div_row, mod_row = divmod(max_nrows, rows) div_col, mod_col = divmod(max_ncols, cols) if mod_row != 0: - warnings.warn('tight_layout not applied: ' - 'number of rows in subplot specifications must' - 'be multiples of one another.') + cbook._warn_external('tight_layout not applied: number of rows ' + 'in subplot specifications must be ' + 'multiples of one another.') return {} if mod_col != 0: - warnings.warn('tight_layout not applied: ' - 'number of columns in subplot specifications must' - 'be multiples of one another.') + cbook._warn_external('tight_layout not applied: number of ' + 'columns in subplot specifications must be ' + 'multiples of one another.') return {} rowNum1, colNum1 = divmod(num1, cols) diff --git a/lib/matplotlib/transforms.py b/lib/matplotlib/transforms.py index 0272dca704f6..af84319d5792 100644 --- a/lib/matplotlib/transforms.py +++ b/lib/matplotlib/transforms.py @@ -34,12 +34,12 @@ # done so that `nan`s are propagated, instead of being silently dropped. import re -import warnings import weakref import numpy as np from numpy.linalg import inv +from matplotlib import cbook from matplotlib._path import ( affine_transform, count_bboxes_overlapping_bbox, update_path_extents) from .path import Path @@ -266,11 +266,11 @@ class BboxBase(TransformNode): if DEBUG: def _check(points): if isinstance(points, np.ma.MaskedArray): - warnings.warn("Bbox bounds are a masked array.") + cbook._warn_external("Bbox bounds are a masked array.") points = np.asarray(points) if (points[1, 0] - points[0, 0] == 0 or points[1, 1] - points[0, 1] == 0): - warnings.warn("Singular Bbox.") + cbook._warn_external("Singular Bbox.") _check = staticmethod(_check) def frozen(self): @@ -1843,7 +1843,7 @@ def transform_affine(self, points): # points to an array in the first place. If we can use # more arrays upstream, that should help here. if not isinstance(points, (np.ma.MaskedArray, np.ndarray)): - warnings.warn( + cbook._warn_external( ('A non-numpy array of type %s was passed in for ' + 'transformation. Please correct this.') % type(points)) diff --git a/lib/matplotlib/tri/triinterpolate.py b/lib/matplotlib/tri/triinterpolate.py index bc4fe84a9935..070bd85700c9 100644 --- a/lib/matplotlib/tri/triinterpolate.py +++ b/lib/matplotlib/tri/triinterpolate.py @@ -2,10 +2,9 @@ Interpolation inside triangular grids. """ -import warnings - import numpy as np +from matplotlib import cbook from matplotlib.tri import Triangulation from matplotlib.tri.trifinder import TriFinder from matplotlib.tri.tritools import TriAnalyzer @@ -1214,9 +1213,10 @@ def compute_dz(self): err0 = np.linalg.norm(Kff_coo.dot(Uf0) - Ff) if err0 < err: # Maybe a good occasion to raise a warning here ? - warnings.warn("In TriCubicInterpolator initialization, PCG sparse" - " solver did not converge after 1000 iterations. " - "`geom` approximation is used instead of `min_E`") + cbook._warn_external("In TriCubicInterpolator initialization, " + "PCG sparse solver did not converge after " + "1000 iterations. `geom` approximation is " + "used instead of `min_E`") Uf = Uf0 # Building dz from Uf diff --git a/lib/mpl_toolkits/axes_grid1/inset_locator.py b/lib/mpl_toolkits/axes_grid1/inset_locator.py index d458bc0e5e0d..19002aacab26 100644 --- a/lib/mpl_toolkits/axes_grid1/inset_locator.py +++ b/lib/mpl_toolkits/axes_grid1/inset_locator.py @@ -2,8 +2,7 @@ A collection of functions and objects for creating or placing inset axes. """ -import warnings -from matplotlib import docstring +from matplotlib import cbook, docstring from matplotlib.offsetbox import AnchoredOffsetbox from matplotlib.patches import Patch, Rectangle from matplotlib.path import Path @@ -504,9 +503,10 @@ def inset_axes(parent_axes, width, height, loc='upper right', if bbox_transform in [parent_axes.transAxes, parent_axes.figure.transFigure]: if bbox_to_anchor is None: - warnings.warn("Using the axes or figure transform requires a " - "bounding box in the respective coordinates. " - "Using bbox_to_anchor=(0,0,1,1) now.") + cbook._warn_external("Using the axes or figure transform " + "requires a bounding box in the respective " + "coordinates. " + "Using bbox_to_anchor=(0,0,1,1) now.") bbox_to_anchor = (0, 0, 1, 1) if bbox_to_anchor is None: diff --git a/lib/mpl_toolkits/axisartist/axislines.py b/lib/mpl_toolkits/axisartist/axislines.py index 010758f75b3c..bd01304e86ad 100644 --- a/lib/mpl_toolkits/axisartist/axislines.py +++ b/lib/mpl_toolkits/axisartist/axislines.py @@ -40,10 +40,9 @@ from the axis as some gridlines can never pass any axis. """ -import warnings - import numpy as np +from matplotlib import cbook from matplotlib import rcParams import matplotlib.artist as martist import matplotlib.axes as maxes @@ -427,7 +426,7 @@ def new_fixed_axis(self, loc, ): if axes is None: - warnings.warn( + cbook._warn_external( "'new_fixed_axis' explicitly requires the axes keyword.") axes = self.axes @@ -447,7 +446,7 @@ def new_floating_axis(self, nth_coord, value, ): if axes is None: - warnings.warn( + cbook._warn_external( "'new_floating_axis' explicitly requires the axes keyword.") axes = self.axes diff --git a/lib/mpl_toolkits/axisartist/clip_path.py b/lib/mpl_toolkits/axisartist/clip_path.py index a3fa76be630a..8d2dcc699364 100644 --- a/lib/mpl_toolkits/axisartist/clip_path.py +++ b/lib/mpl_toolkits/axisartist/clip_path.py @@ -1,12 +1,12 @@ import numpy as np from math import degrees +from matplotlib import cbook import math -import warnings def atan2(dy, dx): if dx == 0 and dy == 0: - warnings.warn("dx and dy is 0") + cbook._warn_external("dx and dy are 0") return 0 else: return math.atan2(dy, dx) diff --git a/lib/mpl_toolkits/mplot3d/axes3d.py b/lib/mpl_toolkits/mplot3d/axes3d.py index c72ebde234e9..dc79509883db 100644 --- a/lib/mpl_toolkits/mplot3d/axes3d.py +++ b/lib/mpl_toolkits/mplot3d/axes3d.py @@ -9,10 +9,9 @@ Module containing Axes3D, an object which can plot 3D objects on a 2D matplotlib figure. """ -from functools import reduce from collections import defaultdict +from functools import reduce import math -import warnings import numpy as np @@ -439,7 +438,8 @@ def margins(self, *margins, x=None, y=None, z=None, tight=True): if x is None and y is None and z is None: if tight is not True: - warnings.warn('ignoring tight=%r in get mode' % (tight,)) + cbook._warn_external( + 'ignoring tight=%r in get mode' % (tight,)) return self._xmargin, self._ymargin, self._zmargin if x is not None: @@ -634,9 +634,10 @@ def set_xlim3d(self, left=None, right=None, emit=True, auto=False, right = old_right if left == right: - warnings.warn(('Attempting to set identical left==right results\n' - 'in singular transformations; automatically expanding.\n' - 'left=%s, right=%s') % (left, right)) + cbook._warn_external( + ('Attempting to set identical left==right results\n' + 'in singular transformations; automatically expanding.\n' + 'left=%s, right=%s') % (left, right)) left, right = mtransforms.nonsingular(left, right, increasing=False) left, right = self.xaxis.limit_range_for_scale(left, right) self.xy_viewLim.intervalx = (left, right) @@ -692,9 +693,10 @@ def set_ylim3d(self, bottom=None, top=None, emit=True, auto=False, top = old_top if top == bottom: - warnings.warn(('Attempting to set identical bottom==top results\n' - 'in singular transformations; automatically expanding.\n' - 'bottom=%s, top=%s') % (bottom, top)) + cbook._warn_external( + ('Attempting to set identical bottom==top results\n' + 'in singular transformations; automatically expanding.\n' + 'bottom=%s, top=%s') % (bottom, top)) bottom, top = mtransforms.nonsingular(bottom, top, increasing=False) bottom, top = self.yaxis.limit_range_for_scale(bottom, top) self.xy_viewLim.intervaly = (bottom, top) @@ -750,9 +752,10 @@ def set_zlim3d(self, bottom=None, top=None, emit=True, auto=False, top = old_top if top == bottom: - warnings.warn(('Attempting to set identical bottom==top results\n' - 'in singular transformations; automatically expanding.\n' - 'bottom=%s, top=%s') % (bottom, top)) + cbook._warn_external( + ('Attempting to set identical bottom==top results\n' + 'in singular transformations; automatically expanding.\n' + 'bottom=%s, top=%s') % (bottom, top)) bottom, top = mtransforms.nonsingular(bottom, top, increasing=False) bottom, top = self.zaxis.limit_range_for_scale(bottom, top) self.zz_viewLim.intervalx = (bottom, top) @@ -1074,9 +1077,9 @@ def mouse_init(self, rotate_btn=1, zoom_btn=3): c3 = canv.mpl_connect('button_release_event', self._button_release) self._cids = [c1, c2, c3] else: - warnings.warn( - "Axes3D.figure.canvas is 'None', mouse rotation disabled. " - "Set canvas then call Axes3D.mouse_init().") + cbook._warn_external("Axes3D.figure.canvas is 'None', mouse " + "rotation disabled. Set canvas then call " + "Axes3D.mouse_init().") # coerce scalars into array-like, then convert into # a regular list to avoid comparisons against None diff --git a/setupext.py b/setupext.py index ba74045077f8..0d558302678b 100644 --- a/setupext.py +++ b/setupext.py @@ -5,6 +5,7 @@ import glob import hashlib import importlib +import logging import os import pathlib import platform @@ -14,11 +15,12 @@ import tarfile import textwrap import urllib.request -import warnings import setuptools import versioneer +_log = logging.getLogger(__name__) + def _get_xdg_cache_dir(): """ @@ -765,7 +767,7 @@ def include_dirs_hook(): ext.include_dirs.append(numpy.get_include()) if not has_include_file( ext.include_dirs, os.path.join("numpy", "arrayobject.h")): - warnings.warn( + _log.warning( "The C headers for numpy could not be found. " "You may need to install the development package")