blob: 709feebf017a25f3e8a259624420f75bfb86981c [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
Serhiy Storchaka527ef072015-09-06 18:33:19 +030015from shutil import (make_archive,
Tarek Ziadé396fad72010-02-23 05:30:31 +000016 register_archive_format, unregister_archive_format,
Tarek Ziadé6ac91722010-04-28 17:51:36 +000017 get_archive_formats, Error, unpack_archive,
18 register_unpack_format, RegistryError,
Hynek Schlawack48653762012-10-07 12:49:58 +020019 unregister_unpack_format, get_unpack_formats,
20 SameFileError)
Tarek Ziadé396fad72010-02-23 05:30:31 +000021import tarfile
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +020022import zipfile
Tarek Ziadé396fad72010-02-23 05:30:31 +000023import warnings
24
25from test import support
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +020026from test.support import TESTFN, check_warnings, captured_stdout
Serhiy Storchaka11213772014-08-06 18:50:19 +030027
Antoine Pitrou7fff0962009-05-01 21:09:44 +000028TESTFN2 = TESTFN + "2"
Barry Warsaw7fc2cca2003-01-24 17:34:13 +000029
Tarek Ziadé396fad72010-02-23 05:30:31 +000030try:
31 import grp
32 import pwd
33 UID_GID_SUPPORT = True
34except ImportError:
35 UID_GID_SUPPORT = False
36
Nick Coghlan8ed3cf32011-03-16 14:05:35 -040037def _fake_rename(*args, **kwargs):
38 # Pretend the destination path is on a different filesystem.
Antoine Pitrouc041ab62012-01-02 19:18:02 +010039 raise OSError(getattr(errno, 'EXDEV', 18), "Invalid cross-device link")
Nick Coghlan8ed3cf32011-03-16 14:05:35 -040040
41def mock_rename(func):
42 @functools.wraps(func)
43 def wrap(*args, **kwargs):
44 try:
45 builtin_rename = os.rename
46 os.rename = _fake_rename
47 return func(*args, **kwargs)
48 finally:
49 os.rename = builtin_rename
50 return wrap
51
Éric Araujoa7e33a12011-08-12 19:51:35 +020052def write_file(path, content, binary=False):
53 """Write *content* to a file located at *path*.
54
55 If *path* is a tuple instead of a string, os.path.join will be used to
56 make a path. If *binary* is true, the file will be opened in binary
57 mode.
58 """
59 if isinstance(path, tuple):
60 path = os.path.join(*path)
61 with open(path, 'wb' if binary else 'w') as fp:
62 fp.write(content)
63
64def read_file(path, binary=False):
65 """Return contents from a file located at *path*.
66
67 If *path* is a tuple instead of a string, os.path.join will be used to
68 make a path. If *binary* is true, the file will be opened in binary
69 mode.
70 """
71 if isinstance(path, tuple):
72 path = os.path.join(*path)
73 with open(path, 'rb' if binary else 'r') as fp:
74 return fp.read()
75
Serhiy Storchaka527ef072015-09-06 18:33:19 +030076def rlistdir(path):
77 res = []
78 for name in sorted(os.listdir(path)):
79 p = os.path.join(path, name)
80 if os.path.isdir(p) and not os.path.islink(p):
81 res.append(name + '/')
82 for n in rlistdir(p):
83 res.append(name + '/' + n)
84 else:
85 res.append(name)
86 return res
87
Éric Araujoa7e33a12011-08-12 19:51:35 +020088
Barry Warsaw7fc2cca2003-01-24 17:34:13 +000089class TestShutil(unittest.TestCase):
Tarek Ziadé396fad72010-02-23 05:30:31 +000090
91 def setUp(self):
92 super(TestShutil, self).setUp()
93 self.tempdirs = []
94
95 def tearDown(self):
96 super(TestShutil, self).tearDown()
97 while self.tempdirs:
98 d = self.tempdirs.pop()
99 shutil.rmtree(d, os.name in ('nt', 'cygwin'))
100
Tarek Ziadé396fad72010-02-23 05:30:31 +0000101
102 def mkdtemp(self):
103 """Create a temporary directory that will be cleaned up.
104
105 Returns the path of the directory.
106 """
107 d = tempfile.mkdtemp()
108 self.tempdirs.append(d)
109 return d
Tarek Ziadé5340db32010-04-19 22:30:51 +0000110
Hynek Schlawack3b527782012-06-25 13:27:31 +0200111 def test_rmtree_works_on_bytes(self):
112 tmp = self.mkdtemp()
113 victim = os.path.join(tmp, 'killme')
114 os.mkdir(victim)
115 write_file(os.path.join(victim, 'somefile'), 'foo')
116 victim = os.fsencode(victim)
117 self.assertIsInstance(victim, bytes)
Serhiy Storchaka41ad77c2014-08-07 19:38:37 +0300118 win = (os.name == 'nt')
119 with self.assertWarns(DeprecationWarning) if win else ExitStack():
120 shutil.rmtree(victim)
Hynek Schlawack3b527782012-06-25 13:27:31 +0200121
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200122 @support.skip_unless_symlink
123 def test_rmtree_fails_on_symlink(self):
124 tmp = self.mkdtemp()
125 dir_ = os.path.join(tmp, 'dir')
126 os.mkdir(dir_)
127 link = os.path.join(tmp, 'link')
128 os.symlink(dir_, link)
129 self.assertRaises(OSError, shutil.rmtree, link)
130 self.assertTrue(os.path.exists(dir_))
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100131 self.assertTrue(os.path.lexists(link))
132 errors = []
133 def onerror(*args):
134 errors.append(args)
135 shutil.rmtree(link, onerror=onerror)
136 self.assertEqual(len(errors), 1)
137 self.assertIs(errors[0][0], os.path.islink)
138 self.assertEqual(errors[0][1], link)
139 self.assertIsInstance(errors[0][2][1], OSError)
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200140
141 @support.skip_unless_symlink
142 def test_rmtree_works_on_symlinks(self):
143 tmp = self.mkdtemp()
144 dir1 = os.path.join(tmp, 'dir1')
145 dir2 = os.path.join(dir1, 'dir2')
146 dir3 = os.path.join(tmp, 'dir3')
147 for d in dir1, dir2, dir3:
148 os.mkdir(d)
149 file1 = os.path.join(tmp, 'file1')
150 write_file(file1, 'foo')
151 link1 = os.path.join(dir1, 'link1')
152 os.symlink(dir2, link1)
153 link2 = os.path.join(dir1, 'link2')
154 os.symlink(dir3, link2)
155 link3 = os.path.join(dir1, 'link3')
156 os.symlink(file1, link3)
157 # make sure symlinks are removed but not followed
158 shutil.rmtree(dir1)
159 self.assertFalse(os.path.exists(dir1))
160 self.assertTrue(os.path.exists(dir3))
161 self.assertTrue(os.path.exists(file1))
162
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000163 def test_rmtree_errors(self):
164 # filename is guaranteed not to exist
165 filename = tempfile.mktemp()
Hynek Schlawackb5501102012-12-10 09:11:25 +0100166 self.assertRaises(FileNotFoundError, shutil.rmtree, filename)
167 # test that ignore_errors option is honored
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100168 shutil.rmtree(filename, ignore_errors=True)
169
170 # existing file
171 tmpdir = self.mkdtemp()
Hynek Schlawackb5501102012-12-10 09:11:25 +0100172 write_file((tmpdir, "tstfile"), "")
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100173 filename = os.path.join(tmpdir, "tstfile")
Hynek Schlawackb5501102012-12-10 09:11:25 +0100174 with self.assertRaises(NotADirectoryError) as cm:
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100175 shutil.rmtree(filename)
Hynek Schlawack87f9b462012-12-10 16:29:57 +0100176 # The reason for this rather odd construct is that Windows sprinkles
177 # a \*.* at the end of file names. But only sometimes on some buildbots
178 possible_args = [filename, os.path.join(filename, '*.*')]
179 self.assertIn(cm.exception.filename, possible_args)
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100180 self.assertTrue(os.path.exists(filename))
Hynek Schlawackb5501102012-12-10 09:11:25 +0100181 # test that ignore_errors option is honored
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100182 shutil.rmtree(filename, ignore_errors=True)
183 self.assertTrue(os.path.exists(filename))
184 errors = []
185 def onerror(*args):
186 errors.append(args)
187 shutil.rmtree(filename, onerror=onerror)
188 self.assertEqual(len(errors), 2)
189 self.assertIs(errors[0][0], os.listdir)
190 self.assertEqual(errors[0][1], filename)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100191 self.assertIsInstance(errors[0][2][1], NotADirectoryError)
Hynek Schlawack87f9b462012-12-10 16:29:57 +0100192 self.assertIn(errors[0][2][1].filename, possible_args)
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100193 self.assertIs(errors[1][0], os.rmdir)
194 self.assertEqual(errors[1][1], filename)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100195 self.assertIsInstance(errors[1][2][1], NotADirectoryError)
Hynek Schlawack87f9b462012-12-10 16:29:57 +0100196 self.assertIn(errors[1][2][1].filename, possible_args)
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000197
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000198
Serhiy Storchaka43767632013-11-03 21:31:38 +0200199 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod()')
200 @unittest.skipIf(sys.platform[:6] == 'cygwin',
201 "This test can't be run on Cygwin (issue #1071513).")
202 @unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0,
203 "This test can't be run reliably as root (issue #1076467).")
204 def test_on_error(self):
205 self.errorState = 0
206 os.mkdir(TESTFN)
207 self.addCleanup(shutil.rmtree, TESTFN)
Antoine Pitrou2f8a75c2012-06-23 21:28:15 +0200208
Serhiy Storchaka43767632013-11-03 21:31:38 +0200209 self.child_file_path = os.path.join(TESTFN, 'a')
210 self.child_dir_path = os.path.join(TESTFN, 'b')
211 support.create_empty_file(self.child_file_path)
212 os.mkdir(self.child_dir_path)
213 old_dir_mode = os.stat(TESTFN).st_mode
214 old_child_file_mode = os.stat(self.child_file_path).st_mode
215 old_child_dir_mode = os.stat(self.child_dir_path).st_mode
216 # Make unwritable.
217 new_mode = stat.S_IREAD|stat.S_IEXEC
218 os.chmod(self.child_file_path, new_mode)
219 os.chmod(self.child_dir_path, new_mode)
220 os.chmod(TESTFN, new_mode)
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000221
Serhiy Storchaka43767632013-11-03 21:31:38 +0200222 self.addCleanup(os.chmod, TESTFN, old_dir_mode)
223 self.addCleanup(os.chmod, self.child_file_path, old_child_file_mode)
224 self.addCleanup(os.chmod, self.child_dir_path, old_child_dir_mode)
Antoine Pitrou2f8a75c2012-06-23 21:28:15 +0200225
Serhiy Storchaka43767632013-11-03 21:31:38 +0200226 shutil.rmtree(TESTFN, onerror=self.check_args_to_onerror)
227 # Test whether onerror has actually been called.
228 self.assertEqual(self.errorState, 3,
229 "Expected call to onerror function did not happen.")
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000230
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000231 def check_args_to_onerror(self, func, arg, exc):
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000232 # test_rmtree_errors deliberately runs rmtree
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200233 # on a directory that is chmod 500, which will fail.
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000234 # This function is run when shutil.rmtree fails.
235 # 99.9% of the time it initially fails to remove
236 # a file in the directory, so the first time through
237 # func is os.remove.
238 # However, some Linux machines running ZFS on
239 # FUSE experienced a failure earlier in the process
240 # at os.listdir. The first failure may legally
241 # be either.
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200242 if self.errorState < 2:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200243 if func is os.unlink:
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200244 self.assertEqual(arg, self.child_file_path)
245 elif func is os.rmdir:
246 self.assertEqual(arg, self.child_dir_path)
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000247 else:
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200248 self.assertIs(func, os.listdir)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200249 self.assertIn(arg, [TESTFN, self.child_dir_path])
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000250 self.assertTrue(issubclass(exc[0], OSError))
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200251 self.errorState += 1
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000252 else:
253 self.assertEqual(func, os.rmdir)
254 self.assertEqual(arg, TESTFN)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000255 self.assertTrue(issubclass(exc[0], OSError))
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200256 self.errorState = 3
257
258 def test_rmtree_does_not_choke_on_failing_lstat(self):
259 try:
260 orig_lstat = os.lstat
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200261 def raiser(fn, *args, **kwargs):
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200262 if fn != TESTFN:
263 raise OSError()
264 else:
265 return orig_lstat(fn)
266 os.lstat = raiser
267
268 os.mkdir(TESTFN)
269 write_file((TESTFN, 'foo'), 'foo')
270 shutil.rmtree(TESTFN)
271 finally:
272 os.lstat = orig_lstat
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000273
Antoine Pitrou78091e62011-12-29 18:54:15 +0100274 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
275 @support.skip_unless_symlink
276 def test_copymode_follow_symlinks(self):
277 tmp_dir = self.mkdtemp()
278 src = os.path.join(tmp_dir, 'foo')
279 dst = os.path.join(tmp_dir, 'bar')
280 src_link = os.path.join(tmp_dir, 'baz')
281 dst_link = os.path.join(tmp_dir, 'quux')
282 write_file(src, 'foo')
283 write_file(dst, 'foo')
284 os.symlink(src, src_link)
285 os.symlink(dst, dst_link)
286 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
287 # file to file
288 os.chmod(dst, stat.S_IRWXO)
289 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
290 shutil.copymode(src, dst)
291 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
Antoine Pitrou3f48ac92014-01-01 02:50:45 +0100292 # On Windows, os.chmod does not follow symlinks (issue #15411)
293 if os.name != 'nt':
294 # follow src link
295 os.chmod(dst, stat.S_IRWXO)
296 shutil.copymode(src_link, dst)
297 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
298 # follow dst link
299 os.chmod(dst, stat.S_IRWXO)
300 shutil.copymode(src, dst_link)
301 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
302 # follow both links
303 os.chmod(dst, stat.S_IRWXO)
304 shutil.copymode(src_link, dst_link)
305 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100306
307 @unittest.skipUnless(hasattr(os, 'lchmod'), 'requires os.lchmod')
308 @support.skip_unless_symlink
309 def test_copymode_symlink_to_symlink(self):
310 tmp_dir = self.mkdtemp()
311 src = os.path.join(tmp_dir, 'foo')
312 dst = os.path.join(tmp_dir, 'bar')
313 src_link = os.path.join(tmp_dir, 'baz')
314 dst_link = os.path.join(tmp_dir, 'quux')
315 write_file(src, 'foo')
316 write_file(dst, 'foo')
317 os.symlink(src, src_link)
318 os.symlink(dst, dst_link)
319 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
320 os.chmod(dst, stat.S_IRWXU)
321 os.lchmod(src_link, stat.S_IRWXO|stat.S_IRWXG)
322 # link to link
323 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700324 shutil.copymode(src_link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100325 self.assertEqual(os.lstat(src_link).st_mode,
326 os.lstat(dst_link).st_mode)
327 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
328 # src link - use chmod
329 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700330 shutil.copymode(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100331 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
332 # dst link - use chmod
333 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700334 shutil.copymode(src, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100335 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
336
337 @unittest.skipIf(hasattr(os, 'lchmod'), 'requires os.lchmod to be missing')
338 @support.skip_unless_symlink
339 def test_copymode_symlink_to_symlink_wo_lchmod(self):
340 tmp_dir = self.mkdtemp()
341 src = os.path.join(tmp_dir, 'foo')
342 dst = os.path.join(tmp_dir, 'bar')
343 src_link = os.path.join(tmp_dir, 'baz')
344 dst_link = os.path.join(tmp_dir, 'quux')
345 write_file(src, 'foo')
346 write_file(dst, 'foo')
347 os.symlink(src, src_link)
348 os.symlink(dst, dst_link)
Larry Hastingsb4038062012-07-15 10:57:38 -0700349 shutil.copymode(src_link, dst_link, follow_symlinks=False) # silent fail
Antoine Pitrou78091e62011-12-29 18:54:15 +0100350
351 @support.skip_unless_symlink
352 def test_copystat_symlinks(self):
353 tmp_dir = self.mkdtemp()
354 src = os.path.join(tmp_dir, 'foo')
355 dst = os.path.join(tmp_dir, 'bar')
356 src_link = os.path.join(tmp_dir, 'baz')
357 dst_link = os.path.join(tmp_dir, 'qux')
358 write_file(src, 'foo')
359 src_stat = os.stat(src)
360 os.utime(src, (src_stat.st_atime,
361 src_stat.st_mtime - 42.0)) # ensure different mtimes
362 write_file(dst, 'bar')
363 self.assertNotEqual(os.stat(src).st_mtime, os.stat(dst).st_mtime)
364 os.symlink(src, src_link)
365 os.symlink(dst, dst_link)
366 if hasattr(os, 'lchmod'):
367 os.lchmod(src_link, stat.S_IRWXO)
368 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
369 os.lchflags(src_link, stat.UF_NODUMP)
370 src_link_stat = os.lstat(src_link)
371 # follow
372 if hasattr(os, 'lchmod'):
Larry Hastingsb4038062012-07-15 10:57:38 -0700373 shutil.copystat(src_link, dst_link, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100374 self.assertNotEqual(src_link_stat.st_mode, os.stat(dst).st_mode)
375 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700376 shutil.copystat(src_link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100377 dst_link_stat = os.lstat(dst_link)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700378 if os.utime in os.supports_follow_symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100379 for attr in 'st_atime', 'st_mtime':
380 # The modification times may be truncated in the new file.
381 self.assertLessEqual(getattr(src_link_stat, attr),
382 getattr(dst_link_stat, attr) + 1)
383 if hasattr(os, 'lchmod'):
384 self.assertEqual(src_link_stat.st_mode, dst_link_stat.st_mode)
385 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
386 self.assertEqual(src_link_stat.st_flags, dst_link_stat.st_flags)
387 # tell to follow but dst is not a link
Larry Hastingsb4038062012-07-15 10:57:38 -0700388 shutil.copystat(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100389 self.assertTrue(abs(os.stat(src).st_mtime - os.stat(dst).st_mtime) <
390 00000.1)
391
Ned Deilybaf75712012-05-10 17:05:19 -0700392 @unittest.skipUnless(hasattr(os, 'chflags') and
393 hasattr(errno, 'EOPNOTSUPP') and
394 hasattr(errno, 'ENOTSUP'),
395 "requires os.chflags, EOPNOTSUPP & ENOTSUP")
396 def test_copystat_handles_harmless_chflags_errors(self):
397 tmpdir = self.mkdtemp()
398 file1 = os.path.join(tmpdir, 'file1')
399 file2 = os.path.join(tmpdir, 'file2')
400 write_file(file1, 'xxx')
401 write_file(file2, 'xxx')
402
403 def make_chflags_raiser(err):
404 ex = OSError()
405
Larry Hastings90867a52012-06-22 17:01:41 -0700406 def _chflags_raiser(path, flags, *, follow_symlinks=True):
Ned Deilybaf75712012-05-10 17:05:19 -0700407 ex.errno = err
408 raise ex
409 return _chflags_raiser
410 old_chflags = os.chflags
411 try:
412 for err in errno.EOPNOTSUPP, errno.ENOTSUP:
413 os.chflags = make_chflags_raiser(err)
414 shutil.copystat(file1, file2)
415 # assert others errors break it
416 os.chflags = make_chflags_raiser(errno.EOPNOTSUPP + errno.ENOTSUP)
417 self.assertRaises(OSError, shutil.copystat, file1, file2)
418 finally:
419 os.chflags = old_chflags
420
Antoine Pitrou424246f2012-05-12 19:02:01 +0200421 @support.skip_unless_xattr
422 def test_copyxattr(self):
423 tmp_dir = self.mkdtemp()
424 src = os.path.join(tmp_dir, 'foo')
425 write_file(src, 'foo')
426 dst = os.path.join(tmp_dir, 'bar')
427 write_file(dst, 'bar')
428
429 # no xattr == no problem
430 shutil._copyxattr(src, dst)
431 # common case
432 os.setxattr(src, 'user.foo', b'42')
433 os.setxattr(src, 'user.bar', b'43')
434 shutil._copyxattr(src, dst)
Gregory P. Smith1093bf22014-01-17 12:01:22 -0800435 self.assertEqual(sorted(os.listxattr(src)), sorted(os.listxattr(dst)))
Antoine Pitrou424246f2012-05-12 19:02:01 +0200436 self.assertEqual(
437 os.getxattr(src, 'user.foo'),
438 os.getxattr(dst, 'user.foo'))
439 # check errors don't affect other attrs
440 os.remove(dst)
441 write_file(dst, 'bar')
442 os_error = OSError(errno.EPERM, 'EPERM')
443
Larry Hastings9cf065c2012-06-22 16:30:09 -0700444 def _raise_on_user_foo(fname, attr, val, **kwargs):
Antoine Pitrou424246f2012-05-12 19:02:01 +0200445 if attr == 'user.foo':
446 raise os_error
447 else:
Larry Hastings9cf065c2012-06-22 16:30:09 -0700448 orig_setxattr(fname, attr, val, **kwargs)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200449 try:
450 orig_setxattr = os.setxattr
451 os.setxattr = _raise_on_user_foo
452 shutil._copyxattr(src, dst)
Antoine Pitrou61597d32012-05-12 23:37:35 +0200453 self.assertIn('user.bar', os.listxattr(dst))
Antoine Pitrou424246f2012-05-12 19:02:01 +0200454 finally:
455 os.setxattr = orig_setxattr
Hynek Schlawack0beab052013-02-05 08:22:44 +0100456 # the source filesystem not supporting xattrs should be ok, too.
457 def _raise_on_src(fname, *, follow_symlinks=True):
458 if fname == src:
459 raise OSError(errno.ENOTSUP, 'Operation not supported')
460 return orig_listxattr(fname, follow_symlinks=follow_symlinks)
461 try:
462 orig_listxattr = os.listxattr
463 os.listxattr = _raise_on_src
464 shutil._copyxattr(src, dst)
465 finally:
466 os.listxattr = orig_listxattr
Antoine Pitrou424246f2012-05-12 19:02:01 +0200467
Larry Hastingsad5ae042012-07-14 17:55:11 -0700468 # test that shutil.copystat copies xattrs
469 src = os.path.join(tmp_dir, 'the_original')
470 write_file(src, src)
471 os.setxattr(src, 'user.the_value', b'fiddly')
472 dst = os.path.join(tmp_dir, 'the_copy')
473 write_file(dst, dst)
474 shutil.copystat(src, dst)
Hynek Schlawackc2d481f2012-07-16 17:11:10 +0200475 self.assertEqual(os.getxattr(dst, 'user.the_value'), b'fiddly')
Larry Hastingsad5ae042012-07-14 17:55:11 -0700476
Antoine Pitrou424246f2012-05-12 19:02:01 +0200477 @support.skip_unless_symlink
478 @support.skip_unless_xattr
479 @unittest.skipUnless(hasattr(os, 'geteuid') and os.geteuid() == 0,
480 'root privileges required')
481 def test_copyxattr_symlinks(self):
482 # On Linux, it's only possible to access non-user xattr for symlinks;
483 # which in turn require root privileges. This test should be expanded
484 # as soon as other platforms gain support for extended attributes.
485 tmp_dir = self.mkdtemp()
486 src = os.path.join(tmp_dir, 'foo')
487 src_link = os.path.join(tmp_dir, 'baz')
488 write_file(src, 'foo')
489 os.symlink(src, src_link)
490 os.setxattr(src, 'trusted.foo', b'42')
Larry Hastings9cf065c2012-06-22 16:30:09 -0700491 os.setxattr(src_link, 'trusted.foo', b'43', follow_symlinks=False)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200492 dst = os.path.join(tmp_dir, 'bar')
493 dst_link = os.path.join(tmp_dir, 'qux')
494 write_file(dst, 'bar')
495 os.symlink(dst, dst_link)
Larry Hastingsb4038062012-07-15 10:57:38 -0700496 shutil._copyxattr(src_link, dst_link, follow_symlinks=False)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700497 self.assertEqual(os.getxattr(dst_link, 'trusted.foo', follow_symlinks=False), b'43')
Antoine Pitrou424246f2012-05-12 19:02:01 +0200498 self.assertRaises(OSError, os.getxattr, dst, 'trusted.foo')
Larry Hastingsb4038062012-07-15 10:57:38 -0700499 shutil._copyxattr(src_link, dst, follow_symlinks=False)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200500 self.assertEqual(os.getxattr(dst, 'trusted.foo'), b'43')
501
Antoine Pitrou78091e62011-12-29 18:54:15 +0100502 @support.skip_unless_symlink
503 def test_copy_symlinks(self):
504 tmp_dir = self.mkdtemp()
505 src = os.path.join(tmp_dir, 'foo')
506 dst = os.path.join(tmp_dir, 'bar')
507 src_link = os.path.join(tmp_dir, 'baz')
508 write_file(src, 'foo')
509 os.symlink(src, src_link)
510 if hasattr(os, 'lchmod'):
511 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
512 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700513 shutil.copy(src_link, dst, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100514 self.assertFalse(os.path.islink(dst))
515 self.assertEqual(read_file(src), read_file(dst))
516 os.remove(dst)
517 # follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700518 shutil.copy(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100519 self.assertTrue(os.path.islink(dst))
520 self.assertEqual(os.readlink(dst), os.readlink(src_link))
521 if hasattr(os, 'lchmod'):
522 self.assertEqual(os.lstat(src_link).st_mode,
523 os.lstat(dst).st_mode)
524
525 @support.skip_unless_symlink
526 def test_copy2_symlinks(self):
527 tmp_dir = self.mkdtemp()
528 src = os.path.join(tmp_dir, 'foo')
529 dst = os.path.join(tmp_dir, 'bar')
530 src_link = os.path.join(tmp_dir, 'baz')
531 write_file(src, 'foo')
532 os.symlink(src, src_link)
533 if hasattr(os, 'lchmod'):
534 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
535 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
536 os.lchflags(src_link, stat.UF_NODUMP)
537 src_stat = os.stat(src)
538 src_link_stat = os.lstat(src_link)
539 # follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700540 shutil.copy2(src_link, dst, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100541 self.assertFalse(os.path.islink(dst))
542 self.assertEqual(read_file(src), read_file(dst))
543 os.remove(dst)
544 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700545 shutil.copy2(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100546 self.assertTrue(os.path.islink(dst))
547 self.assertEqual(os.readlink(dst), os.readlink(src_link))
548 dst_stat = os.lstat(dst)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700549 if os.utime in os.supports_follow_symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100550 for attr in 'st_atime', 'st_mtime':
551 # The modification times may be truncated in the new file.
552 self.assertLessEqual(getattr(src_link_stat, attr),
553 getattr(dst_stat, attr) + 1)
554 if hasattr(os, 'lchmod'):
555 self.assertEqual(src_link_stat.st_mode, dst_stat.st_mode)
556 self.assertNotEqual(src_stat.st_mode, dst_stat.st_mode)
557 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
558 self.assertEqual(src_link_stat.st_flags, dst_stat.st_flags)
559
Antoine Pitrou424246f2012-05-12 19:02:01 +0200560 @support.skip_unless_xattr
561 def test_copy2_xattr(self):
562 tmp_dir = self.mkdtemp()
563 src = os.path.join(tmp_dir, 'foo')
564 dst = os.path.join(tmp_dir, 'bar')
565 write_file(src, 'foo')
566 os.setxattr(src, 'user.foo', b'42')
567 shutil.copy2(src, dst)
568 self.assertEqual(
569 os.getxattr(src, 'user.foo'),
570 os.getxattr(dst, 'user.foo'))
571 os.remove(dst)
572
Antoine Pitrou78091e62011-12-29 18:54:15 +0100573 @support.skip_unless_symlink
574 def test_copyfile_symlinks(self):
575 tmp_dir = self.mkdtemp()
576 src = os.path.join(tmp_dir, 'src')
577 dst = os.path.join(tmp_dir, 'dst')
578 dst_link = os.path.join(tmp_dir, 'dst_link')
579 link = os.path.join(tmp_dir, 'link')
580 write_file(src, 'foo')
581 os.symlink(src, link)
582 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700583 shutil.copyfile(link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100584 self.assertTrue(os.path.islink(dst_link))
585 self.assertEqual(os.readlink(link), os.readlink(dst_link))
586 # follow
587 shutil.copyfile(link, dst)
588 self.assertFalse(os.path.islink(dst))
589
Hynek Schlawack2100b422012-06-23 20:28:32 +0200590 def test_rmtree_uses_safe_fd_version_if_available(self):
Hynek Schlawackd0f6e0a2012-06-29 08:28:20 +0200591 _use_fd_functions = ({os.open, os.stat, os.unlink, os.rmdir} <=
592 os.supports_dir_fd and
593 os.listdir in os.supports_fd and
594 os.stat in os.supports_follow_symlinks)
595 if _use_fd_functions:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200596 self.assertTrue(shutil._use_fd_functions)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000597 self.assertTrue(shutil.rmtree.avoids_symlink_attacks)
Hynek Schlawack2100b422012-06-23 20:28:32 +0200598 tmp_dir = self.mkdtemp()
599 d = os.path.join(tmp_dir, 'a')
600 os.mkdir(d)
601 try:
602 real_rmtree = shutil._rmtree_safe_fd
603 class Called(Exception): pass
604 def _raiser(*args, **kwargs):
605 raise Called
606 shutil._rmtree_safe_fd = _raiser
607 self.assertRaises(Called, shutil.rmtree, d)
608 finally:
609 shutil._rmtree_safe_fd = real_rmtree
610 else:
611 self.assertFalse(shutil._use_fd_functions)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000612 self.assertFalse(shutil.rmtree.avoids_symlink_attacks)
Hynek Schlawack2100b422012-06-23 20:28:32 +0200613
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000614 def test_rmtree_dont_delete_file(self):
615 # When called on a file instead of a directory, don't delete it.
616 handle, path = tempfile.mkstemp()
Victor Stinnerbf816222011-06-30 23:25:47 +0200617 os.close(handle)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200618 self.assertRaises(NotADirectoryError, shutil.rmtree, path)
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000619 os.remove(path)
620
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000621 def test_copytree_simple(self):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000622 src_dir = tempfile.mkdtemp()
623 dst_dir = os.path.join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200624 self.addCleanup(shutil.rmtree, src_dir)
625 self.addCleanup(shutil.rmtree, os.path.dirname(dst_dir))
626 write_file((src_dir, 'test.txt'), '123')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000627 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200628 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000629
Éric Araujoa7e33a12011-08-12 19:51:35 +0200630 shutil.copytree(src_dir, dst_dir)
631 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test.txt')))
632 self.assertTrue(os.path.isdir(os.path.join(dst_dir, 'test_dir')))
633 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test_dir',
634 'test.txt')))
635 actual = read_file((dst_dir, 'test.txt'))
636 self.assertEqual(actual, '123')
637 actual = read_file((dst_dir, 'test_dir', 'test.txt'))
638 self.assertEqual(actual, '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000639
Antoine Pitrou78091e62011-12-29 18:54:15 +0100640 @support.skip_unless_symlink
641 def test_copytree_symlinks(self):
642 tmp_dir = self.mkdtemp()
643 src_dir = os.path.join(tmp_dir, 'src')
644 dst_dir = os.path.join(tmp_dir, 'dst')
645 sub_dir = os.path.join(src_dir, 'sub')
646 os.mkdir(src_dir)
647 os.mkdir(sub_dir)
648 write_file((src_dir, 'file.txt'), 'foo')
649 src_link = os.path.join(sub_dir, 'link')
650 dst_link = os.path.join(dst_dir, 'sub/link')
651 os.symlink(os.path.join(src_dir, 'file.txt'),
652 src_link)
653 if hasattr(os, 'lchmod'):
654 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
655 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
656 os.lchflags(src_link, stat.UF_NODUMP)
657 src_stat = os.lstat(src_link)
658 shutil.copytree(src_dir, dst_dir, symlinks=True)
659 self.assertTrue(os.path.islink(os.path.join(dst_dir, 'sub', 'link')))
660 self.assertEqual(os.readlink(os.path.join(dst_dir, 'sub', 'link')),
661 os.path.join(src_dir, 'file.txt'))
662 dst_stat = os.lstat(dst_link)
663 if hasattr(os, 'lchmod'):
664 self.assertEqual(dst_stat.st_mode, src_stat.st_mode)
665 if hasattr(os, 'lchflags'):
666 self.assertEqual(dst_stat.st_flags, src_stat.st_flags)
667
Georg Brandl2ee470f2008-07-16 12:55:28 +0000668 def test_copytree_with_exclude(self):
Georg Brandl2ee470f2008-07-16 12:55:28 +0000669 # creating data
670 join = os.path.join
671 exists = os.path.exists
672 src_dir = tempfile.mkdtemp()
Georg Brandl2ee470f2008-07-16 12:55:28 +0000673 try:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000674 dst_dir = join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200675 write_file((src_dir, 'test.txt'), '123')
676 write_file((src_dir, 'test.tmp'), '123')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000677 os.mkdir(join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200678 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000679 os.mkdir(join(src_dir, 'test_dir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200680 write_file((src_dir, 'test_dir2', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000681 os.mkdir(join(src_dir, 'test_dir2', 'subdir'))
682 os.mkdir(join(src_dir, 'test_dir2', 'subdir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200683 write_file((src_dir, 'test_dir2', 'subdir', 'test.txt'), '456')
684 write_file((src_dir, 'test_dir2', 'subdir2', 'test.py'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000685
686 # testing glob-like patterns
687 try:
688 patterns = shutil.ignore_patterns('*.tmp', 'test_dir2')
689 shutil.copytree(src_dir, dst_dir, ignore=patterns)
690 # checking the result: some elements should not be copied
691 self.assertTrue(exists(join(dst_dir, 'test.txt')))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200692 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
693 self.assertFalse(exists(join(dst_dir, 'test_dir2')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000694 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200695 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000696 try:
697 patterns = shutil.ignore_patterns('*.tmp', 'subdir*')
698 shutil.copytree(src_dir, dst_dir, ignore=patterns)
699 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200700 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
701 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2')))
702 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
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
706 # testing callable-style
707 try:
708 def _filter(src, names):
709 res = []
710 for name in names:
711 path = os.path.join(src, name)
712
713 if (os.path.isdir(path) and
714 path.split()[-1] == 'subdir'):
715 res.append(name)
716 elif os.path.splitext(path)[-1] in ('.py'):
717 res.append(name)
718 return res
719
720 shutil.copytree(src_dir, dst_dir, ignore=_filter)
721
722 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200723 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2',
724 'test.py')))
725 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000726
727 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200728 shutil.rmtree(dst_dir)
Georg Brandl2ee470f2008-07-16 12:55:28 +0000729 finally:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000730 shutil.rmtree(src_dir)
731 shutil.rmtree(os.path.dirname(dst_dir))
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000732
Antoine Pitrouac601602013-08-16 19:35:02 +0200733 def test_copytree_retains_permissions(self):
734 tmp_dir = tempfile.mkdtemp()
735 src_dir = os.path.join(tmp_dir, 'source')
736 os.mkdir(src_dir)
737 dst_dir = os.path.join(tmp_dir, 'destination')
738 self.addCleanup(shutil.rmtree, tmp_dir)
739
740 os.chmod(src_dir, 0o777)
741 write_file((src_dir, 'permissive.txt'), '123')
742 os.chmod(os.path.join(src_dir, 'permissive.txt'), 0o777)
743 write_file((src_dir, 'restrictive.txt'), '456')
744 os.chmod(os.path.join(src_dir, 'restrictive.txt'), 0o600)
745 restrictive_subdir = tempfile.mkdtemp(dir=src_dir)
746 os.chmod(restrictive_subdir, 0o600)
747
748 shutil.copytree(src_dir, dst_dir)
Brett Cannon9c7eb552013-08-23 14:38:11 -0400749 self.assertEqual(os.stat(src_dir).st_mode, os.stat(dst_dir).st_mode)
750 self.assertEqual(os.stat(os.path.join(src_dir, 'permissive.txt')).st_mode,
Antoine Pitrouac601602013-08-16 19:35:02 +0200751 os.stat(os.path.join(dst_dir, 'permissive.txt')).st_mode)
Brett Cannon9c7eb552013-08-23 14:38:11 -0400752 self.assertEqual(os.stat(os.path.join(src_dir, 'restrictive.txt')).st_mode,
Antoine Pitrouac601602013-08-16 19:35:02 +0200753 os.stat(os.path.join(dst_dir, 'restrictive.txt')).st_mode)
754 restrictive_subdir_dst = os.path.join(dst_dir,
755 os.path.split(restrictive_subdir)[1])
Brett Cannon9c7eb552013-08-23 14:38:11 -0400756 self.assertEqual(os.stat(restrictive_subdir).st_mode,
Antoine Pitrouac601602013-08-16 19:35:02 +0200757 os.stat(restrictive_subdir_dst).st_mode)
758
Berker Peksag884afd92014-12-10 02:50:32 +0200759 @unittest.mock.patch('os.chmod')
760 def test_copytree_winerror(self, mock_patch):
761 # When copying to VFAT, copystat() raises OSError. On Windows, the
762 # exception object has a meaningful 'winerror' attribute, but not
763 # on other operating systems. Do not assume 'winerror' is set.
764 src_dir = tempfile.mkdtemp()
765 dst_dir = os.path.join(tempfile.mkdtemp(), 'destination')
766 self.addCleanup(shutil.rmtree, src_dir)
767 self.addCleanup(shutil.rmtree, os.path.dirname(dst_dir))
768
769 mock_patch.side_effect = PermissionError('ka-boom')
770 with self.assertRaises(shutil.Error):
771 shutil.copytree(src_dir, dst_dir)
772
Zachary Ware9fe6d862013-12-08 00:20:35 -0600773 @unittest.skipIf(os.name == 'nt', 'temporarily disabled on Windows')
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000774 @unittest.skipUnless(hasattr(os, 'link'), 'requires os.link')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000775 def test_dont_copy_file_onto_link_to_itself(self):
776 # bug 851123.
777 os.mkdir(TESTFN)
778 src = os.path.join(TESTFN, 'cheese')
779 dst = os.path.join(TESTFN, 'shop')
780 try:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000781 with open(src, 'w') as f:
782 f.write('cheddar')
783 os.link(src, dst)
Hynek Schlawack48653762012-10-07 12:49:58 +0200784 self.assertRaises(shutil.SameFileError, shutil.copyfile, src, dst)
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000785 with open(src, 'r') as f:
786 self.assertEqual(f.read(), 'cheddar')
787 os.remove(dst)
788 finally:
789 shutil.rmtree(TESTFN, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000790
Brian Curtin3b4499c2010-12-28 14:31:47 +0000791 @support.skip_unless_symlink
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000792 def test_dont_copy_file_onto_symlink_to_itself(self):
793 # bug 851123.
794 os.mkdir(TESTFN)
795 src = os.path.join(TESTFN, 'cheese')
796 dst = os.path.join(TESTFN, 'shop')
797 try:
798 with open(src, 'w') as f:
799 f.write('cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000800 # Using `src` here would mean we end up with a symlink pointing
801 # to TESTFN/TESTFN/cheese, while it should point at
802 # TESTFN/cheese.
803 os.symlink('cheese', dst)
Hynek Schlawack48653762012-10-07 12:49:58 +0200804 self.assertRaises(shutil.SameFileError, shutil.copyfile, src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +0000805 with open(src, 'r') as f:
806 self.assertEqual(f.read(), 'cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000807 os.remove(dst)
808 finally:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000809 shutil.rmtree(TESTFN, ignore_errors=True)
Johannes Gijsbers68128712004-08-14 13:57:08 +0000810
Brian Curtin3b4499c2010-12-28 14:31:47 +0000811 @support.skip_unless_symlink
Brian Curtind40e6f72010-07-08 21:39:08 +0000812 def test_rmtree_on_symlink(self):
813 # bug 1669.
814 os.mkdir(TESTFN)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000815 try:
Brian Curtind40e6f72010-07-08 21:39:08 +0000816 src = os.path.join(TESTFN, 'cheese')
817 dst = os.path.join(TESTFN, 'shop')
818 os.mkdir(src)
819 os.symlink(src, dst)
820 self.assertRaises(OSError, shutil.rmtree, dst)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200821 shutil.rmtree(dst, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000822 finally:
Brian Curtind40e6f72010-07-08 21:39:08 +0000823 shutil.rmtree(TESTFN, ignore_errors=True)
824
Serhiy Storchaka43767632013-11-03 21:31:38 +0200825 # Issue #3002: copyfile and copytree block indefinitely on named pipes
826 @unittest.skipUnless(hasattr(os, "mkfifo"), 'requires os.mkfifo()')
827 def test_copyfile_named_pipe(self):
828 os.mkfifo(TESTFN)
829 try:
830 self.assertRaises(shutil.SpecialFileError,
831 shutil.copyfile, TESTFN, TESTFN2)
832 self.assertRaises(shutil.SpecialFileError,
833 shutil.copyfile, __file__, TESTFN)
834 finally:
835 os.remove(TESTFN)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000836
Serhiy Storchaka43767632013-11-03 21:31:38 +0200837 @unittest.skipUnless(hasattr(os, "mkfifo"), 'requires os.mkfifo()')
838 @support.skip_unless_symlink
839 def test_copytree_named_pipe(self):
840 os.mkdir(TESTFN)
841 try:
842 subdir = os.path.join(TESTFN, "subdir")
843 os.mkdir(subdir)
844 pipe = os.path.join(subdir, "mypipe")
845 os.mkfifo(pipe)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000846 try:
Serhiy Storchaka43767632013-11-03 21:31:38 +0200847 shutil.copytree(TESTFN, TESTFN2)
848 except shutil.Error as e:
849 errors = e.args[0]
850 self.assertEqual(len(errors), 1)
851 src, dst, error_msg = errors[0]
852 self.assertEqual("`%s` is a named pipe" % pipe, error_msg)
853 else:
854 self.fail("shutil.Error should have been raised")
855 finally:
856 shutil.rmtree(TESTFN, ignore_errors=True)
857 shutil.rmtree(TESTFN2, ignore_errors=True)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000858
Tarek Ziadé5340db32010-04-19 22:30:51 +0000859 def test_copytree_special_func(self):
860
861 src_dir = self.mkdtemp()
862 dst_dir = os.path.join(self.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200863 write_file((src_dir, 'test.txt'), '123')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000864 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200865 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000866
867 copied = []
868 def _copy(src, dst):
869 copied.append((src, dst))
870
871 shutil.copytree(src_dir, dst_dir, copy_function=_copy)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000872 self.assertEqual(len(copied), 2)
Tarek Ziadé5340db32010-04-19 22:30:51 +0000873
Brian Curtin3b4499c2010-12-28 14:31:47 +0000874 @support.skip_unless_symlink
Tarek Ziadéfb437512010-04-20 08:57:33 +0000875 def test_copytree_dangling_symlinks(self):
876
877 # a dangling symlink raises an error at the end
878 src_dir = self.mkdtemp()
879 dst_dir = os.path.join(self.mkdtemp(), 'destination')
880 os.symlink('IDONTEXIST', os.path.join(src_dir, 'test.txt'))
881 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200882 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadéfb437512010-04-20 08:57:33 +0000883 self.assertRaises(Error, shutil.copytree, src_dir, dst_dir)
884
885 # a dangling symlink is ignored with the proper flag
886 dst_dir = os.path.join(self.mkdtemp(), 'destination2')
887 shutil.copytree(src_dir, dst_dir, ignore_dangling_symlinks=True)
888 self.assertNotIn('test.txt', os.listdir(dst_dir))
889
890 # a dangling symlink is copied if symlinks=True
891 dst_dir = os.path.join(self.mkdtemp(), 'destination3')
892 shutil.copytree(src_dir, dst_dir, symlinks=True)
893 self.assertIn('test.txt', os.listdir(dst_dir))
894
Berker Peksag5a294d82015-07-25 14:53:48 +0300895 @support.skip_unless_symlink
896 def test_copytree_symlink_dir(self):
897 src_dir = self.mkdtemp()
898 dst_dir = os.path.join(self.mkdtemp(), 'destination')
899 os.mkdir(os.path.join(src_dir, 'real_dir'))
900 with open(os.path.join(src_dir, 'real_dir', 'test.txt'), 'w'):
901 pass
902 os.symlink(os.path.join(src_dir, 'real_dir'),
903 os.path.join(src_dir, 'link_to_dir'),
904 target_is_directory=True)
905
906 shutil.copytree(src_dir, dst_dir, symlinks=False)
907 self.assertFalse(os.path.islink(os.path.join(dst_dir, 'link_to_dir')))
908 self.assertIn('test.txt', os.listdir(os.path.join(dst_dir, 'link_to_dir')))
909
910 dst_dir = os.path.join(self.mkdtemp(), 'destination2')
911 shutil.copytree(src_dir, dst_dir, symlinks=True)
912 self.assertTrue(os.path.islink(os.path.join(dst_dir, 'link_to_dir')))
913 self.assertIn('test.txt', os.listdir(os.path.join(dst_dir, 'link_to_dir')))
914
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400915 def _copy_file(self, method):
916 fname = 'test.txt'
917 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200918 write_file((tmpdir, fname), 'xxx')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400919 file1 = os.path.join(tmpdir, fname)
920 tmpdir2 = self.mkdtemp()
921 method(file1, tmpdir2)
922 file2 = os.path.join(tmpdir2, fname)
923 return (file1, file2)
924
925 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
926 def test_copy(self):
927 # Ensure that the copied file exists and has the same mode bits.
928 file1, file2 = self._copy_file(shutil.copy)
929 self.assertTrue(os.path.exists(file2))
930 self.assertEqual(os.stat(file1).st_mode, os.stat(file2).st_mode)
931
932 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
Senthil Kumaran0c2dba52011-07-03 18:21:38 -0700933 @unittest.skipUnless(hasattr(os, 'utime'), 'requires os.utime')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400934 def test_copy2(self):
935 # Ensure that the copied file exists and has the same mode and
936 # modification time bits.
937 file1, file2 = self._copy_file(shutil.copy2)
938 self.assertTrue(os.path.exists(file2))
939 file1_stat = os.stat(file1)
940 file2_stat = os.stat(file2)
941 self.assertEqual(file1_stat.st_mode, file2_stat.st_mode)
942 for attr in 'st_atime', 'st_mtime':
943 # The modification times may be truncated in the new file.
944 self.assertLessEqual(getattr(file1_stat, attr),
945 getattr(file2_stat, attr) + 1)
946 if hasattr(os, 'chflags') and hasattr(file1_stat, 'st_flags'):
947 self.assertEqual(getattr(file1_stat, 'st_flags'),
948 getattr(file2_stat, 'st_flags'))
949
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +0200950 @support.requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000951 def test_make_tarball(self):
952 # creating something to tar
Serhiy Storchaka527ef072015-09-06 18:33:19 +0300953 root_dir, base_dir = self._create_files('')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000954
955 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400956 # force shutil to create the directory
957 os.rmdir(tmpdir2)
Serhiy Storchakaeba8fee2015-09-07 19:58:23 +0300958 # working with relative paths
959 work_dir = os.path.dirname(tmpdir2)
960 rel_base_name = os.path.join(os.path.basename(tmpdir2), 'archive')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000961
Serhiy Storchakaeba8fee2015-09-07 19:58:23 +0300962 with support.change_cwd(work_dir):
Serhiy Storchaka5558d4f2015-09-08 09:59:02 +0300963 base_name = os.path.abspath(rel_base_name)
Serhiy Storchakaeba8fee2015-09-07 19:58:23 +0300964 tarball = make_archive(rel_base_name, 'gztar', root_dir, '.')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000965
966 # check if the compressed tarball was created
Serhiy Storchakaa091a822015-09-07 13:55:25 +0300967 self.assertEqual(tarball, base_name + '.tar.gz')
Serhiy Storchaka527ef072015-09-06 18:33:19 +0300968 self.assertTrue(os.path.isfile(tarball))
969 self.assertTrue(tarfile.is_tarfile(tarball))
970 with tarfile.open(tarball, 'r:gz') as tf:
971 self.assertCountEqual(tf.getnames(),
972 ['.', './sub', './sub2',
973 './file1', './file2', './sub/file3'])
Tarek Ziadé396fad72010-02-23 05:30:31 +0000974
975 # trying an uncompressed one
Serhiy Storchakaeba8fee2015-09-07 19:58:23 +0300976 with support.change_cwd(work_dir):
977 tarball = make_archive(rel_base_name, 'tar', root_dir, '.')
Serhiy Storchakaa091a822015-09-07 13:55:25 +0300978 self.assertEqual(tarball, base_name + '.tar')
Serhiy Storchaka527ef072015-09-06 18:33:19 +0300979 self.assertTrue(os.path.isfile(tarball))
980 self.assertTrue(tarfile.is_tarfile(tarball))
981 with tarfile.open(tarball, 'r') as tf:
982 self.assertCountEqual(tf.getnames(),
983 ['.', './sub', './sub2',
984 './file1', './file2', './sub/file3'])
Tarek Ziadé396fad72010-02-23 05:30:31 +0000985
986 def _tarinfo(self, path):
Serhiy Storchaka527ef072015-09-06 18:33:19 +0300987 with tarfile.open(path) as tar:
Tarek Ziadé396fad72010-02-23 05:30:31 +0000988 names = tar.getnames()
989 names.sort()
990 return tuple(names)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000991
Serhiy Storchaka527ef072015-09-06 18:33:19 +0300992 def _create_files(self, base_dir='dist'):
Tarek Ziadé396fad72010-02-23 05:30:31 +0000993 # creating something to tar
Serhiy Storchaka527ef072015-09-06 18:33:19 +0300994 root_dir = self.mkdtemp()
995 dist = os.path.join(root_dir, base_dir)
996 os.makedirs(dist, exist_ok=True)
Éric Araujoa7e33a12011-08-12 19:51:35 +0200997 write_file((dist, 'file1'), 'xxx')
998 write_file((dist, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000999 os.mkdir(os.path.join(dist, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +02001000 write_file((dist, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +00001001 os.mkdir(os.path.join(dist, 'sub2'))
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001002 if base_dir:
1003 write_file((root_dir, 'outer'), 'xxx')
1004 return root_dir, base_dir
Tarek Ziadé396fad72010-02-23 05:30:31 +00001005
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001006 @support.requires_zlib
Serhiy Storchakab42de2f2015-11-21 14:09:26 +02001007 @unittest.skipUnless(shutil.which('tar'),
Tarek Ziadé396fad72010-02-23 05:30:31 +00001008 'Need the tar command to run')
1009 def test_tarfile_vs_tar(self):
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001010 root_dir, base_dir = self._create_files()
1011 base_name = os.path.join(self.mkdtemp(), 'archive')
Serhiy Storchakaa091a822015-09-07 13:55:25 +03001012 tarball = make_archive(base_name, 'gztar', root_dir, base_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001013
1014 # check if the compressed tarball was created
Serhiy Storchakaa091a822015-09-07 13:55:25 +03001015 self.assertEqual(tarball, base_name + '.tar.gz')
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001016 self.assertTrue(os.path.isfile(tarball))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001017
1018 # now create another tarball using `tar`
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001019 tarball2 = os.path.join(root_dir, 'archive2.tar')
1020 tar_cmd = ['tar', '-cf', 'archive2.tar', base_dir]
Serhiy Storchakab42de2f2015-11-21 14:09:26 +02001021 subprocess.check_call(tar_cmd, cwd=root_dir,
1022 stdout=subprocess.DEVNULL)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001023
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001024 self.assertTrue(os.path.isfile(tarball2))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001025 # let's compare both tarballs
Ezio Melottib3aedd42010-11-20 19:04:17 +00001026 self.assertEqual(self._tarinfo(tarball), self._tarinfo(tarball2))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001027
1028 # trying an uncompressed one
Serhiy Storchakaa091a822015-09-07 13:55:25 +03001029 tarball = make_archive(base_name, 'tar', root_dir, base_dir)
1030 self.assertEqual(tarball, base_name + '.tar')
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001031 self.assertTrue(os.path.isfile(tarball))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001032
1033 # now for a dry_run
Serhiy Storchakaa091a822015-09-07 13:55:25 +03001034 tarball = make_archive(base_name, 'tar', root_dir, base_dir,
1035 dry_run=True)
1036 self.assertEqual(tarball, base_name + '.tar')
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001037 self.assertTrue(os.path.isfile(tarball))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001038
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001039 @support.requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001040 def test_make_zipfile(self):
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001041 # creating something to zip
1042 root_dir, base_dir = self._create_files()
Serhiy Storchakaeba8fee2015-09-07 19:58:23 +03001043
1044 tmpdir2 = self.mkdtemp()
1045 # force shutil to create the directory
1046 os.rmdir(tmpdir2)
1047 # working with relative paths
1048 work_dir = os.path.dirname(tmpdir2)
1049 rel_base_name = os.path.join(os.path.basename(tmpdir2), 'archive')
Serhiy Storchakaeba8fee2015-09-07 19:58:23 +03001050
1051 with support.change_cwd(work_dir):
Serhiy Storchaka5558d4f2015-09-08 09:59:02 +03001052 base_name = os.path.abspath(rel_base_name)
Serhiy Storchaka666de772016-10-23 15:55:09 +03001053 res = make_archive(rel_base_name, 'zip', root_dir)
1054
1055 self.assertEqual(res, base_name + '.zip')
1056 self.assertTrue(os.path.isfile(res))
1057 self.assertTrue(zipfile.is_zipfile(res))
1058 with zipfile.ZipFile(res) as zf:
1059 self.assertCountEqual(zf.namelist(),
1060 ['dist/', 'dist/sub/', 'dist/sub2/',
1061 'dist/file1', 'dist/file2', 'dist/sub/file3',
1062 'outer'])
1063
1064 with support.change_cwd(work_dir):
1065 base_name = os.path.abspath(rel_base_name)
Serhiy Storchaka2504cec2015-09-08 05:47:23 +03001066 res = make_archive(rel_base_name, 'zip', root_dir, base_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001067
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001068 self.assertEqual(res, base_name + '.zip')
1069 self.assertTrue(os.path.isfile(res))
1070 self.assertTrue(zipfile.is_zipfile(res))
1071 with zipfile.ZipFile(res) as zf:
1072 self.assertCountEqual(zf.namelist(),
Serhiy Storchaka2504cec2015-09-08 05:47:23 +03001073 ['dist/', 'dist/sub/', 'dist/sub2/',
1074 'dist/file1', 'dist/file2', 'dist/sub/file3'])
Tarek Ziadé396fad72010-02-23 05:30:31 +00001075
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001076 @support.requires_zlib
Serhiy Storchakab42de2f2015-11-21 14:09:26 +02001077 @unittest.skipUnless(shutil.which('zip'),
Serhiy Storchaka2504cec2015-09-08 05:47:23 +03001078 'Need the zip command to run')
1079 def test_zipfile_vs_zip(self):
1080 root_dir, base_dir = self._create_files()
1081 base_name = os.path.join(self.mkdtemp(), 'archive')
1082 archive = make_archive(base_name, 'zip', root_dir, base_dir)
1083
1084 # check if ZIP file was created
1085 self.assertEqual(archive, base_name + '.zip')
1086 self.assertTrue(os.path.isfile(archive))
1087
1088 # now create another ZIP file using `zip`
1089 archive2 = os.path.join(root_dir, 'archive2.zip')
1090 zip_cmd = ['zip', '-q', '-r', 'archive2.zip', base_dir]
Serhiy Storchakab42de2f2015-11-21 14:09:26 +02001091 subprocess.check_call(zip_cmd, cwd=root_dir,
1092 stdout=subprocess.DEVNULL)
Serhiy Storchaka2504cec2015-09-08 05:47:23 +03001093
1094 self.assertTrue(os.path.isfile(archive2))
1095 # let's compare both ZIP files
1096 with zipfile.ZipFile(archive) as zf:
1097 names = zf.namelist()
1098 with zipfile.ZipFile(archive2) as zf:
1099 names2 = zf.namelist()
1100 self.assertEqual(sorted(names), sorted(names2))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001101
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001102 @support.requires_zlib
Serhiy Storchaka8bc792a2015-11-22 14:49:58 +02001103 @unittest.skipUnless(shutil.which('unzip'),
1104 'Need the unzip command to run')
1105 def test_unzip_zipfile(self):
1106 root_dir, base_dir = self._create_files()
1107 base_name = os.path.join(self.mkdtemp(), 'archive')
1108 archive = make_archive(base_name, 'zip', root_dir, base_dir)
1109
1110 # check if ZIP file was created
1111 self.assertEqual(archive, base_name + '.zip')
1112 self.assertTrue(os.path.isfile(archive))
1113
1114 # now check the ZIP file using `unzip -t`
1115 zip_cmd = ['unzip', '-t', archive]
1116 with support.change_cwd(root_dir):
1117 try:
1118 subprocess.check_output(zip_cmd, stderr=subprocess.STDOUT)
1119 except subprocess.CalledProcessError as exc:
1120 details = exc.output.decode(errors="replace")
1121 msg = "{}\n\n**Unzip Output**\n{}"
1122 self.fail(msg.format(exc, details))
1123
Tarek Ziadé396fad72010-02-23 05:30:31 +00001124 def test_make_archive(self):
1125 tmpdir = self.mkdtemp()
1126 base_name = os.path.join(tmpdir, 'archive')
1127 self.assertRaises(ValueError, make_archive, base_name, 'xxx')
1128
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001129 @support.requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001130 def test_make_archive_owner_group(self):
1131 # testing make_archive with owner and group, with various combinations
1132 # this works even if there's not gid/uid support
1133 if UID_GID_SUPPORT:
1134 group = grp.getgrgid(0)[0]
1135 owner = pwd.getpwuid(0)[0]
1136 else:
1137 group = owner = 'root'
1138
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001139 root_dir, base_dir = self._create_files()
1140 base_name = os.path.join(self.mkdtemp(), 'archive')
Tarek Ziadé396fad72010-02-23 05:30:31 +00001141 res = make_archive(base_name, 'zip', root_dir, base_dir, owner=owner,
1142 group=group)
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001143 self.assertTrue(os.path.isfile(res))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001144
1145 res = make_archive(base_name, 'zip', root_dir, base_dir)
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001146 self.assertTrue(os.path.isfile(res))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001147
1148 res = make_archive(base_name, 'tar', root_dir, base_dir,
1149 owner=owner, group=group)
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001150 self.assertTrue(os.path.isfile(res))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001151
1152 res = make_archive(base_name, 'tar', root_dir, base_dir,
1153 owner='kjhkjhkjg', group='oihohoh')
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001154 self.assertTrue(os.path.isfile(res))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001155
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001156
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001157 @support.requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001158 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1159 def test_tarfile_root_owner(self):
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001160 root_dir, base_dir = self._create_files()
1161 base_name = os.path.join(self.mkdtemp(), 'archive')
Tarek Ziadé396fad72010-02-23 05:30:31 +00001162 group = grp.getgrgid(0)[0]
1163 owner = pwd.getpwuid(0)[0]
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001164 with support.change_cwd(root_dir):
1165 archive_name = make_archive(base_name, 'gztar', root_dir, 'dist',
1166 owner=owner, group=group)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001167
1168 # check if the compressed tarball was created
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001169 self.assertTrue(os.path.isfile(archive_name))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001170
1171 # now checks the rights
1172 archive = tarfile.open(archive_name)
1173 try:
1174 for member in archive.getmembers():
Ezio Melottib3aedd42010-11-20 19:04:17 +00001175 self.assertEqual(member.uid, 0)
1176 self.assertEqual(member.gid, 0)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001177 finally:
1178 archive.close()
1179
1180 def test_make_archive_cwd(self):
1181 current_dir = os.getcwd()
1182 def _breaks(*args, **kw):
1183 raise RuntimeError()
1184
1185 register_archive_format('xxx', _breaks, [], 'xxx file')
1186 try:
1187 try:
1188 make_archive('xxx', 'xxx', root_dir=self.mkdtemp())
1189 except Exception:
1190 pass
Ezio Melottib3aedd42010-11-20 19:04:17 +00001191 self.assertEqual(os.getcwd(), current_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001192 finally:
1193 unregister_archive_format('xxx')
1194
Serhiy Storchaka9a4fc192014-11-28 00:48:46 +02001195 def test_make_tarfile_in_curdir(self):
1196 # Issue #21280
1197 root_dir = self.mkdtemp()
1198 with support.change_cwd(root_dir):
1199 self.assertEqual(make_archive('test', 'tar'), 'test.tar')
1200 self.assertTrue(os.path.isfile('test.tar'))
1201
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001202 @support.requires_zlib
Serhiy Storchaka9a4fc192014-11-28 00:48:46 +02001203 def test_make_zipfile_in_curdir(self):
1204 # Issue #21280
1205 root_dir = self.mkdtemp()
1206 with support.change_cwd(root_dir):
1207 self.assertEqual(make_archive('test', 'zip'), 'test.zip')
1208 self.assertTrue(os.path.isfile('test.zip'))
1209
Tarek Ziadé396fad72010-02-23 05:30:31 +00001210 def test_register_archive_format(self):
1211
1212 self.assertRaises(TypeError, register_archive_format, 'xxx', 1)
1213 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1214 1)
1215 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1216 [(1, 2), (1, 2, 3)])
1217
1218 register_archive_format('xxx', lambda: x, [(1, 2)], 'xxx file')
1219 formats = [name for name, params in get_archive_formats()]
1220 self.assertIn('xxx', formats)
1221
1222 unregister_archive_format('xxx')
1223 formats = [name for name, params in get_archive_formats()]
1224 self.assertNotIn('xxx', formats)
1225
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001226 def check_unpack_archive(self, format):
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001227 root_dir, base_dir = self._create_files()
Serhiy Storchaka2504cec2015-09-08 05:47:23 +03001228 expected = rlistdir(root_dir)
1229 expected.remove('outer')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001230
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001231 base_name = os.path.join(self.mkdtemp(), 'archive')
1232 filename = make_archive(base_name, format, root_dir, base_dir)
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001233
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001234 # let's try to unpack it now
1235 tmpdir2 = self.mkdtemp()
1236 unpack_archive(filename, tmpdir2)
1237 self.assertEqual(rlistdir(tmpdir2), expected)
1238
1239 # and again, this time with the format specified
1240 tmpdir3 = self.mkdtemp()
1241 unpack_archive(filename, tmpdir3, format=format)
1242 self.assertEqual(rlistdir(tmpdir3), expected)
1243
Nick Coghlanabf202d2011-03-16 13:52:20 -04001244 self.assertRaises(shutil.ReadError, unpack_archive, TESTFN)
1245 self.assertRaises(ValueError, unpack_archive, TESTFN, format='xxx')
1246
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001247 def test_unpack_archive_tar(self):
1248 self.check_unpack_archive('tar')
1249
1250 @support.requires_zlib
1251 def test_unpack_archive_gztar(self):
1252 self.check_unpack_archive('gztar')
1253
1254 @support.requires_bz2
1255 def test_unpack_archive_bztar(self):
1256 self.check_unpack_archive('bztar')
1257
1258 @support.requires_lzma
1259 def test_unpack_archive_xztar(self):
1260 self.check_unpack_archive('xztar')
1261
1262 @support.requires_zlib
1263 def test_unpack_archive_zip(self):
1264 self.check_unpack_archive('zip')
1265
Martin Pantereb995702016-07-28 01:11:04 +00001266 def test_unpack_registry(self):
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001267
1268 formats = get_unpack_formats()
1269
1270 def _boo(filename, extract_dir, extra):
Ezio Melottib3aedd42010-11-20 19:04:17 +00001271 self.assertEqual(extra, 1)
1272 self.assertEqual(filename, 'stuff.boo')
1273 self.assertEqual(extract_dir, 'xx')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001274
1275 register_unpack_format('Boo', ['.boo', '.b2'], _boo, [('extra', 1)])
1276 unpack_archive('stuff.boo', 'xx')
1277
1278 # trying to register a .boo unpacker again
1279 self.assertRaises(RegistryError, register_unpack_format, 'Boo2',
1280 ['.boo'], _boo)
1281
1282 # should work now
1283 unregister_unpack_format('Boo')
1284 register_unpack_format('Boo2', ['.boo'], _boo)
1285 self.assertIn(('Boo2', ['.boo'], ''), get_unpack_formats())
1286 self.assertNotIn(('Boo', ['.boo'], ''), get_unpack_formats())
1287
1288 # let's leave a clean state
1289 unregister_unpack_format('Boo2')
Ezio Melottib3aedd42010-11-20 19:04:17 +00001290 self.assertEqual(get_unpack_formats(), formats)
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001291
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001292 @unittest.skipUnless(hasattr(shutil, 'disk_usage'),
1293 "disk_usage not available on this platform")
1294 def test_disk_usage(self):
1295 usage = shutil.disk_usage(os.getcwd())
Éric Araujo2ee61882011-07-02 16:45:45 +02001296 self.assertGreater(usage.total, 0)
1297 self.assertGreater(usage.used, 0)
1298 self.assertGreaterEqual(usage.free, 0)
1299 self.assertGreaterEqual(usage.total, usage.used)
1300 self.assertGreater(usage.total, usage.free)
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001301
Sandro Tosid902a142011-08-22 23:28:27 +02001302 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1303 @unittest.skipUnless(hasattr(os, 'chown'), 'requires os.chown')
1304 def test_chown(self):
1305
1306 # cleaned-up automatically by TestShutil.tearDown method
1307 dirname = self.mkdtemp()
1308 filename = tempfile.mktemp(dir=dirname)
1309 write_file(filename, 'testing chown function')
1310
1311 with self.assertRaises(ValueError):
1312 shutil.chown(filename)
1313
1314 with self.assertRaises(LookupError):
1315 shutil.chown(filename, user='non-exising username')
1316
1317 with self.assertRaises(LookupError):
1318 shutil.chown(filename, group='non-exising groupname')
1319
1320 with self.assertRaises(TypeError):
1321 shutil.chown(filename, b'spam')
1322
1323 with self.assertRaises(TypeError):
1324 shutil.chown(filename, 3.14)
1325
1326 uid = os.getuid()
1327 gid = os.getgid()
1328
1329 def check_chown(path, uid=None, gid=None):
1330 s = os.stat(filename)
1331 if uid is not None:
1332 self.assertEqual(uid, s.st_uid)
1333 if gid is not None:
1334 self.assertEqual(gid, s.st_gid)
1335
1336 shutil.chown(filename, uid, gid)
1337 check_chown(filename, uid, gid)
1338 shutil.chown(filename, uid)
1339 check_chown(filename, uid)
1340 shutil.chown(filename, user=uid)
1341 check_chown(filename, uid)
1342 shutil.chown(filename, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001343 check_chown(filename, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001344
1345 shutil.chown(dirname, uid, gid)
1346 check_chown(dirname, uid, gid)
1347 shutil.chown(dirname, uid)
1348 check_chown(dirname, uid)
1349 shutil.chown(dirname, user=uid)
1350 check_chown(dirname, uid)
1351 shutil.chown(dirname, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001352 check_chown(dirname, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001353
1354 user = pwd.getpwuid(uid)[0]
1355 group = grp.getgrgid(gid)[0]
1356 shutil.chown(filename, user, group)
1357 check_chown(filename, uid, gid)
1358 shutil.chown(dirname, user, group)
1359 check_chown(dirname, uid, gid)
1360
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001361 def test_copy_return_value(self):
1362 # copy and copy2 both return their destination path.
1363 for fn in (shutil.copy, shutil.copy2):
1364 src_dir = self.mkdtemp()
1365 dst_dir = self.mkdtemp()
1366 src = os.path.join(src_dir, 'foo')
1367 write_file(src, 'foo')
1368 rv = fn(src, dst_dir)
1369 self.assertEqual(rv, os.path.join(dst_dir, 'foo'))
1370 rv = fn(src, os.path.join(dst_dir, 'bar'))
1371 self.assertEqual(rv, os.path.join(dst_dir, 'bar'))
1372
1373 def test_copyfile_return_value(self):
1374 # copytree returns its destination path.
1375 src_dir = self.mkdtemp()
1376 dst_dir = self.mkdtemp()
1377 dst_file = os.path.join(dst_dir, 'bar')
1378 src_file = os.path.join(src_dir, 'foo')
1379 write_file(src_file, 'foo')
1380 rv = shutil.copyfile(src_file, dst_file)
1381 self.assertTrue(os.path.exists(rv))
1382 self.assertEqual(read_file(src_file), read_file(dst_file))
1383
Hynek Schlawack48653762012-10-07 12:49:58 +02001384 def test_copyfile_same_file(self):
1385 # copyfile() should raise SameFileError if the source and destination
1386 # are the same.
1387 src_dir = self.mkdtemp()
1388 src_file = os.path.join(src_dir, 'foo')
1389 write_file(src_file, 'foo')
1390 self.assertRaises(SameFileError, shutil.copyfile, src_file, src_file)
Hynek Schlawack27ddb572012-10-28 13:59:27 +01001391 # But Error should work too, to stay backward compatible.
1392 self.assertRaises(Error, shutil.copyfile, src_file, src_file)
Hynek Schlawack48653762012-10-07 12:49:58 +02001393
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001394 def test_copytree_return_value(self):
1395 # copytree returns its destination path.
1396 src_dir = self.mkdtemp()
1397 dst_dir = src_dir + "dest"
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001398 self.addCleanup(shutil.rmtree, dst_dir, True)
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001399 src = os.path.join(src_dir, 'foo')
1400 write_file(src, 'foo')
1401 rv = shutil.copytree(src_dir, dst_dir)
1402 self.assertEqual(['foo'], os.listdir(rv))
1403
Christian Heimes9bd667a2008-01-20 15:14:11 +00001404
Brian Curtinc57a3452012-06-22 16:00:30 -05001405class TestWhich(unittest.TestCase):
1406
1407 def setUp(self):
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001408 self.temp_dir = tempfile.mkdtemp(prefix="Tmp")
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001409 self.addCleanup(shutil.rmtree, self.temp_dir, True)
Brian Curtinc57a3452012-06-22 16:00:30 -05001410 # Give the temp_file an ".exe" suffix for all.
1411 # It's needed on Windows and not harmful on other platforms.
1412 self.temp_file = tempfile.NamedTemporaryFile(dir=self.temp_dir,
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001413 prefix="Tmp",
1414 suffix=".Exe")
Brian Curtinc57a3452012-06-22 16:00:30 -05001415 os.chmod(self.temp_file.name, stat.S_IXUSR)
1416 self.addCleanup(self.temp_file.close)
1417 self.dir, self.file = os.path.split(self.temp_file.name)
1418
1419 def test_basic(self):
1420 # Given an EXE in a directory, it should be returned.
1421 rv = shutil.which(self.file, path=self.dir)
1422 self.assertEqual(rv, self.temp_file.name)
1423
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001424 def test_absolute_cmd(self):
Brian Curtinc57a3452012-06-22 16:00:30 -05001425 # When given the fully qualified path to an executable that exists,
1426 # it should be returned.
1427 rv = shutil.which(self.temp_file.name, path=self.temp_dir)
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001428 self.assertEqual(rv, self.temp_file.name)
1429
1430 def test_relative_cmd(self):
1431 # When given the relative path with a directory part to an executable
1432 # that exists, it should be returned.
1433 base_dir, tail_dir = os.path.split(self.dir)
1434 relpath = os.path.join(tail_dir, self.file)
Nick Coghlan55175962013-07-28 22:11:50 +10001435 with support.change_cwd(path=base_dir):
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001436 rv = shutil.which(relpath, path=self.temp_dir)
1437 self.assertEqual(rv, relpath)
1438 # But it shouldn't be searched in PATH directories (issue #16957).
Nick Coghlan55175962013-07-28 22:11:50 +10001439 with support.change_cwd(path=self.dir):
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001440 rv = shutil.which(relpath, path=base_dir)
1441 self.assertIsNone(rv)
1442
1443 def test_cwd(self):
1444 # Issue #16957
1445 base_dir = os.path.dirname(self.dir)
Nick Coghlan55175962013-07-28 22:11:50 +10001446 with support.change_cwd(path=self.dir):
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001447 rv = shutil.which(self.file, path=base_dir)
1448 if sys.platform == "win32":
1449 # Windows: current directory implicitly on PATH
1450 self.assertEqual(rv, os.path.join(os.curdir, self.file))
1451 else:
1452 # Other platforms: shouldn't match in the current directory.
1453 self.assertIsNone(rv)
Brian Curtinc57a3452012-06-22 16:00:30 -05001454
Serhiy Storchaka12516e22013-05-28 15:50:15 +03001455 @unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0,
1456 'non-root user required')
Brian Curtinc57a3452012-06-22 16:00:30 -05001457 def test_non_matching_mode(self):
1458 # Set the file read-only and ask for writeable files.
1459 os.chmod(self.temp_file.name, stat.S_IREAD)
Serhiy Storchaka12516e22013-05-28 15:50:15 +03001460 if os.access(self.temp_file.name, os.W_OK):
1461 self.skipTest("can't set the file read-only")
Brian Curtinc57a3452012-06-22 16:00:30 -05001462 rv = shutil.which(self.file, path=self.dir, mode=os.W_OK)
1463 self.assertIsNone(rv)
1464
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001465 def test_relative_path(self):
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001466 base_dir, tail_dir = os.path.split(self.dir)
Nick Coghlan55175962013-07-28 22:11:50 +10001467 with support.change_cwd(path=base_dir):
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001468 rv = shutil.which(self.file, path=tail_dir)
1469 self.assertEqual(rv, os.path.join(tail_dir, self.file))
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001470
Brian Curtinc57a3452012-06-22 16:00:30 -05001471 def test_nonexistent_file(self):
1472 # Return None when no matching executable file is found on the path.
1473 rv = shutil.which("foo.exe", path=self.dir)
1474 self.assertIsNone(rv)
1475
1476 @unittest.skipUnless(sys.platform == "win32",
1477 "pathext check is Windows-only")
1478 def test_pathext_checking(self):
1479 # Ask for the file without the ".exe" extension, then ensure that
1480 # it gets found properly with the extension.
Serhiy Storchakad70127a2013-01-24 20:03:49 +02001481 rv = shutil.which(self.file[:-4], path=self.dir)
Serhiy Storchaka80c88f42013-01-22 10:31:36 +02001482 self.assertEqual(rv, self.temp_file.name[:-4] + ".EXE")
Brian Curtinc57a3452012-06-22 16:00:30 -05001483
Barry Warsaw618738b2013-04-16 11:05:03 -04001484 def test_environ_path(self):
1485 with support.EnvironmentVarGuard() as env:
Victor Stinner1d006a22013-12-16 23:39:40 +01001486 env['PATH'] = self.dir
Barry Warsaw618738b2013-04-16 11:05:03 -04001487 rv = shutil.which(self.file)
1488 self.assertEqual(rv, self.temp_file.name)
1489
1490 def test_empty_path(self):
1491 base_dir = os.path.dirname(self.dir)
Nick Coghlan55175962013-07-28 22:11:50 +10001492 with support.change_cwd(path=self.dir), \
Barry Warsaw618738b2013-04-16 11:05:03 -04001493 support.EnvironmentVarGuard() as env:
Victor Stinner1d006a22013-12-16 23:39:40 +01001494 env['PATH'] = self.dir
Barry Warsaw618738b2013-04-16 11:05:03 -04001495 rv = shutil.which(self.file, path='')
1496 self.assertIsNone(rv)
1497
1498 def test_empty_path_no_PATH(self):
1499 with support.EnvironmentVarGuard() as env:
1500 env.pop('PATH', None)
1501 rv = shutil.which(self.file)
1502 self.assertIsNone(rv)
1503
Brian Curtinc57a3452012-06-22 16:00:30 -05001504
Christian Heimesada8c3b2008-03-18 18:26:33 +00001505class TestMove(unittest.TestCase):
1506
1507 def setUp(self):
1508 filename = "foo"
1509 self.src_dir = tempfile.mkdtemp()
1510 self.dst_dir = tempfile.mkdtemp()
1511 self.src_file = os.path.join(self.src_dir, filename)
1512 self.dst_file = os.path.join(self.dst_dir, filename)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001513 with open(self.src_file, "wb") as f:
1514 f.write(b"spam")
1515
1516 def tearDown(self):
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001517 for d in (self.src_dir, self.dst_dir):
Christian Heimesada8c3b2008-03-18 18:26:33 +00001518 try:
1519 if d:
1520 shutil.rmtree(d)
1521 except:
1522 pass
1523
1524 def _check_move_file(self, src, dst, real_dst):
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001525 with open(src, "rb") as f:
1526 contents = f.read()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001527 shutil.move(src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001528 with open(real_dst, "rb") as f:
1529 self.assertEqual(contents, f.read())
Christian Heimesada8c3b2008-03-18 18:26:33 +00001530 self.assertFalse(os.path.exists(src))
1531
1532 def _check_move_dir(self, src, dst, real_dst):
1533 contents = sorted(os.listdir(src))
1534 shutil.move(src, dst)
1535 self.assertEqual(contents, sorted(os.listdir(real_dst)))
1536 self.assertFalse(os.path.exists(src))
1537
1538 def test_move_file(self):
1539 # Move a file to another location on the same filesystem.
1540 self._check_move_file(self.src_file, self.dst_file, self.dst_file)
1541
1542 def test_move_file_to_dir(self):
1543 # Move a file inside an existing dir on the same filesystem.
1544 self._check_move_file(self.src_file, self.dst_dir, self.dst_file)
1545
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001546 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001547 def test_move_file_other_fs(self):
1548 # Move a file to an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001549 self.test_move_file()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001550
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001551 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001552 def test_move_file_to_dir_other_fs(self):
1553 # Move a file to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001554 self.test_move_file_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001555
1556 def test_move_dir(self):
1557 # Move a dir to another location on the same filesystem.
1558 dst_dir = tempfile.mktemp()
1559 try:
1560 self._check_move_dir(self.src_dir, dst_dir, dst_dir)
1561 finally:
1562 try:
1563 shutil.rmtree(dst_dir)
1564 except:
1565 pass
1566
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001567 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001568 def test_move_dir_other_fs(self):
1569 # Move a dir to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001570 self.test_move_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001571
1572 def test_move_dir_to_dir(self):
1573 # Move a dir inside an existing dir on the same filesystem.
1574 self._check_move_dir(self.src_dir, self.dst_dir,
1575 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1576
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001577 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001578 def test_move_dir_to_dir_other_fs(self):
1579 # Move a dir inside an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001580 self.test_move_dir_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001581
Serhiy Storchaka3a308b92014-02-11 10:30:59 +02001582 def test_move_dir_sep_to_dir(self):
1583 self._check_move_dir(self.src_dir + os.path.sep, self.dst_dir,
1584 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1585
1586 @unittest.skipUnless(os.path.altsep, 'requires os.path.altsep')
1587 def test_move_dir_altsep_to_dir(self):
1588 self._check_move_dir(self.src_dir + os.path.altsep, self.dst_dir,
1589 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1590
Christian Heimesada8c3b2008-03-18 18:26:33 +00001591 def test_existing_file_inside_dest_dir(self):
1592 # A file with the same name inside the destination dir already exists.
1593 with open(self.dst_file, "wb"):
1594 pass
1595 self.assertRaises(shutil.Error, shutil.move, self.src_file, self.dst_dir)
1596
1597 def test_dont_move_dir_in_itself(self):
1598 # Moving a dir inside itself raises an Error.
1599 dst = os.path.join(self.src_dir, "bar")
1600 self.assertRaises(shutil.Error, shutil.move, self.src_dir, dst)
1601
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001602 def test_destinsrc_false_negative(self):
1603 os.mkdir(TESTFN)
1604 try:
1605 for src, dst in [('srcdir', 'srcdir/dest')]:
1606 src = os.path.join(TESTFN, src)
1607 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001608 self.assertTrue(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001609 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001610 'dst (%s) is not in src (%s)' % (dst, src))
1611 finally:
1612 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001613
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001614 def test_destinsrc_false_positive(self):
1615 os.mkdir(TESTFN)
1616 try:
1617 for src, dst in [('srcdir', 'src/dest'), ('srcdir', 'srcdir.new')]:
1618 src = os.path.join(TESTFN, src)
1619 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001620 self.assertFalse(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001621 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001622 'dst (%s) is in src (%s)' % (dst, src))
1623 finally:
1624 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimes9bd667a2008-01-20 15:14:11 +00001625
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +01001626 @support.skip_unless_symlink
1627 @mock_rename
1628 def test_move_file_symlink(self):
1629 dst = os.path.join(self.src_dir, 'bar')
1630 os.symlink(self.src_file, dst)
1631 shutil.move(dst, self.dst_file)
1632 self.assertTrue(os.path.islink(self.dst_file))
1633 self.assertTrue(os.path.samefile(self.src_file, self.dst_file))
1634
1635 @support.skip_unless_symlink
1636 @mock_rename
1637 def test_move_file_symlink_to_dir(self):
1638 filename = "bar"
1639 dst = os.path.join(self.src_dir, filename)
1640 os.symlink(self.src_file, dst)
1641 shutil.move(dst, self.dst_dir)
1642 final_link = os.path.join(self.dst_dir, filename)
1643 self.assertTrue(os.path.islink(final_link))
1644 self.assertTrue(os.path.samefile(self.src_file, final_link))
1645
1646 @support.skip_unless_symlink
1647 @mock_rename
1648 def test_move_dangling_symlink(self):
1649 src = os.path.join(self.src_dir, 'baz')
1650 dst = os.path.join(self.src_dir, 'bar')
1651 os.symlink(src, dst)
1652 dst_link = os.path.join(self.dst_dir, 'quux')
1653 shutil.move(dst, dst_link)
1654 self.assertTrue(os.path.islink(dst_link))
Antoine Pitrou3f48ac92014-01-01 02:50:45 +01001655 # On Windows, os.path.realpath does not follow symlinks (issue #9949)
1656 if os.name == 'nt':
1657 self.assertEqual(os.path.realpath(src), os.readlink(dst_link))
1658 else:
1659 self.assertEqual(os.path.realpath(src), os.path.realpath(dst_link))
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +01001660
1661 @support.skip_unless_symlink
1662 @mock_rename
1663 def test_move_dir_symlink(self):
1664 src = os.path.join(self.src_dir, 'baz')
1665 dst = os.path.join(self.src_dir, 'bar')
1666 os.mkdir(src)
1667 os.symlink(src, dst)
1668 dst_link = os.path.join(self.dst_dir, 'quux')
1669 shutil.move(dst, dst_link)
1670 self.assertTrue(os.path.islink(dst_link))
1671 self.assertTrue(os.path.samefile(src, dst_link))
1672
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001673 def test_move_return_value(self):
1674 rv = shutil.move(self.src_file, self.dst_dir)
1675 self.assertEqual(rv,
1676 os.path.join(self.dst_dir, os.path.basename(self.src_file)))
1677
1678 def test_move_as_rename_return_value(self):
1679 rv = shutil.move(self.src_file, os.path.join(self.dst_dir, 'bar'))
1680 self.assertEqual(rv, os.path.join(self.dst_dir, 'bar'))
1681
R David Murray6ffface2014-06-11 14:40:13 -04001682 @mock_rename
1683 def test_move_file_special_function(self):
1684 moved = []
1685 def _copy(src, dst):
1686 moved.append((src, dst))
1687 shutil.move(self.src_file, self.dst_dir, copy_function=_copy)
1688 self.assertEqual(len(moved), 1)
1689
1690 @mock_rename
1691 def test_move_dir_special_function(self):
1692 moved = []
1693 def _copy(src, dst):
1694 moved.append((src, dst))
1695 support.create_empty_file(os.path.join(self.src_dir, 'child'))
1696 support.create_empty_file(os.path.join(self.src_dir, 'child1'))
1697 shutil.move(self.src_dir, self.dst_dir, copy_function=_copy)
1698 self.assertEqual(len(moved), 3)
1699
Tarek Ziadé5340db32010-04-19 22:30:51 +00001700
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001701class TestCopyFile(unittest.TestCase):
1702
1703 _delete = False
1704
1705 class Faux(object):
1706 _entered = False
1707 _exited_with = None
1708 _raised = False
1709 def __init__(self, raise_in_exit=False, suppress_at_exit=True):
1710 self._raise_in_exit = raise_in_exit
1711 self._suppress_at_exit = suppress_at_exit
1712 def read(self, *args):
1713 return ''
1714 def __enter__(self):
1715 self._entered = True
1716 def __exit__(self, exc_type, exc_val, exc_tb):
1717 self._exited_with = exc_type, exc_val, exc_tb
1718 if self._raise_in_exit:
1719 self._raised = True
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001720 raise OSError("Cannot close")
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001721 return self._suppress_at_exit
1722
1723 def tearDown(self):
1724 if self._delete:
1725 del shutil.open
1726
1727 def _set_shutil_open(self, func):
1728 shutil.open = func
1729 self._delete = True
1730
1731 def test_w_source_open_fails(self):
1732 def _open(filename, mode='r'):
1733 if filename == 'srcfile':
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001734 raise OSError('Cannot open "srcfile"')
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001735 assert 0 # shouldn't reach here.
1736
1737 self._set_shutil_open(_open)
1738
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001739 self.assertRaises(OSError, shutil.copyfile, 'srcfile', 'destfile')
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001740
1741 def test_w_dest_open_fails(self):
1742
1743 srcfile = self.Faux()
1744
1745 def _open(filename, mode='r'):
1746 if filename == 'srcfile':
1747 return srcfile
1748 if filename == 'destfile':
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001749 raise OSError('Cannot open "destfile"')
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001750 assert 0 # shouldn't reach here.
1751
1752 self._set_shutil_open(_open)
1753
1754 shutil.copyfile('srcfile', 'destfile')
1755 self.assertTrue(srcfile._entered)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001756 self.assertTrue(srcfile._exited_with[0] is OSError)
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001757 self.assertEqual(srcfile._exited_with[1].args,
1758 ('Cannot open "destfile"',))
1759
1760 def test_w_dest_close_fails(self):
1761
1762 srcfile = self.Faux()
1763 destfile = self.Faux(True)
1764
1765 def _open(filename, mode='r'):
1766 if filename == 'srcfile':
1767 return srcfile
1768 if filename == 'destfile':
1769 return destfile
1770 assert 0 # shouldn't reach here.
1771
1772 self._set_shutil_open(_open)
1773
1774 shutil.copyfile('srcfile', 'destfile')
1775 self.assertTrue(srcfile._entered)
1776 self.assertTrue(destfile._entered)
1777 self.assertTrue(destfile._raised)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001778 self.assertTrue(srcfile._exited_with[0] is OSError)
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001779 self.assertEqual(srcfile._exited_with[1].args,
1780 ('Cannot close',))
1781
1782 def test_w_source_close_fails(self):
1783
1784 srcfile = self.Faux(True)
1785 destfile = self.Faux()
1786
1787 def _open(filename, mode='r'):
1788 if filename == 'srcfile':
1789 return srcfile
1790 if filename == 'destfile':
1791 return destfile
1792 assert 0 # shouldn't reach here.
1793
1794 self._set_shutil_open(_open)
1795
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001796 self.assertRaises(OSError,
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001797 shutil.copyfile, 'srcfile', 'destfile')
1798 self.assertTrue(srcfile._entered)
1799 self.assertTrue(destfile._entered)
1800 self.assertFalse(destfile._raised)
1801 self.assertTrue(srcfile._exited_with[0] is None)
1802 self.assertTrue(srcfile._raised)
1803
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001804 def test_move_dir_caseinsensitive(self):
1805 # Renames a folder to the same name
1806 # but a different case.
1807
1808 self.src_dir = tempfile.mkdtemp()
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001809 self.addCleanup(shutil.rmtree, self.src_dir, True)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001810 dst_dir = os.path.join(
1811 os.path.dirname(self.src_dir),
1812 os.path.basename(self.src_dir).upper())
1813 self.assertNotEqual(self.src_dir, dst_dir)
1814
1815 try:
1816 shutil.move(self.src_dir, dst_dir)
1817 self.assertTrue(os.path.isdir(dst_dir))
1818 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +02001819 os.rmdir(dst_dir)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001820
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001821class TermsizeTests(unittest.TestCase):
1822 def test_does_not_crash(self):
1823 """Check if get_terminal_size() returns a meaningful value.
1824
1825 There's no easy portable way to actually check the size of the
1826 terminal, so let's check if it returns something sensible instead.
1827 """
1828 size = shutil.get_terminal_size()
Antoine Pitroucfade362012-02-08 23:48:59 +01001829 self.assertGreaterEqual(size.columns, 0)
1830 self.assertGreaterEqual(size.lines, 0)
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001831
1832 def test_os_environ_first(self):
1833 "Check if environment variables have precedence"
1834
1835 with support.EnvironmentVarGuard() as env:
1836 env['COLUMNS'] = '777'
Serhiy Storchakad30829d2016-04-24 09:58:43 +03001837 del env['LINES']
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001838 size = shutil.get_terminal_size()
1839 self.assertEqual(size.columns, 777)
1840
1841 with support.EnvironmentVarGuard() as env:
Serhiy Storchakad30829d2016-04-24 09:58:43 +03001842 del env['COLUMNS']
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001843 env['LINES'] = '888'
1844 size = shutil.get_terminal_size()
1845 self.assertEqual(size.lines, 888)
1846
Serhiy Storchakad30829d2016-04-24 09:58:43 +03001847 def test_bad_environ(self):
1848 with support.EnvironmentVarGuard() as env:
1849 env['COLUMNS'] = 'xxx'
1850 env['LINES'] = 'yyy'
1851 size = shutil.get_terminal_size()
1852 self.assertGreaterEqual(size.columns, 0)
1853 self.assertGreaterEqual(size.lines, 0)
1854
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001855 @unittest.skipUnless(os.isatty(sys.__stdout__.fileno()), "not on tty")
Victor Stinner119ebb72016-04-19 22:24:56 +02001856 @unittest.skipUnless(hasattr(os, 'get_terminal_size'),
1857 'need os.get_terminal_size()')
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001858 def test_stty_match(self):
1859 """Check if stty returns the same results ignoring env
1860
1861 This test will fail if stdin and stdout are connected to
1862 different terminals with different sizes. Nevertheless, such
1863 situations should be pretty rare.
1864 """
1865 try:
1866 size = subprocess.check_output(['stty', 'size']).decode().split()
1867 except (FileNotFoundError, subprocess.CalledProcessError):
1868 self.skipTest("stty invocation failed")
1869 expected = (int(size[1]), int(size[0])) # reversed order
1870
1871 with support.EnvironmentVarGuard() as env:
1872 del env['LINES']
1873 del env['COLUMNS']
1874 actual = shutil.get_terminal_size()
1875
1876 self.assertEqual(expected, actual)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001877
Serhiy Storchakad30829d2016-04-24 09:58:43 +03001878 def test_fallback(self):
1879 with support.EnvironmentVarGuard() as env:
1880 del env['LINES']
1881 del env['COLUMNS']
1882
1883 # sys.__stdout__ has no fileno()
1884 with support.swap_attr(sys, '__stdout__', None):
1885 size = shutil.get_terminal_size(fallback=(10, 20))
1886 self.assertEqual(size.columns, 10)
1887 self.assertEqual(size.lines, 20)
1888
1889 # sys.__stdout__ is not a terminal on Unix
1890 # or fileno() not in (0, 1, 2) on Windows
1891 with open(os.devnull, 'w') as f, \
1892 support.swap_attr(sys, '__stdout__', f):
1893 size = shutil.get_terminal_size(fallback=(30, 40))
1894 self.assertEqual(size.columns, 30)
1895 self.assertEqual(size.lines, 40)
1896
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001897
Berker Peksag8083cd62014-11-01 11:04:06 +02001898class PublicAPITests(unittest.TestCase):
1899 """Ensures that the correct values are exposed in the public API."""
1900
1901 def test_module_all_attribute(self):
1902 self.assertTrue(hasattr(shutil, '__all__'))
1903 target_api = ['copyfileobj', 'copyfile', 'copymode', 'copystat',
1904 'copy', 'copy2', 'copytree', 'move', 'rmtree', 'Error',
1905 'SpecialFileError', 'ExecError', 'make_archive',
1906 'get_archive_formats', 'register_archive_format',
1907 'unregister_archive_format', 'get_unpack_formats',
1908 'register_unpack_format', 'unregister_unpack_format',
1909 'unpack_archive', 'ignore_patterns', 'chown', 'which',
1910 'get_terminal_size', 'SameFileError']
1911 if hasattr(os, 'statvfs') or os.name == 'nt':
1912 target_api.append('disk_usage')
1913 self.assertEqual(set(shutil.__all__), set(target_api))
1914
1915
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001916if __name__ == '__main__':
Brett Cannon3e9a9ae2013-06-12 21:25:59 -04001917 unittest.main()