diff --git a/doc/api/api_changes.rst b/doc/api/api_changes.rst index 8be7932f23d3..1826e65c8082 100644 --- a/doc/api/api_changes.rst +++ b/doc/api/api_changes.rst @@ -17,6 +17,11 @@ For new features that were added to matplotlib, please see Changes in 1.3.x ================ +* On Linux, the user-specific `matplotlibrc` configuration file is now + located in `~/.config/matplotlib/matplotlibrc` to conform to the + `XDG Base Directory Specification + `_. + * The following items that were deprecated in version 1.2 or earlier have now been removed completely. diff --git a/doc/faq/troubleshooting_faq.rst b/doc/faq/troubleshooting_faq.rst index a8cc7646fef1..4fa757e21aa5 100644 --- a/doc/faq/troubleshooting_faq.rst +++ b/doc/faq/troubleshooting_faq.rst @@ -37,10 +37,10 @@ and printing the ``__file__`` attribute:: :file:`.matplotlib` directory location ====================================== -Each user has a :file:`.matplotlib/` directory which may contain a -:ref:`matplotlibrc ` file and various -caches to improve matplotlib's performance. To locate your :file:`.matplotlib/` -directory, use :func:`matplotlib.get_configdir`:: +Each user has a matplotlib configuration directory which may contain a +:ref:`matplotlibrc ` file. To +locate your :file:`.matplotlib/` directory, use +:func:`matplotlib.get_configdir`:: >>> import matplotlib as mpl >>> mpl.get_configdir() diff --git a/doc/users/customizing.rst b/doc/users/customizing.rst index de5716ac3ff1..035d8276e3e3 100644 --- a/doc/users/customizing.rst +++ b/doc/users/customizing.rst @@ -18,21 +18,31 @@ locations, in the following order: 1. :file:`matplotlibrc` in the current working directory, usually used for specific customizations that you do not want to apply elsewhere. -2. :file:`.matplotlib/matplotlibrc`, for the user's default customizations. See - :ref:`locating-matplotlib-config-dir`. -3. :file:`{INSTALL}/matplotlib/mpl-data/matplotlibrc`, where :file:`{INSTALL}` - is something like :file:`/usr/lib/python2.5/site-packages` on Linux, and - maybe :file:`C:\\Python25\\Lib\\site-packages` on Windows. Every time you - install matplotlib, this file will be overwritten, so if you want your - customizations to be saved, please move this file to your :file:`.matplotlib` - directory. + +2. It next looks in a user-specific place, depending on your platform: + + - On Linux, it looks in :file:`.config/matplotlib/matplotlibrc` (or + `$XDG_CONFIG_HOME/matplotlib/matplotlibrc` if you've customized + your environment. + + - On other platforms, it looks in :file:`.matplotlib/matplotlibrc`. + + See :ref:`locating-matplotlib-config-dir`. + +3. :file:`{INSTALL}/matplotlib/mpl-data/matplotlibrc`, where + :file:`{INSTALL}` is something like + :file:`/usr/lib/python2.5/site-packages` on Linux, and maybe + :file:`C:\\Python25\\Lib\\site-packages` on Windows. Every time you + install matplotlib, this file will be overwritten, so if you want + your customizations to be saved, please move this file to your + user-specific matplotlib directory. To display where the currently active :file:`matplotlibrc` file was loaded from, one can do the following:: >>> import matplotlib >>> matplotlib.matplotlib_fname() - '/home/foo/.matplotlib/matplotlibrc' + '/home/foo/.config/matplotlib/matplotlibrc' See below for a sample :ref:`matplotlibrc file`. diff --git a/doc/users/whats_new.rst b/doc/users/whats_new.rst index 0c2b2f908f86..30c2fb59dddf 100644 --- a/doc/users/whats_new.rst +++ b/doc/users/whats_new.rst @@ -66,6 +66,15 @@ animations as well as being fully interactive. Future versions of matplotlib will integrate this backend with the IPython notebook for a fully web browser based plotting frontend. +XDG base directory support +-------------------------- +On Linux, matplotlib now uses the `XDG base directory specification +` +to find the `matplotlibrc` configuration file. `matplotlibrc` should +now be kept in `~/.config/matplotlib`, rather than `~/.matplotlib`. If +your configuration is found in the old location, it will still be used, +but a warning will be displayed. + Path effects on lines --------------------- Thanks to Jae-Joon Lee, path effects now also work on plot lines. diff --git a/lib/matplotlib/__init__.py b/lib/matplotlib/__init__.py index c8d0eb1543c2..0b5a5d45596f 100644 --- a/lib/matplotlib/__init__.py +++ b/lib/matplotlib/__init__.py @@ -146,19 +146,6 @@ sys.argv = ['modpython'] -""" -Manage user customizations through a rc file. - -The default file location is given in the following order - - - environment variable MATPLOTLIBRC - - - HOME/.matplotlib/matplotlibrc if HOME is defined - - - PATH/matplotlibrc where PATH is the return value of - get_data_path() -""" - import sys, os, tempfile if sys.version_info[0] >= 3: @@ -525,21 +512,25 @@ def _create_tmp_config_dir(): get_home = verbose.wrap('$HOME=%s', _get_home, always=False) -def _get_configdir(): +def _get_xdg_config_dir(): """ - Return the string representing the configuration directory. + Returns the XDG configuration directory, according to the `XDG + base directory spec + `_. + """ + return os.environ.get('XDG_CONFIG_HOME', os.path.join(get_home(), '.config')) - The directory is chosen as follows: - 1. If the MPLCONFIGDIR environment variable is supplied, choose that. Else, - choose the '.matplotlib' subdirectory of the user's home directory (and - create it if necessary). - 2. If the chosen directory exists and is writable, use that as the - configuration directory. - 3. If possible, create a temporary directory, and use it as the - configuration directory. - 4. A writable directory could not be found or created; return None. +def _get_xdg_cache_dir(): + """ + Returns the XDG cache directory, according to the `XDG + base directory spec + `_. """ + return os.environ.get('XDG_CACHE_HOME', os.path.join(get_home(), '.cache')) + + +def _get_config_or_cache_dir(xdg_base): from matplotlib.cbook import mkdirs configdir = os.environ.get('MPLCONFIGDIR') @@ -547,28 +538,65 @@ def _get_configdir(): if not os.path.exists(configdir): from matplotlib.cbook import mkdirs mkdirs(configdir) + if not _is_writable_dir(configdir): return _create_tmp_config_dir() return configdir h = get_home() - if h is not None: - p = os.path.join(h, '.matplotlib') + p = os.path.join(h, '.matplotlib') + if (sys.platform.startswith('linux') and + not os.path.exists(p)): + p = _get_xdg_config_dir() - if os.path.exists(p): - if not _is_writable_dir(p): - return _create_tmp_config_dir() - else: - if not _is_writable_dir(h): - return _create_tmp_config_dir() - mkdirs(p) + if os.path.exists(p): + if not _is_writable_dir(p): + return _create_tmp_config_dir() + else: + if not _is_writable_dir(h): + return _create_tmp_config_dir() + mkdirs(p) + + return p + + +def _get_configdir(): + """ + Return the string representing the configuration directory. - return p + The directory is chosen as follows: + + 1. If the MPLCONFIGDIR environment variable is supplied, choose that. + + 2a. On Linux, if `$HOME/.matplotlib` exists, choose that, but warn that + that is the old location. Barring that, follow the XDG specification + and look first in `$XDG_CONFIG_HOME`, if defined, or `$HOME/.config`. + + 2b. On other platforms, choose `$HOME/.matplotlib`. + + 3. If the chosen directory exists and is writable, use that as the + configuration directory. + 4. If possible, create a temporary directory, and use it as the + configuration directory. + 5. A writable directory could not be found or created; return None. + """ + return _get_config_or_cache_dir(_get_xdg_config_dir()) - return _create_tmp_config_dir() get_configdir = verbose.wrap('CONFIGDIR=%s', _get_configdir, always=False) +def _get_cachedir(): + """ + Return the location of the cache directory. + + The procedure used to find the directory is the same as for + _get_config_dir, except using `$XDG_CONFIG_HOME`/`~/.cache` instead. + """ + return _get_config_or_cache_dir(_get_xdg_cache_dir()) + +get_cachedir = verbose.wrap('CACHEDIR=%s', _get_cachedir, always=False) + + def _get_data_path(): 'get the path to matplotlib data' @@ -643,50 +671,36 @@ def get_py2exe_datafiles(): def matplotlib_fname(): """ - Return the path to the rc file used by matplotlib. + Get the location of the config file. - Search order: + The file location is determined in the following order - * current working dir - * environ var MATPLOTLIBRC - * HOME/.matplotlib/matplotlibrc - * MATPLOTLIBDATA/matplotlibrc + - `$PWD/matplotlibrc` - """ - oldname = os.path.join(os.getcwd(), '.matplotlibrc') - if os.path.exists(oldname): - try: - shutil.move('.matplotlibrc', 'matplotlibrc') - except IOError as e: - warnings.warn('File could not be renamed: %s' % e) - else: - warnings.warn("""\ -Old rc filename ".matplotlibrc" found in working dir and and renamed to new - default rc file name "matplotlibrc" (no leading ".").""") - - home = get_home() - configdir = get_configdir() - if home: - oldname = os.path.join(home, '.matplotlibrc') - if os.path.exists(oldname): - if configdir is not None: - newname = os.path.join(configdir, 'matplotlibrc') - - try: - shutil.move(oldname, newname) - except IOError as e: - warnings.warn('File could not be renamed: %s' % e) - else: - warnings.warn("""\ -Old rc filename "%s" found and renamed to new default rc file name "%s".""" - % (oldname, newname)) - else: - warnings.warn("""\ -Could not rename old rc file "%s": a suitable configuration directory could not - be found.""" % oldname) + - environment variable `MATPLOTLIBRC` + + - `$MPLCONFIGDIR/matplotlib` + + - On Linux, + + - `$HOME/.matplotlib/matplotlibrc`, if it exists + - or `$XDG_CONFIG_HOME/matplotlib/matplotlibrc` (if + $XDG_CONFIG_HOME is defined) + + - or `$HOME/.config/matplotlib/matplotlibrc` (if + $XDG_CONFIG_HOME is not defined) + + - On other platforms, + + - `$HOME/.matplotlib/matplotlibrc` if `$HOME` is defined. + + - Lastly, it looks in `$MATPLOTLIBDATA/matplotlibrc` for a + system-defined copy. + """ fname = os.path.join(os.getcwd(), 'matplotlibrc') - if os.path.exists(fname): return fname + if os.path.exists(fname): + return fname if 'MATPLOTLIBRC' in os.environ: path = os.environ['MATPLOTLIBRC'] @@ -695,15 +709,28 @@ def matplotlib_fname(): if os.path.exists(fname): return fname + configdir = _get_configdir() if configdir is not None: fname = os.path.join(configdir, 'matplotlibrc') if os.path.exists(fname): + if (sys.platform.startswith('linux') and + fname == os.path.join( + get_home(), '.matplotlib', 'matplotlibrc')): + warnings.warn( + "Found matplotlib configuration in ~/.matplotlib. " + "To conform with the XDG base directory standard, " + "this configuration location has been deprecated " + "on Linux, and the new location is now %r. Please " + "move your configuration there to ensure that " + "matplotlib will continue to find it in the future." % + _get_xdg_config_dir()) return fname - path = get_data_path() # guaranteed to exist or raise + path = get_data_path() # guaranteed to exist or raise fname = os.path.join(path, 'matplotlibrc') if not os.path.exists(fname): warnings.warn('Could not find matplotlibrc; using defaults') + return fname diff --git a/lib/matplotlib/finance.py b/lib/matplotlib/finance.py index 991917fa609b..46588370615c 100644 --- a/lib/matplotlib/finance.py +++ b/lib/matplotlib/finance.py @@ -17,7 +17,7 @@ import numpy as np -from matplotlib import verbose, get_configdir +from matplotlib import verbose, get_cachedir from matplotlib.dates import date2num from matplotlib.cbook import iterable, mkdirs from matplotlib.collections import LineCollection, PolyCollection @@ -27,10 +27,10 @@ from matplotlib.transforms import Affine2D -configdir = get_configdir() +cachedir = get_cachedir() # cachedir will be None if there is no writable directory. -if configdir is not None: - cachedir = os.path.join(configdir, 'finance.cache') +if cachedir is not None: + cachedir = os.path.join(cachedir, 'finance.cache') else: # Should only happen in a restricted environment (such as Google App # Engine). Deal with this gracefully by not caching finance data. @@ -151,7 +151,7 @@ def fetch_historical_yahoo(ticker, date1, date2, cachename=None,dividends=False) cachename is the name of the local file cache. If None, will default to the md5 hash or the url (which incorporates the ticker and date range) - + set dividends=True to return dividends instead of price data. With this option set, parse functions will not work diff --git a/lib/matplotlib/font_manager.py b/lib/matplotlib/font_manager.py index ca49c3eb6668..c48f1c99e927 100644 --- a/lib/matplotlib/font_manager.py +++ b/lib/matplotlib/font_manager.py @@ -51,7 +51,7 @@ import matplotlib from matplotlib import afm from matplotlib import ft2font -from matplotlib import rcParams, get_configdir +from matplotlib import rcParams, get_cachedir from matplotlib.cbook import is_string_like import matplotlib.cbook as cbook from matplotlib.compat import subprocess @@ -1323,12 +1323,12 @@ def findfont(prop, fontext='ttf'): return result else: - configdir = get_configdir() - if configdir is not None: + cachedir = get_cachedir() + if cachedir is not None: if sys.version_info[0] >= 3: - _fmcache = os.path.join(configdir, 'fontList.py3k.cache') + _fmcache = os.path.join(cachedir, 'fontList.py3k.cache') else: - _fmcache = os.path.join(configdir, 'fontList.cache') + _fmcache = os.path.join(cachedir, 'fontList.cache') else: # Should only happen in a restricted environment (such as Google App # Engine). Deal with this gracefully by not caching fonts. diff --git a/lib/matplotlib/testing/compare.py b/lib/matplotlib/testing/compare.py index 3ef4faf10304..6732fefff454 100644 --- a/lib/matplotlib/testing/compare.py +++ b/lib/matplotlib/testing/compare.py @@ -11,7 +11,7 @@ from matplotlib.testing.noseclasses import ImageComparisonFailure from matplotlib.testing import image_util from matplotlib import _png -from matplotlib import _get_configdir +from matplotlib import _get_cachedir from matplotlib import cbook from distutils import version import hashlib @@ -100,10 +100,10 @@ def compare_float( expected, actual, relTol = None, absTol = None ): # parameters old and new to a list that can be passed to Popen to # convert files with that extension to png format. def get_cache_dir(): - configdir = _get_configdir() - if configdir is None: + cachedir = _get_cachedir() + if cachedir is None: raise RuntimeError('Could not find a suitable configuration directory') - cache_dir = os.path.join(configdir, 'test_cache') + cache_dir = os.path.join(cachedir, 'test_cache') if not os.path.exists(cache_dir): try: cbook.mkdirs(cache_dir) diff --git a/lib/matplotlib/texmanager.py b/lib/matplotlib/texmanager.py index e94838a8d765..6a43606c0bc5 100644 --- a/lib/matplotlib/texmanager.py +++ b/lib/matplotlib/texmanager.py @@ -94,9 +94,9 @@ class TexManager: oldpath = mpl.get_data_path() oldcache = os.path.join(oldpath, '.tex.cache') - configdir = mpl.get_configdir() - if configdir is not None: - texcache = os.path.join(configdir, 'tex.cache') + cachedir = mpl.get_cachedir() + if cachedir is not None: + texcache = os.path.join(cachedir, 'tex.cache') else: # Should only happen in a restricted environment (such as Google App # Engine). Deal with this gracefully by not creating a cache directory.