Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 2 commits into from May 28, 2013
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions doc/api/api_changes.rst
Expand Up @@ -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.

Expand Down
8 changes: 4 additions & 4 deletions doc/faq/troubleshooting_faq.rst
Expand Up @@ -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()
Expand Down
28 changes: 19 additions & 9 deletions doc/users/customizing.rst
Expand Up @@ -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>`.

Expand Down
9 changes: 9 additions & 0 deletions doc/users/whats_new.rst
Expand Up @@ -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.
Expand Down
175 changes: 102 additions & 73 deletions lib/matplotlib/__init__.py
Expand Up @@ -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:
Expand Down Expand Up @@ -525,50 +512,104 @@ 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')
if configdir is not None:
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')
if sys.platform.startswith('linux'):
xdg_path = os.path.join(xdg_base, 'matplotlib')

p = os.path.join(h, '.matplotlib')
if os.path.exists(p):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

if not _is_writable_dir(p):
return _create_tmp_config_dir()
warnings.warn(
"Found matplotlib configuration in ~/.matplotlib. "
"To conform with the XDG base directory standard, "
"this configuration directory 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." %
xdg_path)
else:
if not _is_writable_dir(h):
return _create_tmp_config_dir()
mkdirs(p)
p = xdg_path
else:
p = os.path.join(h, '.matplotlib')

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.

The directory is chosen as follows:

return p
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'

Expand Down Expand Up @@ -643,50 +684,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']
Expand All @@ -695,15 +722,17 @@ 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):
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


Expand Down
10 changes: 5 additions & 5 deletions lib/matplotlib/finance.py
Expand Up @@ -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
Expand All @@ -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.
Expand Down Expand Up @@ -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

Expand Down
10 changes: 5 additions & 5 deletions lib/matplotlib/font_manager.py
Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down