Skip to content

Commit eaa1207

Browse files
committed
Some more fixes for the verbose -> logging switch.
Technically, this PR changes the behavior of get_home(), get_cachedir(), etc. making them insensitive to changes in the relevant environment variables *after* matplotlib is imported. In practice I strongly doubt that we supported that use case to begin with (because the values are probably cached in other places); I am also happy with saying "don't do this" until someone brings up a good reason to change the cache dir in the middle of the program...
1 parent 9767cfe commit eaa1207

File tree

4 files changed

+41
-55
lines changed

4 files changed

+41
-55
lines changed

doc/devel/contributing.rst

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -472,19 +472,18 @@ Then they will receive messages like::
472472
Which logging level to use?
473473
~~~~~~~~~~~~~~~~~~~~~~~~~~~
474474

475-
There are five levels at which you can emit messages.
476-
`logging.critical` and `logging.error`
477-
are really only there for errors that will end the use of the library but
478-
not kill the interpreter. `logging.warning` overlaps with the
479-
``warnings`` library. The
480-
`logging tutorial <https://docs.python.org/3/howto/logging.html#logging-basic-tutorial>`_
481-
suggests that the difference
482-
between `logging.warning` and `warnings.warn` is that
483-
`warnings.warn` be used for things the user must change to stop
484-
the warning, whereas `logging.warning` can be more persistent.
475+
There are five levels at which you can emit messages. `logging.critical` and
476+
`logging.error` are really only there for errors that will end the use of the
477+
library but not kill the interpreter. `logging.warning` overlaps with the
478+
`warnings` library. The `logging tutorial`_ suggests that the difference
479+
between `logging.warning` and `warnings.warn` is that `warnings.warn` be used
480+
for things the user must change to stop the warning, whereas `logging.warning`
481+
can be more persistent.
482+
483+
.. _logging tutorial: https://docs.python.org/3/howto/logging.html#logging-basic-tutorial
485484

486485
By default, `logging` displays all log messages at levels higher than
487-
`logging.WARNING` to `sys.stderr`.
486+
``logging.WARNING`` to `sys.stderr`.
488487

489488
Calls to `logging.info` are not displayed by default. They are for
490489
information that the user may want to know if the program behaves oddly.

lib/matplotlib/__init__.py

Lines changed: 28 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -396,31 +396,6 @@ def ge(self, level):
396396
return self.vald[self.level] >= self.vald[level]
397397

398398

399-
def _wrap(fmt, func, level='DEBUG', always=True):
400-
"""
401-
return a callable function that wraps func and reports its
402-
output through logger
403-
404-
if always is True, the report will occur on every function
405-
call; otherwise only on the first time the function is called
406-
"""
407-
assert callable(func)
408-
409-
def wrapper(*args, **kwargs):
410-
ret = func(*args, **kwargs)
411-
412-
if (always or not wrapper._spoke):
413-
lvl = logging.getLevelName(level.upper())
414-
_log.log(lvl, fmt % ret)
415-
spoke = True
416-
if not wrapper._spoke:
417-
wrapper._spoke = spoke
418-
return ret
419-
wrapper._spoke = False
420-
wrapper.__doc__ = func.__doc__
421-
return wrapper
422-
423-
424399
def checkdep_dvipng():
425400
try:
426401
s = subprocess.Popen([str('dvipng'), '-version'],
@@ -589,7 +564,27 @@ def checkdep_usetex(s):
589564
return flag
590565

591566

592-
def _get_home():
567+
def _log_and_cache_result(fmt, level="DEBUG", func=None):
568+
"""Decorator that logs & caches the result of a function with no arguments.
569+
570+
The first time the decorated *func* is called, its result is logged at
571+
level *level* using log format *fmt*, and cached. Later calls immediately
572+
return the cached result without logging.
573+
"""
574+
if func is None:
575+
return functools.partial(_log_and_cache_result, fmt, level)
576+
577+
@functools.lru_cache(1) # Calls after the 1st return the cached result.
578+
@functools.wraps(func)
579+
def wrapper():
580+
retval = func()
581+
_log.log(logging.getLevelName(level.upper()), fmt, retval)
582+
return retval
583+
return wrapper
584+
585+
586+
@_log_and_cache_result("HOME=%s")
587+
def get_home():
593588
"""Find user's home directory if possible.
594589
Otherwise, returns None.
595590
@@ -620,9 +615,6 @@ def _create_tmp_config_dir():
620615
return configdir
621616

622617

623-
get_home = _wrap('$HOME=%s', _get_home, always=False)
624-
625-
626618
def _get_xdg_config_dir():
627619
"""
628620
Returns the XDG configuration directory, according to the `XDG
@@ -684,7 +676,8 @@ def _get_config_or_cache_dir(xdg_base):
684676
return _create_tmp_config_dir()
685677

686678

687-
def _get_configdir():
679+
@_log_and_cache_result("CONFIGDIR=%s")
680+
def get_configdir():
688681
"""
689682
Return the string representing the configuration directory.
690683
@@ -705,10 +698,9 @@ def _get_configdir():
705698
"""
706699
return _get_config_or_cache_dir(_get_xdg_config_dir())
707700

708-
get_configdir = _wrap('CONFIGDIR=%s', _get_configdir, always=False)
709-
710701

711-
def _get_cachedir():
702+
@_log_and_cache_result("CACHEDIR=%s")
703+
def get_cachedir():
712704
"""
713705
Return the location of the cache directory.
714706
@@ -717,8 +709,6 @@ def _get_cachedir():
717709
"""
718710
return _get_config_or_cache_dir(_get_xdg_cache_dir())
719711

720-
get_cachedir = _wrap('CACHEDIR=%s', _get_cachedir, always=False)
721-
722712

723713
def _decode_filesystem_path(path):
724714
if not isinstance(path, str):
@@ -770,14 +760,12 @@ def _get_data_path():
770760
raise RuntimeError('Could not find the matplotlib data files')
771761

772762

773-
def _get_data_path_cached():
763+
@_log_and_cache_result('rcParams["datapath"]=%s')
764+
def get_data_path():
774765
if defaultParams['datapath'][0] is None:
775766
defaultParams['datapath'][0] = _get_data_path()
776767
return defaultParams['datapath'][0]
777768

778-
get_data_path = _wrap('matplotlib data path %s', _get_data_path_cached,
779-
always=False)
780-
781769

782770
def get_py2exe_datafiles():
783771
datapath = get_data_path()
@@ -835,7 +823,7 @@ def gen_candidates():
835823
else:
836824
yield matplotlibrc
837825
yield os.path.join(matplotlibrc, 'matplotlibrc')
838-
yield os.path.join(_get_configdir(), 'matplotlibrc')
826+
yield os.path.join(get_configdir(), 'matplotlibrc')
839827
yield os.path.join(get_data_path(), 'matplotlibrc')
840828

841829
for fname in gen_candidates():

lib/matplotlib/style/core.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828

2929
BASE_LIBRARY_PATH = os.path.join(mpl.get_data_path(), 'stylelib')
3030
# Users may want multiple library paths, so store a list of paths.
31-
USER_LIBRARY_PATHS = [os.path.join(mpl._get_configdir(), 'stylelib')]
31+
USER_LIBRARY_PATHS = [os.path.join(mpl.get_configdir(), 'stylelib')]
3232
STYLE_EXTENSION = 'mplstyle'
3333
STYLE_FILE_PATTERN = re.compile(r'([\S]+).%s$' % STYLE_EXTENSION)
3434

lib/matplotlib/testing/compare.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
from matplotlib.compat import subprocess
2424
from matplotlib.testing.exceptions import ImageComparisonFailure
2525
from matplotlib import _png
26-
from matplotlib import _get_cachedir
2726
from matplotlib import cbook
2827

2928
__all__ = ['compare_float', 'compare_images', 'comparable_formats']
@@ -82,7 +81,7 @@ def compare_float(expected, actual, relTol=None, absTol=None):
8281

8382

8483
def get_cache_dir():
85-
cachedir = _get_cachedir()
84+
cachedir = matplotlib.get_cachedir()
8685
if cachedir is None:
8786
raise RuntimeError('Could not find a suitable configuration directory')
8887
cache_dir = os.path.join(cachedir, 'test_cache')
@@ -272,7 +271,7 @@ def convert(filename, cache):
272271
created file.
273272
274273
If *cache* is True, the result of the conversion is cached in
275-
`matplotlib._get_cachedir() + '/test_cache/'`. The caching is based
274+
`matplotlib.get_cachedir() + '/test_cache/'`. The caching is based
276275
on a hash of the exact contents of the input file. The is no limit
277276
on the size of the cache, so it may need to be manually cleared
278277
periodically.

0 commit comments

Comments
 (0)