##// END OF EJS Templates
autoformat
Matthias Bussonnier -
Show More
@@ -1,509 +1,509 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 # Copyright (c) IPython Development Team.
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
5 # Distributed under the terms of the Modified BSD License.
6
6
7 import os
7 import os
8 import shutil
8 import shutil
9 import sys
9 import sys
10 import tempfile
10 import tempfile
11 import unittest
11 import unittest
12 from contextlib import contextmanager
12 from contextlib import contextmanager
13 from unittest.mock import patch
13 from unittest.mock import patch
14 from os.path import join, abspath
14 from os.path import join, abspath
15 from importlib import reload
15 from importlib import reload
16
16
17 import pytest
17 import pytest
18
18
19 import IPython
19 import IPython
20 from IPython import paths
20 from IPython import paths
21 from IPython.testing import decorators as dec
21 from IPython.testing import decorators as dec
22 from IPython.testing.decorators import (
22 from IPython.testing.decorators import (
23 skip_if_not_win32,
23 skip_if_not_win32,
24 skip_win32,
24 skip_win32,
25 onlyif_unicode_paths,
25 onlyif_unicode_paths,
26 )
26 )
27 from IPython.testing.tools import make_tempfile
27 from IPython.testing.tools import make_tempfile
28 from IPython.utils import path
28 from IPython.utils import path
29 from IPython.utils.tempdir import TemporaryDirectory
29 from IPython.utils.tempdir import TemporaryDirectory
30
30
31
31
32 # Platform-dependent imports
32 # Platform-dependent imports
33 try:
33 try:
34 import winreg as wreg
34 import winreg as wreg
35 except ImportError:
35 except ImportError:
36 #Fake _winreg module on non-windows platforms
36 #Fake _winreg module on non-windows platforms
37 import types
37 import types
38 wr_name = "winreg"
38 wr_name = "winreg"
39 sys.modules[wr_name] = types.ModuleType(wr_name)
39 sys.modules[wr_name] = types.ModuleType(wr_name)
40 try:
40 try:
41 import winreg as wreg
41 import winreg as wreg
42 except ImportError:
42 except ImportError:
43 import _winreg as wreg
43 import _winreg as wreg
44 #Add entries that needs to be stubbed by the testing code
44 #Add entries that needs to be stubbed by the testing code
45 (wreg.OpenKey, wreg.QueryValueEx,) = (None, None)
45 (wreg.OpenKey, wreg.QueryValueEx,) = (None, None)
46
46
47 #-----------------------------------------------------------------------------
47 #-----------------------------------------------------------------------------
48 # Globals
48 # Globals
49 #-----------------------------------------------------------------------------
49 #-----------------------------------------------------------------------------
50 env = os.environ
50 env = os.environ
51 TMP_TEST_DIR = tempfile.mkdtemp()
51 TMP_TEST_DIR = tempfile.mkdtemp()
52 HOME_TEST_DIR = join(TMP_TEST_DIR, "home_test_dir")
52 HOME_TEST_DIR = join(TMP_TEST_DIR, "home_test_dir")
53 #
53 #
54 # Setup/teardown functions/decorators
54 # Setup/teardown functions/decorators
55 #
55 #
56
56
57 def setup_module():
57 def setup_module():
58 """Setup testenvironment for the module:
58 """Setup testenvironment for the module:
59
59
60 - Adds dummy home dir tree
60 - Adds dummy home dir tree
61 """
61 """
62 # Do not mask exceptions here. In particular, catching WindowsError is a
62 # Do not mask exceptions here. In particular, catching WindowsError is a
63 # problem because that exception is only defined on Windows...
63 # problem because that exception is only defined on Windows...
64 os.makedirs(os.path.join(HOME_TEST_DIR, 'ipython'))
64 os.makedirs(os.path.join(HOME_TEST_DIR, 'ipython'))
65
65
66
66
67 def teardown_module():
67 def teardown_module():
68 """Teardown testenvironment for the module:
68 """Teardown testenvironment for the module:
69
69
70 - Remove dummy home dir tree
70 - Remove dummy home dir tree
71 """
71 """
72 # Note: we remove the parent test dir, which is the root of all test
72 # Note: we remove the parent test dir, which is the root of all test
73 # subdirs we may have created. Use shutil instead of os.removedirs, so
73 # subdirs we may have created. Use shutil instead of os.removedirs, so
74 # that non-empty directories are all recursively removed.
74 # that non-empty directories are all recursively removed.
75 shutil.rmtree(TMP_TEST_DIR)
75 shutil.rmtree(TMP_TEST_DIR)
76
76
77
77
78 def setup_environment():
78 def setup_environment():
79 """Setup testenvironment for some functions that are tested
79 """Setup testenvironment for some functions that are tested
80 in this module. In particular this functions stores attributes
80 in this module. In particular this functions stores attributes
81 and other things that we need to stub in some test functions.
81 and other things that we need to stub in some test functions.
82 This needs to be done on a function level and not module level because
82 This needs to be done on a function level and not module level because
83 each testfunction needs a pristine environment.
83 each testfunction needs a pristine environment.
84 """
84 """
85 global oldstuff, platformstuff
85 global oldstuff, platformstuff
86 oldstuff = (env.copy(), os.name, sys.platform, path.get_home_dir, IPython.__file__, os.getcwd())
86 oldstuff = (env.copy(), os.name, sys.platform, path.get_home_dir, IPython.__file__, os.getcwd())
87
87
88 def teardown_environment():
88 def teardown_environment():
89 """Restore things that were remembered by the setup_environment function
89 """Restore things that were remembered by the setup_environment function
90 """
90 """
91 (oldenv, os.name, sys.platform, path.get_home_dir, IPython.__file__, old_wd) = oldstuff
91 (oldenv, os.name, sys.platform, path.get_home_dir, IPython.__file__, old_wd) = oldstuff
92 os.chdir(old_wd)
92 os.chdir(old_wd)
93 reload(path)
93 reload(path)
94
94
95 for key in list(env):
95 for key in list(env):
96 if key not in oldenv:
96 if key not in oldenv:
97 del env[key]
97 del env[key]
98 env.update(oldenv)
98 env.update(oldenv)
99 if hasattr(sys, 'frozen'):
99 if hasattr(sys, 'frozen'):
100 del sys.frozen
100 del sys.frozen
101
101
102
102
103 # Build decorator that uses the setup_environment/setup_environment
103 # Build decorator that uses the setup_environment/setup_environment
104 @pytest.fixture
104 @pytest.fixture
105 def environment():
105 def environment():
106 setup_environment()
106 setup_environment()
107 yield
107 yield
108 teardown_environment()
108 teardown_environment()
109
109
110
110
111 with_environment = pytest.mark.usefixtures("environment")
111 with_environment = pytest.mark.usefixtures("environment")
112
112
113
113
114 @skip_if_not_win32
114 @skip_if_not_win32
115 @with_environment
115 @with_environment
116 def test_get_home_dir_1():
116 def test_get_home_dir_1():
117 """Testcase for py2exe logic, un-compressed lib
117 """Testcase for py2exe logic, un-compressed lib
118 """
118 """
119 unfrozen = path.get_home_dir()
119 unfrozen = path.get_home_dir()
120 sys.frozen = True
120 sys.frozen = True
121
121
122 #fake filename for IPython.__init__
122 #fake filename for IPython.__init__
123 IPython.__file__ = abspath(join(HOME_TEST_DIR, "Lib/IPython/__init__.py"))
123 IPython.__file__ = abspath(join(HOME_TEST_DIR, "Lib/IPython/__init__.py"))
124
124
125 home_dir = path.get_home_dir()
125 home_dir = path.get_home_dir()
126 assert home_dir == unfrozen
126 assert home_dir == unfrozen
127
127
128
128
129 @skip_if_not_win32
129 @skip_if_not_win32
130 @with_environment
130 @with_environment
131 def test_get_home_dir_2():
131 def test_get_home_dir_2():
132 """Testcase for py2exe logic, compressed lib
132 """Testcase for py2exe logic, compressed lib
133 """
133 """
134 unfrozen = path.get_home_dir()
134 unfrozen = path.get_home_dir()
135 sys.frozen = True
135 sys.frozen = True
136 #fake filename for IPython.__init__
136 #fake filename for IPython.__init__
137 IPython.__file__ = abspath(join(HOME_TEST_DIR, "Library.zip/IPython/__init__.py")).lower()
137 IPython.__file__ = abspath(join(HOME_TEST_DIR, "Library.zip/IPython/__init__.py")).lower()
138
138
139 home_dir = path.get_home_dir(True)
139 home_dir = path.get_home_dir(True)
140 assert home_dir == unfrozen
140 assert home_dir == unfrozen
141
141
142
142
143 @skip_win32
143 @skip_win32
144 @with_environment
144 @with_environment
145 def test_get_home_dir_3():
145 def test_get_home_dir_3():
146 """get_home_dir() uses $HOME if set"""
146 """get_home_dir() uses $HOME if set"""
147 env["HOME"] = HOME_TEST_DIR
147 env["HOME"] = HOME_TEST_DIR
148 home_dir = path.get_home_dir(True)
148 home_dir = path.get_home_dir(True)
149 # get_home_dir expands symlinks
149 # get_home_dir expands symlinks
150 assert home_dir == os.path.realpath(env["HOME"])
150 assert home_dir == os.path.realpath(env["HOME"])
151
151
152
152
153 @with_environment
153 @with_environment
154 def test_get_home_dir_4():
154 def test_get_home_dir_4():
155 """get_home_dir() still works if $HOME is not set"""
155 """get_home_dir() still works if $HOME is not set"""
156
156
157 if 'HOME' in env: del env['HOME']
157 if 'HOME' in env: del env['HOME']
158 # this should still succeed, but we don't care what the answer is
158 # this should still succeed, but we don't care what the answer is
159 home = path.get_home_dir(False)
159 home = path.get_home_dir(False)
160
160
161 @skip_win32
161 @skip_win32
162 @with_environment
162 @with_environment
163 def test_get_home_dir_5():
163 def test_get_home_dir_5():
164 """raise HomeDirError if $HOME is specified, but not a writable dir"""
164 """raise HomeDirError if $HOME is specified, but not a writable dir"""
165 env['HOME'] = abspath(HOME_TEST_DIR+'garbage')
165 env['HOME'] = abspath(HOME_TEST_DIR+'garbage')
166 # set os.name = posix, to prevent My Documents fallback on Windows
166 # set os.name = posix, to prevent My Documents fallback on Windows
167 os.name = 'posix'
167 os.name = 'posix'
168 pytest.raises(path.HomeDirError, path.get_home_dir, True)
168 pytest.raises(path.HomeDirError, path.get_home_dir, True)
169
169
170 # Should we stub wreg fully so we can run the test on all platforms?
170 # Should we stub wreg fully so we can run the test on all platforms?
171 @skip_if_not_win32
171 @skip_if_not_win32
172 @with_environment
172 @with_environment
173 def test_get_home_dir_8():
173 def test_get_home_dir_8():
174 """Using registry hack for 'My Documents', os=='nt'
174 """Using registry hack for 'My Documents', os=='nt'
175
175
176 HOMESHARE, HOMEDRIVE, HOMEPATH, USERPROFILE and others are missing.
176 HOMESHARE, HOMEDRIVE, HOMEPATH, USERPROFILE and others are missing.
177 """
177 """
178 os.name = 'nt'
178 os.name = 'nt'
179 # Remove from stub environment all keys that may be set
179 # Remove from stub environment all keys that may be set
180 for key in ['HOME', 'HOMESHARE', 'HOMEDRIVE', 'HOMEPATH', 'USERPROFILE']:
180 for key in ['HOME', 'HOMESHARE', 'HOMEDRIVE', 'HOMEPATH', 'USERPROFILE']:
181 env.pop(key, None)
181 env.pop(key, None)
182
182
183 class key:
183 class key:
184 def __enter__(self):
184 def __enter__(self):
185 pass
185 pass
186 def Close(self):
186 def Close(self):
187 pass
187 pass
188 def __exit__(*args, **kwargs):
188 def __exit__(*args, **kwargs):
189 pass
189 pass
190
190
191 with patch.object(wreg, 'OpenKey', return_value=key()), \
191 with patch.object(wreg, 'OpenKey', return_value=key()), \
192 patch.object(wreg, 'QueryValueEx', return_value=[abspath(HOME_TEST_DIR)]):
192 patch.object(wreg, 'QueryValueEx', return_value=[abspath(HOME_TEST_DIR)]):
193 home_dir = path.get_home_dir()
193 home_dir = path.get_home_dir()
194 assert home_dir == abspath(HOME_TEST_DIR)
194 assert home_dir == abspath(HOME_TEST_DIR)
195
195
196 @with_environment
196 @with_environment
197 def test_get_xdg_dir_0():
197 def test_get_xdg_dir_0():
198 """test_get_xdg_dir_0, check xdg_dir"""
198 """test_get_xdg_dir_0, check xdg_dir"""
199 reload(path)
199 reload(path)
200 path._writable_dir = lambda path: True
200 path._writable_dir = lambda path: True
201 path.get_home_dir = lambda : 'somewhere'
201 path.get_home_dir = lambda : 'somewhere'
202 os.name = "posix"
202 os.name = "posix"
203 sys.platform = "linux2"
203 sys.platform = "linux2"
204 env.pop('IPYTHON_DIR', None)
204 env.pop('IPYTHON_DIR', None)
205 env.pop('IPYTHONDIR', None)
205 env.pop('IPYTHONDIR', None)
206 env.pop('XDG_CONFIG_HOME', None)
206 env.pop('XDG_CONFIG_HOME', None)
207
207
208 assert path.get_xdg_dir() == os.path.join("somewhere", ".config")
208 assert path.get_xdg_dir() == os.path.join("somewhere", ".config")
209
209
210
210
211 @with_environment
211 @with_environment
212 def test_get_xdg_dir_1():
212 def test_get_xdg_dir_1():
213 """test_get_xdg_dir_1, check nonexistent xdg_dir"""
213 """test_get_xdg_dir_1, check nonexistent xdg_dir"""
214 reload(path)
214 reload(path)
215 path.get_home_dir = lambda : HOME_TEST_DIR
215 path.get_home_dir = lambda : HOME_TEST_DIR
216 os.name = "posix"
216 os.name = "posix"
217 sys.platform = "linux2"
217 sys.platform = "linux2"
218 env.pop('IPYTHON_DIR', None)
218 env.pop('IPYTHON_DIR', None)
219 env.pop('IPYTHONDIR', None)
219 env.pop('IPYTHONDIR', None)
220 env.pop('XDG_CONFIG_HOME', None)
220 env.pop('XDG_CONFIG_HOME', None)
221 assert path.get_xdg_dir() is None
221 assert path.get_xdg_dir() is None
222
222
223 @with_environment
223 @with_environment
224 def test_get_xdg_dir_2():
224 def test_get_xdg_dir_2():
225 """test_get_xdg_dir_2, check xdg_dir default to ~/.config"""
225 """test_get_xdg_dir_2, check xdg_dir default to ~/.config"""
226 reload(path)
226 reload(path)
227 path.get_home_dir = lambda : HOME_TEST_DIR
227 path.get_home_dir = lambda : HOME_TEST_DIR
228 os.name = "posix"
228 os.name = "posix"
229 sys.platform = "linux2"
229 sys.platform = "linux2"
230 env.pop('IPYTHON_DIR', None)
230 env.pop('IPYTHON_DIR', None)
231 env.pop('IPYTHONDIR', None)
231 env.pop('IPYTHONDIR', None)
232 env.pop('XDG_CONFIG_HOME', None)
232 env.pop('XDG_CONFIG_HOME', None)
233 cfgdir=os.path.join(path.get_home_dir(), '.config')
233 cfgdir=os.path.join(path.get_home_dir(), '.config')
234 if not os.path.exists(cfgdir):
234 if not os.path.exists(cfgdir):
235 os.makedirs(cfgdir)
235 os.makedirs(cfgdir)
236
236
237 assert path.get_xdg_dir() == cfgdir
237 assert path.get_xdg_dir() == cfgdir
238
238
239 @with_environment
239 @with_environment
240 def test_get_xdg_dir_3():
240 def test_get_xdg_dir_3():
241 """test_get_xdg_dir_3, check xdg_dir not used on non-posix systems"""
241 """test_get_xdg_dir_3, check xdg_dir not used on non-posix systems"""
242 reload(path)
242 reload(path)
243 path.get_home_dir = lambda : HOME_TEST_DIR
243 path.get_home_dir = lambda : HOME_TEST_DIR
244 os.name = "nt"
244 os.name = "nt"
245 sys.platform = "win32"
245 sys.platform = "win32"
246 env.pop('IPYTHON_DIR', None)
246 env.pop('IPYTHON_DIR', None)
247 env.pop('IPYTHONDIR', None)
247 env.pop('IPYTHONDIR', None)
248 env.pop('XDG_CONFIG_HOME', None)
248 env.pop('XDG_CONFIG_HOME', None)
249 cfgdir=os.path.join(path.get_home_dir(), '.config')
249 cfgdir=os.path.join(path.get_home_dir(), '.config')
250 os.makedirs(cfgdir, exist_ok=True)
250 os.makedirs(cfgdir, exist_ok=True)
251
251
252 assert path.get_xdg_dir() is None
252 assert path.get_xdg_dir() is None
253
253
254 def test_filefind():
254 def test_filefind():
255 """Various tests for filefind"""
255 """Various tests for filefind"""
256 f = tempfile.NamedTemporaryFile()
256 f = tempfile.NamedTemporaryFile()
257 # print 'fname:',f.name
257 # print 'fname:',f.name
258 alt_dirs = paths.get_ipython_dir()
258 alt_dirs = paths.get_ipython_dir()
259 t = path.filefind(f.name, alt_dirs)
259 t = path.filefind(f.name, alt_dirs)
260 # print 'found:',t
260 # print 'found:',t
261
261
262
262
263 @dec.skip_if_not_win32
263 @dec.skip_if_not_win32
264 def test_get_long_path_name_win32():
264 def test_get_long_path_name_win32():
265 with TemporaryDirectory() as tmpdir:
265 with TemporaryDirectory() as tmpdir:
266
266
267 # Make a long path. Expands the path of tmpdir prematurely as it may already have a long
267 # Make a long path. Expands the path of tmpdir prematurely as it may already have a long
268 # path component, so ensure we include the long form of it
268 # path component, so ensure we include the long form of it
269 long_path = os.path.join(path.get_long_path_name(tmpdir), 'this is my long path name')
269 long_path = os.path.join(path.get_long_path_name(tmpdir), 'this is my long path name')
270 os.makedirs(long_path)
270 os.makedirs(long_path)
271
271
272 # Test to see if the short path evaluates correctly.
272 # Test to see if the short path evaluates correctly.
273 short_path = os.path.join(tmpdir, 'THISIS~1')
273 short_path = os.path.join(tmpdir, 'THISIS~1')
274 evaluated_path = path.get_long_path_name(short_path)
274 evaluated_path = path.get_long_path_name(short_path)
275 assert evaluated_path.lower() == long_path.lower()
275 assert evaluated_path.lower() == long_path.lower()
276
276
277
277
278 @dec.skip_win32
278 @dec.skip_win32
279 def test_get_long_path_name():
279 def test_get_long_path_name():
280 p = path.get_long_path_name("/usr/local")
280 p = path.get_long_path_name("/usr/local")
281 assert p == "/usr/local"
281 assert p == "/usr/local"
282
282
283
283
284 class TestRaiseDeprecation(unittest.TestCase):
284 class TestRaiseDeprecation(unittest.TestCase):
285
285
286 @dec.skip_win32 # can't create not-user-writable dir on win
286 @dec.skip_win32 # can't create not-user-writable dir on win
287 @with_environment
287 @with_environment
288 def test_not_writable_ipdir(self):
288 def test_not_writable_ipdir(self):
289 tmpdir = tempfile.mkdtemp()
289 tmpdir = tempfile.mkdtemp()
290 os.name = "posix"
290 os.name = "posix"
291 env.pop('IPYTHON_DIR', None)
291 env.pop('IPYTHON_DIR', None)
292 env.pop('IPYTHONDIR', None)
292 env.pop('IPYTHONDIR', None)
293 env.pop('XDG_CONFIG_HOME', None)
293 env.pop('XDG_CONFIG_HOME', None)
294 env['HOME'] = tmpdir
294 env['HOME'] = tmpdir
295 ipdir = os.path.join(tmpdir, '.ipython')
295 ipdir = os.path.join(tmpdir, '.ipython')
296 os.mkdir(ipdir, 0o555)
296 os.mkdir(ipdir, 0o555)
297 try:
297 try:
298 open(os.path.join(ipdir, "_foo_"), 'w').close()
298 open(os.path.join(ipdir, "_foo_"), 'w').close()
299 except IOError:
299 except IOError:
300 pass
300 pass
301 else:
301 else:
302 # I can still write to an unwritable dir,
302 # I can still write to an unwritable dir,
303 # assume I'm root and skip the test
303 # assume I'm root and skip the test
304 pytest.skip("I can't create directories that I can't write to")
304 pytest.skip("I can't create directories that I can't write to")
305
305
306 with self.assertWarnsRegex(UserWarning, 'is not a writable location'):
306 with self.assertWarnsRegex(UserWarning, 'is not a writable location'):
307 ipdir = paths.get_ipython_dir()
307 ipdir = paths.get_ipython_dir()
308 env.pop('IPYTHON_DIR', None)
308 env.pop('IPYTHON_DIR', None)
309
309
310 @with_environment
310 @with_environment
311 def test_get_py_filename():
311 def test_get_py_filename():
312 os.chdir(TMP_TEST_DIR)
312 os.chdir(TMP_TEST_DIR)
313 with make_tempfile("foo.py"):
313 with make_tempfile("foo.py"):
314 assert path.get_py_filename("foo.py") == "foo.py"
314 assert path.get_py_filename("foo.py") == "foo.py"
315 assert path.get_py_filename("foo") == "foo.py"
315 assert path.get_py_filename("foo") == "foo.py"
316 with make_tempfile("foo"):
316 with make_tempfile("foo"):
317 assert path.get_py_filename("foo") == "foo"
317 assert path.get_py_filename("foo") == "foo"
318 pytest.raises(IOError, path.get_py_filename, "foo.py")
318 pytest.raises(IOError, path.get_py_filename, "foo.py")
319 pytest.raises(IOError, path.get_py_filename, "foo")
319 pytest.raises(IOError, path.get_py_filename, "foo")
320 pytest.raises(IOError, path.get_py_filename, "foo.py")
320 pytest.raises(IOError, path.get_py_filename, "foo.py")
321 true_fn = "foo with spaces.py"
321 true_fn = "foo with spaces.py"
322 with make_tempfile(true_fn):
322 with make_tempfile(true_fn):
323 assert path.get_py_filename("foo with spaces") == true_fn
323 assert path.get_py_filename("foo with spaces") == true_fn
324 assert path.get_py_filename("foo with spaces.py") == true_fn
324 assert path.get_py_filename("foo with spaces.py") == true_fn
325 pytest.raises(IOError, path.get_py_filename, '"foo with spaces.py"')
325 pytest.raises(IOError, path.get_py_filename, '"foo with spaces.py"')
326 pytest.raises(IOError, path.get_py_filename, "'foo with spaces.py'")
326 pytest.raises(IOError, path.get_py_filename, "'foo with spaces.py'")
327
327
328 @onlyif_unicode_paths
328 @onlyif_unicode_paths
329 def test_unicode_in_filename():
329 def test_unicode_in_filename():
330 """When a file doesn't exist, the exception raised should be safe to call
330 """When a file doesn't exist, the exception raised should be safe to call
331 str() on - i.e. in Python 2 it must only have ASCII characters.
331 str() on - i.e. in Python 2 it must only have ASCII characters.
332
332
333 https://github.com/ipython/ipython/issues/875
333 https://github.com/ipython/ipython/issues/875
334 """
334 """
335 try:
335 try:
336 # these calls should not throw unicode encode exceptions
336 # these calls should not throw unicode encode exceptions
337 path.get_py_filename('fooéè.py')
337 path.get_py_filename('fooéè.py')
338 except IOError as ex:
338 except IOError as ex:
339 str(ex)
339 str(ex)
340
340
341
341
342 class TestShellGlob(unittest.TestCase):
342 class TestShellGlob(unittest.TestCase):
343
343
344 @classmethod
344 @classmethod
345 def setUpClass(cls):
345 def setUpClass(cls):
346 cls.filenames_start_with_a = ['a0', 'a1', 'a2']
346 cls.filenames_start_with_a = ['a0', 'a1', 'a2']
347 cls.filenames_end_with_b = ['0b', '1b', '2b']
347 cls.filenames_end_with_b = ['0b', '1b', '2b']
348 cls.filenames = cls.filenames_start_with_a + cls.filenames_end_with_b
348 cls.filenames = cls.filenames_start_with_a + cls.filenames_end_with_b
349 cls.tempdir = TemporaryDirectory()
349 cls.tempdir = TemporaryDirectory()
350 td = cls.tempdir.name
350 td = cls.tempdir.name
351
351
352 with cls.in_tempdir():
352 with cls.in_tempdir():
353 # Create empty files
353 # Create empty files
354 for fname in cls.filenames:
354 for fname in cls.filenames:
355 open(os.path.join(td, fname), 'w').close()
355 open(os.path.join(td, fname), 'w').close()
356
356
357 @classmethod
357 @classmethod
358 def tearDownClass(cls):
358 def tearDownClass(cls):
359 cls.tempdir.cleanup()
359 cls.tempdir.cleanup()
360
360
361 @classmethod
361 @classmethod
362 @contextmanager
362 @contextmanager
363 def in_tempdir(cls):
363 def in_tempdir(cls):
364 save = os.getcwd()
364 save = os.getcwd()
365 try:
365 try:
366 os.chdir(cls.tempdir.name)
366 os.chdir(cls.tempdir.name)
367 yield
367 yield
368 finally:
368 finally:
369 os.chdir(save)
369 os.chdir(save)
370
370
371 def check_match(self, patterns, matches):
371 def check_match(self, patterns, matches):
372 with self.in_tempdir():
372 with self.in_tempdir():
373 # glob returns unordered list. that's why sorted is required.
373 # glob returns unordered list. that's why sorted is required.
374 assert sorted(path.shellglob(patterns)) == sorted(matches)
374 assert sorted(path.shellglob(patterns)) == sorted(matches)
375
375
376 def common_cases(self):
376 def common_cases(self):
377 return [
377 return [
378 (['*'], self.filenames),
378 (['*'], self.filenames),
379 (['a*'], self.filenames_start_with_a),
379 (['a*'], self.filenames_start_with_a),
380 (['*c'], ['*c']),
380 (['*c'], ['*c']),
381 (['*', 'a*', '*b', '*c'], self.filenames
381 (['*', 'a*', '*b', '*c'], self.filenames
382 + self.filenames_start_with_a
382 + self.filenames_start_with_a
383 + self.filenames_end_with_b
383 + self.filenames_end_with_b
384 + ['*c']),
384 + ['*c']),
385 (['a[012]'], self.filenames_start_with_a),
385 (['a[012]'], self.filenames_start_with_a),
386 ]
386 ]
387
387
388 @skip_win32
388 @skip_win32
389 def test_match_posix(self):
389 def test_match_posix(self):
390 for (patterns, matches) in self.common_cases() + [
390 for (patterns, matches) in self.common_cases() + [
391 ([r'\*'], ['*']),
391 ([r'\*'], ['*']),
392 ([r'a\*', 'a*'], ['a*'] + self.filenames_start_with_a),
392 ([r'a\*', 'a*'], ['a*'] + self.filenames_start_with_a),
393 ([r'a\[012]'], ['a[012]']),
393 ([r'a\[012]'], ['a[012]']),
394 ]:
394 ]:
395 self.check_match(patterns, matches)
395 self.check_match(patterns, matches)
396
396
397 @skip_if_not_win32
397 @skip_if_not_win32
398 def test_match_windows(self):
398 def test_match_windows(self):
399 for (patterns, matches) in self.common_cases() + [
399 for (patterns, matches) in self.common_cases() + [
400 # In windows, backslash is interpreted as path
400 # In windows, backslash is interpreted as path
401 # separator. Therefore, you can't escape glob
401 # separator. Therefore, you can't escape glob
402 # using it.
402 # using it.
403 ([r'a\*', 'a*'], [r'a\*'] + self.filenames_start_with_a),
403 ([r'a\*', 'a*'], [r'a\*'] + self.filenames_start_with_a),
404 ([r'a\[012]'], [r'a\[012]']),
404 ([r'a\[012]'], [r'a\[012]']),
405 ]:
405 ]:
406 self.check_match(patterns, matches)
406 self.check_match(patterns, matches)
407
407
408
408
409 @pytest.mark.parametrize(
409 @pytest.mark.parametrize(
410 'globstr, unescaped_globstr',
410 "globstr, unescaped_globstr",
411 [
411 [
412 (r"\*\[\!\]\?", "*[!]?"),
412 (r"\*\[\!\]\?", "*[!]?"),
413 (r"\\*", r"\*"),
413 (r"\\*", r"\*"),
414 (r"\\\*", r"\*"),
414 (r"\\\*", r"\*"),
415 (r"\\a", r"\a"),
415 (r"\\a", r"\a"),
416 (r"\a", r"\a")
416 (r"\a", r"\a"),
417 ]
417 ],
418 )
418 )
419 def test_unescape_glob(globstr, unescaped_globstr):
419 def test_unescape_glob(globstr, unescaped_globstr):
420 assert path.unescape_glob(globstr) == unescaped_globstr
420 assert path.unescape_glob(globstr) == unescaped_globstr
421
421
422
422
423 @onlyif_unicode_paths
423 @onlyif_unicode_paths
424 def test_ensure_dir_exists():
424 def test_ensure_dir_exists():
425 with TemporaryDirectory() as td:
425 with TemporaryDirectory() as td:
426 d = os.path.join(td, 'βˆ‚ir')
426 d = os.path.join(td, 'βˆ‚ir')
427 path.ensure_dir_exists(d) # create it
427 path.ensure_dir_exists(d) # create it
428 assert os.path.isdir(d)
428 assert os.path.isdir(d)
429 path.ensure_dir_exists(d) # no-op
429 path.ensure_dir_exists(d) # no-op
430 f = os.path.join(td, 'Ζ’ile')
430 f = os.path.join(td, 'Ζ’ile')
431 open(f, 'w').close() # touch
431 open(f, 'w').close() # touch
432 with pytest.raises(IOError):
432 with pytest.raises(IOError):
433 path.ensure_dir_exists(f)
433 path.ensure_dir_exists(f)
434
434
435 class TestLinkOrCopy(unittest.TestCase):
435 class TestLinkOrCopy(unittest.TestCase):
436 def setUp(self):
436 def setUp(self):
437 self.tempdir = TemporaryDirectory()
437 self.tempdir = TemporaryDirectory()
438 self.src = self.dst("src")
438 self.src = self.dst("src")
439 with open(self.src, "w") as f:
439 with open(self.src, "w") as f:
440 f.write("Hello, world!")
440 f.write("Hello, world!")
441
441
442 def tearDown(self):
442 def tearDown(self):
443 self.tempdir.cleanup()
443 self.tempdir.cleanup()
444
444
445 def dst(self, *args):
445 def dst(self, *args):
446 return os.path.join(self.tempdir.name, *args)
446 return os.path.join(self.tempdir.name, *args)
447
447
448 def assert_inode_not_equal(self, a, b):
448 def assert_inode_not_equal(self, a, b):
449 assert (
449 assert (
450 os.stat(a).st_ino != os.stat(b).st_ino
450 os.stat(a).st_ino != os.stat(b).st_ino
451 ), "%r and %r do reference the same indoes" % (a, b)
451 ), "%r and %r do reference the same indoes" % (a, b)
452
452
453 def assert_inode_equal(self, a, b):
453 def assert_inode_equal(self, a, b):
454 assert (
454 assert (
455 os.stat(a).st_ino == os.stat(b).st_ino
455 os.stat(a).st_ino == os.stat(b).st_ino
456 ), "%r and %r do not reference the same indoes" % (a, b)
456 ), "%r and %r do not reference the same indoes" % (a, b)
457
457
458 def assert_content_equal(self, a, b):
458 def assert_content_equal(self, a, b):
459 with open(a) as a_f:
459 with open(a) as a_f:
460 with open(b) as b_f:
460 with open(b) as b_f:
461 assert a_f.read() == b_f.read()
461 assert a_f.read() == b_f.read()
462
462
463 @skip_win32
463 @skip_win32
464 def test_link_successful(self):
464 def test_link_successful(self):
465 dst = self.dst("target")
465 dst = self.dst("target")
466 path.link_or_copy(self.src, dst)
466 path.link_or_copy(self.src, dst)
467 self.assert_inode_equal(self.src, dst)
467 self.assert_inode_equal(self.src, dst)
468
468
469 @skip_win32
469 @skip_win32
470 def test_link_into_dir(self):
470 def test_link_into_dir(self):
471 dst = self.dst("some_dir")
471 dst = self.dst("some_dir")
472 os.mkdir(dst)
472 os.mkdir(dst)
473 path.link_or_copy(self.src, dst)
473 path.link_or_copy(self.src, dst)
474 expected_dst = self.dst("some_dir", os.path.basename(self.src))
474 expected_dst = self.dst("some_dir", os.path.basename(self.src))
475 self.assert_inode_equal(self.src, expected_dst)
475 self.assert_inode_equal(self.src, expected_dst)
476
476
477 @skip_win32
477 @skip_win32
478 def test_target_exists(self):
478 def test_target_exists(self):
479 dst = self.dst("target")
479 dst = self.dst("target")
480 open(dst, "w").close()
480 open(dst, "w").close()
481 path.link_or_copy(self.src, dst)
481 path.link_or_copy(self.src, dst)
482 self.assert_inode_equal(self.src, dst)
482 self.assert_inode_equal(self.src, dst)
483
483
484 @skip_win32
484 @skip_win32
485 def test_no_link(self):
485 def test_no_link(self):
486 real_link = os.link
486 real_link = os.link
487 try:
487 try:
488 del os.link
488 del os.link
489 dst = self.dst("target")
489 dst = self.dst("target")
490 path.link_or_copy(self.src, dst)
490 path.link_or_copy(self.src, dst)
491 self.assert_content_equal(self.src, dst)
491 self.assert_content_equal(self.src, dst)
492 self.assert_inode_not_equal(self.src, dst)
492 self.assert_inode_not_equal(self.src, dst)
493 finally:
493 finally:
494 os.link = real_link
494 os.link = real_link
495
495
496 @skip_if_not_win32
496 @skip_if_not_win32
497 def test_windows(self):
497 def test_windows(self):
498 dst = self.dst("target")
498 dst = self.dst("target")
499 path.link_or_copy(self.src, dst)
499 path.link_or_copy(self.src, dst)
500 self.assert_content_equal(self.src, dst)
500 self.assert_content_equal(self.src, dst)
501
501
502 def test_link_twice(self):
502 def test_link_twice(self):
503 # Linking the same file twice shouldn't leave duplicates around.
503 # Linking the same file twice shouldn't leave duplicates around.
504 # See https://github.com/ipython/ipython/issues/6450
504 # See https://github.com/ipython/ipython/issues/6450
505 dst = self.dst('target')
505 dst = self.dst('target')
506 path.link_or_copy(self.src, dst)
506 path.link_or_copy(self.src, dst)
507 path.link_or_copy(self.src, dst)
507 path.link_or_copy(self.src, dst)
508 self.assert_inode_equal(self.src, dst)
508 self.assert_inode_equal(self.src, dst)
509 assert sorted(os.listdir(self.tempdir.name)) == ["src", "target"]
509 assert sorted(os.listdir(self.tempdir.name)) == ["src", "target"]
@@ -1,191 +1,191 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 Tests for platutils.py
3 Tests for platutils.py
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 sys
17 import sys
18 import signal
18 import signal
19 import os
19 import os
20 import time
20 import time
21 from _thread import interrupt_main # Py 3
21 from _thread import interrupt_main # Py 3
22 import threading
22 import threading
23
23
24 import pytest
24 import pytest
25
25
26 from IPython.utils.process import (find_cmd, FindCmdError, arg_split,
26 from IPython.utils.process import (find_cmd, FindCmdError, arg_split,
27 system, getoutput, getoutputerror,
27 system, getoutput, getoutputerror,
28 get_output_error_code)
28 get_output_error_code)
29 from IPython.utils.capture import capture_output
29 from IPython.utils.capture import capture_output
30 from IPython.testing import decorators as dec
30 from IPython.testing import decorators as dec
31 from IPython.testing import tools as tt
31 from IPython.testing import tools as tt
32
32
33 python = os.path.basename(sys.executable)
33 python = os.path.basename(sys.executable)
34
34
35 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
36 # Tests
36 # Tests
37 #-----------------------------------------------------------------------------
37 #-----------------------------------------------------------------------------
38
38
39
39
40 @dec.skip_win32
40 @dec.skip_win32
41 def test_find_cmd_ls():
41 def test_find_cmd_ls():
42 """Make sure we can find the full path to ls."""
42 """Make sure we can find the full path to ls."""
43 path = find_cmd("ls")
43 path = find_cmd("ls")
44 assert path.endswith("ls")
44 assert path.endswith("ls")
45
45
46
46
47 @dec.skip_if_not_win32
47 @dec.skip_if_not_win32
48 def test_find_cmd_pythonw():
48 def test_find_cmd_pythonw():
49 """Try to find pythonw on Windows."""
49 """Try to find pythonw on Windows."""
50 path = find_cmd('pythonw')
50 path = find_cmd('pythonw')
51 assert path.lower().endswith('pythonw.exe'), path
51 assert path.lower().endswith('pythonw.exe'), path
52
52
53
53
54 def test_find_cmd_fail():
54 def test_find_cmd_fail():
55 """Make sure that FindCmdError is raised if we can't find the cmd."""
55 """Make sure that FindCmdError is raised if we can't find the cmd."""
56 pytest.raises(FindCmdError, find_cmd, "asdfasdf")
56 pytest.raises(FindCmdError, find_cmd, "asdfasdf")
57
57
58
58
59 @dec.skip_win32
59 @dec.skip_win32
60 @pytest.mark.parametrize(
60 @pytest.mark.parametrize(
61 'argstr, argv',
61 "argstr, argv",
62 [
62 [
63 ('hi', ['hi']),
63 ("hi", ["hi"]),
64 (u'hi', [u'hi']),
64 (u"hi", [u"hi"]),
65 ('hello there', ['hello', 'there']),
65 ("hello there", ["hello", "there"]),
66 # \u01ce == \N{LATIN SMALL LETTER A WITH CARON}
66 # \u01ce == \N{LATIN SMALL LETTER A WITH CARON}
67 # Do not use \N because the tests crash with syntax error in
67 # Do not use \N because the tests crash with syntax error in
68 # some cases, for example windows python2.6.
68 # some cases, for example windows python2.6.
69 (u'h\u01cello', [u'h\u01cello']),
69 (u"h\u01cello", [u"h\u01cello"]),
70 ('something "with quotes"', ['something', '"with quotes"']),
70 ('something "with quotes"', ["something", '"with quotes"']),
71 ]
71 ],
72 )
72 )
73 def test_arg_split(argstr, argv):
73 def test_arg_split(argstr, argv):
74 """Ensure that argument lines are correctly split like in a shell."""
74 """Ensure that argument lines are correctly split like in a shell."""
75 assert arg_split(argstr) == argv
75 assert arg_split(argstr) == argv
76
76
77
77
78 @dec.skip_if_not_win32
78 @dec.skip_if_not_win32
79 @pytest.mark.parametrize(
79 @pytest.mark.parametrize(
80 'argstr,argv',
80 "argstr,argv",
81 [
81 [
82 ('hi', ['hi']),
82 ("hi", ["hi"]),
83 (u'hi', [u'hi']),
83 (u"hi", [u"hi"]),
84 ('hello there', ['hello', 'there']),
84 ("hello there", ["hello", "there"]),
85 (u'h\u01cello', [u'h\u01cello']),
85 (u"h\u01cello", [u"h\u01cello"]),
86 ('something "with quotes"', ['something', 'with quotes']),
86 ('something "with quotes"', ["something", "with quotes"]),
87 ]
87 ],
88 )
88 )
89 def test_arg_split_win32(argstr, argv):
89 def test_arg_split_win32(argstr, argv):
90 """Ensure that argument lines are correctly split like in a shell."""
90 """Ensure that argument lines are correctly split like in a shell."""
91 assert arg_split(argstr) == argv
91 assert arg_split(argstr) == argv
92
92
93
93
94 class SubProcessTestCase(tt.TempFileMixin):
94 class SubProcessTestCase(tt.TempFileMixin):
95 def setUp(self):
95 def setUp(self):
96 """Make a valid python temp file."""
96 """Make a valid python temp file."""
97 lines = [ "import sys",
97 lines = [ "import sys",
98 "print('on stdout', end='', file=sys.stdout)",
98 "print('on stdout', end='', file=sys.stdout)",
99 "print('on stderr', end='', file=sys.stderr)",
99 "print('on stderr', end='', file=sys.stderr)",
100 "sys.stdout.flush()",
100 "sys.stdout.flush()",
101 "sys.stderr.flush()"]
101 "sys.stderr.flush()"]
102 self.mktmp('\n'.join(lines))
102 self.mktmp('\n'.join(lines))
103
103
104 def test_system(self):
104 def test_system(self):
105 status = system('%s "%s"' % (python, self.fname))
105 status = system('%s "%s"' % (python, self.fname))
106 self.assertEqual(status, 0)
106 self.assertEqual(status, 0)
107
107
108 def test_system_quotes(self):
108 def test_system_quotes(self):
109 status = system('%s -c "import sys"' % python)
109 status = system('%s -c "import sys"' % python)
110 self.assertEqual(status, 0)
110 self.assertEqual(status, 0)
111
111
112 def assert_interrupts(self, command):
112 def assert_interrupts(self, command):
113 """
113 """
114 Interrupt a subprocess after a second.
114 Interrupt a subprocess after a second.
115 """
115 """
116 if threading.main_thread() != threading.current_thread():
116 if threading.main_thread() != threading.current_thread():
117 raise pytest.skip("Can't run this test if not in main thread.")
117 raise pytest.skip("Can't run this test if not in main thread.")
118
118
119 # Some tests can overwrite SIGINT handler (by using pdb for example),
119 # Some tests can overwrite SIGINT handler (by using pdb for example),
120 # which then breaks this test, so just make sure it's operating
120 # which then breaks this test, so just make sure it's operating
121 # normally.
121 # normally.
122 signal.signal(signal.SIGINT, signal.default_int_handler)
122 signal.signal(signal.SIGINT, signal.default_int_handler)
123
123
124 def interrupt():
124 def interrupt():
125 # Wait for subprocess to start:
125 # Wait for subprocess to start:
126 time.sleep(0.5)
126 time.sleep(0.5)
127 interrupt_main()
127 interrupt_main()
128
128
129 threading.Thread(target=interrupt).start()
129 threading.Thread(target=interrupt).start()
130 start = time.time()
130 start = time.time()
131 try:
131 try:
132 result = command()
132 result = command()
133 except KeyboardInterrupt:
133 except KeyboardInterrupt:
134 # Success!
134 # Success!
135 pass
135 pass
136 end = time.time()
136 end = time.time()
137 self.assertTrue(
137 self.assertTrue(
138 end - start < 2, "Process didn't die quickly: %s" % (end - start)
138 end - start < 2, "Process didn't die quickly: %s" % (end - start)
139 )
139 )
140 return result
140 return result
141
141
142 def test_system_interrupt(self):
142 def test_system_interrupt(self):
143 """
143 """
144 When interrupted in the way ipykernel interrupts IPython, the
144 When interrupted in the way ipykernel interrupts IPython, the
145 subprocess is interrupted.
145 subprocess is interrupted.
146 """
146 """
147 def command():
147 def command():
148 return system('%s -c "import time; time.sleep(5)"' % python)
148 return system('%s -c "import time; time.sleep(5)"' % python)
149
149
150 status = self.assert_interrupts(command)
150 status = self.assert_interrupts(command)
151 self.assertNotEqual(
151 self.assertNotEqual(
152 status, 0, "The process wasn't interrupted. Status: %s" % (status,)
152 status, 0, "The process wasn't interrupted. Status: %s" % (status,)
153 )
153 )
154
154
155 def test_getoutput(self):
155 def test_getoutput(self):
156 out = getoutput('%s "%s"' % (python, self.fname))
156 out = getoutput('%s "%s"' % (python, self.fname))
157 # we can't rely on the order the line buffered streams are flushed
157 # we can't rely on the order the line buffered streams are flushed
158 try:
158 try:
159 self.assertEqual(out, 'on stderron stdout')
159 self.assertEqual(out, 'on stderron stdout')
160 except AssertionError:
160 except AssertionError:
161 self.assertEqual(out, 'on stdouton stderr')
161 self.assertEqual(out, 'on stdouton stderr')
162
162
163 def test_getoutput_quoted(self):
163 def test_getoutput_quoted(self):
164 out = getoutput('%s -c "print (1)"' % python)
164 out = getoutput('%s -c "print (1)"' % python)
165 self.assertEqual(out.strip(), '1')
165 self.assertEqual(out.strip(), '1')
166
166
167 #Invalid quoting on windows
167 #Invalid quoting on windows
168 @dec.skip_win32
168 @dec.skip_win32
169 def test_getoutput_quoted2(self):
169 def test_getoutput_quoted2(self):
170 out = getoutput("%s -c 'print (1)'" % python)
170 out = getoutput("%s -c 'print (1)'" % python)
171 self.assertEqual(out.strip(), '1')
171 self.assertEqual(out.strip(), '1')
172 out = getoutput("%s -c 'print (\"1\")'" % python)
172 out = getoutput("%s -c 'print (\"1\")'" % python)
173 self.assertEqual(out.strip(), '1')
173 self.assertEqual(out.strip(), '1')
174
174
175 def test_getoutput_error(self):
175 def test_getoutput_error(self):
176 out, err = getoutputerror('%s "%s"' % (python, self.fname))
176 out, err = getoutputerror('%s "%s"' % (python, self.fname))
177 self.assertEqual(out, 'on stdout')
177 self.assertEqual(out, 'on stdout')
178 self.assertEqual(err, 'on stderr')
178 self.assertEqual(err, 'on stderr')
179
179
180 def test_get_output_error_code(self):
180 def test_get_output_error_code(self):
181 quiet_exit = '%s -c "import sys; sys.exit(1)"' % python
181 quiet_exit = '%s -c "import sys; sys.exit(1)"' % python
182 out, err, code = get_output_error_code(quiet_exit)
182 out, err, code = get_output_error_code(quiet_exit)
183 self.assertEqual(out, '')
183 self.assertEqual(out, '')
184 self.assertEqual(err, '')
184 self.assertEqual(err, '')
185 self.assertEqual(code, 1)
185 self.assertEqual(code, 1)
186 out, err, code = get_output_error_code('%s "%s"' % (python, self.fname))
186 out, err, code = get_output_error_code('%s "%s"' % (python, self.fname))
187 self.assertEqual(out, 'on stdout')
187 self.assertEqual(out, 'on stdout')
188 self.assertEqual(err, 'on stderr')
188 self.assertEqual(err, 'on stderr')
189 self.assertEqual(code, 0)
189 self.assertEqual(code, 0)
190
190
191
191
General Comments 0
You need to be logged in to leave comments. Login now