From dbb715d28fe9833595dcd515e2852e1fa74da39f 2013-11-04 23:12:36 From: Paul Ivanov Date: 2013-11-04 23:12:36 Subject: [PATCH] Merge pull request #4457 from takluyver/ipython-dir-default Use ~/.ipython as default config directory --- diff --git a/IPython/core/usage.py b/IPython/core/usage.py index 5c1cb7b..bce4ea6 100644 --- a/IPython/core/usage.py +++ b/IPython/core/usage.py @@ -45,10 +45,9 @@ Usage This file is typically installed in the `IPYTHONDIR` directory, and there is a separate configuration directory for each profile. The default profile - directory will be located in $IPYTHONDIR/profile_default. For Linux users, - IPYTHONDIR defaults to `$HOME/.config/ipython`, and for other Unix systems - to `$HOME/.ipython`. For Windows users, $HOME resolves to C:\\Documents - and Settings\\YourUserName in most instances. + directory will be located in $IPYTHONDIR/profile_default. IPYTHONDIR + defaults to to `$HOME/.ipython`. For Windows users, $HOME resolves to + C:\\Documents and Settings\\YourUserName in most instances. To initialize a profile with the default configuration file, do:: diff --git a/IPython/utils/path.py b/IPython/utils/path.py index 80fc654..023c1c5 100644 --- a/IPython/utils/path.py +++ b/IPython/utils/path.py @@ -273,7 +273,6 @@ def get_ipython_dir(): ipdir_def = '.ipython' - xdg_def = 'ipython' home_dir = get_home_dir() xdg_dir = get_xdg_dir() @@ -284,20 +283,21 @@ def get_ipython_dir(): 'Please use IPYTHONDIR instead.') ipdir = env.get('IPYTHONDIR', env.get('IPYTHON_DIR', None)) if ipdir is None: - # not set explicitly, use XDG_CONFIG_HOME or HOME - home_ipdir = pjoin(home_dir, ipdir_def) + # not set explicitly, use ~/.ipython + ipdir = pjoin(home_dir, ipdir_def) if xdg_dir: - # use XDG, as long as the user isn't already - # using $HOME/.ipython and *not* XDG/ipython - - xdg_ipdir = pjoin(xdg_dir, xdg_def) - - if _writable_dir(xdg_ipdir) or not _writable_dir(home_ipdir): - ipdir = xdg_ipdir - - if ipdir is None: - # not using XDG - ipdir = home_ipdir + # Several IPython versions (up to 1.x) defaulted to .config/ipython + # on Linux. We have decided to go back to using .ipython everywhere + xdg_ipdir = pjoin(xdg_dir, 'ipython') + + if _writable_dir(xdg_ipdir): + cu = compress_user + if os.path.exists(ipdir): + warnings.warn(('Ignoring {0} in favour of {1}. Remove {0} ' + 'to get rid of this message').format(cu(xdg_ipdir), cu(ipdir))) + else: + warnings.warn('Moving {0} to {1}'.format(cu(xdg_ipdir), cu(ipdir))) + os.rename(xdg_ipdir, ipdir) ipdir = os.path.normpath(os.path.expanduser(ipdir)) diff --git a/IPython/utils/tests/test_path.py b/IPython/utils/tests/test_path.py index 182193f..897d015 100644 --- a/IPython/utils/tests/test_path.py +++ b/IPython/utils/tests/test_path.py @@ -14,10 +14,12 @@ from __future__ import with_statement +import errno import os import shutil import sys import tempfile +import warnings from contextlib import contextmanager from os.path import join, abspath, split @@ -128,6 +130,15 @@ def teardown_environment(): # Build decorator that uses the setup_environment/setup_environment with_environment = with_setup(setup_environment, teardown_environment) +@contextmanager +def patch_get_home_dir(dirpath): + orig_get_home_dir = path.get_home_dir + path.get_home_dir = lambda : dirpath + try: + yield + finally: + path.get_home_dir = orig_get_home_dir + @skip_if_not_win32 @with_environment def test_get_home_dir_1(): @@ -225,74 +236,96 @@ def test_get_ipython_dir_1(): @with_environment def test_get_ipython_dir_2(): """test_get_ipython_dir_2, Testcase to see if we can call get_ipython_dir without Exceptions.""" - path.get_home_dir = lambda : "someplace" - path.get_xdg_dir = lambda : None - path._writable_dir = lambda path: True - os.name = "posix" - env.pop('IPYTHON_DIR', None) - env.pop('IPYTHONDIR', None) - env.pop('XDG_CONFIG_HOME', None) - ipdir = path.get_ipython_dir() - nt.assert_equal(ipdir, os.path.join("someplace", ".ipython")) + with patch_get_home_dir('someplace'): + path.get_xdg_dir = lambda : None + path._writable_dir = lambda path: True + os.name = "posix" + env.pop('IPYTHON_DIR', None) + env.pop('IPYTHONDIR', None) + env.pop('XDG_CONFIG_HOME', None) + ipdir = path.get_ipython_dir() + nt.assert_equal(ipdir, os.path.join("someplace", ".ipython")) @with_environment def test_get_ipython_dir_3(): - """test_get_ipython_dir_3, use XDG if defined, and .ipython doesn't exist.""" - path.get_home_dir = lambda : "someplace" - path._writable_dir = lambda path: True - os.name = "posix" - env.pop('IPYTHON_DIR', None) - env.pop('IPYTHONDIR', None) - env['XDG_CONFIG_HOME'] = XDG_TEST_DIR - ipdir = path.get_ipython_dir() - if sys.platform == "darwin": - expected = os.path.join("someplace", ".ipython") - else: - expected = os.path.join(XDG_TEST_DIR, "ipython") - nt.assert_equal(ipdir, expected) + """test_get_ipython_dir_3, move XDG if defined, and .ipython doesn't exist.""" + tmphome = TemporaryDirectory() + try: + with patch_get_home_dir(tmphome.name): + os.name = "posix" + env.pop('IPYTHON_DIR', None) + env.pop('IPYTHONDIR', None) + env['XDG_CONFIG_HOME'] = XDG_TEST_DIR + + with warnings.catch_warnings(record=True) as w: + ipdir = path.get_ipython_dir() + + nt.assert_equal(ipdir, os.path.join(tmphome.name, ".ipython")) + if sys.platform != 'darwin': + nt.assert_equal(len(w), 1) + nt.assert_in('Moving', str(w[0])) + finally: + tmphome.cleanup() @with_environment def test_get_ipython_dir_4(): - """test_get_ipython_dir_4, use XDG if both exist.""" - path.get_home_dir = lambda : HOME_TEST_DIR - os.name = "posix" - env.pop('IPYTHON_DIR', None) - env.pop('IPYTHONDIR', None) - env['XDG_CONFIG_HOME'] = XDG_TEST_DIR - ipdir = path.get_ipython_dir() - if sys.platform == "darwin": - expected = os.path.join(HOME_TEST_DIR, ".ipython") - else: - expected = os.path.join(XDG_TEST_DIR, "ipython") - nt.assert_equal(ipdir, expected) + """test_get_ipython_dir_4, warn if XDG and home both exist.""" + with patch_get_home_dir(HOME_TEST_DIR): + os.name = "posix" + env.pop('IPYTHON_DIR', None) + env.pop('IPYTHONDIR', None) + env['XDG_CONFIG_HOME'] = XDG_TEST_DIR + try: + os.mkdir(os.path.join(XDG_TEST_DIR, 'ipython')) + except OSError as e: + if e.errno != errno.EEXIST: + raise + + with warnings.catch_warnings(record=True) as w: + ipdir = path.get_ipython_dir() + + nt.assert_equal(ipdir, os.path.join(HOME_TEST_DIR, ".ipython")) + if sys.platform != 'darwin': + nt.assert_equal(len(w), 1) + nt.assert_in('Ignoring', str(w[0])) @with_environment def test_get_ipython_dir_5(): """test_get_ipython_dir_5, use .ipython if exists and XDG defined, but doesn't exist.""" - path.get_home_dir = lambda : HOME_TEST_DIR - os.name = "posix" - env.pop('IPYTHON_DIR', None) - env.pop('IPYTHONDIR', None) - env['XDG_CONFIG_HOME'] = XDG_TEST_DIR - os.rmdir(os.path.join(XDG_TEST_DIR, 'ipython')) - ipdir = path.get_ipython_dir() - nt.assert_equal(ipdir, IP_TEST_DIR) + with patch_get_home_dir(HOME_TEST_DIR): + os.name = "posix" + env.pop('IPYTHON_DIR', None) + env.pop('IPYTHONDIR', None) + env['XDG_CONFIG_HOME'] = XDG_TEST_DIR + try: + os.rmdir(os.path.join(XDG_TEST_DIR, 'ipython')) + except OSError as e: + if e.errno != errno.ENOENT: + raise + ipdir = path.get_ipython_dir() + nt.assert_equal(ipdir, IP_TEST_DIR) @with_environment def test_get_ipython_dir_6(): - """test_get_ipython_dir_6, use XDG if defined and neither exist.""" + """test_get_ipython_dir_6, use home over XDG if defined and neither exist.""" xdg = os.path.join(HOME_TEST_DIR, 'somexdg') os.mkdir(xdg) shutil.rmtree(os.path.join(HOME_TEST_DIR, '.ipython')) - path.get_home_dir = lambda : HOME_TEST_DIR - path.get_xdg_dir = lambda : xdg - os.name = "posix" - env.pop('IPYTHON_DIR', None) - env.pop('IPYTHONDIR', None) - env.pop('XDG_CONFIG_HOME', None) - xdg_ipdir = os.path.join(xdg, "ipython") - ipdir = path.get_ipython_dir() - nt.assert_equal(ipdir, xdg_ipdir) + with patch_get_home_dir(HOME_TEST_DIR): + orig_get_xdg_dir = path.get_xdg_dir + path.get_xdg_dir = lambda : xdg + try: + os.name = "posix" + env.pop('IPYTHON_DIR', None) + env.pop('IPYTHONDIR', None) + env.pop('XDG_CONFIG_HOME', None) + with warnings.catch_warnings(record=True) as w: + ipdir = path.get_ipython_dir() + + nt.assert_equal(ipdir, os.path.join(HOME_TEST_DIR, '.ipython')) + nt.assert_equal(len(w), 0) + finally: + path.get_xdg_dir = orig_get_xdg_dir @with_environment def test_get_ipython_dir_7(): diff --git a/docs/man/ipython.1 b/docs/man/ipython.1 index a017fb0..0f4a191 100644 --- a/docs/man/ipython.1 +++ b/docs/man/ipython.1 @@ -45,8 +45,7 @@ or 'ipython \-\-help\-all' for all available command\(hyline options. \fIIPYTHONDIR\fR .RS 4 This is the location where IPython stores all its configuration files. The default -on most platforms is $HOME/.ipython, but on Linux IPython respects the XDG config -specification, which will put IPYTHONDIR in $HOME/.config/ipython by default. +is $HOME/.ipython if IPYTHONDIR is not defined. You can see the computed value of IPYTHONDIR with `ipython locate`. diff --git a/docs/source/config/old.rst b/docs/source/config/old.rst index 7a64ed9..da67569 100644 --- a/docs/source/config/old.rst +++ b/docs/source/config/old.rst @@ -12,8 +12,7 @@ Outdated configuration information that might still be useful This section will help you set various things in your environment for your IPython sessions to be as efficient as possible. All of IPython's configuration information, along with several example files, is stored -in a directory named by default $HOME/.config/ipython if $HOME/.config -exists (Linux), or $HOME/.ipython as a secondary default. You can change this by +in a directory named by default $HOME/.ipython. You can change this by defining the environment variable IPYTHONDIR, or at runtime with the command line option -ipythondir. diff --git a/docs/source/config/overview.rst b/docs/source/config/overview.rst index 6152866..413cb00 100644 --- a/docs/source/config/overview.rst +++ b/docs/source/config/overview.rst @@ -270,21 +270,17 @@ following algorithm: * If not, the value returned by :func:`IPython.utils.path.get_ipython_dir` is used. This function will first look at the :envvar:`IPYTHONDIR` - environment variable and then default to a platform-specific default. + environment variable and then default to :file:`~/.ipython`. Historical support for the :envvar:`IPYTHON_DIR` environment variable will be removed in a future release. -On posix systems (Linux, Unix, etc.), IPython respects the ``$XDG_CONFIG_HOME`` -part of the `XDG Base Directory`_ specification. If ``$XDG_CONFIG_HOME`` is -defined and exists ( ``XDG_CONFIG_HOME`` has a default interpretation of -:file:`$HOME/.config`), then IPython's config directory will be located in -:file:`$XDG_CONFIG_HOME/ipython`. If users still have an IPython directory -in :file:`$HOME/.ipython`, then that will be used. in preference to the -system default. +For most users, the configuration directory will be :file:`~/.ipython`. -For most users, the default value will simply be something like -:file:`$HOME/.config/ipython` on Linux, or :file:`$HOME/.ipython` -elsewhere. +Previous versions of IPython on Linux would use the XDG config directory, +creating :file:`~/.config/ipython` by default. We have decided to go +back to :file:`~/.ipython` for consistency among systems. IPython will +issue a warning if it finds the XDG location, and will move it to the new +location if there isn't already a directory there. Once the location of the IPython directory has been determined, you need to know which profile you are using. For users with a single configuration, this will @@ -531,5 +527,3 @@ Here are the main requirements we wanted our configuration system to have: dynamic language and you don't always know everything that needs to be configured when a program starts. - -.. _`XDG Base Directory`: http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html diff --git a/docs/source/interactive/reference.rst b/docs/source/interactive/reference.rst index 9955a67..08db774 100644 --- a/docs/source/interactive/reference.rst +++ b/docs/source/interactive/reference.rst @@ -26,10 +26,10 @@ the command line, simply because they are not practical here. Look into your configuration files for details on those. There are separate configuration files for each profile, and the files look like "ipython_config.py" or "ipython_config_.py". Profile directories look like -"profile_profilename" and are typically installed in the IPYTHONDIR directory. -For Linux users, this will be $HOME/.config/ipython, and for other users it -will be $HOME/.ipython. For Windows users, $HOME resolves to C:\\Documents and -Settings\\YourUserName in most instances. +"profile_profilename" and are typically installed in the IPYTHONDIR directory, +which defaults to :file:`$HOME/.ipython`. For Windows users, :envvar:`HOME` +resolves to :file:`C:\\Documents and Settings\\YourUserName` in most +instances. Eventloop integration diff --git a/docs/source/interactive/tutorial.rst b/docs/source/interactive/tutorial.rst index 4ee52fd..363e48f 100644 --- a/docs/source/interactive/tutorial.rst +++ b/docs/source/interactive/tutorial.rst @@ -181,8 +181,7 @@ Configuration Much of IPython can be tweaked through :ref:`configuration `. To get started, use the command ``ipython profile create`` to produce the default config files. These will be placed in -:file:`~/.ipython/profile_default` or -:file:`~/.config/ipython/profile_default`, and contain comments explaining +:file:`~/.ipython/profile_default`, and contain comments explaining what the various options do. Profiles allow you to use IPython for different tasks, keeping separate config diff --git a/docs/source/parallel/parallel_process.rst b/docs/source/parallel/parallel_process.rst index d908459..1a93609 100644 --- a/docs/source/parallel/parallel_process.rst +++ b/docs/source/parallel/parallel_process.rst @@ -627,7 +627,7 @@ the engines. .. note:: The log output of ipcontroller above shows you where the json files were written. - They will be in :file:`~/.ipython` (or :file:`~/.config/ipython`) under + They will be in :file:`~/.ipython` under :file:`profile_default/security/ipcontroller-engine.json` 3. start the engines, using the connection file:: @@ -644,7 +644,7 @@ A couple of notes: then you need not specify its path directly, only the profile (assumes the path exists, otherwise you must create it first):: - [engine.host.n] $ scp controller.host:.ipython/profile_default/security/ipcontroller-engine.json ~/.config/ipython/profile_ssh/security/ + [engine.host.n] $ scp controller.host:.ipython/profile_default/security/ipcontroller-engine.json ~/.ipython/profile_ssh/security/ [engine.host.n] $ ipengine --profile=ssh Of course, if you fetch the file into the default profile, no arguments must be passed to diff --git a/docs/source/whatsnew/pr/no-xdg.rst b/docs/source/whatsnew/pr/no-xdg.rst new file mode 100644 index 0000000..06e73cc --- /dev/null +++ b/docs/source/whatsnew/pr/no-xdg.rst @@ -0,0 +1,5 @@ +* Previous versions of IPython on Linux would use the XDG config directory, + creating :file:`~/.config/ipython` by default. We have decided to go + back to :file:`~/.ipython` for consistency among systems. IPython will + issue a warning if it finds the XDG location, and will move it to the new + location if there isn't already a directory there.