##// END OF EJS Templates
restore My Documents fallback for get_home_dir on Windows
MinRK -
Show More
@@ -1,446 +1,461 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-2009 The IPython Development Team
7 # Copyright (C) 2008-2009 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
22
23 import IPython
23 import IPython
24 from IPython.utils.process import system
24 from IPython.utils.process import system
25 from IPython.utils.importstring import import_item
25 from IPython.utils.importstring import import_item
26 from IPython.utils import py3compat
26 from IPython.utils import py3compat
27
27
28 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
29 # Code
29 # Code
30 #-----------------------------------------------------------------------------
30 #-----------------------------------------------------------------------------
31
31
32 fs_encoding = sys.getfilesystemencoding()
32 fs_encoding = sys.getfilesystemencoding()
33
33
34 def _get_long_path_name(path):
34 def _get_long_path_name(path):
35 """Dummy no-op."""
35 """Dummy no-op."""
36 return path
36 return path
37
37
38 def _writable_dir(path):
38 def _writable_dir(path):
39 """Whether `path` is a directory, to which the user has write access."""
39 """Whether `path` is a directory, to which the user has write access."""
40 return os.path.isdir(path) and os.access(path, os.W_OK)
40 return os.path.isdir(path) and os.access(path, os.W_OK)
41
41
42 if sys.platform == 'win32':
42 if sys.platform == 'win32':
43 def _get_long_path_name(path):
43 def _get_long_path_name(path):
44 """Get a long path name (expand ~) on Windows using ctypes.
44 """Get a long path name (expand ~) on Windows using ctypes.
45
45
46 Examples
46 Examples
47 --------
47 --------
48
48
49 >>> get_long_path_name('c:\\docume~1')
49 >>> get_long_path_name('c:\\docume~1')
50 u'c:\\\\Documents and Settings'
50 u'c:\\\\Documents and Settings'
51
51
52 """
52 """
53 try:
53 try:
54 import ctypes
54 import ctypes
55 except ImportError:
55 except ImportError:
56 raise ImportError('you need to have ctypes installed for this to work')
56 raise ImportError('you need to have ctypes installed for this to work')
57 _GetLongPathName = ctypes.windll.kernel32.GetLongPathNameW
57 _GetLongPathName = ctypes.windll.kernel32.GetLongPathNameW
58 _GetLongPathName.argtypes = [ctypes.c_wchar_p, ctypes.c_wchar_p,
58 _GetLongPathName.argtypes = [ctypes.c_wchar_p, ctypes.c_wchar_p,
59 ctypes.c_uint ]
59 ctypes.c_uint ]
60
60
61 buf = ctypes.create_unicode_buffer(260)
61 buf = ctypes.create_unicode_buffer(260)
62 rv = _GetLongPathName(path, buf, 260)
62 rv = _GetLongPathName(path, buf, 260)
63 if rv == 0 or rv > 260:
63 if rv == 0 or rv > 260:
64 return path
64 return path
65 else:
65 else:
66 return buf.value
66 return buf.value
67
67
68
68
69 def get_long_path_name(path):
69 def get_long_path_name(path):
70 """Expand a path into its long form.
70 """Expand a path into its long form.
71
71
72 On Windows this expands any ~ in the paths. On other platforms, it is
72 On Windows this expands any ~ in the paths. On other platforms, it is
73 a null operation.
73 a null operation.
74 """
74 """
75 return _get_long_path_name(path)
75 return _get_long_path_name(path)
76
76
77
77
78 def unquote_filename(name, win32=(sys.platform=='win32')):
78 def unquote_filename(name, win32=(sys.platform=='win32')):
79 """ On Windows, remove leading and trailing quotes from filenames.
79 """ On Windows, remove leading and trailing quotes from filenames.
80 """
80 """
81 if win32:
81 if win32:
82 if name.startswith(("'", '"')) and name.endswith(("'", '"')):
82 if name.startswith(("'", '"')) and name.endswith(("'", '"')):
83 name = name[1:-1]
83 name = name[1:-1]
84 return name
84 return name
85
85
86
86
87 def get_py_filename(name, force_win32=None):
87 def get_py_filename(name, force_win32=None):
88 """Return a valid python filename in the current directory.
88 """Return a valid python filename in the current directory.
89
89
90 If the given name is not a file, it adds '.py' and searches again.
90 If the given name is not a file, it adds '.py' and searches again.
91 Raises IOError with an informative message if the file isn't found.
91 Raises IOError with an informative message if the file isn't found.
92
92
93 On Windows, apply Windows semantics to the filename. In particular, remove
93 On Windows, apply Windows semantics to the filename. In particular, remove
94 any quoting that has been applied to it. This option can be forced for
94 any quoting that has been applied to it. This option can be forced for
95 testing purposes.
95 testing purposes.
96 """
96 """
97
97
98 name = os.path.expanduser(name)
98 name = os.path.expanduser(name)
99 if force_win32 is None:
99 if force_win32 is None:
100 win32 = (sys.platform == 'win32')
100 win32 = (sys.platform == 'win32')
101 else:
101 else:
102 win32 = force_win32
102 win32 = force_win32
103 name = unquote_filename(name, win32=win32)
103 name = unquote_filename(name, win32=win32)
104 if not os.path.isfile(name) and not name.endswith('.py'):
104 if not os.path.isfile(name) and not name.endswith('.py'):
105 name += '.py'
105 name += '.py'
106 if os.path.isfile(name):
106 if os.path.isfile(name):
107 return name
107 return name
108 else:
108 else:
109 raise IOError,'File `%s` not found.' % name
109 raise IOError,'File `%s` not found.' % name
110
110
111
111
112 def filefind(filename, path_dirs=None):
112 def filefind(filename, path_dirs=None):
113 """Find a file by looking through a sequence of paths.
113 """Find a file by looking through a sequence of paths.
114
114
115 This iterates through a sequence of paths looking for a file and returns
115 This iterates through a sequence of paths looking for a file and returns
116 the full, absolute path of the first occurence of the file. If no set of
116 the full, absolute path of the first occurence of the file. If no set of
117 path dirs is given, the filename is tested as is, after running through
117 path dirs is given, the filename is tested as is, after running through
118 :func:`expandvars` and :func:`expanduser`. Thus a simple call::
118 :func:`expandvars` and :func:`expanduser`. Thus a simple call::
119
119
120 filefind('myfile.txt')
120 filefind('myfile.txt')
121
121
122 will find the file in the current working dir, but::
122 will find the file in the current working dir, but::
123
123
124 filefind('~/myfile.txt')
124 filefind('~/myfile.txt')
125
125
126 Will find the file in the users home directory. This function does not
126 Will find the file in the users home directory. This function does not
127 automatically try any paths, such as the cwd or the user's home directory.
127 automatically try any paths, such as the cwd or the user's home directory.
128
128
129 Parameters
129 Parameters
130 ----------
130 ----------
131 filename : str
131 filename : str
132 The filename to look for.
132 The filename to look for.
133 path_dirs : str, None or sequence of str
133 path_dirs : str, None or sequence of str
134 The sequence of paths to look for the file in. If None, the filename
134 The sequence of paths to look for the file in. If None, the filename
135 need to be absolute or be in the cwd. If a string, the string is
135 need to be absolute or be in the cwd. If a string, the string is
136 put into a sequence and the searched. If a sequence, walk through
136 put into a sequence and the searched. If a sequence, walk through
137 each element and join with ``filename``, calling :func:`expandvars`
137 each element and join with ``filename``, calling :func:`expandvars`
138 and :func:`expanduser` before testing for existence.
138 and :func:`expanduser` before testing for existence.
139
139
140 Returns
140 Returns
141 -------
141 -------
142 Raises :exc:`IOError` or returns absolute path to file.
142 Raises :exc:`IOError` or returns absolute path to file.
143 """
143 """
144
144
145 # If paths are quoted, abspath gets confused, strip them...
145 # If paths are quoted, abspath gets confused, strip them...
146 filename = filename.strip('"').strip("'")
146 filename = filename.strip('"').strip("'")
147 # If the input is an absolute path, just check it exists
147 # If the input is an absolute path, just check it exists
148 if os.path.isabs(filename) and os.path.isfile(filename):
148 if os.path.isabs(filename) and os.path.isfile(filename):
149 return filename
149 return filename
150
150
151 if path_dirs is None:
151 if path_dirs is None:
152 path_dirs = ("",)
152 path_dirs = ("",)
153 elif isinstance(path_dirs, basestring):
153 elif isinstance(path_dirs, basestring):
154 path_dirs = (path_dirs,)
154 path_dirs = (path_dirs,)
155
155
156 for path in path_dirs:
156 for path in path_dirs:
157 if path == '.': path = os.getcwdu()
157 if path == '.': path = os.getcwdu()
158 testname = expand_path(os.path.join(path, filename))
158 testname = expand_path(os.path.join(path, filename))
159 if os.path.isfile(testname):
159 if os.path.isfile(testname):
160 return os.path.abspath(testname)
160 return os.path.abspath(testname)
161
161
162 raise IOError("File %r does not exist in any of the search paths: %r" %
162 raise IOError("File %r does not exist in any of the search paths: %r" %
163 (filename, path_dirs) )
163 (filename, path_dirs) )
164
164
165
165
166 class HomeDirError(Exception):
166 class HomeDirError(Exception):
167 pass
167 pass
168
168
169
169
170 def get_home_dir(require_writable=False):
170 def get_home_dir(require_writable=False):
171 """Return the 'home' directory, as a unicode string.
171 """Return the 'home' directory, as a unicode string.
172
172
173 * First, check for frozen env in case of py2exe
173 * First, check for frozen env in case of py2exe
174 * Otherwise, defer to os.path.expanduser('~')
174 * Otherwise, defer to os.path.expanduser('~')
175
175
176 See stdlib docs for how this is determined.
176 See stdlib docs for how this is determined.
177 $HOME is first priority on *ALL* platforms.
177 $HOME is first priority on *ALL* platforms.
178
178
179 Parameters
179 Parameters
180 ----------
180 ----------
181
181
182 require_writable : bool [default: False]
182 require_writable : bool [default: False]
183 if True:
183 if True:
184 guarantees the return value is a writable directory, otherwise
184 guarantees the return value is a writable directory, otherwise
185 raises HomeDirError
185 raises HomeDirError
186 if False:
186 if False:
187 The path is resolved, but it is not guaranteed to exist or be writable.
187 The path is resolved, but it is not guaranteed to exist or be writable.
188 """
188 """
189
189
190 # first, check py2exe distribution root directory for _ipython.
190 # first, check py2exe distribution root directory for _ipython.
191 # This overrides all. Normally does not exist.
191 # This overrides all. Normally does not exist.
192
192
193 if hasattr(sys, "frozen"): #Is frozen by py2exe
193 if hasattr(sys, "frozen"): #Is frozen by py2exe
194 if '\\library.zip\\' in IPython.__file__.lower():#libraries compressed to zip-file
194 if '\\library.zip\\' in IPython.__file__.lower():#libraries compressed to zip-file
195 root, rest = IPython.__file__.lower().split('library.zip')
195 root, rest = IPython.__file__.lower().split('library.zip')
196 else:
196 else:
197 root=os.path.join(os.path.split(IPython.__file__)[0],"../../")
197 root=os.path.join(os.path.split(IPython.__file__)[0],"../../")
198 root=os.path.abspath(root).rstrip('\\')
198 root=os.path.abspath(root).rstrip('\\')
199 if _writable_dir(os.path.join(root, '_ipython')):
199 if _writable_dir(os.path.join(root, '_ipython')):
200 os.environ["IPYKITROOT"] = root
200 os.environ["IPYKITROOT"] = root
201 return py3compat.cast_unicode(root, fs_encoding)
201 return py3compat.cast_unicode(root, fs_encoding)
202
202
203 homedir = os.path.expanduser('~')
203 homedir = os.path.expanduser('~')
204
205 if not _writable_dir(homedir) and os.name == 'nt':
206 # expanduser failed, use the registry to get the 'My Documents' folder.
207 try:
208 import _winreg as wreg
209 key = wreg.OpenKey(
210 wreg.HKEY_CURRENT_USER,
211 "Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders"
212 )
213 homedir = wreg.QueryValueEx(key,'Personal')[0]
214 key.Close()
215 except:
216 pass
217
204 if (not require_writable) or _writable_dir(homedir):
218 if (not require_writable) or _writable_dir(homedir):
205 return py3compat.cast_unicode(homedir, fs_encoding)
219 return py3compat.cast_unicode(homedir, fs_encoding)
206 else:
220 else:
207 raise HomeDirError('%s is not a writable dir, set $HOME env to override' % homedir)
221 raise HomeDirError('%s is not a writable dir, '
222 'set $HOME environment variable to override' % homedir)
208
223
209 def get_xdg_dir():
224 def get_xdg_dir():
210 """Return the XDG_CONFIG_HOME, if it is defined and exists, else None.
225 """Return the XDG_CONFIG_HOME, if it is defined and exists, else None.
211
226
212 This is only for posix (Linux,Unix,OS X, etc) systems.
227 This is only for posix (Linux,Unix,OS X, etc) systems.
213 """
228 """
214
229
215 env = os.environ
230 env = os.environ
216
231
217 if os.name == 'posix':
232 if os.name == 'posix':
218 # Linux, Unix, AIX, OS X
233 # Linux, Unix, AIX, OS X
219 # use ~/.config if empty OR not set
234 # use ~/.config if empty OR not set
220 xdg = env.get("XDG_CONFIG_HOME", None) or os.path.join(get_home_dir(), '.config')
235 xdg = env.get("XDG_CONFIG_HOME", None) or os.path.join(get_home_dir(), '.config')
221 if xdg and _writable_dir(xdg):
236 if xdg and _writable_dir(xdg):
222 return py3compat.cast_unicode(xdg, fs_encoding)
237 return py3compat.cast_unicode(xdg, fs_encoding)
223
238
224 return None
239 return None
225
240
226
241
227 def get_ipython_dir():
242 def get_ipython_dir():
228 """Get the IPython directory for this platform and user.
243 """Get the IPython directory for this platform and user.
229
244
230 This uses the logic in `get_home_dir` to find the home directory
245 This uses the logic in `get_home_dir` to find the home directory
231 and then adds .ipython to the end of the path.
246 and then adds .ipython to the end of the path.
232 """
247 """
233
248
234 env = os.environ
249 env = os.environ
235 pjoin = os.path.join
250 pjoin = os.path.join
236
251
237
252
238 ipdir_def = '.ipython'
253 ipdir_def = '.ipython'
239 xdg_def = 'ipython'
254 xdg_def = 'ipython'
240
255
241 home_dir = get_home_dir()
256 home_dir = get_home_dir()
242 xdg_dir = get_xdg_dir()
257 xdg_dir = get_xdg_dir()
243
258
244 # import pdb; pdb.set_trace() # dbg
259 # import pdb; pdb.set_trace() # dbg
245 ipdir = env.get('IPYTHON_DIR', env.get('IPYTHONDIR', None))
260 ipdir = env.get('IPYTHON_DIR', env.get('IPYTHONDIR', None))
246 if ipdir is None:
261 if ipdir is None:
247 # not set explicitly, use XDG_CONFIG_HOME or HOME
262 # not set explicitly, use XDG_CONFIG_HOME or HOME
248 home_ipdir = pjoin(home_dir, ipdir_def)
263 home_ipdir = pjoin(home_dir, ipdir_def)
249 if xdg_dir:
264 if xdg_dir:
250 # use XDG, as long as the user isn't already
265 # use XDG, as long as the user isn't already
251 # using $HOME/.ipython and *not* XDG/ipython
266 # using $HOME/.ipython and *not* XDG/ipython
252
267
253 xdg_ipdir = pjoin(xdg_dir, xdg_def)
268 xdg_ipdir = pjoin(xdg_dir, xdg_def)
254
269
255 if _writable_dir(xdg_ipdir) or not _writable_dir(home_ipdir):
270 if _writable_dir(xdg_ipdir) or not _writable_dir(home_ipdir):
256 ipdir = xdg_ipdir
271 ipdir = xdg_ipdir
257
272
258 if ipdir is None:
273 if ipdir is None:
259 # not using XDG
274 # not using XDG
260 ipdir = home_ipdir
275 ipdir = home_ipdir
261
276
262 ipdir = os.path.normpath(os.path.expanduser(ipdir))
277 ipdir = os.path.normpath(os.path.expanduser(ipdir))
263
278
264 if os.path.exists(ipdir) and not _writable_dir(ipdir):
279 if os.path.exists(ipdir) and not _writable_dir(ipdir):
265 # ipdir exists, but is not writable
280 # ipdir exists, but is not writable
266 warnings.warn("IPython dir '%s' is not a writable location,"
281 warnings.warn("IPython dir '%s' is not a writable location,"
267 " using a temp directory."%ipdir)
282 " using a temp directory."%ipdir)
268 ipdir = tempfile.mkdtemp()
283 ipdir = tempfile.mkdtemp()
269 elif not os.path.exists(ipdir):
284 elif not os.path.exists(ipdir):
270 parent = ipdir.rsplit(os.path.sep, 1)[0]
285 parent = ipdir.rsplit(os.path.sep, 1)[0]
271 if not _writable_dir(parent):
286 if not _writable_dir(parent):
272 # ipdir does not exist and parent isn't writable
287 # ipdir does not exist and parent isn't writable
273 warnings.warn("IPython parent '%s' is not a writable location,"
288 warnings.warn("IPython parent '%s' is not a writable location,"
274 " using a temp directory."%parent)
289 " using a temp directory."%parent)
275 ipdir = tempfile.mkdtemp()
290 ipdir = tempfile.mkdtemp()
276
291
277 return py3compat.cast_unicode(ipdir, fs_encoding)
292 return py3compat.cast_unicode(ipdir, fs_encoding)
278
293
279
294
280 def get_ipython_package_dir():
295 def get_ipython_package_dir():
281 """Get the base directory where IPython itself is installed."""
296 """Get the base directory where IPython itself is installed."""
282 ipdir = os.path.dirname(IPython.__file__)
297 ipdir = os.path.dirname(IPython.__file__)
283 return py3compat.cast_unicode(ipdir, fs_encoding)
298 return py3compat.cast_unicode(ipdir, fs_encoding)
284
299
285
300
286 def get_ipython_module_path(module_str):
301 def get_ipython_module_path(module_str):
287 """Find the path to an IPython module in this version of IPython.
302 """Find the path to an IPython module in this version of IPython.
288
303
289 This will always find the version of the module that is in this importable
304 This will always find the version of the module that is in this importable
290 IPython package. This will always return the path to the ``.py``
305 IPython package. This will always return the path to the ``.py``
291 version of the module.
306 version of the module.
292 """
307 """
293 if module_str == 'IPython':
308 if module_str == 'IPython':
294 return os.path.join(get_ipython_package_dir(), '__init__.py')
309 return os.path.join(get_ipython_package_dir(), '__init__.py')
295 mod = import_item(module_str)
310 mod = import_item(module_str)
296 the_path = mod.__file__.replace('.pyc', '.py')
311 the_path = mod.__file__.replace('.pyc', '.py')
297 the_path = the_path.replace('.pyo', '.py')
312 the_path = the_path.replace('.pyo', '.py')
298 return py3compat.cast_unicode(the_path, fs_encoding)
313 return py3compat.cast_unicode(the_path, fs_encoding)
299
314
300 def locate_profile(profile='default'):
315 def locate_profile(profile='default'):
301 """Find the path to the folder associated with a given profile.
316 """Find the path to the folder associated with a given profile.
302
317
303 I.e. find $IPYTHON_DIR/profile_whatever.
318 I.e. find $IPYTHON_DIR/profile_whatever.
304 """
319 """
305 from IPython.core.profiledir import ProfileDir, ProfileDirError
320 from IPython.core.profiledir import ProfileDir, ProfileDirError
306 try:
321 try:
307 pd = ProfileDir.find_profile_dir_by_name(get_ipython_dir(), profile)
322 pd = ProfileDir.find_profile_dir_by_name(get_ipython_dir(), profile)
308 except ProfileDirError:
323 except ProfileDirError:
309 # IOError makes more sense when people are expecting a path
324 # IOError makes more sense when people are expecting a path
310 raise IOError("Couldn't find profile %r" % profile)
325 raise IOError("Couldn't find profile %r" % profile)
311 return pd.location
326 return pd.location
312
327
313 def expand_path(s):
328 def expand_path(s):
314 """Expand $VARS and ~names in a string, like a shell
329 """Expand $VARS and ~names in a string, like a shell
315
330
316 :Examples:
331 :Examples:
317
332
318 In [2]: os.environ['FOO']='test'
333 In [2]: os.environ['FOO']='test'
319
334
320 In [3]: expand_path('variable FOO is $FOO')
335 In [3]: expand_path('variable FOO is $FOO')
321 Out[3]: 'variable FOO is test'
336 Out[3]: 'variable FOO is test'
322 """
337 """
323 # This is a pretty subtle hack. When expand user is given a UNC path
338 # This is a pretty subtle hack. When expand user is given a UNC path
324 # on Windows (\\server\share$\%username%), os.path.expandvars, removes
339 # on Windows (\\server\share$\%username%), os.path.expandvars, removes
325 # the $ to get (\\server\share\%username%). I think it considered $
340 # the $ to get (\\server\share\%username%). I think it considered $
326 # alone an empty var. But, we need the $ to remains there (it indicates
341 # alone an empty var. But, we need the $ to remains there (it indicates
327 # a hidden share).
342 # a hidden share).
328 if os.name=='nt':
343 if os.name=='nt':
329 s = s.replace('$\\', 'IPYTHON_TEMP')
344 s = s.replace('$\\', 'IPYTHON_TEMP')
330 s = os.path.expandvars(os.path.expanduser(s))
345 s = os.path.expandvars(os.path.expanduser(s))
331 if os.name=='nt':
346 if os.name=='nt':
332 s = s.replace('IPYTHON_TEMP', '$\\')
347 s = s.replace('IPYTHON_TEMP', '$\\')
333 return s
348 return s
334
349
335
350
336 def target_outdated(target,deps):
351 def target_outdated(target,deps):
337 """Determine whether a target is out of date.
352 """Determine whether a target is out of date.
338
353
339 target_outdated(target,deps) -> 1/0
354 target_outdated(target,deps) -> 1/0
340
355
341 deps: list of filenames which MUST exist.
356 deps: list of filenames which MUST exist.
342 target: single filename which may or may not exist.
357 target: single filename which may or may not exist.
343
358
344 If target doesn't exist or is older than any file listed in deps, return
359 If target doesn't exist or is older than any file listed in deps, return
345 true, otherwise return false.
360 true, otherwise return false.
346 """
361 """
347 try:
362 try:
348 target_time = os.path.getmtime(target)
363 target_time = os.path.getmtime(target)
349 except os.error:
364 except os.error:
350 return 1
365 return 1
351 for dep in deps:
366 for dep in deps:
352 dep_time = os.path.getmtime(dep)
367 dep_time = os.path.getmtime(dep)
353 if dep_time > target_time:
368 if dep_time > target_time:
354 #print "For target",target,"Dep failed:",dep # dbg
369 #print "For target",target,"Dep failed:",dep # dbg
355 #print "times (dep,tar):",dep_time,target_time # dbg
370 #print "times (dep,tar):",dep_time,target_time # dbg
356 return 1
371 return 1
357 return 0
372 return 0
358
373
359
374
360 def target_update(target,deps,cmd):
375 def target_update(target,deps,cmd):
361 """Update a target with a given command given a list of dependencies.
376 """Update a target with a given command given a list of dependencies.
362
377
363 target_update(target,deps,cmd) -> runs cmd if target is outdated.
378 target_update(target,deps,cmd) -> runs cmd if target is outdated.
364
379
365 This is just a wrapper around target_outdated() which calls the given
380 This is just a wrapper around target_outdated() which calls the given
366 command if target is outdated."""
381 command if target is outdated."""
367
382
368 if target_outdated(target,deps):
383 if target_outdated(target,deps):
369 system(cmd)
384 system(cmd)
370
385
371 def filehash(path):
386 def filehash(path):
372 """Make an MD5 hash of a file, ignoring any differences in line
387 """Make an MD5 hash of a file, ignoring any differences in line
373 ending characters."""
388 ending characters."""
374 with open(path, "rU") as f:
389 with open(path, "rU") as f:
375 return md5(py3compat.str_to_bytes(f.read())).hexdigest()
390 return md5(py3compat.str_to_bytes(f.read())).hexdigest()
376
391
377 # If the config is unmodified from the default, we'll just delete it.
392 # If the config is unmodified from the default, we'll just delete it.
378 # These are consistent for 0.10.x, thankfully. We're not going to worry about
393 # These are consistent for 0.10.x, thankfully. We're not going to worry about
379 # older versions.
394 # older versions.
380 old_config_md5 = {'ipy_user_conf.py': 'fc108bedff4b9a00f91fa0a5999140d3',
395 old_config_md5 = {'ipy_user_conf.py': 'fc108bedff4b9a00f91fa0a5999140d3',
381 'ipythonrc': '12a68954f3403eea2eec09dc8fe5a9b5'}
396 'ipythonrc': '12a68954f3403eea2eec09dc8fe5a9b5'}
382
397
383 def check_for_old_config(ipython_dir=None):
398 def check_for_old_config(ipython_dir=None):
384 """Check for old config files, and present a warning if they exist.
399 """Check for old config files, and present a warning if they exist.
385
400
386 A link to the docs of the new config is included in the message.
401 A link to the docs of the new config is included in the message.
387
402
388 This should mitigate confusion with the transition to the new
403 This should mitigate confusion with the transition to the new
389 config system in 0.11.
404 config system in 0.11.
390 """
405 """
391 if ipython_dir is None:
406 if ipython_dir is None:
392 ipython_dir = get_ipython_dir()
407 ipython_dir = get_ipython_dir()
393
408
394 old_configs = ['ipy_user_conf.py', 'ipythonrc', 'ipython_config.py']
409 old_configs = ['ipy_user_conf.py', 'ipythonrc', 'ipython_config.py']
395 warned = False
410 warned = False
396 for cfg in old_configs:
411 for cfg in old_configs:
397 f = os.path.join(ipython_dir, cfg)
412 f = os.path.join(ipython_dir, cfg)
398 if os.path.exists(f):
413 if os.path.exists(f):
399 if filehash(f) == old_config_md5.get(cfg, ''):
414 if filehash(f) == old_config_md5.get(cfg, ''):
400 os.unlink(f)
415 os.unlink(f)
401 else:
416 else:
402 warnings.warn("Found old IPython config file %r (modified by user)"%f)
417 warnings.warn("Found old IPython config file %r (modified by user)"%f)
403 warned = True
418 warned = True
404
419
405 if warned:
420 if warned:
406 warnings.warn("""
421 warnings.warn("""
407 The IPython configuration system has changed as of 0.11, and these files will
422 The IPython configuration system has changed as of 0.11, and these files will
408 be ignored. See http://ipython.github.com/ipython-doc/dev/config for details
423 be ignored. See http://ipython.github.com/ipython-doc/dev/config for details
409 of the new config system.
424 of the new config system.
410 To start configuring IPython, do `ipython profile create`, and edit
425 To start configuring IPython, do `ipython profile create`, and edit
411 `ipython_config.py` in <ipython_dir>/profile_default.
426 `ipython_config.py` in <ipython_dir>/profile_default.
412 If you need to leave the old config files in place for an older version of
427 If you need to leave the old config files in place for an older version of
413 IPython and want to suppress this warning message, set
428 IPython and want to suppress this warning message, set
414 `c.InteractiveShellApp.ignore_old_config=True` in the new config.""")
429 `c.InteractiveShellApp.ignore_old_config=True` in the new config.""")
415
430
416 def get_security_file(filename, profile='default'):
431 def get_security_file(filename, profile='default'):
417 """Return the absolute path of a security file given by filename and profile
432 """Return the absolute path of a security file given by filename and profile
418
433
419 This allows users and developers to find security files without
434 This allows users and developers to find security files without
420 knowledge of the IPython directory structure. The search path
435 knowledge of the IPython directory structure. The search path
421 will be ['.', profile.security_dir]
436 will be ['.', profile.security_dir]
422
437
423 Parameters
438 Parameters
424 ----------
439 ----------
425
440
426 filename : str
441 filename : str
427 The file to be found. If it is passed as an absolute path, it will
442 The file to be found. If it is passed as an absolute path, it will
428 simply be returned.
443 simply be returned.
429 profile : str [default: 'default']
444 profile : str [default: 'default']
430 The name of the profile to search. Leaving this unspecified
445 The name of the profile to search. Leaving this unspecified
431 The file to be found. If it is passed as an absolute path, fname will
446 The file to be found. If it is passed as an absolute path, fname will
432 simply be returned.
447 simply be returned.
433
448
434 Returns
449 Returns
435 -------
450 -------
436 Raises :exc:`IOError` if file not found or returns absolute path to file.
451 Raises :exc:`IOError` if file not found or returns absolute path to file.
437 """
452 """
438 # import here, because profiledir also imports from utils.path
453 # import here, because profiledir also imports from utils.path
439 from IPython.core.profiledir import ProfileDir
454 from IPython.core.profiledir import ProfileDir
440 try:
455 try:
441 pd = ProfileDir.find_profile_dir_by_name(get_ipython_dir(), profile)
456 pd = ProfileDir.find_profile_dir_by_name(get_ipython_dir(), profile)
442 except Exception:
457 except Exception:
443 # will raise ProfileDirError if no such profile
458 # will raise ProfileDirError if no such profile
444 raise IOError("Profile %r not found")
459 raise IOError("Profile %r not found")
445 return filefind(filename, ['.', pd.security_dir])
460 return filefind(filename, ['.', pd.security_dir])
446
461
@@ -1,375 +1,407 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 The IPython Development Team
5 # Copyright (C) 2008 The IPython Development Team
6 #
6 #
7 # Distributed under the terms of the BSD License. The full license is in
7 # Distributed under the terms of the BSD License. The full license is in
8 # the file COPYING, distributed as part of this software.
8 # the file COPYING, distributed as part of this software.
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Imports
12 # Imports
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 from __future__ import with_statement
15 from __future__ import with_statement
16
16
17 import os
17 import os
18 import shutil
18 import shutil
19 import sys
19 import sys
20 import tempfile
20 import tempfile
21 from io import StringIO
21 from io import StringIO
22
22
23 from os.path import join, abspath, split
23 from os.path import join, abspath, split
24
24
25 import nose.tools as nt
25 import nose.tools as nt
26
26
27 from nose import with_setup
27 from nose import with_setup
28
28
29 import IPython
29 import IPython
30 from IPython.testing import decorators as dec
30 from IPython.testing import decorators as dec
31 from IPython.testing.decorators import skip_if_not_win32, skip_win32
31 from IPython.testing.decorators import skip_if_not_win32, skip_win32
32 from IPython.testing.tools import make_tempfile, AssertPrints
32 from IPython.testing.tools import make_tempfile, AssertPrints
33 from IPython.utils import path, io
33 from IPython.utils import path, io
34 from IPython.utils import py3compat
34 from IPython.utils import py3compat
35
35
36 # Platform-dependent imports
36 # Platform-dependent imports
37 try:
37 try:
38 import _winreg as wreg
38 import _winreg as wreg
39 except ImportError:
39 except ImportError:
40 #Fake _winreg module on none windows platforms
40 #Fake _winreg module on none windows platforms
41 import types
41 import types
42 wr_name = "winreg" if py3compat.PY3 else "_winreg"
42 wr_name = "winreg" if py3compat.PY3 else "_winreg"
43 sys.modules[wr_name] = types.ModuleType(wr_name)
43 sys.modules[wr_name] = types.ModuleType(wr_name)
44 import _winreg as wreg
44 import _winreg as wreg
45 #Add entries that needs to be stubbed by the testing code
45 #Add entries that needs to be stubbed by the testing code
46 (wreg.OpenKey, wreg.QueryValueEx,) = (None, None)
46 (wreg.OpenKey, wreg.QueryValueEx,) = (None, None)
47
47
48 try:
48 try:
49 reload
49 reload
50 except NameError: # Python 3
50 except NameError: # Python 3
51 from imp import reload
51 from imp import reload
52
52
53 #-----------------------------------------------------------------------------
53 #-----------------------------------------------------------------------------
54 # Globals
54 # Globals
55 #-----------------------------------------------------------------------------
55 #-----------------------------------------------------------------------------
56 env = os.environ
56 env = os.environ
57 TEST_FILE_PATH = split(abspath(__file__))[0]
57 TEST_FILE_PATH = split(abspath(__file__))[0]
58 TMP_TEST_DIR = tempfile.mkdtemp()
58 TMP_TEST_DIR = tempfile.mkdtemp()
59 HOME_TEST_DIR = join(TMP_TEST_DIR, "home_test_dir")
59 HOME_TEST_DIR = join(TMP_TEST_DIR, "home_test_dir")
60 XDG_TEST_DIR = join(HOME_TEST_DIR, "xdg_test_dir")
60 XDG_TEST_DIR = join(HOME_TEST_DIR, "xdg_test_dir")
61 IP_TEST_DIR = join(HOME_TEST_DIR,'.ipython')
61 IP_TEST_DIR = join(HOME_TEST_DIR,'.ipython')
62 #
62 #
63 # Setup/teardown functions/decorators
63 # Setup/teardown functions/decorators
64 #
64 #
65
65
66 def setup():
66 def setup():
67 """Setup testenvironment for the module:
67 """Setup testenvironment for the module:
68
68
69 - Adds dummy home dir tree
69 - Adds dummy home dir tree
70 """
70 """
71 # Do not mask exceptions here. In particular, catching WindowsError is a
71 # Do not mask exceptions here. In particular, catching WindowsError is a
72 # problem because that exception is only defined on Windows...
72 # problem because that exception is only defined on Windows...
73 os.makedirs(IP_TEST_DIR)
73 os.makedirs(IP_TEST_DIR)
74 os.makedirs(os.path.join(XDG_TEST_DIR, 'ipython'))
74 os.makedirs(os.path.join(XDG_TEST_DIR, 'ipython'))
75
75
76
76
77 def teardown():
77 def teardown():
78 """Teardown testenvironment for the module:
78 """Teardown testenvironment for the module:
79
79
80 - Remove dummy home dir tree
80 - Remove dummy home dir tree
81 """
81 """
82 # Note: we remove the parent test dir, which is the root of all test
82 # Note: we remove the parent test dir, which is the root of all test
83 # subdirs we may have created. Use shutil instead of os.removedirs, so
83 # subdirs we may have created. Use shutil instead of os.removedirs, so
84 # that non-empty directories are all recursively removed.
84 # that non-empty directories are all recursively removed.
85 shutil.rmtree(TMP_TEST_DIR)
85 shutil.rmtree(TMP_TEST_DIR)
86
86
87
87
88 def setup_environment():
88 def setup_environment():
89 """Setup testenvironment for some functions that are tested
89 """Setup testenvironment for some functions that are tested
90 in this module. In particular this functions stores attributes
90 in this module. In particular this functions stores attributes
91 and other things that we need to stub in some test functions.
91 and other things that we need to stub in some test functions.
92 This needs to be done on a function level and not module level because
92 This needs to be done on a function level and not module level because
93 each testfunction needs a pristine environment.
93 each testfunction needs a pristine environment.
94 """
94 """
95 global oldstuff, platformstuff
95 global oldstuff, platformstuff
96 oldstuff = (env.copy(), os.name, path.get_home_dir, IPython.__file__, os.getcwd())
96 oldstuff = (env.copy(), os.name, path.get_home_dir, IPython.__file__, os.getcwd())
97
97
98 if os.name == 'nt':
98 if os.name == 'nt':
99 platformstuff = (wreg.OpenKey, wreg.QueryValueEx,)
99 platformstuff = (wreg.OpenKey, wreg.QueryValueEx,)
100
100
101
101
102 def teardown_environment():
102 def teardown_environment():
103 """Restore things that were remebered by the setup_environment function
103 """Restore things that were remebered by the setup_environment function
104 """
104 """
105 (oldenv, os.name, path.get_home_dir, IPython.__file__, old_wd) = oldstuff
105 (oldenv, os.name, path.get_home_dir, IPython.__file__, old_wd) = oldstuff
106 os.chdir(old_wd)
106 os.chdir(old_wd)
107 reload(path)
107 reload(path)
108
108
109 for key in env.keys():
109 for key in env.keys():
110 if key not in oldenv:
110 if key not in oldenv:
111 del env[key]
111 del env[key]
112 env.update(oldenv)
112 env.update(oldenv)
113 if hasattr(sys, 'frozen'):
113 if hasattr(sys, 'frozen'):
114 del sys.frozen
114 del sys.frozen
115 if os.name == 'nt':
115 if os.name == 'nt':
116 (wreg.OpenKey, wreg.QueryValueEx,) = platformstuff
116 (wreg.OpenKey, wreg.QueryValueEx,) = platformstuff
117
117
118 # Build decorator that uses the setup_environment/setup_environment
118 # Build decorator that uses the setup_environment/setup_environment
119 with_environment = with_setup(setup_environment, teardown_environment)
119 with_environment = with_setup(setup_environment, teardown_environment)
120
120
121 @skip_if_not_win32
121 @skip_if_not_win32
122 @with_environment
122 @with_environment
123 def test_get_home_dir_1():
123 def test_get_home_dir_1():
124 """Testcase for py2exe logic, un-compressed lib
124 """Testcase for py2exe logic, un-compressed lib
125 """
125 """
126 sys.frozen = True
126 sys.frozen = True
127
127
128 #fake filename for IPython.__init__
128 #fake filename for IPython.__init__
129 IPython.__file__ = abspath(join(HOME_TEST_DIR, "Lib/IPython/__init__.py"))
129 IPython.__file__ = abspath(join(HOME_TEST_DIR, "Lib/IPython/__init__.py"))
130
130
131 home_dir = path.get_home_dir()
131 home_dir = path.get_home_dir()
132 nt.assert_equal(home_dir, abspath(HOME_TEST_DIR))
132 nt.assert_equal(home_dir, abspath(HOME_TEST_DIR))
133
133
134
134
135 @skip_if_not_win32
135 @skip_if_not_win32
136 @with_environment
136 @with_environment
137 def test_get_home_dir_2():
137 def test_get_home_dir_2():
138 """Testcase for py2exe logic, compressed lib
138 """Testcase for py2exe logic, compressed lib
139 """
139 """
140 sys.frozen = True
140 sys.frozen = True
141 #fake filename for IPython.__init__
141 #fake filename for IPython.__init__
142 IPython.__file__ = abspath(join(HOME_TEST_DIR, "Library.zip/IPython/__init__.py")).lower()
142 IPython.__file__ = abspath(join(HOME_TEST_DIR, "Library.zip/IPython/__init__.py")).lower()
143
143
144 home_dir = path.get_home_dir(True)
144 home_dir = path.get_home_dir(True)
145 nt.assert_equal(home_dir, abspath(HOME_TEST_DIR).lower())
145 nt.assert_equal(home_dir, abspath(HOME_TEST_DIR).lower())
146
146
147
147
148 @with_environment
148 @with_environment
149 def test_get_home_dir_3():
149 def test_get_home_dir_3():
150 """get_home_dir() uses $HOME if set"""
150 """get_home_dir() uses $HOME if set"""
151 env["HOME"] = HOME_TEST_DIR
151 env["HOME"] = HOME_TEST_DIR
152 home_dir = path.get_home_dir(True)
152 home_dir = path.get_home_dir(True)
153 nt.assert_equal(home_dir, env["HOME"])
153 nt.assert_equal(home_dir, env["HOME"])
154
154
155
155
156 @with_environment
156 @with_environment
157 def test_get_home_dir_4():
157 def test_get_home_dir_4():
158 """get_home_dir() still works if $HOME is not set"""
158 """get_home_dir() still works if $HOME is not set"""
159
159
160 if 'HOME' in env: del env['HOME']
160 if 'HOME' in env: del env['HOME']
161 # this should still succeed, but we don't know what the answer should be
161 # this should still succeed, but we don't know what the answer should be
162 home = path.get_home_dir(True)
162 home = path.get_home_dir(True)
163 nt.assert_true(path._writable_dir(home))
163 nt.assert_true(path._writable_dir(home))
164
164
165 @with_environment
165 @with_environment
166 def test_get_home_dir_5():
166 def test_get_home_dir_5():
167 """raise HomeDirError if $HOME is specified, but not a writable dir"""
167 """raise HomeDirError if $HOME is specified, but not a writable dir"""
168 env['HOME'] = abspath(HOME_TEST_DIR+'garbage')
168 env['HOME'] = abspath(HOME_TEST_DIR+'garbage')
169 # set os.name = posix, to prevent My Documents fallback on Windows
170 os.name = 'posix'
169 nt.assert_raises(path.HomeDirError, path.get_home_dir, True)
171 nt.assert_raises(path.HomeDirError, path.get_home_dir, True)
170
172
173
174 # Should we stub wreg fully so we can run the test on all platforms?
175 @skip_if_not_win32
176 @with_environment
177 def test_get_home_dir_8():
178 """Using registry hack for 'My Documents', os=='nt'
179
180 HOMESHARE, HOMEDRIVE, HOMEPATH, USERPROFILE and others are missing.
181 """
182 os.name = 'nt'
183 # Remove from stub environment all keys that may be set
184 for key in ['HOME', 'HOMESHARE', 'HOMEDRIVE', 'HOMEPATH', 'USERPROFILE']:
185 env.pop(key, None)
186
187 #Stub windows registry functions
188 def OpenKey(x, y):
189 class key:
190 def Close(self):
191 pass
192 return key()
193 def QueryValueEx(x, y):
194 return [abspath(HOME_TEST_DIR)]
195
196 wreg.OpenKey = OpenKey
197 wreg.QueryValueEx = QueryValueEx
198
199 home_dir = path.get_home_dir()
200 nt.assert_equal(home_dir, abspath(HOME_TEST_DIR))
201
202
171 @with_environment
203 @with_environment
172 def test_get_ipython_dir_1():
204 def test_get_ipython_dir_1():
173 """test_get_ipython_dir_1, Testcase to see if we can call get_ipython_dir without Exceptions."""
205 """test_get_ipython_dir_1, Testcase to see if we can call get_ipython_dir without Exceptions."""
174 env_ipdir = os.path.join("someplace", ".ipython")
206 env_ipdir = os.path.join("someplace", ".ipython")
175 path._writable_dir = lambda path: True
207 path._writable_dir = lambda path: True
176 env['IPYTHON_DIR'] = env_ipdir
208 env['IPYTHON_DIR'] = env_ipdir
177 ipdir = path.get_ipython_dir()
209 ipdir = path.get_ipython_dir()
178 nt.assert_equal(ipdir, env_ipdir)
210 nt.assert_equal(ipdir, env_ipdir)
179
211
180
212
181 @with_environment
213 @with_environment
182 def test_get_ipython_dir_2():
214 def test_get_ipython_dir_2():
183 """test_get_ipython_dir_2, Testcase to see if we can call get_ipython_dir without Exceptions."""
215 """test_get_ipython_dir_2, Testcase to see if we can call get_ipython_dir without Exceptions."""
184 path.get_home_dir = lambda : "someplace"
216 path.get_home_dir = lambda : "someplace"
185 path.get_xdg_dir = lambda : None
217 path.get_xdg_dir = lambda : None
186 path._writable_dir = lambda path: True
218 path._writable_dir = lambda path: True
187 os.name = "posix"
219 os.name = "posix"
188 env.pop('IPYTHON_DIR', None)
220 env.pop('IPYTHON_DIR', None)
189 env.pop('IPYTHONDIR', None)
221 env.pop('IPYTHONDIR', None)
190 env.pop('XDG_CONFIG_HOME', None)
222 env.pop('XDG_CONFIG_HOME', None)
191 ipdir = path.get_ipython_dir()
223 ipdir = path.get_ipython_dir()
192 nt.assert_equal(ipdir, os.path.join("someplace", ".ipython"))
224 nt.assert_equal(ipdir, os.path.join("someplace", ".ipython"))
193
225
194 @with_environment
226 @with_environment
195 def test_get_ipython_dir_3():
227 def test_get_ipython_dir_3():
196 """test_get_ipython_dir_3, use XDG if defined, and .ipython doesn't exist."""
228 """test_get_ipython_dir_3, use XDG if defined, and .ipython doesn't exist."""
197 path.get_home_dir = lambda : "someplace"
229 path.get_home_dir = lambda : "someplace"
198 path._writable_dir = lambda path: True
230 path._writable_dir = lambda path: True
199 os.name = "posix"
231 os.name = "posix"
200 env.pop('IPYTHON_DIR', None)
232 env.pop('IPYTHON_DIR', None)
201 env.pop('IPYTHONDIR', None)
233 env.pop('IPYTHONDIR', None)
202 env['XDG_CONFIG_HOME'] = XDG_TEST_DIR
234 env['XDG_CONFIG_HOME'] = XDG_TEST_DIR
203 ipdir = path.get_ipython_dir()
235 ipdir = path.get_ipython_dir()
204 nt.assert_equal(ipdir, os.path.join(XDG_TEST_DIR, "ipython"))
236 nt.assert_equal(ipdir, os.path.join(XDG_TEST_DIR, "ipython"))
205
237
206 @with_environment
238 @with_environment
207 def test_get_ipython_dir_4():
239 def test_get_ipython_dir_4():
208 """test_get_ipython_dir_4, use XDG if both exist."""
240 """test_get_ipython_dir_4, use XDG if both exist."""
209 path.get_home_dir = lambda : HOME_TEST_DIR
241 path.get_home_dir = lambda : HOME_TEST_DIR
210 os.name = "posix"
242 os.name = "posix"
211 env.pop('IPYTHON_DIR', None)
243 env.pop('IPYTHON_DIR', None)
212 env.pop('IPYTHONDIR', None)
244 env.pop('IPYTHONDIR', None)
213 env['XDG_CONFIG_HOME'] = XDG_TEST_DIR
245 env['XDG_CONFIG_HOME'] = XDG_TEST_DIR
214 xdg_ipdir = os.path.join(XDG_TEST_DIR, "ipython")
246 xdg_ipdir = os.path.join(XDG_TEST_DIR, "ipython")
215 ipdir = path.get_ipython_dir()
247 ipdir = path.get_ipython_dir()
216 nt.assert_equal(ipdir, xdg_ipdir)
248 nt.assert_equal(ipdir, xdg_ipdir)
217
249
218 @with_environment
250 @with_environment
219 def test_get_ipython_dir_5():
251 def test_get_ipython_dir_5():
220 """test_get_ipython_dir_5, use .ipython if exists and XDG defined, but doesn't exist."""
252 """test_get_ipython_dir_5, use .ipython if exists and XDG defined, but doesn't exist."""
221 path.get_home_dir = lambda : HOME_TEST_DIR
253 path.get_home_dir = lambda : HOME_TEST_DIR
222 os.name = "posix"
254 os.name = "posix"
223 env.pop('IPYTHON_DIR', None)
255 env.pop('IPYTHON_DIR', None)
224 env.pop('IPYTHONDIR', None)
256 env.pop('IPYTHONDIR', None)
225 env['XDG_CONFIG_HOME'] = XDG_TEST_DIR
257 env['XDG_CONFIG_HOME'] = XDG_TEST_DIR
226 os.rmdir(os.path.join(XDG_TEST_DIR, 'ipython'))
258 os.rmdir(os.path.join(XDG_TEST_DIR, 'ipython'))
227 ipdir = path.get_ipython_dir()
259 ipdir = path.get_ipython_dir()
228 nt.assert_equal(ipdir, IP_TEST_DIR)
260 nt.assert_equal(ipdir, IP_TEST_DIR)
229
261
230 @with_environment
262 @with_environment
231 def test_get_ipython_dir_6():
263 def test_get_ipython_dir_6():
232 """test_get_ipython_dir_6, use XDG if defined and neither exist."""
264 """test_get_ipython_dir_6, use XDG if defined and neither exist."""
233 xdg = os.path.join(HOME_TEST_DIR, 'somexdg')
265 xdg = os.path.join(HOME_TEST_DIR, 'somexdg')
234 os.mkdir(xdg)
266 os.mkdir(xdg)
235 shutil.rmtree(os.path.join(HOME_TEST_DIR, '.ipython'))
267 shutil.rmtree(os.path.join(HOME_TEST_DIR, '.ipython'))
236 path.get_home_dir = lambda : HOME_TEST_DIR
268 path.get_home_dir = lambda : HOME_TEST_DIR
237 path.get_xdg_dir = lambda : xdg
269 path.get_xdg_dir = lambda : xdg
238 os.name = "posix"
270 os.name = "posix"
239 env.pop('IPYTHON_DIR', None)
271 env.pop('IPYTHON_DIR', None)
240 env.pop('IPYTHONDIR', None)
272 env.pop('IPYTHONDIR', None)
241 env.pop('XDG_CONFIG_HOME', None)
273 env.pop('XDG_CONFIG_HOME', None)
242 xdg_ipdir = os.path.join(xdg, "ipython")
274 xdg_ipdir = os.path.join(xdg, "ipython")
243 ipdir = path.get_ipython_dir()
275 ipdir = path.get_ipython_dir()
244 nt.assert_equal(ipdir, xdg_ipdir)
276 nt.assert_equal(ipdir, xdg_ipdir)
245
277
246 @with_environment
278 @with_environment
247 def test_get_ipython_dir_7():
279 def test_get_ipython_dir_7():
248 """test_get_ipython_dir_7, test home directory expansion on IPYTHON_DIR"""
280 """test_get_ipython_dir_7, test home directory expansion on IPYTHON_DIR"""
249 path._writable_dir = lambda path: True
281 path._writable_dir = lambda path: True
250 home_dir = os.path.expanduser('~')
282 home_dir = os.path.expanduser('~')
251 env['IPYTHON_DIR'] = os.path.join('~', 'somewhere')
283 env['IPYTHON_DIR'] = os.path.join('~', 'somewhere')
252 ipdir = path.get_ipython_dir()
284 ipdir = path.get_ipython_dir()
253 nt.assert_equal(ipdir, os.path.join(home_dir, 'somewhere'))
285 nt.assert_equal(ipdir, os.path.join(home_dir, 'somewhere'))
254
286
255
287
256 @with_environment
288 @with_environment
257 def test_get_xdg_dir_1():
289 def test_get_xdg_dir_1():
258 """test_get_xdg_dir_1, check xdg_dir"""
290 """test_get_xdg_dir_1, check xdg_dir"""
259 reload(path)
291 reload(path)
260 path._writable_dir = lambda path: True
292 path._writable_dir = lambda path: True
261 path.get_home_dir = lambda : 'somewhere'
293 path.get_home_dir = lambda : 'somewhere'
262 os.name = "posix"
294 os.name = "posix"
263 env.pop('IPYTHON_DIR', None)
295 env.pop('IPYTHON_DIR', None)
264 env.pop('IPYTHONDIR', None)
296 env.pop('IPYTHONDIR', None)
265 env.pop('XDG_CONFIG_HOME', None)
297 env.pop('XDG_CONFIG_HOME', None)
266
298
267 nt.assert_equal(path.get_xdg_dir(), os.path.join('somewhere', '.config'))
299 nt.assert_equal(path.get_xdg_dir(), os.path.join('somewhere', '.config'))
268
300
269
301
270 @with_environment
302 @with_environment
271 def test_get_xdg_dir_1():
303 def test_get_xdg_dir_1():
272 """test_get_xdg_dir_1, check nonexistant xdg_dir"""
304 """test_get_xdg_dir_1, check nonexistant xdg_dir"""
273 reload(path)
305 reload(path)
274 path.get_home_dir = lambda : HOME_TEST_DIR
306 path.get_home_dir = lambda : HOME_TEST_DIR
275 os.name = "posix"
307 os.name = "posix"
276 env.pop('IPYTHON_DIR', None)
308 env.pop('IPYTHON_DIR', None)
277 env.pop('IPYTHONDIR', None)
309 env.pop('IPYTHONDIR', None)
278 env.pop('XDG_CONFIG_HOME', None)
310 env.pop('XDG_CONFIG_HOME', None)
279 nt.assert_equal(path.get_xdg_dir(), None)
311 nt.assert_equal(path.get_xdg_dir(), None)
280
312
281 @with_environment
313 @with_environment
282 def test_get_xdg_dir_2():
314 def test_get_xdg_dir_2():
283 """test_get_xdg_dir_2, check xdg_dir default to ~/.config"""
315 """test_get_xdg_dir_2, check xdg_dir default to ~/.config"""
284 reload(path)
316 reload(path)
285 path.get_home_dir = lambda : HOME_TEST_DIR
317 path.get_home_dir = lambda : HOME_TEST_DIR
286 os.name = "posix"
318 os.name = "posix"
287 env.pop('IPYTHON_DIR', None)
319 env.pop('IPYTHON_DIR', None)
288 env.pop('IPYTHONDIR', None)
320 env.pop('IPYTHONDIR', None)
289 env.pop('XDG_CONFIG_HOME', None)
321 env.pop('XDG_CONFIG_HOME', None)
290 cfgdir=os.path.join(path.get_home_dir(), '.config')
322 cfgdir=os.path.join(path.get_home_dir(), '.config')
291 os.makedirs(cfgdir)
323 os.makedirs(cfgdir)
292
324
293 nt.assert_equal(path.get_xdg_dir(), cfgdir)
325 nt.assert_equal(path.get_xdg_dir(), cfgdir)
294
326
295 def test_filefind():
327 def test_filefind():
296 """Various tests for filefind"""
328 """Various tests for filefind"""
297 f = tempfile.NamedTemporaryFile()
329 f = tempfile.NamedTemporaryFile()
298 # print 'fname:',f.name
330 # print 'fname:',f.name
299 alt_dirs = path.get_ipython_dir()
331 alt_dirs = path.get_ipython_dir()
300 t = path.filefind(f.name, alt_dirs)
332 t = path.filefind(f.name, alt_dirs)
301 # print 'found:',t
333 # print 'found:',t
302
334
303
335
304 def test_get_ipython_package_dir():
336 def test_get_ipython_package_dir():
305 ipdir = path.get_ipython_package_dir()
337 ipdir = path.get_ipython_package_dir()
306 nt.assert_true(os.path.isdir(ipdir))
338 nt.assert_true(os.path.isdir(ipdir))
307
339
308
340
309 def test_get_ipython_module_path():
341 def test_get_ipython_module_path():
310 ipapp_path = path.get_ipython_module_path('IPython.frontend.terminal.ipapp')
342 ipapp_path = path.get_ipython_module_path('IPython.frontend.terminal.ipapp')
311 nt.assert_true(os.path.isfile(ipapp_path))
343 nt.assert_true(os.path.isfile(ipapp_path))
312
344
313
345
314 @dec.skip_if_not_win32
346 @dec.skip_if_not_win32
315 def test_get_long_path_name_win32():
347 def test_get_long_path_name_win32():
316 p = path.get_long_path_name('c:\\docume~1')
348 p = path.get_long_path_name('c:\\docume~1')
317 nt.assert_equals(p,u'c:\\Documents and Settings')
349 nt.assert_equals(p,u'c:\\Documents and Settings')
318
350
319
351
320 @dec.skip_win32
352 @dec.skip_win32
321 def test_get_long_path_name():
353 def test_get_long_path_name():
322 p = path.get_long_path_name('/usr/local')
354 p = path.get_long_path_name('/usr/local')
323 nt.assert_equals(p,'/usr/local')
355 nt.assert_equals(p,'/usr/local')
324
356
325 @dec.skip_win32 # can't create not-user-writable dir on win
357 @dec.skip_win32 # can't create not-user-writable dir on win
326 @with_environment
358 @with_environment
327 def test_not_writable_ipdir():
359 def test_not_writable_ipdir():
328 tmpdir = tempfile.mkdtemp()
360 tmpdir = tempfile.mkdtemp()
329 os.name = "posix"
361 os.name = "posix"
330 env.pop('IPYTHON_DIR', None)
362 env.pop('IPYTHON_DIR', None)
331 env.pop('IPYTHONDIR', None)
363 env.pop('IPYTHONDIR', None)
332 env.pop('XDG_CONFIG_HOME', None)
364 env.pop('XDG_CONFIG_HOME', None)
333 env['HOME'] = tmpdir
365 env['HOME'] = tmpdir
334 ipdir = os.path.join(tmpdir, '.ipython')
366 ipdir = os.path.join(tmpdir, '.ipython')
335 os.mkdir(ipdir)
367 os.mkdir(ipdir)
336 os.chmod(ipdir, 600)
368 os.chmod(ipdir, 600)
337 with AssertPrints('is not a writable location', channel='stderr'):
369 with AssertPrints('is not a writable location', channel='stderr'):
338 ipdir = path.get_ipython_dir()
370 ipdir = path.get_ipython_dir()
339 env.pop('IPYTHON_DIR', None)
371 env.pop('IPYTHON_DIR', None)
340
372
341 def test_unquote_filename():
373 def test_unquote_filename():
342 for win32 in (True, False):
374 for win32 in (True, False):
343 nt.assert_equals(path.unquote_filename('foo.py', win32=win32), 'foo.py')
375 nt.assert_equals(path.unquote_filename('foo.py', win32=win32), 'foo.py')
344 nt.assert_equals(path.unquote_filename('foo bar.py', win32=win32), 'foo bar.py')
376 nt.assert_equals(path.unquote_filename('foo bar.py', win32=win32), 'foo bar.py')
345 nt.assert_equals(path.unquote_filename('"foo.py"', win32=True), 'foo.py')
377 nt.assert_equals(path.unquote_filename('"foo.py"', win32=True), 'foo.py')
346 nt.assert_equals(path.unquote_filename('"foo bar.py"', win32=True), 'foo bar.py')
378 nt.assert_equals(path.unquote_filename('"foo bar.py"', win32=True), 'foo bar.py')
347 nt.assert_equals(path.unquote_filename("'foo.py'", win32=True), 'foo.py')
379 nt.assert_equals(path.unquote_filename("'foo.py'", win32=True), 'foo.py')
348 nt.assert_equals(path.unquote_filename("'foo bar.py'", win32=True), 'foo bar.py')
380 nt.assert_equals(path.unquote_filename("'foo bar.py'", win32=True), 'foo bar.py')
349 nt.assert_equals(path.unquote_filename('"foo.py"', win32=False), '"foo.py"')
381 nt.assert_equals(path.unquote_filename('"foo.py"', win32=False), '"foo.py"')
350 nt.assert_equals(path.unquote_filename('"foo bar.py"', win32=False), '"foo bar.py"')
382 nt.assert_equals(path.unquote_filename('"foo bar.py"', win32=False), '"foo bar.py"')
351 nt.assert_equals(path.unquote_filename("'foo.py'", win32=False), "'foo.py'")
383 nt.assert_equals(path.unquote_filename("'foo.py'", win32=False), "'foo.py'")
352 nt.assert_equals(path.unquote_filename("'foo bar.py'", win32=False), "'foo bar.py'")
384 nt.assert_equals(path.unquote_filename("'foo bar.py'", win32=False), "'foo bar.py'")
353
385
354 @with_environment
386 @with_environment
355 def test_get_py_filename():
387 def test_get_py_filename():
356 os.chdir(TMP_TEST_DIR)
388 os.chdir(TMP_TEST_DIR)
357 for win32 in (True, False):
389 for win32 in (True, False):
358 with make_tempfile('foo.py'):
390 with make_tempfile('foo.py'):
359 nt.assert_equals(path.get_py_filename('foo.py', force_win32=win32), 'foo.py')
391 nt.assert_equals(path.get_py_filename('foo.py', force_win32=win32), 'foo.py')
360 nt.assert_equals(path.get_py_filename('foo', force_win32=win32), 'foo.py')
392 nt.assert_equals(path.get_py_filename('foo', force_win32=win32), 'foo.py')
361 with make_tempfile('foo'):
393 with make_tempfile('foo'):
362 nt.assert_equals(path.get_py_filename('foo', force_win32=win32), 'foo')
394 nt.assert_equals(path.get_py_filename('foo', force_win32=win32), 'foo')
363 nt.assert_raises(IOError, path.get_py_filename, 'foo.py', force_win32=win32)
395 nt.assert_raises(IOError, path.get_py_filename, 'foo.py', force_win32=win32)
364 nt.assert_raises(IOError, path.get_py_filename, 'foo', force_win32=win32)
396 nt.assert_raises(IOError, path.get_py_filename, 'foo', force_win32=win32)
365 nt.assert_raises(IOError, path.get_py_filename, 'foo.py', force_win32=win32)
397 nt.assert_raises(IOError, path.get_py_filename, 'foo.py', force_win32=win32)
366 true_fn = 'foo with spaces.py'
398 true_fn = 'foo with spaces.py'
367 with make_tempfile(true_fn):
399 with make_tempfile(true_fn):
368 nt.assert_equals(path.get_py_filename('foo with spaces', force_win32=win32), true_fn)
400 nt.assert_equals(path.get_py_filename('foo with spaces', force_win32=win32), true_fn)
369 nt.assert_equals(path.get_py_filename('foo with spaces.py', force_win32=win32), true_fn)
401 nt.assert_equals(path.get_py_filename('foo with spaces.py', force_win32=win32), true_fn)
370 if win32:
402 if win32:
371 nt.assert_equals(path.get_py_filename('"foo with spaces.py"', force_win32=True), true_fn)
403 nt.assert_equals(path.get_py_filename('"foo with spaces.py"', force_win32=True), true_fn)
372 nt.assert_equals(path.get_py_filename("'foo with spaces.py'", force_win32=True), true_fn)
404 nt.assert_equals(path.get_py_filename("'foo with spaces.py'", force_win32=True), true_fn)
373 else:
405 else:
374 nt.assert_raises(IOError, path.get_py_filename, '"foo with spaces.py"', force_win32=False)
406 nt.assert_raises(IOError, path.get_py_filename, '"foo with spaces.py"', force_win32=False)
375 nt.assert_raises(IOError, path.get_py_filename, "'foo with spaces.py'", force_win32=False)
407 nt.assert_raises(IOError, path.get_py_filename, "'foo with spaces.py'", force_win32=False)
General Comments 0
You need to be logged in to leave comments. Login now