##// END OF EJS Templates
Move IPython specific functions from utils to IPython.paths
Thomas Kluyver -
Show More
@@ -0,0 +1,149 b''
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
119
120 def get_security_file(filename, profile='default'):
121 """Return the absolute path of a security file given by filename and profile
122
123 This allows users and developers to find security files without
124 knowledge of the IPython directory structure. The search path
125 will be ['.', profile.security_dir]
126
127 Parameters
128 ----------
129
130 filename : str
131 The file to be found. If it is passed as an absolute path, it will
132 simply be returned.
133 profile : str [default: 'default']
134 The name of the profile to search. Leaving this unspecified
135 The file to be found. If it is passed as an absolute path, fname will
136 simply be returned.
137
138 Returns
139 -------
140 Raises :exc:`IOError` if file not found or returns absolute path to file.
141 """
142 # import here, because profiledir also imports from utils.path
143 from IPython.core.profiledir import ProfileDir
144 try:
145 pd = ProfileDir.find_profile_dir_by_name(get_ipython_dir(), profile)
146 except Exception:
147 # will raise ProfileDirError if no such profile
148 raise IOError("Profile %r not found")
149 return filefind(filename, ['.', pd.security_dir])
@@ -1,558 +1,455 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 Utilities for path handling.
3 Utilities for path handling.
4 """
4 """
5
5
6 # Copyright (c) IPython Development Team.
6 # Copyright (c) IPython Development Team.
7 # Distributed under the terms of the Modified BSD License.
7 # Distributed under the terms of the Modified BSD License.
8
8
9 import os
9 import os
10 import sys
10 import sys
11 import errno
11 import errno
12 import shutil
12 import shutil
13 import random
13 import random
14 import tempfile
14 import tempfile
15 import glob
15 import glob
16 from warnings import warn
16 from warnings import warn
17 from hashlib import md5
17 from hashlib import md5
18
18
19 import IPython
20 from IPython.testing.skipdoctest import skip_doctest
19 from IPython.testing.skipdoctest import skip_doctest
21 from IPython.utils.process import system
20 from IPython.utils.process import system
22 from IPython.utils.importstring import import_item
23 from IPython.utils import py3compat
21 from IPython.utils import py3compat
24 from IPython.utils.decorators import undoc
22 from IPython.utils.decorators import undoc
25
23
26 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
27 # Code
25 # Code
28 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
29
27
30 fs_encoding = sys.getfilesystemencoding()
28 fs_encoding = sys.getfilesystemencoding()
31
29
32 def _writable_dir(path):
30 def _writable_dir(path):
33 """Whether `path` is a directory, to which the user has write access."""
31 """Whether `path` is a directory, to which the user has write access."""
34 return os.path.isdir(path) and os.access(path, os.W_OK)
32 return os.path.isdir(path) and os.access(path, os.W_OK)
35
33
36 if sys.platform == 'win32':
34 if sys.platform == 'win32':
37 @skip_doctest
35 @skip_doctest
38 def _get_long_path_name(path):
36 def _get_long_path_name(path):
39 """Get a long path name (expand ~) on Windows using ctypes.
37 """Get a long path name (expand ~) on Windows using ctypes.
40
38
41 Examples
39 Examples
42 --------
40 --------
43
41
44 >>> get_long_path_name('c:\\docume~1')
42 >>> get_long_path_name('c:\\docume~1')
45 u'c:\\\\Documents and Settings'
43 u'c:\\\\Documents and Settings'
46
44
47 """
45 """
48 try:
46 try:
49 import ctypes
47 import ctypes
50 except ImportError:
48 except ImportError:
51 raise ImportError('you need to have ctypes installed for this to work')
49 raise ImportError('you need to have ctypes installed for this to work')
52 _GetLongPathName = ctypes.windll.kernel32.GetLongPathNameW
50 _GetLongPathName = ctypes.windll.kernel32.GetLongPathNameW
53 _GetLongPathName.argtypes = [ctypes.c_wchar_p, ctypes.c_wchar_p,
51 _GetLongPathName.argtypes = [ctypes.c_wchar_p, ctypes.c_wchar_p,
54 ctypes.c_uint ]
52 ctypes.c_uint ]
55
53
56 buf = ctypes.create_unicode_buffer(260)
54 buf = ctypes.create_unicode_buffer(260)
57 rv = _GetLongPathName(path, buf, 260)
55 rv = _GetLongPathName(path, buf, 260)
58 if rv == 0 or rv > 260:
56 if rv == 0 or rv > 260:
59 return path
57 return path
60 else:
58 else:
61 return buf.value
59 return buf.value
62 else:
60 else:
63 def _get_long_path_name(path):
61 def _get_long_path_name(path):
64 """Dummy no-op."""
62 """Dummy no-op."""
65 return path
63 return path
66
64
67
65
68
66
69 def get_long_path_name(path):
67 def get_long_path_name(path):
70 """Expand a path into its long form.
68 """Expand a path into its long form.
71
69
72 On Windows this expands any ~ in the paths. On other platforms, it is
70 On Windows this expands any ~ in the paths. On other platforms, it is
73 a null operation.
71 a null operation.
74 """
72 """
75 return _get_long_path_name(path)
73 return _get_long_path_name(path)
76
74
77
75
78 def unquote_filename(name, win32=(sys.platform=='win32')):
76 def unquote_filename(name, win32=(sys.platform=='win32')):
79 """ On Windows, remove leading and trailing quotes from filenames.
77 """ On Windows, remove leading and trailing quotes from filenames.
80 """
78 """
81 if win32:
79 if win32:
82 if name.startswith(("'", '"')) and name.endswith(("'", '"')):
80 if name.startswith(("'", '"')) and name.endswith(("'", '"')):
83 name = name[1:-1]
81 name = name[1:-1]
84 return name
82 return name
85
83
86 def compress_user(path):
84 def compress_user(path):
87 """Reverse of :func:`os.path.expanduser`
85 """Reverse of :func:`os.path.expanduser`
88 """
86 """
89 home = os.path.expanduser('~')
87 home = os.path.expanduser('~')
90 if path.startswith(home):
88 if path.startswith(home):
91 path = "~" + path[len(home):]
89 path = "~" + path[len(home):]
92 return path
90 return path
93
91
94 def get_py_filename(name, force_win32=None):
92 def get_py_filename(name, force_win32=None):
95 """Return a valid python filename in the current directory.
93 """Return a valid python filename in the current directory.
96
94
97 If the given name is not a file, it adds '.py' and searches again.
95 If the given name is not a file, it adds '.py' and searches again.
98 Raises IOError with an informative message if the file isn't found.
96 Raises IOError with an informative message if the file isn't found.
99
97
100 On Windows, apply Windows semantics to the filename. In particular, remove
98 On Windows, apply Windows semantics to the filename. In particular, remove
101 any quoting that has been applied to it. This option can be forced for
99 any quoting that has been applied to it. This option can be forced for
102 testing purposes.
100 testing purposes.
103 """
101 """
104
102
105 name = os.path.expanduser(name)
103 name = os.path.expanduser(name)
106 if force_win32 is None:
104 if force_win32 is None:
107 win32 = (sys.platform == 'win32')
105 win32 = (sys.platform == 'win32')
108 else:
106 else:
109 win32 = force_win32
107 win32 = force_win32
110 name = unquote_filename(name, win32=win32)
108 name = unquote_filename(name, win32=win32)
111 if not os.path.isfile(name) and not name.endswith('.py'):
109 if not os.path.isfile(name) and not name.endswith('.py'):
112 name += '.py'
110 name += '.py'
113 if os.path.isfile(name):
111 if os.path.isfile(name):
114 return name
112 return name
115 else:
113 else:
116 raise IOError('File `%r` not found.' % name)
114 raise IOError('File `%r` not found.' % name)
117
115
118
116
119 def filefind(filename, path_dirs=None):
117 def filefind(filename, path_dirs=None):
120 """Find a file by looking through a sequence of paths.
118 """Find a file by looking through a sequence of paths.
121
119
122 This iterates through a sequence of paths looking for a file and returns
120 This iterates through a sequence of paths looking for a file and returns
123 the full, absolute path of the first occurence of the file. If no set of
121 the full, absolute path of the first occurence of the file. If no set of
124 path dirs is given, the filename is tested as is, after running through
122 path dirs is given, the filename is tested as is, after running through
125 :func:`expandvars` and :func:`expanduser`. Thus a simple call::
123 :func:`expandvars` and :func:`expanduser`. Thus a simple call::
126
124
127 filefind('myfile.txt')
125 filefind('myfile.txt')
128
126
129 will find the file in the current working dir, but::
127 will find the file in the current working dir, but::
130
128
131 filefind('~/myfile.txt')
129 filefind('~/myfile.txt')
132
130
133 Will find the file in the users home directory. This function does not
131 Will find the file in the users home directory. This function does not
134 automatically try any paths, such as the cwd or the user's home directory.
132 automatically try any paths, such as the cwd or the user's home directory.
135
133
136 Parameters
134 Parameters
137 ----------
135 ----------
138 filename : str
136 filename : str
139 The filename to look for.
137 The filename to look for.
140 path_dirs : str, None or sequence of str
138 path_dirs : str, None or sequence of str
141 The sequence of paths to look for the file in. If None, the filename
139 The sequence of paths to look for the file in. If None, the filename
142 need to be absolute or be in the cwd. If a string, the string is
140 need to be absolute or be in the cwd. If a string, the string is
143 put into a sequence and the searched. If a sequence, walk through
141 put into a sequence and the searched. If a sequence, walk through
144 each element and join with ``filename``, calling :func:`expandvars`
142 each element and join with ``filename``, calling :func:`expandvars`
145 and :func:`expanduser` before testing for existence.
143 and :func:`expanduser` before testing for existence.
146
144
147 Returns
145 Returns
148 -------
146 -------
149 Raises :exc:`IOError` or returns absolute path to file.
147 Raises :exc:`IOError` or returns absolute path to file.
150 """
148 """
151
149
152 # If paths are quoted, abspath gets confused, strip them...
150 # If paths are quoted, abspath gets confused, strip them...
153 filename = filename.strip('"').strip("'")
151 filename = filename.strip('"').strip("'")
154 # If the input is an absolute path, just check it exists
152 # If the input is an absolute path, just check it exists
155 if os.path.isabs(filename) and os.path.isfile(filename):
153 if os.path.isabs(filename) and os.path.isfile(filename):
156 return filename
154 return filename
157
155
158 if path_dirs is None:
156 if path_dirs is None:
159 path_dirs = ("",)
157 path_dirs = ("",)
160 elif isinstance(path_dirs, py3compat.string_types):
158 elif isinstance(path_dirs, py3compat.string_types):
161 path_dirs = (path_dirs,)
159 path_dirs = (path_dirs,)
162
160
163 for path in path_dirs:
161 for path in path_dirs:
164 if path == '.': path = py3compat.getcwd()
162 if path == '.': path = py3compat.getcwd()
165 testname = expand_path(os.path.join(path, filename))
163 testname = expand_path(os.path.join(path, filename))
166 if os.path.isfile(testname):
164 if os.path.isfile(testname):
167 return os.path.abspath(testname)
165 return os.path.abspath(testname)
168
166
169 raise IOError("File %r does not exist in any of the search paths: %r" %
167 raise IOError("File %r does not exist in any of the search paths: %r" %
170 (filename, path_dirs) )
168 (filename, path_dirs) )
171
169
172
170
173 class HomeDirError(Exception):
171 class HomeDirError(Exception):
174 pass
172 pass
175
173
176
174
177 def get_home_dir(require_writable=False):
175 def get_home_dir(require_writable=False):
178 """Return the 'home' directory, as a unicode string.
176 """Return the 'home' directory, as a unicode string.
179
177
180 Uses os.path.expanduser('~'), and checks for writability.
178 Uses os.path.expanduser('~'), and checks for writability.
181
179
182 See stdlib docs for how this is determined.
180 See stdlib docs for how this is determined.
183 $HOME is first priority on *ALL* platforms.
181 $HOME is first priority on *ALL* platforms.
184
182
185 Parameters
183 Parameters
186 ----------
184 ----------
187
185
188 require_writable : bool [default: False]
186 require_writable : bool [default: False]
189 if True:
187 if True:
190 guarantees the return value is a writable directory, otherwise
188 guarantees the return value is a writable directory, otherwise
191 raises HomeDirError
189 raises HomeDirError
192 if False:
190 if False:
193 The path is resolved, but it is not guaranteed to exist or be writable.
191 The path is resolved, but it is not guaranteed to exist or be writable.
194 """
192 """
195
193
196 homedir = os.path.expanduser('~')
194 homedir = os.path.expanduser('~')
197 # Next line will make things work even when /home/ is a symlink to
195 # Next line will make things work even when /home/ is a symlink to
198 # /usr/home as it is on FreeBSD, for example
196 # /usr/home as it is on FreeBSD, for example
199 homedir = os.path.realpath(homedir)
197 homedir = os.path.realpath(homedir)
200
198
201 if not _writable_dir(homedir) and os.name == 'nt':
199 if not _writable_dir(homedir) and os.name == 'nt':
202 # expanduser failed, use the registry to get the 'My Documents' folder.
200 # expanduser failed, use the registry to get the 'My Documents' folder.
203 try:
201 try:
204 try:
202 try:
205 import winreg as wreg # Py 3
203 import winreg as wreg # Py 3
206 except ImportError:
204 except ImportError:
207 import _winreg as wreg # Py 2
205 import _winreg as wreg # Py 2
208 key = wreg.OpenKey(
206 key = wreg.OpenKey(
209 wreg.HKEY_CURRENT_USER,
207 wreg.HKEY_CURRENT_USER,
210 "Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders"
208 "Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders"
211 )
209 )
212 homedir = wreg.QueryValueEx(key,'Personal')[0]
210 homedir = wreg.QueryValueEx(key,'Personal')[0]
213 key.Close()
211 key.Close()
214 except:
212 except:
215 pass
213 pass
216
214
217 if (not require_writable) or _writable_dir(homedir):
215 if (not require_writable) or _writable_dir(homedir):
218 return py3compat.cast_unicode(homedir, fs_encoding)
216 return py3compat.cast_unicode(homedir, fs_encoding)
219 else:
217 else:
220 raise HomeDirError('%s is not a writable dir, '
218 raise HomeDirError('%s is not a writable dir, '
221 'set $HOME environment variable to override' % homedir)
219 'set $HOME environment variable to override' % homedir)
222
220
223 def get_xdg_dir():
221 def get_xdg_dir():
224 """Return the XDG_CONFIG_HOME, if it is defined and exists, else None.
222 """Return the XDG_CONFIG_HOME, if it is defined and exists, else None.
225
223
226 This is only for non-OS X posix (Linux,Unix,etc.) systems.
224 This is only for non-OS X posix (Linux,Unix,etc.) systems.
227 """
225 """
228
226
229 env = os.environ
227 env = os.environ
230
228
231 if os.name == 'posix' and sys.platform != 'darwin':
229 if os.name == 'posix' and sys.platform != 'darwin':
232 # Linux, Unix, AIX, etc.
230 # Linux, Unix, AIX, etc.
233 # use ~/.config if empty OR not set
231 # use ~/.config if empty OR not set
234 xdg = env.get("XDG_CONFIG_HOME", None) or os.path.join(get_home_dir(), '.config')
232 xdg = env.get("XDG_CONFIG_HOME", None) or os.path.join(get_home_dir(), '.config')
235 if xdg and _writable_dir(xdg):
233 if xdg and _writable_dir(xdg):
236 return py3compat.cast_unicode(xdg, fs_encoding)
234 return py3compat.cast_unicode(xdg, fs_encoding)
237
235
238 return None
236 return None
239
237
240
238
241 def get_xdg_cache_dir():
239 def get_xdg_cache_dir():
242 """Return the XDG_CACHE_HOME, if it is defined and exists, else None.
240 """Return the XDG_CACHE_HOME, if it is defined and exists, else None.
243
241
244 This is only for non-OS X posix (Linux,Unix,etc.) systems.
242 This is only for non-OS X posix (Linux,Unix,etc.) systems.
245 """
243 """
246
244
247 env = os.environ
245 env = os.environ
248
246
249 if os.name == 'posix' and sys.platform != 'darwin':
247 if os.name == 'posix' and sys.platform != 'darwin':
250 # Linux, Unix, AIX, etc.
248 # Linux, Unix, AIX, etc.
251 # use ~/.cache if empty OR not set
249 # use ~/.cache if empty OR not set
252 xdg = env.get("XDG_CACHE_HOME", None) or os.path.join(get_home_dir(), '.cache')
250 xdg = env.get("XDG_CACHE_HOME", None) or os.path.join(get_home_dir(), '.cache')
253 if xdg and _writable_dir(xdg):
251 if xdg and _writable_dir(xdg):
254 return py3compat.cast_unicode(xdg, fs_encoding)
252 return py3compat.cast_unicode(xdg, fs_encoding)
255
253
256 return None
254 return None
257
255
258
256
257 @undoc
259 def get_ipython_dir():
258 def get_ipython_dir():
260 """Get the IPython directory for this platform and user.
259 warn("get_ipython_dir has moved to the IPython.paths module")
261
260 from IPython.paths import get_ipython_dir
262 This uses the logic in `get_home_dir` to find the home directory
263 and then adds .ipython to the end of the path.
264 """
265
266 env = os.environ
267 pjoin = os.path.join
268
269
270 ipdir_def = '.ipython'
271
272 home_dir = get_home_dir()
273 xdg_dir = get_xdg_dir()
274
275 # import pdb; pdb.set_trace() # dbg
276 if 'IPYTHON_DIR' in env:
277 warn('The environment variable IPYTHON_DIR is deprecated. '
278 'Please use IPYTHONDIR instead.')
279 ipdir = env.get('IPYTHONDIR', env.get('IPYTHON_DIR', None))
280 if ipdir is None:
281 # not set explicitly, use ~/.ipython
282 ipdir = pjoin(home_dir, ipdir_def)
283 if xdg_dir:
284 # Several IPython versions (up to 1.x) defaulted to .config/ipython
285 # on Linux. We have decided to go back to using .ipython everywhere
286 xdg_ipdir = pjoin(xdg_dir, 'ipython')
287
288 if _writable_dir(xdg_ipdir):
289 cu = compress_user
290 if os.path.exists(ipdir):
291 warn(('Ignoring {0} in favour of {1}. Remove {0} to '
292 'get rid of this message').format(cu(xdg_ipdir), cu(ipdir)))
293 elif os.path.islink(xdg_ipdir):
294 warn(('{0} is deprecated. Move link to {1} to '
295 'get rid of this message').format(cu(xdg_ipdir), cu(ipdir)))
296 else:
297 warn('Moving {0} to {1}'.format(cu(xdg_ipdir), cu(ipdir)))
298 shutil.move(xdg_ipdir, ipdir)
299
300 ipdir = os.path.normpath(os.path.expanduser(ipdir))
301
302 if os.path.exists(ipdir) and not _writable_dir(ipdir):
303 # ipdir exists, but is not writable
304 warn("IPython dir '{0}' is not a writable location,"
305 " using a temp directory.".format(ipdir))
306 ipdir = tempfile.mkdtemp()
307 elif not os.path.exists(ipdir):
308 parent = os.path.dirname(ipdir)
309 if not _writable_dir(parent):
310 # ipdir does not exist and parent isn't writable
311 warn("IPython parent '{0}' is not a writable location,"
312 " using a temp directory.".format(parent))
313 ipdir = tempfile.mkdtemp()
314
315 return py3compat.cast_unicode(ipdir, fs_encoding)
316
317
318 def get_ipython_cache_dir():
319 """Get the cache directory it is created if it does not exist."""
320 xdgdir = get_xdg_cache_dir()
321 if xdgdir is None:
322 return get_ipython_dir()
323 ipdir = os.path.join(xdgdir, "ipython")
324 if not os.path.exists(ipdir) and _writable_dir(xdgdir):
325 ensure_dir_exists(ipdir)
326 elif not _writable_dir(xdgdir):
327 return get_ipython_dir()
261 return get_ipython_dir()
328
262
329 return py3compat.cast_unicode(ipdir, fs_encoding)
263 @undoc
330
264 def get_ipython_cache_dir():
265 warn("get_ipython_cache_dir has moved to the IPython.paths module")
266 from IPython.paths import get_ipython_cache_dir
267 return get_ipython_cache_dir()
331
268
269 @undoc
332 def get_ipython_package_dir():
270 def get_ipython_package_dir():
333 """Get the base directory where IPython itself is installed."""
271 warn("get_ipython_package_dir has moved to the IPython.paths module")
334 ipdir = os.path.dirname(IPython.__file__)
272 from IPython.paths import get_ipython_package_dir
335 return py3compat.cast_unicode(ipdir, fs_encoding)
273 return get_ipython_package_dir()
336
337
274
275 @undoc
338 def get_ipython_module_path(module_str):
276 def get_ipython_module_path(module_str):
339 """Find the path to an IPython module in this version of IPython.
277 warn("get_ipython_module_path has moved to the IPython.paths module")
340
278 from IPython.paths import get_ipython_module_path
341 This will always find the version of the module that is in this importable
279 return get_ipython_module_path(module_str)
342 IPython package. This will always return the path to the ``.py``
343 version of the module.
344 """
345 if module_str == 'IPython':
346 return os.path.join(get_ipython_package_dir(), '__init__.py')
347 mod = import_item(module_str)
348 the_path = mod.__file__.replace('.pyc', '.py')
349 the_path = the_path.replace('.pyo', '.py')
350 return py3compat.cast_unicode(the_path, fs_encoding)
351
280
281 @undoc
352 def locate_profile(profile='default'):
282 def locate_profile(profile='default'):
353 """Find the path to the folder associated with a given profile.
283 warn("locate_profile has moved to the IPython.paths module")
354
284 from IPython.paths import locate_profile
355 I.e. find $IPYTHONDIR/profile_whatever.
285 return locate_profile(profile=profile)
356 """
357 from IPython.core.profiledir import ProfileDir, ProfileDirError
358 try:
359 pd = ProfileDir.find_profile_dir_by_name(get_ipython_dir(), profile)
360 except ProfileDirError:
361 # IOError makes more sense when people are expecting a path
362 raise IOError("Couldn't find profile %r" % profile)
363 return pd.location
364
286
365 def expand_path(s):
287 def expand_path(s):
366 """Expand $VARS and ~names in a string, like a shell
288 """Expand $VARS and ~names in a string, like a shell
367
289
368 :Examples:
290 :Examples:
369
291
370 In [2]: os.environ['FOO']='test'
292 In [2]: os.environ['FOO']='test'
371
293
372 In [3]: expand_path('variable FOO is $FOO')
294 In [3]: expand_path('variable FOO is $FOO')
373 Out[3]: 'variable FOO is test'
295 Out[3]: 'variable FOO is test'
374 """
296 """
375 # This is a pretty subtle hack. When expand user is given a UNC path
297 # This is a pretty subtle hack. When expand user is given a UNC path
376 # on Windows (\\server\share$\%username%), os.path.expandvars, removes
298 # on Windows (\\server\share$\%username%), os.path.expandvars, removes
377 # the $ to get (\\server\share\%username%). I think it considered $
299 # the $ to get (\\server\share\%username%). I think it considered $
378 # alone an empty var. But, we need the $ to remains there (it indicates
300 # alone an empty var. But, we need the $ to remains there (it indicates
379 # a hidden share).
301 # a hidden share).
380 if os.name=='nt':
302 if os.name=='nt':
381 s = s.replace('$\\', 'IPYTHON_TEMP')
303 s = s.replace('$\\', 'IPYTHON_TEMP')
382 s = os.path.expandvars(os.path.expanduser(s))
304 s = os.path.expandvars(os.path.expanduser(s))
383 if os.name=='nt':
305 if os.name=='nt':
384 s = s.replace('IPYTHON_TEMP', '$\\')
306 s = s.replace('IPYTHON_TEMP', '$\\')
385 return s
307 return s
386
308
387
309
388 def unescape_glob(string):
310 def unescape_glob(string):
389 """Unescape glob pattern in `string`."""
311 """Unescape glob pattern in `string`."""
390 def unescape(s):
312 def unescape(s):
391 for pattern in '*[]!?':
313 for pattern in '*[]!?':
392 s = s.replace(r'\{0}'.format(pattern), pattern)
314 s = s.replace(r'\{0}'.format(pattern), pattern)
393 return s
315 return s
394 return '\\'.join(map(unescape, string.split('\\\\')))
316 return '\\'.join(map(unescape, string.split('\\\\')))
395
317
396
318
397 def shellglob(args):
319 def shellglob(args):
398 """
320 """
399 Do glob expansion for each element in `args` and return a flattened list.
321 Do glob expansion for each element in `args` and return a flattened list.
400
322
401 Unmatched glob pattern will remain as-is in the returned list.
323 Unmatched glob pattern will remain as-is in the returned list.
402
324
403 """
325 """
404 expanded = []
326 expanded = []
405 # Do not unescape backslash in Windows as it is interpreted as
327 # Do not unescape backslash in Windows as it is interpreted as
406 # path separator:
328 # path separator:
407 unescape = unescape_glob if sys.platform != 'win32' else lambda x: x
329 unescape = unescape_glob if sys.platform != 'win32' else lambda x: x
408 for a in args:
330 for a in args:
409 expanded.extend(glob.glob(a) or [unescape(a)])
331 expanded.extend(glob.glob(a) or [unescape(a)])
410 return expanded
332 return expanded
411
333
412
334
413 def target_outdated(target,deps):
335 def target_outdated(target,deps):
414 """Determine whether a target is out of date.
336 """Determine whether a target is out of date.
415
337
416 target_outdated(target,deps) -> 1/0
338 target_outdated(target,deps) -> 1/0
417
339
418 deps: list of filenames which MUST exist.
340 deps: list of filenames which MUST exist.
419 target: single filename which may or may not exist.
341 target: single filename which may or may not exist.
420
342
421 If target doesn't exist or is older than any file listed in deps, return
343 If target doesn't exist or is older than any file listed in deps, return
422 true, otherwise return false.
344 true, otherwise return false.
423 """
345 """
424 try:
346 try:
425 target_time = os.path.getmtime(target)
347 target_time = os.path.getmtime(target)
426 except os.error:
348 except os.error:
427 return 1
349 return 1
428 for dep in deps:
350 for dep in deps:
429 dep_time = os.path.getmtime(dep)
351 dep_time = os.path.getmtime(dep)
430 if dep_time > target_time:
352 if dep_time > target_time:
431 #print "For target",target,"Dep failed:",dep # dbg
353 #print "For target",target,"Dep failed:",dep # dbg
432 #print "times (dep,tar):",dep_time,target_time # dbg
354 #print "times (dep,tar):",dep_time,target_time # dbg
433 return 1
355 return 1
434 return 0
356 return 0
435
357
436
358
437 def target_update(target,deps,cmd):
359 def target_update(target,deps,cmd):
438 """Update a target with a given command given a list of dependencies.
360 """Update a target with a given command given a list of dependencies.
439
361
440 target_update(target,deps,cmd) -> runs cmd if target is outdated.
362 target_update(target,deps,cmd) -> runs cmd if target is outdated.
441
363
442 This is just a wrapper around target_outdated() which calls the given
364 This is just a wrapper around target_outdated() which calls the given
443 command if target is outdated."""
365 command if target is outdated."""
444
366
445 if target_outdated(target,deps):
367 if target_outdated(target,deps):
446 system(cmd)
368 system(cmd)
447
369
448 @undoc
370 @undoc
449 def filehash(path):
371 def filehash(path):
450 """Make an MD5 hash of a file, ignoring any differences in line
372 """Make an MD5 hash of a file, ignoring any differences in line
451 ending characters."""
373 ending characters."""
452 warn("filehash() is deprecated")
374 warn("filehash() is deprecated")
453 with open(path, "rU") as f:
375 with open(path, "rU") as f:
454 return md5(py3compat.str_to_bytes(f.read())).hexdigest()
376 return md5(py3compat.str_to_bytes(f.read())).hexdigest()
455
377
378 @undoc
456 def get_security_file(filename, profile='default'):
379 def get_security_file(filename, profile='default'):
457 """Return the absolute path of a security file given by filename and profile
380 warn("get_security_file has moved to the IPython.paths module")
458
381 from IPython.paths import get_security_file
459 This allows users and developers to find security files without
382 return get_security_file(filename, profile=profile)
460 knowledge of the IPython directory structure. The search path
461 will be ['.', profile.security_dir]
462
463 Parameters
464 ----------
465
466 filename : str
467 The file to be found. If it is passed as an absolute path, it will
468 simply be returned.
469 profile : str [default: 'default']
470 The name of the profile to search. Leaving this unspecified
471 The file to be found. If it is passed as an absolute path, fname will
472 simply be returned.
473
474 Returns
475 -------
476 Raises :exc:`IOError` if file not found or returns absolute path to file.
477 """
478 # import here, because profiledir also imports from utils.path
479 from IPython.core.profiledir import ProfileDir
480 try:
481 pd = ProfileDir.find_profile_dir_by_name(get_ipython_dir(), profile)
482 except Exception:
483 # will raise ProfileDirError if no such profile
484 raise IOError("Profile %r not found")
485 return filefind(filename, ['.', pd.security_dir])
486
383
487
384
488 ENOLINK = 1998
385 ENOLINK = 1998
489
386
490 def link(src, dst):
387 def link(src, dst):
491 """Hard links ``src`` to ``dst``, returning 0 or errno.
388 """Hard links ``src`` to ``dst``, returning 0 or errno.
492
389
493 Note that the special errno ``ENOLINK`` will be returned if ``os.link`` isn't
390 Note that the special errno ``ENOLINK`` will be returned if ``os.link`` isn't
494 supported by the operating system.
391 supported by the operating system.
495 """
392 """
496
393
497 if not hasattr(os, "link"):
394 if not hasattr(os, "link"):
498 return ENOLINK
395 return ENOLINK
499 link_errno = 0
396 link_errno = 0
500 try:
397 try:
501 os.link(src, dst)
398 os.link(src, dst)
502 except OSError as e:
399 except OSError as e:
503 link_errno = e.errno
400 link_errno = e.errno
504 return link_errno
401 return link_errno
505
402
506
403
507 def link_or_copy(src, dst):
404 def link_or_copy(src, dst):
508 """Attempts to hardlink ``src`` to ``dst``, copying if the link fails.
405 """Attempts to hardlink ``src`` to ``dst``, copying if the link fails.
509
406
510 Attempts to maintain the semantics of ``shutil.copy``.
407 Attempts to maintain the semantics of ``shutil.copy``.
511
408
512 Because ``os.link`` does not overwrite files, a unique temporary file
409 Because ``os.link`` does not overwrite files, a unique temporary file
513 will be used if the target already exists, then that file will be moved
410 will be used if the target already exists, then that file will be moved
514 into place.
411 into place.
515 """
412 """
516
413
517 if os.path.isdir(dst):
414 if os.path.isdir(dst):
518 dst = os.path.join(dst, os.path.basename(src))
415 dst = os.path.join(dst, os.path.basename(src))
519
416
520 link_errno = link(src, dst)
417 link_errno = link(src, dst)
521 if link_errno == errno.EEXIST:
418 if link_errno == errno.EEXIST:
522 if os.stat(src).st_ino == os.stat(dst).st_ino:
419 if os.stat(src).st_ino == os.stat(dst).st_ino:
523 # dst is already a hard link to the correct file, so we don't need
420 # dst is already a hard link to the correct file, so we don't need
524 # to do anything else. If we try to link and rename the file
421 # to do anything else. If we try to link and rename the file
525 # anyway, we get duplicate files - see http://bugs.python.org/issue21876
422 # anyway, we get duplicate files - see http://bugs.python.org/issue21876
526 return
423 return
527
424
528 new_dst = dst + "-temp-%04X" %(random.randint(1, 16**4), )
425 new_dst = dst + "-temp-%04X" %(random.randint(1, 16**4), )
529 try:
426 try:
530 link_or_copy(src, new_dst)
427 link_or_copy(src, new_dst)
531 except:
428 except:
532 try:
429 try:
533 os.remove(new_dst)
430 os.remove(new_dst)
534 except OSError:
431 except OSError:
535 pass
432 pass
536 raise
433 raise
537 os.rename(new_dst, dst)
434 os.rename(new_dst, dst)
538 elif link_errno != 0:
435 elif link_errno != 0:
539 # Either link isn't supported, or the filesystem doesn't support
436 # Either link isn't supported, or the filesystem doesn't support
540 # linking, or 'src' and 'dst' are on different filesystems.
437 # linking, or 'src' and 'dst' are on different filesystems.
541 shutil.copy(src, dst)
438 shutil.copy(src, dst)
542
439
543 def ensure_dir_exists(path, mode=0o755):
440 def ensure_dir_exists(path, mode=0o755):
544 """ensure that a directory exists
441 """ensure that a directory exists
545
442
546 If it doesn't exist, try to create it and protect against a race condition
443 If it doesn't exist, try to create it and protect against a race condition
547 if another process is doing the same.
444 if another process is doing the same.
548
445
549 The default permissions are 755, which differ from os.makedirs default of 777.
446 The default permissions are 755, which differ from os.makedirs default of 777.
550 """
447 """
551 if not os.path.exists(path):
448 if not os.path.exists(path):
552 try:
449 try:
553 os.makedirs(path, mode=mode)
450 os.makedirs(path, mode=mode)
554 except OSError as e:
451 except OSError as e:
555 if e.errno != errno.EEXIST:
452 if e.errno != errno.EEXIST:
556 raise
453 raise
557 elif not os.path.isdir(path):
454 elif not os.path.isdir(path):
558 raise IOError("%r exists but is not a directory" % path)
455 raise IOError("%r exists but is not a directory" % path)
General Comments 0
You need to be logged in to leave comments. Login now