##// END OF EJS Templates
Do not unescape backslashes in Windows
Takafumi Arakaki -
Show More
@@ -1,491 +1,494 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 * First, check for frozen env in case of py2exe
176 * Otherwise, defer to os.path.expanduser('~')
176 * Otherwise, defer to os.path.expanduser('~')
177
177
178 See stdlib docs for how this is determined.
178 See stdlib docs for how this is determined.
179 $HOME is first priority on *ALL* platforms.
179 $HOME is first priority on *ALL* platforms.
180
180
181 Parameters
181 Parameters
182 ----------
182 ----------
183
183
184 require_writable : bool [default: False]
184 require_writable : bool [default: False]
185 if True:
185 if True:
186 guarantees the return value is a writable directory, otherwise
186 guarantees the return value is a writable directory, otherwise
187 raises HomeDirError
187 raises HomeDirError
188 if False:
188 if False:
189 The path is resolved, but it is not guaranteed to exist or be writable.
189 The path is resolved, but it is not guaranteed to exist or be writable.
190 """
190 """
191
191
192 # first, check py2exe distribution root directory for _ipython.
192 # first, check py2exe distribution root directory for _ipython.
193 # This overrides all. Normally does not exist.
193 # This overrides all. Normally does not exist.
194
194
195 if hasattr(sys, "frozen"): #Is frozen by py2exe
195 if hasattr(sys, "frozen"): #Is frozen by py2exe
196 if '\\library.zip\\' in IPython.__file__.lower():#libraries compressed to zip-file
196 if '\\library.zip\\' in IPython.__file__.lower():#libraries compressed to zip-file
197 root, rest = IPython.__file__.lower().split('library.zip')
197 root, rest = IPython.__file__.lower().split('library.zip')
198 else:
198 else:
199 root=os.path.join(os.path.split(IPython.__file__)[0],"../../")
199 root=os.path.join(os.path.split(IPython.__file__)[0],"../../")
200 root=os.path.abspath(root).rstrip('\\')
200 root=os.path.abspath(root).rstrip('\\')
201 if _writable_dir(os.path.join(root, '_ipython')):
201 if _writable_dir(os.path.join(root, '_ipython')):
202 os.environ["IPYKITROOT"] = root
202 os.environ["IPYKITROOT"] = root
203 return py3compat.cast_unicode(root, fs_encoding)
203 return py3compat.cast_unicode(root, fs_encoding)
204
204
205 homedir = os.path.expanduser('~')
205 homedir = os.path.expanduser('~')
206 # Next line will make things work even when /home/ is a symlink to
206 # Next line will make things work even when /home/ is a symlink to
207 # /usr/home as it is on FreeBSD, for example
207 # /usr/home as it is on FreeBSD, for example
208 homedir = os.path.realpath(homedir)
208 homedir = os.path.realpath(homedir)
209
209
210 if not _writable_dir(homedir) and os.name == 'nt':
210 if not _writable_dir(homedir) and os.name == 'nt':
211 # expanduser failed, use the registry to get the 'My Documents' folder.
211 # expanduser failed, use the registry to get the 'My Documents' folder.
212 try:
212 try:
213 import _winreg as wreg
213 import _winreg as wreg
214 key = wreg.OpenKey(
214 key = wreg.OpenKey(
215 wreg.HKEY_CURRENT_USER,
215 wreg.HKEY_CURRENT_USER,
216 "Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders"
216 "Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders"
217 )
217 )
218 homedir = wreg.QueryValueEx(key,'Personal')[0]
218 homedir = wreg.QueryValueEx(key,'Personal')[0]
219 key.Close()
219 key.Close()
220 except:
220 except:
221 pass
221 pass
222
222
223 if (not require_writable) or _writable_dir(homedir):
223 if (not require_writable) or _writable_dir(homedir):
224 return py3compat.cast_unicode(homedir, fs_encoding)
224 return py3compat.cast_unicode(homedir, fs_encoding)
225 else:
225 else:
226 raise HomeDirError('%s is not a writable dir, '
226 raise HomeDirError('%s is not a writable dir, '
227 'set $HOME environment variable to override' % homedir)
227 'set $HOME environment variable to override' % homedir)
228
228
229 def get_xdg_dir():
229 def get_xdg_dir():
230 """Return the XDG_CONFIG_HOME, if it is defined and exists, else None.
230 """Return the XDG_CONFIG_HOME, if it is defined and exists, else None.
231
231
232 This is only for non-OS X posix (Linux,Unix,etc.) systems.
232 This is only for non-OS X posix (Linux,Unix,etc.) systems.
233 """
233 """
234
234
235 env = os.environ
235 env = os.environ
236
236
237 if os.name == 'posix' and sys.platform != 'darwin':
237 if os.name == 'posix' and sys.platform != 'darwin':
238 # Linux, Unix, AIX, etc.
238 # Linux, Unix, AIX, etc.
239 # use ~/.config if empty OR not set
239 # use ~/.config if empty OR not set
240 xdg = env.get("XDG_CONFIG_HOME", None) or os.path.join(get_home_dir(), '.config')
240 xdg = env.get("XDG_CONFIG_HOME", None) or os.path.join(get_home_dir(), '.config')
241 if xdg and _writable_dir(xdg):
241 if xdg and _writable_dir(xdg):
242 return py3compat.cast_unicode(xdg, fs_encoding)
242 return py3compat.cast_unicode(xdg, fs_encoding)
243
243
244 return None
244 return None
245
245
246
246
247 def get_ipython_dir():
247 def get_ipython_dir():
248 """Get the IPython directory for this platform and user.
248 """Get the IPython directory for this platform and user.
249
249
250 This uses the logic in `get_home_dir` to find the home directory
250 This uses the logic in `get_home_dir` to find the home directory
251 and then adds .ipython to the end of the path.
251 and then adds .ipython to the end of the path.
252 """
252 """
253
253
254 env = os.environ
254 env = os.environ
255 pjoin = os.path.join
255 pjoin = os.path.join
256
256
257
257
258 ipdir_def = '.ipython'
258 ipdir_def = '.ipython'
259 xdg_def = 'ipython'
259 xdg_def = 'ipython'
260
260
261 home_dir = get_home_dir()
261 home_dir = get_home_dir()
262 xdg_dir = get_xdg_dir()
262 xdg_dir = get_xdg_dir()
263
263
264 # import pdb; pdb.set_trace() # dbg
264 # import pdb; pdb.set_trace() # dbg
265 if 'IPYTHON_DIR' in env:
265 if 'IPYTHON_DIR' in env:
266 warnings.warn('The environment variable IPYTHON_DIR is deprecated. '
266 warnings.warn('The environment variable IPYTHON_DIR is deprecated. '
267 'Please use IPYTHONDIR instead.')
267 'Please use IPYTHONDIR instead.')
268 ipdir = env.get('IPYTHONDIR', env.get('IPYTHON_DIR', None))
268 ipdir = env.get('IPYTHONDIR', env.get('IPYTHON_DIR', None))
269 if ipdir is None:
269 if ipdir is None:
270 # not set explicitly, use XDG_CONFIG_HOME or HOME
270 # not set explicitly, use XDG_CONFIG_HOME or HOME
271 home_ipdir = pjoin(home_dir, ipdir_def)
271 home_ipdir = pjoin(home_dir, ipdir_def)
272 if xdg_dir:
272 if xdg_dir:
273 # use XDG, as long as the user isn't already
273 # use XDG, as long as the user isn't already
274 # using $HOME/.ipython and *not* XDG/ipython
274 # using $HOME/.ipython and *not* XDG/ipython
275
275
276 xdg_ipdir = pjoin(xdg_dir, xdg_def)
276 xdg_ipdir = pjoin(xdg_dir, xdg_def)
277
277
278 if _writable_dir(xdg_ipdir) or not _writable_dir(home_ipdir):
278 if _writable_dir(xdg_ipdir) or not _writable_dir(home_ipdir):
279 ipdir = xdg_ipdir
279 ipdir = xdg_ipdir
280
280
281 if ipdir is None:
281 if ipdir is None:
282 # not using XDG
282 # not using XDG
283 ipdir = home_ipdir
283 ipdir = home_ipdir
284
284
285 ipdir = os.path.normpath(os.path.expanduser(ipdir))
285 ipdir = os.path.normpath(os.path.expanduser(ipdir))
286
286
287 if os.path.exists(ipdir) and not _writable_dir(ipdir):
287 if os.path.exists(ipdir) and not _writable_dir(ipdir):
288 # ipdir exists, but is not writable
288 # ipdir exists, but is not writable
289 warnings.warn("IPython dir '%s' is not a writable location,"
289 warnings.warn("IPython dir '%s' is not a writable location,"
290 " using a temp directory."%ipdir)
290 " using a temp directory."%ipdir)
291 ipdir = tempfile.mkdtemp()
291 ipdir = tempfile.mkdtemp()
292 elif not os.path.exists(ipdir):
292 elif not os.path.exists(ipdir):
293 parent = ipdir.rsplit(os.path.sep, 1)[0]
293 parent = ipdir.rsplit(os.path.sep, 1)[0]
294 if not _writable_dir(parent):
294 if not _writable_dir(parent):
295 # ipdir does not exist and parent isn't writable
295 # ipdir does not exist and parent isn't writable
296 warnings.warn("IPython parent '%s' is not a writable location,"
296 warnings.warn("IPython parent '%s' is not a writable location,"
297 " using a temp directory."%parent)
297 " using a temp directory."%parent)
298 ipdir = tempfile.mkdtemp()
298 ipdir = tempfile.mkdtemp()
299
299
300 return py3compat.cast_unicode(ipdir, fs_encoding)
300 return py3compat.cast_unicode(ipdir, fs_encoding)
301
301
302
302
303 def get_ipython_package_dir():
303 def get_ipython_package_dir():
304 """Get the base directory where IPython itself is installed."""
304 """Get the base directory where IPython itself is installed."""
305 ipdir = os.path.dirname(IPython.__file__)
305 ipdir = os.path.dirname(IPython.__file__)
306 return py3compat.cast_unicode(ipdir, fs_encoding)
306 return py3compat.cast_unicode(ipdir, fs_encoding)
307
307
308
308
309 def get_ipython_module_path(module_str):
309 def get_ipython_module_path(module_str):
310 """Find the path to an IPython module in this version of IPython.
310 """Find the path to an IPython module in this version of IPython.
311
311
312 This will always find the version of the module that is in this importable
312 This will always find the version of the module that is in this importable
313 IPython package. This will always return the path to the ``.py``
313 IPython package. This will always return the path to the ``.py``
314 version of the module.
314 version of the module.
315 """
315 """
316 if module_str == 'IPython':
316 if module_str == 'IPython':
317 return os.path.join(get_ipython_package_dir(), '__init__.py')
317 return os.path.join(get_ipython_package_dir(), '__init__.py')
318 mod = import_item(module_str)
318 mod = import_item(module_str)
319 the_path = mod.__file__.replace('.pyc', '.py')
319 the_path = mod.__file__.replace('.pyc', '.py')
320 the_path = the_path.replace('.pyo', '.py')
320 the_path = the_path.replace('.pyo', '.py')
321 return py3compat.cast_unicode(the_path, fs_encoding)
321 return py3compat.cast_unicode(the_path, fs_encoding)
322
322
323 def locate_profile(profile='default'):
323 def locate_profile(profile='default'):
324 """Find the path to the folder associated with a given profile.
324 """Find the path to the folder associated with a given profile.
325
325
326 I.e. find $IPYTHONDIR/profile_whatever.
326 I.e. find $IPYTHONDIR/profile_whatever.
327 """
327 """
328 from IPython.core.profiledir import ProfileDir, ProfileDirError
328 from IPython.core.profiledir import ProfileDir, ProfileDirError
329 try:
329 try:
330 pd = ProfileDir.find_profile_dir_by_name(get_ipython_dir(), profile)
330 pd = ProfileDir.find_profile_dir_by_name(get_ipython_dir(), profile)
331 except ProfileDirError:
331 except ProfileDirError:
332 # IOError makes more sense when people are expecting a path
332 # IOError makes more sense when people are expecting a path
333 raise IOError("Couldn't find profile %r" % profile)
333 raise IOError("Couldn't find profile %r" % profile)
334 return pd.location
334 return pd.location
335
335
336 def expand_path(s):
336 def expand_path(s):
337 """Expand $VARS and ~names in a string, like a shell
337 """Expand $VARS and ~names in a string, like a shell
338
338
339 :Examples:
339 :Examples:
340
340
341 In [2]: os.environ['FOO']='test'
341 In [2]: os.environ['FOO']='test'
342
342
343 In [3]: expand_path('variable FOO is $FOO')
343 In [3]: expand_path('variable FOO is $FOO')
344 Out[3]: 'variable FOO is test'
344 Out[3]: 'variable FOO is test'
345 """
345 """
346 # This is a pretty subtle hack. When expand user is given a UNC path
346 # This is a pretty subtle hack. When expand user is given a UNC path
347 # on Windows (\\server\share$\%username%), os.path.expandvars, removes
347 # on Windows (\\server\share$\%username%), os.path.expandvars, removes
348 # the $ to get (\\server\share\%username%). I think it considered $
348 # the $ to get (\\server\share\%username%). I think it considered $
349 # alone an empty var. But, we need the $ to remains there (it indicates
349 # alone an empty var. But, we need the $ to remains there (it indicates
350 # a hidden share).
350 # a hidden share).
351 if os.name=='nt':
351 if os.name=='nt':
352 s = s.replace('$\\', 'IPYTHON_TEMP')
352 s = s.replace('$\\', 'IPYTHON_TEMP')
353 s = os.path.expandvars(os.path.expanduser(s))
353 s = os.path.expandvars(os.path.expanduser(s))
354 if os.name=='nt':
354 if os.name=='nt':
355 s = s.replace('IPYTHON_TEMP', '$\\')
355 s = s.replace('IPYTHON_TEMP', '$\\')
356 return s
356 return s
357
357
358
358
359 def unescape_glob(string):
359 def unescape_glob(string):
360 """Unescape glob pattern in `string`."""
360 """Unescape glob pattern in `string`."""
361 def unescape(s):
361 def unescape(s):
362 for pattern in '*[]!?':
362 for pattern in '*[]!?':
363 s = s.replace(r'\{0}'.format(pattern), pattern)
363 s = s.replace(r'\{0}'.format(pattern), pattern)
364 return s
364 return s
365 return '\\'.join(map(unescape, string.split('\\\\')))
365 return '\\'.join(map(unescape, string.split('\\\\')))
366
366
367
367
368 def shellglob(args):
368 def shellglob(args):
369 """
369 """
370 Do glob expansion for each element in `args` and return a flattened list.
370 Do glob expansion for each element in `args` and return a flattened list.
371
371
372 Unmatched glob pattern will remain as-is in the returned list.
372 Unmatched glob pattern will remain as-is in the returned list.
373
373
374 """
374 """
375 expanded = []
375 expanded = []
376 # Do not unescape backslash in Windows as it is interpreted as
377 # path separator:
378 unescape = unescape_glob if sys.platform != 'win32' else lambda x: x
376 for a in args:
379 for a in args:
377 expanded.extend(glob.glob(a) or [unescape_glob(a)])
380 expanded.extend(glob.glob(a) or [unescape(a)])
378 return expanded
381 return expanded
379
382
380
383
381 def target_outdated(target,deps):
384 def target_outdated(target,deps):
382 """Determine whether a target is out of date.
385 """Determine whether a target is out of date.
383
386
384 target_outdated(target,deps) -> 1/0
387 target_outdated(target,deps) -> 1/0
385
388
386 deps: list of filenames which MUST exist.
389 deps: list of filenames which MUST exist.
387 target: single filename which may or may not exist.
390 target: single filename which may or may not exist.
388
391
389 If target doesn't exist or is older than any file listed in deps, return
392 If target doesn't exist or is older than any file listed in deps, return
390 true, otherwise return false.
393 true, otherwise return false.
391 """
394 """
392 try:
395 try:
393 target_time = os.path.getmtime(target)
396 target_time = os.path.getmtime(target)
394 except os.error:
397 except os.error:
395 return 1
398 return 1
396 for dep in deps:
399 for dep in deps:
397 dep_time = os.path.getmtime(dep)
400 dep_time = os.path.getmtime(dep)
398 if dep_time > target_time:
401 if dep_time > target_time:
399 #print "For target",target,"Dep failed:",dep # dbg
402 #print "For target",target,"Dep failed:",dep # dbg
400 #print "times (dep,tar):",dep_time,target_time # dbg
403 #print "times (dep,tar):",dep_time,target_time # dbg
401 return 1
404 return 1
402 return 0
405 return 0
403
406
404
407
405 def target_update(target,deps,cmd):
408 def target_update(target,deps,cmd):
406 """Update a target with a given command given a list of dependencies.
409 """Update a target with a given command given a list of dependencies.
407
410
408 target_update(target,deps,cmd) -> runs cmd if target is outdated.
411 target_update(target,deps,cmd) -> runs cmd if target is outdated.
409
412
410 This is just a wrapper around target_outdated() which calls the given
413 This is just a wrapper around target_outdated() which calls the given
411 command if target is outdated."""
414 command if target is outdated."""
412
415
413 if target_outdated(target,deps):
416 if target_outdated(target,deps):
414 system(cmd)
417 system(cmd)
415
418
416 def filehash(path):
419 def filehash(path):
417 """Make an MD5 hash of a file, ignoring any differences in line
420 """Make an MD5 hash of a file, ignoring any differences in line
418 ending characters."""
421 ending characters."""
419 with open(path, "rU") as f:
422 with open(path, "rU") as f:
420 return md5(py3compat.str_to_bytes(f.read())).hexdigest()
423 return md5(py3compat.str_to_bytes(f.read())).hexdigest()
421
424
422 # If the config is unmodified from the default, we'll just delete it.
425 # If the config is unmodified from the default, we'll just delete it.
423 # These are consistent for 0.10.x, thankfully. We're not going to worry about
426 # These are consistent for 0.10.x, thankfully. We're not going to worry about
424 # older versions.
427 # older versions.
425 old_config_md5 = {'ipy_user_conf.py': 'fc108bedff4b9a00f91fa0a5999140d3',
428 old_config_md5 = {'ipy_user_conf.py': 'fc108bedff4b9a00f91fa0a5999140d3',
426 'ipythonrc': '12a68954f3403eea2eec09dc8fe5a9b5'}
429 'ipythonrc': '12a68954f3403eea2eec09dc8fe5a9b5'}
427
430
428 def check_for_old_config(ipython_dir=None):
431 def check_for_old_config(ipython_dir=None):
429 """Check for old config files, and present a warning if they exist.
432 """Check for old config files, and present a warning if they exist.
430
433
431 A link to the docs of the new config is included in the message.
434 A link to the docs of the new config is included in the message.
432
435
433 This should mitigate confusion with the transition to the new
436 This should mitigate confusion with the transition to the new
434 config system in 0.11.
437 config system in 0.11.
435 """
438 """
436 if ipython_dir is None:
439 if ipython_dir is None:
437 ipython_dir = get_ipython_dir()
440 ipython_dir = get_ipython_dir()
438
441
439 old_configs = ['ipy_user_conf.py', 'ipythonrc', 'ipython_config.py']
442 old_configs = ['ipy_user_conf.py', 'ipythonrc', 'ipython_config.py']
440 warned = False
443 warned = False
441 for cfg in old_configs:
444 for cfg in old_configs:
442 f = os.path.join(ipython_dir, cfg)
445 f = os.path.join(ipython_dir, cfg)
443 if os.path.exists(f):
446 if os.path.exists(f):
444 if filehash(f) == old_config_md5.get(cfg, ''):
447 if filehash(f) == old_config_md5.get(cfg, ''):
445 os.unlink(f)
448 os.unlink(f)
446 else:
449 else:
447 warnings.warn("Found old IPython config file %r (modified by user)"%f)
450 warnings.warn("Found old IPython config file %r (modified by user)"%f)
448 warned = True
451 warned = True
449
452
450 if warned:
453 if warned:
451 warnings.warn("""
454 warnings.warn("""
452 The IPython configuration system has changed as of 0.11, and these files will
455 The IPython configuration system has changed as of 0.11, and these files will
453 be ignored. See http://ipython.github.com/ipython-doc/dev/config for details
456 be ignored. See http://ipython.github.com/ipython-doc/dev/config for details
454 of the new config system.
457 of the new config system.
455 To start configuring IPython, do `ipython profile create`, and edit
458 To start configuring IPython, do `ipython profile create`, and edit
456 `ipython_config.py` in <ipython_dir>/profile_default.
459 `ipython_config.py` in <ipython_dir>/profile_default.
457 If you need to leave the old config files in place for an older version of
460 If you need to leave the old config files in place for an older version of
458 IPython and want to suppress this warning message, set
461 IPython and want to suppress this warning message, set
459 `c.InteractiveShellApp.ignore_old_config=True` in the new config.""")
462 `c.InteractiveShellApp.ignore_old_config=True` in the new config.""")
460
463
461 def get_security_file(filename, profile='default'):
464 def get_security_file(filename, profile='default'):
462 """Return the absolute path of a security file given by filename and profile
465 """Return the absolute path of a security file given by filename and profile
463
466
464 This allows users and developers to find security files without
467 This allows users and developers to find security files without
465 knowledge of the IPython directory structure. The search path
468 knowledge of the IPython directory structure. The search path
466 will be ['.', profile.security_dir]
469 will be ['.', profile.security_dir]
467
470
468 Parameters
471 Parameters
469 ----------
472 ----------
470
473
471 filename : str
474 filename : str
472 The file to be found. If it is passed as an absolute path, it will
475 The file to be found. If it is passed as an absolute path, it will
473 simply be returned.
476 simply be returned.
474 profile : str [default: 'default']
477 profile : str [default: 'default']
475 The name of the profile to search. Leaving this unspecified
478 The name of the profile to search. Leaving this unspecified
476 The file to be found. If it is passed as an absolute path, fname will
479 The file to be found. If it is passed as an absolute path, fname will
477 simply be returned.
480 simply be returned.
478
481
479 Returns
482 Returns
480 -------
483 -------
481 Raises :exc:`IOError` if file not found or returns absolute path to file.
484 Raises :exc:`IOError` if file not found or returns absolute path to file.
482 """
485 """
483 # import here, because profiledir also imports from utils.path
486 # import here, because profiledir also imports from utils.path
484 from IPython.core.profiledir import ProfileDir
487 from IPython.core.profiledir import ProfileDir
485 try:
488 try:
486 pd = ProfileDir.find_profile_dir_by_name(get_ipython_dir(), profile)
489 pd = ProfileDir.find_profile_dir_by_name(get_ipython_dir(), profile)
487 except Exception:
490 except Exception:
488 # will raise ProfileDirError if no such profile
491 # will raise ProfileDirError if no such profile
489 raise IOError("Profile %r not found")
492 raise IOError("Profile %r not found")
490 return filefind(filename, ['.', pd.security_dir])
493 return filefind(filename, ['.', pd.security_dir])
491
494
General Comments 0
You need to be logged in to leave comments. Login now