Skip to content

Commit 0efa52f

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 477c1dc commit 0efa52f

File tree

4 files changed

+43
-55
lines changed

4 files changed

+43
-55
lines changed

doc/devel/contributing.rst

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

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

491490
By default, `logging` displays all log messages at levels higher than
492-
`logging.WARNING` to `sys.stderr`.
491+
``logging.WARNING`` to `sys.stderr`.
493492

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

lib/matplotlib/__init__.py

Lines changed: 30 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,11 @@
120120
import tempfile
121121
import warnings
122122

123+
try:
124+
from functools import lru_cache
125+
except ImportError:
126+
from backports.functools_lru_cache import lru_cache
127+
123128
# cbook must import matplotlib only within function
124129
# definitions, so it is safe to import from it here.
125130
from . import cbook
@@ -385,31 +390,6 @@ def ge(self, level):
385390
return self.vald[self.level] >= self.vald[level]
386391

387392

388-
def _wrap(fmt, func, level='INFO', always=True):
389-
"""
390-
return a callable function that wraps func and reports its
391-
output through logger
392-
393-
if always is True, the report will occur on every function
394-
call; otherwise only on the first time the function is called
395-
"""
396-
assert callable(func)
397-
398-
def wrapper(*args, **kwargs):
399-
ret = func(*args, **kwargs)
400-
401-
if (always or not wrapper._spoke):
402-
lvl = logging.getLevelName(level.upper())
403-
_log.log(lvl, fmt % ret)
404-
spoke = True
405-
if not wrapper._spoke:
406-
wrapper._spoke = spoke
407-
return ret
408-
wrapper._spoke = False
409-
wrapper.__doc__ = func.__doc__
410-
return wrapper
411-
412-
413393
def checkdep_dvipng():
414394
try:
415395
s = subprocess.Popen([str('dvipng'), '-version'],
@@ -578,7 +558,21 @@ def checkdep_usetex(s):
578558
return flag
579559

580560

581-
def _get_home():
561+
def _log_result(fmt, level="INFO", func=None):
562+
if func is None:
563+
return functools.partial(_log_result, fmt, level)
564+
565+
@functools.wraps(func)
566+
def wrapper(*args, **kwargs):
567+
retval = func(*args, **kwargs)
568+
_log.log(logging.getLevelName(level.upper()), fmt, retval)
569+
return retval
570+
return wrapper
571+
572+
573+
@lru_cache(1)
574+
@_log_result("HOME=%s")
575+
def get_home():
582576
"""Find user's home directory if possible.
583577
Otherwise, returns None.
584578
@@ -608,9 +602,6 @@ def _create_tmp_config_dir():
608602
return configdir
609603

610604

611-
get_home = _wrap('$HOME=%s', _get_home, always=False)
612-
613-
614605
def _get_xdg_config_dir():
615606
"""
616607
Returns the XDG configuration directory, according to the `XDG
@@ -676,7 +667,9 @@ def _get_config_or_cache_dir(xdg_base):
676667
return _create_tmp_config_dir()
677668

678669

679-
def _get_configdir():
670+
@lru_cache(1)
671+
@_log_result("CONFIGDIR=%s")
672+
def get_configdir():
680673
"""
681674
Return the string representing the configuration directory.
682675
@@ -697,10 +690,10 @@ def _get_configdir():
697690
"""
698691
return _get_config_or_cache_dir(_get_xdg_config_dir())
699692

700-
get_configdir = _wrap('CONFIGDIR=%s', _get_configdir, always=False)
701-
702693

703-
def _get_cachedir():
694+
@lru_cache(1)
695+
@_log_result("CACHEDIR=%s")
696+
def get_cachedir():
704697
"""
705698
Return the location of the cache directory.
706699
@@ -709,8 +702,6 @@ def _get_cachedir():
709702
"""
710703
return _get_config_or_cache_dir(_get_xdg_cache_dir())
711704

712-
get_cachedir = _wrap('CACHEDIR=%s', _get_cachedir, always=False)
713-
714705

715706
def _decode_filesystem_path(path):
716707
if isinstance(path, bytes):
@@ -762,14 +753,13 @@ def _get_data_path():
762753
raise RuntimeError('Could not find the matplotlib data files')
763754

764755

765-
def _get_data_path_cached():
756+
@lru_cache(1)
757+
@_log_result('rcParams["datapath"]=%s')
758+
def get_data_path():
766759
if defaultParams['datapath'][0] is None:
767760
defaultParams['datapath'][0] = _get_data_path()
768761
return defaultParams['datapath'][0]
769762

770-
get_data_path = _wrap('matplotlib data path %s', _get_data_path_cached,
771-
always=False)
772-
773763

774764
def get_py2exe_datafiles():
775765
datapath = get_data_path()
@@ -826,7 +816,7 @@ def gen_candidates():
826816
else:
827817
yield matplotlibrc
828818
yield os.path.join(matplotlibrc, 'matplotlibrc')
829-
yield os.path.join(_get_configdir(), 'matplotlibrc')
819+
yield os.path.join(get_configdir(), 'matplotlibrc')
830820
yield os.path.join(get_data_path(), 'matplotlibrc')
831821

832822
for fname in gen_candidates():

lib/matplotlib/style/core.py

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

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

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')
@@ -273,7 +272,7 @@ def convert(filename, cache):
273272
created file.
274273
275274
If *cache* is True, the result of the conversion is cached in
276-
`matplotlib._get_cachedir() + '/test_cache/'`. The caching is based
275+
`matplotlib.get_cachedir() + '/test_cache/'`. The caching is based
277276
on a hash of the exact contents of the input file. The is no limit
278277
on the size of the cache, so it may need to be manually cleared
279278
periodically.

0 commit comments

Comments
 (0)