Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Use a subdirectory of $XDG_CONFIG_HOME instead of ~/.matplotlibrc on Linux #454

Merged
merged 2 commits into from

6 participants

@mdboom
Owner

The latest version of the XDG basedir spec seems to recommend this.

http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html

Is this something we want to do? Will it only add to confusion for platforms that don't use this (presumably Mac OS-X)?

@fperez
Collaborator

FWIW, here's what we've done on this topic:

http://ipython.org/ipython-doc/dev/config/overview.html#configuration-file-location

It is indeed a little more information to provide, since osx is now different than linux, but people felt that following the xdg standard was a good idea.

@jkseppan
Collaborator

On Mac OS X, this kind of files tend to go in ~/Library/Application Support. I think that directory is strictly meant for applications, not libraries, so e.g. a hypothetical application named Pylab.app might place its files in ~/Library/Application Support/org.scipy.Pylab.

Even more strictly, application configuration should go in ~/Library/Preferences and be managed with the appropriate OS X APIs.

http://developer.apple.com/library/mac/#documentation/FileManagement/Conceptual/FileSystemProgrammingGUide/MacOSXDirectories/MacOSXDirectories.html

A lot of common Unix programs do keep their configuration in dotfiles in the home directory, though.

@WeatherGod
Collaborator

Could we have it so that if that environment variable is set, then use it. Otherwise, stick with the old location for now?

However, there might be some issues if a person already has an rc file in both locations, how do we know which one to use?

@pelson
Collaborator

Sounds like a good idea. Shall we get on and implement it? Anyone keen to give it a shot?

@mdboom
Owner

+1 on doing this. This has obviously just fallen through the cracks. I think we should plan this for the next major release (I've added a milestone).

@eheintzmann

According to XDG Base directory specification:
User data should go into $XDG_DATA_HOME (which default to ~/.local/share),
user preferences should go into $XDG_CONFIG_HOME (which default to ~/.config)
and cached data should go to $XDG_CACHE_HOME (which default to ~/.cache).
More details at :
http://ploum.net/post/207-modify-your-application-to-use-xdg-folders
https://live.gnome.org/GnomeGoals/XDGConfigFolders

Full specification can be found at:
http://standards.freedesktop.org/basedir-spec/latest/

The Freedesktop.org XDG base directory specification have good de facto adoption.
It has been adopted by:

I think that matplotlib should use same locations than the vast majority of Desktop environment and applications.

There are real advantages of following this specification :

  • a lot less cluttered $HOME
  • Make backups a lot more safer and easier. Backuping your $XDG_DATA_HOME along with your files is enough (or just excluding $XDG_CACHE_HOME)
  • A lot easier to reset a default configuration if you want/need it (and without any risk to loose informations). Even for the software itself could choose to reset $XDG_CONFIG_HOME if needed.
  • Avoid some strange bugs that happens because you had a old version of some configuration file
  • A lot more of flexibility and portability because no path are hardcoded.
@mdboom
Owner

@eheintzmann, @fperez: Anyone willing to test this, to make sure the migration path works? I'd like to get this in for 1.3. If a ~/.matplotlib/matplotlibrc file already exists on Linux, it will continue to use that, but display a big fat warning. I think this is better than just going on to use the new location and having users scratch their heads as to why their config appears to be "missing". It's just a matter of moving it to the new location (.config/matplotlib) and it should be quiet, though.

@WeatherGod: I deliberately didn't change behavior on OS-X. We could consider ~/Library/Applications etc., but I think that should be a follow-on PR.

@pelson
Collaborator

@mdboom - the warning was good. But I wonder if we can do this migration automatically? Especially given that the only files in my .matplotlib folder are automatically generated caches anyway.

@mdboom
Owner

Most of the files in ~/.matplotlib are auto-generated caches, but the most important one, matplotlibrc is not.

With this PR, all of the cache files will automatically (and silently) start being created and used in ~/.cache/matplotlib. It is only when the human-written matplotlibrc file exists in the old location that this warning will be generated. I'm not a fan of automatically moving the config file. I, for example, have the config files I care about as symlinks into a git repository so they get version controlled and backed up. If this file were to get moved, it might escape that process, (moving a symlink is probably fine, but we can't assume everyone works the way I do) and I would only get the warning that it was moved the first time (which might be easy to miss).

@pelson
Collaborator

It is only when the human-written matplotlibrc file exists in the old location that this warning will be generated.

That was not my experience (I didn't look at the code, just ran it...). I'm happy with the approach you discuss though.

lib/matplotlib/__init__.py
((14 lines not shown))
+ p = os.path.join(h, '.matplotlib')
if os.path.exists(p):
@pelson Collaborator
pelson added a note

This is the bit which causes the warning for people with a cache but not necessarily a matplotlibrc.

@mdboom Owner
mdboom added a note

Ah, I see. I'll fix that up.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@mdboom mdboom merged commit f870c35 into matplotlib:master

1 check passed

Details default The Travis CI build passed
@herr-biber herr-biber referenced this pull request from a commit in herr-biber/matplotlib
@herr-biber herr-biber Fix paths in doc which are searched for matplotlibrc (XDG).
See pull request #454 (3ac8144)
82837cb
@mdboom mdboom deleted the mdboom:xdg_config branch
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on May 22, 2013
  1. @mdboom
Commits on May 24, 2013
  1. @mdboom
This page is out of date. Refresh to see the latest.
View
5 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
+ <http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html>`_.
+
* The following items that were deprecated in version 1.2 or earlier
have now been removed completely.
View
8 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 <customizing-with-matplotlibrc-files>` 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 <customizing-with-matplotlibrc-files>` file. To
+locate your :file:`.matplotlib/` directory, use
+:func:`matplotlib.get_configdir`::
>>> import matplotlib as mpl
>>> mpl.get_configdir()
View
28 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<matplotlibrc-sample>`.
View
9 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
+<http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html>`
+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.
View
177 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
+ <http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html>`_.
+ """
+ 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
+ <http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html>`_.
"""
+ 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
View
10 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
View
10 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.
View
8 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)
View
6 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.
Something went wrong with that request. Please try again.