##// END OF EJS Templates
add skip_win32_py38 decorator, skip another test
Nicholas Bollweg -
Show More
@@ -1,378 +1,383 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Decorators for labeling test objects.
3 3
4 4 Decorators that merely return a modified version of the original function
5 5 object are straightforward. Decorators that return a new function object need
6 6 to use nose.tools.make_decorator(original_function)(decorator) in returning the
7 7 decorator, in order to preserve metadata such as function name, setup and
8 8 teardown functions and so on - see nose.tools for more information.
9 9
10 10 This module provides a set of useful decorators meant to be ready to use in
11 11 your own tests. See the bottom of the file for the ready-made ones, and if you
12 12 find yourself writing a new one that may be of generic use, add it here.
13 13
14 14 Included decorators:
15 15
16 16
17 17 Lightweight testing that remains unittest-compatible.
18 18
19 19 - An @as_unittest decorator can be used to tag any normal parameter-less
20 20 function as a unittest TestCase. Then, both nose and normal unittest will
21 21 recognize it as such. This will make it easier to migrate away from Nose if
22 22 we ever need/want to while maintaining very lightweight tests.
23 23
24 24 NOTE: This file contains IPython-specific decorators. Using the machinery in
25 25 IPython.external.decorators, we import either numpy.testing.decorators if numpy is
26 26 available, OR use equivalent code in IPython.external._decorators, which
27 27 we've copied verbatim from numpy.
28 28
29 29 """
30 30
31 31 # Copyright (c) IPython Development Team.
32 32 # Distributed under the terms of the Modified BSD License.
33 33
34 34 import os
35 35 import shutil
36 36 import sys
37 37 import tempfile
38 38 import unittest
39 39 import warnings
40 40 from importlib import import_module
41 41
42 42 from decorator import decorator
43 43
44 44 # Expose the unittest-driven decorators
45 45 from .ipunittest import ipdoctest, ipdocstring
46 46
47 47 # Grab the numpy-specific decorators which we keep in a file that we
48 48 # occasionally update from upstream: decorators.py is a copy of
49 49 # numpy.testing.decorators, we expose all of it here.
50 50 from IPython.external.decorators import knownfailureif
51 51
52 52 #-----------------------------------------------------------------------------
53 53 # Classes and functions
54 54 #-----------------------------------------------------------------------------
55 55
56 56 # Simple example of the basic idea
57 57 def as_unittest(func):
58 58 """Decorator to make a simple function into a normal test via unittest."""
59 59 class Tester(unittest.TestCase):
60 60 def test(self):
61 61 func()
62 62
63 63 Tester.__name__ = func.__name__
64 64
65 65 return Tester
66 66
67 67 # Utility functions
68 68
69 69 def apply_wrapper(wrapper, func):
70 70 """Apply a wrapper to a function for decoration.
71 71
72 72 This mixes Michele Simionato's decorator tool with nose's make_decorator,
73 73 to apply a wrapper in a decorator so that all nose attributes, as well as
74 74 function signature and other properties, survive the decoration cleanly.
75 75 This will ensure that wrapped functions can still be well introspected via
76 76 IPython, for example.
77 77 """
78 78 warnings.warn("The function `apply_wrapper` is deprecated since IPython 4.0",
79 79 DeprecationWarning, stacklevel=2)
80 80 import nose.tools
81 81
82 82 return decorator(wrapper,nose.tools.make_decorator(func)(wrapper))
83 83
84 84
85 85 def make_label_dec(label, ds=None):
86 86 """Factory function to create a decorator that applies one or more labels.
87 87
88 88 Parameters
89 89 ----------
90 90 label : string or sequence
91 91 One or more labels that will be applied by the decorator to the functions
92 92 it decorates. Labels are attributes of the decorated function with their
93 93 value set to True.
94 94
95 95 ds : string
96 96 An optional docstring for the resulting decorator. If not given, a
97 97 default docstring is auto-generated.
98 98
99 99 Returns
100 100 -------
101 101 A decorator.
102 102
103 103 Examples
104 104 --------
105 105
106 106 A simple labeling decorator:
107 107
108 108 >>> slow = make_label_dec('slow')
109 109 >>> slow.__doc__
110 110 "Labels a test as 'slow'."
111
111
112 112 And one that uses multiple labels and a custom docstring:
113
113
114 114 >>> rare = make_label_dec(['slow','hard'],
115 115 ... "Mix labels 'slow' and 'hard' for rare tests.")
116 116 >>> rare.__doc__
117 117 "Mix labels 'slow' and 'hard' for rare tests."
118 118
119 119 Now, let's test using this one:
120 120 >>> @rare
121 121 ... def f(): pass
122 122 ...
123 123 >>>
124 124 >>> f.slow
125 125 True
126 126 >>> f.hard
127 127 True
128 128 """
129 129
130 130 warnings.warn("The function `make_label_dec` is deprecated since IPython 4.0",
131 131 DeprecationWarning, stacklevel=2)
132 132 if isinstance(label, str):
133 133 labels = [label]
134 134 else:
135 135 labels = label
136 136
137 137 # Validate that the given label(s) are OK for use in setattr() by doing a
138 138 # dry run on a dummy function.
139 139 tmp = lambda : None
140 140 for label in labels:
141 141 setattr(tmp,label,True)
142 142
143 143 # This is the actual decorator we'll return
144 144 def decor(f):
145 145 for label in labels:
146 146 setattr(f,label,True)
147 147 return f
148 148
149 149 # Apply the user's docstring, or autogenerate a basic one
150 150 if ds is None:
151 151 ds = "Labels a test as %r." % label
152 152 decor.__doc__ = ds
153 153
154 154 return decor
155 155
156 156
157 157 # Inspired by numpy's skipif, but uses the full apply_wrapper utility to
158 158 # preserve function metadata better and allows the skip condition to be a
159 159 # callable.
160 160 def skipif(skip_condition, msg=None):
161 161 ''' Make function raise SkipTest exception if skip_condition is true
162 162
163 163 Parameters
164 164 ----------
165 165
166 166 skip_condition : bool or callable
167 167 Flag to determine whether to skip test. If the condition is a
168 168 callable, it is used at runtime to dynamically make the decision. This
169 169 is useful for tests that may require costly imports, to delay the cost
170 170 until the test suite is actually executed.
171 171 msg : string
172 172 Message to give on raising a SkipTest exception.
173 173
174 174 Returns
175 175 -------
176 176 decorator : function
177 177 Decorator, which, when applied to a function, causes SkipTest
178 178 to be raised when the skip_condition was True, and the function
179 179 to be called normally otherwise.
180 180
181 181 Notes
182 182 -----
183 183 You will see from the code that we had to further decorate the
184 184 decorator with the nose.tools.make_decorator function in order to
185 185 transmit function name, and various other metadata.
186 186 '''
187 187
188 188 def skip_decorator(f):
189 189 # Local import to avoid a hard nose dependency and only incur the
190 190 # import time overhead at actual test-time.
191 191 import nose
192 192
193 193 # Allow for both boolean or callable skip conditions.
194 194 if callable(skip_condition):
195 195 skip_val = skip_condition
196 196 else:
197 197 skip_val = lambda : skip_condition
198 198
199 199 def get_msg(func,msg=None):
200 200 """Skip message with information about function being skipped."""
201 201 if msg is None: out = 'Test skipped due to test condition.'
202 202 else: out = msg
203 203 return "Skipping test: %s. %s" % (func.__name__,out)
204 204
205 205 # We need to define *two* skippers because Python doesn't allow both
206 206 # return with value and yield inside the same function.
207 207 def skipper_func(*args, **kwargs):
208 208 """Skipper for normal test functions."""
209 209 if skip_val():
210 210 raise nose.SkipTest(get_msg(f,msg))
211 211 else:
212 212 return f(*args, **kwargs)
213 213
214 214 def skipper_gen(*args, **kwargs):
215 215 """Skipper for test generators."""
216 216 if skip_val():
217 217 raise nose.SkipTest(get_msg(f,msg))
218 218 else:
219 219 for x in f(*args, **kwargs):
220 220 yield x
221 221
222 222 # Choose the right skipper to use when building the actual generator.
223 223 if nose.util.isgenerator(f):
224 224 skipper = skipper_gen
225 225 else:
226 226 skipper = skipper_func
227 227
228 228 return nose.tools.make_decorator(f)(skipper)
229 229
230 230 return skip_decorator
231 231
232 232 # A version with the condition set to true, common case just to attach a message
233 233 # to a skip decorator
234 234 def skip(msg=None):
235 235 """Decorator factory - mark a test function for skipping from test suite.
236 236
237 237 Parameters
238 238 ----------
239 239 msg : string
240 240 Optional message to be added.
241 241
242 242 Returns
243 243 -------
244 244 decorator : function
245 245 Decorator, which, when applied to a function, causes SkipTest
246 246 to be raised, with the optional message added.
247 247 """
248 248 if msg and not isinstance(msg, str):
249 249 raise ValueError('invalid object passed to `@skip` decorator, did you '
250 250 'meant `@skip()` with brackets ?')
251 251 return skipif(True, msg)
252 252
253 253
254 254 def onlyif(condition, msg):
255 255 """The reverse from skipif, see skipif for details."""
256 256
257 257 if callable(condition):
258 258 skip_condition = lambda : not condition()
259 259 else:
260 260 skip_condition = lambda : not condition
261 261
262 262 return skipif(skip_condition, msg)
263 263
264 264 #-----------------------------------------------------------------------------
265 265 # Utility functions for decorators
266 266 def module_not_available(module):
267 267 """Can module be imported? Returns true if module does NOT import.
268 268
269 269 This is used to make a decorator to skip tests that require module to be
270 270 available, but delay the 'import numpy' to test execution time.
271 271 """
272 272 try:
273 273 mod = import_module(module)
274 274 mod_not_avail = False
275 275 except ImportError:
276 276 mod_not_avail = True
277 277
278 278 return mod_not_avail
279 279
280 280
281 281 def decorated_dummy(dec, name):
282 282 """Return a dummy function decorated with dec, with the given name.
283
283
284 284 Examples
285 285 --------
286 286 import IPython.testing.decorators as dec
287 287 setup = dec.decorated_dummy(dec.skip_if_no_x11, __name__)
288 288 """
289 289 warnings.warn("The function `decorated_dummy` is deprecated since IPython 4.0",
290 290 DeprecationWarning, stacklevel=2)
291 291 dummy = lambda: None
292 292 dummy.__name__ = name
293 293 return dec(dummy)
294 294
295 295 #-----------------------------------------------------------------------------
296 296 # Decorators for public use
297 297
298 298 # Decorators to skip certain tests on specific platforms.
299 299 skip_win32 = skipif(sys.platform == 'win32',
300 300 "This test does not run under Windows")
301 301 skip_linux = skipif(sys.platform.startswith('linux'),
302 302 "This test does not run under Linux")
303 303 skip_osx = skipif(sys.platform == 'darwin',"This test does not run under OS X")
304 304
305 305
306 306 # Decorators to skip tests if not on specific platforms.
307 307 skip_if_not_win32 = skipif(sys.platform != 'win32',
308 308 "This test only runs under Windows")
309 309 skip_if_not_linux = skipif(not sys.platform.startswith('linux'),
310 310 "This test only runs under Linux")
311 311 skip_if_not_osx = skipif(sys.platform != 'darwin',
312 312 "This test only runs under OSX")
313 313
314 314
315 315 _x11_skip_cond = (sys.platform not in ('darwin', 'win32') and
316 316 os.environ.get('DISPLAY', '') == '')
317 317 _x11_skip_msg = "Skipped under *nix when X11/XOrg not available"
318 318
319 319 skip_if_no_x11 = skipif(_x11_skip_cond, _x11_skip_msg)
320 320
321
322 # Decorators to skip certain tests on specific platform/python combinations
323 skip_win32_py38 = skipif(sys.version_info > (3,8) and os.name == 'nt')
324
325
321 326 # not a decorator itself, returns a dummy function to be used as setup
322 327 def skip_file_no_x11(name):
323 328 warnings.warn("The function `skip_file_no_x11` is deprecated since IPython 4.0",
324 329 DeprecationWarning, stacklevel=2)
325 330 return decorated_dummy(skip_if_no_x11, name) if _x11_skip_cond else None
326 331
327 332 # Other skip decorators
328 333
329 334 # generic skip without module
330 335 skip_without = lambda mod: skipif(module_not_available(mod), "This test requires %s" % mod)
331 336
332 337 skipif_not_numpy = skip_without('numpy')
333 338
334 339 skipif_not_matplotlib = skip_without('matplotlib')
335 340
336 341 skipif_not_sympy = skip_without('sympy')
337 342
338 343 skip_known_failure = knownfailureif(True,'This test is known to fail')
339 344
340 345 # A null 'decorator', useful to make more readable code that needs to pick
341 346 # between different decorators based on OS or other conditions
342 347 null_deco = lambda f: f
343 348
344 349 # Some tests only run where we can use unicode paths. Note that we can't just
345 350 # check os.path.supports_unicode_filenames, which is always False on Linux.
346 351 try:
347 352 f = tempfile.NamedTemporaryFile(prefix=u"tmp€")
348 353 except UnicodeEncodeError:
349 354 unicode_paths = False
350 355 else:
351 356 unicode_paths = True
352 357 f.close()
353 358
354 359 onlyif_unicode_paths = onlyif(unicode_paths, ("This test is only applicable "
355 360 "where we can use unicode in filenames."))
356 361
357 362
358 363 def onlyif_cmds_exist(*commands):
359 364 """
360 365 Decorator to skip test when at least one of `commands` is not found.
361 366 """
362 367 for cmd in commands:
363 368 if not shutil.which(cmd):
364 369 return skip("This test runs only if command '{0}' "
365 370 "is installed".format(cmd))
366 371 return null_deco
367 372
368 373 def onlyif_any_cmd_exists(*commands):
369 374 """
370 375 Decorator to skip test unless at least one of `commands` is found.
371 376 """
372 377 warnings.warn("The function `onlyif_any_cmd_exists` is deprecated since IPython 4.0",
373 378 DeprecationWarning, stacklevel=2)
374 379 for cmd in commands:
375 380 if shutil.which(cmd):
376 381 return null_deco
377 382 return skip("This test runs only if one of the commands {0} "
378 383 "is installed".format(commands))
@@ -1,485 +1,488 b''
1 1 # encoding: utf-8
2 2 """Tests for IPython.utils.path.py"""
3 3
4 4 # Copyright (c) IPython Development Team.
5 5 # Distributed under the terms of the Modified BSD License.
6 6
7 7 import os
8 8 import shutil
9 9 import sys
10 10 import tempfile
11 11 import unittest
12 12 from contextlib import contextmanager
13 13 from unittest.mock import patch
14 14 from os.path import join, abspath
15 15 from imp import reload
16 16
17 17 from nose import SkipTest, with_setup
18 18 import nose.tools as nt
19 19
20 20 import IPython
21 21 from IPython import paths
22 22 from IPython.testing import decorators as dec
23 23 from IPython.testing.decorators import (skip_if_not_win32, skip_win32,
24 onlyif_unicode_paths,)
24 onlyif_unicode_paths, skipif,
25 skip_win32_py38,)
25 26 from IPython.testing.tools import make_tempfile, AssertPrints
26 27 from IPython.utils import path
27 28 from IPython.utils.tempdir import TemporaryDirectory
28 29
30
29 31 # Platform-dependent imports
30 32 try:
31 33 import winreg as wreg
32 34 except ImportError:
33 35 #Fake _winreg module on non-windows platforms
34 36 import types
35 37 wr_name = "winreg"
36 38 sys.modules[wr_name] = types.ModuleType(wr_name)
37 39 try:
38 40 import winreg as wreg
39 41 except ImportError:
40 42 import _winreg as wreg
41 43 #Add entries that needs to be stubbed by the testing code
42 44 (wreg.OpenKey, wreg.QueryValueEx,) = (None, None)
43 45
44 46 #-----------------------------------------------------------------------------
45 47 # Globals
46 48 #-----------------------------------------------------------------------------
47 49 env = os.environ
48 50 TMP_TEST_DIR = tempfile.mkdtemp()
49 51 HOME_TEST_DIR = join(TMP_TEST_DIR, "home_test_dir")
50 52 #
51 53 # Setup/teardown functions/decorators
52 54 #
53 55
54 56 def setup_module():
55 57 """Setup testenvironment for the module:
56 58
57 59 - Adds dummy home dir tree
58 60 """
59 61 # Do not mask exceptions here. In particular, catching WindowsError is a
60 62 # problem because that exception is only defined on Windows...
61 63 os.makedirs(os.path.join(HOME_TEST_DIR, 'ipython'))
62 64
63 65
64 66 def teardown_module():
65 67 """Teardown testenvironment for the module:
66 68
67 69 - Remove dummy home dir tree
68 70 """
69 71 # Note: we remove the parent test dir, which is the root of all test
70 72 # subdirs we may have created. Use shutil instead of os.removedirs, so
71 73 # that non-empty directories are all recursively removed.
72 74 shutil.rmtree(TMP_TEST_DIR)
73 75
74 76
75 77 def setup_environment():
76 78 """Setup testenvironment for some functions that are tested
77 79 in this module. In particular this functions stores attributes
78 80 and other things that we need to stub in some test functions.
79 81 This needs to be done on a function level and not module level because
80 82 each testfunction needs a pristine environment.
81 83 """
82 84 global oldstuff, platformstuff
83 85 oldstuff = (env.copy(), os.name, sys.platform, path.get_home_dir, IPython.__file__, os.getcwd())
84 86
85 87 def teardown_environment():
86 88 """Restore things that were remembered by the setup_environment function
87 89 """
88 90 (oldenv, os.name, sys.platform, path.get_home_dir, IPython.__file__, old_wd) = oldstuff
89 91 os.chdir(old_wd)
90 92 reload(path)
91 93
92 94 for key in list(env):
93 95 if key not in oldenv:
94 96 del env[key]
95 97 env.update(oldenv)
96 98 if hasattr(sys, 'frozen'):
97 99 del sys.frozen
98 100
99 101 # Build decorator that uses the setup_environment/setup_environment
100 102 with_environment = with_setup(setup_environment, teardown_environment)
101 103
102 104 @skip_if_not_win32
103 105 @with_environment
104 106 def test_get_home_dir_1():
105 107 """Testcase for py2exe logic, un-compressed lib
106 108 """
107 109 unfrozen = path.get_home_dir()
108 110 sys.frozen = True
109 111
110 112 #fake filename for IPython.__init__
111 113 IPython.__file__ = abspath(join(HOME_TEST_DIR, "Lib/IPython/__init__.py"))
112 114
113 115 home_dir = path.get_home_dir()
114 116 nt.assert_equal(home_dir, unfrozen)
115 117
116 118
117 119 @skip_if_not_win32
118 120 @with_environment
119 121 def test_get_home_dir_2():
120 122 """Testcase for py2exe logic, compressed lib
121 123 """
122 124 unfrozen = path.get_home_dir()
123 125 sys.frozen = True
124 126 #fake filename for IPython.__init__
125 127 IPython.__file__ = abspath(join(HOME_TEST_DIR, "Library.zip/IPython/__init__.py")).lower()
126 128
127 129 home_dir = path.get_home_dir(True)
128 130 nt.assert_equal(home_dir, unfrozen)
129 131
130 132
131 @skipif(sys.version_info > (3,8) and os.name == 'nt')
133 @skip_win32_py38
132 134 @with_environment
133 135 def test_get_home_dir_3():
134 136 """get_home_dir() uses $HOME if set"""
135 137 env["HOME"] = HOME_TEST_DIR
136 138 home_dir = path.get_home_dir(True)
137 139 # get_home_dir expands symlinks
138 140 nt.assert_equal(home_dir, os.path.realpath(env["HOME"]))
139 141
140 142
141 143 @with_environment
142 144 def test_get_home_dir_4():
143 145 """get_home_dir() still works if $HOME is not set"""
144 146
145 147 if 'HOME' in env: del env['HOME']
146 148 # this should still succeed, but we don't care what the answer is
147 149 home = path.get_home_dir(False)
148 150
151 @skip_win32_py38
149 152 @with_environment
150 153 def test_get_home_dir_5():
151 154 """raise HomeDirError if $HOME is specified, but not a writable dir"""
152 155 env['HOME'] = abspath(HOME_TEST_DIR+'garbage')
153 156 # set os.name = posix, to prevent My Documents fallback on Windows
154 157 os.name = 'posix'
155 158 nt.assert_raises(path.HomeDirError, path.get_home_dir, True)
156 159
157 160 # Should we stub wreg fully so we can run the test on all platforms?
158 161 @skip_if_not_win32
159 162 @with_environment
160 163 def test_get_home_dir_8():
161 164 """Using registry hack for 'My Documents', os=='nt'
162 165
163 166 HOMESHARE, HOMEDRIVE, HOMEPATH, USERPROFILE and others are missing.
164 167 """
165 168 os.name = 'nt'
166 169 # Remove from stub environment all keys that may be set
167 170 for key in ['HOME', 'HOMESHARE', 'HOMEDRIVE', 'HOMEPATH', 'USERPROFILE']:
168 171 env.pop(key, None)
169 172
170 173 class key:
171 174 def Close(self):
172 175 pass
173 176
174 177 with patch.object(wreg, 'OpenKey', return_value=key()), \
175 178 patch.object(wreg, 'QueryValueEx', return_value=[abspath(HOME_TEST_DIR)]):
176 179 home_dir = path.get_home_dir()
177 180 nt.assert_equal(home_dir, abspath(HOME_TEST_DIR))
178 181
179 182 @with_environment
180 183 def test_get_xdg_dir_0():
181 184 """test_get_xdg_dir_0, check xdg_dir"""
182 185 reload(path)
183 186 path._writable_dir = lambda path: True
184 187 path.get_home_dir = lambda : 'somewhere'
185 188 os.name = "posix"
186 189 sys.platform = "linux2"
187 190 env.pop('IPYTHON_DIR', None)
188 191 env.pop('IPYTHONDIR', None)
189 192 env.pop('XDG_CONFIG_HOME', None)
190 193
191 194 nt.assert_equal(path.get_xdg_dir(), os.path.join('somewhere', '.config'))
192 195
193 196
194 197 @with_environment
195 198 def test_get_xdg_dir_1():
196 199 """test_get_xdg_dir_1, check nonexistent xdg_dir"""
197 200 reload(path)
198 201 path.get_home_dir = lambda : HOME_TEST_DIR
199 202 os.name = "posix"
200 203 sys.platform = "linux2"
201 204 env.pop('IPYTHON_DIR', None)
202 205 env.pop('IPYTHONDIR', None)
203 206 env.pop('XDG_CONFIG_HOME', None)
204 207 nt.assert_equal(path.get_xdg_dir(), None)
205 208
206 209 @with_environment
207 210 def test_get_xdg_dir_2():
208 211 """test_get_xdg_dir_2, check xdg_dir default to ~/.config"""
209 212 reload(path)
210 213 path.get_home_dir = lambda : HOME_TEST_DIR
211 214 os.name = "posix"
212 215 sys.platform = "linux2"
213 216 env.pop('IPYTHON_DIR', None)
214 217 env.pop('IPYTHONDIR', None)
215 218 env.pop('XDG_CONFIG_HOME', None)
216 219 cfgdir=os.path.join(path.get_home_dir(), '.config')
217 220 if not os.path.exists(cfgdir):
218 221 os.makedirs(cfgdir)
219 222
220 223 nt.assert_equal(path.get_xdg_dir(), cfgdir)
221 224
222 225 @with_environment
223 226 def test_get_xdg_dir_3():
224 227 """test_get_xdg_dir_3, check xdg_dir not used on OS X"""
225 228 reload(path)
226 229 path.get_home_dir = lambda : HOME_TEST_DIR
227 230 os.name = "posix"
228 231 sys.platform = "darwin"
229 232 env.pop('IPYTHON_DIR', None)
230 233 env.pop('IPYTHONDIR', None)
231 234 env.pop('XDG_CONFIG_HOME', None)
232 235 cfgdir=os.path.join(path.get_home_dir(), '.config')
233 236 if not os.path.exists(cfgdir):
234 237 os.makedirs(cfgdir)
235 238
236 239 nt.assert_equal(path.get_xdg_dir(), None)
237 240
238 241 def test_filefind():
239 242 """Various tests for filefind"""
240 243 f = tempfile.NamedTemporaryFile()
241 244 # print 'fname:',f.name
242 245 alt_dirs = paths.get_ipython_dir()
243 246 t = path.filefind(f.name, alt_dirs)
244 247 # print 'found:',t
245 248
246 249
247 250 @dec.skip_if_not_win32
248 251 def test_get_long_path_name_win32():
249 252 with TemporaryDirectory() as tmpdir:
250 253
251 254 # Make a long path. Expands the path of tmpdir prematurely as it may already have a long
252 255 # path component, so ensure we include the long form of it
253 256 long_path = os.path.join(path.get_long_path_name(tmpdir), 'this is my long path name')
254 257 os.makedirs(long_path)
255 258
256 259 # Test to see if the short path evaluates correctly.
257 260 short_path = os.path.join(tmpdir, 'THISIS~1')
258 261 evaluated_path = path.get_long_path_name(short_path)
259 262 nt.assert_equal(evaluated_path.lower(), long_path.lower())
260 263
261 264
262 265 @dec.skip_win32
263 266 def test_get_long_path_name():
264 267 p = path.get_long_path_name('/usr/local')
265 268 nt.assert_equal(p,'/usr/local')
266 269
267 270
268 271 class TestRaiseDeprecation(unittest.TestCase):
269 272
270 273 @dec.skip_win32 # can't create not-user-writable dir on win
271 274 @with_environment
272 275 def test_not_writable_ipdir(self):
273 276 tmpdir = tempfile.mkdtemp()
274 277 os.name = "posix"
275 278 env.pop('IPYTHON_DIR', None)
276 279 env.pop('IPYTHONDIR', None)
277 280 env.pop('XDG_CONFIG_HOME', None)
278 281 env['HOME'] = tmpdir
279 282 ipdir = os.path.join(tmpdir, '.ipython')
280 283 os.mkdir(ipdir, 0o555)
281 284 try:
282 285 open(os.path.join(ipdir, "_foo_"), 'w').close()
283 286 except IOError:
284 287 pass
285 288 else:
286 289 # I can still write to an unwritable dir,
287 290 # assume I'm root and skip the test
288 291 raise SkipTest("I can't create directories that I can't write to")
289 292 with self.assertWarnsRegex(UserWarning, 'is not a writable location'):
290 293 ipdir = paths.get_ipython_dir()
291 294 env.pop('IPYTHON_DIR', None)
292 295
293 296 @with_environment
294 297 def test_get_py_filename():
295 298 os.chdir(TMP_TEST_DIR)
296 299 with make_tempfile('foo.py'):
297 300 nt.assert_equal(path.get_py_filename('foo.py'), 'foo.py')
298 301 nt.assert_equal(path.get_py_filename('foo'), 'foo.py')
299 302 with make_tempfile('foo'):
300 303 nt.assert_equal(path.get_py_filename('foo'), 'foo')
301 304 nt.assert_raises(IOError, path.get_py_filename, 'foo.py')
302 305 nt.assert_raises(IOError, path.get_py_filename, 'foo')
303 306 nt.assert_raises(IOError, path.get_py_filename, 'foo.py')
304 307 true_fn = 'foo with spaces.py'
305 308 with make_tempfile(true_fn):
306 309 nt.assert_equal(path.get_py_filename('foo with spaces'), true_fn)
307 310 nt.assert_equal(path.get_py_filename('foo with spaces.py'), true_fn)
308 311 nt.assert_raises(IOError, path.get_py_filename, '"foo with spaces.py"')
309 312 nt.assert_raises(IOError, path.get_py_filename, "'foo with spaces.py'")
310 313
311 314 @onlyif_unicode_paths
312 315 def test_unicode_in_filename():
313 316 """When a file doesn't exist, the exception raised should be safe to call
314 317 str() on - i.e. in Python 2 it must only have ASCII characters.
315 318
316 319 https://github.com/ipython/ipython/issues/875
317 320 """
318 321 try:
319 322 # these calls should not throw unicode encode exceptions
320 323 path.get_py_filename('fooéè.py')
321 324 except IOError as ex:
322 325 str(ex)
323 326
324 327
325 328 class TestShellGlob(unittest.TestCase):
326 329
327 330 @classmethod
328 331 def setUpClass(cls):
329 332 cls.filenames_start_with_a = ['a0', 'a1', 'a2']
330 333 cls.filenames_end_with_b = ['0b', '1b', '2b']
331 334 cls.filenames = cls.filenames_start_with_a + cls.filenames_end_with_b
332 335 cls.tempdir = TemporaryDirectory()
333 336 td = cls.tempdir.name
334 337
335 338 with cls.in_tempdir():
336 339 # Create empty files
337 340 for fname in cls.filenames:
338 341 open(os.path.join(td, fname), 'w').close()
339 342
340 343 @classmethod
341 344 def tearDownClass(cls):
342 345 cls.tempdir.cleanup()
343 346
344 347 @classmethod
345 348 @contextmanager
346 349 def in_tempdir(cls):
347 350 save = os.getcwd()
348 351 try:
349 352 os.chdir(cls.tempdir.name)
350 353 yield
351 354 finally:
352 355 os.chdir(save)
353 356
354 357 def check_match(self, patterns, matches):
355 358 with self.in_tempdir():
356 359 # glob returns unordered list. that's why sorted is required.
357 360 nt.assert_equal(sorted(path.shellglob(patterns)),
358 361 sorted(matches))
359 362
360 363 def common_cases(self):
361 364 return [
362 365 (['*'], self.filenames),
363 366 (['a*'], self.filenames_start_with_a),
364 367 (['*c'], ['*c']),
365 368 (['*', 'a*', '*b', '*c'], self.filenames
366 369 + self.filenames_start_with_a
367 370 + self.filenames_end_with_b
368 371 + ['*c']),
369 372 (['a[012]'], self.filenames_start_with_a),
370 373 ]
371 374
372 375 @skip_win32
373 376 def test_match_posix(self):
374 377 for (patterns, matches) in self.common_cases() + [
375 378 ([r'\*'], ['*']),
376 379 ([r'a\*', 'a*'], ['a*'] + self.filenames_start_with_a),
377 380 ([r'a\[012]'], ['a[012]']),
378 381 ]:
379 382 yield (self.check_match, patterns, matches)
380 383
381 384 @skip_if_not_win32
382 385 def test_match_windows(self):
383 386 for (patterns, matches) in self.common_cases() + [
384 387 # In windows, backslash is interpreted as path
385 388 # separator. Therefore, you can't escape glob
386 389 # using it.
387 390 ([r'a\*', 'a*'], [r'a\*'] + self.filenames_start_with_a),
388 391 ([r'a\[012]'], [r'a\[012]']),
389 392 ]:
390 393 yield (self.check_match, patterns, matches)
391 394
392 395
393 396 def test_unescape_glob():
394 397 nt.assert_equal(path.unescape_glob(r'\*\[\!\]\?'), '*[!]?')
395 398 nt.assert_equal(path.unescape_glob(r'\\*'), r'\*')
396 399 nt.assert_equal(path.unescape_glob(r'\\\*'), r'\*')
397 400 nt.assert_equal(path.unescape_glob(r'\\a'), r'\a')
398 401 nt.assert_equal(path.unescape_glob(r'\a'), r'\a')
399 402
400 403
401 404 @onlyif_unicode_paths
402 405 def test_ensure_dir_exists():
403 406 with TemporaryDirectory() as td:
404 407 d = os.path.join(td, 'βˆ‚ir')
405 408 path.ensure_dir_exists(d) # create it
406 409 assert os.path.isdir(d)
407 410 path.ensure_dir_exists(d) # no-op
408 411 f = os.path.join(td, 'Ζ’ile')
409 412 open(f, 'w').close() # touch
410 413 with nt.assert_raises(IOError):
411 414 path.ensure_dir_exists(f)
412 415
413 416 class TestLinkOrCopy(unittest.TestCase):
414 417 def setUp(self):
415 418 self.tempdir = TemporaryDirectory()
416 419 self.src = self.dst("src")
417 420 with open(self.src, "w") as f:
418 421 f.write("Hello, world!")
419 422
420 423 def tearDown(self):
421 424 self.tempdir.cleanup()
422 425
423 426 def dst(self, *args):
424 427 return os.path.join(self.tempdir.name, *args)
425 428
426 429 def assert_inode_not_equal(self, a, b):
427 430 nt.assert_not_equal(os.stat(a).st_ino, os.stat(b).st_ino,
428 431 "%r and %r do reference the same indoes" %(a, b))
429 432
430 433 def assert_inode_equal(self, a, b):
431 434 nt.assert_equal(os.stat(a).st_ino, os.stat(b).st_ino,
432 435 "%r and %r do not reference the same indoes" %(a, b))
433 436
434 437 def assert_content_equal(self, a, b):
435 438 with open(a) as a_f:
436 439 with open(b) as b_f:
437 440 nt.assert_equal(a_f.read(), b_f.read())
438 441
439 442 @skip_win32
440 443 def test_link_successful(self):
441 444 dst = self.dst("target")
442 445 path.link_or_copy(self.src, dst)
443 446 self.assert_inode_equal(self.src, dst)
444 447
445 448 @skip_win32
446 449 def test_link_into_dir(self):
447 450 dst = self.dst("some_dir")
448 451 os.mkdir(dst)
449 452 path.link_or_copy(self.src, dst)
450 453 expected_dst = self.dst("some_dir", os.path.basename(self.src))
451 454 self.assert_inode_equal(self.src, expected_dst)
452 455
453 456 @skip_win32
454 457 def test_target_exists(self):
455 458 dst = self.dst("target")
456 459 open(dst, "w").close()
457 460 path.link_or_copy(self.src, dst)
458 461 self.assert_inode_equal(self.src, dst)
459 462
460 463 @skip_win32
461 464 def test_no_link(self):
462 465 real_link = os.link
463 466 try:
464 467 del os.link
465 468 dst = self.dst("target")
466 469 path.link_or_copy(self.src, dst)
467 470 self.assert_content_equal(self.src, dst)
468 471 self.assert_inode_not_equal(self.src, dst)
469 472 finally:
470 473 os.link = real_link
471 474
472 475 @skip_if_not_win32
473 476 def test_windows(self):
474 477 dst = self.dst("target")
475 478 path.link_or_copy(self.src, dst)
476 479 self.assert_content_equal(self.src, dst)
477 480
478 481 def test_link_twice(self):
479 482 # Linking the same file twice shouldn't leave duplicates around.
480 483 # See https://github.com/ipython/ipython/issues/6450
481 484 dst = self.dst('target')
482 485 path.link_or_copy(self.src, dst)
483 486 path.link_or_copy(self.src, dst)
484 487 self.assert_inode_equal(self.src, dst)
485 488 nt.assert_equal(sorted(os.listdir(self.tempdir.name)), ['src', 'target'])
General Comments 0
You need to be logged in to leave comments. Login now