##// END OF EJS Templates
Start migrating somethings to pytest's monkeypatch
Matthias Bussonnier -
Show More
@@ -1,509 +1,507
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 importlib import reload
13 from importlib import reload
14 from os.path import abspath, join
14 from os.path import abspath, join
15 from unittest.mock import patch
15 from unittest.mock import patch
16
16
17 import pytest
17 import pytest
18 from tempfile import TemporaryDirectory
18 from tempfile import TemporaryDirectory
19
19
20 import IPython
20 import IPython
21 from IPython import paths
21 from IPython import paths
22 from IPython.testing import decorators as dec
22 from IPython.testing import decorators as dec
23 from IPython.testing.decorators import (
23 from IPython.testing.decorators import (
24 onlyif_unicode_paths,
24 onlyif_unicode_paths,
25 skip_if_not_win32,
25 skip_if_not_win32,
26 skip_win32,
26 skip_win32,
27 )
27 )
28 from IPython.testing.tools import make_tempfile
28 from IPython.testing.tools import make_tempfile
29 from IPython.utils import path
29 from IPython.utils import path
30
30
31 # Platform-dependent imports
31 # Platform-dependent imports
32 try:
32 try:
33 import winreg as wreg
33 import winreg as wreg
34 except ImportError:
34 except ImportError:
35 #Fake _winreg module on non-windows platforms
35 #Fake _winreg module on non-windows platforms
36 import types
36 import types
37 wr_name = "winreg"
37 wr_name = "winreg"
38 sys.modules[wr_name] = types.ModuleType(wr_name)
38 sys.modules[wr_name] = types.ModuleType(wr_name)
39 try:
39 try:
40 import winreg as wreg
40 import winreg as wreg
41 except ImportError:
41 except ImportError:
42 import _winreg as wreg
42 import _winreg as wreg
43
43
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(monkeypatch):
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 monkeypatch.setattr(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(monkeypatch):
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 monkeypatch.setattr(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(
138 join(HOME_TEST_DIR, "Library.zip/IPython/__init__.py")
139 ).lower()
138
140
139 home_dir = path.get_home_dir(True)
141 home_dir = path.get_home_dir(True)
140 assert home_dir == unfrozen
142 assert home_dir == unfrozen
141
143
142
144
143 @skip_win32
145 @skip_win32
144 @with_environment
146 @with_environment
145 def test_get_home_dir_3():
147 def test_get_home_dir_3():
146 """get_home_dir() uses $HOME if set"""
148 """get_home_dir() uses $HOME if set"""
147 env["HOME"] = HOME_TEST_DIR
149 env["HOME"] = HOME_TEST_DIR
148 home_dir = path.get_home_dir(True)
150 home_dir = path.get_home_dir(True)
149 # get_home_dir expands symlinks
151 # get_home_dir expands symlinks
150 assert home_dir == os.path.realpath(env["HOME"])
152 assert home_dir == os.path.realpath(env["HOME"])
151
153
152
154
153 @with_environment
155 @with_environment
154 def test_get_home_dir_4():
156 def test_get_home_dir_4():
155 """get_home_dir() still works if $HOME is not set"""
157 """get_home_dir() still works if $HOME is not set"""
156
158
157 if 'HOME' in env: del env['HOME']
159 if 'HOME' in env: del env['HOME']
158 # this should still succeed, but we don't care what the answer is
160 # this should still succeed, but we don't care what the answer is
159 home = path.get_home_dir(False)
161 home = path.get_home_dir(False)
160
162
161 @skip_win32
163 @skip_win32
162 @with_environment
164 @with_environment
163 def test_get_home_dir_5():
165 def test_get_home_dir_5(monkeypatch):
164 """raise HomeDirError if $HOME is specified, but not a writable dir"""
166 """raise HomeDirError if $HOME is specified, but not a writable dir"""
165 env['HOME'] = abspath(HOME_TEST_DIR+'garbage')
167 env['HOME'] = abspath(HOME_TEST_DIR+'garbage')
166 # set os.name = posix, to prevent My Documents fallback on Windows
168 # set os.name = posix, to prevent My Documents fallback on Windows
167 os.name = 'posix'
169 monkeypatch.setattr(os, "name", "posix")
168 pytest.raises(path.HomeDirError, path.get_home_dir, True)
170 pytest.raises(path.HomeDirError, path.get_home_dir, True)
169
171
170 # Should we stub wreg fully so we can run the test on all platforms?
172 # Should we stub wreg fully so we can run the test on all platforms?
171 @skip_if_not_win32
173 @skip_if_not_win32
172 @with_environment
174 @with_environment
173 def test_get_home_dir_8():
175 def test_get_home_dir_8(monkeypatch):
174 """Using registry hack for 'My Documents', os=='nt'
176 """Using registry hack for 'My Documents', os=='nt'
175
177
176 HOMESHARE, HOMEDRIVE, HOMEPATH, USERPROFILE and others are missing.
178 HOMESHARE, HOMEDRIVE, HOMEPATH, USERPROFILE and others are missing.
177 """
179 """
178 os.name = 'nt'
180 monkeypatch.setattr(os, "name", "nt")
179 # Remove from stub environment all keys that may be set
181 # Remove from stub environment all keys that may be set
180 for key in ['HOME', 'HOMESHARE', 'HOMEDRIVE', 'HOMEPATH', 'USERPROFILE']:
182 for key in ['HOME', 'HOMESHARE', 'HOMEDRIVE', 'HOMEPATH', 'USERPROFILE']:
181 env.pop(key, None)
183 env.pop(key, None)
182
184
183 class key:
185 class key:
184 def __enter__(self):
186 def __enter__(self):
185 pass
187 pass
186 def Close(self):
188 def Close(self):
187 pass
189 pass
188 def __exit__(*args, **kwargs):
190 def __exit__(*args, **kwargs):
189 pass
191 pass
190
192
191 with patch.object(wreg, 'OpenKey', return_value=key()), \
193 with patch.object(wreg, 'OpenKey', return_value=key()), \
192 patch.object(wreg, 'QueryValueEx', return_value=[abspath(HOME_TEST_DIR)]):
194 patch.object(wreg, 'QueryValueEx', return_value=[abspath(HOME_TEST_DIR)]):
193 home_dir = path.get_home_dir()
195 home_dir = path.get_home_dir()
194 assert home_dir == abspath(HOME_TEST_DIR)
196 assert home_dir == abspath(HOME_TEST_DIR)
195
197
196 @with_environment
198 @with_environment
197 def test_get_xdg_dir_0():
199 def test_get_xdg_dir_0(monkeypatch):
198 """test_get_xdg_dir_0, check xdg_dir"""
200 """test_get_xdg_dir_0, check xdg_dir"""
199 reload(path)
201 monkeypatch.setattr(path, "_writable_dir", lambda path: True)
200 path._writable_dir = lambda path: True
202 monkeypatch.setattr(path, "get_home_dir", lambda: "somewhere")
201 path.get_home_dir = lambda : 'somewhere'
203 monkeypatch.setattr(os, "name", "posix")
202 os.name = "posix"
204 monkeypatch.setattr(sys, "platform", "linux2")
203 sys.platform = "linux2"
204 env.pop('IPYTHON_DIR', None)
205 env.pop('IPYTHON_DIR', None)
205 env.pop('IPYTHONDIR', None)
206 env.pop('IPYTHONDIR', None)
206 env.pop('XDG_CONFIG_HOME', None)
207 env.pop('XDG_CONFIG_HOME', None)
207
208
208 assert path.get_xdg_dir() == os.path.join("somewhere", ".config")
209 assert path.get_xdg_dir() == os.path.join("somewhere", ".config")
209
210
210
211
211 @with_environment
212 @with_environment
212 def test_get_xdg_dir_1():
213 def test_get_xdg_dir_1(monkeypatch):
213 """test_get_xdg_dir_1, check nonexistent xdg_dir"""
214 """test_get_xdg_dir_1, check nonexistent xdg_dir"""
214 reload(path)
215 monkeypatch.setattr(path, "get_home_dir", lambda: HOME_TEST_DIR)
215 path.get_home_dir = lambda : HOME_TEST_DIR
216 monkeypatch.setattr(os, "name", "posix")
216 os.name = "posix"
217 monkeypatch.setattr(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(monkeypatch):
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 monkeypatch.setattr(path, "get_home_dir", lambda: HOME_TEST_DIR)
227 path.get_home_dir = lambda : HOME_TEST_DIR
227 monkeypatch.setattr(os, "name", "posix")
228 os.name = "posix"
228 monkeypatch.setattr(sys, "platform", "linux2")
229 sys.platform = "linux2"
229 env.pop("IPYTHON_DIR", None)
230 env.pop('IPYTHON_DIR', None)
230 env.pop("IPYTHONDIR", None)
231 env.pop('IPYTHONDIR', None)
231 env.pop("XDG_CONFIG_HOME", None)
232 env.pop('XDG_CONFIG_HOME', None)
232 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):
233 if not os.path.exists(cfgdir):
235 os.makedirs(cfgdir)
234 os.makedirs(cfgdir)
236
235
237 assert path.get_xdg_dir() == cfgdir
236 assert path.get_xdg_dir() == cfgdir
238
237
239 @with_environment
238 @with_environment
240 def test_get_xdg_dir_3():
239 def test_get_xdg_dir_3(monkeypatch):
241 """test_get_xdg_dir_3, check xdg_dir not used on non-posix systems"""
240 """test_get_xdg_dir_3, check xdg_dir not used on non-posix systems"""
242 reload(path)
241 monkeypatch.setattr(path, "get_home_dir", lambda: HOME_TEST_DIR)
243 path.get_home_dir = lambda : HOME_TEST_DIR
242 monkeypatch.setattr(os, "name", "nt")
244 os.name = "nt"
243 monkeypatch.setattr(sys, "platform", "win32")
245 sys.platform = "win32"
244 env.pop("IPYTHON_DIR", None)
246 env.pop('IPYTHON_DIR', None)
245 env.pop("IPYTHONDIR", None)
247 env.pop('IPYTHONDIR', None)
246 env.pop("XDG_CONFIG_HOME", None)
248 env.pop('XDG_CONFIG_HOME', None)
247 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)
248 os.makedirs(cfgdir, exist_ok=True)
251
249
252 assert path.get_xdg_dir() is None
250 assert path.get_xdg_dir() is None
253
251
254 def test_filefind():
252 def test_filefind():
255 """Various tests for filefind"""
253 """Various tests for filefind"""
256 f = tempfile.NamedTemporaryFile()
254 f = tempfile.NamedTemporaryFile()
257 # print('fname:',f.name)
255 # print('fname:',f.name)
258 alt_dirs = paths.get_ipython_dir()
256 alt_dirs = paths.get_ipython_dir()
259 t = path.filefind(f.name, alt_dirs)
257 t = path.filefind(f.name, alt_dirs)
260 # print('found:',t)
258 # print('found:',t)
261
259
262
260
263 @dec.skip_if_not_win32
261 @dec.skip_if_not_win32
264 def test_get_long_path_name_win32():
262 def test_get_long_path_name_win32():
265 with TemporaryDirectory() as tmpdir:
263 with TemporaryDirectory() as tmpdir:
266
264
267 # Make a long path. Expands the path of tmpdir prematurely as it may already have a long
265 # 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
266 # 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')
267 long_path = os.path.join(path.get_long_path_name(tmpdir), 'this is my long path name')
270 os.makedirs(long_path)
268 os.makedirs(long_path)
271
269
272 # Test to see if the short path evaluates correctly.
270 # Test to see if the short path evaluates correctly.
273 short_path = os.path.join(tmpdir, 'THISIS~1')
271 short_path = os.path.join(tmpdir, 'THISIS~1')
274 evaluated_path = path.get_long_path_name(short_path)
272 evaluated_path = path.get_long_path_name(short_path)
275 assert evaluated_path.lower() == long_path.lower()
273 assert evaluated_path.lower() == long_path.lower()
276
274
277
275
278 @dec.skip_win32
276 @dec.skip_win32
279 def test_get_long_path_name():
277 def test_get_long_path_name():
280 p = path.get_long_path_name("/usr/local")
278 p = path.get_long_path_name("/usr/local")
281 assert p == "/usr/local"
279 assert p == "/usr/local"
282
280
283
281
284 class TestRaiseDeprecation(unittest.TestCase):
282 class TestRaiseDeprecation(unittest.TestCase):
285
283
286 @dec.skip_win32 # can't create not-user-writable dir on win
284 @dec.skip_win32 # can't create not-user-writable dir on win
287 @with_environment
285 @with_environment
288 def test_not_writable_ipdir(self):
286 def test_not_writable_ipdir(self):
289 tmpdir = tempfile.mkdtemp()
287 tmpdir = tempfile.mkdtemp()
290 os.name = "posix"
288 os.name = "posix"
291 env.pop('IPYTHON_DIR', None)
289 env.pop('IPYTHON_DIR', None)
292 env.pop('IPYTHONDIR', None)
290 env.pop('IPYTHONDIR', None)
293 env.pop('XDG_CONFIG_HOME', None)
291 env.pop('XDG_CONFIG_HOME', None)
294 env['HOME'] = tmpdir
292 env['HOME'] = tmpdir
295 ipdir = os.path.join(tmpdir, '.ipython')
293 ipdir = os.path.join(tmpdir, '.ipython')
296 os.mkdir(ipdir, 0o555)
294 os.mkdir(ipdir, 0o555)
297 try:
295 try:
298 open(os.path.join(ipdir, "_foo_"), "w", encoding="utf-8").close()
296 open(os.path.join(ipdir, "_foo_"), "w", encoding="utf-8").close()
299 except IOError:
297 except IOError:
300 pass
298 pass
301 else:
299 else:
302 # I can still write to an unwritable dir,
300 # I can still write to an unwritable dir,
303 # assume I'm root and skip the test
301 # assume I'm root and skip the test
304 pytest.skip("I can't create directories that I can't write to")
302 pytest.skip("I can't create directories that I can't write to")
305
303
306 with self.assertWarnsRegex(UserWarning, 'is not a writable location'):
304 with self.assertWarnsRegex(UserWarning, 'is not a writable location'):
307 ipdir = paths.get_ipython_dir()
305 ipdir = paths.get_ipython_dir()
308 env.pop('IPYTHON_DIR', None)
306 env.pop('IPYTHON_DIR', None)
309
307
310 @with_environment
308 @with_environment
311 def test_get_py_filename():
309 def test_get_py_filename():
312 os.chdir(TMP_TEST_DIR)
310 os.chdir(TMP_TEST_DIR)
313 with make_tempfile("foo.py"):
311 with make_tempfile("foo.py"):
314 assert path.get_py_filename("foo.py") == "foo.py"
312 assert path.get_py_filename("foo.py") == "foo.py"
315 assert path.get_py_filename("foo") == "foo.py"
313 assert path.get_py_filename("foo") == "foo.py"
316 with make_tempfile("foo"):
314 with make_tempfile("foo"):
317 assert path.get_py_filename("foo") == "foo"
315 assert path.get_py_filename("foo") == "foo"
318 pytest.raises(IOError, path.get_py_filename, "foo.py")
316 pytest.raises(IOError, path.get_py_filename, "foo.py")
319 pytest.raises(IOError, path.get_py_filename, "foo")
317 pytest.raises(IOError, path.get_py_filename, "foo")
320 pytest.raises(IOError, path.get_py_filename, "foo.py")
318 pytest.raises(IOError, path.get_py_filename, "foo.py")
321 true_fn = "foo with spaces.py"
319 true_fn = "foo with spaces.py"
322 with make_tempfile(true_fn):
320 with make_tempfile(true_fn):
323 assert path.get_py_filename("foo with spaces") == true_fn
321 assert path.get_py_filename("foo with spaces") == true_fn
324 assert path.get_py_filename("foo with spaces.py") == true_fn
322 assert path.get_py_filename("foo with spaces.py") == true_fn
325 pytest.raises(IOError, path.get_py_filename, '"foo with spaces.py"')
323 pytest.raises(IOError, path.get_py_filename, '"foo with spaces.py"')
326 pytest.raises(IOError, path.get_py_filename, "'foo with spaces.py'")
324 pytest.raises(IOError, path.get_py_filename, "'foo with spaces.py'")
327
325
328 @onlyif_unicode_paths
326 @onlyif_unicode_paths
329 def test_unicode_in_filename():
327 def test_unicode_in_filename():
330 """When a file doesn't exist, the exception raised should be safe to call
328 """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.
329 str() on - i.e. in Python 2 it must only have ASCII characters.
332
330
333 https://github.com/ipython/ipython/issues/875
331 https://github.com/ipython/ipython/issues/875
334 """
332 """
335 try:
333 try:
336 # these calls should not throw unicode encode exceptions
334 # these calls should not throw unicode encode exceptions
337 path.get_py_filename('fooéè.py')
335 path.get_py_filename('fooéè.py')
338 except IOError as ex:
336 except IOError as ex:
339 str(ex)
337 str(ex)
340
338
341
339
342 class TestShellGlob(unittest.TestCase):
340 class TestShellGlob(unittest.TestCase):
343
341
344 @classmethod
342 @classmethod
345 def setUpClass(cls):
343 def setUpClass(cls):
346 cls.filenames_start_with_a = ['a0', 'a1', 'a2']
344 cls.filenames_start_with_a = ['a0', 'a1', 'a2']
347 cls.filenames_end_with_b = ['0b', '1b', '2b']
345 cls.filenames_end_with_b = ['0b', '1b', '2b']
348 cls.filenames = cls.filenames_start_with_a + cls.filenames_end_with_b
346 cls.filenames = cls.filenames_start_with_a + cls.filenames_end_with_b
349 cls.tempdir = TemporaryDirectory()
347 cls.tempdir = TemporaryDirectory()
350 td = cls.tempdir.name
348 td = cls.tempdir.name
351
349
352 with cls.in_tempdir():
350 with cls.in_tempdir():
353 # Create empty files
351 # Create empty files
354 for fname in cls.filenames:
352 for fname in cls.filenames:
355 open(os.path.join(td, fname), "w", encoding="utf-8").close()
353 open(os.path.join(td, fname), "w", encoding="utf-8").close()
356
354
357 @classmethod
355 @classmethod
358 def tearDownClass(cls):
356 def tearDownClass(cls):
359 cls.tempdir.cleanup()
357 cls.tempdir.cleanup()
360
358
361 @classmethod
359 @classmethod
362 @contextmanager
360 @contextmanager
363 def in_tempdir(cls):
361 def in_tempdir(cls):
364 save = os.getcwd()
362 save = os.getcwd()
365 try:
363 try:
366 os.chdir(cls.tempdir.name)
364 os.chdir(cls.tempdir.name)
367 yield
365 yield
368 finally:
366 finally:
369 os.chdir(save)
367 os.chdir(save)
370
368
371 def check_match(self, patterns, matches):
369 def check_match(self, patterns, matches):
372 with self.in_tempdir():
370 with self.in_tempdir():
373 # glob returns unordered list. that's why sorted is required.
371 # glob returns unordered list. that's why sorted is required.
374 assert sorted(path.shellglob(patterns)) == sorted(matches)
372 assert sorted(path.shellglob(patterns)) == sorted(matches)
375
373
376 def common_cases(self):
374 def common_cases(self):
377 return [
375 return [
378 (['*'], self.filenames),
376 (['*'], self.filenames),
379 (['a*'], self.filenames_start_with_a),
377 (['a*'], self.filenames_start_with_a),
380 (['*c'], ['*c']),
378 (['*c'], ['*c']),
381 (['*', 'a*', '*b', '*c'], self.filenames
379 (['*', 'a*', '*b', '*c'], self.filenames
382 + self.filenames_start_with_a
380 + self.filenames_start_with_a
383 + self.filenames_end_with_b
381 + self.filenames_end_with_b
384 + ['*c']),
382 + ['*c']),
385 (['a[012]'], self.filenames_start_with_a),
383 (['a[012]'], self.filenames_start_with_a),
386 ]
384 ]
387
385
388 @skip_win32
386 @skip_win32
389 def test_match_posix(self):
387 def test_match_posix(self):
390 for (patterns, matches) in self.common_cases() + [
388 for (patterns, matches) in self.common_cases() + [
391 ([r'\*'], ['*']),
389 ([r'\*'], ['*']),
392 ([r'a\*', 'a*'], ['a*'] + self.filenames_start_with_a),
390 ([r'a\*', 'a*'], ['a*'] + self.filenames_start_with_a),
393 ([r'a\[012]'], ['a[012]']),
391 ([r'a\[012]'], ['a[012]']),
394 ]:
392 ]:
395 self.check_match(patterns, matches)
393 self.check_match(patterns, matches)
396
394
397 @skip_if_not_win32
395 @skip_if_not_win32
398 def test_match_windows(self):
396 def test_match_windows(self):
399 for (patterns, matches) in self.common_cases() + [
397 for (patterns, matches) in self.common_cases() + [
400 # In windows, backslash is interpreted as path
398 # In windows, backslash is interpreted as path
401 # separator. Therefore, you can't escape glob
399 # separator. Therefore, you can't escape glob
402 # using it.
400 # using it.
403 ([r'a\*', 'a*'], [r'a\*'] + self.filenames_start_with_a),
401 ([r'a\*', 'a*'], [r'a\*'] + self.filenames_start_with_a),
404 ([r'a\[012]'], [r'a\[012]']),
402 ([r'a\[012]'], [r'a\[012]']),
405 ]:
403 ]:
406 self.check_match(patterns, matches)
404 self.check_match(patterns, matches)
407
405
408
406
409 @pytest.mark.parametrize(
407 @pytest.mark.parametrize(
410 "globstr, unescaped_globstr",
408 "globstr, unescaped_globstr",
411 [
409 [
412 (r"\*\[\!\]\?", "*[!]?"),
410 (r"\*\[\!\]\?", "*[!]?"),
413 (r"\\*", r"\*"),
411 (r"\\*", r"\*"),
414 (r"\\\*", r"\*"),
412 (r"\\\*", r"\*"),
415 (r"\\a", r"\a"),
413 (r"\\a", r"\a"),
416 (r"\a", r"\a"),
414 (r"\a", r"\a"),
417 ],
415 ],
418 )
416 )
419 def test_unescape_glob(globstr, unescaped_globstr):
417 def test_unescape_glob(globstr, unescaped_globstr):
420 assert path.unescape_glob(globstr) == unescaped_globstr
418 assert path.unescape_glob(globstr) == unescaped_globstr
421
419
422
420
423 @onlyif_unicode_paths
421 @onlyif_unicode_paths
424 def test_ensure_dir_exists():
422 def test_ensure_dir_exists():
425 with TemporaryDirectory() as td:
423 with TemporaryDirectory() as td:
426 d = os.path.join(td, 'βˆ‚ir')
424 d = os.path.join(td, 'βˆ‚ir')
427 path.ensure_dir_exists(d) # create it
425 path.ensure_dir_exists(d) # create it
428 assert os.path.isdir(d)
426 assert os.path.isdir(d)
429 path.ensure_dir_exists(d) # no-op
427 path.ensure_dir_exists(d) # no-op
430 f = os.path.join(td, "Ζ’ile")
428 f = os.path.join(td, "Ζ’ile")
431 open(f, "w", encoding="utf-8").close() # touch
429 open(f, "w", encoding="utf-8").close() # touch
432 with pytest.raises(IOError):
430 with pytest.raises(IOError):
433 path.ensure_dir_exists(f)
431 path.ensure_dir_exists(f)
434
432
435 class TestLinkOrCopy(unittest.TestCase):
433 class TestLinkOrCopy(unittest.TestCase):
436 def setUp(self):
434 def setUp(self):
437 self.tempdir = TemporaryDirectory()
435 self.tempdir = TemporaryDirectory()
438 self.src = self.dst("src")
436 self.src = self.dst("src")
439 with open(self.src, "w", encoding="utf-8") as f:
437 with open(self.src, "w", encoding="utf-8") as f:
440 f.write("Hello, world!")
438 f.write("Hello, world!")
441
439
442 def tearDown(self):
440 def tearDown(self):
443 self.tempdir.cleanup()
441 self.tempdir.cleanup()
444
442
445 def dst(self, *args):
443 def dst(self, *args):
446 return os.path.join(self.tempdir.name, *args)
444 return os.path.join(self.tempdir.name, *args)
447
445
448 def assert_inode_not_equal(self, a, b):
446 def assert_inode_not_equal(self, a, b):
449 assert (
447 assert (
450 os.stat(a).st_ino != os.stat(b).st_ino
448 os.stat(a).st_ino != os.stat(b).st_ino
451 ), "%r and %r do reference the same indoes" % (a, b)
449 ), "%r and %r do reference the same indoes" % (a, b)
452
450
453 def assert_inode_equal(self, a, b):
451 def assert_inode_equal(self, a, b):
454 assert (
452 assert (
455 os.stat(a).st_ino == os.stat(b).st_ino
453 os.stat(a).st_ino == os.stat(b).st_ino
456 ), "%r and %r do not reference the same indoes" % (a, b)
454 ), "%r and %r do not reference the same indoes" % (a, b)
457
455
458 def assert_content_equal(self, a, b):
456 def assert_content_equal(self, a, b):
459 with open(a, "rb") as a_f:
457 with open(a, "rb") as a_f:
460 with open(b, "rb") as b_f:
458 with open(b, "rb") as b_f:
461 assert a_f.read() == b_f.read()
459 assert a_f.read() == b_f.read()
462
460
463 @skip_win32
461 @skip_win32
464 def test_link_successful(self):
462 def test_link_successful(self):
465 dst = self.dst("target")
463 dst = self.dst("target")
466 path.link_or_copy(self.src, dst)
464 path.link_or_copy(self.src, dst)
467 self.assert_inode_equal(self.src, dst)
465 self.assert_inode_equal(self.src, dst)
468
466
469 @skip_win32
467 @skip_win32
470 def test_link_into_dir(self):
468 def test_link_into_dir(self):
471 dst = self.dst("some_dir")
469 dst = self.dst("some_dir")
472 os.mkdir(dst)
470 os.mkdir(dst)
473 path.link_or_copy(self.src, dst)
471 path.link_or_copy(self.src, dst)
474 expected_dst = self.dst("some_dir", os.path.basename(self.src))
472 expected_dst = self.dst("some_dir", os.path.basename(self.src))
475 self.assert_inode_equal(self.src, expected_dst)
473 self.assert_inode_equal(self.src, expected_dst)
476
474
477 @skip_win32
475 @skip_win32
478 def test_target_exists(self):
476 def test_target_exists(self):
479 dst = self.dst("target")
477 dst = self.dst("target")
480 open(dst, "w", encoding="utf-8").close()
478 open(dst, "w", encoding="utf-8").close()
481 path.link_or_copy(self.src, dst)
479 path.link_or_copy(self.src, dst)
482 self.assert_inode_equal(self.src, dst)
480 self.assert_inode_equal(self.src, dst)
483
481
484 @skip_win32
482 @skip_win32
485 def test_no_link(self):
483 def test_no_link(self):
486 real_link = os.link
484 real_link = os.link
487 try:
485 try:
488 del os.link
486 del os.link
489 dst = self.dst("target")
487 dst = self.dst("target")
490 path.link_or_copy(self.src, dst)
488 path.link_or_copy(self.src, dst)
491 self.assert_content_equal(self.src, dst)
489 self.assert_content_equal(self.src, dst)
492 self.assert_inode_not_equal(self.src, dst)
490 self.assert_inode_not_equal(self.src, dst)
493 finally:
491 finally:
494 os.link = real_link
492 os.link = real_link
495
493
496 @skip_if_not_win32
494 @skip_if_not_win32
497 def test_windows(self):
495 def test_windows(self):
498 dst = self.dst("target")
496 dst = self.dst("target")
499 path.link_or_copy(self.src, dst)
497 path.link_or_copy(self.src, dst)
500 self.assert_content_equal(self.src, dst)
498 self.assert_content_equal(self.src, dst)
501
499
502 def test_link_twice(self):
500 def test_link_twice(self):
503 # Linking the same file twice shouldn't leave duplicates around.
501 # Linking the same file twice shouldn't leave duplicates around.
504 # See https://github.com/ipython/ipython/issues/6450
502 # See https://github.com/ipython/ipython/issues/6450
505 dst = self.dst('target')
503 dst = self.dst('target')
506 path.link_or_copy(self.src, dst)
504 path.link_or_copy(self.src, dst)
507 path.link_or_copy(self.src, dst)
505 path.link_or_copy(self.src, dst)
508 self.assert_inode_equal(self.src, dst)
506 self.assert_inode_equal(self.src, dst)
509 assert sorted(os.listdir(self.tempdir.name)) == ["src", "target"]
507 assert sorted(os.listdir(self.tempdir.name)) == ["src", "target"]
General Comments 0
You need to be logged in to leave comments. Login now