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 : '')