##// END OF EJS Templates
don't use XDG path on OS X...
MinRK -
Show More
@@ -1,467 +1,467 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 Utilities for path handling.
3 Utilities for path handling.
4 """
4 """
5
5
6 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
7 # Copyright (C) 2008-2011 The IPython Development Team
7 # Copyright (C) 2008-2011 The IPython Development Team
8 #
8 #
9 # Distributed under the terms of the BSD License. The full license is in
9 # Distributed under the terms of the BSD License. The full license is in
10 # the file COPYING, distributed as part of this software.
10 # the file COPYING, distributed as part of this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 import os
17 import os
18 import sys
18 import sys
19 import tempfile
19 import tempfile
20 import warnings
20 import warnings
21 from hashlib import md5
21 from hashlib import md5
22
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 `%r` not found.' % name
109 raise IOError,'File `%r` 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 # Next line will make things work even when /home/ is a symlink to
204 # Next line will make things work even when /home/ is a symlink to
205 # /usr/home as it is on FreeBSD, for example
205 # /usr/home as it is on FreeBSD, for example
206 homedir = os.path.realpath(homedir)
206 homedir = os.path.realpath(homedir)
207
207
208 if not _writable_dir(homedir) and os.name == 'nt':
208 if not _writable_dir(homedir) and os.name == 'nt':
209 # expanduser failed, use the registry to get the 'My Documents' folder.
209 # expanduser failed, use the registry to get the 'My Documents' folder.
210 try:
210 try:
211 import _winreg as wreg
211 import _winreg as wreg
212 key = wreg.OpenKey(
212 key = wreg.OpenKey(
213 wreg.HKEY_CURRENT_USER,
213 wreg.HKEY_CURRENT_USER,
214 "Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders"
214 "Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders"
215 )
215 )
216 homedir = wreg.QueryValueEx(key,'Personal')[0]
216 homedir = wreg.QueryValueEx(key,'Personal')[0]
217 key.Close()
217 key.Close()
218 except:
218 except:
219 pass
219 pass
220
220
221 if (not require_writable) or _writable_dir(homedir):
221 if (not require_writable) or _writable_dir(homedir):
222 return py3compat.cast_unicode(homedir, fs_encoding)
222 return py3compat.cast_unicode(homedir, fs_encoding)
223 else:
223 else:
224 raise HomeDirError('%s is not a writable dir, '
224 raise HomeDirError('%s is not a writable dir, '
225 'set $HOME environment variable to override' % homedir)
225 'set $HOME environment variable to override' % homedir)
226
226
227 def get_xdg_dir():
227 def get_xdg_dir():
228 """Return the XDG_CONFIG_HOME, if it is defined and exists, else None.
228 """Return the XDG_CONFIG_HOME, if it is defined and exists, else None.
229
229
230 This is only for posix (Linux,Unix,OS X, etc) systems.
230 This is only for non-OS X posix (Linux,Unix,etc.) systems.
231 """
231 """
232
232
233 env = os.environ
233 env = os.environ
234
234
235 if os.name == 'posix':
235 if os.name == 'posix' and sys.platform != 'darwin':
236 # Linux, Unix, AIX, OS X
236 # Linux, Unix, AIX, etc.
237 # use ~/.config if empty OR not set
237 # use ~/.config if empty OR not set
238 xdg = env.get("XDG_CONFIG_HOME", None) or os.path.join(get_home_dir(), '.config')
238 xdg = env.get("XDG_CONFIG_HOME", None) or os.path.join(get_home_dir(), '.config')
239 if xdg and _writable_dir(xdg):
239 if xdg and _writable_dir(xdg):
240 return py3compat.cast_unicode(xdg, fs_encoding)
240 return py3compat.cast_unicode(xdg, fs_encoding)
241
241
242 return None
242 return None
243
243
244
244
245 def get_ipython_dir():
245 def get_ipython_dir():
246 """Get the IPython directory for this platform and user.
246 """Get the IPython directory for this platform and user.
247
247
248 This uses the logic in `get_home_dir` to find the home directory
248 This uses the logic in `get_home_dir` to find the home directory
249 and then adds .ipython to the end of the path.
249 and then adds .ipython to the end of the path.
250 """
250 """
251
251
252 env = os.environ
252 env = os.environ
253 pjoin = os.path.join
253 pjoin = os.path.join
254
254
255
255
256 ipdir_def = '.ipython'
256 ipdir_def = '.ipython'
257 xdg_def = 'ipython'
257 xdg_def = 'ipython'
258
258
259 home_dir = get_home_dir()
259 home_dir = get_home_dir()
260 xdg_dir = get_xdg_dir()
260 xdg_dir = get_xdg_dir()
261
261
262 # import pdb; pdb.set_trace() # dbg
262 # import pdb; pdb.set_trace() # dbg
263 if 'IPYTHON_DIR' in env:
263 if 'IPYTHON_DIR' in env:
264 warnings.warn('The environment variable IPYTHON_DIR is deprecated. '
264 warnings.warn('The environment variable IPYTHON_DIR is deprecated. '
265 'Please use IPYTHONDIR instead.')
265 'Please use IPYTHONDIR instead.')
266 ipdir = env.get('IPYTHONDIR', env.get('IPYTHON_DIR', None))
266 ipdir = env.get('IPYTHONDIR', env.get('IPYTHON_DIR', None))
267 if ipdir is None:
267 if ipdir is None:
268 # not set explicitly, use XDG_CONFIG_HOME or HOME
268 # not set explicitly, use XDG_CONFIG_HOME or HOME
269 home_ipdir = pjoin(home_dir, ipdir_def)
269 home_ipdir = pjoin(home_dir, ipdir_def)
270 if xdg_dir:
270 if xdg_dir:
271 # use XDG, as long as the user isn't already
271 # use XDG, as long as the user isn't already
272 # using $HOME/.ipython and *not* XDG/ipython
272 # using $HOME/.ipython and *not* XDG/ipython
273
273
274 xdg_ipdir = pjoin(xdg_dir, xdg_def)
274 xdg_ipdir = pjoin(xdg_dir, xdg_def)
275
275
276 if _writable_dir(xdg_ipdir) or not _writable_dir(home_ipdir):
276 if _writable_dir(xdg_ipdir) or not _writable_dir(home_ipdir):
277 ipdir = xdg_ipdir
277 ipdir = xdg_ipdir
278
278
279 if ipdir is None:
279 if ipdir is None:
280 # not using XDG
280 # not using XDG
281 ipdir = home_ipdir
281 ipdir = home_ipdir
282
282
283 ipdir = os.path.normpath(os.path.expanduser(ipdir))
283 ipdir = os.path.normpath(os.path.expanduser(ipdir))
284
284
285 if os.path.exists(ipdir) and not _writable_dir(ipdir):
285 if os.path.exists(ipdir) and not _writable_dir(ipdir):
286 # ipdir exists, but is not writable
286 # ipdir exists, but is not writable
287 warnings.warn("IPython dir '%s' is not a writable location,"
287 warnings.warn("IPython dir '%s' is not a writable location,"
288 " using a temp directory."%ipdir)
288 " using a temp directory."%ipdir)
289 ipdir = tempfile.mkdtemp()
289 ipdir = tempfile.mkdtemp()
290 elif not os.path.exists(ipdir):
290 elif not os.path.exists(ipdir):
291 parent = ipdir.rsplit(os.path.sep, 1)[0]
291 parent = ipdir.rsplit(os.path.sep, 1)[0]
292 if not _writable_dir(parent):
292 if not _writable_dir(parent):
293 # ipdir does not exist and parent isn't writable
293 # ipdir does not exist and parent isn't writable
294 warnings.warn("IPython parent '%s' is not a writable location,"
294 warnings.warn("IPython parent '%s' is not a writable location,"
295 " using a temp directory."%parent)
295 " using a temp directory."%parent)
296 ipdir = tempfile.mkdtemp()
296 ipdir = tempfile.mkdtemp()
297
297
298 return py3compat.cast_unicode(ipdir, fs_encoding)
298 return py3compat.cast_unicode(ipdir, fs_encoding)
299
299
300
300
301 def get_ipython_package_dir():
301 def get_ipython_package_dir():
302 """Get the base directory where IPython itself is installed."""
302 """Get the base directory where IPython itself is installed."""
303 ipdir = os.path.dirname(IPython.__file__)
303 ipdir = os.path.dirname(IPython.__file__)
304 return py3compat.cast_unicode(ipdir, fs_encoding)
304 return py3compat.cast_unicode(ipdir, fs_encoding)
305
305
306
306
307 def get_ipython_module_path(module_str):
307 def get_ipython_module_path(module_str):
308 """Find the path to an IPython module in this version of IPython.
308 """Find the path to an IPython module in this version of IPython.
309
309
310 This will always find the version of the module that is in this importable
310 This will always find the version of the module that is in this importable
311 IPython package. This will always return the path to the ``.py``
311 IPython package. This will always return the path to the ``.py``
312 version of the module.
312 version of the module.
313 """
313 """
314 if module_str == 'IPython':
314 if module_str == 'IPython':
315 return os.path.join(get_ipython_package_dir(), '__init__.py')
315 return os.path.join(get_ipython_package_dir(), '__init__.py')
316 mod = import_item(module_str)
316 mod = import_item(module_str)
317 the_path = mod.__file__.replace('.pyc', '.py')
317 the_path = mod.__file__.replace('.pyc', '.py')
318 the_path = the_path.replace('.pyo', '.py')
318 the_path = the_path.replace('.pyo', '.py')
319 return py3compat.cast_unicode(the_path, fs_encoding)
319 return py3compat.cast_unicode(the_path, fs_encoding)
320
320
321 def locate_profile(profile='default'):
321 def locate_profile(profile='default'):
322 """Find the path to the folder associated with a given profile.
322 """Find the path to the folder associated with a given profile.
323
323
324 I.e. find $IPYTHONDIR/profile_whatever.
324 I.e. find $IPYTHONDIR/profile_whatever.
325 """
325 """
326 from IPython.core.profiledir import ProfileDir, ProfileDirError
326 from IPython.core.profiledir import ProfileDir, ProfileDirError
327 try:
327 try:
328 pd = ProfileDir.find_profile_dir_by_name(get_ipython_dir(), profile)
328 pd = ProfileDir.find_profile_dir_by_name(get_ipython_dir(), profile)
329 except ProfileDirError:
329 except ProfileDirError:
330 # IOError makes more sense when people are expecting a path
330 # IOError makes more sense when people are expecting a path
331 raise IOError("Couldn't find profile %r" % profile)
331 raise IOError("Couldn't find profile %r" % profile)
332 return pd.location
332 return pd.location
333
333
334 def expand_path(s):
334 def expand_path(s):
335 """Expand $VARS and ~names in a string, like a shell
335 """Expand $VARS and ~names in a string, like a shell
336
336
337 :Examples:
337 :Examples:
338
338
339 In [2]: os.environ['FOO']='test'
339 In [2]: os.environ['FOO']='test'
340
340
341 In [3]: expand_path('variable FOO is $FOO')
341 In [3]: expand_path('variable FOO is $FOO')
342 Out[3]: 'variable FOO is test'
342 Out[3]: 'variable FOO is test'
343 """
343 """
344 # This is a pretty subtle hack. When expand user is given a UNC path
344 # This is a pretty subtle hack. When expand user is given a UNC path
345 # on Windows (\\server\share$\%username%), os.path.expandvars, removes
345 # on Windows (\\server\share$\%username%), os.path.expandvars, removes
346 # the $ to get (\\server\share\%username%). I think it considered $
346 # the $ to get (\\server\share\%username%). I think it considered $
347 # alone an empty var. But, we need the $ to remains there (it indicates
347 # alone an empty var. But, we need the $ to remains there (it indicates
348 # a hidden share).
348 # a hidden share).
349 if os.name=='nt':
349 if os.name=='nt':
350 s = s.replace('$\\', 'IPYTHON_TEMP')
350 s = s.replace('$\\', 'IPYTHON_TEMP')
351 s = os.path.expandvars(os.path.expanduser(s))
351 s = os.path.expandvars(os.path.expanduser(s))
352 if os.name=='nt':
352 if os.name=='nt':
353 s = s.replace('IPYTHON_TEMP', '$\\')
353 s = s.replace('IPYTHON_TEMP', '$\\')
354 return s
354 return s
355
355
356
356
357 def target_outdated(target,deps):
357 def target_outdated(target,deps):
358 """Determine whether a target is out of date.
358 """Determine whether a target is out of date.
359
359
360 target_outdated(target,deps) -> 1/0
360 target_outdated(target,deps) -> 1/0
361
361
362 deps: list of filenames which MUST exist.
362 deps: list of filenames which MUST exist.
363 target: single filename which may or may not exist.
363 target: single filename which may or may not exist.
364
364
365 If target doesn't exist or is older than any file listed in deps, return
365 If target doesn't exist or is older than any file listed in deps, return
366 true, otherwise return false.
366 true, otherwise return false.
367 """
367 """
368 try:
368 try:
369 target_time = os.path.getmtime(target)
369 target_time = os.path.getmtime(target)
370 except os.error:
370 except os.error:
371 return 1
371 return 1
372 for dep in deps:
372 for dep in deps:
373 dep_time = os.path.getmtime(dep)
373 dep_time = os.path.getmtime(dep)
374 if dep_time > target_time:
374 if dep_time > target_time:
375 #print "For target",target,"Dep failed:",dep # dbg
375 #print "For target",target,"Dep failed:",dep # dbg
376 #print "times (dep,tar):",dep_time,target_time # dbg
376 #print "times (dep,tar):",dep_time,target_time # dbg
377 return 1
377 return 1
378 return 0
378 return 0
379
379
380
380
381 def target_update(target,deps,cmd):
381 def target_update(target,deps,cmd):
382 """Update a target with a given command given a list of dependencies.
382 """Update a target with a given command given a list of dependencies.
383
383
384 target_update(target,deps,cmd) -> runs cmd if target is outdated.
384 target_update(target,deps,cmd) -> runs cmd if target is outdated.
385
385
386 This is just a wrapper around target_outdated() which calls the given
386 This is just a wrapper around target_outdated() which calls the given
387 command if target is outdated."""
387 command if target is outdated."""
388
388
389 if target_outdated(target,deps):
389 if target_outdated(target,deps):
390 system(cmd)
390 system(cmd)
391
391
392 def filehash(path):
392 def filehash(path):
393 """Make an MD5 hash of a file, ignoring any differences in line
393 """Make an MD5 hash of a file, ignoring any differences in line
394 ending characters."""
394 ending characters."""
395 with open(path, "rU") as f:
395 with open(path, "rU") as f:
396 return md5(py3compat.str_to_bytes(f.read())).hexdigest()
396 return md5(py3compat.str_to_bytes(f.read())).hexdigest()
397
397
398 # If the config is unmodified from the default, we'll just delete it.
398 # If the config is unmodified from the default, we'll just delete it.
399 # These are consistent for 0.10.x, thankfully. We're not going to worry about
399 # These are consistent for 0.10.x, thankfully. We're not going to worry about
400 # older versions.
400 # older versions.
401 old_config_md5 = {'ipy_user_conf.py': 'fc108bedff4b9a00f91fa0a5999140d3',
401 old_config_md5 = {'ipy_user_conf.py': 'fc108bedff4b9a00f91fa0a5999140d3',
402 'ipythonrc': '12a68954f3403eea2eec09dc8fe5a9b5'}
402 'ipythonrc': '12a68954f3403eea2eec09dc8fe5a9b5'}
403
403
404 def check_for_old_config(ipython_dir=None):
404 def check_for_old_config(ipython_dir=None):
405 """Check for old config files, and present a warning if they exist.
405 """Check for old config files, and present a warning if they exist.
406
406
407 A link to the docs of the new config is included in the message.
407 A link to the docs of the new config is included in the message.
408
408
409 This should mitigate confusion with the transition to the new
409 This should mitigate confusion with the transition to the new
410 config system in 0.11.
410 config system in 0.11.
411 """
411 """
412 if ipython_dir is None:
412 if ipython_dir is None:
413 ipython_dir = get_ipython_dir()
413 ipython_dir = get_ipython_dir()
414
414
415 old_configs = ['ipy_user_conf.py', 'ipythonrc', 'ipython_config.py']
415 old_configs = ['ipy_user_conf.py', 'ipythonrc', 'ipython_config.py']
416 warned = False
416 warned = False
417 for cfg in old_configs:
417 for cfg in old_configs:
418 f = os.path.join(ipython_dir, cfg)
418 f = os.path.join(ipython_dir, cfg)
419 if os.path.exists(f):
419 if os.path.exists(f):
420 if filehash(f) == old_config_md5.get(cfg, ''):
420 if filehash(f) == old_config_md5.get(cfg, ''):
421 os.unlink(f)
421 os.unlink(f)
422 else:
422 else:
423 warnings.warn("Found old IPython config file %r (modified by user)"%f)
423 warnings.warn("Found old IPython config file %r (modified by user)"%f)
424 warned = True
424 warned = True
425
425
426 if warned:
426 if warned:
427 warnings.warn("""
427 warnings.warn("""
428 The IPython configuration system has changed as of 0.11, and these files will
428 The IPython configuration system has changed as of 0.11, and these files will
429 be ignored. See http://ipython.github.com/ipython-doc/dev/config for details
429 be ignored. See http://ipython.github.com/ipython-doc/dev/config for details
430 of the new config system.
430 of the new config system.
431 To start configuring IPython, do `ipython profile create`, and edit
431 To start configuring IPython, do `ipython profile create`, and edit
432 `ipython_config.py` in <ipython_dir>/profile_default.
432 `ipython_config.py` in <ipython_dir>/profile_default.
433 If you need to leave the old config files in place for an older version of
433 If you need to leave the old config files in place for an older version of
434 IPython and want to suppress this warning message, set
434 IPython and want to suppress this warning message, set
435 `c.InteractiveShellApp.ignore_old_config=True` in the new config.""")
435 `c.InteractiveShellApp.ignore_old_config=True` in the new config.""")
436
436
437 def get_security_file(filename, profile='default'):
437 def get_security_file(filename, profile='default'):
438 """Return the absolute path of a security file given by filename and profile
438 """Return the absolute path of a security file given by filename and profile
439
439
440 This allows users and developers to find security files without
440 This allows users and developers to find security files without
441 knowledge of the IPython directory structure. The search path
441 knowledge of the IPython directory structure. The search path
442 will be ['.', profile.security_dir]
442 will be ['.', profile.security_dir]
443
443
444 Parameters
444 Parameters
445 ----------
445 ----------
446
446
447 filename : str
447 filename : str
448 The file to be found. If it is passed as an absolute path, it will
448 The file to be found. If it is passed as an absolute path, it will
449 simply be returned.
449 simply be returned.
450 profile : str [default: 'default']
450 profile : str [default: 'default']
451 The name of the profile to search. Leaving this unspecified
451 The name of the profile to search. Leaving this unspecified
452 The file to be found. If it is passed as an absolute path, fname will
452 The file to be found. If it is passed as an absolute path, fname will
453 simply be returned.
453 simply be returned.
454
454
455 Returns
455 Returns
456 -------
456 -------
457 Raises :exc:`IOError` if file not found or returns absolute path to file.
457 Raises :exc:`IOError` if file not found or returns absolute path to file.
458 """
458 """
459 # import here, because profiledir also imports from utils.path
459 # import here, because profiledir also imports from utils.path
460 from IPython.core.profiledir import ProfileDir
460 from IPython.core.profiledir import ProfileDir
461 try:
461 try:
462 pd = ProfileDir.find_profile_dir_by_name(get_ipython_dir(), profile)
462 pd = ProfileDir.find_profile_dir_by_name(get_ipython_dir(), profile)
463 except Exception:
463 except Exception:
464 # will raise ProfileDirError if no such profile
464 # will raise ProfileDirError if no such profile
465 raise IOError("Profile %r not found")
465 raise IOError("Profile %r not found")
466 return filefind(filename, ['.', pd.security_dir])
466 return filefind(filename, ['.', pd.security_dir])
467
467
@@ -1,420 +1,447 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """Tests for IPython.utils.path.py"""
2 """Tests for IPython.utils.path.py"""
3
3
4 #-----------------------------------------------------------------------------
4 #-----------------------------------------------------------------------------
5 # Copyright (C) 2008-2011 The IPython Development Team
5 # Copyright (C) 2008-2011 The IPython Development Team
6 #
6 #
7 # Distributed under the terms of the BSD License. The full license is in
7 # Distributed under the terms of the BSD License. The full license is in
8 # the file COPYING, distributed as part of this software.
8 # the file COPYING, distributed as part of this software.
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Imports
12 # Imports
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 from __future__ import with_statement
15 from __future__ import with_statement
16
16
17 import os
17 import os
18 import shutil
18 import shutil
19 import sys
19 import sys
20 import tempfile
20 import tempfile
21 from io import StringIO
21 from io import StringIO
22
22
23 from os.path import join, abspath, split
23 from os.path import join, abspath, split
24
24
25 import nose.tools as nt
25 import nose.tools as nt
26
26
27 from nose import with_setup
27 from nose import with_setup
28
28
29 import IPython
29 import IPython
30 from IPython.testing import decorators as dec
30 from IPython.testing import decorators as dec
31 from IPython.testing.decorators import skip_if_not_win32, skip_win32
31 from IPython.testing.decorators import skip_if_not_win32, skip_win32
32 from IPython.testing.tools import make_tempfile, AssertPrints
32 from IPython.testing.tools import make_tempfile, AssertPrints
33 from IPython.utils import path, io
33 from IPython.utils import path, io
34 from IPython.utils import py3compat
34 from IPython.utils import py3compat
35
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, sys.platform, 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, sys.platform, 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 # get_home_dir expands symlinks
153 # get_home_dir expands symlinks
154 nt.assert_equal(home_dir, os.path.realpath(env["HOME"]))
154 nt.assert_equal(home_dir, os.path.realpath(env["HOME"]))
155
155
156
156
157 @with_environment
157 @with_environment
158 def test_get_home_dir_4():
158 def test_get_home_dir_4():
159 """get_home_dir() still works if $HOME is not set"""
159 """get_home_dir() still works if $HOME is not set"""
160
160
161 if 'HOME' in env: del env['HOME']
161 if 'HOME' in env: del env['HOME']
162 # this should still succeed, but we don't know what the answer should be
162 # this should still succeed, but we don't know what the answer should be
163 home = path.get_home_dir(True)
163 home = path.get_home_dir(True)
164 nt.assert_true(path._writable_dir(home))
164 nt.assert_true(path._writable_dir(home))
165
165
166 @with_environment
166 @with_environment
167 def test_get_home_dir_5():
167 def test_get_home_dir_5():
168 """raise HomeDirError if $HOME is specified, but not a writable dir"""
168 """raise HomeDirError if $HOME is specified, but not a writable dir"""
169 env['HOME'] = abspath(HOME_TEST_DIR+'garbage')
169 env['HOME'] = abspath(HOME_TEST_DIR+'garbage')
170 # set os.name = posix, to prevent My Documents fallback on Windows
170 # set os.name = posix, to prevent My Documents fallback on Windows
171 os.name = 'posix'
171 os.name = 'posix'
172 nt.assert_raises(path.HomeDirError, path.get_home_dir, True)
172 nt.assert_raises(path.HomeDirError, path.get_home_dir, True)
173
173
174
174
175 # Should we stub wreg fully so we can run the test on all platforms?
175 # Should we stub wreg fully so we can run the test on all platforms?
176 @skip_if_not_win32
176 @skip_if_not_win32
177 @with_environment
177 @with_environment
178 def test_get_home_dir_8():
178 def test_get_home_dir_8():
179 """Using registry hack for 'My Documents', os=='nt'
179 """Using registry hack for 'My Documents', os=='nt'
180
180
181 HOMESHARE, HOMEDRIVE, HOMEPATH, USERPROFILE and others are missing.
181 HOMESHARE, HOMEDRIVE, HOMEPATH, USERPROFILE and others are missing.
182 """
182 """
183 os.name = 'nt'
183 os.name = 'nt'
184 # Remove from stub environment all keys that may be set
184 # Remove from stub environment all keys that may be set
185 for key in ['HOME', 'HOMESHARE', 'HOMEDRIVE', 'HOMEPATH', 'USERPROFILE']:
185 for key in ['HOME', 'HOMESHARE', 'HOMEDRIVE', 'HOMEPATH', 'USERPROFILE']:
186 env.pop(key, None)
186 env.pop(key, None)
187
187
188 #Stub windows registry functions
188 #Stub windows registry functions
189 def OpenKey(x, y):
189 def OpenKey(x, y):
190 class key:
190 class key:
191 def Close(self):
191 def Close(self):
192 pass
192 pass
193 return key()
193 return key()
194 def QueryValueEx(x, y):
194 def QueryValueEx(x, y):
195 return [abspath(HOME_TEST_DIR)]
195 return [abspath(HOME_TEST_DIR)]
196
196
197 wreg.OpenKey = OpenKey
197 wreg.OpenKey = OpenKey
198 wreg.QueryValueEx = QueryValueEx
198 wreg.QueryValueEx = QueryValueEx
199
199
200 home_dir = path.get_home_dir()
200 home_dir = path.get_home_dir()
201 nt.assert_equal(home_dir, abspath(HOME_TEST_DIR))
201 nt.assert_equal(home_dir, abspath(HOME_TEST_DIR))
202
202
203
203
204 @with_environment
204 @with_environment
205 def test_get_ipython_dir_1():
205 def test_get_ipython_dir_1():
206 """test_get_ipython_dir_1, Testcase to see if we can call get_ipython_dir without Exceptions."""
206 """test_get_ipython_dir_1, Testcase to see if we can call get_ipython_dir without Exceptions."""
207 env_ipdir = os.path.join("someplace", ".ipython")
207 env_ipdir = os.path.join("someplace", ".ipython")
208 path._writable_dir = lambda path: True
208 path._writable_dir = lambda path: True
209 env['IPYTHONDIR'] = env_ipdir
209 env['IPYTHONDIR'] = env_ipdir
210 ipdir = path.get_ipython_dir()
210 ipdir = path.get_ipython_dir()
211 nt.assert_equal(ipdir, env_ipdir)
211 nt.assert_equal(ipdir, env_ipdir)
212
212
213
213
214 @with_environment
214 @with_environment
215 def test_get_ipython_dir_2():
215 def test_get_ipython_dir_2():
216 """test_get_ipython_dir_2, Testcase to see if we can call get_ipython_dir without Exceptions."""
216 """test_get_ipython_dir_2, Testcase to see if we can call get_ipython_dir without Exceptions."""
217 path.get_home_dir = lambda : "someplace"
217 path.get_home_dir = lambda : "someplace"
218 path.get_xdg_dir = lambda : None
218 path.get_xdg_dir = lambda : None
219 path._writable_dir = lambda path: True
219 path._writable_dir = lambda path: True
220 os.name = "posix"
220 os.name = "posix"
221 env.pop('IPYTHON_DIR', None)
221 env.pop('IPYTHON_DIR', None)
222 env.pop('IPYTHONDIR', None)
222 env.pop('IPYTHONDIR', None)
223 env.pop('XDG_CONFIG_HOME', None)
223 env.pop('XDG_CONFIG_HOME', None)
224 ipdir = path.get_ipython_dir()
224 ipdir = path.get_ipython_dir()
225 nt.assert_equal(ipdir, os.path.join("someplace", ".ipython"))
225 nt.assert_equal(ipdir, os.path.join("someplace", ".ipython"))
226
226
227 @with_environment
227 @with_environment
228 def test_get_ipython_dir_3():
228 def test_get_ipython_dir_3():
229 """test_get_ipython_dir_3, use XDG if defined, and .ipython doesn't exist."""
229 """test_get_ipython_dir_3, use XDG if defined, and .ipython doesn't exist."""
230 path.get_home_dir = lambda : "someplace"
230 path.get_home_dir = lambda : "someplace"
231 path._writable_dir = lambda path: True
231 path._writable_dir = lambda path: True
232 os.name = "posix"
232 os.name = "posix"
233 env.pop('IPYTHON_DIR', None)
233 env.pop('IPYTHON_DIR', None)
234 env.pop('IPYTHONDIR', None)
234 env.pop('IPYTHONDIR', None)
235 env['XDG_CONFIG_HOME'] = XDG_TEST_DIR
235 env['XDG_CONFIG_HOME'] = XDG_TEST_DIR
236 ipdir = path.get_ipython_dir()
236 ipdir = path.get_ipython_dir()
237 nt.assert_equal(ipdir, os.path.join(XDG_TEST_DIR, "ipython"))
237 if sys.platform == "darwin":
238 expected = os.path.join("someplace", ".ipython")
239 else:
240 expected = os.path.join(XDG_TEST_DIR, "ipython")
241 nt.assert_equal(ipdir, expected)
238
242
239 @with_environment
243 @with_environment
240 def test_get_ipython_dir_4():
244 def test_get_ipython_dir_4():
241 """test_get_ipython_dir_4, use XDG if both exist."""
245 """test_get_ipython_dir_4, use XDG if both exist."""
242 path.get_home_dir = lambda : HOME_TEST_DIR
246 path.get_home_dir = lambda : HOME_TEST_DIR
243 os.name = "posix"
247 os.name = "posix"
244 env.pop('IPYTHON_DIR', None)
248 env.pop('IPYTHON_DIR', None)
245 env.pop('IPYTHONDIR', None)
249 env.pop('IPYTHONDIR', None)
246 env['XDG_CONFIG_HOME'] = XDG_TEST_DIR
250 env['XDG_CONFIG_HOME'] = XDG_TEST_DIR
247 xdg_ipdir = os.path.join(XDG_TEST_DIR, "ipython")
248 ipdir = path.get_ipython_dir()
251 ipdir = path.get_ipython_dir()
249 nt.assert_equal(ipdir, xdg_ipdir)
252 if sys.platform == "darwin":
253 expected = os.path.join(HOME_TEST_DIR, ".ipython")
254 else:
255 expected = os.path.join(XDG_TEST_DIR, "ipython")
256 nt.assert_equal(ipdir, expected)
250
257
251 @with_environment
258 @with_environment
252 def test_get_ipython_dir_5():
259 def test_get_ipython_dir_5():
253 """test_get_ipython_dir_5, use .ipython if exists and XDG defined, but doesn't exist."""
260 """test_get_ipython_dir_5, use .ipython if exists and XDG defined, but doesn't exist."""
254 path.get_home_dir = lambda : HOME_TEST_DIR
261 path.get_home_dir = lambda : HOME_TEST_DIR
255 os.name = "posix"
262 os.name = "posix"
256 env.pop('IPYTHON_DIR', None)
263 env.pop('IPYTHON_DIR', None)
257 env.pop('IPYTHONDIR', None)
264 env.pop('IPYTHONDIR', None)
258 env['XDG_CONFIG_HOME'] = XDG_TEST_DIR
265 env['XDG_CONFIG_HOME'] = XDG_TEST_DIR
259 os.rmdir(os.path.join(XDG_TEST_DIR, 'ipython'))
266 os.rmdir(os.path.join(XDG_TEST_DIR, 'ipython'))
260 ipdir = path.get_ipython_dir()
267 ipdir = path.get_ipython_dir()
261 nt.assert_equal(ipdir, IP_TEST_DIR)
268 nt.assert_equal(ipdir, IP_TEST_DIR)
262
269
263 @with_environment
270 @with_environment
264 def test_get_ipython_dir_6():
271 def test_get_ipython_dir_6():
265 """test_get_ipython_dir_6, use XDG if defined and neither exist."""
272 """test_get_ipython_dir_6, use XDG if defined and neither exist."""
266 xdg = os.path.join(HOME_TEST_DIR, 'somexdg')
273 xdg = os.path.join(HOME_TEST_DIR, 'somexdg')
267 os.mkdir(xdg)
274 os.mkdir(xdg)
268 shutil.rmtree(os.path.join(HOME_TEST_DIR, '.ipython'))
275 shutil.rmtree(os.path.join(HOME_TEST_DIR, '.ipython'))
269 path.get_home_dir = lambda : HOME_TEST_DIR
276 path.get_home_dir = lambda : HOME_TEST_DIR
270 path.get_xdg_dir = lambda : xdg
277 path.get_xdg_dir = lambda : xdg
271 os.name = "posix"
278 os.name = "posix"
272 env.pop('IPYTHON_DIR', None)
279 env.pop('IPYTHON_DIR', None)
273 env.pop('IPYTHONDIR', None)
280 env.pop('IPYTHONDIR', None)
274 env.pop('XDG_CONFIG_HOME', None)
281 env.pop('XDG_CONFIG_HOME', None)
275 xdg_ipdir = os.path.join(xdg, "ipython")
282 xdg_ipdir = os.path.join(xdg, "ipython")
276 ipdir = path.get_ipython_dir()
283 ipdir = path.get_ipython_dir()
277 nt.assert_equal(ipdir, xdg_ipdir)
284 nt.assert_equal(ipdir, xdg_ipdir)
278
285
279 @with_environment
286 @with_environment
280 def test_get_ipython_dir_7():
287 def test_get_ipython_dir_7():
281 """test_get_ipython_dir_7, test home directory expansion on IPYTHONDIR"""
288 """test_get_ipython_dir_7, test home directory expansion on IPYTHONDIR"""
282 path._writable_dir = lambda path: True
289 path._writable_dir = lambda path: True
283 home_dir = os.path.expanduser('~')
290 home_dir = os.path.expanduser('~')
284 env['IPYTHONDIR'] = os.path.join('~', 'somewhere')
291 env['IPYTHONDIR'] = os.path.join('~', 'somewhere')
285 ipdir = path.get_ipython_dir()
292 ipdir = path.get_ipython_dir()
286 nt.assert_equal(ipdir, os.path.join(home_dir, 'somewhere'))
293 nt.assert_equal(ipdir, os.path.join(home_dir, 'somewhere'))
287
294
288
295
289 @with_environment
296 @with_environment
290 def test_get_xdg_dir_1():
297 def test_get_xdg_dir_0():
291 """test_get_xdg_dir_1, check xdg_dir"""
298 """test_get_xdg_dir_0, check xdg_dir"""
292 reload(path)
299 reload(path)
293 path._writable_dir = lambda path: True
300 path._writable_dir = lambda path: True
294 path.get_home_dir = lambda : 'somewhere'
301 path.get_home_dir = lambda : 'somewhere'
295 os.name = "posix"
302 os.name = "posix"
303 sys.platform = "linux2"
296 env.pop('IPYTHON_DIR', None)
304 env.pop('IPYTHON_DIR', None)
297 env.pop('IPYTHONDIR', None)
305 env.pop('IPYTHONDIR', None)
298 env.pop('XDG_CONFIG_HOME', None)
306 env.pop('XDG_CONFIG_HOME', None)
299
307
300 nt.assert_equal(path.get_xdg_dir(), os.path.join('somewhere', '.config'))
308 nt.assert_equal(path.get_xdg_dir(), os.path.join('somewhere', '.config'))
301
309
302
310
303 @with_environment
311 @with_environment
304 def test_get_xdg_dir_1():
312 def test_get_xdg_dir_1():
305 """test_get_xdg_dir_1, check nonexistant xdg_dir"""
313 """test_get_xdg_dir_1, check nonexistant xdg_dir"""
306 reload(path)
314 reload(path)
307 path.get_home_dir = lambda : HOME_TEST_DIR
315 path.get_home_dir = lambda : HOME_TEST_DIR
308 os.name = "posix"
316 os.name = "posix"
317 sys.platform = "linux2"
309 env.pop('IPYTHON_DIR', None)
318 env.pop('IPYTHON_DIR', None)
310 env.pop('IPYTHONDIR', None)
319 env.pop('IPYTHONDIR', None)
311 env.pop('XDG_CONFIG_HOME', None)
320 env.pop('XDG_CONFIG_HOME', None)
312 nt.assert_equal(path.get_xdg_dir(), None)
321 nt.assert_equal(path.get_xdg_dir(), None)
313
322
314 @with_environment
323 @with_environment
315 def test_get_xdg_dir_2():
324 def test_get_xdg_dir_2():
316 """test_get_xdg_dir_2, check xdg_dir default to ~/.config"""
325 """test_get_xdg_dir_2, check xdg_dir default to ~/.config"""
317 reload(path)
326 reload(path)
318 path.get_home_dir = lambda : HOME_TEST_DIR
327 path.get_home_dir = lambda : HOME_TEST_DIR
319 os.name = "posix"
328 os.name = "posix"
329 sys.platform = "linux2"
320 env.pop('IPYTHON_DIR', None)
330 env.pop('IPYTHON_DIR', None)
321 env.pop('IPYTHONDIR', None)
331 env.pop('IPYTHONDIR', None)
322 env.pop('XDG_CONFIG_HOME', None)
332 env.pop('XDG_CONFIG_HOME', None)
323 cfgdir=os.path.join(path.get_home_dir(), '.config')
333 cfgdir=os.path.join(path.get_home_dir(), '.config')
324 os.makedirs(cfgdir)
334 if not os.path.exists(cfgdir):
335 os.makedirs(cfgdir)
325
336
326 nt.assert_equal(path.get_xdg_dir(), cfgdir)
337 nt.assert_equal(path.get_xdg_dir(), cfgdir)
327
338
339 @with_environment
340 def test_get_xdg_dir_3():
341 """test_get_xdg_dir_3, check xdg_dir not used on OS X"""
342 reload(path)
343 path.get_home_dir = lambda : HOME_TEST_DIR
344 os.name = "posix"
345 sys.platform = "darwin"
346 env.pop('IPYTHON_DIR', None)
347 env.pop('IPYTHONDIR', None)
348 env.pop('XDG_CONFIG_HOME', None)
349 cfgdir=os.path.join(path.get_home_dir(), '.config')
350 if not os.path.exists(cfgdir):
351 os.makedirs(cfgdir)
352
353 nt.assert_equal(path.get_xdg_dir(), None)
354
328 def test_filefind():
355 def test_filefind():
329 """Various tests for filefind"""
356 """Various tests for filefind"""
330 f = tempfile.NamedTemporaryFile()
357 f = tempfile.NamedTemporaryFile()
331 # print 'fname:',f.name
358 # print 'fname:',f.name
332 alt_dirs = path.get_ipython_dir()
359 alt_dirs = path.get_ipython_dir()
333 t = path.filefind(f.name, alt_dirs)
360 t = path.filefind(f.name, alt_dirs)
334 # print 'found:',t
361 # print 'found:',t
335
362
336
363
337 def test_get_ipython_package_dir():
364 def test_get_ipython_package_dir():
338 ipdir = path.get_ipython_package_dir()
365 ipdir = path.get_ipython_package_dir()
339 nt.assert_true(os.path.isdir(ipdir))
366 nt.assert_true(os.path.isdir(ipdir))
340
367
341
368
342 def test_get_ipython_module_path():
369 def test_get_ipython_module_path():
343 ipapp_path = path.get_ipython_module_path('IPython.frontend.terminal.ipapp')
370 ipapp_path = path.get_ipython_module_path('IPython.frontend.terminal.ipapp')
344 nt.assert_true(os.path.isfile(ipapp_path))
371 nt.assert_true(os.path.isfile(ipapp_path))
345
372
346
373
347 @dec.skip_if_not_win32
374 @dec.skip_if_not_win32
348 def test_get_long_path_name_win32():
375 def test_get_long_path_name_win32():
349 p = path.get_long_path_name('c:\\docume~1')
376 p = path.get_long_path_name('c:\\docume~1')
350 nt.assert_equals(p,u'c:\\Documents and Settings')
377 nt.assert_equals(p,u'c:\\Documents and Settings')
351
378
352
379
353 @dec.skip_win32
380 @dec.skip_win32
354 def test_get_long_path_name():
381 def test_get_long_path_name():
355 p = path.get_long_path_name('/usr/local')
382 p = path.get_long_path_name('/usr/local')
356 nt.assert_equals(p,'/usr/local')
383 nt.assert_equals(p,'/usr/local')
357
384
358 @dec.skip_win32 # can't create not-user-writable dir on win
385 @dec.skip_win32 # can't create not-user-writable dir on win
359 @with_environment
386 @with_environment
360 def test_not_writable_ipdir():
387 def test_not_writable_ipdir():
361 tmpdir = tempfile.mkdtemp()
388 tmpdir = tempfile.mkdtemp()
362 os.name = "posix"
389 os.name = "posix"
363 env.pop('IPYTHON_DIR', None)
390 env.pop('IPYTHON_DIR', None)
364 env.pop('IPYTHONDIR', None)
391 env.pop('IPYTHONDIR', None)
365 env.pop('XDG_CONFIG_HOME', None)
392 env.pop('XDG_CONFIG_HOME', None)
366 env['HOME'] = tmpdir
393 env['HOME'] = tmpdir
367 ipdir = os.path.join(tmpdir, '.ipython')
394 ipdir = os.path.join(tmpdir, '.ipython')
368 os.mkdir(ipdir)
395 os.mkdir(ipdir)
369 os.chmod(ipdir, 600)
396 os.chmod(ipdir, 600)
370 with AssertPrints('is not a writable location', channel='stderr'):
397 with AssertPrints('is not a writable location', channel='stderr'):
371 ipdir = path.get_ipython_dir()
398 ipdir = path.get_ipython_dir()
372 env.pop('IPYTHON_DIR', None)
399 env.pop('IPYTHON_DIR', None)
373
400
374 def test_unquote_filename():
401 def test_unquote_filename():
375 for win32 in (True, False):
402 for win32 in (True, False):
376 nt.assert_equals(path.unquote_filename('foo.py', win32=win32), 'foo.py')
403 nt.assert_equals(path.unquote_filename('foo.py', win32=win32), 'foo.py')
377 nt.assert_equals(path.unquote_filename('foo bar.py', win32=win32), 'foo bar.py')
404 nt.assert_equals(path.unquote_filename('foo bar.py', win32=win32), 'foo bar.py')
378 nt.assert_equals(path.unquote_filename('"foo.py"', win32=True), 'foo.py')
405 nt.assert_equals(path.unquote_filename('"foo.py"', win32=True), 'foo.py')
379 nt.assert_equals(path.unquote_filename('"foo bar.py"', win32=True), 'foo bar.py')
406 nt.assert_equals(path.unquote_filename('"foo bar.py"', win32=True), 'foo bar.py')
380 nt.assert_equals(path.unquote_filename("'foo.py'", win32=True), 'foo.py')
407 nt.assert_equals(path.unquote_filename("'foo.py'", win32=True), 'foo.py')
381 nt.assert_equals(path.unquote_filename("'foo bar.py'", win32=True), 'foo bar.py')
408 nt.assert_equals(path.unquote_filename("'foo bar.py'", win32=True), 'foo bar.py')
382 nt.assert_equals(path.unquote_filename('"foo.py"', win32=False), '"foo.py"')
409 nt.assert_equals(path.unquote_filename('"foo.py"', win32=False), '"foo.py"')
383 nt.assert_equals(path.unquote_filename('"foo bar.py"', win32=False), '"foo bar.py"')
410 nt.assert_equals(path.unquote_filename('"foo bar.py"', win32=False), '"foo bar.py"')
384 nt.assert_equals(path.unquote_filename("'foo.py'", win32=False), "'foo.py'")
411 nt.assert_equals(path.unquote_filename("'foo.py'", win32=False), "'foo.py'")
385 nt.assert_equals(path.unquote_filename("'foo bar.py'", win32=False), "'foo bar.py'")
412 nt.assert_equals(path.unquote_filename("'foo bar.py'", win32=False), "'foo bar.py'")
386
413
387 @with_environment
414 @with_environment
388 def test_get_py_filename():
415 def test_get_py_filename():
389 os.chdir(TMP_TEST_DIR)
416 os.chdir(TMP_TEST_DIR)
390 for win32 in (True, False):
417 for win32 in (True, False):
391 with make_tempfile('foo.py'):
418 with make_tempfile('foo.py'):
392 nt.assert_equals(path.get_py_filename('foo.py', force_win32=win32), 'foo.py')
419 nt.assert_equals(path.get_py_filename('foo.py', force_win32=win32), 'foo.py')
393 nt.assert_equals(path.get_py_filename('foo', force_win32=win32), 'foo.py')
420 nt.assert_equals(path.get_py_filename('foo', force_win32=win32), 'foo.py')
394 with make_tempfile('foo'):
421 with make_tempfile('foo'):
395 nt.assert_equals(path.get_py_filename('foo', force_win32=win32), 'foo')
422 nt.assert_equals(path.get_py_filename('foo', force_win32=win32), 'foo')
396 nt.assert_raises(IOError, path.get_py_filename, 'foo.py', force_win32=win32)
423 nt.assert_raises(IOError, path.get_py_filename, 'foo.py', force_win32=win32)
397 nt.assert_raises(IOError, path.get_py_filename, 'foo', force_win32=win32)
424 nt.assert_raises(IOError, path.get_py_filename, 'foo', force_win32=win32)
398 nt.assert_raises(IOError, path.get_py_filename, 'foo.py', force_win32=win32)
425 nt.assert_raises(IOError, path.get_py_filename, 'foo.py', force_win32=win32)
399 true_fn = 'foo with spaces.py'
426 true_fn = 'foo with spaces.py'
400 with make_tempfile(true_fn):
427 with make_tempfile(true_fn):
401 nt.assert_equals(path.get_py_filename('foo with spaces', force_win32=win32), true_fn)
428 nt.assert_equals(path.get_py_filename('foo with spaces', force_win32=win32), true_fn)
402 nt.assert_equals(path.get_py_filename('foo with spaces.py', force_win32=win32), true_fn)
429 nt.assert_equals(path.get_py_filename('foo with spaces.py', force_win32=win32), true_fn)
403 if win32:
430 if win32:
404 nt.assert_equals(path.get_py_filename('"foo with spaces.py"', force_win32=True), true_fn)
431 nt.assert_equals(path.get_py_filename('"foo with spaces.py"', force_win32=True), true_fn)
405 nt.assert_equals(path.get_py_filename("'foo with spaces.py'", force_win32=True), true_fn)
432 nt.assert_equals(path.get_py_filename("'foo with spaces.py'", force_win32=True), true_fn)
406 else:
433 else:
407 nt.assert_raises(IOError, path.get_py_filename, '"foo with spaces.py"', force_win32=False)
434 nt.assert_raises(IOError, path.get_py_filename, '"foo with spaces.py"', force_win32=False)
408 nt.assert_raises(IOError, path.get_py_filename, "'foo with spaces.py'", force_win32=False)
435 nt.assert_raises(IOError, path.get_py_filename, "'foo with spaces.py'", force_win32=False)
409
436
410 def test_unicode_in_filename():
437 def test_unicode_in_filename():
411 """When a file doesn't exist, the exception raised should be safe to call
438 """When a file doesn't exist, the exception raised should be safe to call
412 str() on - i.e. in Python 2 it must only have ASCII characters.
439 str() on - i.e. in Python 2 it must only have ASCII characters.
413
440
414 https://github.com/ipython/ipython/issues/875
441 https://github.com/ipython/ipython/issues/875
415 """
442 """
416 try:
443 try:
417 # these calls should not throw unicode encode exceptions
444 # these calls should not throw unicode encode exceptions
418 path.get_py_filename(u'fooéè.py', force_win32=False)
445 path.get_py_filename(u'fooéè.py', force_win32=False)
419 except IOError as ex:
446 except IOError as ex:
420 str(ex)
447 str(ex)
General Comments 0
You need to be logged in to leave comments. Login now