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