Skip to content

Commit da0b7fd

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 da0b7fd

File tree

3 files changed

+40
-52
lines changed

3 files changed

+40
-52
lines changed

doc/devel/contributing.rst

+10-11
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

+29-40
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,20 @@ 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+
@functools.wraps(func)
565+
def wrapper(*args, **kwargs):
566+
retval = func(*args, **kwargs)
567+
_log.log(logging.getLevelName(level.upper()), fmt, retval)
568+
return retval
569+
return wrapper
570+
571+
572+
@lru_cache(1)
573+
@_log_result("HOME=%s")
574+
def get_home():
582575
"""Find user's home directory if possible.
583576
Otherwise, returns None.
584577
@@ -608,9 +601,6 @@ def _create_tmp_config_dir():
608601
return configdir
609602

610603

611-
get_home = _wrap('$HOME=%s', _get_home, always=False)
612-
613-
614604
def _get_xdg_config_dir():
615605
"""
616606
Returns the XDG configuration directory, according to the `XDG
@@ -676,7 +666,9 @@ def _get_config_or_cache_dir(xdg_base):
676666
return _create_tmp_config_dir()
677667

678668

679-
def _get_configdir():
669+
@lru_cache(1)
670+
@_log_result("CONFIGDIR=%s")
671+
def get_configdir():
680672
"""
681673
Return the string representing the configuration directory.
682674
@@ -697,10 +689,10 @@ def _get_configdir():
697689
"""
698690
return _get_config_or_cache_dir(_get_xdg_config_dir())
699691

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

703-
def _get_cachedir():
693+
@lru_cache(1)
694+
@_log_result("CACHEDIR=%s")
695+
def get_cachedir():
704696
"""
705697
Return the location of the cache directory.
706698
@@ -709,8 +701,6 @@ def _get_cachedir():
709701
"""
710702
return _get_config_or_cache_dir(_get_xdg_cache_dir())
711703

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

715705
def _decode_filesystem_path(path):
716706
if isinstance(path, bytes):
@@ -762,14 +752,13 @@ def _get_data_path():
762752
raise RuntimeError('Could not find the matplotlib data files')
763753

764754

765-
def _get_data_path_cached():
755+
@lru_cache(1)
756+
@_log_result('rcParams["datapath"]=%s')
757+
def get_data_path():
766758
if defaultParams['datapath'][0] is None:
767759
defaultParams['datapath'][0] = _get_data_path()
768760
return defaultParams['datapath'][0]
769761

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

774763
def get_py2exe_datafiles():
775764
datapath = get_data_path()
@@ -826,7 +815,7 @@ def gen_candidates():
826815
else:
827816
yield matplotlibrc
828817
yield os.path.join(matplotlibrc, 'matplotlibrc')
829-
yield os.path.join(_get_configdir(), 'matplotlibrc')
818+
yield os.path.join(get_configdir(), 'matplotlibrc')
830819
yield os.path.join(get_data_path(), 'matplotlibrc')
831820

832821
for fname in gen_candidates():

lib/matplotlib/style/core.py

+1-1
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

0 commit comments

Comments
 (0)