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