From 844877c141179a9c799e1cc93dab0757fae3d2ca Mon Sep 17 00:00:00 2001 From: Jody Klymak Date: Sat, 7 Oct 2017 19:38:07 -0700 Subject: [PATCH] Change verbose to standard logging library Change verbose to standard logging library PEP8 fixes and formatting of log messages @anntzer PEP8 fixes and formatting of log messages @anntzer Small fixes as suggested by @aantzer and @tacaswell Documentation Fix on merge Number small fixes Small fix for docs Small fix for error in animate.py fixed import order and small doc fix Small doc fix Changed log. to _log. Fix on merge Number small fixes Small fix for docs Small fix for error in animate.py fixed import order and small doc fix Small doc fix Changed log. to _log. Changed log. to _log. fixed fonts gah gah gah gah gah gah PEP8 doc fix revert _base.py fix missing _log Fixes for @efiring Fixes for @anntzer minor Doc link fixes @anntzer Small doc change Many small changes, thanks @QuLogic and @anntzer Link error docs --- doc/devel/contributing.rst | 66 ++++++++- doc/faq/troubleshooting_faq.rst | 42 ++++-- .../next_whats_new/2017_10_10_logging.rst | 24 ++++ lib/matplotlib/__init__.py | 128 +++++++++++++++--- lib/matplotlib/animation.py | 88 ++++++------ lib/matplotlib/backends/__init__.py | 5 +- lib/matplotlib/backends/backend_agg.py | 2 +- lib/matplotlib/backends/backend_gtk.py | 14 +- lib/matplotlib/backends/backend_gtk3.py | 10 +- lib/matplotlib/backends/backend_pdf.py | 23 ++-- lib/matplotlib/backends/backend_ps.py | 40 +++--- lib/matplotlib/backends/backend_svg.py | 7 +- lib/matplotlib/backends/backend_tkagg.py | 7 +- lib/matplotlib/backends/qt_compat.py | 11 +- lib/matplotlib/blocking_input.py | 15 +- lib/matplotlib/dviread.py | 60 ++++---- lib/matplotlib/figure.py | 3 + lib/matplotlib/finance.py | 11 +- lib/matplotlib/font_manager.py | 32 ++--- lib/matplotlib/sankey.py | 21 +-- lib/matplotlib/tests/test_backend_ps.py | 1 - lib/matplotlib/texmanager.py | 47 +++---- lib/matplotlib/text.py | 9 +- matplotlibrc.template | 20 --- 24 files changed, 436 insertions(+), 250 deletions(-) create mode 100644 doc/users/next_whats_new/2017_10_10_logging.rst diff --git a/doc/devel/contributing.rst b/doc/devel/contributing.rst index 74449565fd94..e77e667b313a 100644 --- a/doc/devel/contributing.rst +++ b/doc/devel/contributing.rst @@ -171,7 +171,7 @@ repository `__ on GitHub, then submit a "pull request" (PR). The best practices for using GitHub to make PRs to Matplotlib are -documented in the :ref:`development-workflow` section. +documented in the :ref:`development-workflow` section. A brief overview is: @@ -437,6 +437,70 @@ forced to use ``**kwargs``. An example is elif len(args) == 1: ...etc... +.. _using_logging: + +Using logging for debug messages +-------------------------------- + +Matplotlib uses the standard python `logging` library to write verbose +warnings, information, and +debug messages. Please use it! In all those places you write :func:`print()` +statements to do your debugging, try using :func:`log.debug()` instead! + + +To include `logging` in your module, at the top of the module, you need to +``import logging``. Then calls in your code like:: + + _log = logging.getLogger(__name__) # right after the imports + + # code + # more code + _log.info('Here is some information') + _log.debug('Here is some more detailed information') + +will log to a logger named ``matplotlib.yourmodulename``. + +If an end-user of Matplotlib sets up `logging` to display at levels +more verbose than `logger.WARNING` in their code as follows:: + + import logging + fmt = '%(name)s:%(lineno)5d - %(levelname)s - %(message)s' + logging.basicConfig(level=logging.DEBUG, format=fmt) + import matplotlib.pyplot as plt + +Then they will receive messages like:: + + matplotlib.backends: 89 - INFO - backend MacOSX version unknown + matplotlib.yourmodulename: 347 - INFO - Here is some information + matplotlib.yourmodulename: 348 - DEBUG - Here is some more detailed information + +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` be used for things the user must change to stop +the warning, whereas `logging.warning` can be more persistent. + +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 set +``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. + .. _custom_backend: Developing a new backend diff --git a/doc/faq/troubleshooting_faq.rst b/doc/faq/troubleshooting_faq.rst index 7074147c142b..3ceb9a578468 100644 --- a/doc/faq/troubleshooting_faq.rst +++ b/doc/faq/troubleshooting_faq.rst @@ -9,10 +9,10 @@ Troubleshooting .. _matplotlib-version: -Obtaining matplotlib version +Obtaining Matplotlib version ============================ -To find out your matplotlib version number, import it and print the +To find out your Matplotlib version number, import it and print the ``__version__`` attribute:: >>> import matplotlib @@ -25,7 +25,7 @@ To find out your matplotlib version number, import it and print the :file:`matplotlib` install location =================================== -You can find what directory matplotlib is installed in by importing it +You can find what directory Matplotlib is installed in by importing it and printing the ``__file__`` attribute:: >>> import matplotlib @@ -37,7 +37,7 @@ and printing the ``__file__`` attribute:: :file:`matplotlib` configuration and cache directory locations ============================================================== -Each user has a matplotlib configuration directory which may contain a +Each user has a Matplotlib configuration directory which may contain a :ref:`matplotlibrc ` file. To locate your :file:`matplotlib/` configuration directory, use :func:`matplotlib.get_configdir`:: @@ -79,7 +79,7 @@ directory and the cache directory. Getting help ============ -There are a number of good resources for getting help with matplotlib. +There are a number of good resources for getting help with Matplotlib. There is a good chance your question has already been asked: - The `mailing list archive `_. @@ -114,11 +114,35 @@ provide the following information in your e-mail to the `mailing list the error will help you find a bug in *your* code that is causing the problem. -* You can get very helpful debugging output from matlotlib by running your - script with a ``verbose-helpful`` or ``--verbose-debug`` flags and posting - the verbose output the lists:: +* You can get helpful debugging output from Matlotlib by using the `logging` + library in your code and posting the verbose output to the lists. For a + command-line version of this, try:: - python simple_plot.py --verbose-helpful > output.txt + python -c "from logging import *; basicConfig(level=DEBUG); from pylab import *; plot(); show()" + + + If you want to put the debugging hooks in your own code, then the + most simple way to do so is to insert the following *before* any calls + to ``import matplotlib``:: + + import logging + logging.basicConfig(level=logging.DEBUG) + + import matplotlib.pyplot as plt + + Note that if you want to use `logging` in your own code, but do not + want verbose Matplotlib output, you can set the logging level + for Matplotlib independently:: + + import logging + # set DEBUG for everything + logging.basicConfig(level=logging.DEBUG) + logger = logging.getLogger('matplotlib') + # set WARNING for Matplotlib + logger.setLevel(logging.WARNING) + + The `logging` module is very flexible, and can be a valuable tool in chasing + down errors. If you compiled Matplotlib yourself, please also provide: diff --git a/doc/users/next_whats_new/2017_10_10_logging.rst b/doc/users/next_whats_new/2017_10_10_logging.rst new file mode 100644 index 000000000000..8013f2f165b5 --- /dev/null +++ b/doc/users/next_whats_new/2017_10_10_logging.rst @@ -0,0 +1,24 @@ +Logging for debug output +------------------------ + +Matplotlib has in the past (sporadically) used an internal +verbose-output reporter. This version converts those calls to using the +standard python `logging` library. + +Support for the old ``rcParams`` ``verbose.level`` and ``verbose.fileo`` is +dropped. + +The command-line options ``--verbose-helpful`` and ``--verbose-debug`` are +still accepted, but deprecated. They are now equivalent to setting +``logging.INFO`` and ``logging.DEBUG``. + +The logger's root name is ``matplotlib`` and can be accessed from programs +as:: + + import logging + mlog = logging.getLogger('matplotlib') + +Instructions for basic usage are in :ref:`troubleshooting-faq` and for +developers in :ref:`contributing`. + +.. _logging: https://docs.python.org/3/library/logging.html diff --git a/lib/matplotlib/__init__.py b/lib/matplotlib/__init__.py index 659d2a2ea846..b3935f75a4a7 100644 --- a/lib/matplotlib/__init__.py +++ b/lib/matplotlib/__init__.py @@ -113,6 +113,7 @@ import inspect import itertools import locale +import logging import os import re import sys @@ -137,6 +138,8 @@ __version__ = str(get_versions()['version']) del get_versions +_log = logging.getLogger(__name__) + __version__numpy__ = str('1.7.1') # minimum required numpy version __bibtex__ = r"""@Article{Hunter:2007, @@ -160,6 +163,9 @@ if not (_python27 or _python34): raise ImportError("Matplotlib requires Python 2.7 or 3.4 or later") +if _python27: + _log.addHandler(logging.NullHandler()) + def compare_versions(a, b): "return True if a is greater than or equal to b" @@ -215,7 +221,75 @@ def _is_writable_dir(p): """ return os.access(p, os.W_OK) and os.path.isdir(p) +_verbose_msg = """\ +Command line argument --verbose-LEVEL is deprecated. +This functionality is now provided by the standard +python logging library. To get more (or less) logging output: + import logging + logger = logging.getLogger('matplotlib') + logger.set_level(logging.INFO)""" + + +def _set_logger_verbose_level(level_str='silent', file_str='sys.stdout'): + """ + Use a --verbose-LEVEL level to set the logging level: + + """ + levelmap = {'silent': logging.WARNING, 'helpful': logging.INFO, + 'debug': logging.DEBUG, 'debug-annoying': logging.DEBUG, + 'info': logging.INFO, 'warning': logging.WARNING} + # Check that current state of logger isn't already more verbose + # than the requested level. If it is more verbose, then leave more + # verbose. + newlev = levelmap[level_str] + oldlev = _log.getEffectiveLevel() + if newlev < oldlev: + _log.setLevel(newlev) + std = { + 'sys.stdout': sys.stdout, + 'sys.stderr': sys.stderr, + } + if file_str in std: + fileo = std[file_str] + else: + fileo = sys.stdout + try: + 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)) + console = logging.StreamHandler(fileo) + console.setLevel(newlev) + _log.addHandler(console) + + +def _parse_commandline(): + """ + Check for --verbose-LEVEL type command line arguments and + set logging level appropriately. + """ + levels = ('silent', 'helpful', 'debug', 'debug-annoying', + 'info', 'warning') + + for arg in sys.argv[1:]: + # cast to str because we are using unicode_literals, + # and argv is always str + + if arg.startswith(str('--verbose-')): + level_str = arg[10:] + # If it doesn't match one of ours, then don't even + # bother noting it, we are just a 3rd-party library + # to somebody else's script. + if level_str in levels: + _set_logger_verbose_level(level_str) + +_parse_commandline() + + +@cbook.deprecated("2.2", message=_verbose_msg) class Verbose(object): """ A class to handle reporting. Set the fileo attribute to any file @@ -311,7 +385,29 @@ def ge(self, level): return self.vald[self.level] >= self.vald[level] -verbose = Verbose() +def _wrap(fmt, func, level='INFO', always=True): + """ + return a callable function that wraps func and reports its + output through logger + + if always is True, the report will occur on every function + call; otherwise only on the first time the function is called + """ + assert callable(func) + + def wrapper(*args, **kwargs): + ret = func(*args, **kwargs) + + if (always or not wrapper._spoke): + lvl = logging.getLevelName(level.upper()) + _log.log(lvl, fmt % ret) + spoke = True + if not wrapper._spoke: + wrapper._spoke = spoke + return ret + wrapper._spoke = False + wrapper.__doc__ = func.__doc__ + return wrapper def checkdep_dvipng(): @@ -512,7 +608,7 @@ def _create_tmp_config_dir(): return configdir -get_home = verbose.wrap('$HOME=%s', _get_home, always=False) +get_home = _wrap('$HOME=%s', _get_home, always=False) def _get_xdg_config_dir(): @@ -601,7 +697,7 @@ def _get_configdir(): """ return _get_config_or_cache_dir(_get_xdg_config_dir()) -get_configdir = verbose.wrap('CONFIGDIR=%s', _get_configdir, always=False) +get_configdir = _wrap('CONFIGDIR=%s', _get_configdir, always=False) def _get_cachedir(): @@ -613,7 +709,7 @@ def _get_cachedir(): """ return _get_config_or_cache_dir(_get_xdg_cache_dir()) -get_cachedir = verbose.wrap('CACHEDIR=%s', _get_cachedir, always=False) +get_cachedir = _wrap('CACHEDIR=%s', _get_cachedir, always=False) def _decode_filesystem_path(path): @@ -671,8 +767,8 @@ def _get_data_path_cached(): defaultParams['datapath'][0] = _get_data_path() return defaultParams['datapath'][0] -get_data_path = verbose.wrap('matplotlib data path %s', _get_data_path_cached, - always=False) +get_data_path = _wrap('matplotlib data path %s', _get_data_path_cached, + always=False) def get_py2exe_datafiles(): @@ -1035,22 +1131,18 @@ def rc_params_from_file(fname, fail_on_error=False, use_default_template=True): if key not in _all_deprecated]) config.update(config_from_file) - verbose.set_level(config['verbose.level']) - verbose.set_fileo(config['verbose.fileo']) - if config['datapath'] is None: config['datapath'] = get_data_path() if "".join(config['text.latex.preamble']): - verbose.report(""" + _log.info(""" ***************************************************************** You have the following UNSUPPORTED LaTeX preamble customizations: %s Please do not ask for support with these customizations active. ***************************************************************** -""" % '\n'.join(config['text.latex.preamble']), 'helpful') - - verbose.report('loaded rc file %s' % fname) +""", '\n'.join(config['text.latex.preamble'])) + _log.info('loaded rc file %s', fname) return config @@ -1736,9 +1828,7 @@ def inner(ax, *args, **kwargs): return inner return param - -verbose.report('matplotlib version %s' % __version__) -verbose.report('verbose.level %s' % verbose.level) -verbose.report('interactive is %s' % is_interactive()) -verbose.report('platform is %s' % sys.platform) -verbose.report('loaded modules: %s' % list(sys.modules), 'debug') +_log.info('matplotlib version %s', __version__) +_log.info('interactive is %s', is_interactive()) +_log.info('platform is %s', sys.platform) +_log.debug('loaded modules: %s', list(sys.modules)) diff --git a/lib/matplotlib/animation.py b/lib/matplotlib/animation.py index 8cd6b410b4f3..ddd337dccd84 100644 --- a/lib/matplotlib/animation.py +++ b/lib/matplotlib/animation.py @@ -39,17 +39,20 @@ import tempfile import uuid import warnings +import logging + from matplotlib._animation_data import (DISPLAY_TEMPLATE, INCLUDED_FRAMES, JS_INCLUDE) from matplotlib.cbook import iterable, deprecated from matplotlib.compat import subprocess -from matplotlib import verbose from matplotlib import rcParams, rcParamsDefault, rc_context if sys.version_info < (3, 0): from cStringIO import StringIO as InMemory else: from io import BytesIO as InMemory +_log = logging.getLogger(__name__) + # Process creation flag for subprocess to prevent it raising a terminal # window. See for example: # https://stackoverflow.com/questions/24130623/using-python-subprocess-popen-cant-prevent-exe-stopped-working-prompt @@ -319,13 +322,11 @@ def _adjust_frame_size(self): w, h = adjusted_figsize(wo, ho, self.dpi, 2) if not (wo, ho) == (w, h): self.fig.set_size_inches(w, h, forward=True) - verbose.report('figure size (inches) has been adjusted ' - 'from %s x %s to %s x %s' % (wo, ho, w, h), - level='helpful') + _log.info('figure size (inches) has been adjusted ' + 'from %s x %s to %s x %s', wo, ho, w, h) else: w, h = self.fig.get_size_inches() - verbose.report('frame size in pixels is %s x %s' % self.frame_size, - level='debug') + _log.debug('frame size in pixels is %s x %s' % self.frame_size) return w, h def setup(self, fig, outfile, dpi=None): @@ -358,11 +359,8 @@ def _run(self): # movie file. *args* returns the sequence of command line arguments # from a few configuration options. command = self._args() - if verbose.ge('debug'): - output = sys.stdout - else: - output = subprocess.PIPE - verbose.report('MovieWriter.run: running command: %s' % + output = subprocess.PIPE + _log.info('MovieWriter.run: running command: %s', ' '.join(command)) self._proc = subprocess.Popen(command, shell=False, stdout=output, stderr=output, @@ -380,8 +378,7 @@ def grab_frame(self, **savefig_kwargs): All keyword arguments in savefig_kwargs are passed on to the `savefig` command that saves the figure. ''' - verbose.report('MovieWriter.grab_frame: Grabbing frame.', - level='debug') + _log.debug('MovieWriter.grab_frame: Grabbing frame.') try: # re-adjust the figure size in case it has been changed by the # user. We must ensure that every frame is the same size or @@ -393,12 +390,12 @@ def grab_frame(self, **savefig_kwargs): dpi=self.dpi, **savefig_kwargs) except (RuntimeError, IOError) as e: out, err = self._proc.communicate() - verbose.report('MovieWriter -- Error ' - 'running proc:\n%s\n%s' % (out, err), - level='helpful') + _log.info('MovieWriter -- Error ' + 'running proc:\n%s\n%s' % (out, err)) raise IOError('Error saving animation to file (cause: {0}) ' 'Stdout: {1} StdError: {2}. It may help to re-run ' - 'with --verbose-debug.'.format(e, out, err)) + 'with logging level set to ' + 'DEBUG.'.format(e, out, err)) def _frame_sink(self): '''Returns the place to which frames should be written.''' @@ -412,10 +409,10 @@ def cleanup(self): '''Clean-up and collect the process used to write the movie file.''' out, err = self._proc.communicate() self._frame_sink().close() - verbose.report('MovieWriter -- ' - 'Command stdout:\n%s' % out, level='debug') - verbose.report('MovieWriter -- ' - 'Command stderr:\n%s' % err, level='debug') + _log.debug('MovieWriter -- ' + 'Command stdout:\n%s' % out) + _log.debug('MovieWriter -- ' + 'Command stderr:\n%s' % err) @classmethod def bin_path(cls): @@ -524,10 +521,9 @@ def _frame_sink(self): # Save the filename so we can delete it later if necessary self._temp_names.append(fname) - verbose.report( + _log.debug( 'FileMovieWriter.frame_sink: saving frame %d to fname=%s' % - (self._frame_counter, fname), - level='debug') + (self._frame_counter, fname)) self._frame_counter += 1 # Ensures each created name is 'unique' # This file returned here will be closed once it's used by savefig() @@ -541,8 +537,7 @@ def grab_frame(self, **savefig_kwargs): command that saves the figure. ''' # Overloaded to explicitly close temp file. - verbose.report('MovieWriter.grab_frame: Grabbing frame.', - level='debug') + _log.debug('MovieWriter.grab_frame: Grabbing frame.') try: # Tell the figure to save its data to the sink, using the # frame format and dpi. @@ -552,9 +547,8 @@ def grab_frame(self, **savefig_kwargs): except RuntimeError: out, err = self._proc.communicate() - verbose.report('MovieWriter -- Error ' - 'running proc:\n%s\n%s' % (out, - err), level='helpful') + _log.info('MovieWriter -- Error ' + 'running proc:\n%s\n%s' % (out, err)) raise def finish(self): @@ -569,15 +563,12 @@ def finish(self): try: stdout = [s.decode() for s in self._proc._stdout_buff] stderr = [s.decode() for s in self._proc._stderr_buff] - verbose.report("MovieWriter.finish: stdout: %s" % stdout, - level='helpful') - verbose.report("MovieWriter.finish: stderr: %s" % stderr, - level='helpful') + _log.info("MovieWriter.finish: stdout: %s", stdout) + _log.info("MovieWriter.finish: stderr: %s", stderr) except Exception as e: pass msg = ('Error creating movie, return code: ' + - str(self._proc.returncode) + - ' Try setting mpl.verbose.set_level("helpful")') + str(self._proc.returncode)) raise RuntimeError(msg) def cleanup(self): @@ -585,10 +576,9 @@ def cleanup(self): # Delete temporary files if self.clear_temp: - verbose.report( + _log.debug( 'MovieWriter: clearing temporary fnames=%s' % - str(self._temp_names), - level='debug') + str(self._temp_names)) for fname in self._temp_names: os.remove(fname) @@ -650,7 +640,8 @@ def _args(self): '-s', '%dx%d' % self.frame_size, '-pix_fmt', self.frame_format, '-r', str(self.fps)] # Logging is quieted because subprocess.PIPE has limited buffer size. - if not verbose.ge('debug'): + + if (_log.getEffectiveLevel() < logging.DEBUG): args += ['-loglevel', 'quiet'] args += ['-i', 'pipe:'] + self.output_args return args @@ -933,7 +924,7 @@ def __init__(self, fps=30, codec=None, bitrate=None, extra_args=None, if self.default_mode not in ['loop', 'once', 'reflect']: self.default_mode = 'loop' - warnings.warn("unrecognized default_mode: using 'loop'") + _log.warning("unrecognized default_mode: using 'loop'") self._saved_frames = [] self._total_bytes = 0 @@ -969,7 +960,7 @@ def grab_frame(self, **savefig_kwargs): imgdata64 = encodebytes(f.getvalue()).decode('ascii') self._total_bytes += len(imgdata64) if self._total_bytes >= self._bytes_limit: - warnings.warn("Animation size has reached {0._total_bytes} " + _log.warning("Animation size has reached {0._total_bytes} " "bytes, exceeding the limit of " "{0._bytes_limit}. If you're sure you want " "a larger animation embedded, set the " @@ -1220,7 +1211,7 @@ class to use, such as 'ffmpeg' or 'mencoder'. If ``None``, extra_args=extra_args, metadata=metadata) else: - warnings.warn("MovieWriter %s unavailable" % writer) + _log.warning("MovieWriter %s unavailable" % writer) try: writer = writers[writers.list()[0]](fps, codec, bitrate, @@ -1230,12 +1221,10 @@ class to use, such as 'ffmpeg' or 'mencoder'. If ``None``, raise ValueError("Cannot save animation: no writers are " "available. Please install " "ffmpeg to save animations.") - - verbose.report('Animation.save using %s' % type(writer), - level='helpful') + _log.info('Animation.save using %s', type(writer)) if 'bbox_inches' in savefig_kwargs: - warnings.warn("Warning: discarding the 'bbox_inches' argument in " + _log.warning("Warning: discarding the 'bbox_inches' argument in " "'savefig_kwargs' as it may cause frame size " "to vary, which is inappropriate for animation.") savefig_kwargs.pop('bbox_inches') @@ -1248,10 +1237,9 @@ class to use, such as 'ffmpeg' or 'mencoder'. If ``None``, # allow for this non-existent use case or find a way to make it work. with rc_context(): if rcParams['savefig.bbox'] == 'tight': - verbose.report("Disabling savefig.bbox = 'tight', as it " + _log.info("Disabling savefig.bbox = 'tight', as it " "may cause frame size to vary, which " - "is inappropriate for animation.", - level='helpful') + "is inappropriate for animation.") rcParams['savefig.bbox'] = None with writer.saving(self._fig, filename, dpi): for anim in all_anim: @@ -1422,7 +1410,7 @@ def to_html5_video(self, embed_limit=None): vid64 = encodebytes(video.read()) vid_len = len(vid64) if vid_len >= embed_limit: - warnings.warn("Animation movie is {} bytes, exceeding " + _log.warning("Animation movie is {} bytes, exceeding " "the limit of {}. If you're sure you want a " "large animation embedded, set the " "animation.embed_limit rc parameter to a " diff --git a/lib/matplotlib/backends/__init__.py b/lib/matplotlib/backends/__init__.py index c2b29d474d8d..f74eabb95cbc 100644 --- a/lib/matplotlib/backends/__init__.py +++ b/lib/matplotlib/backends/__init__.py @@ -7,7 +7,9 @@ import inspect import traceback import warnings +import logging +_log = logging.getLogger(__name__) backend = matplotlib.get_backend() _backend_loading_tb = "".join( @@ -85,8 +87,7 @@ def do_nothing(*args, **kwargs): draw_if_interactive = getattr(backend_mod, 'draw_if_interactive', do_nothing) - matplotlib.verbose.report('backend %s version %s' % - (name, backend_version)) + _log.info('backend %s version %s' % (name, backend_version)) # need to keep a global reference to the backend for compatibility # reasons. See https://github.com/matplotlib/matplotlib/issues/6092 diff --git a/lib/matplotlib/backends/backend_agg.py b/lib/matplotlib/backends/backend_agg.py index fc5a2866f438..1d867fea8914 100644 --- a/lib/matplotlib/backends/backend_agg.py +++ b/lib/matplotlib/backends/backend_agg.py @@ -28,7 +28,7 @@ import numpy as np from collections import OrderedDict from math import radians, cos, sin -from matplotlib import verbose, rcParams, __version__ +from matplotlib import rcParams, __version__ from matplotlib.backend_bases import ( _Backend, FigureCanvasBase, FigureManagerBase, RendererBase, cursors) from matplotlib.figure import Figure diff --git a/lib/matplotlib/backends/backend_gtk.py b/lib/matplotlib/backends/backend_gtk.py index ec2d3a6a609d..ba62b1c4e208 100644 --- a/lib/matplotlib/backends/backend_gtk.py +++ b/lib/matplotlib/backends/backend_gtk.py @@ -3,7 +3,10 @@ import six -import os, sys, warnings +import logging +import os +import sys +import warnings if six.PY3: warnings.warn( @@ -38,7 +41,9 @@ from matplotlib.widgets import SubplotTool from matplotlib import ( - cbook, colors as mcolors, lines, markers, rcParams, verbose) + cbook, colors as mcolors, lines, markers, rcParams) + +_log = logging.getLogger(__name__) backend_version = "%d.%d.%d" % gtk.pygtk_version @@ -512,7 +517,8 @@ def __init__(self, canvas, num): # all, so I am not sure how to catch it. I am unhappy # diong a blanket catch here, but an not sure what a # better way is - JDH - verbose.report('Could not load matplotlib icon: %s' % sys.exc_info()[1]) + _log.info('Could not load matplotlib ' + 'icon: %s', sys.exc_info()[1]) self.vbox = gtk.VBox() self.window.add(self.vbox) @@ -997,7 +1003,7 @@ def on_dialog_lineprops_cancelbutton_clicked(self, button): window_icon = os.path.join(rcParams['datapath'], 'images', icon_filename) except: window_icon = None - verbose.report('Could not load matplotlib icon: %s' % sys.exc_info()[1]) + _log.info('Could not load matplotlib icon: %s', sys.exc_info()[1]) def error_msg_gtk(msg, parent=None): if parent is not None: # find the toplevel gtk.Window diff --git a/lib/matplotlib/backends/backend_gtk3.py b/lib/matplotlib/backends/backend_gtk3.py index 16800bcbca52..0500f52c2bf9 100644 --- a/lib/matplotlib/backends/backend_gtk3.py +++ b/lib/matplotlib/backends/backend_gtk3.py @@ -3,7 +3,9 @@ import six -import os, sys +import logging +import os +import sys try: import gi @@ -37,7 +39,9 @@ from matplotlib.widgets import SubplotTool from matplotlib import ( - backend_tools, cbook, colors as mcolors, lines, verbose, rcParams) + backend_tools, cbook, colors as mcolors, lines, rcParams) + +_log = logging.getLogger(__name__) backend_version = "%s.%s.%s" % ( Gtk.get_major_version(), Gtk.get_micro_version(), Gtk.get_minor_version()) @@ -366,7 +370,7 @@ def __init__(self, canvas, num): # all, so I am not sure how to catch it. I am unhappy # doing a blanket catch here, but am not sure what a # better way is - JDH - verbose.report('Could not load matplotlib icon: %s' % sys.exc_info()[1]) + _log.info('Could not load matplotlib icon: %s', sys.exc_info()[1]) self.vbox = Gtk.Box() self.vbox.set_property("orientation", Gtk.Orientation.VERTICAL) diff --git a/lib/matplotlib/backends/backend_pdf.py b/lib/matplotlib/backends/backend_pdf.py index 46b8ac2d46ca..f84b3d539afd 100644 --- a/lib/matplotlib/backends/backend_pdf.py +++ b/lib/matplotlib/backends/backend_pdf.py @@ -16,6 +16,7 @@ import sys import time import warnings +import logging import zlib import collections from io import BytesIO @@ -52,6 +53,8 @@ from matplotlib import _png from matplotlib import ttconv +_log = logging.getLogger(__name__) + # Overview # # The low-level knowledge about pdf syntax lies mainly in the pdfRepr @@ -658,9 +661,7 @@ def fontName(self, fontprop): Fx = Name('F%d' % self.nextFont) self.fontNames[filename] = Fx self.nextFont += 1 - matplotlib.verbose.report( - 'Assigning font %s = %r' % (Fx, filename), - 'debug') + _log.debug('Assigning font %s = %r' % (Fx, filename)) return Fx @@ -694,9 +695,8 @@ def dviFontName(self, dvifont): pdfname = Name('F%d' % self.nextFont) self.nextFont += 1 - matplotlib.verbose.report( - 'Assigning font {0} = {1} (dvi)'.format(pdfname, dvifont.texname), - 'debug') + _log.debug('Assigning font {0} = {1} (dvi)'.format(pdfname, + dvifont.texname)) self.dviFontInfo[dvifont.texname] = Bunch( dvifont=dvifont, pdfname=pdfname, @@ -710,19 +710,18 @@ def writeFonts(self): fonts = {} for dviname, info in sorted(self.dviFontInfo.items()): Fx = info.pdfname - matplotlib.verbose.report('Embedding Type-1 font %s from dvi' - % dviname, 'debug') + _log.debug('Embedding Type-1 font %s from dvi' % dviname) fonts[Fx] = self._embedTeXFont(info) for filename in sorted(self.fontNames): Fx = self.fontNames[filename] - matplotlib.verbose.report('Embedding font %s' % filename, 'debug') + _log.debug('Embedding font %s' % filename) if filename.endswith('.afm'): # from pdf.use14corefonts - matplotlib.verbose.report('Writing AFM font', 'debug') + _log.debug('Writing AFM font') fonts[Fx] = self._write_afm_font(filename) else: # a normal TrueType font - matplotlib.verbose.report('Writing TrueType font', 'debug') + _log.debug('Writing TrueType font') realpath, stat_key = get_realpath_and_stat(filename) chars = self.used_characters.get(stat_key) if chars is not None and len(chars[1]): @@ -744,7 +743,7 @@ def _write_afm_font(self, filename): def _embedTeXFont(self, fontinfo): msg = ('Embedding TeX font {0} - fontinfo={1}' .format(fontinfo.dvifont.texname, fontinfo.__dict__)) - matplotlib.verbose.report(msg, 'debug') + _log.debug(msg) # Widths widthsObject = self.reserveObject('font widths') diff --git a/lib/matplotlib/backends/backend_ps.py b/lib/matplotlib/backends/backend_ps.py index 401892435d90..7711ba26c9ea 100644 --- a/lib/matplotlib/backends/backend_ps.py +++ b/lib/matplotlib/backends/backend_ps.py @@ -10,9 +10,10 @@ import glob, os, shutil, sys, time, datetime import io +import logging from tempfile import mkstemp -from matplotlib import verbose, __version__, rcParams, checkdep_ghostscript +from matplotlib import __version__, rcParams, checkdep_ghostscript from matplotlib.afm import AFM from matplotlib.backend_bases import ( _Backend, FigureCanvasBase, FigureManagerBase, GraphicsContextBase, @@ -39,6 +40,7 @@ import binascii import re +_log = logging.getLogger(__name__) backend_version = 'Level II' @@ -1328,10 +1330,10 @@ def write(self, *kl, **kwargs): paperWidth, paperHeight = papersize[papertype] if (width > paperWidth or height > paperHeight) and isEPSF: paperWidth, paperHeight = papersize[temp_papertype] - verbose.report( + _log.info( ('Your figure is too big to fit on %s paper. %s ' 'paper will be used to prevent clipping.' - ) % (papertype, temp_papertype), 'helpful') + ) % (papertype, temp_papertype)) texmanager = ps_renderer.get_texmanager() font_preamble = texmanager.get_font_preamble() @@ -1429,9 +1431,9 @@ def convert_psfrags(tmpfile, psfrags, font_preamble, custom_preamble, try: latexh.write(s.encode('ascii')) except UnicodeEncodeError: - verbose.report("You are using unicode and latex, but have " - "not enabled the matplotlib 'text.latex.unicode' " - "rcParam.", 'helpful') + _log.info("You are using unicode and latex, but have " + "not enabled the matplotlib 'text.latex.unicode' " + "rcParam.") raise # Replace \\ for / so latex does not think there is a function call @@ -1440,7 +1442,7 @@ def convert_psfrags(tmpfile, psfrags, font_preamble, custom_preamble, latexfile = latexfile.replace("~", "\\string~") command = [str("latex"), "-interaction=nonstopmode", '"%s"' % latexfile] - verbose.report(command, 'debug') + _log.debug('%s', command) try: report = subprocess.check_output(command, cwd=tmpdir, stderr=subprocess.STDOUT) @@ -1451,11 +1453,11 @@ def convert_psfrags(tmpfile, psfrags, font_preamble, custom_preamble, 'Here is the full report generated by LaTeX:\n%s ' '\n\n' % (latexfile, exc.output.decode("utf-8")))) - verbose.report(report, 'debug') + _log.debug(report) command = [str('dvips'), '-q', '-R0', '-o', os.path.basename(psfile), os.path.basename(dvifile)] - verbose.report(command, 'debug') + _log.debug(command) try: report = subprocess.check_output(command, cwd=tmpdir, stderr=subprocess.STDOUT) @@ -1466,7 +1468,7 @@ def convert_psfrags(tmpfile, psfrags, font_preamble, custom_preamble, 'Here is the full report generated by dvips:\n%s ' '\n\n' % (dvifile, exc.output.decode("utf-8")))) - verbose.report(report, 'debug') + _log.debug(report) os.remove(epsfile) shutil.move(psfile, tmpfile) @@ -1513,7 +1515,7 @@ def gs_distill(tmpfile, eps=False, ptype='letter', bbox=None, rotated=False): command = [str(gs_exe), "-dBATCH", "-dNOPAUSE", "-r%d" % dpi, "-sDEVICE=%s" % device_name, paper_option, "-sOutputFile=%s" % psfile, tmpfile] - verbose.report(command, 'debug') + _log.debug(command) try: report = subprocess.check_output(command, stderr=subprocess.STDOUT) except subprocess.CalledProcessError as exc: @@ -1521,7 +1523,7 @@ def gs_distill(tmpfile, eps=False, ptype='letter', bbox=None, rotated=False): ('ghostscript was not able to process your image.\n' 'Here is the full report generated by ghostscript:\n%s ' '\n\n' % exc.output.decode("utf-8"))) - verbose.report(report, 'debug') + _log.debug(report) os.remove(tmpfile) shutil.move(psfile, tmpfile) @@ -1571,7 +1573,7 @@ def xpdf_distill(tmpfile, eps=False, ptype='letter', bbox=None, rotated=False): "-sGrayImageFilter=FlateEncode", "-sColorImageFilter=FlateEncode", paper_option, tmpfile, pdffile] - verbose.report(command, 'debug') + _log.debug(command) try: report = subprocess.check_output(command, stderr=subprocess.STDOUT) @@ -1580,10 +1582,10 @@ def xpdf_distill(tmpfile, eps=False, ptype='letter', bbox=None, rotated=False): ('ps2pdf was not able to process your image.\n' 'Here is the full report generated by ps2pdf:\n%s ' '\n\n' % exc.output.decode("utf-8"))) - verbose.report(report, 'debug') + _log.debug(report) command = [str("pdftops"), "-paper", "match", "-level2", pdffile, psfile] - verbose.report(command, 'debug') + _log.debug(command) try: report = subprocess.check_output(command, stderr=subprocess.STDOUT) except subprocess.CalledProcessError as exc: @@ -1591,7 +1593,7 @@ def xpdf_distill(tmpfile, eps=False, ptype='letter', bbox=None, rotated=False): ('pdftops was not able to process your image.\n' 'Here is the full report generated by pdftops:\n%s ' '\n\n' % exc.output.decode("utf-8"))) - verbose.report(report, 'debug') + _log.debug(report) os.remove(tmpfile) shutil.move(psfile, tmpfile) @@ -1630,14 +1632,14 @@ def get_bbox(tmpfile, bbox): gs_exe = ps_backend_helper.gs_exe command = [gs_exe, "-dBATCH", "-dNOPAUSE", "-sDEVICE=bbox" "%s" % tmpfile] - verbose.report(command, 'debug') + _log.debug(command) p = subprocess.Popen(command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True) (stdout, stderr) = (p.stdout, p.stderr) - verbose.report(stdout.read(), 'debug-annoying') + _log.debug(stdout.read()) bbox_info = stderr.read() - verbose.report(bbox_info, 'helpful') + _log.info(bbox_info) bbox_found = re.search('%%HiResBoundingBox: .*', bbox_info) if bbox_found: bbox_info = bbox_found.group() diff --git a/lib/matplotlib/backends/backend_svg.py b/lib/matplotlib/backends/backend_svg.py index 98a0369f8128..f799973f932e 100644 --- a/lib/matplotlib/backends/backend_svg.py +++ b/lib/matplotlib/backends/backend_svg.py @@ -10,11 +10,12 @@ import os, base64, tempfile, gzip, io, sys, codecs, re import numpy as np +import logging from hashlib import md5 import uuid -from matplotlib import verbose, __version__, rcParams +from matplotlib import __version__, rcParams from matplotlib.backend_bases import ( _Backend, FigureCanvasBase, FigureManagerBase, GraphicsContextBase, RendererBase) @@ -32,6 +33,8 @@ from xml.sax.saxutils import escape as escape_xml_text +_log = logging.getLogger(__name__) + backend_version = __version__ # ---------------------------------------------------------------------- @@ -823,7 +826,7 @@ def draw_image(self, gc, x, y, im, transform=None): else: self._imaged[self.basename] = self._imaged.get(self.basename, 0) + 1 filename = '%s.image%d.png'%(self.basename, self._imaged[self.basename]) - verbose.report('Writing image file for inclusion: %s' % filename) + _log.info('Writing image file for inclusion: %s', filename) _png.write_png(im, filename) oid = oid or 'Im_' + self._make_id('image', filename) attrib['xlink:href'] = filename diff --git a/lib/matplotlib/backends/backend_tkagg.py b/lib/matplotlib/backends/backend_tkagg.py index 58d171f0d737..75257811c998 100644 --- a/lib/matplotlib/backends/backend_tkagg.py +++ b/lib/matplotlib/backends/backend_tkagg.py @@ -8,6 +8,7 @@ import os, sys, math import os.path +import logging # Paint image to Tk photo blitter extension import matplotlib.backends.tkagg as tkagg @@ -30,9 +31,9 @@ import matplotlib.cbook as cbook -rcParams = matplotlib.rcParams -verbose = matplotlib.verbose +_log = logging.getLogger(__name__) +rcParams = matplotlib.rcParams backend_version = Tk.TkVersion @@ -1059,7 +1060,7 @@ def new_figure_manager_given_figure(num, figure): window.tk.call('wm', 'foobar', window._w, icon_img) except Exception as exc: # log the failure (due e.g. to Tk version), but carry on - verbose.report('Could not load matplotlib icon: %s' % exc) + _log.info('Could not load matplotlib icon: %s', exc) canvas = FigureCanvasTkAgg(figure, master=window) manager = FigureManagerTkAgg(canvas, num, window) diff --git a/lib/matplotlib/backends/qt_compat.py b/lib/matplotlib/backends/qt_compat.py index 3542228d9799..3b8d4ecf3478 100644 --- a/lib/matplotlib/backends/qt_compat.py +++ b/lib/matplotlib/backends/qt_compat.py @@ -6,8 +6,11 @@ import six import os +import logging import sys -from matplotlib import rcParams, verbose +from matplotlib import rcParams + +_log = logging.getLogger(__name__) # Available APIs. QT_API_PYQT = 'PyQt4' # API is not set here; Python 2.x default is V 1 @@ -111,7 +114,7 @@ QT_API = QT_API_PYSIDE cond = ("Could not import sip; falling back on PySide\n" "in place of PyQt4 or PyQt5.\n") - verbose.report(cond, 'helpful') + _log.info(cond) if _sip_imported: if QT_API == QT_API_PYQTv2: @@ -124,14 +127,14 @@ sip.setapi('QString', 2) except: res = 'QString API v2 specification failed. Defaulting to v1.' - verbose.report(cond + res, 'helpful') + _log.info(cond + res) # condition has now been reported, no need to repeat it: cond = "" try: sip.setapi('QVariant', 2) except: res = 'QVariant API v2 specification failed. Defaulting to v1.' - verbose.report(cond + res, 'helpful') + _log.info(cond + res) if QT_API == QT_API_PYQT5: try: from PyQt5 import QtCore, QtGui, QtWidgets diff --git a/lib/matplotlib/blocking_input.py b/lib/matplotlib/blocking_input.py index 4dc50f47eb68..17e3633a39ae 100644 --- a/lib/matplotlib/blocking_input.py +++ b/lib/matplotlib/blocking_input.py @@ -26,10 +26,11 @@ unicode_literals) import six -from matplotlib import verbose import matplotlib.lines as mlines -import warnings +import logging + +_log = logging.getLogger(__name__) class BlockingInput(object): @@ -50,8 +51,7 @@ def on_event(self, event): # overkill for the base class, but this is consistent with # subclasses self.add_event(event) - - verbose.report("Event %i" % len(self.events)) + _log.info("Event %i", len(self.events)) # This will extract info from events self.post_event() @@ -148,7 +148,7 @@ def post_event(self): This will be called to process events """ if len(self.events) == 0: - warnings.warn("No events yet") + _log.warning("No events yet") elif self.events[-1].name == 'key_press_event': self.key_event() else: @@ -230,8 +230,7 @@ def add_click(self, event): This add the coordinates of an event to the list of clicks """ self.clicks.append((event.xdata, event.ydata)) - - verbose.report("input %i: %f,%f" % + _log.info("input %i: %f,%f" % (len(self.clicks), event.xdata, event.ydata)) # If desired plot up click @@ -361,7 +360,7 @@ def post_event(self): Determines if it is a key event """ if len(self.events) == 0: - warnings.warn("No events yet") + _log.warning("No events yet") else: self.keyormouse = self.events[-1].name == 'key_press_event' diff --git a/lib/matplotlib/dviread.py b/lib/matplotlib/dviread.py index 014d134533c1..f3b55ddd532a 100644 --- a/lib/matplotlib/dviread.py +++ b/lib/matplotlib/dviread.py @@ -26,10 +26,7 @@ from collections import namedtuple import errno from functools import partial, wraps -import matplotlib -import matplotlib.cbook as mpl_cbook -from matplotlib.compat import subprocess -from matplotlib import rcParams +import logging import numpy as np import re import struct @@ -37,6 +34,11 @@ import textwrap import os +import matplotlib +import matplotlib.cbook as mpl_cbook +from matplotlib.compat import subprocess +from matplotlib import rcParams + try: from functools import lru_cache except ImportError: # Py2 @@ -46,6 +48,8 @@ def ord(x): return x +_log = logging.getLogger(__name__) + # Dvi is a bytecode format documented in # http://mirrors.ctan.org/systems/knuth/dist/texware/dvitype.web # http://texdoc.net/texmf-dist/doc/generic/knuth/texware/dvitype.pdf @@ -204,7 +208,7 @@ def __init__(self, filename, dpi): *dpi* only sets the units and does not limit the resolution. Use None to return TeX's internal units. """ - matplotlib.verbose.report('Dvi: ' + filename, 'debug') + _log.debug('Dvi: ' + filename) self.file = open(filename, 'rb') self.dpi = dpi self.fonts = {} @@ -450,12 +454,11 @@ def _xxx(self, datalen): else: def chr_(x): return x - matplotlib.verbose.report( + _log.debug( 'Dvi._xxx: encountered special: %s' % ''.join([(32 <= ord(ch) < 127) and chr_(ch) or '<%02x>' % ord(ch) - for ch in special]), - 'debug') + for ch in special])) @dispatch(min=243, max=246, args=('olen1', 'u4', 'u4', 'u4', 'u1', 'u1')) def _fnt_def(self, k, c, s, d, a, l): @@ -580,10 +583,8 @@ def _width_of(self, char): width = self._tfm.width.get(char, None) if width is not None: return _mul2012(width, self._scale) - - matplotlib.verbose.report( - 'No width for char %d in font %s' % (char, self.texname), - 'debug') + _log.debug( + 'No width for char %d in font %s' % (char, self.texname)) return 0 def _height_depth_of(self, char): @@ -596,10 +597,9 @@ def _height_depth_of(self, char): (self._tfm.depth, "depth")): value = metric.get(char, None) if value is None: - matplotlib.verbose.report( + _log.debug( 'No %s for char %d in font %s' % ( - name, char, self.texname), - 'debug') + name, char, self.texname)) result.append(0) else: result.append(_mul2012(value, self._scale)) @@ -712,7 +712,7 @@ def _pre(self, i, x, cs, ds): if i != 202: raise ValueError("Unknown vf format %d" % i) if len(x): - matplotlib.verbose.report('vf file comment: ' + x, 'debug') + _log.debug('vf file comment: ' + x) self.state = _dvistate.outer # cs = checksum, ds = design size @@ -760,14 +760,14 @@ class Tfm(object): __slots__ = ('checksum', 'design_size', 'width', 'height', 'depth') def __init__(self, filename): - matplotlib.verbose.report('opening tfm file ' + filename, 'debug') + _log.debug('opening tfm file ' + filename) with open(filename, 'rb') as file: header1 = file.read(24) lh, bc, ec, nw, nh, nd = \ struct.unpack(str('!6H'), header1[2:14]) - matplotlib.verbose.report( + _log.debug( 'lh=%d, bc=%d, ec=%d, nw=%d, nh=%d, nd=%d' % ( - lh, bc, ec, nw, nh, nd), 'debug') + lh, bc, ec, nw, nh, nd)) header2 = file.read(4*lh) self.checksum, self.design_size = \ struct.unpack(str('!2I'), header2[:8]) @@ -864,7 +864,7 @@ def __getitem__(self, texname): msg = fmt.format(texname.decode('ascii'), self._filename) msg = textwrap.fill(msg, break_on_hyphens=False, break_long_words=False) - matplotlib.verbose.report(msg, 'helpful') + _log.info(msg) raise fn, enc = result.filename, result.encoding if fn is not None and not fn.startswith(b'/'): @@ -937,10 +937,9 @@ def _parse(self, file): w.group('enc2') or w.group('enc1')) if enc: if encoding is not None: - matplotlib.verbose.report( + _log.debug( 'Multiple encodings for %s = %s' - % (texname, psname), - 'debug') + % (texname, psname)) encoding = enc continue # File names are probably unquoted: @@ -983,11 +982,9 @@ class Encoding(object): def __init__(self, filename): with open(filename, 'rb') as file: - matplotlib.verbose.report('Parsing TeX encoding ' + filename, - 'debug-annoying') + _log.debug('Parsing TeX encoding ' + filename) self.encoding = self._parse(file) - matplotlib.verbose.report('Result: ' + repr(self.encoding), - 'debug-annoying') + _log.debug('Result: ' + repr(self.encoding)) def __iter__(self): for name in self.encoding: @@ -1047,9 +1044,8 @@ def find_tex_file(filename, format=None): if format is not None: cmd += ['--format=' + format] cmd += [filename] - - matplotlib.verbose.report('find_tex_file(%s): %s' - % (filename, cmd), 'debug') + _log.debug('find_tex_file(%s): %s' + % (filename, cmd)) # stderr is unused, but reading it avoids a subprocess optimization # that breaks EINTR handling in some Python versions: # http://bugs.python.org/issue12493 @@ -1057,8 +1053,7 @@ def find_tex_file(filename, format=None): pipe = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) result = pipe.communicate()[0].rstrip() - matplotlib.verbose.report('find_tex_file result: %s' % result, - 'debug') + _log.debug('find_tex_file result: %s' % result) return result.decode('ascii') @@ -1078,7 +1073,6 @@ def _fontfile(cls, suffix, texname): if __name__ == '__main__': import sys - matplotlib.verbose.set_level('debug-annoying') fname = sys.argv[1] try: dpi = float(sys.argv[2]) diff --git a/lib/matplotlib/figure.py b/lib/matplotlib/figure.py index a8ff2e303417..d1eda6858344 100644 --- a/lib/matplotlib/figure.py +++ b/lib/matplotlib/figure.py @@ -16,6 +16,7 @@ import six +import logging import warnings import numpy as np @@ -48,6 +49,8 @@ TransformedBbox) from matplotlib.backend_bases import NonGuiException +_log = logging.getLogger(__name__) + docstring.interpd.update(projection_names=get_projection_names()) diff --git a/lib/matplotlib/finance.py b/lib/matplotlib/finance.py index d64b09c87523..9121c41c87aa 100644 --- a/lib/matplotlib/finance.py +++ b/lib/matplotlib/finance.py @@ -17,10 +17,11 @@ from six.moves.urllib.request import urlopen import datetime +import logging import numpy as np -from matplotlib import colors as mcolors, verbose, get_cachedir +from matplotlib import colors as mcolors, get_cachedir from matplotlib.dates import date2num from matplotlib.cbook import iterable, mkdirs, warn_deprecated from matplotlib.collections import LineCollection, PolyCollection @@ -28,6 +29,8 @@ from matplotlib.patches import Rectangle from matplotlib.transforms import Affine2D +_log = logging.getLogger(__name__) + warn_deprecated( since=2.0, message=("The finance module has been deprecated in mpl 2.0 and will " @@ -338,7 +341,7 @@ def fetch_historical_yahoo(ticker, date1, date2, cachename=None, if dividends: g = 'v' - verbose.report('Retrieving dividends instead of prices') + _log.info('Retrieving dividends instead of prices') else: g = 'd' @@ -353,14 +356,14 @@ def fetch_historical_yahoo(ticker, date1, date2, cachename=None, if cachename is not None: if os.path.exists(cachename): fh = open(cachename) - verbose.report('Using cachefile %s for ' + _log.info('Using cachefile %s for ' '%s' % (cachename, ticker)) else: mkdirs(os.path.abspath(os.path.dirname(cachename))) with contextlib.closing(urlopen(url)) as urlfh: with open(cachename, 'wb') as fh: fh.write(urlfh.read()) - verbose.report('Saved %s data to cache file ' + _log.info('Saved %s data to cache file ' '%s' % (ticker, cachename)) fh = open(cachename, 'r') diff --git a/lib/matplotlib/font_manager.py b/lib/matplotlib/font_manager.py index bcffeb02f6cb..70044d692bfa 100644 --- a/lib/matplotlib/font_manager.py +++ b/lib/matplotlib/font_manager.py @@ -53,6 +53,7 @@ import sys from threading import Timer import warnings +import logging import matplotlib from matplotlib import afm, cbook, ft2font, rcParams, get_cachedir @@ -65,9 +66,9 @@ except ImportError: from backports.functools_lru_cache import lru_cache +_log = logging.getLogger(__name__) USE_FONTCONFIG = False -verbose = matplotlib.verbose font_scalings = { 'xx-small' : 0.579, @@ -554,7 +555,7 @@ def createFontList(fontfiles, fontext='ttf'): # Add fonts from list of known font files. seen = set() for fpath in fontfiles: - verbose.report('createFontDict: %s' % fpath, 'debug') + _log.debug('createFontDict: %s' % (fpath)) fname = os.path.split(fpath)[1] if fname in seen: continue @@ -564,12 +565,12 @@ def createFontList(fontfiles, fontext='ttf'): try: fh = open(fpath, 'rb') except EnvironmentError: - verbose.report("Could not open font file %s" % fpath) + _log.info("Could not open font file %s", fpath) continue try: font = afm.AFM(fh) except RuntimeError: - verbose.report("Could not parse font file %s" % fpath) + _log.info("Could not parse font file %s", fpath) continue finally: fh.close() @@ -581,13 +582,13 @@ def createFontList(fontfiles, fontext='ttf'): try: font = ft2font.FT2Font(fpath) except RuntimeError: - verbose.report("Could not open font file %s" % fpath) + _log.info("Could not open font file %s", fpath) continue except UnicodeError: - verbose.report("Cannot handle unicode filenames") + _log.info("Cannot handle unicode filenames") continue except IOError: - verbose.report("IO error - cannot open font file %s" % fpath) + _log.info("IO error - cannot open font file %s", fpath) continue try: prop = ttfFontProperty(font) @@ -1057,8 +1058,7 @@ def __init__(self, size=None, weight='normal'): paths.extend(ttfpath.split(':')) else: paths.append(ttfpath) - - verbose.report('font search path %s'%(str(paths))) + _log.info('font search path %s', str(paths)) # Load TrueType fonts and create font dictionary. self.ttffiles = findSystemFonts(paths) + findSystemFonts() @@ -1068,7 +1068,7 @@ def __init__(self, size=None, weight='normal'): self.defaultFont = {} for fname in self.ttffiles: - verbose.report('trying fontname %s' % fname, 'debug') + _log.debug('trying fontname %s' % fname) if fname.lower().find('DejaVuSans.ttf')>=0: self.defaultFont['ttf'] = fname break @@ -1288,8 +1288,9 @@ def _findfont_cached(self, prop, fontext, directory, fallback_to_default, if not isinstance(prop, FontProperties): prop = FontProperties(prop) fname = prop.get_file() + if fname is not None: - verbose.report('findfont returning %s'%fname, 'debug') + _log.debug('findfont returning %s'%fname) return fname if fontext == 'afm': @@ -1340,14 +1341,14 @@ def _findfont_cached(self, prop, fontext, directory, fallback_to_default, UserWarning) result = self.defaultFont[fontext] else: - verbose.report( + _log.info( 'findfont: Matching %s to %s (%s) with score of %f' % (prop, best_font.name, repr(best_font.fname), best_score)) result = best_font.fname if not os.path.isfile(result): if rebuild_if_missing: - verbose.report( + _log.info( 'findfont: Found a missing font file. Rebuilding cache.') _rebuild() return fontManager.findfont( @@ -1444,8 +1445,7 @@ def _rebuild(): if _fmcache: with cbook.Locked(cachedir): json_dump(fontManager, _fmcache) - - verbose.report("generated new fontManager") + _log.info("generated new fontManager") if _fmcache: try: @@ -1455,7 +1455,7 @@ def _rebuild(): _rebuild() else: fontManager.default_size = None - verbose.report("Using fontManager instance from %s" % _fmcache) + _log.info("Using fontManager instance from %s", _fmcache) except cbook.Locked.TimeoutError: raise except: diff --git a/lib/matplotlib/sankey.py b/lib/matplotlib/sankey.py index d57a66333ba8..84a2c2950faf 100644 --- a/lib/matplotlib/sankey.py +++ b/lib/matplotlib/sankey.py @@ -5,6 +5,7 @@ unicode_literals) import six +import logging from six.moves import zip import numpy as np @@ -12,10 +13,11 @@ from matplotlib.path import Path from matplotlib.patches import PathPatch from matplotlib.transforms import Affine2D -from matplotlib import verbose from matplotlib import docstring from matplotlib import rcParams +_log = logging.getLogger(__name__) + __author__ = "Kevin L. Davies" __credits__ = ["Yannick Copin"] __license__ = "BSD" @@ -465,22 +467,21 @@ def add(self, patchlabel='', flows=None, orientations=None, labels='', "trunklength is negative.\nThis isn't allowed, because it would " "cause poor layout.") if np.abs(np.sum(flows)) > self.tolerance: - verbose.report( - "The sum of the flows is nonzero (%f).\nIs the " - "system not at steady state?" % np.sum(flows), 'helpful') + _log.info("The sum of the flows is nonzero (%f).\nIs the " + "system not at steady state?", np.sum(flows)) scaled_flows = self.scale * flows gain = sum(max(flow, 0) for flow in scaled_flows) loss = sum(min(flow, 0) for flow in scaled_flows) if not (0.5 <= gain <= 2.0): - verbose.report( + _log.info( "The scaled sum of the inputs is %f.\nThis may " "cause poor layout.\nConsider changing the scale so" - " that the scaled sum is approximately 1.0." % gain, 'helpful') + " that the scaled sum is approximately 1.0.", gain) if not (-2.0 <= loss <= -0.5): - verbose.report( + _log.info( "The scaled sum of the outputs is %f.\nThis may " "cause poor layout.\nConsider changing the scale so" - " that the scaled sum is approximately 1.0." % gain, 'helpful') + " that the scaled sum is approximately 1.0.", gain) if prior is not None: if prior < 0: raise ValueError("The index of the prior diagram is negative.") @@ -522,11 +523,11 @@ def add(self, patchlabel='', flows=None, orientations=None, labels='', elif flow <= -self.tolerance: are_inputs[i] = False else: - verbose.report( + _log.info( "The magnitude of flow %d (%f) is below the " "tolerance (%f).\nIt will not be shown, and it " "cannot be used in a connection." - % (i, flow, self.tolerance), 'helpful') + % (i, flow, self.tolerance)) # Determine the angles of the arrows (before rotation). angles = [None] * n diff --git a/lib/matplotlib/tests/test_backend_ps.py b/lib/matplotlib/tests/test_backend_ps.py index f7bb1fb0e1be..64fbd5dbe65c 100644 --- a/lib/matplotlib/tests/test_backend_ps.py +++ b/lib/matplotlib/tests/test_backend_ps.py @@ -140,7 +140,6 @@ def test_tilde_in_tempfilename(): plt.rc('text', usetex=True) plt.plot([1, 2, 3, 4]) plt.xlabel(r'\textbf{time} (s)') - # matplotlib.verbose.set_level("debug") output_eps = os.path.join(base_tempdir, 'tex_demo.eps') # use the PS backend to write the file... plt.savefig(output_eps, format="ps") diff --git a/lib/matplotlib/texmanager.py b/lib/matplotlib/texmanager.py index ac2875bdae12..cafb56f93d9b 100644 --- a/lib/matplotlib/texmanager.py +++ b/lib/matplotlib/texmanager.py @@ -44,6 +44,7 @@ import shutil import sys import warnings +import logging from hashlib import md5 @@ -57,6 +58,7 @@ import matplotlib.dviread as dviread import re +_log = logging.getLogger(__name__) DEBUG = False @@ -68,17 +70,16 @@ def dvipng_hack_alpha(): stderr=STDOUT, close_fds=(sys.platform != 'win32')) stdout, stderr = p.communicate() except OSError: - mpl.verbose.report('No dvipng was found', 'helpful') + _log.info('No dvipng was found') return False lines = stdout.decode(sys.getdefaultencoding()).split('\n') for line in lines: if line.startswith('dvipng '): version = line.split()[-1] - mpl.verbose.report('Found dvipng version %s' % version, - 'helpful') + _log.info('Found dvipng version %s', version) version = distutils.version.LooseVersion(version) return version < distutils.version.LooseVersion('1.6') - mpl.verbose.report('Unexpected response from dvipng -version', 'helpful') + _log.info('Unexpected response from dvipng -version') return False @@ -169,11 +170,10 @@ def __init__(self): elif isinstance(ff, six.string_types) and ff.lower() in self.font_families: self.font_family = ff.lower() else: - mpl.verbose.report( + _log.info( 'font.family must be one of (%s) when text.usetex is True. ' - 'serif will be used by default.' % - ', '.join(self.font_families), - 'helpful') + 'serif will be used by default.', + ', '.join(self.font_families)) self.font_family = 'serif' fontconfig = [self.font_family] @@ -192,9 +192,9 @@ def __init__(self): if DEBUG: print('$s font is not compatible with usetex') else: - mpl.verbose.report('No LaTeX-compatible font found for the ' + _log.info('No LaTeX-compatible font found for the ' '%s font family in rcParams. Using ' - 'default.' % font_family, 'helpful') + 'default.', font_family) setattr(self, font_family_attr, self.font_info[font_family]) fontconfig.append(getattr(self, font_family_attr)[0]) # Add a hash of the latex preamble to self._fontconfig so that the @@ -295,10 +295,9 @@ def make_tex(self, tex, fontsize): try: fh.write(s.encode('ascii')) except UnicodeEncodeError as err: - mpl.verbose.report("You are using unicode and latex, but " + _log.info("You are using unicode and latex, but " "have not enabled the matplotlib " - "'text.latex.unicode' rcParam.", - 'helpful') + "'text.latex.unicode' rcParam.") raise return texfile @@ -356,10 +355,9 @@ def make_tex_preview(self, tex, fontsize): try: fh.write(s.encode('ascii')) except UnicodeEncodeError as err: - mpl.verbose.report("You are using unicode and latex, but " + _log.info("You are using unicode and latex, but " "have not enabled the matplotlib " - "'text.latex.unicode' rcParam.", - 'helpful') + "'text.latex.unicode' rcParam.") raise return texfile @@ -376,12 +374,11 @@ def make_dvi(self, tex, fontsize): basefile = self.get_basefile(tex, fontsize) dvifile = '%s.dvi' % basefile - if DEBUG or not os.path.exists(dvifile): texfile = self.make_tex(tex, fontsize) command = [str("latex"), "-interaction=nonstopmode", os.path.basename(texfile)] - mpl.verbose.report(command, 'debug') + _log.debug(command) with Locked(self.texcache): try: report = subprocess.check_output(command, @@ -394,7 +391,7 @@ def make_dvi(self, tex, fontsize): 'Here is the full report generated by LaTeX:\n%s ' '\n\n' % (repr(tex.encode('unicode_escape')), exc.output.decode("utf-8")))) - mpl.verbose.report(report, 'debug') + _log.debug(report) for fname in glob.glob(basefile + '*'): if fname.endswith('dvi'): pass @@ -425,7 +422,7 @@ def make_dvi_preview(self, tex, fontsize): texfile = self.make_tex_preview(tex, fontsize) command = [str("latex"), "-interaction=nonstopmode", os.path.basename(texfile)] - mpl.verbose.report(command, 'debug') + _log.debug(command) try: report = subprocess.check_output(command, cwd=self.texcache, @@ -437,7 +434,7 @@ def make_dvi_preview(self, tex, fontsize): 'Here is the full report generated by LaTeX:\n%s ' '\n\n' % (repr(tex.encode('unicode_escape')), exc.output.decode("utf-8")))) - mpl.verbose.report(report, 'debug') + _log.debug(report) # find the box extent information in the latex output # file and store them in ".baseline" file @@ -475,7 +472,7 @@ def make_png(self, tex, fontsize, dpi): command = [str("dvipng"), "-bg", "Transparent", "-D", str(dpi), "-T", "tight", "-o", os.path.basename(pngfile), os.path.basename(dvifile)] - mpl.verbose.report(command, 'debug') + _log.debug(command) try: report = subprocess.check_output(command, cwd=self.texcache, @@ -487,7 +484,7 @@ def make_png(self, tex, fontsize, dpi): 'Here is the full report generated by dvipng:\n%s ' '\n\n' % (repr(tex.encode('unicode_escape')), exc.output.decode("utf-8")))) - mpl.verbose.report(report, 'debug') + _log.debug(report) return pngfile @@ -505,7 +502,7 @@ def make_ps(self, tex, fontsize): command = [str("dvips"), "-q", "-E", "-o", os.path.basename(psfile), os.path.basename(dvifile)] - mpl.verbose.report(command, 'debug') + _log.debug(command) try: report = subprocess.check_output(command, cwd=self.texcache, @@ -517,7 +514,7 @@ def make_ps(self, tex, fontsize): 'Here is the full report generated by dvips:\n%s ' '\n\n' % (repr(tex.encode('unicode_escape')), exc.output.decode("utf-8")))) - mpl.verbose.report(report, 'debug') + _log.debug(report) return psfile diff --git a/lib/matplotlib/text.py b/lib/matplotlib/text.py index 22a27756f895..a55afdb49b69 100644 --- a/lib/matplotlib/text.py +++ b/lib/matplotlib/text.py @@ -9,6 +9,7 @@ import math import warnings +import logging import weakref import contextlib @@ -20,7 +21,7 @@ import matplotlib.artist as artist from matplotlib.artist import Artist from matplotlib.cbook import maxdict -from matplotlib import docstring, verbose +from matplotlib import docstring from matplotlib.font_manager import FontProperties from matplotlib.patches import FancyBboxPatch from matplotlib.patches import FancyArrowPatch, Rectangle @@ -33,6 +34,8 @@ from matplotlib.textpath import TextPath +_log = logging.getLogger(__name__) + def _process_text_args(override, fontdict=None, **kwargs): "Return an override dict. See :func:`~pyplot.text' docstring for info" @@ -721,9 +724,7 @@ def draw(self, renderer): posy = float(textobj.convert_yunits(textobj._y)) posx, posy = trans.transform_point((posx, posy)) if not np.isfinite(posx) or not np.isfinite(posy): - verbose.report("x and y are not finite values for text " - "string '{}'. Not rendering " - "text.".format(self.get_text()), 'helpful') + _log.warning("posx and posy should be finite values") return canvasw, canvash = renderer.get_canvas_width_height() diff --git a/matplotlibrc.template b/matplotlibrc.template index 5013c9755c8e..22fb2cfef5a1 100644 --- a/matplotlibrc.template +++ b/matplotlibrc.template @@ -557,26 +557,6 @@ backend : $TEMPLATE_BACKEND # docstring params #docstring.hardcopy = False # set this when you want to generate hardcopy docstring -# Set the verbose flags. This controls how much information -# matplotlib gives you at runtime and where it goes. The verbosity -# levels are: silent, helpful, debug, debug-annoying. Any level is -# inclusive of all the levels below it. If your setting is "debug", -# you'll get all the debug and helpful messages. When submitting -# problems to the mailing-list, please set verbose to "helpful" or "debug" -# and paste the output into your report. -# -# The "fileo" gives the destination for any calls to verbose.report. -# These objects can a filename, or a filehandle like sys.stdout. -# -# You can override the rc default verbosity from the command line by -# giving the flags --verbose-LEVEL where LEVEL is one of the legal -# levels, e.g., --verbose-helpful. -# -# You can access the verbose instance in your code -# from matplotlib import verbose. -#verbose.level : silent # one of silent, helpful, debug, debug-annoying -#verbose.fileo : sys.stdout # a log filename, sys.stdout or sys.stderr - # Event keys to interact with figures/plots via keyboard. # Customize these settings according to your needs. # Leave the field(s) empty if you don't need a key-map. (i.e., fullscreen : '')