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