blob: c5545ba3b32fb16feeaea5e5e9a87dfa9f580b76 [file] [log] [blame]
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001# Copyright (C) 2003 Python Software Foundation
2
3import unittest
Berker Peksag884afd92014-12-10 02:50:32 +02004import unittest.mock
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00005import shutil
6import tempfile
Johannes Gijsbers8e6f2de2004-11-23 09:27:27 +00007import sys
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +00008import stat
Brett Cannon1c3fa182004-06-19 21:11:35 +00009import os
10import os.path
Antoine Pitrouc041ab62012-01-02 19:18:02 +010011import errno
Nick Coghlan8ed3cf32011-03-16 14:05:35 -040012import functools
Antoine Pitroubcf2b592012-02-08 23:28:36 +010013import subprocess
Serhiy Storchaka41ad77c2014-08-07 19:38:37 +030014from contextlib import ExitStack
Benjamin Petersonee8712c2008-05-20 21:35:26 +000015from test import support
16from test.support import TESTFN
Tarek Ziadé396fad72010-02-23 05:30:31 +000017from os.path import splitdrive
18from distutils.spawn import find_executable, spawn
19from shutil import (_make_tarball, _make_zipfile, make_archive,
20 register_archive_format, unregister_archive_format,
Tarek Ziadé6ac91722010-04-28 17:51:36 +000021 get_archive_formats, Error, unpack_archive,
22 register_unpack_format, RegistryError,
Hynek Schlawack48653762012-10-07 12:49:58 +020023 unregister_unpack_format, get_unpack_formats,
24 SameFileError)
Tarek Ziadé396fad72010-02-23 05:30:31 +000025import tarfile
26import warnings
27
28from test import support
Ezio Melotti975077a2011-05-19 22:03:22 +030029from test.support import TESTFN, check_warnings, captured_stdout, requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +000030
Tarek Ziadéffa155a2010-04-29 13:34:35 +000031try:
32 import bz2
33 BZ2_SUPPORTED = True
34except ImportError:
35 BZ2_SUPPORTED = False
36
Serhiy Storchaka11213772014-08-06 18:50:19 +030037try:
38 import lzma
39 LZMA_SUPPORTED = True
40except ImportError:
41 LZMA_SUPPORTED = False
42
Antoine Pitrou7fff0962009-05-01 21:09:44 +000043TESTFN2 = TESTFN + "2"
Barry Warsaw7fc2cca2003-01-24 17:34:13 +000044
Tarek Ziadé396fad72010-02-23 05:30:31 +000045try:
46 import grp
47 import pwd
48 UID_GID_SUPPORT = True
49except ImportError:
50 UID_GID_SUPPORT = False
51
52try:
Tarek Ziadé396fad72010-02-23 05:30:31 +000053 import zipfile
54 ZIP_SUPPORT = True
55except ImportError:
56 ZIP_SUPPORT = find_executable('zip')
57
Nick Coghlan8ed3cf32011-03-16 14:05:35 -040058def _fake_rename(*args, **kwargs):
59 # Pretend the destination path is on a different filesystem.
Antoine Pitrouc041ab62012-01-02 19:18:02 +010060 raise OSError(getattr(errno, 'EXDEV', 18), "Invalid cross-device link")
Nick Coghlan8ed3cf32011-03-16 14:05:35 -040061
62def mock_rename(func):
63 @functools.wraps(func)
64 def wrap(*args, **kwargs):
65 try:
66 builtin_rename = os.rename
67 os.rename = _fake_rename
68 return func(*args, **kwargs)
69 finally:
70 os.rename = builtin_rename
71 return wrap
72
Éric Araujoa7e33a12011-08-12 19:51:35 +020073def write_file(path, content, binary=False):
74 """Write *content* to a file located at *path*.
75
76 If *path* is a tuple instead of a string, os.path.join will be used to
77 make a path. If *binary* is true, the file will be opened in binary
78 mode.
79 """
80 if isinstance(path, tuple):
81 path = os.path.join(*path)
82 with open(path, 'wb' if binary else 'w') as fp:
83 fp.write(content)
84
85def read_file(path, binary=False):
86 """Return contents from a file located at *path*.
87
88 If *path* is a tuple instead of a string, os.path.join will be used to
89 make a path. If *binary* is true, the file will be opened in binary
90 mode.
91 """
92 if isinstance(path, tuple):
93 path = os.path.join(*path)
94 with open(path, 'rb' if binary else 'r') as fp:
95 return fp.read()
96
97
Barry Warsaw7fc2cca2003-01-24 17:34:13 +000098class TestShutil(unittest.TestCase):
Tarek Ziadé396fad72010-02-23 05:30:31 +000099
100 def setUp(self):
101 super(TestShutil, self).setUp()
102 self.tempdirs = []
103
104 def tearDown(self):
105 super(TestShutil, self).tearDown()
106 while self.tempdirs:
107 d = self.tempdirs.pop()
108 shutil.rmtree(d, os.name in ('nt', 'cygwin'))
109
Tarek Ziadé396fad72010-02-23 05:30:31 +0000110
111 def mkdtemp(self):
112 """Create a temporary directory that will be cleaned up.
113
114 Returns the path of the directory.
115 """
116 d = tempfile.mkdtemp()
117 self.tempdirs.append(d)
118 return d
Tarek Ziadé5340db32010-04-19 22:30:51 +0000119
Hynek Schlawack3b527782012-06-25 13:27:31 +0200120 def test_rmtree_works_on_bytes(self):
121 tmp = self.mkdtemp()
122 victim = os.path.join(tmp, 'killme')
123 os.mkdir(victim)
124 write_file(os.path.join(victim, 'somefile'), 'foo')
125 victim = os.fsencode(victim)
126 self.assertIsInstance(victim, bytes)
Serhiy Storchaka41ad77c2014-08-07 19:38:37 +0300127 win = (os.name == 'nt')
128 with self.assertWarns(DeprecationWarning) if win else ExitStack():
129 shutil.rmtree(victim)
Hynek Schlawack3b527782012-06-25 13:27:31 +0200130
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200131 @support.skip_unless_symlink
132 def test_rmtree_fails_on_symlink(self):
133 tmp = self.mkdtemp()
134 dir_ = os.path.join(tmp, 'dir')
135 os.mkdir(dir_)
136 link = os.path.join(tmp, 'link')
137 os.symlink(dir_, link)
138 self.assertRaises(OSError, shutil.rmtree, link)
139 self.assertTrue(os.path.exists(dir_))
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100140 self.assertTrue(os.path.lexists(link))
141 errors = []
142 def onerror(*args):
143 errors.append(args)
144 shutil.rmtree(link, onerror=onerror)
145 self.assertEqual(len(errors), 1)
146 self.assertIs(errors[0][0], os.path.islink)
147 self.assertEqual(errors[0][1], link)
148 self.assertIsInstance(errors[0][2][1], OSError)
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200149
150 @support.skip_unless_symlink
151 def test_rmtree_works_on_symlinks(self):
152 tmp = self.mkdtemp()
153 dir1 = os.path.join(tmp, 'dir1')
154 dir2 = os.path.join(dir1, 'dir2')
155 dir3 = os.path.join(tmp, 'dir3')
156 for d in dir1, dir2, dir3:
157 os.mkdir(d)
158 file1 = os.path.join(tmp, 'file1')
159 write_file(file1, 'foo')
160 link1 = os.path.join(dir1, 'link1')
161 os.symlink(dir2, link1)
162 link2 = os.path.join(dir1, 'link2')
163 os.symlink(dir3, link2)
164 link3 = os.path.join(dir1, 'link3')
165 os.symlink(file1, link3)
166 # make sure symlinks are removed but not followed
167 shutil.rmtree(dir1)
168 self.assertFalse(os.path.exists(dir1))
169 self.assertTrue(os.path.exists(dir3))
170 self.assertTrue(os.path.exists(file1))
171
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000172 def test_rmtree_errors(self):
173 # filename is guaranteed not to exist
174 filename = tempfile.mktemp()
Hynek Schlawackb5501102012-12-10 09:11:25 +0100175 self.assertRaises(FileNotFoundError, shutil.rmtree, filename)
176 # test that ignore_errors option is honored
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100177 shutil.rmtree(filename, ignore_errors=True)
178
179 # existing file
180 tmpdir = self.mkdtemp()
Hynek Schlawackb5501102012-12-10 09:11:25 +0100181 write_file((tmpdir, "tstfile"), "")
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100182 filename = os.path.join(tmpdir, "tstfile")
Hynek Schlawackb5501102012-12-10 09:11:25 +0100183 with self.assertRaises(NotADirectoryError) as cm:
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100184 shutil.rmtree(filename)
Hynek Schlawack87f9b462012-12-10 16:29:57 +0100185 # The reason for this rather odd construct is that Windows sprinkles
186 # a \*.* at the end of file names. But only sometimes on some buildbots
187 possible_args = [filename, os.path.join(filename, '*.*')]
188 self.assertIn(cm.exception.filename, possible_args)
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100189 self.assertTrue(os.path.exists(filename))
Hynek Schlawackb5501102012-12-10 09:11:25 +0100190 # test that ignore_errors option is honored
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100191 shutil.rmtree(filename, ignore_errors=True)
192 self.assertTrue(os.path.exists(filename))
193 errors = []
194 def onerror(*args):
195 errors.append(args)
196 shutil.rmtree(filename, onerror=onerror)
197 self.assertEqual(len(errors), 2)
198 self.assertIs(errors[0][0], os.listdir)
199 self.assertEqual(errors[0][1], filename)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100200 self.assertIsInstance(errors[0][2][1], NotADirectoryError)
Hynek Schlawack87f9b462012-12-10 16:29:57 +0100201 self.assertIn(errors[0][2][1].filename, possible_args)
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100202 self.assertIs(errors[1][0], os.rmdir)
203 self.assertEqual(errors[1][1], filename)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100204 self.assertIsInstance(errors[1][2][1], NotADirectoryError)
Hynek Schlawack87f9b462012-12-10 16:29:57 +0100205 self.assertIn(errors[1][2][1].filename, possible_args)
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000206
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000207
Serhiy Storchaka43767632013-11-03 21:31:38 +0200208 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod()')
209 @unittest.skipIf(sys.platform[:6] == 'cygwin',
210 "This test can't be run on Cygwin (issue #1071513).")
211 @unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0,
212 "This test can't be run reliably as root (issue #1076467).")
213 def test_on_error(self):
214 self.errorState = 0
215 os.mkdir(TESTFN)
216 self.addCleanup(shutil.rmtree, TESTFN)
Antoine Pitrou2f8a75c2012-06-23 21:28:15 +0200217
Serhiy Storchaka43767632013-11-03 21:31:38 +0200218 self.child_file_path = os.path.join(TESTFN, 'a')
219 self.child_dir_path = os.path.join(TESTFN, 'b')
220 support.create_empty_file(self.child_file_path)
221 os.mkdir(self.child_dir_path)
222 old_dir_mode = os.stat(TESTFN).st_mode
223 old_child_file_mode = os.stat(self.child_file_path).st_mode
224 old_child_dir_mode = os.stat(self.child_dir_path).st_mode
225 # Make unwritable.
226 new_mode = stat.S_IREAD|stat.S_IEXEC
227 os.chmod(self.child_file_path, new_mode)
228 os.chmod(self.child_dir_path, new_mode)
229 os.chmod(TESTFN, new_mode)
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000230
Serhiy Storchaka43767632013-11-03 21:31:38 +0200231 self.addCleanup(os.chmod, TESTFN, old_dir_mode)
232 self.addCleanup(os.chmod, self.child_file_path, old_child_file_mode)
233 self.addCleanup(os.chmod, self.child_dir_path, old_child_dir_mode)
Antoine Pitrou2f8a75c2012-06-23 21:28:15 +0200234
Serhiy Storchaka43767632013-11-03 21:31:38 +0200235 shutil.rmtree(TESTFN, onerror=self.check_args_to_onerror)
236 # Test whether onerror has actually been called.
237 self.assertEqual(self.errorState, 3,
238 "Expected call to onerror function did not happen.")
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000239
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000240 def check_args_to_onerror(self, func, arg, exc):
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000241 # test_rmtree_errors deliberately runs rmtree
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200242 # on a directory that is chmod 500, which will fail.
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000243 # This function is run when shutil.rmtree fails.
244 # 99.9% of the time it initially fails to remove
245 # a file in the directory, so the first time through
246 # func is os.remove.
247 # However, some Linux machines running ZFS on
248 # FUSE experienced a failure earlier in the process
249 # at os.listdir. The first failure may legally
250 # be either.
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200251 if self.errorState < 2:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200252 if func is os.unlink:
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200253 self.assertEqual(arg, self.child_file_path)
254 elif func is os.rmdir:
255 self.assertEqual(arg, self.child_dir_path)
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000256 else:
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200257 self.assertIs(func, os.listdir)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200258 self.assertIn(arg, [TESTFN, self.child_dir_path])
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000259 self.assertTrue(issubclass(exc[0], OSError))
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200260 self.errorState += 1
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000261 else:
262 self.assertEqual(func, os.rmdir)
263 self.assertEqual(arg, TESTFN)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000264 self.assertTrue(issubclass(exc[0], OSError))
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200265 self.errorState = 3
266
267 def test_rmtree_does_not_choke_on_failing_lstat(self):
268 try:
269 orig_lstat = os.lstat
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200270 def raiser(fn, *args, **kwargs):
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200271 if fn != TESTFN:
272 raise OSError()
273 else:
274 return orig_lstat(fn)
275 os.lstat = raiser
276
277 os.mkdir(TESTFN)
278 write_file((TESTFN, 'foo'), 'foo')
279 shutil.rmtree(TESTFN)
280 finally:
281 os.lstat = orig_lstat
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000282
Antoine Pitrou78091e62011-12-29 18:54:15 +0100283 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
284 @support.skip_unless_symlink
285 def test_copymode_follow_symlinks(self):
286 tmp_dir = self.mkdtemp()
287 src = os.path.join(tmp_dir, 'foo')
288 dst = os.path.join(tmp_dir, 'bar')
289 src_link = os.path.join(tmp_dir, 'baz')
290 dst_link = os.path.join(tmp_dir, 'quux')
291 write_file(src, 'foo')
292 write_file(dst, 'foo')
293 os.symlink(src, src_link)
294 os.symlink(dst, dst_link)
295 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
296 # file to file
297 os.chmod(dst, stat.S_IRWXO)
298 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
299 shutil.copymode(src, dst)
300 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
Antoine Pitrou3f48ac92014-01-01 02:50:45 +0100301 # On Windows, os.chmod does not follow symlinks (issue #15411)
302 if os.name != 'nt':
303 # follow src link
304 os.chmod(dst, stat.S_IRWXO)
305 shutil.copymode(src_link, dst)
306 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
307 # follow dst link
308 os.chmod(dst, stat.S_IRWXO)
309 shutil.copymode(src, dst_link)
310 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
311 # follow both links
312 os.chmod(dst, stat.S_IRWXO)
313 shutil.copymode(src_link, dst_link)
314 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100315
316 @unittest.skipUnless(hasattr(os, 'lchmod'), 'requires os.lchmod')
317 @support.skip_unless_symlink
318 def test_copymode_symlink_to_symlink(self):
319 tmp_dir = self.mkdtemp()
320 src = os.path.join(tmp_dir, 'foo')
321 dst = os.path.join(tmp_dir, 'bar')
322 src_link = os.path.join(tmp_dir, 'baz')
323 dst_link = os.path.join(tmp_dir, 'quux')
324 write_file(src, 'foo')
325 write_file(dst, 'foo')
326 os.symlink(src, src_link)
327 os.symlink(dst, dst_link)
328 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
329 os.chmod(dst, stat.S_IRWXU)
330 os.lchmod(src_link, stat.S_IRWXO|stat.S_IRWXG)
331 # link to link
332 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700333 shutil.copymode(src_link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100334 self.assertEqual(os.lstat(src_link).st_mode,
335 os.lstat(dst_link).st_mode)
336 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
337 # src link - use chmod
338 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700339 shutil.copymode(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100340 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
341 # dst link - use chmod
342 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700343 shutil.copymode(src, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100344 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
345
346 @unittest.skipIf(hasattr(os, 'lchmod'), 'requires os.lchmod to be missing')
347 @support.skip_unless_symlink
348 def test_copymode_symlink_to_symlink_wo_lchmod(self):
349 tmp_dir = self.mkdtemp()
350 src = os.path.join(tmp_dir, 'foo')
351 dst = os.path.join(tmp_dir, 'bar')
352 src_link = os.path.join(tmp_dir, 'baz')
353 dst_link = os.path.join(tmp_dir, 'quux')
354 write_file(src, 'foo')
355 write_file(dst, 'foo')
356 os.symlink(src, src_link)
357 os.symlink(dst, dst_link)
Larry Hastingsb4038062012-07-15 10:57:38 -0700358 shutil.copymode(src_link, dst_link, follow_symlinks=False) # silent fail
Antoine Pitrou78091e62011-12-29 18:54:15 +0100359
360 @support.skip_unless_symlink
361 def test_copystat_symlinks(self):
362 tmp_dir = self.mkdtemp()
363 src = os.path.join(tmp_dir, 'foo')
364 dst = os.path.join(tmp_dir, 'bar')
365 src_link = os.path.join(tmp_dir, 'baz')
366 dst_link = os.path.join(tmp_dir, 'qux')
367 write_file(src, 'foo')
368 src_stat = os.stat(src)
369 os.utime(src, (src_stat.st_atime,
370 src_stat.st_mtime - 42.0)) # ensure different mtimes
371 write_file(dst, 'bar')
372 self.assertNotEqual(os.stat(src).st_mtime, os.stat(dst).st_mtime)
373 os.symlink(src, src_link)
374 os.symlink(dst, dst_link)
375 if hasattr(os, 'lchmod'):
376 os.lchmod(src_link, stat.S_IRWXO)
377 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
378 os.lchflags(src_link, stat.UF_NODUMP)
379 src_link_stat = os.lstat(src_link)
380 # follow
381 if hasattr(os, 'lchmod'):
Larry Hastingsb4038062012-07-15 10:57:38 -0700382 shutil.copystat(src_link, dst_link, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100383 self.assertNotEqual(src_link_stat.st_mode, os.stat(dst).st_mode)
384 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700385 shutil.copystat(src_link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100386 dst_link_stat = os.lstat(dst_link)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700387 if os.utime in os.supports_follow_symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100388 for attr in 'st_atime', 'st_mtime':
389 # The modification times may be truncated in the new file.
390 self.assertLessEqual(getattr(src_link_stat, attr),
391 getattr(dst_link_stat, attr) + 1)
392 if hasattr(os, 'lchmod'):
393 self.assertEqual(src_link_stat.st_mode, dst_link_stat.st_mode)
394 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
395 self.assertEqual(src_link_stat.st_flags, dst_link_stat.st_flags)
396 # tell to follow but dst is not a link
Larry Hastingsb4038062012-07-15 10:57:38 -0700397 shutil.copystat(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100398 self.assertTrue(abs(os.stat(src).st_mtime - os.stat(dst).st_mtime) <
399 00000.1)
400
Ned Deilybaf75712012-05-10 17:05:19 -0700401 @unittest.skipUnless(hasattr(os, 'chflags') and
402 hasattr(errno, 'EOPNOTSUPP') and
403 hasattr(errno, 'ENOTSUP'),
404 "requires os.chflags, EOPNOTSUPP & ENOTSUP")
405 def test_copystat_handles_harmless_chflags_errors(self):
406 tmpdir = self.mkdtemp()
407 file1 = os.path.join(tmpdir, 'file1')
408 file2 = os.path.join(tmpdir, 'file2')
409 write_file(file1, 'xxx')
410 write_file(file2, 'xxx')
411
412 def make_chflags_raiser(err):
413 ex = OSError()
414
Larry Hastings90867a52012-06-22 17:01:41 -0700415 def _chflags_raiser(path, flags, *, follow_symlinks=True):
Ned Deilybaf75712012-05-10 17:05:19 -0700416 ex.errno = err
417 raise ex
418 return _chflags_raiser
419 old_chflags = os.chflags
420 try:
421 for err in errno.EOPNOTSUPP, errno.ENOTSUP:
422 os.chflags = make_chflags_raiser(err)
423 shutil.copystat(file1, file2)
424 # assert others errors break it
425 os.chflags = make_chflags_raiser(errno.EOPNOTSUPP + errno.ENOTSUP)
426 self.assertRaises(OSError, shutil.copystat, file1, file2)
427 finally:
428 os.chflags = old_chflags
429
Antoine Pitrou424246f2012-05-12 19:02:01 +0200430 @support.skip_unless_xattr
431 def test_copyxattr(self):
432 tmp_dir = self.mkdtemp()
433 src = os.path.join(tmp_dir, 'foo')
434 write_file(src, 'foo')
435 dst = os.path.join(tmp_dir, 'bar')
436 write_file(dst, 'bar')
437
438 # no xattr == no problem
439 shutil._copyxattr(src, dst)
440 # common case
441 os.setxattr(src, 'user.foo', b'42')
442 os.setxattr(src, 'user.bar', b'43')
443 shutil._copyxattr(src, dst)
Gregory P. Smith1093bf22014-01-17 12:01:22 -0800444 self.assertEqual(sorted(os.listxattr(src)), sorted(os.listxattr(dst)))
Antoine Pitrou424246f2012-05-12 19:02:01 +0200445 self.assertEqual(
446 os.getxattr(src, 'user.foo'),
447 os.getxattr(dst, 'user.foo'))
448 # check errors don't affect other attrs
449 os.remove(dst)
450 write_file(dst, 'bar')
451 os_error = OSError(errno.EPERM, 'EPERM')
452
Larry Hastings9cf065c2012-06-22 16:30:09 -0700453 def _raise_on_user_foo(fname, attr, val, **kwargs):
Antoine Pitrou424246f2012-05-12 19:02:01 +0200454 if attr == 'user.foo':
455 raise os_error
456 else:
Larry Hastings9cf065c2012-06-22 16:30:09 -0700457 orig_setxattr(fname, attr, val, **kwargs)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200458 try:
459 orig_setxattr = os.setxattr
460 os.setxattr = _raise_on_user_foo
461 shutil._copyxattr(src, dst)
Antoine Pitrou61597d32012-05-12 23:37:35 +0200462 self.assertIn('user.bar', os.listxattr(dst))
Antoine Pitrou424246f2012-05-12 19:02:01 +0200463 finally:
464 os.setxattr = orig_setxattr
Hynek Schlawack0beab052013-02-05 08:22:44 +0100465 # the source filesystem not supporting xattrs should be ok, too.
466 def _raise_on_src(fname, *, follow_symlinks=True):
467 if fname == src:
468 raise OSError(errno.ENOTSUP, 'Operation not supported')
469 return orig_listxattr(fname, follow_symlinks=follow_symlinks)
470 try:
471 orig_listxattr = os.listxattr
472 os.listxattr = _raise_on_src
473 shutil._copyxattr(src, dst)
474 finally:
475 os.listxattr = orig_listxattr
Antoine Pitrou424246f2012-05-12 19:02:01 +0200476
Larry Hastingsad5ae042012-07-14 17:55:11 -0700477 # test that shutil.copystat copies xattrs
478 src = os.path.join(tmp_dir, 'the_original')
479 write_file(src, src)
480 os.setxattr(src, 'user.the_value', b'fiddly')
481 dst = os.path.join(tmp_dir, 'the_copy')
482 write_file(dst, dst)
483 shutil.copystat(src, dst)
Hynek Schlawackc2d481f2012-07-16 17:11:10 +0200484 self.assertEqual(os.getxattr(dst, 'user.the_value'), b'fiddly')
Larry Hastingsad5ae042012-07-14 17:55:11 -0700485
Antoine Pitrou424246f2012-05-12 19:02:01 +0200486 @support.skip_unless_symlink
487 @support.skip_unless_xattr
488 @unittest.skipUnless(hasattr(os, 'geteuid') and os.geteuid() == 0,
489 'root privileges required')
490 def test_copyxattr_symlinks(self):
491 # On Linux, it's only possible to access non-user xattr for symlinks;
492 # which in turn require root privileges. This test should be expanded
493 # as soon as other platforms gain support for extended attributes.
494 tmp_dir = self.mkdtemp()
495 src = os.path.join(tmp_dir, 'foo')
496 src_link = os.path.join(tmp_dir, 'baz')
497 write_file(src, 'foo')
498 os.symlink(src, src_link)
499 os.setxattr(src, 'trusted.foo', b'42')
Larry Hastings9cf065c2012-06-22 16:30:09 -0700500 os.setxattr(src_link, 'trusted.foo', b'43', follow_symlinks=False)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200501 dst = os.path.join(tmp_dir, 'bar')
502 dst_link = os.path.join(tmp_dir, 'qux')
503 write_file(dst, 'bar')
504 os.symlink(dst, dst_link)
Larry Hastingsb4038062012-07-15 10:57:38 -0700505 shutil._copyxattr(src_link, dst_link, follow_symlinks=False)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700506 self.assertEqual(os.getxattr(dst_link, 'trusted.foo', follow_symlinks=False), b'43')
Antoine Pitrou424246f2012-05-12 19:02:01 +0200507 self.assertRaises(OSError, os.getxattr, dst, 'trusted.foo')
Larry Hastingsb4038062012-07-15 10:57:38 -0700508 shutil._copyxattr(src_link, dst, follow_symlinks=False)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200509 self.assertEqual(os.getxattr(dst, 'trusted.foo'), b'43')
510
Antoine Pitrou78091e62011-12-29 18:54:15 +0100511 @support.skip_unless_symlink
512 def test_copy_symlinks(self):
513 tmp_dir = self.mkdtemp()
514 src = os.path.join(tmp_dir, 'foo')
515 dst = os.path.join(tmp_dir, 'bar')
516 src_link = os.path.join(tmp_dir, 'baz')
517 write_file(src, 'foo')
518 os.symlink(src, src_link)
519 if hasattr(os, 'lchmod'):
520 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
521 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700522 shutil.copy(src_link, dst, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100523 self.assertFalse(os.path.islink(dst))
524 self.assertEqual(read_file(src), read_file(dst))
525 os.remove(dst)
526 # follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700527 shutil.copy(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100528 self.assertTrue(os.path.islink(dst))
529 self.assertEqual(os.readlink(dst), os.readlink(src_link))
530 if hasattr(os, 'lchmod'):
531 self.assertEqual(os.lstat(src_link).st_mode,
532 os.lstat(dst).st_mode)
533
534 @support.skip_unless_symlink
535 def test_copy2_symlinks(self):
536 tmp_dir = self.mkdtemp()
537 src = os.path.join(tmp_dir, 'foo')
538 dst = os.path.join(tmp_dir, 'bar')
539 src_link = os.path.join(tmp_dir, 'baz')
540 write_file(src, 'foo')
541 os.symlink(src, src_link)
542 if hasattr(os, 'lchmod'):
543 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
544 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
545 os.lchflags(src_link, stat.UF_NODUMP)
546 src_stat = os.stat(src)
547 src_link_stat = os.lstat(src_link)
548 # follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700549 shutil.copy2(src_link, dst, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100550 self.assertFalse(os.path.islink(dst))
551 self.assertEqual(read_file(src), read_file(dst))
552 os.remove(dst)
553 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700554 shutil.copy2(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100555 self.assertTrue(os.path.islink(dst))
556 self.assertEqual(os.readlink(dst), os.readlink(src_link))
557 dst_stat = os.lstat(dst)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700558 if os.utime in os.supports_follow_symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100559 for attr in 'st_atime', 'st_mtime':
560 # The modification times may be truncated in the new file.
561 self.assertLessEqual(getattr(src_link_stat, attr),
562 getattr(dst_stat, attr) + 1)
563 if hasattr(os, 'lchmod'):
564 self.assertEqual(src_link_stat.st_mode, dst_stat.st_mode)
565 self.assertNotEqual(src_stat.st_mode, dst_stat.st_mode)
566 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
567 self.assertEqual(src_link_stat.st_flags, dst_stat.st_flags)
568
Antoine Pitrou424246f2012-05-12 19:02:01 +0200569 @support.skip_unless_xattr
570 def test_copy2_xattr(self):
571 tmp_dir = self.mkdtemp()
572 src = os.path.join(tmp_dir, 'foo')
573 dst = os.path.join(tmp_dir, 'bar')
574 write_file(src, 'foo')
575 os.setxattr(src, 'user.foo', b'42')
576 shutil.copy2(src, dst)
577 self.assertEqual(
578 os.getxattr(src, 'user.foo'),
579 os.getxattr(dst, 'user.foo'))
580 os.remove(dst)
581
Antoine Pitrou78091e62011-12-29 18:54:15 +0100582 @support.skip_unless_symlink
583 def test_copyfile_symlinks(self):
584 tmp_dir = self.mkdtemp()
585 src = os.path.join(tmp_dir, 'src')
586 dst = os.path.join(tmp_dir, 'dst')
587 dst_link = os.path.join(tmp_dir, 'dst_link')
588 link = os.path.join(tmp_dir, 'link')
589 write_file(src, 'foo')
590 os.symlink(src, link)
591 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700592 shutil.copyfile(link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100593 self.assertTrue(os.path.islink(dst_link))
594 self.assertEqual(os.readlink(link), os.readlink(dst_link))
595 # follow
596 shutil.copyfile(link, dst)
597 self.assertFalse(os.path.islink(dst))
598
Hynek Schlawack2100b422012-06-23 20:28:32 +0200599 def test_rmtree_uses_safe_fd_version_if_available(self):
Hynek Schlawackd0f6e0a2012-06-29 08:28:20 +0200600 _use_fd_functions = ({os.open, os.stat, os.unlink, os.rmdir} <=
601 os.supports_dir_fd and
602 os.listdir in os.supports_fd and
603 os.stat in os.supports_follow_symlinks)
604 if _use_fd_functions:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200605 self.assertTrue(shutil._use_fd_functions)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000606 self.assertTrue(shutil.rmtree.avoids_symlink_attacks)
Hynek Schlawack2100b422012-06-23 20:28:32 +0200607 tmp_dir = self.mkdtemp()
608 d = os.path.join(tmp_dir, 'a')
609 os.mkdir(d)
610 try:
611 real_rmtree = shutil._rmtree_safe_fd
612 class Called(Exception): pass
613 def _raiser(*args, **kwargs):
614 raise Called
615 shutil._rmtree_safe_fd = _raiser
616 self.assertRaises(Called, shutil.rmtree, d)
617 finally:
618 shutil._rmtree_safe_fd = real_rmtree
619 else:
620 self.assertFalse(shutil._use_fd_functions)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000621 self.assertFalse(shutil.rmtree.avoids_symlink_attacks)
Hynek Schlawack2100b422012-06-23 20:28:32 +0200622
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000623 def test_rmtree_dont_delete_file(self):
624 # When called on a file instead of a directory, don't delete it.
625 handle, path = tempfile.mkstemp()
Victor Stinnerbf816222011-06-30 23:25:47 +0200626 os.close(handle)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200627 self.assertRaises(NotADirectoryError, shutil.rmtree, path)
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000628 os.remove(path)
629
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000630 def test_copytree_simple(self):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000631 src_dir = tempfile.mkdtemp()
632 dst_dir = os.path.join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200633 self.addCleanup(shutil.rmtree, src_dir)
634 self.addCleanup(shutil.rmtree, os.path.dirname(dst_dir))
635 write_file((src_dir, 'test.txt'), '123')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000636 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200637 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000638
Éric Araujoa7e33a12011-08-12 19:51:35 +0200639 shutil.copytree(src_dir, dst_dir)
640 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test.txt')))
641 self.assertTrue(os.path.isdir(os.path.join(dst_dir, 'test_dir')))
642 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test_dir',
643 'test.txt')))
644 actual = read_file((dst_dir, 'test.txt'))
645 self.assertEqual(actual, '123')
646 actual = read_file((dst_dir, 'test_dir', 'test.txt'))
647 self.assertEqual(actual, '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000648
Antoine Pitrou78091e62011-12-29 18:54:15 +0100649 @support.skip_unless_symlink
650 def test_copytree_symlinks(self):
651 tmp_dir = self.mkdtemp()
652 src_dir = os.path.join(tmp_dir, 'src')
653 dst_dir = os.path.join(tmp_dir, 'dst')
654 sub_dir = os.path.join(src_dir, 'sub')
655 os.mkdir(src_dir)
656 os.mkdir(sub_dir)
657 write_file((src_dir, 'file.txt'), 'foo')
658 src_link = os.path.join(sub_dir, 'link')
659 dst_link = os.path.join(dst_dir, 'sub/link')
660 os.symlink(os.path.join(src_dir, 'file.txt'),
661 src_link)
662 if hasattr(os, 'lchmod'):
663 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
664 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
665 os.lchflags(src_link, stat.UF_NODUMP)
666 src_stat = os.lstat(src_link)
667 shutil.copytree(src_dir, dst_dir, symlinks=True)
668 self.assertTrue(os.path.islink(os.path.join(dst_dir, 'sub', 'link')))
669 self.assertEqual(os.readlink(os.path.join(dst_dir, 'sub', 'link')),
670 os.path.join(src_dir, 'file.txt'))
671 dst_stat = os.lstat(dst_link)
672 if hasattr(os, 'lchmod'):
673 self.assertEqual(dst_stat.st_mode, src_stat.st_mode)
674 if hasattr(os, 'lchflags'):
675 self.assertEqual(dst_stat.st_flags, src_stat.st_flags)
676
Georg Brandl2ee470f2008-07-16 12:55:28 +0000677 def test_copytree_with_exclude(self):
Georg Brandl2ee470f2008-07-16 12:55:28 +0000678 # creating data
679 join = os.path.join
680 exists = os.path.exists
681 src_dir = tempfile.mkdtemp()
Georg Brandl2ee470f2008-07-16 12:55:28 +0000682 try:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000683 dst_dir = join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200684 write_file((src_dir, 'test.txt'), '123')
685 write_file((src_dir, 'test.tmp'), '123')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000686 os.mkdir(join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200687 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000688 os.mkdir(join(src_dir, 'test_dir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200689 write_file((src_dir, 'test_dir2', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000690 os.mkdir(join(src_dir, 'test_dir2', 'subdir'))
691 os.mkdir(join(src_dir, 'test_dir2', 'subdir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200692 write_file((src_dir, 'test_dir2', 'subdir', 'test.txt'), '456')
693 write_file((src_dir, 'test_dir2', 'subdir2', 'test.py'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000694
695 # testing glob-like patterns
696 try:
697 patterns = shutil.ignore_patterns('*.tmp', 'test_dir2')
698 shutil.copytree(src_dir, dst_dir, ignore=patterns)
699 # checking the result: some elements should not be copied
700 self.assertTrue(exists(join(dst_dir, 'test.txt')))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200701 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
702 self.assertFalse(exists(join(dst_dir, 'test_dir2')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000703 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200704 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000705 try:
706 patterns = shutil.ignore_patterns('*.tmp', 'subdir*')
707 shutil.copytree(src_dir, dst_dir, ignore=patterns)
708 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200709 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
710 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2')))
711 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000712 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200713 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000714
715 # testing callable-style
716 try:
717 def _filter(src, names):
718 res = []
719 for name in names:
720 path = os.path.join(src, name)
721
722 if (os.path.isdir(path) and
723 path.split()[-1] == 'subdir'):
724 res.append(name)
725 elif os.path.splitext(path)[-1] in ('.py'):
726 res.append(name)
727 return res
728
729 shutil.copytree(src_dir, dst_dir, ignore=_filter)
730
731 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200732 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2',
733 'test.py')))
734 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000735
736 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200737 shutil.rmtree(dst_dir)
Georg Brandl2ee470f2008-07-16 12:55:28 +0000738 finally:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000739 shutil.rmtree(src_dir)
740 shutil.rmtree(os.path.dirname(dst_dir))
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000741
Antoine Pitrouac601602013-08-16 19:35:02 +0200742 def test_copytree_retains_permissions(self):
743 tmp_dir = tempfile.mkdtemp()
744 src_dir = os.path.join(tmp_dir, 'source')
745 os.mkdir(src_dir)
746 dst_dir = os.path.join(tmp_dir, 'destination')
747 self.addCleanup(shutil.rmtree, tmp_dir)
748
749 os.chmod(src_dir, 0o777)
750 write_file((src_dir, 'permissive.txt'), '123')
751 os.chmod(os.path.join(src_dir, 'permissive.txt'), 0o777)
752 write_file((src_dir, 'restrictive.txt'), '456')
753 os.chmod(os.path.join(src_dir, 'restrictive.txt'), 0o600)
754 restrictive_subdir = tempfile.mkdtemp(dir=src_dir)
755 os.chmod(restrictive_subdir, 0o600)
756
757 shutil.copytree(src_dir, dst_dir)
Brett Cannon9c7eb552013-08-23 14:38:11 -0400758 self.assertEqual(os.stat(src_dir).st_mode, os.stat(dst_dir).st_mode)
759 self.assertEqual(os.stat(os.path.join(src_dir, 'permissive.txt')).st_mode,
Antoine Pitrouac601602013-08-16 19:35:02 +0200760 os.stat(os.path.join(dst_dir, 'permissive.txt')).st_mode)
Brett Cannon9c7eb552013-08-23 14:38:11 -0400761 self.assertEqual(os.stat(os.path.join(src_dir, 'restrictive.txt')).st_mode,
Antoine Pitrouac601602013-08-16 19:35:02 +0200762 os.stat(os.path.join(dst_dir, 'restrictive.txt')).st_mode)
763 restrictive_subdir_dst = os.path.join(dst_dir,
764 os.path.split(restrictive_subdir)[1])
Brett Cannon9c7eb552013-08-23 14:38:11 -0400765 self.assertEqual(os.stat(restrictive_subdir).st_mode,
Antoine Pitrouac601602013-08-16 19:35:02 +0200766 os.stat(restrictive_subdir_dst).st_mode)
767
Berker Peksag884afd92014-12-10 02:50:32 +0200768 @unittest.mock.patch('os.chmod')
769 def test_copytree_winerror(self, mock_patch):
770 # When copying to VFAT, copystat() raises OSError. On Windows, the
771 # exception object has a meaningful 'winerror' attribute, but not
772 # on other operating systems. Do not assume 'winerror' is set.
773 src_dir = tempfile.mkdtemp()
774 dst_dir = os.path.join(tempfile.mkdtemp(), 'destination')
775 self.addCleanup(shutil.rmtree, src_dir)
776 self.addCleanup(shutil.rmtree, os.path.dirname(dst_dir))
777
778 mock_patch.side_effect = PermissionError('ka-boom')
779 with self.assertRaises(shutil.Error):
780 shutil.copytree(src_dir, dst_dir)
781
Zachary Ware9fe6d862013-12-08 00:20:35 -0600782 @unittest.skipIf(os.name == 'nt', 'temporarily disabled on Windows')
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000783 @unittest.skipUnless(hasattr(os, 'link'), 'requires os.link')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000784 def test_dont_copy_file_onto_link_to_itself(self):
785 # bug 851123.
786 os.mkdir(TESTFN)
787 src = os.path.join(TESTFN, 'cheese')
788 dst = os.path.join(TESTFN, 'shop')
789 try:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000790 with open(src, 'w') as f:
791 f.write('cheddar')
792 os.link(src, dst)
Hynek Schlawack48653762012-10-07 12:49:58 +0200793 self.assertRaises(shutil.SameFileError, shutil.copyfile, src, dst)
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000794 with open(src, 'r') as f:
795 self.assertEqual(f.read(), 'cheddar')
796 os.remove(dst)
797 finally:
798 shutil.rmtree(TESTFN, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000799
Brian Curtin3b4499c2010-12-28 14:31:47 +0000800 @support.skip_unless_symlink
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000801 def test_dont_copy_file_onto_symlink_to_itself(self):
802 # bug 851123.
803 os.mkdir(TESTFN)
804 src = os.path.join(TESTFN, 'cheese')
805 dst = os.path.join(TESTFN, 'shop')
806 try:
807 with open(src, 'w') as f:
808 f.write('cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000809 # Using `src` here would mean we end up with a symlink pointing
810 # to TESTFN/TESTFN/cheese, while it should point at
811 # TESTFN/cheese.
812 os.symlink('cheese', dst)
Hynek Schlawack48653762012-10-07 12:49:58 +0200813 self.assertRaises(shutil.SameFileError, shutil.copyfile, src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +0000814 with open(src, 'r') as f:
815 self.assertEqual(f.read(), 'cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000816 os.remove(dst)
817 finally:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000818 shutil.rmtree(TESTFN, ignore_errors=True)
Johannes Gijsbers68128712004-08-14 13:57:08 +0000819
Brian Curtin3b4499c2010-12-28 14:31:47 +0000820 @support.skip_unless_symlink
Brian Curtind40e6f72010-07-08 21:39:08 +0000821 def test_rmtree_on_symlink(self):
822 # bug 1669.
823 os.mkdir(TESTFN)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000824 try:
Brian Curtind40e6f72010-07-08 21:39:08 +0000825 src = os.path.join(TESTFN, 'cheese')
826 dst = os.path.join(TESTFN, 'shop')
827 os.mkdir(src)
828 os.symlink(src, dst)
829 self.assertRaises(OSError, shutil.rmtree, dst)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200830 shutil.rmtree(dst, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000831 finally:
Brian Curtind40e6f72010-07-08 21:39:08 +0000832 shutil.rmtree(TESTFN, ignore_errors=True)
833
Serhiy Storchaka43767632013-11-03 21:31:38 +0200834 # Issue #3002: copyfile and copytree block indefinitely on named pipes
835 @unittest.skipUnless(hasattr(os, "mkfifo"), 'requires os.mkfifo()')
836 def test_copyfile_named_pipe(self):
837 os.mkfifo(TESTFN)
838 try:
839 self.assertRaises(shutil.SpecialFileError,
840 shutil.copyfile, TESTFN, TESTFN2)
841 self.assertRaises(shutil.SpecialFileError,
842 shutil.copyfile, __file__, TESTFN)
843 finally:
844 os.remove(TESTFN)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000845
Serhiy Storchaka43767632013-11-03 21:31:38 +0200846 @unittest.skipUnless(hasattr(os, "mkfifo"), 'requires os.mkfifo()')
847 @support.skip_unless_symlink
848 def test_copytree_named_pipe(self):
849 os.mkdir(TESTFN)
850 try:
851 subdir = os.path.join(TESTFN, "subdir")
852 os.mkdir(subdir)
853 pipe = os.path.join(subdir, "mypipe")
854 os.mkfifo(pipe)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000855 try:
Serhiy Storchaka43767632013-11-03 21:31:38 +0200856 shutil.copytree(TESTFN, TESTFN2)
857 except shutil.Error as e:
858 errors = e.args[0]
859 self.assertEqual(len(errors), 1)
860 src, dst, error_msg = errors[0]
861 self.assertEqual("`%s` is a named pipe" % pipe, error_msg)
862 else:
863 self.fail("shutil.Error should have been raised")
864 finally:
865 shutil.rmtree(TESTFN, ignore_errors=True)
866 shutil.rmtree(TESTFN2, ignore_errors=True)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000867
Tarek Ziadé5340db32010-04-19 22:30:51 +0000868 def test_copytree_special_func(self):
869
870 src_dir = self.mkdtemp()
871 dst_dir = os.path.join(self.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200872 write_file((src_dir, 'test.txt'), '123')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000873 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200874 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000875
876 copied = []
877 def _copy(src, dst):
878 copied.append((src, dst))
879
880 shutil.copytree(src_dir, dst_dir, copy_function=_copy)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000881 self.assertEqual(len(copied), 2)
Tarek Ziadé5340db32010-04-19 22:30:51 +0000882
Brian Curtin3b4499c2010-12-28 14:31:47 +0000883 @support.skip_unless_symlink
Tarek Ziadéfb437512010-04-20 08:57:33 +0000884 def test_copytree_dangling_symlinks(self):
885
886 # a dangling symlink raises an error at the end
887 src_dir = self.mkdtemp()
888 dst_dir = os.path.join(self.mkdtemp(), 'destination')
889 os.symlink('IDONTEXIST', os.path.join(src_dir, 'test.txt'))
890 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200891 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadéfb437512010-04-20 08:57:33 +0000892 self.assertRaises(Error, shutil.copytree, src_dir, dst_dir)
893
894 # a dangling symlink is ignored with the proper flag
895 dst_dir = os.path.join(self.mkdtemp(), 'destination2')
896 shutil.copytree(src_dir, dst_dir, ignore_dangling_symlinks=True)
897 self.assertNotIn('test.txt', os.listdir(dst_dir))
898
899 # a dangling symlink is copied if symlinks=True
900 dst_dir = os.path.join(self.mkdtemp(), 'destination3')
901 shutil.copytree(src_dir, dst_dir, symlinks=True)
902 self.assertIn('test.txt', os.listdir(dst_dir))
903
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400904 def _copy_file(self, method):
905 fname = 'test.txt'
906 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200907 write_file((tmpdir, fname), 'xxx')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400908 file1 = os.path.join(tmpdir, fname)
909 tmpdir2 = self.mkdtemp()
910 method(file1, tmpdir2)
911 file2 = os.path.join(tmpdir2, fname)
912 return (file1, file2)
913
914 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
915 def test_copy(self):
916 # Ensure that the copied file exists and has the same mode bits.
917 file1, file2 = self._copy_file(shutil.copy)
918 self.assertTrue(os.path.exists(file2))
919 self.assertEqual(os.stat(file1).st_mode, os.stat(file2).st_mode)
920
921 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
Senthil Kumaran0c2dba52011-07-03 18:21:38 -0700922 @unittest.skipUnless(hasattr(os, 'utime'), 'requires os.utime')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400923 def test_copy2(self):
924 # Ensure that the copied file exists and has the same mode and
925 # modification time bits.
926 file1, file2 = self._copy_file(shutil.copy2)
927 self.assertTrue(os.path.exists(file2))
928 file1_stat = os.stat(file1)
929 file2_stat = os.stat(file2)
930 self.assertEqual(file1_stat.st_mode, file2_stat.st_mode)
931 for attr in 'st_atime', 'st_mtime':
932 # The modification times may be truncated in the new file.
933 self.assertLessEqual(getattr(file1_stat, attr),
934 getattr(file2_stat, attr) + 1)
935 if hasattr(os, 'chflags') and hasattr(file1_stat, 'st_flags'):
936 self.assertEqual(getattr(file1_stat, 'st_flags'),
937 getattr(file2_stat, 'st_flags'))
938
Ezio Melotti975077a2011-05-19 22:03:22 +0300939 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000940 def test_make_tarball(self):
941 # creating something to tar
942 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200943 write_file((tmpdir, 'file1'), 'xxx')
944 write_file((tmpdir, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000945 os.mkdir(os.path.join(tmpdir, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200946 write_file((tmpdir, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000947
948 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400949 # force shutil to create the directory
950 os.rmdir(tmpdir2)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000951 unittest.skipUnless(splitdrive(tmpdir)[0] == splitdrive(tmpdir2)[0],
952 "source and target should be on same drive")
953
954 base_name = os.path.join(tmpdir2, 'archive')
955
956 # working with relative paths to avoid tar warnings
957 old_dir = os.getcwd()
958 os.chdir(tmpdir)
959 try:
960 _make_tarball(splitdrive(base_name)[1], '.')
961 finally:
962 os.chdir(old_dir)
963
964 # check if the compressed tarball was created
965 tarball = base_name + '.tar.gz'
966 self.assertTrue(os.path.exists(tarball))
967
968 # trying an uncompressed one
969 base_name = os.path.join(tmpdir2, 'archive')
970 old_dir = os.getcwd()
971 os.chdir(tmpdir)
972 try:
973 _make_tarball(splitdrive(base_name)[1], '.', compress=None)
974 finally:
975 os.chdir(old_dir)
976 tarball = base_name + '.tar'
977 self.assertTrue(os.path.exists(tarball))
978
979 def _tarinfo(self, path):
980 tar = tarfile.open(path)
981 try:
982 names = tar.getnames()
983 names.sort()
984 return tuple(names)
985 finally:
986 tar.close()
987
988 def _create_files(self):
989 # creating something to tar
990 tmpdir = self.mkdtemp()
991 dist = os.path.join(tmpdir, 'dist')
992 os.mkdir(dist)
Éric Araujoa7e33a12011-08-12 19:51:35 +0200993 write_file((dist, 'file1'), 'xxx')
994 write_file((dist, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000995 os.mkdir(os.path.join(dist, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200996 write_file((dist, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000997 os.mkdir(os.path.join(dist, 'sub2'))
998 tmpdir2 = self.mkdtemp()
999 base_name = os.path.join(tmpdir2, 'archive')
1000 return tmpdir, tmpdir2, base_name
1001
Ezio Melotti975077a2011-05-19 22:03:22 +03001002 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001003 @unittest.skipUnless(find_executable('tar') and find_executable('gzip'),
1004 'Need the tar command to run')
1005 def test_tarfile_vs_tar(self):
1006 tmpdir, tmpdir2, base_name = self._create_files()
1007 old_dir = os.getcwd()
1008 os.chdir(tmpdir)
1009 try:
1010 _make_tarball(base_name, 'dist')
1011 finally:
1012 os.chdir(old_dir)
1013
1014 # check if the compressed tarball was created
1015 tarball = base_name + '.tar.gz'
1016 self.assertTrue(os.path.exists(tarball))
1017
1018 # now create another tarball using `tar`
1019 tarball2 = os.path.join(tmpdir, 'archive2.tar.gz')
1020 tar_cmd = ['tar', '-cf', 'archive2.tar', 'dist']
1021 gzip_cmd = ['gzip', '-f9', 'archive2.tar']
1022 old_dir = os.getcwd()
1023 os.chdir(tmpdir)
1024 try:
1025 with captured_stdout() as s:
1026 spawn(tar_cmd)
1027 spawn(gzip_cmd)
1028 finally:
1029 os.chdir(old_dir)
1030
1031 self.assertTrue(os.path.exists(tarball2))
1032 # let's compare both tarballs
Ezio Melottib3aedd42010-11-20 19:04:17 +00001033 self.assertEqual(self._tarinfo(tarball), self._tarinfo(tarball2))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001034
1035 # trying an uncompressed one
1036 base_name = os.path.join(tmpdir2, 'archive')
1037 old_dir = os.getcwd()
1038 os.chdir(tmpdir)
1039 try:
1040 _make_tarball(base_name, 'dist', compress=None)
1041 finally:
1042 os.chdir(old_dir)
1043 tarball = base_name + '.tar'
1044 self.assertTrue(os.path.exists(tarball))
1045
1046 # now for a dry_run
1047 base_name = os.path.join(tmpdir2, 'archive')
1048 old_dir = os.getcwd()
1049 os.chdir(tmpdir)
1050 try:
1051 _make_tarball(base_name, 'dist', compress=None, dry_run=True)
1052 finally:
1053 os.chdir(old_dir)
1054 tarball = base_name + '.tar'
1055 self.assertTrue(os.path.exists(tarball))
1056
Ezio Melotti975077a2011-05-19 22:03:22 +03001057 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001058 @unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run')
1059 def test_make_zipfile(self):
1060 # creating something to tar
1061 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +02001062 write_file((tmpdir, 'file1'), 'xxx')
1063 write_file((tmpdir, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +00001064
1065 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001066 # force shutil to create the directory
1067 os.rmdir(tmpdir2)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001068 base_name = os.path.join(tmpdir2, 'archive')
1069 _make_zipfile(base_name, tmpdir)
1070
1071 # check if the compressed tarball was created
1072 tarball = base_name + '.zip'
Éric Araujo1c505492010-11-06 02:12:51 +00001073 self.assertTrue(os.path.exists(tarball))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001074
1075
1076 def test_make_archive(self):
1077 tmpdir = self.mkdtemp()
1078 base_name = os.path.join(tmpdir, 'archive')
1079 self.assertRaises(ValueError, make_archive, base_name, 'xxx')
1080
Ezio Melotti975077a2011-05-19 22:03:22 +03001081 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001082 def test_make_archive_owner_group(self):
1083 # testing make_archive with owner and group, with various combinations
1084 # this works even if there's not gid/uid support
1085 if UID_GID_SUPPORT:
1086 group = grp.getgrgid(0)[0]
1087 owner = pwd.getpwuid(0)[0]
1088 else:
1089 group = owner = 'root'
1090
1091 base_dir, root_dir, base_name = self._create_files()
1092 base_name = os.path.join(self.mkdtemp() , 'archive')
1093 res = make_archive(base_name, 'zip', root_dir, base_dir, owner=owner,
1094 group=group)
1095 self.assertTrue(os.path.exists(res))
1096
1097 res = make_archive(base_name, 'zip', root_dir, base_dir)
1098 self.assertTrue(os.path.exists(res))
1099
1100 res = make_archive(base_name, 'tar', root_dir, base_dir,
1101 owner=owner, group=group)
1102 self.assertTrue(os.path.exists(res))
1103
1104 res = make_archive(base_name, 'tar', root_dir, base_dir,
1105 owner='kjhkjhkjg', group='oihohoh')
1106 self.assertTrue(os.path.exists(res))
1107
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001108
Ezio Melotti975077a2011-05-19 22:03:22 +03001109 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001110 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1111 def test_tarfile_root_owner(self):
1112 tmpdir, tmpdir2, base_name = self._create_files()
1113 old_dir = os.getcwd()
1114 os.chdir(tmpdir)
1115 group = grp.getgrgid(0)[0]
1116 owner = pwd.getpwuid(0)[0]
1117 try:
1118 archive_name = _make_tarball(base_name, 'dist', compress=None,
1119 owner=owner, group=group)
1120 finally:
1121 os.chdir(old_dir)
1122
1123 # check if the compressed tarball was created
1124 self.assertTrue(os.path.exists(archive_name))
1125
1126 # now checks the rights
1127 archive = tarfile.open(archive_name)
1128 try:
1129 for member in archive.getmembers():
Ezio Melottib3aedd42010-11-20 19:04:17 +00001130 self.assertEqual(member.uid, 0)
1131 self.assertEqual(member.gid, 0)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001132 finally:
1133 archive.close()
1134
1135 def test_make_archive_cwd(self):
1136 current_dir = os.getcwd()
1137 def _breaks(*args, **kw):
1138 raise RuntimeError()
1139
1140 register_archive_format('xxx', _breaks, [], 'xxx file')
1141 try:
1142 try:
1143 make_archive('xxx', 'xxx', root_dir=self.mkdtemp())
1144 except Exception:
1145 pass
Ezio Melottib3aedd42010-11-20 19:04:17 +00001146 self.assertEqual(os.getcwd(), current_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001147 finally:
1148 unregister_archive_format('xxx')
1149
Serhiy Storchaka9a4fc192014-11-28 00:48:46 +02001150 def test_make_tarfile_in_curdir(self):
1151 # Issue #21280
1152 root_dir = self.mkdtemp()
1153 with support.change_cwd(root_dir):
1154 self.assertEqual(make_archive('test', 'tar'), 'test.tar')
1155 self.assertTrue(os.path.isfile('test.tar'))
1156
1157 @requires_zlib
1158 def test_make_zipfile_in_curdir(self):
1159 # Issue #21280
1160 root_dir = self.mkdtemp()
1161 with support.change_cwd(root_dir):
1162 self.assertEqual(make_archive('test', 'zip'), 'test.zip')
1163 self.assertTrue(os.path.isfile('test.zip'))
1164
Tarek Ziadé396fad72010-02-23 05:30:31 +00001165 def test_register_archive_format(self):
1166
1167 self.assertRaises(TypeError, register_archive_format, 'xxx', 1)
1168 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1169 1)
1170 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1171 [(1, 2), (1, 2, 3)])
1172
1173 register_archive_format('xxx', lambda: x, [(1, 2)], 'xxx file')
1174 formats = [name for name, params in get_archive_formats()]
1175 self.assertIn('xxx', formats)
1176
1177 unregister_archive_format('xxx')
1178 formats = [name for name, params in get_archive_formats()]
1179 self.assertNotIn('xxx', formats)
1180
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001181 def _compare_dirs(self, dir1, dir2):
1182 # check that dir1 and dir2 are equivalent,
1183 # return the diff
1184 diff = []
1185 for root, dirs, files in os.walk(dir1):
1186 for file_ in files:
1187 path = os.path.join(root, file_)
1188 target_path = os.path.join(dir2, os.path.split(path)[-1])
1189 if not os.path.exists(target_path):
1190 diff.append(file_)
1191 return diff
1192
Ezio Melotti975077a2011-05-19 22:03:22 +03001193 @requires_zlib
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001194 def test_unpack_archive(self):
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001195 formats = ['tar', 'gztar', 'zip']
1196 if BZ2_SUPPORTED:
1197 formats.append('bztar')
Serhiy Storchaka11213772014-08-06 18:50:19 +03001198 if LZMA_SUPPORTED:
1199 formats.append('xztar')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001200
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001201 for format in formats:
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001202 tmpdir = self.mkdtemp()
1203 base_dir, root_dir, base_name = self._create_files()
1204 tmpdir2 = self.mkdtemp()
1205 filename = make_archive(base_name, format, root_dir, base_dir)
1206
1207 # let's try to unpack it now
1208 unpack_archive(filename, tmpdir2)
1209 diff = self._compare_dirs(tmpdir, tmpdir2)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001210 self.assertEqual(diff, [])
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001211
Nick Coghlanabf202d2011-03-16 13:52:20 -04001212 # and again, this time with the format specified
1213 tmpdir3 = self.mkdtemp()
1214 unpack_archive(filename, tmpdir3, format=format)
1215 diff = self._compare_dirs(tmpdir, tmpdir3)
1216 self.assertEqual(diff, [])
1217 self.assertRaises(shutil.ReadError, unpack_archive, TESTFN)
1218 self.assertRaises(ValueError, unpack_archive, TESTFN, format='xxx')
1219
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001220 def test_unpack_registery(self):
1221
1222 formats = get_unpack_formats()
1223
1224 def _boo(filename, extract_dir, extra):
Ezio Melottib3aedd42010-11-20 19:04:17 +00001225 self.assertEqual(extra, 1)
1226 self.assertEqual(filename, 'stuff.boo')
1227 self.assertEqual(extract_dir, 'xx')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001228
1229 register_unpack_format('Boo', ['.boo', '.b2'], _boo, [('extra', 1)])
1230 unpack_archive('stuff.boo', 'xx')
1231
1232 # trying to register a .boo unpacker again
1233 self.assertRaises(RegistryError, register_unpack_format, 'Boo2',
1234 ['.boo'], _boo)
1235
1236 # should work now
1237 unregister_unpack_format('Boo')
1238 register_unpack_format('Boo2', ['.boo'], _boo)
1239 self.assertIn(('Boo2', ['.boo'], ''), get_unpack_formats())
1240 self.assertNotIn(('Boo', ['.boo'], ''), get_unpack_formats())
1241
1242 # let's leave a clean state
1243 unregister_unpack_format('Boo2')
Ezio Melottib3aedd42010-11-20 19:04:17 +00001244 self.assertEqual(get_unpack_formats(), formats)
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001245
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001246 @unittest.skipUnless(hasattr(shutil, 'disk_usage'),
1247 "disk_usage not available on this platform")
1248 def test_disk_usage(self):
1249 usage = shutil.disk_usage(os.getcwd())
Éric Araujo2ee61882011-07-02 16:45:45 +02001250 self.assertGreater(usage.total, 0)
1251 self.assertGreater(usage.used, 0)
1252 self.assertGreaterEqual(usage.free, 0)
1253 self.assertGreaterEqual(usage.total, usage.used)
1254 self.assertGreater(usage.total, usage.free)
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001255
Sandro Tosid902a142011-08-22 23:28:27 +02001256 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1257 @unittest.skipUnless(hasattr(os, 'chown'), 'requires os.chown')
1258 def test_chown(self):
1259
1260 # cleaned-up automatically by TestShutil.tearDown method
1261 dirname = self.mkdtemp()
1262 filename = tempfile.mktemp(dir=dirname)
1263 write_file(filename, 'testing chown function')
1264
1265 with self.assertRaises(ValueError):
1266 shutil.chown(filename)
1267
1268 with self.assertRaises(LookupError):
1269 shutil.chown(filename, user='non-exising username')
1270
1271 with self.assertRaises(LookupError):
1272 shutil.chown(filename, group='non-exising groupname')
1273
1274 with self.assertRaises(TypeError):
1275 shutil.chown(filename, b'spam')
1276
1277 with self.assertRaises(TypeError):
1278 shutil.chown(filename, 3.14)
1279
1280 uid = os.getuid()
1281 gid = os.getgid()
1282
1283 def check_chown(path, uid=None, gid=None):
1284 s = os.stat(filename)
1285 if uid is not None:
1286 self.assertEqual(uid, s.st_uid)
1287 if gid is not None:
1288 self.assertEqual(gid, s.st_gid)
1289
1290 shutil.chown(filename, uid, gid)
1291 check_chown(filename, uid, gid)
1292 shutil.chown(filename, uid)
1293 check_chown(filename, uid)
1294 shutil.chown(filename, user=uid)
1295 check_chown(filename, uid)
1296 shutil.chown(filename, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001297 check_chown(filename, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001298
1299 shutil.chown(dirname, uid, gid)
1300 check_chown(dirname, uid, gid)
1301 shutil.chown(dirname, uid)
1302 check_chown(dirname, uid)
1303 shutil.chown(dirname, user=uid)
1304 check_chown(dirname, uid)
1305 shutil.chown(dirname, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001306 check_chown(dirname, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001307
1308 user = pwd.getpwuid(uid)[0]
1309 group = grp.getgrgid(gid)[0]
1310 shutil.chown(filename, user, group)
1311 check_chown(filename, uid, gid)
1312 shutil.chown(dirname, user, group)
1313 check_chown(dirname, uid, gid)
1314
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001315 def test_copy_return_value(self):
1316 # copy and copy2 both return their destination path.
1317 for fn in (shutil.copy, shutil.copy2):
1318 src_dir = self.mkdtemp()
1319 dst_dir = self.mkdtemp()
1320 src = os.path.join(src_dir, 'foo')
1321 write_file(src, 'foo')
1322 rv = fn(src, dst_dir)
1323 self.assertEqual(rv, os.path.join(dst_dir, 'foo'))
1324 rv = fn(src, os.path.join(dst_dir, 'bar'))
1325 self.assertEqual(rv, os.path.join(dst_dir, 'bar'))
1326
1327 def test_copyfile_return_value(self):
1328 # copytree returns its destination path.
1329 src_dir = self.mkdtemp()
1330 dst_dir = self.mkdtemp()
1331 dst_file = os.path.join(dst_dir, 'bar')
1332 src_file = os.path.join(src_dir, 'foo')
1333 write_file(src_file, 'foo')
1334 rv = shutil.copyfile(src_file, dst_file)
1335 self.assertTrue(os.path.exists(rv))
1336 self.assertEqual(read_file(src_file), read_file(dst_file))
1337
Hynek Schlawack48653762012-10-07 12:49:58 +02001338 def test_copyfile_same_file(self):
1339 # copyfile() should raise SameFileError if the source and destination
1340 # are the same.
1341 src_dir = self.mkdtemp()
1342 src_file = os.path.join(src_dir, 'foo')
1343 write_file(src_file, 'foo')
1344 self.assertRaises(SameFileError, shutil.copyfile, src_file, src_file)
Hynek Schlawack27ddb572012-10-28 13:59:27 +01001345 # But Error should work too, to stay backward compatible.
1346 self.assertRaises(Error, shutil.copyfile, src_file, src_file)
Hynek Schlawack48653762012-10-07 12:49:58 +02001347
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001348 def test_copytree_return_value(self):
1349 # copytree returns its destination path.
1350 src_dir = self.mkdtemp()
1351 dst_dir = src_dir + "dest"
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001352 self.addCleanup(shutil.rmtree, dst_dir, True)
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001353 src = os.path.join(src_dir, 'foo')
1354 write_file(src, 'foo')
1355 rv = shutil.copytree(src_dir, dst_dir)
1356 self.assertEqual(['foo'], os.listdir(rv))
1357
Christian Heimes9bd667a2008-01-20 15:14:11 +00001358
Brian Curtinc57a3452012-06-22 16:00:30 -05001359class TestWhich(unittest.TestCase):
1360
1361 def setUp(self):
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001362 self.temp_dir = tempfile.mkdtemp(prefix="Tmp")
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001363 self.addCleanup(shutil.rmtree, self.temp_dir, True)
Brian Curtinc57a3452012-06-22 16:00:30 -05001364 # Give the temp_file an ".exe" suffix for all.
1365 # It's needed on Windows and not harmful on other platforms.
1366 self.temp_file = tempfile.NamedTemporaryFile(dir=self.temp_dir,
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001367 prefix="Tmp",
1368 suffix=".Exe")
Brian Curtinc57a3452012-06-22 16:00:30 -05001369 os.chmod(self.temp_file.name, stat.S_IXUSR)
1370 self.addCleanup(self.temp_file.close)
1371 self.dir, self.file = os.path.split(self.temp_file.name)
1372
1373 def test_basic(self):
1374 # Given an EXE in a directory, it should be returned.
1375 rv = shutil.which(self.file, path=self.dir)
1376 self.assertEqual(rv, self.temp_file.name)
1377
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001378 def test_absolute_cmd(self):
Brian Curtinc57a3452012-06-22 16:00:30 -05001379 # When given the fully qualified path to an executable that exists,
1380 # it should be returned.
1381 rv = shutil.which(self.temp_file.name, path=self.temp_dir)
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001382 self.assertEqual(rv, self.temp_file.name)
1383
1384 def test_relative_cmd(self):
1385 # When given the relative path with a directory part to an executable
1386 # that exists, it should be returned.
1387 base_dir, tail_dir = os.path.split(self.dir)
1388 relpath = os.path.join(tail_dir, self.file)
Nick Coghlan55175962013-07-28 22:11:50 +10001389 with support.change_cwd(path=base_dir):
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001390 rv = shutil.which(relpath, path=self.temp_dir)
1391 self.assertEqual(rv, relpath)
1392 # But it shouldn't be searched in PATH directories (issue #16957).
Nick Coghlan55175962013-07-28 22:11:50 +10001393 with support.change_cwd(path=self.dir):
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001394 rv = shutil.which(relpath, path=base_dir)
1395 self.assertIsNone(rv)
1396
1397 def test_cwd(self):
1398 # Issue #16957
1399 base_dir = os.path.dirname(self.dir)
Nick Coghlan55175962013-07-28 22:11:50 +10001400 with support.change_cwd(path=self.dir):
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001401 rv = shutil.which(self.file, path=base_dir)
1402 if sys.platform == "win32":
1403 # Windows: current directory implicitly on PATH
1404 self.assertEqual(rv, os.path.join(os.curdir, self.file))
1405 else:
1406 # Other platforms: shouldn't match in the current directory.
1407 self.assertIsNone(rv)
Brian Curtinc57a3452012-06-22 16:00:30 -05001408
Serhiy Storchaka12516e22013-05-28 15:50:15 +03001409 @unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0,
1410 'non-root user required')
Brian Curtinc57a3452012-06-22 16:00:30 -05001411 def test_non_matching_mode(self):
1412 # Set the file read-only and ask for writeable files.
1413 os.chmod(self.temp_file.name, stat.S_IREAD)
Serhiy Storchaka12516e22013-05-28 15:50:15 +03001414 if os.access(self.temp_file.name, os.W_OK):
1415 self.skipTest("can't set the file read-only")
Brian Curtinc57a3452012-06-22 16:00:30 -05001416 rv = shutil.which(self.file, path=self.dir, mode=os.W_OK)
1417 self.assertIsNone(rv)
1418
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001419 def test_relative_path(self):
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001420 base_dir, tail_dir = os.path.split(self.dir)
Nick Coghlan55175962013-07-28 22:11:50 +10001421 with support.change_cwd(path=base_dir):
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001422 rv = shutil.which(self.file, path=tail_dir)
1423 self.assertEqual(rv, os.path.join(tail_dir, self.file))
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001424
Brian Curtinc57a3452012-06-22 16:00:30 -05001425 def test_nonexistent_file(self):
1426 # Return None when no matching executable file is found on the path.
1427 rv = shutil.which("foo.exe", path=self.dir)
1428 self.assertIsNone(rv)
1429
1430 @unittest.skipUnless(sys.platform == "win32",
1431 "pathext check is Windows-only")
1432 def test_pathext_checking(self):
1433 # Ask for the file without the ".exe" extension, then ensure that
1434 # it gets found properly with the extension.
Serhiy Storchakad70127a2013-01-24 20:03:49 +02001435 rv = shutil.which(self.file[:-4], path=self.dir)
Serhiy Storchaka80c88f42013-01-22 10:31:36 +02001436 self.assertEqual(rv, self.temp_file.name[:-4] + ".EXE")
Brian Curtinc57a3452012-06-22 16:00:30 -05001437
Barry Warsaw618738b2013-04-16 11:05:03 -04001438 def test_environ_path(self):
1439 with support.EnvironmentVarGuard() as env:
Victor Stinner1d006a22013-12-16 23:39:40 +01001440 env['PATH'] = self.dir
Barry Warsaw618738b2013-04-16 11:05:03 -04001441 rv = shutil.which(self.file)
1442 self.assertEqual(rv, self.temp_file.name)
1443
1444 def test_empty_path(self):
1445 base_dir = os.path.dirname(self.dir)
Nick Coghlan55175962013-07-28 22:11:50 +10001446 with support.change_cwd(path=self.dir), \
Barry Warsaw618738b2013-04-16 11:05:03 -04001447 support.EnvironmentVarGuard() as env:
Victor Stinner1d006a22013-12-16 23:39:40 +01001448 env['PATH'] = self.dir
Barry Warsaw618738b2013-04-16 11:05:03 -04001449 rv = shutil.which(self.file, path='')
1450 self.assertIsNone(rv)
1451
1452 def test_empty_path_no_PATH(self):
1453 with support.EnvironmentVarGuard() as env:
1454 env.pop('PATH', None)
1455 rv = shutil.which(self.file)
1456 self.assertIsNone(rv)
1457
Brian Curtinc57a3452012-06-22 16:00:30 -05001458
Christian Heimesada8c3b2008-03-18 18:26:33 +00001459class TestMove(unittest.TestCase):
1460
1461 def setUp(self):
1462 filename = "foo"
1463 self.src_dir = tempfile.mkdtemp()
1464 self.dst_dir = tempfile.mkdtemp()
1465 self.src_file = os.path.join(self.src_dir, filename)
1466 self.dst_file = os.path.join(self.dst_dir, filename)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001467 with open(self.src_file, "wb") as f:
1468 f.write(b"spam")
1469
1470 def tearDown(self):
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001471 for d in (self.src_dir, self.dst_dir):
Christian Heimesada8c3b2008-03-18 18:26:33 +00001472 try:
1473 if d:
1474 shutil.rmtree(d)
1475 except:
1476 pass
1477
1478 def _check_move_file(self, src, dst, real_dst):
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001479 with open(src, "rb") as f:
1480 contents = f.read()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001481 shutil.move(src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001482 with open(real_dst, "rb") as f:
1483 self.assertEqual(contents, f.read())
Christian Heimesada8c3b2008-03-18 18:26:33 +00001484 self.assertFalse(os.path.exists(src))
1485
1486 def _check_move_dir(self, src, dst, real_dst):
1487 contents = sorted(os.listdir(src))
1488 shutil.move(src, dst)
1489 self.assertEqual(contents, sorted(os.listdir(real_dst)))
1490 self.assertFalse(os.path.exists(src))
1491
1492 def test_move_file(self):
1493 # Move a file to another location on the same filesystem.
1494 self._check_move_file(self.src_file, self.dst_file, self.dst_file)
1495
1496 def test_move_file_to_dir(self):
1497 # Move a file inside an existing dir on the same filesystem.
1498 self._check_move_file(self.src_file, self.dst_dir, self.dst_file)
1499
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001500 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001501 def test_move_file_other_fs(self):
1502 # Move a file to an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001503 self.test_move_file()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001504
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001505 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001506 def test_move_file_to_dir_other_fs(self):
1507 # Move a file to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001508 self.test_move_file_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001509
1510 def test_move_dir(self):
1511 # Move a dir to another location on the same filesystem.
1512 dst_dir = tempfile.mktemp()
1513 try:
1514 self._check_move_dir(self.src_dir, dst_dir, dst_dir)
1515 finally:
1516 try:
1517 shutil.rmtree(dst_dir)
1518 except:
1519 pass
1520
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001521 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001522 def test_move_dir_other_fs(self):
1523 # Move a dir to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001524 self.test_move_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001525
1526 def test_move_dir_to_dir(self):
1527 # Move a dir inside an existing dir on the same filesystem.
1528 self._check_move_dir(self.src_dir, self.dst_dir,
1529 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1530
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001531 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001532 def test_move_dir_to_dir_other_fs(self):
1533 # Move a dir inside an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001534 self.test_move_dir_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001535
Serhiy Storchaka3a308b92014-02-11 10:30:59 +02001536 def test_move_dir_sep_to_dir(self):
1537 self._check_move_dir(self.src_dir + os.path.sep, self.dst_dir,
1538 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1539
1540 @unittest.skipUnless(os.path.altsep, 'requires os.path.altsep')
1541 def test_move_dir_altsep_to_dir(self):
1542 self._check_move_dir(self.src_dir + os.path.altsep, self.dst_dir,
1543 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1544
Christian Heimesada8c3b2008-03-18 18:26:33 +00001545 def test_existing_file_inside_dest_dir(self):
1546 # A file with the same name inside the destination dir already exists.
1547 with open(self.dst_file, "wb"):
1548 pass
1549 self.assertRaises(shutil.Error, shutil.move, self.src_file, self.dst_dir)
1550
1551 def test_dont_move_dir_in_itself(self):
1552 # Moving a dir inside itself raises an Error.
1553 dst = os.path.join(self.src_dir, "bar")
1554 self.assertRaises(shutil.Error, shutil.move, self.src_dir, dst)
1555
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001556 def test_destinsrc_false_negative(self):
1557 os.mkdir(TESTFN)
1558 try:
1559 for src, dst in [('srcdir', 'srcdir/dest')]:
1560 src = os.path.join(TESTFN, src)
1561 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001562 self.assertTrue(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001563 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001564 'dst (%s) is not in src (%s)' % (dst, src))
1565 finally:
1566 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001567
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001568 def test_destinsrc_false_positive(self):
1569 os.mkdir(TESTFN)
1570 try:
1571 for src, dst in [('srcdir', 'src/dest'), ('srcdir', 'srcdir.new')]:
1572 src = os.path.join(TESTFN, src)
1573 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001574 self.assertFalse(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001575 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001576 'dst (%s) is in src (%s)' % (dst, src))
1577 finally:
1578 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimes9bd667a2008-01-20 15:14:11 +00001579
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +01001580 @support.skip_unless_symlink
1581 @mock_rename
1582 def test_move_file_symlink(self):
1583 dst = os.path.join(self.src_dir, 'bar')
1584 os.symlink(self.src_file, dst)
1585 shutil.move(dst, self.dst_file)
1586 self.assertTrue(os.path.islink(self.dst_file))
1587 self.assertTrue(os.path.samefile(self.src_file, self.dst_file))
1588
1589 @support.skip_unless_symlink
1590 @mock_rename
1591 def test_move_file_symlink_to_dir(self):
1592 filename = "bar"
1593 dst = os.path.join(self.src_dir, filename)
1594 os.symlink(self.src_file, dst)
1595 shutil.move(dst, self.dst_dir)
1596 final_link = os.path.join(self.dst_dir, filename)
1597 self.assertTrue(os.path.islink(final_link))
1598 self.assertTrue(os.path.samefile(self.src_file, final_link))
1599
1600 @support.skip_unless_symlink
1601 @mock_rename
1602 def test_move_dangling_symlink(self):
1603 src = os.path.join(self.src_dir, 'baz')
1604 dst = os.path.join(self.src_dir, 'bar')
1605 os.symlink(src, dst)
1606 dst_link = os.path.join(self.dst_dir, 'quux')
1607 shutil.move(dst, dst_link)
1608 self.assertTrue(os.path.islink(dst_link))
Antoine Pitrou3f48ac92014-01-01 02:50:45 +01001609 # On Windows, os.path.realpath does not follow symlinks (issue #9949)
1610 if os.name == 'nt':
1611 self.assertEqual(os.path.realpath(src), os.readlink(dst_link))
1612 else:
1613 self.assertEqual(os.path.realpath(src), os.path.realpath(dst_link))
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +01001614
1615 @support.skip_unless_symlink
1616 @mock_rename
1617 def test_move_dir_symlink(self):
1618 src = os.path.join(self.src_dir, 'baz')
1619 dst = os.path.join(self.src_dir, 'bar')
1620 os.mkdir(src)
1621 os.symlink(src, dst)
1622 dst_link = os.path.join(self.dst_dir, 'quux')
1623 shutil.move(dst, dst_link)
1624 self.assertTrue(os.path.islink(dst_link))
1625 self.assertTrue(os.path.samefile(src, dst_link))
1626
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001627 def test_move_return_value(self):
1628 rv = shutil.move(self.src_file, self.dst_dir)
1629 self.assertEqual(rv,
1630 os.path.join(self.dst_dir, os.path.basename(self.src_file)))
1631
1632 def test_move_as_rename_return_value(self):
1633 rv = shutil.move(self.src_file, os.path.join(self.dst_dir, 'bar'))
1634 self.assertEqual(rv, os.path.join(self.dst_dir, 'bar'))
1635
R David Murray6ffface2014-06-11 14:40:13 -04001636 @mock_rename
1637 def test_move_file_special_function(self):
1638 moved = []
1639 def _copy(src, dst):
1640 moved.append((src, dst))
1641 shutil.move(self.src_file, self.dst_dir, copy_function=_copy)
1642 self.assertEqual(len(moved), 1)
1643
1644 @mock_rename
1645 def test_move_dir_special_function(self):
1646 moved = []
1647 def _copy(src, dst):
1648 moved.append((src, dst))
1649 support.create_empty_file(os.path.join(self.src_dir, 'child'))
1650 support.create_empty_file(os.path.join(self.src_dir, 'child1'))
1651 shutil.move(self.src_dir, self.dst_dir, copy_function=_copy)
1652 self.assertEqual(len(moved), 3)
1653
Tarek Ziadé5340db32010-04-19 22:30:51 +00001654
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001655class TestCopyFile(unittest.TestCase):
1656
1657 _delete = False
1658
1659 class Faux(object):
1660 _entered = False
1661 _exited_with = None
1662 _raised = False
1663 def __init__(self, raise_in_exit=False, suppress_at_exit=True):
1664 self._raise_in_exit = raise_in_exit
1665 self._suppress_at_exit = suppress_at_exit
1666 def read(self, *args):
1667 return ''
1668 def __enter__(self):
1669 self._entered = True
1670 def __exit__(self, exc_type, exc_val, exc_tb):
1671 self._exited_with = exc_type, exc_val, exc_tb
1672 if self._raise_in_exit:
1673 self._raised = True
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001674 raise OSError("Cannot close")
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001675 return self._suppress_at_exit
1676
1677 def tearDown(self):
1678 if self._delete:
1679 del shutil.open
1680
1681 def _set_shutil_open(self, func):
1682 shutil.open = func
1683 self._delete = True
1684
1685 def test_w_source_open_fails(self):
1686 def _open(filename, mode='r'):
1687 if filename == 'srcfile':
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001688 raise OSError('Cannot open "srcfile"')
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001689 assert 0 # shouldn't reach here.
1690
1691 self._set_shutil_open(_open)
1692
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001693 self.assertRaises(OSError, shutil.copyfile, 'srcfile', 'destfile')
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001694
1695 def test_w_dest_open_fails(self):
1696
1697 srcfile = self.Faux()
1698
1699 def _open(filename, mode='r'):
1700 if filename == 'srcfile':
1701 return srcfile
1702 if filename == 'destfile':
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001703 raise OSError('Cannot open "destfile"')
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001704 assert 0 # shouldn't reach here.
1705
1706 self._set_shutil_open(_open)
1707
1708 shutil.copyfile('srcfile', 'destfile')
1709 self.assertTrue(srcfile._entered)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001710 self.assertTrue(srcfile._exited_with[0] is OSError)
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001711 self.assertEqual(srcfile._exited_with[1].args,
1712 ('Cannot open "destfile"',))
1713
1714 def test_w_dest_close_fails(self):
1715
1716 srcfile = self.Faux()
1717 destfile = self.Faux(True)
1718
1719 def _open(filename, mode='r'):
1720 if filename == 'srcfile':
1721 return srcfile
1722 if filename == 'destfile':
1723 return destfile
1724 assert 0 # shouldn't reach here.
1725
1726 self._set_shutil_open(_open)
1727
1728 shutil.copyfile('srcfile', 'destfile')
1729 self.assertTrue(srcfile._entered)
1730 self.assertTrue(destfile._entered)
1731 self.assertTrue(destfile._raised)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001732 self.assertTrue(srcfile._exited_with[0] is OSError)
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001733 self.assertEqual(srcfile._exited_with[1].args,
1734 ('Cannot close',))
1735
1736 def test_w_source_close_fails(self):
1737
1738 srcfile = self.Faux(True)
1739 destfile = self.Faux()
1740
1741 def _open(filename, mode='r'):
1742 if filename == 'srcfile':
1743 return srcfile
1744 if filename == 'destfile':
1745 return destfile
1746 assert 0 # shouldn't reach here.
1747
1748 self._set_shutil_open(_open)
1749
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001750 self.assertRaises(OSError,
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001751 shutil.copyfile, 'srcfile', 'destfile')
1752 self.assertTrue(srcfile._entered)
1753 self.assertTrue(destfile._entered)
1754 self.assertFalse(destfile._raised)
1755 self.assertTrue(srcfile._exited_with[0] is None)
1756 self.assertTrue(srcfile._raised)
1757
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001758 def test_move_dir_caseinsensitive(self):
1759 # Renames a folder to the same name
1760 # but a different case.
1761
1762 self.src_dir = tempfile.mkdtemp()
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001763 self.addCleanup(shutil.rmtree, self.src_dir, True)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001764 dst_dir = os.path.join(
1765 os.path.dirname(self.src_dir),
1766 os.path.basename(self.src_dir).upper())
1767 self.assertNotEqual(self.src_dir, dst_dir)
1768
1769 try:
1770 shutil.move(self.src_dir, dst_dir)
1771 self.assertTrue(os.path.isdir(dst_dir))
1772 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +02001773 os.rmdir(dst_dir)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001774
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001775class TermsizeTests(unittest.TestCase):
1776 def test_does_not_crash(self):
1777 """Check if get_terminal_size() returns a meaningful value.
1778
1779 There's no easy portable way to actually check the size of the
1780 terminal, so let's check if it returns something sensible instead.
1781 """
1782 size = shutil.get_terminal_size()
Antoine Pitroucfade362012-02-08 23:48:59 +01001783 self.assertGreaterEqual(size.columns, 0)
1784 self.assertGreaterEqual(size.lines, 0)
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001785
1786 def test_os_environ_first(self):
1787 "Check if environment variables have precedence"
1788
1789 with support.EnvironmentVarGuard() as env:
1790 env['COLUMNS'] = '777'
1791 size = shutil.get_terminal_size()
1792 self.assertEqual(size.columns, 777)
1793
1794 with support.EnvironmentVarGuard() as env:
1795 env['LINES'] = '888'
1796 size = shutil.get_terminal_size()
1797 self.assertEqual(size.lines, 888)
1798
1799 @unittest.skipUnless(os.isatty(sys.__stdout__.fileno()), "not on tty")
1800 def test_stty_match(self):
1801 """Check if stty returns the same results ignoring env
1802
1803 This test will fail if stdin and stdout are connected to
1804 different terminals with different sizes. Nevertheless, such
1805 situations should be pretty rare.
1806 """
1807 try:
1808 size = subprocess.check_output(['stty', 'size']).decode().split()
1809 except (FileNotFoundError, subprocess.CalledProcessError):
1810 self.skipTest("stty invocation failed")
1811 expected = (int(size[1]), int(size[0])) # reversed order
1812
1813 with support.EnvironmentVarGuard() as env:
1814 del env['LINES']
1815 del env['COLUMNS']
1816 actual = shutil.get_terminal_size()
1817
1818 self.assertEqual(expected, actual)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001819
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001820
Berker Peksag8083cd62014-11-01 11:04:06 +02001821class PublicAPITests(unittest.TestCase):
1822 """Ensures that the correct values are exposed in the public API."""
1823
1824 def test_module_all_attribute(self):
1825 self.assertTrue(hasattr(shutil, '__all__'))
1826 target_api = ['copyfileobj', 'copyfile', 'copymode', 'copystat',
1827 'copy', 'copy2', 'copytree', 'move', 'rmtree', 'Error',
1828 'SpecialFileError', 'ExecError', 'make_archive',
1829 'get_archive_formats', 'register_archive_format',
1830 'unregister_archive_format', 'get_unpack_formats',
1831 'register_unpack_format', 'unregister_unpack_format',
1832 'unpack_archive', 'ignore_patterns', 'chown', 'which',
1833 'get_terminal_size', 'SameFileError']
1834 if hasattr(os, 'statvfs') or os.name == 'nt':
1835 target_api.append('disk_usage')
1836 self.assertEqual(set(shutil.__all__), set(target_api))
1837
1838
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001839if __name__ == '__main__':
Brett Cannon3e9a9ae2013-06-12 21:25:59 -04001840 unittest.main()