##// END OF EJS Templates
Fix unescape_glob: support escaping "\"
Takafumi Arakaki -
Show More
@@ -1,489 +1,491 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 for pattern in '*[]!?':
362 for pattern in '*[]!?':
362 string = string.replace(r'\{0}'.format(pattern), pattern)
363 s = s.replace(r'\{0}'.format(pattern), pattern)
363 return string
364 return s
365 return '\\'.join(map(unescape, string.split('\\\\')))
364
366
365
367
366 def shellglob(args):
368 def shellglob(args):
367 """
369 """
368 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.
369
371
370 Unmatched glob pattern will remain as-is in the returned list.
372 Unmatched glob pattern will remain as-is in the returned list.
371
373
372 """
374 """
373 expanded = []
375 expanded = []
374 for a in args:
376 for a in args:
375 expanded.extend(glob.glob(a) or [unescape_glob(a)])
377 expanded.extend(glob.glob(a) or [unescape_glob(a)])
376 return expanded
378 return expanded
377
379
378
380
379 def target_outdated(target,deps):
381 def target_outdated(target,deps):
380 """Determine whether a target is out of date.
382 """Determine whether a target is out of date.
381
383
382 target_outdated(target,deps) -> 1/0
384 target_outdated(target,deps) -> 1/0
383
385
384 deps: list of filenames which MUST exist.
386 deps: list of filenames which MUST exist.
385 target: single filename which may or may not exist.
387 target: single filename which may or may not exist.
386
388
387 If target doesn't exist or is older than any file listed in deps, return
389 If target doesn't exist or is older than any file listed in deps, return
388 true, otherwise return false.
390 true, otherwise return false.
389 """
391 """
390 try:
392 try:
391 target_time = os.path.getmtime(target)
393 target_time = os.path.getmtime(target)
392 except os.error:
394 except os.error:
393 return 1
395 return 1
394 for dep in deps:
396 for dep in deps:
395 dep_time = os.path.getmtime(dep)
397 dep_time = os.path.getmtime(dep)
396 if dep_time > target_time:
398 if dep_time > target_time:
397 #print "For target",target,"Dep failed:",dep # dbg
399 #print "For target",target,"Dep failed:",dep # dbg
398 #print "times (dep,tar):",dep_time,target_time # dbg
400 #print "times (dep,tar):",dep_time,target_time # dbg
399 return 1
401 return 1
400 return 0
402 return 0
401
403
402
404
403 def target_update(target,deps,cmd):
405 def target_update(target,deps,cmd):
404 """Update a target with a given command given a list of dependencies.
406 """Update a target with a given command given a list of dependencies.
405
407
406 target_update(target,deps,cmd) -> runs cmd if target is outdated.
408 target_update(target,deps,cmd) -> runs cmd if target is outdated.
407
409
408 This is just a wrapper around target_outdated() which calls the given
410 This is just a wrapper around target_outdated() which calls the given
409 command if target is outdated."""
411 command if target is outdated."""
410
412
411 if target_outdated(target,deps):
413 if target_outdated(target,deps):
412 system(cmd)
414 system(cmd)
413
415
414 def filehash(path):
416 def filehash(path):
415 """Make an MD5 hash of a file, ignoring any differences in line
417 """Make an MD5 hash of a file, ignoring any differences in line
416 ending characters."""
418 ending characters."""
417 with open(path, "rU") as f:
419 with open(path, "rU") as f:
418 return md5(py3compat.str_to_bytes(f.read())).hexdigest()
420 return md5(py3compat.str_to_bytes(f.read())).hexdigest()
419
421
420 # If the config is unmodified from the default, we'll just delete it.
422 # If the config is unmodified from the default, we'll just delete it.
421 # These are consistent for 0.10.x, thankfully. We're not going to worry about
423 # These are consistent for 0.10.x, thankfully. We're not going to worry about
422 # older versions.
424 # older versions.
423 old_config_md5 = {'ipy_user_conf.py': 'fc108bedff4b9a00f91fa0a5999140d3',
425 old_config_md5 = {'ipy_user_conf.py': 'fc108bedff4b9a00f91fa0a5999140d3',
424 'ipythonrc': '12a68954f3403eea2eec09dc8fe5a9b5'}
426 'ipythonrc': '12a68954f3403eea2eec09dc8fe5a9b5'}
425
427
426 def check_for_old_config(ipython_dir=None):
428 def check_for_old_config(ipython_dir=None):
427 """Check for old config files, and present a warning if they exist.
429 """Check for old config files, and present a warning if they exist.
428
430
429 A link to the docs of the new config is included in the message.
431 A link to the docs of the new config is included in the message.
430
432
431 This should mitigate confusion with the transition to the new
433 This should mitigate confusion with the transition to the new
432 config system in 0.11.
434 config system in 0.11.
433 """
435 """
434 if ipython_dir is None:
436 if ipython_dir is None:
435 ipython_dir = get_ipython_dir()
437 ipython_dir = get_ipython_dir()
436
438
437 old_configs = ['ipy_user_conf.py', 'ipythonrc', 'ipython_config.py']
439 old_configs = ['ipy_user_conf.py', 'ipythonrc', 'ipython_config.py']
438 warned = False
440 warned = False
439 for cfg in old_configs:
441 for cfg in old_configs:
440 f = os.path.join(ipython_dir, cfg)
442 f = os.path.join(ipython_dir, cfg)
441 if os.path.exists(f):
443 if os.path.exists(f):
442 if filehash(f) == old_config_md5.get(cfg, ''):
444 if filehash(f) == old_config_md5.get(cfg, ''):
443 os.unlink(f)
445 os.unlink(f)
444 else:
446 else:
445 warnings.warn("Found old IPython config file %r (modified by user)"%f)
447 warnings.warn("Found old IPython config file %r (modified by user)"%f)
446 warned = True
448 warned = True
447
449
448 if warned:
450 if warned:
449 warnings.warn("""
451 warnings.warn("""
450 The IPython configuration system has changed as of 0.11, and these files will
452 The IPython configuration system has changed as of 0.11, and these files will
451 be ignored. See http://ipython.github.com/ipython-doc/dev/config for details
453 be ignored. See http://ipython.github.com/ipython-doc/dev/config for details
452 of the new config system.
454 of the new config system.
453 To start configuring IPython, do `ipython profile create`, and edit
455 To start configuring IPython, do `ipython profile create`, and edit
454 `ipython_config.py` in <ipython_dir>/profile_default.
456 `ipython_config.py` in <ipython_dir>/profile_default.
455 If you need to leave the old config files in place for an older version of
457 If you need to leave the old config files in place for an older version of
456 IPython and want to suppress this warning message, set
458 IPython and want to suppress this warning message, set
457 `c.InteractiveShellApp.ignore_old_config=True` in the new config.""")
459 `c.InteractiveShellApp.ignore_old_config=True` in the new config.""")
458
460
459 def get_security_file(filename, profile='default'):
461 def get_security_file(filename, profile='default'):
460 """Return the absolute path of a security file given by filename and profile
462 """Return the absolute path of a security file given by filename and profile
461
463
462 This allows users and developers to find security files without
464 This allows users and developers to find security files without
463 knowledge of the IPython directory structure. The search path
465 knowledge of the IPython directory structure. The search path
464 will be ['.', profile.security_dir]
466 will be ['.', profile.security_dir]
465
467
466 Parameters
468 Parameters
467 ----------
469 ----------
468
470
469 filename : str
471 filename : str
470 The file to be found. If it is passed as an absolute path, it will
472 The file to be found. If it is passed as an absolute path, it will
471 simply be returned.
473 simply be returned.
472 profile : str [default: 'default']
474 profile : str [default: 'default']
473 The name of the profile to search. Leaving this unspecified
475 The name of the profile to search. Leaving this unspecified
474 The file to be found. If it is passed as an absolute path, fname will
476 The file to be found. If it is passed as an absolute path, fname will
475 simply be returned.
477 simply be returned.
476
478
477 Returns
479 Returns
478 -------
480 -------
479 Raises :exc:`IOError` if file not found or returns absolute path to file.
481 Raises :exc:`IOError` if file not found or returns absolute path to file.
480 """
482 """
481 # import here, because profiledir also imports from utils.path
483 # import here, because profiledir also imports from utils.path
482 from IPython.core.profiledir import ProfileDir
484 from IPython.core.profiledir import ProfileDir
483 try:
485 try:
484 pd = ProfileDir.find_profile_dir_by_name(get_ipython_dir(), profile)
486 pd = ProfileDir.find_profile_dir_by_name(get_ipython_dir(), profile)
485 except Exception:
487 except Exception:
486 # will raise ProfileDirError if no such profile
488 # will raise ProfileDirError if no such profile
487 raise IOError("Profile %r not found")
489 raise IOError("Profile %r not found")
488 return filefind(filename, ['.', pd.security_dir])
490 return filefind(filename, ['.', pd.security_dir])
489
491
@@ -1,488 +1,492 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """Tests for IPython.utils.path.py"""
2 """Tests for IPython.utils.path.py"""
3
3
4 #-----------------------------------------------------------------------------
4 #-----------------------------------------------------------------------------
5 # Copyright (C) 2008-2011 The IPython Development Team
5 # Copyright (C) 2008-2011 The IPython Development Team
6 #
6 #
7 # Distributed under the terms of the BSD License. The full license is in
7 # Distributed under the terms of the BSD License. The full license is in
8 # the file COPYING, distributed as part of this software.
8 # the file COPYING, distributed as part of this software.
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Imports
12 # Imports
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 from __future__ import with_statement
15 from __future__ import with_statement
16
16
17 import os
17 import os
18 import shutil
18 import shutil
19 import sys
19 import sys
20 import tempfile
20 import tempfile
21 from io import StringIO
21 from io import StringIO
22
22
23 from os.path import join, abspath, split
23 from os.path import join, abspath, split
24
24
25 import nose.tools as nt
25 import nose.tools as nt
26
26
27 from nose import with_setup
27 from nose import with_setup
28
28
29 import IPython
29 import IPython
30 from IPython.testing import decorators as dec
30 from IPython.testing import decorators as dec
31 from IPython.testing.decorators import skip_if_not_win32, skip_win32
31 from IPython.testing.decorators import skip_if_not_win32, skip_win32
32 from IPython.testing.tools import make_tempfile, AssertPrints
32 from IPython.testing.tools import make_tempfile, AssertPrints
33 from IPython.utils import path, io
33 from IPython.utils import path, io
34 from IPython.utils import py3compat
34 from IPython.utils import py3compat
35 from IPython.utils.tempdir import TemporaryDirectory
35 from IPython.utils.tempdir import TemporaryDirectory
36
36
37 # Platform-dependent imports
37 # Platform-dependent imports
38 try:
38 try:
39 import _winreg as wreg
39 import _winreg as wreg
40 except ImportError:
40 except ImportError:
41 #Fake _winreg module on none windows platforms
41 #Fake _winreg module on none windows platforms
42 import types
42 import types
43 wr_name = "winreg" if py3compat.PY3 else "_winreg"
43 wr_name = "winreg" if py3compat.PY3 else "_winreg"
44 sys.modules[wr_name] = types.ModuleType(wr_name)
44 sys.modules[wr_name] = types.ModuleType(wr_name)
45 import _winreg as wreg
45 import _winreg as wreg
46 #Add entries that needs to be stubbed by the testing code
46 #Add entries that needs to be stubbed by the testing code
47 (wreg.OpenKey, wreg.QueryValueEx,) = (None, None)
47 (wreg.OpenKey, wreg.QueryValueEx,) = (None, None)
48
48
49 try:
49 try:
50 reload
50 reload
51 except NameError: # Python 3
51 except NameError: # Python 3
52 from imp import reload
52 from imp import reload
53
53
54 #-----------------------------------------------------------------------------
54 #-----------------------------------------------------------------------------
55 # Globals
55 # Globals
56 #-----------------------------------------------------------------------------
56 #-----------------------------------------------------------------------------
57 env = os.environ
57 env = os.environ
58 TEST_FILE_PATH = split(abspath(__file__))[0]
58 TEST_FILE_PATH = split(abspath(__file__))[0]
59 TMP_TEST_DIR = tempfile.mkdtemp()
59 TMP_TEST_DIR = tempfile.mkdtemp()
60 HOME_TEST_DIR = join(TMP_TEST_DIR, "home_test_dir")
60 HOME_TEST_DIR = join(TMP_TEST_DIR, "home_test_dir")
61 XDG_TEST_DIR = join(HOME_TEST_DIR, "xdg_test_dir")
61 XDG_TEST_DIR = join(HOME_TEST_DIR, "xdg_test_dir")
62 IP_TEST_DIR = join(HOME_TEST_DIR,'.ipython')
62 IP_TEST_DIR = join(HOME_TEST_DIR,'.ipython')
63 #
63 #
64 # Setup/teardown functions/decorators
64 # Setup/teardown functions/decorators
65 #
65 #
66
66
67 def setup():
67 def setup():
68 """Setup testenvironment for the module:
68 """Setup testenvironment for the module:
69
69
70 - Adds dummy home dir tree
70 - Adds dummy home dir tree
71 """
71 """
72 # Do not mask exceptions here. In particular, catching WindowsError is a
72 # Do not mask exceptions here. In particular, catching WindowsError is a
73 # problem because that exception is only defined on Windows...
73 # problem because that exception is only defined on Windows...
74 os.makedirs(IP_TEST_DIR)
74 os.makedirs(IP_TEST_DIR)
75 os.makedirs(os.path.join(XDG_TEST_DIR, 'ipython'))
75 os.makedirs(os.path.join(XDG_TEST_DIR, 'ipython'))
76
76
77
77
78 def teardown():
78 def teardown():
79 """Teardown testenvironment for the module:
79 """Teardown testenvironment for the module:
80
80
81 - Remove dummy home dir tree
81 - Remove dummy home dir tree
82 """
82 """
83 # Note: we remove the parent test dir, which is the root of all test
83 # Note: we remove the parent test dir, which is the root of all test
84 # subdirs we may have created. Use shutil instead of os.removedirs, so
84 # subdirs we may have created. Use shutil instead of os.removedirs, so
85 # that non-empty directories are all recursively removed.
85 # that non-empty directories are all recursively removed.
86 shutil.rmtree(TMP_TEST_DIR)
86 shutil.rmtree(TMP_TEST_DIR)
87
87
88
88
89 def setup_environment():
89 def setup_environment():
90 """Setup testenvironment for some functions that are tested
90 """Setup testenvironment for some functions that are tested
91 in this module. In particular this functions stores attributes
91 in this module. In particular this functions stores attributes
92 and other things that we need to stub in some test functions.
92 and other things that we need to stub in some test functions.
93 This needs to be done on a function level and not module level because
93 This needs to be done on a function level and not module level because
94 each testfunction needs a pristine environment.
94 each testfunction needs a pristine environment.
95 """
95 """
96 global oldstuff, platformstuff
96 global oldstuff, platformstuff
97 oldstuff = (env.copy(), os.name, sys.platform, path.get_home_dir, IPython.__file__, os.getcwd())
97 oldstuff = (env.copy(), os.name, sys.platform, path.get_home_dir, IPython.__file__, os.getcwd())
98
98
99 if os.name == 'nt':
99 if os.name == 'nt':
100 platformstuff = (wreg.OpenKey, wreg.QueryValueEx,)
100 platformstuff = (wreg.OpenKey, wreg.QueryValueEx,)
101
101
102
102
103 def teardown_environment():
103 def teardown_environment():
104 """Restore things that were remebered by the setup_environment function
104 """Restore things that were remebered by the setup_environment function
105 """
105 """
106 (oldenv, os.name, sys.platform, path.get_home_dir, IPython.__file__, old_wd) = oldstuff
106 (oldenv, os.name, sys.platform, path.get_home_dir, IPython.__file__, old_wd) = oldstuff
107 os.chdir(old_wd)
107 os.chdir(old_wd)
108 reload(path)
108 reload(path)
109
109
110 for key in env.keys():
110 for key in env.keys():
111 if key not in oldenv:
111 if key not in oldenv:
112 del env[key]
112 del env[key]
113 env.update(oldenv)
113 env.update(oldenv)
114 if hasattr(sys, 'frozen'):
114 if hasattr(sys, 'frozen'):
115 del sys.frozen
115 del sys.frozen
116 if os.name == 'nt':
116 if os.name == 'nt':
117 (wreg.OpenKey, wreg.QueryValueEx,) = platformstuff
117 (wreg.OpenKey, wreg.QueryValueEx,) = platformstuff
118
118
119 # Build decorator that uses the setup_environment/setup_environment
119 # Build decorator that uses the setup_environment/setup_environment
120 with_environment = with_setup(setup_environment, teardown_environment)
120 with_environment = with_setup(setup_environment, teardown_environment)
121
121
122 @skip_if_not_win32
122 @skip_if_not_win32
123 @with_environment
123 @with_environment
124 def test_get_home_dir_1():
124 def test_get_home_dir_1():
125 """Testcase for py2exe logic, un-compressed lib
125 """Testcase for py2exe logic, un-compressed lib
126 """
126 """
127 sys.frozen = True
127 sys.frozen = True
128
128
129 #fake filename for IPython.__init__
129 #fake filename for IPython.__init__
130 IPython.__file__ = abspath(join(HOME_TEST_DIR, "Lib/IPython/__init__.py"))
130 IPython.__file__ = abspath(join(HOME_TEST_DIR, "Lib/IPython/__init__.py"))
131
131
132 home_dir = path.get_home_dir()
132 home_dir = path.get_home_dir()
133 nt.assert_equal(home_dir, abspath(HOME_TEST_DIR))
133 nt.assert_equal(home_dir, abspath(HOME_TEST_DIR))
134
134
135
135
136 @skip_if_not_win32
136 @skip_if_not_win32
137 @with_environment
137 @with_environment
138 def test_get_home_dir_2():
138 def test_get_home_dir_2():
139 """Testcase for py2exe logic, compressed lib
139 """Testcase for py2exe logic, compressed lib
140 """
140 """
141 sys.frozen = True
141 sys.frozen = True
142 #fake filename for IPython.__init__
142 #fake filename for IPython.__init__
143 IPython.__file__ = abspath(join(HOME_TEST_DIR, "Library.zip/IPython/__init__.py")).lower()
143 IPython.__file__ = abspath(join(HOME_TEST_DIR, "Library.zip/IPython/__init__.py")).lower()
144
144
145 home_dir = path.get_home_dir(True)
145 home_dir = path.get_home_dir(True)
146 nt.assert_equal(home_dir, abspath(HOME_TEST_DIR).lower())
146 nt.assert_equal(home_dir, abspath(HOME_TEST_DIR).lower())
147
147
148
148
149 @with_environment
149 @with_environment
150 def test_get_home_dir_3():
150 def test_get_home_dir_3():
151 """get_home_dir() uses $HOME if set"""
151 """get_home_dir() uses $HOME if set"""
152 env["HOME"] = HOME_TEST_DIR
152 env["HOME"] = HOME_TEST_DIR
153 home_dir = path.get_home_dir(True)
153 home_dir = path.get_home_dir(True)
154 # get_home_dir expands symlinks
154 # get_home_dir expands symlinks
155 nt.assert_equal(home_dir, os.path.realpath(env["HOME"]))
155 nt.assert_equal(home_dir, os.path.realpath(env["HOME"]))
156
156
157
157
158 @with_environment
158 @with_environment
159 def test_get_home_dir_4():
159 def test_get_home_dir_4():
160 """get_home_dir() still works if $HOME is not set"""
160 """get_home_dir() still works if $HOME is not set"""
161
161
162 if 'HOME' in env: del env['HOME']
162 if 'HOME' in env: del env['HOME']
163 # this should still succeed, but we don't care what the answer is
163 # this should still succeed, but we don't care what the answer is
164 home = path.get_home_dir(False)
164 home = path.get_home_dir(False)
165
165
166 @with_environment
166 @with_environment
167 def test_get_home_dir_5():
167 def test_get_home_dir_5():
168 """raise HomeDirError if $HOME is specified, but not a writable dir"""
168 """raise HomeDirError if $HOME is specified, but not a writable dir"""
169 env['HOME'] = abspath(HOME_TEST_DIR+'garbage')
169 env['HOME'] = abspath(HOME_TEST_DIR+'garbage')
170 # set os.name = posix, to prevent My Documents fallback on Windows
170 # set os.name = posix, to prevent My Documents fallback on Windows
171 os.name = 'posix'
171 os.name = 'posix'
172 nt.assert_raises(path.HomeDirError, path.get_home_dir, True)
172 nt.assert_raises(path.HomeDirError, path.get_home_dir, True)
173
173
174
174
175 # Should we stub wreg fully so we can run the test on all platforms?
175 # Should we stub wreg fully so we can run the test on all platforms?
176 @skip_if_not_win32
176 @skip_if_not_win32
177 @with_environment
177 @with_environment
178 def test_get_home_dir_8():
178 def test_get_home_dir_8():
179 """Using registry hack for 'My Documents', os=='nt'
179 """Using registry hack for 'My Documents', os=='nt'
180
180
181 HOMESHARE, HOMEDRIVE, HOMEPATH, USERPROFILE and others are missing.
181 HOMESHARE, HOMEDRIVE, HOMEPATH, USERPROFILE and others are missing.
182 """
182 """
183 os.name = 'nt'
183 os.name = 'nt'
184 # Remove from stub environment all keys that may be set
184 # Remove from stub environment all keys that may be set
185 for key in ['HOME', 'HOMESHARE', 'HOMEDRIVE', 'HOMEPATH', 'USERPROFILE']:
185 for key in ['HOME', 'HOMESHARE', 'HOMEDRIVE', 'HOMEPATH', 'USERPROFILE']:
186 env.pop(key, None)
186 env.pop(key, None)
187
187
188 #Stub windows registry functions
188 #Stub windows registry functions
189 def OpenKey(x, y):
189 def OpenKey(x, y):
190 class key:
190 class key:
191 def Close(self):
191 def Close(self):
192 pass
192 pass
193 return key()
193 return key()
194 def QueryValueEx(x, y):
194 def QueryValueEx(x, y):
195 return [abspath(HOME_TEST_DIR)]
195 return [abspath(HOME_TEST_DIR)]
196
196
197 wreg.OpenKey = OpenKey
197 wreg.OpenKey = OpenKey
198 wreg.QueryValueEx = QueryValueEx
198 wreg.QueryValueEx = QueryValueEx
199
199
200 home_dir = path.get_home_dir()
200 home_dir = path.get_home_dir()
201 nt.assert_equal(home_dir, abspath(HOME_TEST_DIR))
201 nt.assert_equal(home_dir, abspath(HOME_TEST_DIR))
202
202
203
203
204 @with_environment
204 @with_environment
205 def test_get_ipython_dir_1():
205 def test_get_ipython_dir_1():
206 """test_get_ipython_dir_1, Testcase to see if we can call get_ipython_dir without Exceptions."""
206 """test_get_ipython_dir_1, Testcase to see if we can call get_ipython_dir without Exceptions."""
207 env_ipdir = os.path.join("someplace", ".ipython")
207 env_ipdir = os.path.join("someplace", ".ipython")
208 path._writable_dir = lambda path: True
208 path._writable_dir = lambda path: True
209 env['IPYTHONDIR'] = env_ipdir
209 env['IPYTHONDIR'] = env_ipdir
210 ipdir = path.get_ipython_dir()
210 ipdir = path.get_ipython_dir()
211 nt.assert_equal(ipdir, env_ipdir)
211 nt.assert_equal(ipdir, env_ipdir)
212
212
213
213
214 @with_environment
214 @with_environment
215 def test_get_ipython_dir_2():
215 def test_get_ipython_dir_2():
216 """test_get_ipython_dir_2, Testcase to see if we can call get_ipython_dir without Exceptions."""
216 """test_get_ipython_dir_2, Testcase to see if we can call get_ipython_dir without Exceptions."""
217 path.get_home_dir = lambda : "someplace"
217 path.get_home_dir = lambda : "someplace"
218 path.get_xdg_dir = lambda : None
218 path.get_xdg_dir = lambda : None
219 path._writable_dir = lambda path: True
219 path._writable_dir = lambda path: True
220 os.name = "posix"
220 os.name = "posix"
221 env.pop('IPYTHON_DIR', None)
221 env.pop('IPYTHON_DIR', None)
222 env.pop('IPYTHONDIR', None)
222 env.pop('IPYTHONDIR', None)
223 env.pop('XDG_CONFIG_HOME', None)
223 env.pop('XDG_CONFIG_HOME', None)
224 ipdir = path.get_ipython_dir()
224 ipdir = path.get_ipython_dir()
225 nt.assert_equal(ipdir, os.path.join("someplace", ".ipython"))
225 nt.assert_equal(ipdir, os.path.join("someplace", ".ipython"))
226
226
227 @with_environment
227 @with_environment
228 def test_get_ipython_dir_3():
228 def test_get_ipython_dir_3():
229 """test_get_ipython_dir_3, use XDG if defined, and .ipython doesn't exist."""
229 """test_get_ipython_dir_3, use XDG if defined, and .ipython doesn't exist."""
230 path.get_home_dir = lambda : "someplace"
230 path.get_home_dir = lambda : "someplace"
231 path._writable_dir = lambda path: True
231 path._writable_dir = lambda path: True
232 os.name = "posix"
232 os.name = "posix"
233 env.pop('IPYTHON_DIR', None)
233 env.pop('IPYTHON_DIR', None)
234 env.pop('IPYTHONDIR', None)
234 env.pop('IPYTHONDIR', None)
235 env['XDG_CONFIG_HOME'] = XDG_TEST_DIR
235 env['XDG_CONFIG_HOME'] = XDG_TEST_DIR
236 ipdir = path.get_ipython_dir()
236 ipdir = path.get_ipython_dir()
237 if sys.platform == "darwin":
237 if sys.platform == "darwin":
238 expected = os.path.join("someplace", ".ipython")
238 expected = os.path.join("someplace", ".ipython")
239 else:
239 else:
240 expected = os.path.join(XDG_TEST_DIR, "ipython")
240 expected = os.path.join(XDG_TEST_DIR, "ipython")
241 nt.assert_equal(ipdir, expected)
241 nt.assert_equal(ipdir, expected)
242
242
243 @with_environment
243 @with_environment
244 def test_get_ipython_dir_4():
244 def test_get_ipython_dir_4():
245 """test_get_ipython_dir_4, use XDG if both exist."""
245 """test_get_ipython_dir_4, use XDG if both exist."""
246 path.get_home_dir = lambda : HOME_TEST_DIR
246 path.get_home_dir = lambda : HOME_TEST_DIR
247 os.name = "posix"
247 os.name = "posix"
248 env.pop('IPYTHON_DIR', None)
248 env.pop('IPYTHON_DIR', None)
249 env.pop('IPYTHONDIR', None)
249 env.pop('IPYTHONDIR', None)
250 env['XDG_CONFIG_HOME'] = XDG_TEST_DIR
250 env['XDG_CONFIG_HOME'] = XDG_TEST_DIR
251 ipdir = path.get_ipython_dir()
251 ipdir = path.get_ipython_dir()
252 if sys.platform == "darwin":
252 if sys.platform == "darwin":
253 expected = os.path.join(HOME_TEST_DIR, ".ipython")
253 expected = os.path.join(HOME_TEST_DIR, ".ipython")
254 else:
254 else:
255 expected = os.path.join(XDG_TEST_DIR, "ipython")
255 expected = os.path.join(XDG_TEST_DIR, "ipython")
256 nt.assert_equal(ipdir, expected)
256 nt.assert_equal(ipdir, expected)
257
257
258 @with_environment
258 @with_environment
259 def test_get_ipython_dir_5():
259 def test_get_ipython_dir_5():
260 """test_get_ipython_dir_5, use .ipython if exists and XDG defined, but doesn't exist."""
260 """test_get_ipython_dir_5, use .ipython if exists and XDG defined, but doesn't exist."""
261 path.get_home_dir = lambda : HOME_TEST_DIR
261 path.get_home_dir = lambda : HOME_TEST_DIR
262 os.name = "posix"
262 os.name = "posix"
263 env.pop('IPYTHON_DIR', None)
263 env.pop('IPYTHON_DIR', None)
264 env.pop('IPYTHONDIR', None)
264 env.pop('IPYTHONDIR', None)
265 env['XDG_CONFIG_HOME'] = XDG_TEST_DIR
265 env['XDG_CONFIG_HOME'] = XDG_TEST_DIR
266 os.rmdir(os.path.join(XDG_TEST_DIR, 'ipython'))
266 os.rmdir(os.path.join(XDG_TEST_DIR, 'ipython'))
267 ipdir = path.get_ipython_dir()
267 ipdir = path.get_ipython_dir()
268 nt.assert_equal(ipdir, IP_TEST_DIR)
268 nt.assert_equal(ipdir, IP_TEST_DIR)
269
269
270 @with_environment
270 @with_environment
271 def test_get_ipython_dir_6():
271 def test_get_ipython_dir_6():
272 """test_get_ipython_dir_6, use XDG if defined and neither exist."""
272 """test_get_ipython_dir_6, use XDG if defined and neither exist."""
273 xdg = os.path.join(HOME_TEST_DIR, 'somexdg')
273 xdg = os.path.join(HOME_TEST_DIR, 'somexdg')
274 os.mkdir(xdg)
274 os.mkdir(xdg)
275 shutil.rmtree(os.path.join(HOME_TEST_DIR, '.ipython'))
275 shutil.rmtree(os.path.join(HOME_TEST_DIR, '.ipython'))
276 path.get_home_dir = lambda : HOME_TEST_DIR
276 path.get_home_dir = lambda : HOME_TEST_DIR
277 path.get_xdg_dir = lambda : xdg
277 path.get_xdg_dir = lambda : xdg
278 os.name = "posix"
278 os.name = "posix"
279 env.pop('IPYTHON_DIR', None)
279 env.pop('IPYTHON_DIR', None)
280 env.pop('IPYTHONDIR', None)
280 env.pop('IPYTHONDIR', None)
281 env.pop('XDG_CONFIG_HOME', None)
281 env.pop('XDG_CONFIG_HOME', None)
282 xdg_ipdir = os.path.join(xdg, "ipython")
282 xdg_ipdir = os.path.join(xdg, "ipython")
283 ipdir = path.get_ipython_dir()
283 ipdir = path.get_ipython_dir()
284 nt.assert_equal(ipdir, xdg_ipdir)
284 nt.assert_equal(ipdir, xdg_ipdir)
285
285
286 @with_environment
286 @with_environment
287 def test_get_ipython_dir_7():
287 def test_get_ipython_dir_7():
288 """test_get_ipython_dir_7, test home directory expansion on IPYTHONDIR"""
288 """test_get_ipython_dir_7, test home directory expansion on IPYTHONDIR"""
289 path._writable_dir = lambda path: True
289 path._writable_dir = lambda path: True
290 home_dir = os.path.normpath(os.path.expanduser('~'))
290 home_dir = os.path.normpath(os.path.expanduser('~'))
291 env['IPYTHONDIR'] = os.path.join('~', 'somewhere')
291 env['IPYTHONDIR'] = os.path.join('~', 'somewhere')
292 ipdir = path.get_ipython_dir()
292 ipdir = path.get_ipython_dir()
293 nt.assert_equal(ipdir, os.path.join(home_dir, 'somewhere'))
293 nt.assert_equal(ipdir, os.path.join(home_dir, 'somewhere'))
294
294
295
295
296 @with_environment
296 @with_environment
297 def test_get_xdg_dir_0():
297 def test_get_xdg_dir_0():
298 """test_get_xdg_dir_0, check xdg_dir"""
298 """test_get_xdg_dir_0, check xdg_dir"""
299 reload(path)
299 reload(path)
300 path._writable_dir = lambda path: True
300 path._writable_dir = lambda path: True
301 path.get_home_dir = lambda : 'somewhere'
301 path.get_home_dir = lambda : 'somewhere'
302 os.name = "posix"
302 os.name = "posix"
303 sys.platform = "linux2"
303 sys.platform = "linux2"
304 env.pop('IPYTHON_DIR', None)
304 env.pop('IPYTHON_DIR', None)
305 env.pop('IPYTHONDIR', None)
305 env.pop('IPYTHONDIR', None)
306 env.pop('XDG_CONFIG_HOME', None)
306 env.pop('XDG_CONFIG_HOME', None)
307
307
308 nt.assert_equal(path.get_xdg_dir(), os.path.join('somewhere', '.config'))
308 nt.assert_equal(path.get_xdg_dir(), os.path.join('somewhere', '.config'))
309
309
310
310
311 @with_environment
311 @with_environment
312 def test_get_xdg_dir_1():
312 def test_get_xdg_dir_1():
313 """test_get_xdg_dir_1, check nonexistant xdg_dir"""
313 """test_get_xdg_dir_1, check nonexistant xdg_dir"""
314 reload(path)
314 reload(path)
315 path.get_home_dir = lambda : HOME_TEST_DIR
315 path.get_home_dir = lambda : HOME_TEST_DIR
316 os.name = "posix"
316 os.name = "posix"
317 sys.platform = "linux2"
317 sys.platform = "linux2"
318 env.pop('IPYTHON_DIR', None)
318 env.pop('IPYTHON_DIR', None)
319 env.pop('IPYTHONDIR', None)
319 env.pop('IPYTHONDIR', None)
320 env.pop('XDG_CONFIG_HOME', None)
320 env.pop('XDG_CONFIG_HOME', None)
321 nt.assert_equal(path.get_xdg_dir(), None)
321 nt.assert_equal(path.get_xdg_dir(), None)
322
322
323 @with_environment
323 @with_environment
324 def test_get_xdg_dir_2():
324 def test_get_xdg_dir_2():
325 """test_get_xdg_dir_2, check xdg_dir default to ~/.config"""
325 """test_get_xdg_dir_2, check xdg_dir default to ~/.config"""
326 reload(path)
326 reload(path)
327 path.get_home_dir = lambda : HOME_TEST_DIR
327 path.get_home_dir = lambda : HOME_TEST_DIR
328 os.name = "posix"
328 os.name = "posix"
329 sys.platform = "linux2"
329 sys.platform = "linux2"
330 env.pop('IPYTHON_DIR', None)
330 env.pop('IPYTHON_DIR', None)
331 env.pop('IPYTHONDIR', None)
331 env.pop('IPYTHONDIR', None)
332 env.pop('XDG_CONFIG_HOME', None)
332 env.pop('XDG_CONFIG_HOME', None)
333 cfgdir=os.path.join(path.get_home_dir(), '.config')
333 cfgdir=os.path.join(path.get_home_dir(), '.config')
334 if not os.path.exists(cfgdir):
334 if not os.path.exists(cfgdir):
335 os.makedirs(cfgdir)
335 os.makedirs(cfgdir)
336
336
337 nt.assert_equal(path.get_xdg_dir(), cfgdir)
337 nt.assert_equal(path.get_xdg_dir(), cfgdir)
338
338
339 @with_environment
339 @with_environment
340 def test_get_xdg_dir_3():
340 def test_get_xdg_dir_3():
341 """test_get_xdg_dir_3, check xdg_dir not used on OS X"""
341 """test_get_xdg_dir_3, check xdg_dir not used on OS X"""
342 reload(path)
342 reload(path)
343 path.get_home_dir = lambda : HOME_TEST_DIR
343 path.get_home_dir = lambda : HOME_TEST_DIR
344 os.name = "posix"
344 os.name = "posix"
345 sys.platform = "darwin"
345 sys.platform = "darwin"
346 env.pop('IPYTHON_DIR', None)
346 env.pop('IPYTHON_DIR', None)
347 env.pop('IPYTHONDIR', None)
347 env.pop('IPYTHONDIR', None)
348 env.pop('XDG_CONFIG_HOME', None)
348 env.pop('XDG_CONFIG_HOME', None)
349 cfgdir=os.path.join(path.get_home_dir(), '.config')
349 cfgdir=os.path.join(path.get_home_dir(), '.config')
350 if not os.path.exists(cfgdir):
350 if not os.path.exists(cfgdir):
351 os.makedirs(cfgdir)
351 os.makedirs(cfgdir)
352
352
353 nt.assert_equal(path.get_xdg_dir(), None)
353 nt.assert_equal(path.get_xdg_dir(), None)
354
354
355 def test_filefind():
355 def test_filefind():
356 """Various tests for filefind"""
356 """Various tests for filefind"""
357 f = tempfile.NamedTemporaryFile()
357 f = tempfile.NamedTemporaryFile()
358 # print 'fname:',f.name
358 # print 'fname:',f.name
359 alt_dirs = path.get_ipython_dir()
359 alt_dirs = path.get_ipython_dir()
360 t = path.filefind(f.name, alt_dirs)
360 t = path.filefind(f.name, alt_dirs)
361 # print 'found:',t
361 # print 'found:',t
362
362
363
363
364 def test_get_ipython_package_dir():
364 def test_get_ipython_package_dir():
365 ipdir = path.get_ipython_package_dir()
365 ipdir = path.get_ipython_package_dir()
366 nt.assert_true(os.path.isdir(ipdir))
366 nt.assert_true(os.path.isdir(ipdir))
367
367
368
368
369 def test_get_ipython_module_path():
369 def test_get_ipython_module_path():
370 ipapp_path = path.get_ipython_module_path('IPython.frontend.terminal.ipapp')
370 ipapp_path = path.get_ipython_module_path('IPython.frontend.terminal.ipapp')
371 nt.assert_true(os.path.isfile(ipapp_path))
371 nt.assert_true(os.path.isfile(ipapp_path))
372
372
373
373
374 @dec.skip_if_not_win32
374 @dec.skip_if_not_win32
375 def test_get_long_path_name_win32():
375 def test_get_long_path_name_win32():
376 p = path.get_long_path_name('c:\\docume~1')
376 p = path.get_long_path_name('c:\\docume~1')
377 nt.assert_equals(p,u'c:\\Documents and Settings')
377 nt.assert_equals(p,u'c:\\Documents and Settings')
378
378
379
379
380 @dec.skip_win32
380 @dec.skip_win32
381 def test_get_long_path_name():
381 def test_get_long_path_name():
382 p = path.get_long_path_name('/usr/local')
382 p = path.get_long_path_name('/usr/local')
383 nt.assert_equals(p,'/usr/local')
383 nt.assert_equals(p,'/usr/local')
384
384
385 @dec.skip_win32 # can't create not-user-writable dir on win
385 @dec.skip_win32 # can't create not-user-writable dir on win
386 @with_environment
386 @with_environment
387 def test_not_writable_ipdir():
387 def test_not_writable_ipdir():
388 tmpdir = tempfile.mkdtemp()
388 tmpdir = tempfile.mkdtemp()
389 os.name = "posix"
389 os.name = "posix"
390 env.pop('IPYTHON_DIR', None)
390 env.pop('IPYTHON_DIR', None)
391 env.pop('IPYTHONDIR', None)
391 env.pop('IPYTHONDIR', None)
392 env.pop('XDG_CONFIG_HOME', None)
392 env.pop('XDG_CONFIG_HOME', None)
393 env['HOME'] = tmpdir
393 env['HOME'] = tmpdir
394 ipdir = os.path.join(tmpdir, '.ipython')
394 ipdir = os.path.join(tmpdir, '.ipython')
395 os.mkdir(ipdir)
395 os.mkdir(ipdir)
396 os.chmod(ipdir, 600)
396 os.chmod(ipdir, 600)
397 with AssertPrints('is not a writable location', channel='stderr'):
397 with AssertPrints('is not a writable location', channel='stderr'):
398 ipdir = path.get_ipython_dir()
398 ipdir = path.get_ipython_dir()
399 env.pop('IPYTHON_DIR', None)
399 env.pop('IPYTHON_DIR', None)
400
400
401 def test_unquote_filename():
401 def test_unquote_filename():
402 for win32 in (True, False):
402 for win32 in (True, False):
403 nt.assert_equals(path.unquote_filename('foo.py', win32=win32), 'foo.py')
403 nt.assert_equals(path.unquote_filename('foo.py', win32=win32), 'foo.py')
404 nt.assert_equals(path.unquote_filename('foo bar.py', win32=win32), 'foo bar.py')
404 nt.assert_equals(path.unquote_filename('foo bar.py', win32=win32), 'foo bar.py')
405 nt.assert_equals(path.unquote_filename('"foo.py"', win32=True), 'foo.py')
405 nt.assert_equals(path.unquote_filename('"foo.py"', win32=True), 'foo.py')
406 nt.assert_equals(path.unquote_filename('"foo bar.py"', win32=True), 'foo bar.py')
406 nt.assert_equals(path.unquote_filename('"foo bar.py"', win32=True), 'foo bar.py')
407 nt.assert_equals(path.unquote_filename("'foo.py'", win32=True), 'foo.py')
407 nt.assert_equals(path.unquote_filename("'foo.py'", win32=True), 'foo.py')
408 nt.assert_equals(path.unquote_filename("'foo bar.py'", win32=True), 'foo bar.py')
408 nt.assert_equals(path.unquote_filename("'foo bar.py'", win32=True), 'foo bar.py')
409 nt.assert_equals(path.unquote_filename('"foo.py"', win32=False), '"foo.py"')
409 nt.assert_equals(path.unquote_filename('"foo.py"', win32=False), '"foo.py"')
410 nt.assert_equals(path.unquote_filename('"foo bar.py"', win32=False), '"foo bar.py"')
410 nt.assert_equals(path.unquote_filename('"foo bar.py"', win32=False), '"foo bar.py"')
411 nt.assert_equals(path.unquote_filename("'foo.py'", win32=False), "'foo.py'")
411 nt.assert_equals(path.unquote_filename("'foo.py'", win32=False), "'foo.py'")
412 nt.assert_equals(path.unquote_filename("'foo bar.py'", win32=False), "'foo bar.py'")
412 nt.assert_equals(path.unquote_filename("'foo bar.py'", win32=False), "'foo bar.py'")
413
413
414 @with_environment
414 @with_environment
415 def test_get_py_filename():
415 def test_get_py_filename():
416 os.chdir(TMP_TEST_DIR)
416 os.chdir(TMP_TEST_DIR)
417 for win32 in (True, False):
417 for win32 in (True, False):
418 with make_tempfile('foo.py'):
418 with make_tempfile('foo.py'):
419 nt.assert_equals(path.get_py_filename('foo.py', force_win32=win32), 'foo.py')
419 nt.assert_equals(path.get_py_filename('foo.py', force_win32=win32), 'foo.py')
420 nt.assert_equals(path.get_py_filename('foo', force_win32=win32), 'foo.py')
420 nt.assert_equals(path.get_py_filename('foo', force_win32=win32), 'foo.py')
421 with make_tempfile('foo'):
421 with make_tempfile('foo'):
422 nt.assert_equals(path.get_py_filename('foo', force_win32=win32), 'foo')
422 nt.assert_equals(path.get_py_filename('foo', force_win32=win32), 'foo')
423 nt.assert_raises(IOError, path.get_py_filename, 'foo.py', force_win32=win32)
423 nt.assert_raises(IOError, path.get_py_filename, 'foo.py', force_win32=win32)
424 nt.assert_raises(IOError, path.get_py_filename, 'foo', force_win32=win32)
424 nt.assert_raises(IOError, path.get_py_filename, 'foo', force_win32=win32)
425 nt.assert_raises(IOError, path.get_py_filename, 'foo.py', force_win32=win32)
425 nt.assert_raises(IOError, path.get_py_filename, 'foo.py', force_win32=win32)
426 true_fn = 'foo with spaces.py'
426 true_fn = 'foo with spaces.py'
427 with make_tempfile(true_fn):
427 with make_tempfile(true_fn):
428 nt.assert_equals(path.get_py_filename('foo with spaces', force_win32=win32), true_fn)
428 nt.assert_equals(path.get_py_filename('foo with spaces', force_win32=win32), true_fn)
429 nt.assert_equals(path.get_py_filename('foo with spaces.py', force_win32=win32), true_fn)
429 nt.assert_equals(path.get_py_filename('foo with spaces.py', force_win32=win32), true_fn)
430 if win32:
430 if win32:
431 nt.assert_equals(path.get_py_filename('"foo with spaces.py"', force_win32=True), true_fn)
431 nt.assert_equals(path.get_py_filename('"foo with spaces.py"', force_win32=True), true_fn)
432 nt.assert_equals(path.get_py_filename("'foo with spaces.py'", force_win32=True), true_fn)
432 nt.assert_equals(path.get_py_filename("'foo with spaces.py'", force_win32=True), true_fn)
433 else:
433 else:
434 nt.assert_raises(IOError, path.get_py_filename, '"foo with spaces.py"', force_win32=False)
434 nt.assert_raises(IOError, path.get_py_filename, '"foo with spaces.py"', force_win32=False)
435 nt.assert_raises(IOError, path.get_py_filename, "'foo with spaces.py'", force_win32=False)
435 nt.assert_raises(IOError, path.get_py_filename, "'foo with spaces.py'", force_win32=False)
436
436
437 def test_unicode_in_filename():
437 def test_unicode_in_filename():
438 """When a file doesn't exist, the exception raised should be safe to call
438 """When a file doesn't exist, the exception raised should be safe to call
439 str() on - i.e. in Python 2 it must only have ASCII characters.
439 str() on - i.e. in Python 2 it must only have ASCII characters.
440
440
441 https://github.com/ipython/ipython/issues/875
441 https://github.com/ipython/ipython/issues/875
442 """
442 """
443 try:
443 try:
444 # these calls should not throw unicode encode exceptions
444 # these calls should not throw unicode encode exceptions
445 path.get_py_filename(u'fooéè.py', force_win32=False)
445 path.get_py_filename(u'fooéè.py', force_win32=False)
446 except IOError as ex:
446 except IOError as ex:
447 str(ex)
447 str(ex)
448
448
449
449
450 def test_shellglob():
450 def test_shellglob():
451 """Test glob expansion for %run magic."""
451 """Test glob expansion for %run magic."""
452 filenames_start_with_a = map('a{0}'.format, range(3))
452 filenames_start_with_a = map('a{0}'.format, range(3))
453 filenames_end_with_b = map('{0}b'.format, range(3))
453 filenames_end_with_b = map('{0}b'.format, range(3))
454 filenames = filenames_start_with_a + filenames_end_with_b
454 filenames = filenames_start_with_a + filenames_end_with_b
455
455
456 with TemporaryDirectory() as td:
456 with TemporaryDirectory() as td:
457 save = os.getcwdu()
457 save = os.getcwdu()
458 try:
458 try:
459 os.chdir(td)
459 os.chdir(td)
460
460
461 # Create empty files
461 # Create empty files
462 for fname in filenames:
462 for fname in filenames:
463 open(os.path.join(td, fname), 'w').close()
463 open(os.path.join(td, fname), 'w').close()
464
464
465 def assert_match(patterns, matches):
465 def assert_match(patterns, matches):
466 # glob returns unordered list. that's why sorted is required.
466 # glob returns unordered list. that's why sorted is required.
467 nt.assert_equals(sorted(path.shellglob(patterns)),
467 nt.assert_equals(sorted(path.shellglob(patterns)),
468 sorted(matches))
468 sorted(matches))
469
469
470 assert_match(['*'], filenames)
470 assert_match(['*'], filenames)
471 assert_match(['a*'], filenames_start_with_a)
471 assert_match(['a*'], filenames_start_with_a)
472 assert_match(['*c'], ['*c'])
472 assert_match(['*c'], ['*c'])
473 assert_match(['*', 'a*', '*b', '*c'],
473 assert_match(['*', 'a*', '*b', '*c'],
474 filenames
474 filenames
475 + filenames_start_with_a
475 + filenames_start_with_a
476 + filenames_end_with_b
476 + filenames_end_with_b
477 + ['*c'])
477 + ['*c'])
478
478
479 assert_match([r'\*'], ['*'])
479 assert_match([r'\*'], ['*'])
480 assert_match([r'a\*', 'a*'], ['a*'] + filenames_start_with_a)
480 assert_match([r'a\*', 'a*'], ['a*'] + filenames_start_with_a)
481 assert_match(['a[012]'], filenames_start_with_a)
481 assert_match(['a[012]'], filenames_start_with_a)
482 assert_match([r'a\[012]'], ['a[012]'])
482 assert_match([r'a\[012]'], ['a[012]'])
483 finally:
483 finally:
484 os.chdir(save)
484 os.chdir(save)
485
485
486
486
487 def test_unescape_glob():
487 def test_unescape_glob():
488 nt.assert_equals(path.unescape_glob(r'\*\[\!\]\?'), '*[!]?')
488 nt.assert_equals(path.unescape_glob(r'\*\[\!\]\?'), '*[!]?')
489 nt.assert_equals(path.unescape_glob(r'\\*'), r'\*')
490 nt.assert_equals(path.unescape_glob(r'\\\*'), r'\*')
491 nt.assert_equals(path.unescape_glob(r'\\a'), r'\a')
492 nt.assert_equals(path.unescape_glob(r'\a'), r'\a')
General Comments 0
You need to be logged in to leave comments. Login now