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