blob: c7f7d1d3e6157f0f258491266dec9a5331c50f3c [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 Storchaka527ef072015-09-06 18:33:19 +030014from shutil import (make_archive,
Tarek Ziadé396fad72010-02-23 05:30:31 +000015 register_archive_format, unregister_archive_format,
Tarek Ziadé6ac91722010-04-28 17:51:36 +000016 get_archive_formats, Error, unpack_archive,
17 register_unpack_format, RegistryError,
Hynek Schlawack48653762012-10-07 12:49:58 +020018 unregister_unpack_format, get_unpack_formats,
19 SameFileError)
Tarek Ziadé396fad72010-02-23 05:30:31 +000020import tarfile
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +020021import zipfile
Tarek Ziadé396fad72010-02-23 05:30:31 +000022
23from test import support
Victor Stinnerd6debb22017-03-27 16:05:26 +020024from test.support import TESTFN, android_not_root
Serhiy Storchaka11213772014-08-06 18:50:19 +030025
Antoine Pitrou7fff0962009-05-01 21:09:44 +000026TESTFN2 = TESTFN + "2"
Barry Warsaw7fc2cca2003-01-24 17:34:13 +000027
Tarek Ziadé396fad72010-02-23 05:30:31 +000028try:
29 import grp
30 import pwd
31 UID_GID_SUPPORT = True
32except ImportError:
33 UID_GID_SUPPORT = False
34
Nick Coghlan8ed3cf32011-03-16 14:05:35 -040035def _fake_rename(*args, **kwargs):
36 # Pretend the destination path is on a different filesystem.
Antoine Pitrouc041ab62012-01-02 19:18:02 +010037 raise OSError(getattr(errno, 'EXDEV', 18), "Invalid cross-device link")
Nick Coghlan8ed3cf32011-03-16 14:05:35 -040038
39def mock_rename(func):
40 @functools.wraps(func)
41 def wrap(*args, **kwargs):
42 try:
43 builtin_rename = os.rename
44 os.rename = _fake_rename
45 return func(*args, **kwargs)
46 finally:
47 os.rename = builtin_rename
48 return wrap
49
Éric Araujoa7e33a12011-08-12 19:51:35 +020050def write_file(path, content, binary=False):
51 """Write *content* to a file located at *path*.
52
53 If *path* is a tuple instead of a string, os.path.join will be used to
54 make a path. If *binary* is true, the file will be opened in binary
55 mode.
56 """
57 if isinstance(path, tuple):
58 path = os.path.join(*path)
59 with open(path, 'wb' if binary else 'w') as fp:
60 fp.write(content)
61
62def read_file(path, binary=False):
63 """Return contents from a file located at *path*.
64
65 If *path* is a tuple instead of a string, os.path.join will be used to
66 make a path. If *binary* is true, the file will be opened in binary
67 mode.
68 """
69 if isinstance(path, tuple):
70 path = os.path.join(*path)
71 with open(path, 'rb' if binary else 'r') as fp:
72 return fp.read()
73
Serhiy Storchaka527ef072015-09-06 18:33:19 +030074def rlistdir(path):
75 res = []
76 for name in sorted(os.listdir(path)):
77 p = os.path.join(path, name)
78 if os.path.isdir(p) and not os.path.islink(p):
79 res.append(name + '/')
80 for n in rlistdir(p):
81 res.append(name + '/' + n)
82 else:
83 res.append(name)
84 return res
85
Éric Araujoa7e33a12011-08-12 19:51:35 +020086
Barry Warsaw7fc2cca2003-01-24 17:34:13 +000087class TestShutil(unittest.TestCase):
Tarek Ziadé396fad72010-02-23 05:30:31 +000088
89 def setUp(self):
90 super(TestShutil, self).setUp()
91 self.tempdirs = []
92
93 def tearDown(self):
94 super(TestShutil, self).tearDown()
95 while self.tempdirs:
96 d = self.tempdirs.pop()
97 shutil.rmtree(d, os.name in ('nt', 'cygwin'))
98
Tarek Ziadé396fad72010-02-23 05:30:31 +000099
100 def mkdtemp(self):
101 """Create a temporary directory that will be cleaned up.
102
103 Returns the path of the directory.
104 """
105 d = tempfile.mkdtemp()
106 self.tempdirs.append(d)
107 return d
Tarek Ziadé5340db32010-04-19 22:30:51 +0000108
Hynek Schlawack3b527782012-06-25 13:27:31 +0200109 def test_rmtree_works_on_bytes(self):
110 tmp = self.mkdtemp()
111 victim = os.path.join(tmp, 'killme')
112 os.mkdir(victim)
113 write_file(os.path.join(victim, 'somefile'), 'foo')
114 victim = os.fsencode(victim)
115 self.assertIsInstance(victim, bytes)
Steve Dowere58571b2016-09-08 11:11:13 -0700116 shutil.rmtree(victim)
Hynek Schlawack3b527782012-06-25 13:27:31 +0200117
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200118 @support.skip_unless_symlink
119 def test_rmtree_fails_on_symlink(self):
120 tmp = self.mkdtemp()
121 dir_ = os.path.join(tmp, 'dir')
122 os.mkdir(dir_)
123 link = os.path.join(tmp, 'link')
124 os.symlink(dir_, link)
125 self.assertRaises(OSError, shutil.rmtree, link)
126 self.assertTrue(os.path.exists(dir_))
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100127 self.assertTrue(os.path.lexists(link))
128 errors = []
129 def onerror(*args):
130 errors.append(args)
131 shutil.rmtree(link, onerror=onerror)
132 self.assertEqual(len(errors), 1)
133 self.assertIs(errors[0][0], os.path.islink)
134 self.assertEqual(errors[0][1], link)
135 self.assertIsInstance(errors[0][2][1], OSError)
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200136
137 @support.skip_unless_symlink
138 def test_rmtree_works_on_symlinks(self):
139 tmp = self.mkdtemp()
140 dir1 = os.path.join(tmp, 'dir1')
141 dir2 = os.path.join(dir1, 'dir2')
142 dir3 = os.path.join(tmp, 'dir3')
143 for d in dir1, dir2, dir3:
144 os.mkdir(d)
145 file1 = os.path.join(tmp, 'file1')
146 write_file(file1, 'foo')
147 link1 = os.path.join(dir1, 'link1')
148 os.symlink(dir2, link1)
149 link2 = os.path.join(dir1, 'link2')
150 os.symlink(dir3, link2)
151 link3 = os.path.join(dir1, 'link3')
152 os.symlink(file1, link3)
153 # make sure symlinks are removed but not followed
154 shutil.rmtree(dir1)
155 self.assertFalse(os.path.exists(dir1))
156 self.assertTrue(os.path.exists(dir3))
157 self.assertTrue(os.path.exists(file1))
158
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000159 def test_rmtree_errors(self):
160 # filename is guaranteed not to exist
161 filename = tempfile.mktemp()
Hynek Schlawackb5501102012-12-10 09:11:25 +0100162 self.assertRaises(FileNotFoundError, shutil.rmtree, filename)
163 # test that ignore_errors option is honored
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100164 shutil.rmtree(filename, ignore_errors=True)
165
166 # existing file
167 tmpdir = self.mkdtemp()
Hynek Schlawackb5501102012-12-10 09:11:25 +0100168 write_file((tmpdir, "tstfile"), "")
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100169 filename = os.path.join(tmpdir, "tstfile")
Hynek Schlawackb5501102012-12-10 09:11:25 +0100170 with self.assertRaises(NotADirectoryError) as cm:
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100171 shutil.rmtree(filename)
Hynek Schlawack87f9b462012-12-10 16:29:57 +0100172 # The reason for this rather odd construct is that Windows sprinkles
173 # a \*.* at the end of file names. But only sometimes on some buildbots
174 possible_args = [filename, os.path.join(filename, '*.*')]
175 self.assertIn(cm.exception.filename, possible_args)
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100176 self.assertTrue(os.path.exists(filename))
Hynek Schlawackb5501102012-12-10 09:11:25 +0100177 # test that ignore_errors option is honored
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100178 shutil.rmtree(filename, ignore_errors=True)
179 self.assertTrue(os.path.exists(filename))
180 errors = []
181 def onerror(*args):
182 errors.append(args)
183 shutil.rmtree(filename, onerror=onerror)
184 self.assertEqual(len(errors), 2)
185 self.assertIs(errors[0][0], os.listdir)
186 self.assertEqual(errors[0][1], filename)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100187 self.assertIsInstance(errors[0][2][1], NotADirectoryError)
Hynek Schlawack87f9b462012-12-10 16:29:57 +0100188 self.assertIn(errors[0][2][1].filename, possible_args)
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100189 self.assertIs(errors[1][0], os.rmdir)
190 self.assertEqual(errors[1][1], filename)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100191 self.assertIsInstance(errors[1][2][1], NotADirectoryError)
Hynek Schlawack87f9b462012-12-10 16:29:57 +0100192 self.assertIn(errors[1][2][1].filename, possible_args)
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000193
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000194
Serhiy Storchaka43767632013-11-03 21:31:38 +0200195 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod()')
196 @unittest.skipIf(sys.platform[:6] == 'cygwin',
197 "This test can't be run on Cygwin (issue #1071513).")
198 @unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0,
199 "This test can't be run reliably as root (issue #1076467).")
200 def test_on_error(self):
201 self.errorState = 0
202 os.mkdir(TESTFN)
203 self.addCleanup(shutil.rmtree, TESTFN)
Antoine Pitrou2f8a75c2012-06-23 21:28:15 +0200204
Serhiy Storchaka43767632013-11-03 21:31:38 +0200205 self.child_file_path = os.path.join(TESTFN, 'a')
206 self.child_dir_path = os.path.join(TESTFN, 'b')
207 support.create_empty_file(self.child_file_path)
208 os.mkdir(self.child_dir_path)
209 old_dir_mode = os.stat(TESTFN).st_mode
210 old_child_file_mode = os.stat(self.child_file_path).st_mode
211 old_child_dir_mode = os.stat(self.child_dir_path).st_mode
212 # Make unwritable.
213 new_mode = stat.S_IREAD|stat.S_IEXEC
214 os.chmod(self.child_file_path, new_mode)
215 os.chmod(self.child_dir_path, new_mode)
216 os.chmod(TESTFN, new_mode)
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000217
Serhiy Storchaka43767632013-11-03 21:31:38 +0200218 self.addCleanup(os.chmod, TESTFN, old_dir_mode)
219 self.addCleanup(os.chmod, self.child_file_path, old_child_file_mode)
220 self.addCleanup(os.chmod, self.child_dir_path, old_child_dir_mode)
Antoine Pitrou2f8a75c2012-06-23 21:28:15 +0200221
Serhiy Storchaka43767632013-11-03 21:31:38 +0200222 shutil.rmtree(TESTFN, onerror=self.check_args_to_onerror)
223 # Test whether onerror has actually been called.
224 self.assertEqual(self.errorState, 3,
225 "Expected call to onerror function did not happen.")
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000226
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000227 def check_args_to_onerror(self, func, arg, exc):
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000228 # test_rmtree_errors deliberately runs rmtree
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200229 # on a directory that is chmod 500, which will fail.
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000230 # This function is run when shutil.rmtree fails.
231 # 99.9% of the time it initially fails to remove
232 # a file in the directory, so the first time through
233 # func is os.remove.
234 # However, some Linux machines running ZFS on
235 # FUSE experienced a failure earlier in the process
236 # at os.listdir. The first failure may legally
237 # be either.
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200238 if self.errorState < 2:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200239 if func is os.unlink:
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200240 self.assertEqual(arg, self.child_file_path)
241 elif func is os.rmdir:
242 self.assertEqual(arg, self.child_dir_path)
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000243 else:
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200244 self.assertIs(func, os.listdir)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200245 self.assertIn(arg, [TESTFN, self.child_dir_path])
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000246 self.assertTrue(issubclass(exc[0], OSError))
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200247 self.errorState += 1
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000248 else:
249 self.assertEqual(func, os.rmdir)
250 self.assertEqual(arg, TESTFN)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000251 self.assertTrue(issubclass(exc[0], OSError))
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200252 self.errorState = 3
253
254 def test_rmtree_does_not_choke_on_failing_lstat(self):
255 try:
256 orig_lstat = os.lstat
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200257 def raiser(fn, *args, **kwargs):
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200258 if fn != TESTFN:
259 raise OSError()
260 else:
261 return orig_lstat(fn)
262 os.lstat = raiser
263
264 os.mkdir(TESTFN)
265 write_file((TESTFN, 'foo'), 'foo')
266 shutil.rmtree(TESTFN)
267 finally:
268 os.lstat = orig_lstat
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000269
Antoine Pitrou78091e62011-12-29 18:54:15 +0100270 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
271 @support.skip_unless_symlink
272 def test_copymode_follow_symlinks(self):
273 tmp_dir = self.mkdtemp()
274 src = os.path.join(tmp_dir, 'foo')
275 dst = os.path.join(tmp_dir, 'bar')
276 src_link = os.path.join(tmp_dir, 'baz')
277 dst_link = os.path.join(tmp_dir, 'quux')
278 write_file(src, 'foo')
279 write_file(dst, 'foo')
280 os.symlink(src, src_link)
281 os.symlink(dst, dst_link)
282 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
283 # file to file
284 os.chmod(dst, stat.S_IRWXO)
285 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
286 shutil.copymode(src, dst)
287 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
Antoine Pitrou3f48ac92014-01-01 02:50:45 +0100288 # On Windows, os.chmod does not follow symlinks (issue #15411)
289 if os.name != 'nt':
290 # follow src link
291 os.chmod(dst, stat.S_IRWXO)
292 shutil.copymode(src_link, dst)
293 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
294 # follow dst link
295 os.chmod(dst, stat.S_IRWXO)
296 shutil.copymode(src, dst_link)
297 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
298 # follow both links
299 os.chmod(dst, stat.S_IRWXO)
300 shutil.copymode(src_link, dst_link)
301 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100302
303 @unittest.skipUnless(hasattr(os, 'lchmod'), 'requires os.lchmod')
304 @support.skip_unless_symlink
305 def test_copymode_symlink_to_symlink(self):
306 tmp_dir = self.mkdtemp()
307 src = os.path.join(tmp_dir, 'foo')
308 dst = os.path.join(tmp_dir, 'bar')
309 src_link = os.path.join(tmp_dir, 'baz')
310 dst_link = os.path.join(tmp_dir, 'quux')
311 write_file(src, 'foo')
312 write_file(dst, 'foo')
313 os.symlink(src, src_link)
314 os.symlink(dst, dst_link)
315 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
316 os.chmod(dst, stat.S_IRWXU)
317 os.lchmod(src_link, stat.S_IRWXO|stat.S_IRWXG)
318 # link to link
319 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700320 shutil.copymode(src_link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100321 self.assertEqual(os.lstat(src_link).st_mode,
322 os.lstat(dst_link).st_mode)
323 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
324 # src link - use chmod
325 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700326 shutil.copymode(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100327 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
328 # dst link - use chmod
329 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700330 shutil.copymode(src, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100331 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
332
333 @unittest.skipIf(hasattr(os, 'lchmod'), 'requires os.lchmod to be missing')
334 @support.skip_unless_symlink
335 def test_copymode_symlink_to_symlink_wo_lchmod(self):
336 tmp_dir = self.mkdtemp()
337 src = os.path.join(tmp_dir, 'foo')
338 dst = os.path.join(tmp_dir, 'bar')
339 src_link = os.path.join(tmp_dir, 'baz')
340 dst_link = os.path.join(tmp_dir, 'quux')
341 write_file(src, 'foo')
342 write_file(dst, 'foo')
343 os.symlink(src, src_link)
344 os.symlink(dst, dst_link)
Larry Hastingsb4038062012-07-15 10:57:38 -0700345 shutil.copymode(src_link, dst_link, follow_symlinks=False) # silent fail
Antoine Pitrou78091e62011-12-29 18:54:15 +0100346
347 @support.skip_unless_symlink
348 def test_copystat_symlinks(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, 'qux')
354 write_file(src, 'foo')
355 src_stat = os.stat(src)
356 os.utime(src, (src_stat.st_atime,
357 src_stat.st_mtime - 42.0)) # ensure different mtimes
358 write_file(dst, 'bar')
359 self.assertNotEqual(os.stat(src).st_mtime, os.stat(dst).st_mtime)
360 os.symlink(src, src_link)
361 os.symlink(dst, dst_link)
362 if hasattr(os, 'lchmod'):
363 os.lchmod(src_link, stat.S_IRWXO)
364 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
365 os.lchflags(src_link, stat.UF_NODUMP)
366 src_link_stat = os.lstat(src_link)
367 # follow
368 if hasattr(os, 'lchmod'):
Larry Hastingsb4038062012-07-15 10:57:38 -0700369 shutil.copystat(src_link, dst_link, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100370 self.assertNotEqual(src_link_stat.st_mode, os.stat(dst).st_mode)
371 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700372 shutil.copystat(src_link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100373 dst_link_stat = os.lstat(dst_link)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700374 if os.utime in os.supports_follow_symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100375 for attr in 'st_atime', 'st_mtime':
376 # The modification times may be truncated in the new file.
377 self.assertLessEqual(getattr(src_link_stat, attr),
378 getattr(dst_link_stat, attr) + 1)
379 if hasattr(os, 'lchmod'):
380 self.assertEqual(src_link_stat.st_mode, dst_link_stat.st_mode)
381 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
382 self.assertEqual(src_link_stat.st_flags, dst_link_stat.st_flags)
383 # tell to follow but dst is not a link
Larry Hastingsb4038062012-07-15 10:57:38 -0700384 shutil.copystat(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100385 self.assertTrue(abs(os.stat(src).st_mtime - os.stat(dst).st_mtime) <
386 00000.1)
387
Ned Deilybaf75712012-05-10 17:05:19 -0700388 @unittest.skipUnless(hasattr(os, 'chflags') and
389 hasattr(errno, 'EOPNOTSUPP') and
390 hasattr(errno, 'ENOTSUP'),
391 "requires os.chflags, EOPNOTSUPP & ENOTSUP")
392 def test_copystat_handles_harmless_chflags_errors(self):
393 tmpdir = self.mkdtemp()
394 file1 = os.path.join(tmpdir, 'file1')
395 file2 = os.path.join(tmpdir, 'file2')
396 write_file(file1, 'xxx')
397 write_file(file2, 'xxx')
398
399 def make_chflags_raiser(err):
400 ex = OSError()
401
Larry Hastings90867a52012-06-22 17:01:41 -0700402 def _chflags_raiser(path, flags, *, follow_symlinks=True):
Ned Deilybaf75712012-05-10 17:05:19 -0700403 ex.errno = err
404 raise ex
405 return _chflags_raiser
406 old_chflags = os.chflags
407 try:
408 for err in errno.EOPNOTSUPP, errno.ENOTSUP:
409 os.chflags = make_chflags_raiser(err)
410 shutil.copystat(file1, file2)
411 # assert others errors break it
412 os.chflags = make_chflags_raiser(errno.EOPNOTSUPP + errno.ENOTSUP)
413 self.assertRaises(OSError, shutil.copystat, file1, file2)
414 finally:
415 os.chflags = old_chflags
416
Antoine Pitrou424246f2012-05-12 19:02:01 +0200417 @support.skip_unless_xattr
418 def test_copyxattr(self):
419 tmp_dir = self.mkdtemp()
420 src = os.path.join(tmp_dir, 'foo')
421 write_file(src, 'foo')
422 dst = os.path.join(tmp_dir, 'bar')
423 write_file(dst, 'bar')
424
425 # no xattr == no problem
426 shutil._copyxattr(src, dst)
427 # common case
428 os.setxattr(src, 'user.foo', b'42')
429 os.setxattr(src, 'user.bar', b'43')
430 shutil._copyxattr(src, dst)
Gregory P. Smith1093bf22014-01-17 12:01:22 -0800431 self.assertEqual(sorted(os.listxattr(src)), sorted(os.listxattr(dst)))
Antoine Pitrou424246f2012-05-12 19:02:01 +0200432 self.assertEqual(
433 os.getxattr(src, 'user.foo'),
434 os.getxattr(dst, 'user.foo'))
435 # check errors don't affect other attrs
436 os.remove(dst)
437 write_file(dst, 'bar')
438 os_error = OSError(errno.EPERM, 'EPERM')
439
Larry Hastings9cf065c2012-06-22 16:30:09 -0700440 def _raise_on_user_foo(fname, attr, val, **kwargs):
Antoine Pitrou424246f2012-05-12 19:02:01 +0200441 if attr == 'user.foo':
442 raise os_error
443 else:
Larry Hastings9cf065c2012-06-22 16:30:09 -0700444 orig_setxattr(fname, attr, val, **kwargs)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200445 try:
446 orig_setxattr = os.setxattr
447 os.setxattr = _raise_on_user_foo
448 shutil._copyxattr(src, dst)
Antoine Pitrou61597d32012-05-12 23:37:35 +0200449 self.assertIn('user.bar', os.listxattr(dst))
Antoine Pitrou424246f2012-05-12 19:02:01 +0200450 finally:
451 os.setxattr = orig_setxattr
Hynek Schlawack0beab052013-02-05 08:22:44 +0100452 # the source filesystem not supporting xattrs should be ok, too.
453 def _raise_on_src(fname, *, follow_symlinks=True):
454 if fname == src:
455 raise OSError(errno.ENOTSUP, 'Operation not supported')
456 return orig_listxattr(fname, follow_symlinks=follow_symlinks)
457 try:
458 orig_listxattr = os.listxattr
459 os.listxattr = _raise_on_src
460 shutil._copyxattr(src, dst)
461 finally:
462 os.listxattr = orig_listxattr
Antoine Pitrou424246f2012-05-12 19:02:01 +0200463
Larry Hastingsad5ae042012-07-14 17:55:11 -0700464 # test that shutil.copystat copies xattrs
465 src = os.path.join(tmp_dir, 'the_original')
466 write_file(src, src)
467 os.setxattr(src, 'user.the_value', b'fiddly')
468 dst = os.path.join(tmp_dir, 'the_copy')
469 write_file(dst, dst)
470 shutil.copystat(src, dst)
Hynek Schlawackc2d481f2012-07-16 17:11:10 +0200471 self.assertEqual(os.getxattr(dst, 'user.the_value'), b'fiddly')
Larry Hastingsad5ae042012-07-14 17:55:11 -0700472
Antoine Pitrou424246f2012-05-12 19:02:01 +0200473 @support.skip_unless_symlink
474 @support.skip_unless_xattr
475 @unittest.skipUnless(hasattr(os, 'geteuid') and os.geteuid() == 0,
476 'root privileges required')
477 def test_copyxattr_symlinks(self):
478 # On Linux, it's only possible to access non-user xattr for symlinks;
479 # which in turn require root privileges. This test should be expanded
480 # as soon as other platforms gain support for extended attributes.
481 tmp_dir = self.mkdtemp()
482 src = os.path.join(tmp_dir, 'foo')
483 src_link = os.path.join(tmp_dir, 'baz')
484 write_file(src, 'foo')
485 os.symlink(src, src_link)
486 os.setxattr(src, 'trusted.foo', b'42')
Larry Hastings9cf065c2012-06-22 16:30:09 -0700487 os.setxattr(src_link, 'trusted.foo', b'43', follow_symlinks=False)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200488 dst = os.path.join(tmp_dir, 'bar')
489 dst_link = os.path.join(tmp_dir, 'qux')
490 write_file(dst, 'bar')
491 os.symlink(dst, dst_link)
Larry Hastingsb4038062012-07-15 10:57:38 -0700492 shutil._copyxattr(src_link, dst_link, follow_symlinks=False)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700493 self.assertEqual(os.getxattr(dst_link, 'trusted.foo', follow_symlinks=False), b'43')
Antoine Pitrou424246f2012-05-12 19:02:01 +0200494 self.assertRaises(OSError, os.getxattr, dst, 'trusted.foo')
Larry Hastingsb4038062012-07-15 10:57:38 -0700495 shutil._copyxattr(src_link, dst, follow_symlinks=False)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200496 self.assertEqual(os.getxattr(dst, 'trusted.foo'), b'43')
497
Antoine Pitrou78091e62011-12-29 18:54:15 +0100498 @support.skip_unless_symlink
499 def test_copy_symlinks(self):
500 tmp_dir = self.mkdtemp()
501 src = os.path.join(tmp_dir, 'foo')
502 dst = os.path.join(tmp_dir, 'bar')
503 src_link = os.path.join(tmp_dir, 'baz')
504 write_file(src, 'foo')
505 os.symlink(src, src_link)
506 if hasattr(os, 'lchmod'):
507 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
508 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700509 shutil.copy(src_link, dst, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100510 self.assertFalse(os.path.islink(dst))
511 self.assertEqual(read_file(src), read_file(dst))
512 os.remove(dst)
513 # follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700514 shutil.copy(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100515 self.assertTrue(os.path.islink(dst))
516 self.assertEqual(os.readlink(dst), os.readlink(src_link))
517 if hasattr(os, 'lchmod'):
518 self.assertEqual(os.lstat(src_link).st_mode,
519 os.lstat(dst).st_mode)
520
521 @support.skip_unless_symlink
522 def test_copy2_symlinks(self):
523 tmp_dir = self.mkdtemp()
524 src = os.path.join(tmp_dir, 'foo')
525 dst = os.path.join(tmp_dir, 'bar')
526 src_link = os.path.join(tmp_dir, 'baz')
527 write_file(src, 'foo')
528 os.symlink(src, src_link)
529 if hasattr(os, 'lchmod'):
530 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
531 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
532 os.lchflags(src_link, stat.UF_NODUMP)
533 src_stat = os.stat(src)
534 src_link_stat = os.lstat(src_link)
535 # follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700536 shutil.copy2(src_link, dst, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100537 self.assertFalse(os.path.islink(dst))
538 self.assertEqual(read_file(src), read_file(dst))
539 os.remove(dst)
540 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700541 shutil.copy2(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100542 self.assertTrue(os.path.islink(dst))
543 self.assertEqual(os.readlink(dst), os.readlink(src_link))
544 dst_stat = os.lstat(dst)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700545 if os.utime in os.supports_follow_symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100546 for attr in 'st_atime', 'st_mtime':
547 # The modification times may be truncated in the new file.
548 self.assertLessEqual(getattr(src_link_stat, attr),
549 getattr(dst_stat, attr) + 1)
550 if hasattr(os, 'lchmod'):
551 self.assertEqual(src_link_stat.st_mode, dst_stat.st_mode)
552 self.assertNotEqual(src_stat.st_mode, dst_stat.st_mode)
553 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
554 self.assertEqual(src_link_stat.st_flags, dst_stat.st_flags)
555
Antoine Pitrou424246f2012-05-12 19:02:01 +0200556 @support.skip_unless_xattr
557 def test_copy2_xattr(self):
558 tmp_dir = self.mkdtemp()
559 src = os.path.join(tmp_dir, 'foo')
560 dst = os.path.join(tmp_dir, 'bar')
561 write_file(src, 'foo')
562 os.setxattr(src, 'user.foo', b'42')
563 shutil.copy2(src, dst)
564 self.assertEqual(
565 os.getxattr(src, 'user.foo'),
566 os.getxattr(dst, 'user.foo'))
567 os.remove(dst)
568
Antoine Pitrou78091e62011-12-29 18:54:15 +0100569 @support.skip_unless_symlink
570 def test_copyfile_symlinks(self):
571 tmp_dir = self.mkdtemp()
572 src = os.path.join(tmp_dir, 'src')
573 dst = os.path.join(tmp_dir, 'dst')
574 dst_link = os.path.join(tmp_dir, 'dst_link')
575 link = os.path.join(tmp_dir, 'link')
576 write_file(src, 'foo')
577 os.symlink(src, link)
578 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700579 shutil.copyfile(link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100580 self.assertTrue(os.path.islink(dst_link))
581 self.assertEqual(os.readlink(link), os.readlink(dst_link))
582 # follow
583 shutil.copyfile(link, dst)
584 self.assertFalse(os.path.islink(dst))
585
Hynek Schlawack2100b422012-06-23 20:28:32 +0200586 def test_rmtree_uses_safe_fd_version_if_available(self):
Hynek Schlawackd0f6e0a2012-06-29 08:28:20 +0200587 _use_fd_functions = ({os.open, os.stat, os.unlink, os.rmdir} <=
588 os.supports_dir_fd and
589 os.listdir in os.supports_fd and
590 os.stat in os.supports_follow_symlinks)
591 if _use_fd_functions:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200592 self.assertTrue(shutil._use_fd_functions)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000593 self.assertTrue(shutil.rmtree.avoids_symlink_attacks)
Hynek Schlawack2100b422012-06-23 20:28:32 +0200594 tmp_dir = self.mkdtemp()
595 d = os.path.join(tmp_dir, 'a')
596 os.mkdir(d)
597 try:
598 real_rmtree = shutil._rmtree_safe_fd
599 class Called(Exception): pass
600 def _raiser(*args, **kwargs):
601 raise Called
602 shutil._rmtree_safe_fd = _raiser
603 self.assertRaises(Called, shutil.rmtree, d)
604 finally:
605 shutil._rmtree_safe_fd = real_rmtree
606 else:
607 self.assertFalse(shutil._use_fd_functions)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000608 self.assertFalse(shutil.rmtree.avoids_symlink_attacks)
Hynek Schlawack2100b422012-06-23 20:28:32 +0200609
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000610 def test_rmtree_dont_delete_file(self):
611 # When called on a file instead of a directory, don't delete it.
612 handle, path = tempfile.mkstemp()
Victor Stinnerbf816222011-06-30 23:25:47 +0200613 os.close(handle)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200614 self.assertRaises(NotADirectoryError, shutil.rmtree, path)
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000615 os.remove(path)
616
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000617 def test_copytree_simple(self):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000618 src_dir = tempfile.mkdtemp()
619 dst_dir = os.path.join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200620 self.addCleanup(shutil.rmtree, src_dir)
621 self.addCleanup(shutil.rmtree, os.path.dirname(dst_dir))
622 write_file((src_dir, 'test.txt'), '123')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000623 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200624 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000625
Éric Araujoa7e33a12011-08-12 19:51:35 +0200626 shutil.copytree(src_dir, dst_dir)
627 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test.txt')))
628 self.assertTrue(os.path.isdir(os.path.join(dst_dir, 'test_dir')))
629 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test_dir',
630 'test.txt')))
631 actual = read_file((dst_dir, 'test.txt'))
632 self.assertEqual(actual, '123')
633 actual = read_file((dst_dir, 'test_dir', 'test.txt'))
634 self.assertEqual(actual, '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000635
Antoine Pitrou78091e62011-12-29 18:54:15 +0100636 @support.skip_unless_symlink
637 def test_copytree_symlinks(self):
638 tmp_dir = self.mkdtemp()
639 src_dir = os.path.join(tmp_dir, 'src')
640 dst_dir = os.path.join(tmp_dir, 'dst')
641 sub_dir = os.path.join(src_dir, 'sub')
642 os.mkdir(src_dir)
643 os.mkdir(sub_dir)
644 write_file((src_dir, 'file.txt'), 'foo')
645 src_link = os.path.join(sub_dir, 'link')
646 dst_link = os.path.join(dst_dir, 'sub/link')
647 os.symlink(os.path.join(src_dir, 'file.txt'),
648 src_link)
649 if hasattr(os, 'lchmod'):
650 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
651 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
652 os.lchflags(src_link, stat.UF_NODUMP)
653 src_stat = os.lstat(src_link)
654 shutil.copytree(src_dir, dst_dir, symlinks=True)
655 self.assertTrue(os.path.islink(os.path.join(dst_dir, 'sub', 'link')))
656 self.assertEqual(os.readlink(os.path.join(dst_dir, 'sub', 'link')),
657 os.path.join(src_dir, 'file.txt'))
658 dst_stat = os.lstat(dst_link)
659 if hasattr(os, 'lchmod'):
660 self.assertEqual(dst_stat.st_mode, src_stat.st_mode)
661 if hasattr(os, 'lchflags'):
662 self.assertEqual(dst_stat.st_flags, src_stat.st_flags)
663
Georg Brandl2ee470f2008-07-16 12:55:28 +0000664 def test_copytree_with_exclude(self):
Georg Brandl2ee470f2008-07-16 12:55:28 +0000665 # creating data
666 join = os.path.join
667 exists = os.path.exists
668 src_dir = tempfile.mkdtemp()
Georg Brandl2ee470f2008-07-16 12:55:28 +0000669 try:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000670 dst_dir = join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200671 write_file((src_dir, 'test.txt'), '123')
672 write_file((src_dir, 'test.tmp'), '123')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000673 os.mkdir(join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200674 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000675 os.mkdir(join(src_dir, 'test_dir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200676 write_file((src_dir, 'test_dir2', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000677 os.mkdir(join(src_dir, 'test_dir2', 'subdir'))
678 os.mkdir(join(src_dir, 'test_dir2', 'subdir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200679 write_file((src_dir, 'test_dir2', 'subdir', 'test.txt'), '456')
680 write_file((src_dir, 'test_dir2', 'subdir2', 'test.py'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000681
682 # testing glob-like patterns
683 try:
684 patterns = shutil.ignore_patterns('*.tmp', 'test_dir2')
685 shutil.copytree(src_dir, dst_dir, ignore=patterns)
686 # checking the result: some elements should not be copied
687 self.assertTrue(exists(join(dst_dir, 'test.txt')))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200688 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
689 self.assertFalse(exists(join(dst_dir, 'test_dir2')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000690 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200691 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000692 try:
693 patterns = shutil.ignore_patterns('*.tmp', 'subdir*')
694 shutil.copytree(src_dir, dst_dir, ignore=patterns)
695 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200696 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
697 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2')))
698 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000699 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200700 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000701
702 # testing callable-style
703 try:
704 def _filter(src, names):
705 res = []
706 for name in names:
707 path = os.path.join(src, name)
708
709 if (os.path.isdir(path) and
710 path.split()[-1] == 'subdir'):
711 res.append(name)
712 elif os.path.splitext(path)[-1] in ('.py'):
713 res.append(name)
714 return res
715
716 shutil.copytree(src_dir, dst_dir, ignore=_filter)
717
718 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200719 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2',
720 'test.py')))
721 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000722
723 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200724 shutil.rmtree(dst_dir)
Georg Brandl2ee470f2008-07-16 12:55:28 +0000725 finally:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000726 shutil.rmtree(src_dir)
727 shutil.rmtree(os.path.dirname(dst_dir))
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000728
Antoine Pitrouac601602013-08-16 19:35:02 +0200729 def test_copytree_retains_permissions(self):
730 tmp_dir = tempfile.mkdtemp()
731 src_dir = os.path.join(tmp_dir, 'source')
732 os.mkdir(src_dir)
733 dst_dir = os.path.join(tmp_dir, 'destination')
734 self.addCleanup(shutil.rmtree, tmp_dir)
735
736 os.chmod(src_dir, 0o777)
737 write_file((src_dir, 'permissive.txt'), '123')
738 os.chmod(os.path.join(src_dir, 'permissive.txt'), 0o777)
739 write_file((src_dir, 'restrictive.txt'), '456')
740 os.chmod(os.path.join(src_dir, 'restrictive.txt'), 0o600)
741 restrictive_subdir = tempfile.mkdtemp(dir=src_dir)
742 os.chmod(restrictive_subdir, 0o600)
743
744 shutil.copytree(src_dir, dst_dir)
Brett Cannon9c7eb552013-08-23 14:38:11 -0400745 self.assertEqual(os.stat(src_dir).st_mode, os.stat(dst_dir).st_mode)
746 self.assertEqual(os.stat(os.path.join(src_dir, 'permissive.txt')).st_mode,
Antoine Pitrouac601602013-08-16 19:35:02 +0200747 os.stat(os.path.join(dst_dir, 'permissive.txt')).st_mode)
Brett Cannon9c7eb552013-08-23 14:38:11 -0400748 self.assertEqual(os.stat(os.path.join(src_dir, 'restrictive.txt')).st_mode,
Antoine Pitrouac601602013-08-16 19:35:02 +0200749 os.stat(os.path.join(dst_dir, 'restrictive.txt')).st_mode)
750 restrictive_subdir_dst = os.path.join(dst_dir,
751 os.path.split(restrictive_subdir)[1])
Brett Cannon9c7eb552013-08-23 14:38:11 -0400752 self.assertEqual(os.stat(restrictive_subdir).st_mode,
Antoine Pitrouac601602013-08-16 19:35:02 +0200753 os.stat(restrictive_subdir_dst).st_mode)
754
Berker Peksag884afd92014-12-10 02:50:32 +0200755 @unittest.mock.patch('os.chmod')
756 def test_copytree_winerror(self, mock_patch):
757 # When copying to VFAT, copystat() raises OSError. On Windows, the
758 # exception object has a meaningful 'winerror' attribute, but not
759 # on other operating systems. Do not assume 'winerror' is set.
760 src_dir = tempfile.mkdtemp()
761 dst_dir = os.path.join(tempfile.mkdtemp(), 'destination')
762 self.addCleanup(shutil.rmtree, src_dir)
763 self.addCleanup(shutil.rmtree, os.path.dirname(dst_dir))
764
765 mock_patch.side_effect = PermissionError('ka-boom')
766 with self.assertRaises(shutil.Error):
767 shutil.copytree(src_dir, dst_dir)
768
Zachary Ware9fe6d862013-12-08 00:20:35 -0600769 @unittest.skipIf(os.name == 'nt', 'temporarily disabled on Windows')
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000770 @unittest.skipUnless(hasattr(os, 'link'), 'requires os.link')
Xavier de Gaye3a4e9892016-12-13 10:00:01 +0100771 @unittest.skipIf(android_not_root, "hard links not allowed, non root user")
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000772 def test_dont_copy_file_onto_link_to_itself(self):
773 # bug 851123.
774 os.mkdir(TESTFN)
775 src = os.path.join(TESTFN, 'cheese')
776 dst = os.path.join(TESTFN, 'shop')
777 try:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000778 with open(src, 'w') as f:
779 f.write('cheddar')
780 os.link(src, dst)
Hynek Schlawack48653762012-10-07 12:49:58 +0200781 self.assertRaises(shutil.SameFileError, shutil.copyfile, src, dst)
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000782 with open(src, 'r') as f:
783 self.assertEqual(f.read(), 'cheddar')
784 os.remove(dst)
785 finally:
786 shutil.rmtree(TESTFN, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000787
Brian Curtin3b4499c2010-12-28 14:31:47 +0000788 @support.skip_unless_symlink
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000789 def test_dont_copy_file_onto_symlink_to_itself(self):
790 # bug 851123.
791 os.mkdir(TESTFN)
792 src = os.path.join(TESTFN, 'cheese')
793 dst = os.path.join(TESTFN, 'shop')
794 try:
795 with open(src, 'w') as f:
796 f.write('cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000797 # Using `src` here would mean we end up with a symlink pointing
798 # to TESTFN/TESTFN/cheese, while it should point at
799 # TESTFN/cheese.
800 os.symlink('cheese', dst)
Hynek Schlawack48653762012-10-07 12:49:58 +0200801 self.assertRaises(shutil.SameFileError, shutil.copyfile, src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +0000802 with open(src, 'r') as f:
803 self.assertEqual(f.read(), 'cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000804 os.remove(dst)
805 finally:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000806 shutil.rmtree(TESTFN, ignore_errors=True)
Johannes Gijsbers68128712004-08-14 13:57:08 +0000807
Brian Curtin3b4499c2010-12-28 14:31:47 +0000808 @support.skip_unless_symlink
Brian Curtind40e6f72010-07-08 21:39:08 +0000809 def test_rmtree_on_symlink(self):
810 # bug 1669.
811 os.mkdir(TESTFN)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000812 try:
Brian Curtind40e6f72010-07-08 21:39:08 +0000813 src = os.path.join(TESTFN, 'cheese')
814 dst = os.path.join(TESTFN, 'shop')
815 os.mkdir(src)
816 os.symlink(src, dst)
817 self.assertRaises(OSError, shutil.rmtree, dst)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200818 shutil.rmtree(dst, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000819 finally:
Brian Curtind40e6f72010-07-08 21:39:08 +0000820 shutil.rmtree(TESTFN, ignore_errors=True)
821
Serhiy Storchaka43767632013-11-03 21:31:38 +0200822 # Issue #3002: copyfile and copytree block indefinitely on named pipes
823 @unittest.skipUnless(hasattr(os, "mkfifo"), 'requires os.mkfifo()')
Xavier de Gaye3a4e9892016-12-13 10:00:01 +0100824 @unittest.skipIf(android_not_root, "mkfifo not allowed, non root user")
Serhiy Storchaka43767632013-11-03 21:31:38 +0200825 def test_copyfile_named_pipe(self):
826 os.mkfifo(TESTFN)
827 try:
828 self.assertRaises(shutil.SpecialFileError,
829 shutil.copyfile, TESTFN, TESTFN2)
830 self.assertRaises(shutil.SpecialFileError,
831 shutil.copyfile, __file__, TESTFN)
832 finally:
833 os.remove(TESTFN)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000834
Xavier de Gaye3a4e9892016-12-13 10:00:01 +0100835 @unittest.skipIf(android_not_root, "mkfifo not allowed, non root user")
Serhiy Storchaka43767632013-11-03 21:31:38 +0200836 @unittest.skipUnless(hasattr(os, "mkfifo"), 'requires os.mkfifo()')
837 @support.skip_unless_symlink
838 def test_copytree_named_pipe(self):
839 os.mkdir(TESTFN)
840 try:
841 subdir = os.path.join(TESTFN, "subdir")
842 os.mkdir(subdir)
843 pipe = os.path.join(subdir, "mypipe")
844 os.mkfifo(pipe)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000845 try:
Serhiy Storchaka43767632013-11-03 21:31:38 +0200846 shutil.copytree(TESTFN, TESTFN2)
847 except shutil.Error as e:
848 errors = e.args[0]
849 self.assertEqual(len(errors), 1)
850 src, dst, error_msg = errors[0]
851 self.assertEqual("`%s` is a named pipe" % pipe, error_msg)
852 else:
853 self.fail("shutil.Error should have been raised")
854 finally:
855 shutil.rmtree(TESTFN, ignore_errors=True)
856 shutil.rmtree(TESTFN2, ignore_errors=True)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000857
Tarek Ziadé5340db32010-04-19 22:30:51 +0000858 def test_copytree_special_func(self):
859
860 src_dir = self.mkdtemp()
861 dst_dir = os.path.join(self.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200862 write_file((src_dir, 'test.txt'), '123')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000863 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200864 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000865
866 copied = []
867 def _copy(src, dst):
868 copied.append((src, dst))
869
870 shutil.copytree(src_dir, dst_dir, copy_function=_copy)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000871 self.assertEqual(len(copied), 2)
Tarek Ziadé5340db32010-04-19 22:30:51 +0000872
Brian Curtin3b4499c2010-12-28 14:31:47 +0000873 @support.skip_unless_symlink
Tarek Ziadéfb437512010-04-20 08:57:33 +0000874 def test_copytree_dangling_symlinks(self):
875
876 # a dangling symlink raises an error at the end
877 src_dir = self.mkdtemp()
878 dst_dir = os.path.join(self.mkdtemp(), 'destination')
879 os.symlink('IDONTEXIST', os.path.join(src_dir, 'test.txt'))
880 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200881 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadéfb437512010-04-20 08:57:33 +0000882 self.assertRaises(Error, shutil.copytree, src_dir, dst_dir)
883
884 # a dangling symlink is ignored with the proper flag
885 dst_dir = os.path.join(self.mkdtemp(), 'destination2')
886 shutil.copytree(src_dir, dst_dir, ignore_dangling_symlinks=True)
887 self.assertNotIn('test.txt', os.listdir(dst_dir))
888
889 # a dangling symlink is copied if symlinks=True
890 dst_dir = os.path.join(self.mkdtemp(), 'destination3')
891 shutil.copytree(src_dir, dst_dir, symlinks=True)
892 self.assertIn('test.txt', os.listdir(dst_dir))
893
Berker Peksag5a294d82015-07-25 14:53:48 +0300894 @support.skip_unless_symlink
895 def test_copytree_symlink_dir(self):
896 src_dir = self.mkdtemp()
897 dst_dir = os.path.join(self.mkdtemp(), 'destination')
898 os.mkdir(os.path.join(src_dir, 'real_dir'))
899 with open(os.path.join(src_dir, 'real_dir', 'test.txt'), 'w'):
900 pass
901 os.symlink(os.path.join(src_dir, 'real_dir'),
902 os.path.join(src_dir, 'link_to_dir'),
903 target_is_directory=True)
904
905 shutil.copytree(src_dir, dst_dir, symlinks=False)
906 self.assertFalse(os.path.islink(os.path.join(dst_dir, 'link_to_dir')))
907 self.assertIn('test.txt', os.listdir(os.path.join(dst_dir, 'link_to_dir')))
908
909 dst_dir = os.path.join(self.mkdtemp(), 'destination2')
910 shutil.copytree(src_dir, dst_dir, symlinks=True)
911 self.assertTrue(os.path.islink(os.path.join(dst_dir, 'link_to_dir')))
912 self.assertIn('test.txt', os.listdir(os.path.join(dst_dir, 'link_to_dir')))
913
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400914 def _copy_file(self, method):
915 fname = 'test.txt'
916 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200917 write_file((tmpdir, fname), 'xxx')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400918 file1 = os.path.join(tmpdir, fname)
919 tmpdir2 = self.mkdtemp()
920 method(file1, tmpdir2)
921 file2 = os.path.join(tmpdir2, fname)
922 return (file1, file2)
923
924 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
925 def test_copy(self):
926 # Ensure that the copied file exists and has the same mode bits.
927 file1, file2 = self._copy_file(shutil.copy)
928 self.assertTrue(os.path.exists(file2))
929 self.assertEqual(os.stat(file1).st_mode, os.stat(file2).st_mode)
930
931 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
Senthil Kumaran0c2dba52011-07-03 18:21:38 -0700932 @unittest.skipUnless(hasattr(os, 'utime'), 'requires os.utime')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400933 def test_copy2(self):
934 # Ensure that the copied file exists and has the same mode and
935 # modification time bits.
936 file1, file2 = self._copy_file(shutil.copy2)
937 self.assertTrue(os.path.exists(file2))
938 file1_stat = os.stat(file1)
939 file2_stat = os.stat(file2)
940 self.assertEqual(file1_stat.st_mode, file2_stat.st_mode)
941 for attr in 'st_atime', 'st_mtime':
942 # The modification times may be truncated in the new file.
943 self.assertLessEqual(getattr(file1_stat, attr),
944 getattr(file2_stat, attr) + 1)
945 if hasattr(os, 'chflags') and hasattr(file1_stat, 'st_flags'):
946 self.assertEqual(getattr(file1_stat, 'st_flags'),
947 getattr(file2_stat, 'st_flags'))
948
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +0200949 @support.requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000950 def test_make_tarball(self):
951 # creating something to tar
Serhiy Storchaka527ef072015-09-06 18:33:19 +0300952 root_dir, base_dir = self._create_files('')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000953
954 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400955 # force shutil to create the directory
956 os.rmdir(tmpdir2)
Serhiy Storchakaeba8fee2015-09-07 19:58:23 +0300957 # working with relative paths
958 work_dir = os.path.dirname(tmpdir2)
959 rel_base_name = os.path.join(os.path.basename(tmpdir2), 'archive')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000960
Serhiy Storchakaeba8fee2015-09-07 19:58:23 +0300961 with support.change_cwd(work_dir):
Serhiy Storchaka5558d4f2015-09-08 09:59:02 +0300962 base_name = os.path.abspath(rel_base_name)
Serhiy Storchakaeba8fee2015-09-07 19:58:23 +0300963 tarball = make_archive(rel_base_name, 'gztar', root_dir, '.')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000964
965 # check if the compressed tarball was created
Serhiy Storchakaa091a822015-09-07 13:55:25 +0300966 self.assertEqual(tarball, base_name + '.tar.gz')
Serhiy Storchaka527ef072015-09-06 18:33:19 +0300967 self.assertTrue(os.path.isfile(tarball))
968 self.assertTrue(tarfile.is_tarfile(tarball))
969 with tarfile.open(tarball, 'r:gz') as tf:
970 self.assertCountEqual(tf.getnames(),
971 ['.', './sub', './sub2',
972 './file1', './file2', './sub/file3'])
Tarek Ziadé396fad72010-02-23 05:30:31 +0000973
974 # trying an uncompressed one
Serhiy Storchakaeba8fee2015-09-07 19:58:23 +0300975 with support.change_cwd(work_dir):
976 tarball = make_archive(rel_base_name, 'tar', root_dir, '.')
Serhiy Storchakaa091a822015-09-07 13:55:25 +0300977 self.assertEqual(tarball, base_name + '.tar')
Serhiy Storchaka527ef072015-09-06 18:33:19 +0300978 self.assertTrue(os.path.isfile(tarball))
979 self.assertTrue(tarfile.is_tarfile(tarball))
980 with tarfile.open(tarball, 'r') as tf:
981 self.assertCountEqual(tf.getnames(),
982 ['.', './sub', './sub2',
983 './file1', './file2', './sub/file3'])
Tarek Ziadé396fad72010-02-23 05:30:31 +0000984
985 def _tarinfo(self, path):
Serhiy Storchaka527ef072015-09-06 18:33:19 +0300986 with tarfile.open(path) as tar:
Tarek Ziadé396fad72010-02-23 05:30:31 +0000987 names = tar.getnames()
988 names.sort()
989 return tuple(names)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000990
Serhiy Storchaka527ef072015-09-06 18:33:19 +0300991 def _create_files(self, base_dir='dist'):
Tarek Ziadé396fad72010-02-23 05:30:31 +0000992 # creating something to tar
Serhiy Storchaka527ef072015-09-06 18:33:19 +0300993 root_dir = self.mkdtemp()
994 dist = os.path.join(root_dir, base_dir)
995 os.makedirs(dist, exist_ok=True)
Éric Araujoa7e33a12011-08-12 19:51:35 +0200996 write_file((dist, 'file1'), 'xxx')
997 write_file((dist, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000998 os.mkdir(os.path.join(dist, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200999 write_file((dist, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +00001000 os.mkdir(os.path.join(dist, 'sub2'))
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001001 if base_dir:
1002 write_file((root_dir, 'outer'), 'xxx')
1003 return root_dir, base_dir
Tarek Ziadé396fad72010-02-23 05:30:31 +00001004
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001005 @support.requires_zlib
Serhiy Storchakab42de2f2015-11-21 14:09:26 +02001006 @unittest.skipUnless(shutil.which('tar'),
Tarek Ziadé396fad72010-02-23 05:30:31 +00001007 'Need the tar command to run')
1008 def test_tarfile_vs_tar(self):
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001009 root_dir, base_dir = self._create_files()
1010 base_name = os.path.join(self.mkdtemp(), 'archive')
Serhiy Storchakaa091a822015-09-07 13:55:25 +03001011 tarball = make_archive(base_name, 'gztar', root_dir, base_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001012
1013 # check if the compressed tarball was created
Serhiy Storchakaa091a822015-09-07 13:55:25 +03001014 self.assertEqual(tarball, base_name + '.tar.gz')
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001015 self.assertTrue(os.path.isfile(tarball))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001016
1017 # now create another tarball using `tar`
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001018 tarball2 = os.path.join(root_dir, 'archive2.tar')
1019 tar_cmd = ['tar', '-cf', 'archive2.tar', base_dir]
Serhiy Storchakab42de2f2015-11-21 14:09:26 +02001020 subprocess.check_call(tar_cmd, cwd=root_dir,
1021 stdout=subprocess.DEVNULL)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001022
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001023 self.assertTrue(os.path.isfile(tarball2))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001024 # let's compare both tarballs
Ezio Melottib3aedd42010-11-20 19:04:17 +00001025 self.assertEqual(self._tarinfo(tarball), self._tarinfo(tarball2))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001026
1027 # trying an uncompressed one
Serhiy Storchakaa091a822015-09-07 13:55:25 +03001028 tarball = make_archive(base_name, 'tar', root_dir, base_dir)
1029 self.assertEqual(tarball, base_name + '.tar')
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001030 self.assertTrue(os.path.isfile(tarball))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001031
1032 # now for a dry_run
Serhiy Storchakaa091a822015-09-07 13:55:25 +03001033 tarball = make_archive(base_name, 'tar', root_dir, base_dir,
1034 dry_run=True)
1035 self.assertEqual(tarball, base_name + '.tar')
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001036 self.assertTrue(os.path.isfile(tarball))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001037
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001038 @support.requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001039 def test_make_zipfile(self):
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001040 # creating something to zip
1041 root_dir, base_dir = self._create_files()
Serhiy Storchakaeba8fee2015-09-07 19:58:23 +03001042
1043 tmpdir2 = self.mkdtemp()
1044 # force shutil to create the directory
1045 os.rmdir(tmpdir2)
1046 # working with relative paths
1047 work_dir = os.path.dirname(tmpdir2)
1048 rel_base_name = os.path.join(os.path.basename(tmpdir2), 'archive')
Serhiy Storchakaeba8fee2015-09-07 19:58:23 +03001049
1050 with support.change_cwd(work_dir):
Serhiy Storchaka5558d4f2015-09-08 09:59:02 +03001051 base_name = os.path.abspath(rel_base_name)
Serhiy Storchaka666de772016-10-23 15:55:09 +03001052 res = make_archive(rel_base_name, 'zip', root_dir)
1053
1054 self.assertEqual(res, base_name + '.zip')
1055 self.assertTrue(os.path.isfile(res))
1056 self.assertTrue(zipfile.is_zipfile(res))
1057 with zipfile.ZipFile(res) as zf:
1058 self.assertCountEqual(zf.namelist(),
1059 ['dist/', 'dist/sub/', 'dist/sub2/',
1060 'dist/file1', 'dist/file2', 'dist/sub/file3',
1061 'outer'])
1062
1063 with support.change_cwd(work_dir):
1064 base_name = os.path.abspath(rel_base_name)
Serhiy Storchaka2504cec2015-09-08 05:47:23 +03001065 res = make_archive(rel_base_name, 'zip', root_dir, base_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001066
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001067 self.assertEqual(res, base_name + '.zip')
1068 self.assertTrue(os.path.isfile(res))
1069 self.assertTrue(zipfile.is_zipfile(res))
1070 with zipfile.ZipFile(res) as zf:
1071 self.assertCountEqual(zf.namelist(),
Serhiy Storchaka2504cec2015-09-08 05:47:23 +03001072 ['dist/', 'dist/sub/', 'dist/sub2/',
1073 'dist/file1', 'dist/file2', 'dist/sub/file3'])
Tarek Ziadé396fad72010-02-23 05:30:31 +00001074
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001075 @support.requires_zlib
Serhiy Storchakab42de2f2015-11-21 14:09:26 +02001076 @unittest.skipUnless(shutil.which('zip'),
Serhiy Storchaka2504cec2015-09-08 05:47:23 +03001077 'Need the zip command to run')
1078 def test_zipfile_vs_zip(self):
1079 root_dir, base_dir = self._create_files()
1080 base_name = os.path.join(self.mkdtemp(), 'archive')
1081 archive = make_archive(base_name, 'zip', root_dir, base_dir)
1082
1083 # check if ZIP file was created
1084 self.assertEqual(archive, base_name + '.zip')
1085 self.assertTrue(os.path.isfile(archive))
1086
1087 # now create another ZIP file using `zip`
1088 archive2 = os.path.join(root_dir, 'archive2.zip')
1089 zip_cmd = ['zip', '-q', '-r', 'archive2.zip', base_dir]
Serhiy Storchakab42de2f2015-11-21 14:09:26 +02001090 subprocess.check_call(zip_cmd, cwd=root_dir,
1091 stdout=subprocess.DEVNULL)
Serhiy Storchaka2504cec2015-09-08 05:47:23 +03001092
1093 self.assertTrue(os.path.isfile(archive2))
1094 # let's compare both ZIP files
1095 with zipfile.ZipFile(archive) as zf:
1096 names = zf.namelist()
1097 with zipfile.ZipFile(archive2) as zf:
1098 names2 = zf.namelist()
1099 self.assertEqual(sorted(names), sorted(names2))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001100
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001101 @support.requires_zlib
Serhiy Storchaka8bc792a2015-11-22 14:49:58 +02001102 @unittest.skipUnless(shutil.which('unzip'),
1103 'Need the unzip command to run')
1104 def test_unzip_zipfile(self):
1105 root_dir, base_dir = self._create_files()
1106 base_name = os.path.join(self.mkdtemp(), 'archive')
1107 archive = make_archive(base_name, 'zip', root_dir, base_dir)
1108
1109 # check if ZIP file was created
1110 self.assertEqual(archive, base_name + '.zip')
1111 self.assertTrue(os.path.isfile(archive))
1112
1113 # now check the ZIP file using `unzip -t`
1114 zip_cmd = ['unzip', '-t', archive]
1115 with support.change_cwd(root_dir):
1116 try:
1117 subprocess.check_output(zip_cmd, stderr=subprocess.STDOUT)
1118 except subprocess.CalledProcessError as exc:
1119 details = exc.output.decode(errors="replace")
1120 msg = "{}\n\n**Unzip Output**\n{}"
1121 self.fail(msg.format(exc, details))
1122
Tarek Ziadé396fad72010-02-23 05:30:31 +00001123 def test_make_archive(self):
1124 tmpdir = self.mkdtemp()
1125 base_name = os.path.join(tmpdir, 'archive')
1126 self.assertRaises(ValueError, make_archive, base_name, 'xxx')
1127
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001128 @support.requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001129 def test_make_archive_owner_group(self):
1130 # testing make_archive with owner and group, with various combinations
1131 # this works even if there's not gid/uid support
1132 if UID_GID_SUPPORT:
1133 group = grp.getgrgid(0)[0]
1134 owner = pwd.getpwuid(0)[0]
1135 else:
1136 group = owner = 'root'
1137
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001138 root_dir, base_dir = self._create_files()
1139 base_name = os.path.join(self.mkdtemp(), 'archive')
Tarek Ziadé396fad72010-02-23 05:30:31 +00001140 res = make_archive(base_name, 'zip', root_dir, base_dir, owner=owner,
1141 group=group)
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001142 self.assertTrue(os.path.isfile(res))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001143
1144 res = make_archive(base_name, 'zip', root_dir, base_dir)
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001145 self.assertTrue(os.path.isfile(res))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001146
1147 res = make_archive(base_name, 'tar', root_dir, base_dir,
1148 owner=owner, group=group)
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001149 self.assertTrue(os.path.isfile(res))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001150
1151 res = make_archive(base_name, 'tar', root_dir, base_dir,
1152 owner='kjhkjhkjg', group='oihohoh')
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001153 self.assertTrue(os.path.isfile(res))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001154
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001155
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001156 @support.requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001157 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1158 def test_tarfile_root_owner(self):
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001159 root_dir, base_dir = self._create_files()
1160 base_name = os.path.join(self.mkdtemp(), 'archive')
Tarek Ziadé396fad72010-02-23 05:30:31 +00001161 group = grp.getgrgid(0)[0]
1162 owner = pwd.getpwuid(0)[0]
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001163 with support.change_cwd(root_dir):
1164 archive_name = make_archive(base_name, 'gztar', root_dir, 'dist',
1165 owner=owner, group=group)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001166
1167 # check if the compressed tarball was created
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001168 self.assertTrue(os.path.isfile(archive_name))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001169
1170 # now checks the rights
1171 archive = tarfile.open(archive_name)
1172 try:
1173 for member in archive.getmembers():
Ezio Melottib3aedd42010-11-20 19:04:17 +00001174 self.assertEqual(member.uid, 0)
1175 self.assertEqual(member.gid, 0)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001176 finally:
1177 archive.close()
1178
1179 def test_make_archive_cwd(self):
1180 current_dir = os.getcwd()
1181 def _breaks(*args, **kw):
1182 raise RuntimeError()
1183
1184 register_archive_format('xxx', _breaks, [], 'xxx file')
1185 try:
1186 try:
1187 make_archive('xxx', 'xxx', root_dir=self.mkdtemp())
1188 except Exception:
1189 pass
Ezio Melottib3aedd42010-11-20 19:04:17 +00001190 self.assertEqual(os.getcwd(), current_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001191 finally:
1192 unregister_archive_format('xxx')
1193
Serhiy Storchaka9a4fc192014-11-28 00:48:46 +02001194 def test_make_tarfile_in_curdir(self):
1195 # Issue #21280
1196 root_dir = self.mkdtemp()
1197 with support.change_cwd(root_dir):
1198 self.assertEqual(make_archive('test', 'tar'), 'test.tar')
1199 self.assertTrue(os.path.isfile('test.tar'))
1200
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001201 @support.requires_zlib
Serhiy Storchaka9a4fc192014-11-28 00:48:46 +02001202 def test_make_zipfile_in_curdir(self):
1203 # Issue #21280
1204 root_dir = self.mkdtemp()
1205 with support.change_cwd(root_dir):
1206 self.assertEqual(make_archive('test', 'zip'), 'test.zip')
1207 self.assertTrue(os.path.isfile('test.zip'))
1208
Tarek Ziadé396fad72010-02-23 05:30:31 +00001209 def test_register_archive_format(self):
1210
1211 self.assertRaises(TypeError, register_archive_format, 'xxx', 1)
1212 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1213 1)
1214 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1215 [(1, 2), (1, 2, 3)])
1216
1217 register_archive_format('xxx', lambda: x, [(1, 2)], 'xxx file')
1218 formats = [name for name, params in get_archive_formats()]
1219 self.assertIn('xxx', formats)
1220
1221 unregister_archive_format('xxx')
1222 formats = [name for name, params in get_archive_formats()]
1223 self.assertNotIn('xxx', formats)
1224
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001225 def check_unpack_archive(self, format):
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001226 root_dir, base_dir = self._create_files()
Serhiy Storchaka2504cec2015-09-08 05:47:23 +03001227 expected = rlistdir(root_dir)
1228 expected.remove('outer')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001229
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001230 base_name = os.path.join(self.mkdtemp(), 'archive')
1231 filename = make_archive(base_name, format, root_dir, base_dir)
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001232
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001233 # let's try to unpack it now
1234 tmpdir2 = self.mkdtemp()
1235 unpack_archive(filename, tmpdir2)
1236 self.assertEqual(rlistdir(tmpdir2), expected)
1237
1238 # and again, this time with the format specified
1239 tmpdir3 = self.mkdtemp()
1240 unpack_archive(filename, tmpdir3, format=format)
1241 self.assertEqual(rlistdir(tmpdir3), expected)
1242
Nick Coghlanabf202d2011-03-16 13:52:20 -04001243 self.assertRaises(shutil.ReadError, unpack_archive, TESTFN)
1244 self.assertRaises(ValueError, unpack_archive, TESTFN, format='xxx')
1245
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001246 def test_unpack_archive_tar(self):
1247 self.check_unpack_archive('tar')
1248
1249 @support.requires_zlib
1250 def test_unpack_archive_gztar(self):
1251 self.check_unpack_archive('gztar')
1252
1253 @support.requires_bz2
1254 def test_unpack_archive_bztar(self):
1255 self.check_unpack_archive('bztar')
1256
1257 @support.requires_lzma
1258 def test_unpack_archive_xztar(self):
1259 self.check_unpack_archive('xztar')
1260
1261 @support.requires_zlib
1262 def test_unpack_archive_zip(self):
1263 self.check_unpack_archive('zip')
1264
Martin Pantereb995702016-07-28 01:11:04 +00001265 def test_unpack_registry(self):
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001266
1267 formats = get_unpack_formats()
1268
1269 def _boo(filename, extract_dir, extra):
Ezio Melottib3aedd42010-11-20 19:04:17 +00001270 self.assertEqual(extra, 1)
1271 self.assertEqual(filename, 'stuff.boo')
1272 self.assertEqual(extract_dir, 'xx')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001273
1274 register_unpack_format('Boo', ['.boo', '.b2'], _boo, [('extra', 1)])
1275 unpack_archive('stuff.boo', 'xx')
1276
1277 # trying to register a .boo unpacker again
1278 self.assertRaises(RegistryError, register_unpack_format, 'Boo2',
1279 ['.boo'], _boo)
1280
1281 # should work now
1282 unregister_unpack_format('Boo')
1283 register_unpack_format('Boo2', ['.boo'], _boo)
1284 self.assertIn(('Boo2', ['.boo'], ''), get_unpack_formats())
1285 self.assertNotIn(('Boo', ['.boo'], ''), get_unpack_formats())
1286
1287 # let's leave a clean state
1288 unregister_unpack_format('Boo2')
Ezio Melottib3aedd42010-11-20 19:04:17 +00001289 self.assertEqual(get_unpack_formats(), formats)
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001290
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001291 @unittest.skipUnless(hasattr(shutil, 'disk_usage'),
1292 "disk_usage not available on this platform")
1293 def test_disk_usage(self):
1294 usage = shutil.disk_usage(os.getcwd())
Éric Araujo2ee61882011-07-02 16:45:45 +02001295 self.assertGreater(usage.total, 0)
1296 self.assertGreater(usage.used, 0)
1297 self.assertGreaterEqual(usage.free, 0)
1298 self.assertGreaterEqual(usage.total, usage.used)
1299 self.assertGreater(usage.total, usage.free)
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001300
Sandro Tosid902a142011-08-22 23:28:27 +02001301 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1302 @unittest.skipUnless(hasattr(os, 'chown'), 'requires os.chown')
1303 def test_chown(self):
1304
1305 # cleaned-up automatically by TestShutil.tearDown method
1306 dirname = self.mkdtemp()
1307 filename = tempfile.mktemp(dir=dirname)
1308 write_file(filename, 'testing chown function')
1309
1310 with self.assertRaises(ValueError):
1311 shutil.chown(filename)
1312
1313 with self.assertRaises(LookupError):
Raymond Hettinger15f44ab2016-08-30 10:47:49 -07001314 shutil.chown(filename, user='non-existing username')
Sandro Tosid902a142011-08-22 23:28:27 +02001315
1316 with self.assertRaises(LookupError):
Raymond Hettinger15f44ab2016-08-30 10:47:49 -07001317 shutil.chown(filename, group='non-existing groupname')
Sandro Tosid902a142011-08-22 23:28:27 +02001318
1319 with self.assertRaises(TypeError):
1320 shutil.chown(filename, b'spam')
1321
1322 with self.assertRaises(TypeError):
1323 shutil.chown(filename, 3.14)
1324
1325 uid = os.getuid()
1326 gid = os.getgid()
1327
1328 def check_chown(path, uid=None, gid=None):
1329 s = os.stat(filename)
1330 if uid is not None:
1331 self.assertEqual(uid, s.st_uid)
1332 if gid is not None:
1333 self.assertEqual(gid, s.st_gid)
1334
1335 shutil.chown(filename, uid, gid)
1336 check_chown(filename, uid, gid)
1337 shutil.chown(filename, uid)
1338 check_chown(filename, uid)
1339 shutil.chown(filename, user=uid)
1340 check_chown(filename, uid)
1341 shutil.chown(filename, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001342 check_chown(filename, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001343
1344 shutil.chown(dirname, uid, gid)
1345 check_chown(dirname, uid, gid)
1346 shutil.chown(dirname, uid)
1347 check_chown(dirname, uid)
1348 shutil.chown(dirname, user=uid)
1349 check_chown(dirname, uid)
1350 shutil.chown(dirname, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001351 check_chown(dirname, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001352
1353 user = pwd.getpwuid(uid)[0]
1354 group = grp.getgrgid(gid)[0]
1355 shutil.chown(filename, user, group)
1356 check_chown(filename, uid, gid)
1357 shutil.chown(dirname, user, group)
1358 check_chown(dirname, uid, gid)
1359
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001360 def test_copy_return_value(self):
1361 # copy and copy2 both return their destination path.
1362 for fn in (shutil.copy, shutil.copy2):
1363 src_dir = self.mkdtemp()
1364 dst_dir = self.mkdtemp()
1365 src = os.path.join(src_dir, 'foo')
1366 write_file(src, 'foo')
1367 rv = fn(src, dst_dir)
1368 self.assertEqual(rv, os.path.join(dst_dir, 'foo'))
1369 rv = fn(src, os.path.join(dst_dir, 'bar'))
1370 self.assertEqual(rv, os.path.join(dst_dir, 'bar'))
1371
1372 def test_copyfile_return_value(self):
1373 # copytree returns its destination path.
1374 src_dir = self.mkdtemp()
1375 dst_dir = self.mkdtemp()
1376 dst_file = os.path.join(dst_dir, 'bar')
1377 src_file = os.path.join(src_dir, 'foo')
1378 write_file(src_file, 'foo')
1379 rv = shutil.copyfile(src_file, dst_file)
1380 self.assertTrue(os.path.exists(rv))
1381 self.assertEqual(read_file(src_file), read_file(dst_file))
1382
Hynek Schlawack48653762012-10-07 12:49:58 +02001383 def test_copyfile_same_file(self):
1384 # copyfile() should raise SameFileError if the source and destination
1385 # are the same.
1386 src_dir = self.mkdtemp()
1387 src_file = os.path.join(src_dir, 'foo')
1388 write_file(src_file, 'foo')
1389 self.assertRaises(SameFileError, shutil.copyfile, src_file, src_file)
Hynek Schlawack27ddb572012-10-28 13:59:27 +01001390 # But Error should work too, to stay backward compatible.
1391 self.assertRaises(Error, shutil.copyfile, src_file, src_file)
Hynek Schlawack48653762012-10-07 12:49:58 +02001392
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001393 def test_copytree_return_value(self):
1394 # copytree returns its destination path.
1395 src_dir = self.mkdtemp()
1396 dst_dir = src_dir + "dest"
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001397 self.addCleanup(shutil.rmtree, dst_dir, True)
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001398 src = os.path.join(src_dir, 'foo')
1399 write_file(src, 'foo')
1400 rv = shutil.copytree(src_dir, dst_dir)
1401 self.assertEqual(['foo'], os.listdir(rv))
1402
Christian Heimes9bd667a2008-01-20 15:14:11 +00001403
Brian Curtinc57a3452012-06-22 16:00:30 -05001404class TestWhich(unittest.TestCase):
1405
1406 def setUp(self):
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001407 self.temp_dir = tempfile.mkdtemp(prefix="Tmp")
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001408 self.addCleanup(shutil.rmtree, self.temp_dir, True)
Brian Curtinc57a3452012-06-22 16:00:30 -05001409 # Give the temp_file an ".exe" suffix for all.
1410 # It's needed on Windows and not harmful on other platforms.
1411 self.temp_file = tempfile.NamedTemporaryFile(dir=self.temp_dir,
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001412 prefix="Tmp",
1413 suffix=".Exe")
Brian Curtinc57a3452012-06-22 16:00:30 -05001414 os.chmod(self.temp_file.name, stat.S_IXUSR)
1415 self.addCleanup(self.temp_file.close)
1416 self.dir, self.file = os.path.split(self.temp_file.name)
1417
1418 def test_basic(self):
1419 # Given an EXE in a directory, it should be returned.
1420 rv = shutil.which(self.file, path=self.dir)
1421 self.assertEqual(rv, self.temp_file.name)
1422
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001423 def test_absolute_cmd(self):
Brian Curtinc57a3452012-06-22 16:00:30 -05001424 # When given the fully qualified path to an executable that exists,
1425 # it should be returned.
1426 rv = shutil.which(self.temp_file.name, path=self.temp_dir)
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001427 self.assertEqual(rv, self.temp_file.name)
1428
1429 def test_relative_cmd(self):
1430 # When given the relative path with a directory part to an executable
1431 # that exists, it should be returned.
1432 base_dir, tail_dir = os.path.split(self.dir)
1433 relpath = os.path.join(tail_dir, self.file)
Nick Coghlan55175962013-07-28 22:11:50 +10001434 with support.change_cwd(path=base_dir):
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001435 rv = shutil.which(relpath, path=self.temp_dir)
1436 self.assertEqual(rv, relpath)
1437 # But it shouldn't be searched in PATH directories (issue #16957).
Nick Coghlan55175962013-07-28 22:11:50 +10001438 with support.change_cwd(path=self.dir):
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001439 rv = shutil.which(relpath, path=base_dir)
1440 self.assertIsNone(rv)
1441
1442 def test_cwd(self):
1443 # Issue #16957
1444 base_dir = os.path.dirname(self.dir)
Nick Coghlan55175962013-07-28 22:11:50 +10001445 with support.change_cwd(path=self.dir):
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001446 rv = shutil.which(self.file, path=base_dir)
1447 if sys.platform == "win32":
1448 # Windows: current directory implicitly on PATH
1449 self.assertEqual(rv, os.path.join(os.curdir, self.file))
1450 else:
1451 # Other platforms: shouldn't match in the current directory.
1452 self.assertIsNone(rv)
Brian Curtinc57a3452012-06-22 16:00:30 -05001453
Serhiy Storchaka12516e22013-05-28 15:50:15 +03001454 @unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0,
1455 'non-root user required')
Brian Curtinc57a3452012-06-22 16:00:30 -05001456 def test_non_matching_mode(self):
1457 # Set the file read-only and ask for writeable files.
1458 os.chmod(self.temp_file.name, stat.S_IREAD)
Serhiy Storchaka12516e22013-05-28 15:50:15 +03001459 if os.access(self.temp_file.name, os.W_OK):
1460 self.skipTest("can't set the file read-only")
Brian Curtinc57a3452012-06-22 16:00:30 -05001461 rv = shutil.which(self.file, path=self.dir, mode=os.W_OK)
1462 self.assertIsNone(rv)
1463
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001464 def test_relative_path(self):
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001465 base_dir, tail_dir = os.path.split(self.dir)
Nick Coghlan55175962013-07-28 22:11:50 +10001466 with support.change_cwd(path=base_dir):
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001467 rv = shutil.which(self.file, path=tail_dir)
1468 self.assertEqual(rv, os.path.join(tail_dir, self.file))
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001469
Brian Curtinc57a3452012-06-22 16:00:30 -05001470 def test_nonexistent_file(self):
1471 # Return None when no matching executable file is found on the path.
1472 rv = shutil.which("foo.exe", path=self.dir)
1473 self.assertIsNone(rv)
1474
1475 @unittest.skipUnless(sys.platform == "win32",
1476 "pathext check is Windows-only")
1477 def test_pathext_checking(self):
1478 # Ask for the file without the ".exe" extension, then ensure that
1479 # it gets found properly with the extension.
Serhiy Storchakad70127a2013-01-24 20:03:49 +02001480 rv = shutil.which(self.file[:-4], path=self.dir)
Serhiy Storchaka80c88f42013-01-22 10:31:36 +02001481 self.assertEqual(rv, self.temp_file.name[:-4] + ".EXE")
Brian Curtinc57a3452012-06-22 16:00:30 -05001482
Barry Warsaw618738b2013-04-16 11:05:03 -04001483 def test_environ_path(self):
1484 with support.EnvironmentVarGuard() as env:
Victor Stinner1d006a22013-12-16 23:39:40 +01001485 env['PATH'] = self.dir
Barry Warsaw618738b2013-04-16 11:05:03 -04001486 rv = shutil.which(self.file)
1487 self.assertEqual(rv, self.temp_file.name)
1488
1489 def test_empty_path(self):
1490 base_dir = os.path.dirname(self.dir)
Nick Coghlan55175962013-07-28 22:11:50 +10001491 with support.change_cwd(path=self.dir), \
Barry Warsaw618738b2013-04-16 11:05:03 -04001492 support.EnvironmentVarGuard() as env:
Victor Stinner1d006a22013-12-16 23:39:40 +01001493 env['PATH'] = self.dir
Barry Warsaw618738b2013-04-16 11:05:03 -04001494 rv = shutil.which(self.file, path='')
1495 self.assertIsNone(rv)
1496
1497 def test_empty_path_no_PATH(self):
1498 with support.EnvironmentVarGuard() as env:
1499 env.pop('PATH', None)
1500 rv = shutil.which(self.file)
1501 self.assertIsNone(rv)
1502
Brian Curtinc57a3452012-06-22 16:00:30 -05001503
Christian Heimesada8c3b2008-03-18 18:26:33 +00001504class TestMove(unittest.TestCase):
1505
1506 def setUp(self):
1507 filename = "foo"
1508 self.src_dir = tempfile.mkdtemp()
1509 self.dst_dir = tempfile.mkdtemp()
1510 self.src_file = os.path.join(self.src_dir, filename)
1511 self.dst_file = os.path.join(self.dst_dir, filename)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001512 with open(self.src_file, "wb") as f:
1513 f.write(b"spam")
1514
1515 def tearDown(self):
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001516 for d in (self.src_dir, self.dst_dir):
Christian Heimesada8c3b2008-03-18 18:26:33 +00001517 try:
1518 if d:
1519 shutil.rmtree(d)
1520 except:
1521 pass
1522
1523 def _check_move_file(self, src, dst, real_dst):
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001524 with open(src, "rb") as f:
1525 contents = f.read()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001526 shutil.move(src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001527 with open(real_dst, "rb") as f:
1528 self.assertEqual(contents, f.read())
Christian Heimesada8c3b2008-03-18 18:26:33 +00001529 self.assertFalse(os.path.exists(src))
1530
1531 def _check_move_dir(self, src, dst, real_dst):
1532 contents = sorted(os.listdir(src))
1533 shutil.move(src, dst)
1534 self.assertEqual(contents, sorted(os.listdir(real_dst)))
1535 self.assertFalse(os.path.exists(src))
1536
1537 def test_move_file(self):
1538 # Move a file to another location on the same filesystem.
1539 self._check_move_file(self.src_file, self.dst_file, self.dst_file)
1540
1541 def test_move_file_to_dir(self):
1542 # Move a file inside an existing dir on the same filesystem.
1543 self._check_move_file(self.src_file, self.dst_dir, self.dst_file)
1544
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001545 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001546 def test_move_file_other_fs(self):
1547 # Move a file to an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001548 self.test_move_file()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001549
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001550 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001551 def test_move_file_to_dir_other_fs(self):
1552 # Move a file to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001553 self.test_move_file_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001554
1555 def test_move_dir(self):
1556 # Move a dir to another location on the same filesystem.
1557 dst_dir = tempfile.mktemp()
1558 try:
1559 self._check_move_dir(self.src_dir, dst_dir, dst_dir)
1560 finally:
1561 try:
1562 shutil.rmtree(dst_dir)
1563 except:
1564 pass
1565
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001566 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001567 def test_move_dir_other_fs(self):
1568 # Move a dir to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001569 self.test_move_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001570
1571 def test_move_dir_to_dir(self):
1572 # Move a dir inside an existing dir on the same filesystem.
1573 self._check_move_dir(self.src_dir, self.dst_dir,
1574 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1575
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001576 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001577 def test_move_dir_to_dir_other_fs(self):
1578 # Move a dir inside an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001579 self.test_move_dir_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001580
Serhiy Storchaka3a308b92014-02-11 10:30:59 +02001581 def test_move_dir_sep_to_dir(self):
1582 self._check_move_dir(self.src_dir + os.path.sep, self.dst_dir,
1583 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1584
1585 @unittest.skipUnless(os.path.altsep, 'requires os.path.altsep')
1586 def test_move_dir_altsep_to_dir(self):
1587 self._check_move_dir(self.src_dir + os.path.altsep, self.dst_dir,
1588 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1589
Christian Heimesada8c3b2008-03-18 18:26:33 +00001590 def test_existing_file_inside_dest_dir(self):
1591 # A file with the same name inside the destination dir already exists.
1592 with open(self.dst_file, "wb"):
1593 pass
1594 self.assertRaises(shutil.Error, shutil.move, self.src_file, self.dst_dir)
1595
1596 def test_dont_move_dir_in_itself(self):
1597 # Moving a dir inside itself raises an Error.
1598 dst = os.path.join(self.src_dir, "bar")
1599 self.assertRaises(shutil.Error, shutil.move, self.src_dir, dst)
1600
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001601 def test_destinsrc_false_negative(self):
1602 os.mkdir(TESTFN)
1603 try:
1604 for src, dst in [('srcdir', 'srcdir/dest')]:
1605 src = os.path.join(TESTFN, src)
1606 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001607 self.assertTrue(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001608 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001609 'dst (%s) is not in src (%s)' % (dst, src))
1610 finally:
1611 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001612
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001613 def test_destinsrc_false_positive(self):
1614 os.mkdir(TESTFN)
1615 try:
1616 for src, dst in [('srcdir', 'src/dest'), ('srcdir', 'srcdir.new')]:
1617 src = os.path.join(TESTFN, src)
1618 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001619 self.assertFalse(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001620 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001621 'dst (%s) is in src (%s)' % (dst, src))
1622 finally:
1623 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimes9bd667a2008-01-20 15:14:11 +00001624
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +01001625 @support.skip_unless_symlink
1626 @mock_rename
1627 def test_move_file_symlink(self):
1628 dst = os.path.join(self.src_dir, 'bar')
1629 os.symlink(self.src_file, dst)
1630 shutil.move(dst, self.dst_file)
1631 self.assertTrue(os.path.islink(self.dst_file))
1632 self.assertTrue(os.path.samefile(self.src_file, self.dst_file))
1633
1634 @support.skip_unless_symlink
1635 @mock_rename
1636 def test_move_file_symlink_to_dir(self):
1637 filename = "bar"
1638 dst = os.path.join(self.src_dir, filename)
1639 os.symlink(self.src_file, dst)
1640 shutil.move(dst, self.dst_dir)
1641 final_link = os.path.join(self.dst_dir, filename)
1642 self.assertTrue(os.path.islink(final_link))
1643 self.assertTrue(os.path.samefile(self.src_file, final_link))
1644
1645 @support.skip_unless_symlink
1646 @mock_rename
1647 def test_move_dangling_symlink(self):
1648 src = os.path.join(self.src_dir, 'baz')
1649 dst = os.path.join(self.src_dir, 'bar')
1650 os.symlink(src, dst)
1651 dst_link = os.path.join(self.dst_dir, 'quux')
1652 shutil.move(dst, dst_link)
1653 self.assertTrue(os.path.islink(dst_link))
Antoine Pitrou3f48ac92014-01-01 02:50:45 +01001654 # On Windows, os.path.realpath does not follow symlinks (issue #9949)
1655 if os.name == 'nt':
1656 self.assertEqual(os.path.realpath(src), os.readlink(dst_link))
1657 else:
1658 self.assertEqual(os.path.realpath(src), os.path.realpath(dst_link))
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +01001659
1660 @support.skip_unless_symlink
1661 @mock_rename
1662 def test_move_dir_symlink(self):
1663 src = os.path.join(self.src_dir, 'baz')
1664 dst = os.path.join(self.src_dir, 'bar')
1665 os.mkdir(src)
1666 os.symlink(src, dst)
1667 dst_link = os.path.join(self.dst_dir, 'quux')
1668 shutil.move(dst, dst_link)
1669 self.assertTrue(os.path.islink(dst_link))
1670 self.assertTrue(os.path.samefile(src, dst_link))
1671
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001672 def test_move_return_value(self):
1673 rv = shutil.move(self.src_file, self.dst_dir)
1674 self.assertEqual(rv,
1675 os.path.join(self.dst_dir, os.path.basename(self.src_file)))
1676
1677 def test_move_as_rename_return_value(self):
1678 rv = shutil.move(self.src_file, os.path.join(self.dst_dir, 'bar'))
1679 self.assertEqual(rv, os.path.join(self.dst_dir, 'bar'))
1680
R David Murray6ffface2014-06-11 14:40:13 -04001681 @mock_rename
1682 def test_move_file_special_function(self):
1683 moved = []
1684 def _copy(src, dst):
1685 moved.append((src, dst))
1686 shutil.move(self.src_file, self.dst_dir, copy_function=_copy)
1687 self.assertEqual(len(moved), 1)
1688
1689 @mock_rename
1690 def test_move_dir_special_function(self):
1691 moved = []
1692 def _copy(src, dst):
1693 moved.append((src, dst))
1694 support.create_empty_file(os.path.join(self.src_dir, 'child'))
1695 support.create_empty_file(os.path.join(self.src_dir, 'child1'))
1696 shutil.move(self.src_dir, self.dst_dir, copy_function=_copy)
1697 self.assertEqual(len(moved), 3)
1698
Tarek Ziadé5340db32010-04-19 22:30:51 +00001699
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001700class TestCopyFile(unittest.TestCase):
1701
1702 _delete = False
1703
1704 class Faux(object):
1705 _entered = False
1706 _exited_with = None
1707 _raised = False
1708 def __init__(self, raise_in_exit=False, suppress_at_exit=True):
1709 self._raise_in_exit = raise_in_exit
1710 self._suppress_at_exit = suppress_at_exit
1711 def read(self, *args):
1712 return ''
1713 def __enter__(self):
1714 self._entered = True
1715 def __exit__(self, exc_type, exc_val, exc_tb):
1716 self._exited_with = exc_type, exc_val, exc_tb
1717 if self._raise_in_exit:
1718 self._raised = True
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001719 raise OSError("Cannot close")
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001720 return self._suppress_at_exit
1721
1722 def tearDown(self):
1723 if self._delete:
1724 del shutil.open
1725
1726 def _set_shutil_open(self, func):
1727 shutil.open = func
1728 self._delete = True
1729
1730 def test_w_source_open_fails(self):
1731 def _open(filename, mode='r'):
1732 if filename == 'srcfile':
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001733 raise OSError('Cannot open "srcfile"')
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001734 assert 0 # shouldn't reach here.
1735
1736 self._set_shutil_open(_open)
1737
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001738 self.assertRaises(OSError, shutil.copyfile, 'srcfile', 'destfile')
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001739
1740 def test_w_dest_open_fails(self):
1741
1742 srcfile = self.Faux()
1743
1744 def _open(filename, mode='r'):
1745 if filename == 'srcfile':
1746 return srcfile
1747 if filename == 'destfile':
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001748 raise OSError('Cannot open "destfile"')
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001749 assert 0 # shouldn't reach here.
1750
1751 self._set_shutil_open(_open)
1752
1753 shutil.copyfile('srcfile', 'destfile')
1754 self.assertTrue(srcfile._entered)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001755 self.assertTrue(srcfile._exited_with[0] is OSError)
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001756 self.assertEqual(srcfile._exited_with[1].args,
1757 ('Cannot open "destfile"',))
1758
1759 def test_w_dest_close_fails(self):
1760
1761 srcfile = self.Faux()
1762 destfile = self.Faux(True)
1763
1764 def _open(filename, mode='r'):
1765 if filename == 'srcfile':
1766 return srcfile
1767 if filename == 'destfile':
1768 return destfile
1769 assert 0 # shouldn't reach here.
1770
1771 self._set_shutil_open(_open)
1772
1773 shutil.copyfile('srcfile', 'destfile')
1774 self.assertTrue(srcfile._entered)
1775 self.assertTrue(destfile._entered)
1776 self.assertTrue(destfile._raised)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001777 self.assertTrue(srcfile._exited_with[0] is OSError)
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001778 self.assertEqual(srcfile._exited_with[1].args,
1779 ('Cannot close',))
1780
1781 def test_w_source_close_fails(self):
1782
1783 srcfile = self.Faux(True)
1784 destfile = self.Faux()
1785
1786 def _open(filename, mode='r'):
1787 if filename == 'srcfile':
1788 return srcfile
1789 if filename == 'destfile':
1790 return destfile
1791 assert 0 # shouldn't reach here.
1792
1793 self._set_shutil_open(_open)
1794
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001795 self.assertRaises(OSError,
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001796 shutil.copyfile, 'srcfile', 'destfile')
1797 self.assertTrue(srcfile._entered)
1798 self.assertTrue(destfile._entered)
1799 self.assertFalse(destfile._raised)
1800 self.assertTrue(srcfile._exited_with[0] is None)
1801 self.assertTrue(srcfile._raised)
1802
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001803 def test_move_dir_caseinsensitive(self):
1804 # Renames a folder to the same name
1805 # but a different case.
1806
1807 self.src_dir = tempfile.mkdtemp()
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001808 self.addCleanup(shutil.rmtree, self.src_dir, True)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001809 dst_dir = os.path.join(
1810 os.path.dirname(self.src_dir),
1811 os.path.basename(self.src_dir).upper())
1812 self.assertNotEqual(self.src_dir, dst_dir)
1813
1814 try:
1815 shutil.move(self.src_dir, dst_dir)
1816 self.assertTrue(os.path.isdir(dst_dir))
1817 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +02001818 os.rmdir(dst_dir)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001819
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001820class TermsizeTests(unittest.TestCase):
1821 def test_does_not_crash(self):
1822 """Check if get_terminal_size() returns a meaningful value.
1823
1824 There's no easy portable way to actually check the size of the
1825 terminal, so let's check if it returns something sensible instead.
1826 """
1827 size = shutil.get_terminal_size()
Antoine Pitroucfade362012-02-08 23:48:59 +01001828 self.assertGreaterEqual(size.columns, 0)
1829 self.assertGreaterEqual(size.lines, 0)
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001830
1831 def test_os_environ_first(self):
1832 "Check if environment variables have precedence"
1833
1834 with support.EnvironmentVarGuard() as env:
1835 env['COLUMNS'] = '777'
Serhiy Storchakad30829d2016-04-24 09:58:43 +03001836 del env['LINES']
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001837 size = shutil.get_terminal_size()
1838 self.assertEqual(size.columns, 777)
1839
1840 with support.EnvironmentVarGuard() as env:
Serhiy Storchakad30829d2016-04-24 09:58:43 +03001841 del env['COLUMNS']
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001842 env['LINES'] = '888'
1843 size = shutil.get_terminal_size()
1844 self.assertEqual(size.lines, 888)
1845
Serhiy Storchakad30829d2016-04-24 09:58:43 +03001846 def test_bad_environ(self):
1847 with support.EnvironmentVarGuard() as env:
1848 env['COLUMNS'] = 'xxx'
1849 env['LINES'] = 'yyy'
1850 size = shutil.get_terminal_size()
1851 self.assertGreaterEqual(size.columns, 0)
1852 self.assertGreaterEqual(size.lines, 0)
1853
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001854 @unittest.skipUnless(os.isatty(sys.__stdout__.fileno()), "not on tty")
Victor Stinner119ebb72016-04-19 22:24:56 +02001855 @unittest.skipUnless(hasattr(os, 'get_terminal_size'),
1856 'need os.get_terminal_size()')
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001857 def test_stty_match(self):
1858 """Check if stty returns the same results ignoring env
1859
1860 This test will fail if stdin and stdout are connected to
1861 different terminals with different sizes. Nevertheless, such
1862 situations should be pretty rare.
1863 """
1864 try:
1865 size = subprocess.check_output(['stty', 'size']).decode().split()
Xavier de Gaye38c8b7d2016-11-14 17:14:42 +01001866 except (FileNotFoundError, PermissionError,
1867 subprocess.CalledProcessError):
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001868 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()