Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit a6fd3b1

Browse files
committed
Merge pull request #8214 from takluyver/split-utils-path
Split IPython specific functions out of utils.path
2 parents 63f431a + 9eb0d29 commit a6fd3b1

6 files changed

Lines changed: 392 additions & 353 deletions

File tree

IPython/core/tests/test_paths.py

Lines changed: 246 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,246 @@
1+
from contextlib import contextmanager
2+
import errno
3+
import os
4+
import shutil
5+
import sys
6+
import tempfile
7+
import warnings
8+
9+
try:
10+
reload
11+
except NameError: # Python 3
12+
from imp import reload
13+
14+
from nose import with_setup
15+
import nose.tools as nt
16+
17+
import IPython
18+
from IPython import paths
19+
from IPython.testing.decorators import skip_win32
20+
from IPython.utils.tempdir import TemporaryDirectory
21+
22+
env = os.environ
23+
TMP_TEST_DIR = tempfile.mkdtemp()
24+
HOME_TEST_DIR = os.path.join(TMP_TEST_DIR, "home_test_dir")
25+
XDG_TEST_DIR = os.path.join(HOME_TEST_DIR, "xdg_test_dir")
26+
XDG_CACHE_DIR = os.path.join(HOME_TEST_DIR, "xdg_cache_dir")
27+
IP_TEST_DIR = os.path.join(HOME_TEST_DIR,'.ipython')
28+
29+
def setup():
30+
"""Setup testenvironment for the module:
31+
32+
- Adds dummy home dir tree
33+
"""
34+
# Do not mask exceptions here. In particular, catching WindowsError is a
35+
# problem because that exception is only defined on Windows...
36+
os.makedirs(IP_TEST_DIR)
37+
os.makedirs(os.path.join(XDG_TEST_DIR, 'ipython'))
38+
os.makedirs(os.path.join(XDG_CACHE_DIR, 'ipython'))
39+
40+
41+
def teardown():
42+
"""Teardown testenvironment for the module:
43+
44+
- Remove dummy home dir tree
45+
"""
46+
# Note: we remove the parent test dir, which is the root of all test
47+
# subdirs we may have created. Use shutil instead of os.removedirs, so
48+
# that non-empty directories are all recursively removed.
49+
shutil.rmtree(TMP_TEST_DIR)
50+
51+
52+
def setup_environment():
53+
"""Setup testenvironment for some functions that are tested
54+
in this module. In particular this functions stores attributes
55+
and other things that we need to stub in some test functions.
56+
This needs to be done on a function level and not module level because
57+
each testfunction needs a pristine environment.
58+
"""
59+
global oldstuff, platformstuff
60+
oldstuff = (env.copy(), os.name, sys.platform, paths.get_home_dir, IPython.__file__, os.getcwd())
61+
62+
def teardown_environment():
63+
"""Restore things that were remembered by the setup_environment function
64+
"""
65+
(oldenv, os.name, sys.platform, paths.get_home_dir, IPython.__file__, old_wd) = oldstuff
66+
os.chdir(old_wd)
67+
reload(paths)
68+
69+
for key in list(env):
70+
if key not in oldenv:
71+
del env[key]
72+
env.update(oldenv)
73+
if hasattr(sys, 'frozen'):
74+
del sys.frozen
75+
76+
# Build decorator that uses the setup_environment/setup_environment
77+
with_environment = with_setup(setup_environment, teardown_environment)
78+
79+
@contextmanager
80+
def patch_get_home_dir(dirpath):
81+
orig_get_home_dir = paths.get_home_dir
82+
paths.get_home_dir = lambda : dirpath
83+
try:
84+
yield
85+
finally:
86+
paths.get_home_dir = orig_get_home_dir
87+
88+
89+
@with_environment
90+
def test_get_ipython_dir_1():
91+
"""test_get_ipython_dir_1, Testcase to see if we can call get_ipython_dir without Exceptions."""
92+
env_ipdir = os.path.join("someplace", ".ipython")
93+
paths._writable_dir = lambda path: True
94+
env['IPYTHONDIR'] = env_ipdir
95+
ipdir = paths.get_ipython_dir()
96+
nt.assert_equal(ipdir, env_ipdir)
97+
98+
99+
@with_environment
100+
def test_get_ipython_dir_2():
101+
"""test_get_ipython_dir_2, Testcase to see if we can call get_ipython_dir without Exceptions."""
102+
with patch_get_home_dir('someplace'):
103+
paths.get_xdg_dir = lambda : None
104+
paths._writable_dir = lambda path: True
105+
os.name = "posix"
106+
env.pop('IPYTHON_DIR', None)
107+
env.pop('IPYTHONDIR', None)
108+
env.pop('XDG_CONFIG_HOME', None)
109+
ipdir = paths.get_ipython_dir()
110+
nt.assert_equal(ipdir, os.path.join("someplace", ".ipython"))
111+
112+
@with_environment
113+
def test_get_ipython_dir_3():
114+
"""test_get_ipython_dir_3, move XDG if defined, and .ipython doesn't exist."""
115+
tmphome = TemporaryDirectory()
116+
try:
117+
with patch_get_home_dir(tmphome.name):
118+
os.name = "posix"
119+
env.pop('IPYTHON_DIR', None)
120+
env.pop('IPYTHONDIR', None)
121+
env['XDG_CONFIG_HOME'] = XDG_TEST_DIR
122+
123+
with warnings.catch_warnings(record=True) as w:
124+
ipdir = paths.get_ipython_dir()
125+
126+
nt.assert_equal(ipdir, os.path.join(tmphome.name, ".ipython"))
127+
if sys.platform != 'darwin':
128+
nt.assert_equal(len(w), 1)
129+
nt.assert_in('Moving', str(w[0]))
130+
finally:
131+
tmphome.cleanup()
132+
133+
@with_environment
134+
def test_get_ipython_dir_4():
135+
"""test_get_ipython_dir_4, warn if XDG and home both exist."""
136+
with patch_get_home_dir(HOME_TEST_DIR):
137+
os.name = "posix"
138+
env.pop('IPYTHON_DIR', None)
139+
env.pop('IPYTHONDIR', None)
140+
env['XDG_CONFIG_HOME'] = XDG_TEST_DIR
141+
try:
142+
os.mkdir(os.path.join(XDG_TEST_DIR, 'ipython'))
143+
except OSError as e:
144+
if e.errno != errno.EEXIST:
145+
raise
146+
147+
with warnings.catch_warnings(record=True) as w:
148+
ipdir = paths.get_ipython_dir()
149+
150+
nt.assert_equal(ipdir, os.path.join(HOME_TEST_DIR, ".ipython"))
151+
if sys.platform != 'darwin':
152+
nt.assert_equal(len(w), 1)
153+
nt.assert_in('Ignoring', str(w[0]))
154+
155+
@with_environment
156+
def test_get_ipython_dir_5():
157+
"""test_get_ipython_dir_5, use .ipython if exists and XDG defined, but doesn't exist."""
158+
with patch_get_home_dir(HOME_TEST_DIR):
159+
os.name = "posix"
160+
env.pop('IPYTHON_DIR', None)
161+
env.pop('IPYTHONDIR', None)
162+
env['XDG_CONFIG_HOME'] = XDG_TEST_DIR
163+
try:
164+
os.rmdir(os.path.join(XDG_TEST_DIR, 'ipython'))
165+
except OSError as e:
166+
if e.errno != errno.ENOENT:
167+
raise
168+
ipdir = paths.get_ipython_dir()
169+
nt.assert_equal(ipdir, IP_TEST_DIR)
170+
171+
@with_environment
172+
def test_get_ipython_dir_6():
173+
"""test_get_ipython_dir_6, use home over XDG if defined and neither exist."""
174+
xdg = os.path.join(HOME_TEST_DIR, 'somexdg')
175+
os.mkdir(xdg)
176+
shutil.rmtree(os.path.join(HOME_TEST_DIR, '.ipython'))
177+
with patch_get_home_dir(HOME_TEST_DIR):
178+
orig_get_xdg_dir = paths.get_xdg_dir
179+
paths.get_xdg_dir = lambda : xdg
180+
try:
181+
os.name = "posix"
182+
env.pop('IPYTHON_DIR', None)
183+
env.pop('IPYTHONDIR', None)
184+
env.pop('XDG_CONFIG_HOME', None)
185+
with warnings.catch_warnings(record=True) as w:
186+
ipdir = paths.get_ipython_dir()
187+
188+
nt.assert_equal(ipdir, os.path.join(HOME_TEST_DIR, '.ipython'))
189+
nt.assert_equal(len(w), 0)
190+
finally:
191+
paths.get_xdg_dir = orig_get_xdg_dir
192+
193+
@with_environment
194+
def test_get_ipython_dir_7():
195+
"""test_get_ipython_dir_7, test home directory expansion on IPYTHONDIR"""
196+
paths._writable_dir = lambda path: True
197+
home_dir = os.path.normpath(os.path.expanduser('~'))
198+
env['IPYTHONDIR'] = os.path.join('~', 'somewhere')
199+
ipdir = paths.get_ipython_dir()
200+
nt.assert_equal(ipdir, os.path.join(home_dir, 'somewhere'))
201+
202+
@skip_win32
203+
@with_environment
204+
def test_get_ipython_dir_8():
205+
"""test_get_ipython_dir_8, test / home directory"""
206+
old = paths._writable_dir, paths.get_xdg_dir
207+
try:
208+
paths._writable_dir = lambda path: bool(path)
209+
paths.get_xdg_dir = lambda: None
210+
env.pop('IPYTHON_DIR', None)
211+
env.pop('IPYTHONDIR', None)
212+
env['HOME'] = '/'
213+
nt.assert_equal(paths.get_ipython_dir(), '/.ipython')
214+
finally:
215+
paths._writable_dir, paths.get_xdg_dir = old
216+
217+
218+
@with_environment
219+
def test_get_ipython_cache_dir():
220+
os.environ["HOME"] = HOME_TEST_DIR
221+
if os.name == 'posix' and sys.platform != 'darwin':
222+
# test default
223+
os.makedirs(os.path.join(HOME_TEST_DIR, ".cache"))
224+
os.environ.pop("XDG_CACHE_HOME", None)
225+
ipdir = paths.get_ipython_cache_dir()
226+
nt.assert_equal(os.path.join(HOME_TEST_DIR, ".cache", "ipython"),
227+
ipdir)
228+
nt.assert_true(os.path.isdir(ipdir))
229+
230+
# test env override
231+
os.environ["XDG_CACHE_HOME"] = XDG_CACHE_DIR
232+
ipdir = paths.get_ipython_cache_dir()
233+
nt.assert_true(os.path.isdir(ipdir))
234+
nt.assert_equal(ipdir, os.path.join(XDG_CACHE_DIR, "ipython"))
235+
else:
236+
nt.assert_equal(paths.get_ipython_cache_dir(),
237+
paths.get_ipython_dir())
238+
239+
def test_get_ipython_package_dir():
240+
ipdir = paths.get_ipython_package_dir()
241+
nt.assert_true(os.path.isdir(ipdir))
242+
243+
244+
def test_get_ipython_module_path():
245+
ipapp_path = paths.get_ipython_module_path('IPython.terminal.ipapp')
246+
nt.assert_true(os.path.isfile(ipapp_path))

IPython/paths.py

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
import os.path
2+
import shutil
3+
import tempfile
4+
from warnings import warn
5+
6+
import IPython
7+
from IPython.utils.importstring import import_item
8+
from IPython.utils.path import (
9+
get_home_dir, get_xdg_dir, get_xdg_cache_dir, compress_user, _writable_dir,
10+
ensure_dir_exists, fs_encoding, filefind
11+
)
12+
from IPython.utils import py3compat
13+
14+
def get_ipython_dir():
15+
"""Get the IPython directory for this platform and user.
16+
17+
This uses the logic in `get_home_dir` to find the home directory
18+
and then adds .ipython to the end of the path.
19+
"""
20+
21+
env = os.environ
22+
pjoin = os.path.join
23+
24+
25+
ipdir_def = '.ipython'
26+
27+
home_dir = get_home_dir()
28+
xdg_dir = get_xdg_dir()
29+
30+
# import pdb; pdb.set_trace() # dbg
31+
if 'IPYTHON_DIR' in env:
32+
warn('The environment variable IPYTHON_DIR is deprecated. '
33+
'Please use IPYTHONDIR instead.')
34+
ipdir = env.get('IPYTHONDIR', env.get('IPYTHON_DIR', None))
35+
if ipdir is None:
36+
# not set explicitly, use ~/.ipython
37+
ipdir = pjoin(home_dir, ipdir_def)
38+
if xdg_dir:
39+
# Several IPython versions (up to 1.x) defaulted to .config/ipython
40+
# on Linux. We have decided to go back to using .ipython everywhere
41+
xdg_ipdir = pjoin(xdg_dir, 'ipython')
42+
43+
if _writable_dir(xdg_ipdir):
44+
cu = compress_user
45+
if os.path.exists(ipdir):
46+
warn(('Ignoring {0} in favour of {1}. Remove {0} to '
47+
'get rid of this message').format(cu(xdg_ipdir), cu(ipdir)))
48+
elif os.path.islink(xdg_ipdir):
49+
warn(('{0} is deprecated. Move link to {1} to '
50+
'get rid of this message').format(cu(xdg_ipdir), cu(ipdir)))
51+
else:
52+
warn('Moving {0} to {1}'.format(cu(xdg_ipdir), cu(ipdir)))
53+
shutil.move(xdg_ipdir, ipdir)
54+
55+
ipdir = os.path.normpath(os.path.expanduser(ipdir))
56+
57+
if os.path.exists(ipdir) and not _writable_dir(ipdir):
58+
# ipdir exists, but is not writable
59+
warn("IPython dir '{0}' is not a writable location,"
60+
" using a temp directory.".format(ipdir))
61+
ipdir = tempfile.mkdtemp()
62+
elif not os.path.exists(ipdir):
63+
parent = os.path.dirname(ipdir)
64+
if not _writable_dir(parent):
65+
# ipdir does not exist and parent isn't writable
66+
warn("IPython parent '{0}' is not a writable location,"
67+
" using a temp directory.".format(parent))
68+
ipdir = tempfile.mkdtemp()
69+
70+
return py3compat.cast_unicode(ipdir, fs_encoding)
71+
72+
73+
def get_ipython_cache_dir():
74+
"""Get the cache directory it is created if it does not exist."""
75+
xdgdir = get_xdg_cache_dir()
76+
if xdgdir is None:
77+
return get_ipython_dir()
78+
ipdir = os.path.join(xdgdir, "ipython")
79+
if not os.path.exists(ipdir) and _writable_dir(xdgdir):
80+
ensure_dir_exists(ipdir)
81+
elif not _writable_dir(xdgdir):
82+
return get_ipython_dir()
83+
84+
return py3compat.cast_unicode(ipdir, fs_encoding)
85+
86+
87+
def get_ipython_package_dir():
88+
"""Get the base directory where IPython itself is installed."""
89+
ipdir = os.path.dirname(IPython.__file__)
90+
return py3compat.cast_unicode(ipdir, fs_encoding)
91+
92+
93+
def get_ipython_module_path(module_str):
94+
"""Find the path to an IPython module in this version of IPython.
95+
96+
This will always find the version of the module that is in this importable
97+
IPython package. This will always return the path to the ``.py``
98+
version of the module.
99+
"""
100+
if module_str == 'IPython':
101+
return os.path.join(get_ipython_package_dir(), '__init__.py')
102+
mod = import_item(module_str)
103+
the_path = mod.__file__.replace('.pyc', '.py')
104+
the_path = the_path.replace('.pyo', '.py')
105+
return py3compat.cast_unicode(the_path, fs_encoding)
106+
107+
def locate_profile(profile='default'):
108+
"""Find the path to the folder associated with a given profile.
109+
110+
I.e. find $IPYTHONDIR/profile_whatever.
111+
"""
112+
from IPython.core.profiledir import ProfileDir, ProfileDirError
113+
try:
114+
pd = ProfileDir.find_profile_dir_by_name(get_ipython_dir(), profile)
115+
except ProfileDirError:
116+
# IOError makes more sense when people are expecting a path
117+
raise IOError("Couldn't find profile %r" % profile)
118+
return pd.location

0 commit comments

Comments
 (0)