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