blob: 6e2b1004d309c967c795bdb01708833630769599 [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
Jelle Zijlstraa12df7b2017-05-05 14:27:12 -070013import pathlib
Antoine Pitroubcf2b592012-02-08 23:28:36 +010014import subprocess
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 +000023
24from test import support
Miss Islington (bot)a13b6542018-03-02 02:17:51 -080025from test.support import TESTFN, FakePath
Serhiy Storchaka11213772014-08-06 18:50:19 +030026
Antoine Pitrou7fff0962009-05-01 21:09:44 +000027TESTFN2 = TESTFN + "2"
Barry Warsaw7fc2cca2003-01-24 17:34:13 +000028
Tarek Ziadé396fad72010-02-23 05:30:31 +000029try:
30 import grp
31 import pwd
32 UID_GID_SUPPORT = True
33except ImportError:
34 UID_GID_SUPPORT = False
35
Nick Coghlan8ed3cf32011-03-16 14:05:35 -040036def _fake_rename(*args, **kwargs):
37 # Pretend the destination path is on a different filesystem.
Antoine Pitrouc041ab62012-01-02 19:18:02 +010038 raise OSError(getattr(errno, 'EXDEV', 18), "Invalid cross-device link")
Nick Coghlan8ed3cf32011-03-16 14:05:35 -040039
40def mock_rename(func):
41 @functools.wraps(func)
42 def wrap(*args, **kwargs):
43 try:
44 builtin_rename = os.rename
45 os.rename = _fake_rename
46 return func(*args, **kwargs)
47 finally:
48 os.rename = builtin_rename
49 return wrap
50
Éric Araujoa7e33a12011-08-12 19:51:35 +020051def write_file(path, content, binary=False):
52 """Write *content* to a file located at *path*.
53
54 If *path* is a tuple instead of a string, os.path.join will be used to
55 make a path. If *binary* is true, the file will be opened in binary
56 mode.
57 """
58 if isinstance(path, tuple):
59 path = os.path.join(*path)
60 with open(path, 'wb' if binary else 'w') as fp:
61 fp.write(content)
62
63def read_file(path, binary=False):
64 """Return contents from a file located at *path*.
65
66 If *path* is a tuple instead of a string, os.path.join will be used to
67 make a path. If *binary* is true, the file will be opened in binary
68 mode.
69 """
70 if isinstance(path, tuple):
71 path = os.path.join(*path)
72 with open(path, 'rb' if binary else 'r') as fp:
73 return fp.read()
74
Serhiy Storchaka527ef072015-09-06 18:33:19 +030075def rlistdir(path):
76 res = []
77 for name in sorted(os.listdir(path)):
78 p = os.path.join(path, name)
79 if os.path.isdir(p) and not os.path.islink(p):
80 res.append(name + '/')
81 for n in rlistdir(p):
82 res.append(name + '/' + n)
83 else:
84 res.append(name)
85 return res
86
Éric Araujoa7e33a12011-08-12 19:51:35 +020087
Barry Warsaw7fc2cca2003-01-24 17:34:13 +000088class TestShutil(unittest.TestCase):
Tarek Ziadé396fad72010-02-23 05:30:31 +000089
90 def setUp(self):
91 super(TestShutil, self).setUp()
92 self.tempdirs = []
93
94 def tearDown(self):
95 super(TestShutil, self).tearDown()
96 while self.tempdirs:
97 d = self.tempdirs.pop()
98 shutil.rmtree(d, os.name in ('nt', 'cygwin'))
99
Tarek Ziadé396fad72010-02-23 05:30:31 +0000100
101 def mkdtemp(self):
102 """Create a temporary directory that will be cleaned up.
103
104 Returns the path of the directory.
105 """
106 d = tempfile.mkdtemp()
107 self.tempdirs.append(d)
108 return d
Tarek Ziadé5340db32010-04-19 22:30:51 +0000109
Hynek Schlawack3b527782012-06-25 13:27:31 +0200110 def test_rmtree_works_on_bytes(self):
111 tmp = self.mkdtemp()
112 victim = os.path.join(tmp, 'killme')
113 os.mkdir(victim)
114 write_file(os.path.join(victim, 'somefile'), 'foo')
115 victim = os.fsencode(victim)
116 self.assertIsInstance(victim, bytes)
Steve Dowere58571b2016-09-08 11:11:13 -0700117 shutil.rmtree(victim)
Hynek Schlawack3b527782012-06-25 13:27:31 +0200118
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200119 @support.skip_unless_symlink
120 def test_rmtree_fails_on_symlink(self):
121 tmp = self.mkdtemp()
122 dir_ = os.path.join(tmp, 'dir')
123 os.mkdir(dir_)
124 link = os.path.join(tmp, 'link')
125 os.symlink(dir_, link)
126 self.assertRaises(OSError, shutil.rmtree, link)
127 self.assertTrue(os.path.exists(dir_))
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100128 self.assertTrue(os.path.lexists(link))
129 errors = []
130 def onerror(*args):
131 errors.append(args)
132 shutil.rmtree(link, onerror=onerror)
133 self.assertEqual(len(errors), 1)
134 self.assertIs(errors[0][0], os.path.islink)
135 self.assertEqual(errors[0][1], link)
136 self.assertIsInstance(errors[0][2][1], OSError)
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200137
138 @support.skip_unless_symlink
139 def test_rmtree_works_on_symlinks(self):
140 tmp = self.mkdtemp()
141 dir1 = os.path.join(tmp, 'dir1')
142 dir2 = os.path.join(dir1, 'dir2')
143 dir3 = os.path.join(tmp, 'dir3')
144 for d in dir1, dir2, dir3:
145 os.mkdir(d)
146 file1 = os.path.join(tmp, 'file1')
147 write_file(file1, 'foo')
148 link1 = os.path.join(dir1, 'link1')
149 os.symlink(dir2, link1)
150 link2 = os.path.join(dir1, 'link2')
151 os.symlink(dir3, link2)
152 link3 = os.path.join(dir1, 'link3')
153 os.symlink(file1, link3)
154 # make sure symlinks are removed but not followed
155 shutil.rmtree(dir1)
156 self.assertFalse(os.path.exists(dir1))
157 self.assertTrue(os.path.exists(dir3))
158 self.assertTrue(os.path.exists(file1))
159
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000160 def test_rmtree_errors(self):
161 # filename is guaranteed not to exist
162 filename = tempfile.mktemp()
Hynek Schlawackb5501102012-12-10 09:11:25 +0100163 self.assertRaises(FileNotFoundError, shutil.rmtree, filename)
164 # test that ignore_errors option is honored
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100165 shutil.rmtree(filename, ignore_errors=True)
166
167 # existing file
168 tmpdir = self.mkdtemp()
Hynek Schlawackb5501102012-12-10 09:11:25 +0100169 write_file((tmpdir, "tstfile"), "")
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100170 filename = os.path.join(tmpdir, "tstfile")
Hynek Schlawackb5501102012-12-10 09:11:25 +0100171 with self.assertRaises(NotADirectoryError) as cm:
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100172 shutil.rmtree(filename)
Hynek Schlawack87f9b462012-12-10 16:29:57 +0100173 # The reason for this rather odd construct is that Windows sprinkles
174 # a \*.* at the end of file names. But only sometimes on some buildbots
175 possible_args = [filename, os.path.join(filename, '*.*')]
176 self.assertIn(cm.exception.filename, possible_args)
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100177 self.assertTrue(os.path.exists(filename))
Hynek Schlawackb5501102012-12-10 09:11:25 +0100178 # test that ignore_errors option is honored
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100179 shutil.rmtree(filename, ignore_errors=True)
180 self.assertTrue(os.path.exists(filename))
181 errors = []
182 def onerror(*args):
183 errors.append(args)
184 shutil.rmtree(filename, onerror=onerror)
185 self.assertEqual(len(errors), 2)
Serhiy Storchakad4d79bc2017-11-04 14:16:35 +0200186 self.assertIs(errors[0][0], os.scandir)
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100187 self.assertEqual(errors[0][1], filename)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100188 self.assertIsInstance(errors[0][2][1], NotADirectoryError)
Hynek Schlawack87f9b462012-12-10 16:29:57 +0100189 self.assertIn(errors[0][2][1].filename, possible_args)
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100190 self.assertIs(errors[1][0], os.rmdir)
191 self.assertEqual(errors[1][1], filename)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100192 self.assertIsInstance(errors[1][2][1], NotADirectoryError)
Hynek Schlawack87f9b462012-12-10 16:29:57 +0100193 self.assertIn(errors[1][2][1].filename, possible_args)
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000194
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000195
Serhiy Storchaka43767632013-11-03 21:31:38 +0200196 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod()')
197 @unittest.skipIf(sys.platform[:6] == 'cygwin',
198 "This test can't be run on Cygwin (issue #1071513).")
199 @unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0,
200 "This test can't be run reliably as root (issue #1076467).")
201 def test_on_error(self):
202 self.errorState = 0
203 os.mkdir(TESTFN)
204 self.addCleanup(shutil.rmtree, TESTFN)
Antoine Pitrou2f8a75c2012-06-23 21:28:15 +0200205
Serhiy Storchaka43767632013-11-03 21:31:38 +0200206 self.child_file_path = os.path.join(TESTFN, 'a')
207 self.child_dir_path = os.path.join(TESTFN, 'b')
208 support.create_empty_file(self.child_file_path)
209 os.mkdir(self.child_dir_path)
210 old_dir_mode = os.stat(TESTFN).st_mode
211 old_child_file_mode = os.stat(self.child_file_path).st_mode
212 old_child_dir_mode = os.stat(self.child_dir_path).st_mode
213 # Make unwritable.
214 new_mode = stat.S_IREAD|stat.S_IEXEC
215 os.chmod(self.child_file_path, new_mode)
216 os.chmod(self.child_dir_path, new_mode)
217 os.chmod(TESTFN, new_mode)
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000218
Serhiy Storchaka43767632013-11-03 21:31:38 +0200219 self.addCleanup(os.chmod, TESTFN, old_dir_mode)
220 self.addCleanup(os.chmod, self.child_file_path, old_child_file_mode)
221 self.addCleanup(os.chmod, self.child_dir_path, old_child_dir_mode)
Antoine Pitrou2f8a75c2012-06-23 21:28:15 +0200222
Serhiy Storchaka43767632013-11-03 21:31:38 +0200223 shutil.rmtree(TESTFN, onerror=self.check_args_to_onerror)
224 # Test whether onerror has actually been called.
225 self.assertEqual(self.errorState, 3,
226 "Expected call to onerror function did not happen.")
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000227
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000228 def check_args_to_onerror(self, func, arg, exc):
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000229 # test_rmtree_errors deliberately runs rmtree
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200230 # on a directory that is chmod 500, which will fail.
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000231 # This function is run when shutil.rmtree fails.
232 # 99.9% of the time it initially fails to remove
233 # a file in the directory, so the first time through
234 # func is os.remove.
235 # However, some Linux machines running ZFS on
236 # FUSE experienced a failure earlier in the process
237 # at os.listdir. The first failure may legally
238 # be either.
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200239 if self.errorState < 2:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200240 if func is os.unlink:
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200241 self.assertEqual(arg, self.child_file_path)
242 elif func is os.rmdir:
243 self.assertEqual(arg, self.child_dir_path)
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000244 else:
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200245 self.assertIs(func, os.listdir)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200246 self.assertIn(arg, [TESTFN, self.child_dir_path])
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000247 self.assertTrue(issubclass(exc[0], OSError))
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200248 self.errorState += 1
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000249 else:
250 self.assertEqual(func, os.rmdir)
251 self.assertEqual(arg, TESTFN)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000252 self.assertTrue(issubclass(exc[0], OSError))
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200253 self.errorState = 3
254
255 def test_rmtree_does_not_choke_on_failing_lstat(self):
256 try:
257 orig_lstat = os.lstat
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200258 def raiser(fn, *args, **kwargs):
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200259 if fn != TESTFN:
260 raise OSError()
261 else:
262 return orig_lstat(fn)
263 os.lstat = raiser
264
265 os.mkdir(TESTFN)
266 write_file((TESTFN, 'foo'), 'foo')
267 shutil.rmtree(TESTFN)
268 finally:
269 os.lstat = orig_lstat
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000270
Antoine Pitrou78091e62011-12-29 18:54:15 +0100271 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
272 @support.skip_unless_symlink
273 def test_copymode_follow_symlinks(self):
274 tmp_dir = self.mkdtemp()
275 src = os.path.join(tmp_dir, 'foo')
276 dst = os.path.join(tmp_dir, 'bar')
277 src_link = os.path.join(tmp_dir, 'baz')
278 dst_link = os.path.join(tmp_dir, 'quux')
279 write_file(src, 'foo')
280 write_file(dst, 'foo')
281 os.symlink(src, src_link)
282 os.symlink(dst, dst_link)
283 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
284 # file to file
285 os.chmod(dst, stat.S_IRWXO)
286 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
287 shutil.copymode(src, dst)
288 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
Antoine Pitrou3f48ac92014-01-01 02:50:45 +0100289 # On Windows, os.chmod does not follow symlinks (issue #15411)
290 if os.name != 'nt':
291 # follow src link
292 os.chmod(dst, stat.S_IRWXO)
293 shutil.copymode(src_link, dst)
294 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
295 # follow dst link
296 os.chmod(dst, stat.S_IRWXO)
297 shutil.copymode(src, dst_link)
298 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
299 # follow both links
300 os.chmod(dst, stat.S_IRWXO)
301 shutil.copymode(src_link, dst_link)
302 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100303
304 @unittest.skipUnless(hasattr(os, 'lchmod'), 'requires os.lchmod')
305 @support.skip_unless_symlink
306 def test_copymode_symlink_to_symlink(self):
307 tmp_dir = self.mkdtemp()
308 src = os.path.join(tmp_dir, 'foo')
309 dst = os.path.join(tmp_dir, 'bar')
310 src_link = os.path.join(tmp_dir, 'baz')
311 dst_link = os.path.join(tmp_dir, 'quux')
312 write_file(src, 'foo')
313 write_file(dst, 'foo')
314 os.symlink(src, src_link)
315 os.symlink(dst, dst_link)
316 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
317 os.chmod(dst, stat.S_IRWXU)
318 os.lchmod(src_link, stat.S_IRWXO|stat.S_IRWXG)
319 # link to link
320 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700321 shutil.copymode(src_link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100322 self.assertEqual(os.lstat(src_link).st_mode,
323 os.lstat(dst_link).st_mode)
324 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
325 # src link - use chmod
326 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700327 shutil.copymode(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100328 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
329 # dst link - use chmod
330 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700331 shutil.copymode(src, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100332 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
333
334 @unittest.skipIf(hasattr(os, 'lchmod'), 'requires os.lchmod to be missing')
335 @support.skip_unless_symlink
336 def test_copymode_symlink_to_symlink_wo_lchmod(self):
337 tmp_dir = self.mkdtemp()
338 src = os.path.join(tmp_dir, 'foo')
339 dst = os.path.join(tmp_dir, 'bar')
340 src_link = os.path.join(tmp_dir, 'baz')
341 dst_link = os.path.join(tmp_dir, 'quux')
342 write_file(src, 'foo')
343 write_file(dst, 'foo')
344 os.symlink(src, src_link)
345 os.symlink(dst, dst_link)
Larry Hastingsb4038062012-07-15 10:57:38 -0700346 shutil.copymode(src_link, dst_link, follow_symlinks=False) # silent fail
Antoine Pitrou78091e62011-12-29 18:54:15 +0100347
348 @support.skip_unless_symlink
349 def test_copystat_symlinks(self):
350 tmp_dir = self.mkdtemp()
351 src = os.path.join(tmp_dir, 'foo')
352 dst = os.path.join(tmp_dir, 'bar')
353 src_link = os.path.join(tmp_dir, 'baz')
354 dst_link = os.path.join(tmp_dir, 'qux')
355 write_file(src, 'foo')
356 src_stat = os.stat(src)
357 os.utime(src, (src_stat.st_atime,
358 src_stat.st_mtime - 42.0)) # ensure different mtimes
359 write_file(dst, 'bar')
360 self.assertNotEqual(os.stat(src).st_mtime, os.stat(dst).st_mtime)
361 os.symlink(src, src_link)
362 os.symlink(dst, dst_link)
363 if hasattr(os, 'lchmod'):
364 os.lchmod(src_link, stat.S_IRWXO)
365 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
366 os.lchflags(src_link, stat.UF_NODUMP)
367 src_link_stat = os.lstat(src_link)
368 # follow
369 if hasattr(os, 'lchmod'):
Larry Hastingsb4038062012-07-15 10:57:38 -0700370 shutil.copystat(src_link, dst_link, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100371 self.assertNotEqual(src_link_stat.st_mode, os.stat(dst).st_mode)
372 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700373 shutil.copystat(src_link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100374 dst_link_stat = os.lstat(dst_link)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700375 if os.utime in os.supports_follow_symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100376 for attr in 'st_atime', 'st_mtime':
377 # The modification times may be truncated in the new file.
378 self.assertLessEqual(getattr(src_link_stat, attr),
379 getattr(dst_link_stat, attr) + 1)
380 if hasattr(os, 'lchmod'):
381 self.assertEqual(src_link_stat.st_mode, dst_link_stat.st_mode)
382 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
383 self.assertEqual(src_link_stat.st_flags, dst_link_stat.st_flags)
384 # tell to follow but dst is not a link
Larry Hastingsb4038062012-07-15 10:57:38 -0700385 shutil.copystat(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100386 self.assertTrue(abs(os.stat(src).st_mtime - os.stat(dst).st_mtime) <
387 00000.1)
388
Ned Deilybaf75712012-05-10 17:05:19 -0700389 @unittest.skipUnless(hasattr(os, 'chflags') and
390 hasattr(errno, 'EOPNOTSUPP') and
391 hasattr(errno, 'ENOTSUP'),
392 "requires os.chflags, EOPNOTSUPP & ENOTSUP")
393 def test_copystat_handles_harmless_chflags_errors(self):
394 tmpdir = self.mkdtemp()
395 file1 = os.path.join(tmpdir, 'file1')
396 file2 = os.path.join(tmpdir, 'file2')
397 write_file(file1, 'xxx')
398 write_file(file2, 'xxx')
399
400 def make_chflags_raiser(err):
401 ex = OSError()
402
Larry Hastings90867a52012-06-22 17:01:41 -0700403 def _chflags_raiser(path, flags, *, follow_symlinks=True):
Ned Deilybaf75712012-05-10 17:05:19 -0700404 ex.errno = err
405 raise ex
406 return _chflags_raiser
407 old_chflags = os.chflags
408 try:
409 for err in errno.EOPNOTSUPP, errno.ENOTSUP:
410 os.chflags = make_chflags_raiser(err)
411 shutil.copystat(file1, file2)
412 # assert others errors break it
413 os.chflags = make_chflags_raiser(errno.EOPNOTSUPP + errno.ENOTSUP)
414 self.assertRaises(OSError, shutil.copystat, file1, file2)
415 finally:
416 os.chflags = old_chflags
417
Antoine Pitrou424246f2012-05-12 19:02:01 +0200418 @support.skip_unless_xattr
419 def test_copyxattr(self):
420 tmp_dir = self.mkdtemp()
421 src = os.path.join(tmp_dir, 'foo')
422 write_file(src, 'foo')
423 dst = os.path.join(tmp_dir, 'bar')
424 write_file(dst, 'bar')
425
426 # no xattr == no problem
427 shutil._copyxattr(src, dst)
428 # common case
429 os.setxattr(src, 'user.foo', b'42')
430 os.setxattr(src, 'user.bar', b'43')
431 shutil._copyxattr(src, dst)
Gregory P. Smith1093bf22014-01-17 12:01:22 -0800432 self.assertEqual(sorted(os.listxattr(src)), sorted(os.listxattr(dst)))
Antoine Pitrou424246f2012-05-12 19:02:01 +0200433 self.assertEqual(
434 os.getxattr(src, 'user.foo'),
435 os.getxattr(dst, 'user.foo'))
436 # check errors don't affect other attrs
437 os.remove(dst)
438 write_file(dst, 'bar')
439 os_error = OSError(errno.EPERM, 'EPERM')
440
Larry Hastings9cf065c2012-06-22 16:30:09 -0700441 def _raise_on_user_foo(fname, attr, val, **kwargs):
Antoine Pitrou424246f2012-05-12 19:02:01 +0200442 if attr == 'user.foo':
443 raise os_error
444 else:
Larry Hastings9cf065c2012-06-22 16:30:09 -0700445 orig_setxattr(fname, attr, val, **kwargs)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200446 try:
447 orig_setxattr = os.setxattr
448 os.setxattr = _raise_on_user_foo
449 shutil._copyxattr(src, dst)
Antoine Pitrou61597d32012-05-12 23:37:35 +0200450 self.assertIn('user.bar', os.listxattr(dst))
Antoine Pitrou424246f2012-05-12 19:02:01 +0200451 finally:
452 os.setxattr = orig_setxattr
Hynek Schlawack0beab052013-02-05 08:22:44 +0100453 # the source filesystem not supporting xattrs should be ok, too.
454 def _raise_on_src(fname, *, follow_symlinks=True):
455 if fname == src:
456 raise OSError(errno.ENOTSUP, 'Operation not supported')
457 return orig_listxattr(fname, follow_symlinks=follow_symlinks)
458 try:
459 orig_listxattr = os.listxattr
460 os.listxattr = _raise_on_src
461 shutil._copyxattr(src, dst)
462 finally:
463 os.listxattr = orig_listxattr
Antoine Pitrou424246f2012-05-12 19:02:01 +0200464
Larry Hastingsad5ae042012-07-14 17:55:11 -0700465 # test that shutil.copystat copies xattrs
466 src = os.path.join(tmp_dir, 'the_original')
467 write_file(src, src)
468 os.setxattr(src, 'user.the_value', b'fiddly')
469 dst = os.path.join(tmp_dir, 'the_copy')
470 write_file(dst, dst)
471 shutil.copystat(src, dst)
Hynek Schlawackc2d481f2012-07-16 17:11:10 +0200472 self.assertEqual(os.getxattr(dst, 'user.the_value'), b'fiddly')
Larry Hastingsad5ae042012-07-14 17:55:11 -0700473
Antoine Pitrou424246f2012-05-12 19:02:01 +0200474 @support.skip_unless_symlink
475 @support.skip_unless_xattr
476 @unittest.skipUnless(hasattr(os, 'geteuid') and os.geteuid() == 0,
477 'root privileges required')
478 def test_copyxattr_symlinks(self):
479 # On Linux, it's only possible to access non-user xattr for symlinks;
480 # which in turn require root privileges. This test should be expanded
481 # as soon as other platforms gain support for extended attributes.
482 tmp_dir = self.mkdtemp()
483 src = os.path.join(tmp_dir, 'foo')
484 src_link = os.path.join(tmp_dir, 'baz')
485 write_file(src, 'foo')
486 os.symlink(src, src_link)
487 os.setxattr(src, 'trusted.foo', b'42')
Larry Hastings9cf065c2012-06-22 16:30:09 -0700488 os.setxattr(src_link, 'trusted.foo', b'43', follow_symlinks=False)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200489 dst = os.path.join(tmp_dir, 'bar')
490 dst_link = os.path.join(tmp_dir, 'qux')
491 write_file(dst, 'bar')
492 os.symlink(dst, dst_link)
Larry Hastingsb4038062012-07-15 10:57:38 -0700493 shutil._copyxattr(src_link, dst_link, follow_symlinks=False)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700494 self.assertEqual(os.getxattr(dst_link, 'trusted.foo', follow_symlinks=False), b'43')
Antoine Pitrou424246f2012-05-12 19:02:01 +0200495 self.assertRaises(OSError, os.getxattr, dst, 'trusted.foo')
Larry Hastingsb4038062012-07-15 10:57:38 -0700496 shutil._copyxattr(src_link, dst, follow_symlinks=False)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200497 self.assertEqual(os.getxattr(dst, 'trusted.foo'), b'43')
498
Antoine Pitrou78091e62011-12-29 18:54:15 +0100499 @support.skip_unless_symlink
500 def test_copy_symlinks(self):
501 tmp_dir = self.mkdtemp()
502 src = os.path.join(tmp_dir, 'foo')
503 dst = os.path.join(tmp_dir, 'bar')
504 src_link = os.path.join(tmp_dir, 'baz')
505 write_file(src, 'foo')
506 os.symlink(src, src_link)
507 if hasattr(os, 'lchmod'):
508 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
509 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700510 shutil.copy(src_link, dst, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100511 self.assertFalse(os.path.islink(dst))
512 self.assertEqual(read_file(src), read_file(dst))
513 os.remove(dst)
514 # follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700515 shutil.copy(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100516 self.assertTrue(os.path.islink(dst))
517 self.assertEqual(os.readlink(dst), os.readlink(src_link))
518 if hasattr(os, 'lchmod'):
519 self.assertEqual(os.lstat(src_link).st_mode,
520 os.lstat(dst).st_mode)
521
522 @support.skip_unless_symlink
523 def test_copy2_symlinks(self):
524 tmp_dir = self.mkdtemp()
525 src = os.path.join(tmp_dir, 'foo')
526 dst = os.path.join(tmp_dir, 'bar')
527 src_link = os.path.join(tmp_dir, 'baz')
528 write_file(src, 'foo')
529 os.symlink(src, src_link)
530 if hasattr(os, 'lchmod'):
531 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
532 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
533 os.lchflags(src_link, stat.UF_NODUMP)
534 src_stat = os.stat(src)
535 src_link_stat = os.lstat(src_link)
536 # follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700537 shutil.copy2(src_link, dst, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100538 self.assertFalse(os.path.islink(dst))
539 self.assertEqual(read_file(src), read_file(dst))
540 os.remove(dst)
541 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700542 shutil.copy2(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100543 self.assertTrue(os.path.islink(dst))
544 self.assertEqual(os.readlink(dst), os.readlink(src_link))
545 dst_stat = os.lstat(dst)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700546 if os.utime in os.supports_follow_symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100547 for attr in 'st_atime', 'st_mtime':
548 # The modification times may be truncated in the new file.
549 self.assertLessEqual(getattr(src_link_stat, attr),
550 getattr(dst_stat, attr) + 1)
551 if hasattr(os, 'lchmod'):
552 self.assertEqual(src_link_stat.st_mode, dst_stat.st_mode)
553 self.assertNotEqual(src_stat.st_mode, dst_stat.st_mode)
554 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
555 self.assertEqual(src_link_stat.st_flags, dst_stat.st_flags)
556
Antoine Pitrou424246f2012-05-12 19:02:01 +0200557 @support.skip_unless_xattr
558 def test_copy2_xattr(self):
559 tmp_dir = self.mkdtemp()
560 src = os.path.join(tmp_dir, 'foo')
561 dst = os.path.join(tmp_dir, 'bar')
562 write_file(src, 'foo')
563 os.setxattr(src, 'user.foo', b'42')
564 shutil.copy2(src, dst)
565 self.assertEqual(
566 os.getxattr(src, 'user.foo'),
567 os.getxattr(dst, 'user.foo'))
568 os.remove(dst)
569
Antoine Pitrou78091e62011-12-29 18:54:15 +0100570 @support.skip_unless_symlink
571 def test_copyfile_symlinks(self):
572 tmp_dir = self.mkdtemp()
573 src = os.path.join(tmp_dir, 'src')
574 dst = os.path.join(tmp_dir, 'dst')
575 dst_link = os.path.join(tmp_dir, 'dst_link')
576 link = os.path.join(tmp_dir, 'link')
577 write_file(src, 'foo')
578 os.symlink(src, link)
579 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700580 shutil.copyfile(link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100581 self.assertTrue(os.path.islink(dst_link))
582 self.assertEqual(os.readlink(link), os.readlink(dst_link))
583 # follow
584 shutil.copyfile(link, dst)
585 self.assertFalse(os.path.islink(dst))
586
Hynek Schlawack2100b422012-06-23 20:28:32 +0200587 def test_rmtree_uses_safe_fd_version_if_available(self):
Hynek Schlawackd0f6e0a2012-06-29 08:28:20 +0200588 _use_fd_functions = ({os.open, os.stat, os.unlink, os.rmdir} <=
589 os.supports_dir_fd and
590 os.listdir in os.supports_fd and
591 os.stat in os.supports_follow_symlinks)
592 if _use_fd_functions:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200593 self.assertTrue(shutil._use_fd_functions)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000594 self.assertTrue(shutil.rmtree.avoids_symlink_attacks)
Hynek Schlawack2100b422012-06-23 20:28:32 +0200595 tmp_dir = self.mkdtemp()
596 d = os.path.join(tmp_dir, 'a')
597 os.mkdir(d)
598 try:
599 real_rmtree = shutil._rmtree_safe_fd
600 class Called(Exception): pass
601 def _raiser(*args, **kwargs):
602 raise Called
603 shutil._rmtree_safe_fd = _raiser
604 self.assertRaises(Called, shutil.rmtree, d)
605 finally:
606 shutil._rmtree_safe_fd = real_rmtree
607 else:
608 self.assertFalse(shutil._use_fd_functions)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000609 self.assertFalse(shutil.rmtree.avoids_symlink_attacks)
Hynek Schlawack2100b422012-06-23 20:28:32 +0200610
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000611 def test_rmtree_dont_delete_file(self):
612 # When called on a file instead of a directory, don't delete it.
613 handle, path = tempfile.mkstemp()
Victor Stinnerbf816222011-06-30 23:25:47 +0200614 os.close(handle)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200615 self.assertRaises(NotADirectoryError, shutil.rmtree, path)
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000616 os.remove(path)
617
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000618 def test_copytree_simple(self):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000619 src_dir = tempfile.mkdtemp()
620 dst_dir = os.path.join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200621 self.addCleanup(shutil.rmtree, src_dir)
622 self.addCleanup(shutil.rmtree, os.path.dirname(dst_dir))
623 write_file((src_dir, 'test.txt'), '123')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000624 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200625 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000626
Éric Araujoa7e33a12011-08-12 19:51:35 +0200627 shutil.copytree(src_dir, dst_dir)
628 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test.txt')))
629 self.assertTrue(os.path.isdir(os.path.join(dst_dir, 'test_dir')))
630 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test_dir',
631 'test.txt')))
632 actual = read_file((dst_dir, 'test.txt'))
633 self.assertEqual(actual, '123')
634 actual = read_file((dst_dir, 'test_dir', 'test.txt'))
635 self.assertEqual(actual, '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000636
Antoine Pitrou78091e62011-12-29 18:54:15 +0100637 @support.skip_unless_symlink
638 def test_copytree_symlinks(self):
639 tmp_dir = self.mkdtemp()
640 src_dir = os.path.join(tmp_dir, 'src')
641 dst_dir = os.path.join(tmp_dir, 'dst')
642 sub_dir = os.path.join(src_dir, 'sub')
643 os.mkdir(src_dir)
644 os.mkdir(sub_dir)
645 write_file((src_dir, 'file.txt'), 'foo')
646 src_link = os.path.join(sub_dir, 'link')
647 dst_link = os.path.join(dst_dir, 'sub/link')
648 os.symlink(os.path.join(src_dir, 'file.txt'),
649 src_link)
650 if hasattr(os, 'lchmod'):
651 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
652 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
653 os.lchflags(src_link, stat.UF_NODUMP)
654 src_stat = os.lstat(src_link)
655 shutil.copytree(src_dir, dst_dir, symlinks=True)
656 self.assertTrue(os.path.islink(os.path.join(dst_dir, 'sub', 'link')))
657 self.assertEqual(os.readlink(os.path.join(dst_dir, 'sub', 'link')),
658 os.path.join(src_dir, 'file.txt'))
659 dst_stat = os.lstat(dst_link)
660 if hasattr(os, 'lchmod'):
661 self.assertEqual(dst_stat.st_mode, src_stat.st_mode)
662 if hasattr(os, 'lchflags'):
663 self.assertEqual(dst_stat.st_flags, src_stat.st_flags)
664
Georg Brandl2ee470f2008-07-16 12:55:28 +0000665 def test_copytree_with_exclude(self):
Georg Brandl2ee470f2008-07-16 12:55:28 +0000666 # creating data
667 join = os.path.join
668 exists = os.path.exists
669 src_dir = tempfile.mkdtemp()
Georg Brandl2ee470f2008-07-16 12:55:28 +0000670 try:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000671 dst_dir = join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200672 write_file((src_dir, 'test.txt'), '123')
673 write_file((src_dir, 'test.tmp'), '123')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000674 os.mkdir(join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200675 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000676 os.mkdir(join(src_dir, 'test_dir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200677 write_file((src_dir, 'test_dir2', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000678 os.mkdir(join(src_dir, 'test_dir2', 'subdir'))
679 os.mkdir(join(src_dir, 'test_dir2', 'subdir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200680 write_file((src_dir, 'test_dir2', 'subdir', 'test.txt'), '456')
681 write_file((src_dir, 'test_dir2', 'subdir2', 'test.py'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000682
683 # testing glob-like patterns
684 try:
685 patterns = shutil.ignore_patterns('*.tmp', 'test_dir2')
686 shutil.copytree(src_dir, dst_dir, ignore=patterns)
687 # checking the result: some elements should not be copied
688 self.assertTrue(exists(join(dst_dir, 'test.txt')))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200689 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
690 self.assertFalse(exists(join(dst_dir, 'test_dir2')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000691 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200692 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000693 try:
694 patterns = shutil.ignore_patterns('*.tmp', 'subdir*')
695 shutil.copytree(src_dir, dst_dir, ignore=patterns)
696 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200697 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
698 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2')))
699 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000700 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200701 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000702
703 # testing callable-style
704 try:
705 def _filter(src, names):
706 res = []
707 for name in names:
708 path = os.path.join(src, name)
709
710 if (os.path.isdir(path) and
711 path.split()[-1] == 'subdir'):
712 res.append(name)
713 elif os.path.splitext(path)[-1] in ('.py'):
714 res.append(name)
715 return res
716
717 shutil.copytree(src_dir, dst_dir, ignore=_filter)
718
719 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200720 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2',
721 'test.py')))
722 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000723
724 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200725 shutil.rmtree(dst_dir)
Georg Brandl2ee470f2008-07-16 12:55:28 +0000726 finally:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000727 shutil.rmtree(src_dir)
728 shutil.rmtree(os.path.dirname(dst_dir))
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000729
Antoine Pitrouac601602013-08-16 19:35:02 +0200730 def test_copytree_retains_permissions(self):
731 tmp_dir = tempfile.mkdtemp()
732 src_dir = os.path.join(tmp_dir, 'source')
733 os.mkdir(src_dir)
734 dst_dir = os.path.join(tmp_dir, 'destination')
735 self.addCleanup(shutil.rmtree, tmp_dir)
736
737 os.chmod(src_dir, 0o777)
738 write_file((src_dir, 'permissive.txt'), '123')
739 os.chmod(os.path.join(src_dir, 'permissive.txt'), 0o777)
740 write_file((src_dir, 'restrictive.txt'), '456')
741 os.chmod(os.path.join(src_dir, 'restrictive.txt'), 0o600)
742 restrictive_subdir = tempfile.mkdtemp(dir=src_dir)
743 os.chmod(restrictive_subdir, 0o600)
744
745 shutil.copytree(src_dir, dst_dir)
Brett Cannon9c7eb552013-08-23 14:38:11 -0400746 self.assertEqual(os.stat(src_dir).st_mode, os.stat(dst_dir).st_mode)
747 self.assertEqual(os.stat(os.path.join(src_dir, 'permissive.txt')).st_mode,
Antoine Pitrouac601602013-08-16 19:35:02 +0200748 os.stat(os.path.join(dst_dir, 'permissive.txt')).st_mode)
Brett Cannon9c7eb552013-08-23 14:38:11 -0400749 self.assertEqual(os.stat(os.path.join(src_dir, 'restrictive.txt')).st_mode,
Antoine Pitrouac601602013-08-16 19:35:02 +0200750 os.stat(os.path.join(dst_dir, 'restrictive.txt')).st_mode)
751 restrictive_subdir_dst = os.path.join(dst_dir,
752 os.path.split(restrictive_subdir)[1])
Brett Cannon9c7eb552013-08-23 14:38:11 -0400753 self.assertEqual(os.stat(restrictive_subdir).st_mode,
Antoine Pitrouac601602013-08-16 19:35:02 +0200754 os.stat(restrictive_subdir_dst).st_mode)
755
Berker Peksag884afd92014-12-10 02:50:32 +0200756 @unittest.mock.patch('os.chmod')
757 def test_copytree_winerror(self, mock_patch):
758 # When copying to VFAT, copystat() raises OSError. On Windows, the
759 # exception object has a meaningful 'winerror' attribute, but not
760 # on other operating systems. Do not assume 'winerror' is set.
761 src_dir = tempfile.mkdtemp()
762 dst_dir = os.path.join(tempfile.mkdtemp(), 'destination')
763 self.addCleanup(shutil.rmtree, src_dir)
764 self.addCleanup(shutil.rmtree, os.path.dirname(dst_dir))
765
766 mock_patch.side_effect = PermissionError('ka-boom')
767 with self.assertRaises(shutil.Error):
768 shutil.copytree(src_dir, dst_dir)
769
Zachary Ware9fe6d862013-12-08 00:20:35 -0600770 @unittest.skipIf(os.name == 'nt', 'temporarily disabled on Windows')
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000771 @unittest.skipUnless(hasattr(os, 'link'), 'requires os.link')
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')
xdegaye92c2ca72017-11-12 17:31:07 +0100780 try:
781 os.link(src, dst)
782 except PermissionError as e:
783 self.skipTest('os.link(): %s' % e)
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):
xdegaye92c2ca72017-11-12 17:31:07 +0100828 try:
829 os.mkfifo(TESTFN)
830 except PermissionError as e:
831 self.skipTest('os.mkfifo(): %s' % e)
Serhiy Storchaka43767632013-11-03 21:31:38 +0200832 try:
833 self.assertRaises(shutil.SpecialFileError,
834 shutil.copyfile, TESTFN, TESTFN2)
835 self.assertRaises(shutil.SpecialFileError,
836 shutil.copyfile, __file__, TESTFN)
837 finally:
838 os.remove(TESTFN)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000839
Serhiy Storchaka43767632013-11-03 21:31:38 +0200840 @unittest.skipUnless(hasattr(os, "mkfifo"), 'requires os.mkfifo()')
841 @support.skip_unless_symlink
842 def test_copytree_named_pipe(self):
843 os.mkdir(TESTFN)
844 try:
845 subdir = os.path.join(TESTFN, "subdir")
846 os.mkdir(subdir)
847 pipe = os.path.join(subdir, "mypipe")
xdegaye92c2ca72017-11-12 17:31:07 +0100848 try:
849 os.mkfifo(pipe)
850 except PermissionError as e:
851 self.skipTest('os.mkfifo(): %s' % e)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000852 try:
Serhiy Storchaka43767632013-11-03 21:31:38 +0200853 shutil.copytree(TESTFN, TESTFN2)
854 except shutil.Error as e:
855 errors = e.args[0]
856 self.assertEqual(len(errors), 1)
857 src, dst, error_msg = errors[0]
858 self.assertEqual("`%s` is a named pipe" % pipe, error_msg)
859 else:
860 self.fail("shutil.Error should have been raised")
861 finally:
862 shutil.rmtree(TESTFN, ignore_errors=True)
863 shutil.rmtree(TESTFN2, ignore_errors=True)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000864
Tarek Ziadé5340db32010-04-19 22:30:51 +0000865 def test_copytree_special_func(self):
866
867 src_dir = self.mkdtemp()
868 dst_dir = os.path.join(self.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200869 write_file((src_dir, 'test.txt'), '123')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000870 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200871 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000872
873 copied = []
874 def _copy(src, dst):
875 copied.append((src, dst))
876
877 shutil.copytree(src_dir, dst_dir, copy_function=_copy)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000878 self.assertEqual(len(copied), 2)
Tarek Ziadé5340db32010-04-19 22:30:51 +0000879
Brian Curtin3b4499c2010-12-28 14:31:47 +0000880 @support.skip_unless_symlink
Tarek Ziadéfb437512010-04-20 08:57:33 +0000881 def test_copytree_dangling_symlinks(self):
882
883 # a dangling symlink raises an error at the end
884 src_dir = self.mkdtemp()
885 dst_dir = os.path.join(self.mkdtemp(), 'destination')
886 os.symlink('IDONTEXIST', os.path.join(src_dir, 'test.txt'))
887 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200888 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadéfb437512010-04-20 08:57:33 +0000889 self.assertRaises(Error, shutil.copytree, src_dir, dst_dir)
890
891 # a dangling symlink is ignored with the proper flag
892 dst_dir = os.path.join(self.mkdtemp(), 'destination2')
893 shutil.copytree(src_dir, dst_dir, ignore_dangling_symlinks=True)
894 self.assertNotIn('test.txt', os.listdir(dst_dir))
895
896 # a dangling symlink is copied if symlinks=True
897 dst_dir = os.path.join(self.mkdtemp(), 'destination3')
898 shutil.copytree(src_dir, dst_dir, symlinks=True)
899 self.assertIn('test.txt', os.listdir(dst_dir))
900
Berker Peksag5a294d82015-07-25 14:53:48 +0300901 @support.skip_unless_symlink
902 def test_copytree_symlink_dir(self):
903 src_dir = self.mkdtemp()
904 dst_dir = os.path.join(self.mkdtemp(), 'destination')
905 os.mkdir(os.path.join(src_dir, 'real_dir'))
906 with open(os.path.join(src_dir, 'real_dir', 'test.txt'), 'w'):
907 pass
908 os.symlink(os.path.join(src_dir, 'real_dir'),
909 os.path.join(src_dir, 'link_to_dir'),
910 target_is_directory=True)
911
912 shutil.copytree(src_dir, dst_dir, symlinks=False)
913 self.assertFalse(os.path.islink(os.path.join(dst_dir, 'link_to_dir')))
914 self.assertIn('test.txt', os.listdir(os.path.join(dst_dir, 'link_to_dir')))
915
916 dst_dir = os.path.join(self.mkdtemp(), 'destination2')
917 shutil.copytree(src_dir, dst_dir, symlinks=True)
918 self.assertTrue(os.path.islink(os.path.join(dst_dir, 'link_to_dir')))
919 self.assertIn('test.txt', os.listdir(os.path.join(dst_dir, 'link_to_dir')))
920
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400921 def _copy_file(self, method):
922 fname = 'test.txt'
923 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200924 write_file((tmpdir, fname), 'xxx')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400925 file1 = os.path.join(tmpdir, fname)
926 tmpdir2 = self.mkdtemp()
927 method(file1, tmpdir2)
928 file2 = os.path.join(tmpdir2, fname)
929 return (file1, file2)
930
931 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
932 def test_copy(self):
933 # Ensure that the copied file exists and has the same mode bits.
934 file1, file2 = self._copy_file(shutil.copy)
935 self.assertTrue(os.path.exists(file2))
936 self.assertEqual(os.stat(file1).st_mode, os.stat(file2).st_mode)
937
938 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
Senthil Kumaran0c2dba52011-07-03 18:21:38 -0700939 @unittest.skipUnless(hasattr(os, 'utime'), 'requires os.utime')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400940 def test_copy2(self):
941 # Ensure that the copied file exists and has the same mode and
942 # modification time bits.
943 file1, file2 = self._copy_file(shutil.copy2)
944 self.assertTrue(os.path.exists(file2))
945 file1_stat = os.stat(file1)
946 file2_stat = os.stat(file2)
947 self.assertEqual(file1_stat.st_mode, file2_stat.st_mode)
948 for attr in 'st_atime', 'st_mtime':
949 # The modification times may be truncated in the new file.
950 self.assertLessEqual(getattr(file1_stat, attr),
951 getattr(file2_stat, attr) + 1)
952 if hasattr(os, 'chflags') and hasattr(file1_stat, 'st_flags'):
953 self.assertEqual(getattr(file1_stat, 'st_flags'),
954 getattr(file2_stat, 'st_flags'))
955
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +0200956 @support.requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000957 def test_make_tarball(self):
958 # creating something to tar
Serhiy Storchaka527ef072015-09-06 18:33:19 +0300959 root_dir, base_dir = self._create_files('')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000960
961 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400962 # force shutil to create the directory
963 os.rmdir(tmpdir2)
Serhiy Storchakaeba8fee2015-09-07 19:58:23 +0300964 # working with relative paths
965 work_dir = os.path.dirname(tmpdir2)
966 rel_base_name = os.path.join(os.path.basename(tmpdir2), 'archive')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000967
Serhiy Storchakaeba8fee2015-09-07 19:58:23 +0300968 with support.change_cwd(work_dir):
Serhiy Storchaka5558d4f2015-09-08 09:59:02 +0300969 base_name = os.path.abspath(rel_base_name)
Serhiy Storchakaeba8fee2015-09-07 19:58:23 +0300970 tarball = make_archive(rel_base_name, 'gztar', root_dir, '.')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000971
972 # check if the compressed tarball was created
Serhiy Storchakaa091a822015-09-07 13:55:25 +0300973 self.assertEqual(tarball, base_name + '.tar.gz')
Serhiy Storchaka527ef072015-09-06 18:33:19 +0300974 self.assertTrue(os.path.isfile(tarball))
975 self.assertTrue(tarfile.is_tarfile(tarball))
976 with tarfile.open(tarball, 'r:gz') as tf:
977 self.assertCountEqual(tf.getnames(),
978 ['.', './sub', './sub2',
979 './file1', './file2', './sub/file3'])
Tarek Ziadé396fad72010-02-23 05:30:31 +0000980
981 # trying an uncompressed one
Serhiy Storchakaeba8fee2015-09-07 19:58:23 +0300982 with support.change_cwd(work_dir):
983 tarball = make_archive(rel_base_name, 'tar', root_dir, '.')
Serhiy Storchakaa091a822015-09-07 13:55:25 +0300984 self.assertEqual(tarball, base_name + '.tar')
Serhiy Storchaka527ef072015-09-06 18:33:19 +0300985 self.assertTrue(os.path.isfile(tarball))
986 self.assertTrue(tarfile.is_tarfile(tarball))
987 with tarfile.open(tarball, 'r') as tf:
988 self.assertCountEqual(tf.getnames(),
989 ['.', './sub', './sub2',
990 './file1', './file2', './sub/file3'])
Tarek Ziadé396fad72010-02-23 05:30:31 +0000991
992 def _tarinfo(self, path):
Serhiy Storchaka527ef072015-09-06 18:33:19 +0300993 with tarfile.open(path) as tar:
Tarek Ziadé396fad72010-02-23 05:30:31 +0000994 names = tar.getnames()
995 names.sort()
996 return tuple(names)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000997
Serhiy Storchaka527ef072015-09-06 18:33:19 +0300998 def _create_files(self, base_dir='dist'):
Tarek Ziadé396fad72010-02-23 05:30:31 +0000999 # creating something to tar
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001000 root_dir = self.mkdtemp()
1001 dist = os.path.join(root_dir, base_dir)
1002 os.makedirs(dist, exist_ok=True)
Éric Araujoa7e33a12011-08-12 19:51:35 +02001003 write_file((dist, 'file1'), 'xxx')
1004 write_file((dist, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +00001005 os.mkdir(os.path.join(dist, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +02001006 write_file((dist, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +00001007 os.mkdir(os.path.join(dist, 'sub2'))
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001008 if base_dir:
1009 write_file((root_dir, 'outer'), 'xxx')
1010 return root_dir, base_dir
Tarek Ziadé396fad72010-02-23 05:30:31 +00001011
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001012 @support.requires_zlib
Serhiy Storchakab42de2f2015-11-21 14:09:26 +02001013 @unittest.skipUnless(shutil.which('tar'),
Tarek Ziadé396fad72010-02-23 05:30:31 +00001014 'Need the tar command to run')
1015 def test_tarfile_vs_tar(self):
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001016 root_dir, base_dir = self._create_files()
1017 base_name = os.path.join(self.mkdtemp(), 'archive')
Serhiy Storchakaa091a822015-09-07 13:55:25 +03001018 tarball = make_archive(base_name, 'gztar', root_dir, base_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001019
1020 # check if the compressed tarball was created
Serhiy Storchakaa091a822015-09-07 13:55:25 +03001021 self.assertEqual(tarball, base_name + '.tar.gz')
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001022 self.assertTrue(os.path.isfile(tarball))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001023
1024 # now create another tarball using `tar`
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001025 tarball2 = os.path.join(root_dir, 'archive2.tar')
1026 tar_cmd = ['tar', '-cf', 'archive2.tar', base_dir]
Serhiy Storchakab42de2f2015-11-21 14:09:26 +02001027 subprocess.check_call(tar_cmd, cwd=root_dir,
1028 stdout=subprocess.DEVNULL)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001029
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001030 self.assertTrue(os.path.isfile(tarball2))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001031 # let's compare both tarballs
Ezio Melottib3aedd42010-11-20 19:04:17 +00001032 self.assertEqual(self._tarinfo(tarball), self._tarinfo(tarball2))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001033
1034 # trying an uncompressed one
Serhiy Storchakaa091a822015-09-07 13:55:25 +03001035 tarball = make_archive(base_name, 'tar', root_dir, base_dir)
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
1039 # now for a dry_run
Serhiy Storchakaa091a822015-09-07 13:55:25 +03001040 tarball = make_archive(base_name, 'tar', root_dir, base_dir,
1041 dry_run=True)
1042 self.assertEqual(tarball, base_name + '.tar')
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001043 self.assertTrue(os.path.isfile(tarball))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001044
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001045 @support.requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001046 def test_make_zipfile(self):
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001047 # creating something to zip
1048 root_dir, base_dir = self._create_files()
Serhiy Storchakaeba8fee2015-09-07 19:58:23 +03001049
1050 tmpdir2 = self.mkdtemp()
1051 # force shutil to create the directory
1052 os.rmdir(tmpdir2)
1053 # working with relative paths
1054 work_dir = os.path.dirname(tmpdir2)
1055 rel_base_name = os.path.join(os.path.basename(tmpdir2), 'archive')
Serhiy Storchakaeba8fee2015-09-07 19:58:23 +03001056
1057 with support.change_cwd(work_dir):
Serhiy Storchaka5558d4f2015-09-08 09:59:02 +03001058 base_name = os.path.abspath(rel_base_name)
Serhiy Storchaka666de772016-10-23 15:55:09 +03001059 res = make_archive(rel_base_name, 'zip', root_dir)
1060
1061 self.assertEqual(res, base_name + '.zip')
1062 self.assertTrue(os.path.isfile(res))
1063 self.assertTrue(zipfile.is_zipfile(res))
1064 with zipfile.ZipFile(res) as zf:
1065 self.assertCountEqual(zf.namelist(),
1066 ['dist/', 'dist/sub/', 'dist/sub2/',
1067 'dist/file1', 'dist/file2', 'dist/sub/file3',
1068 'outer'])
1069
1070 with support.change_cwd(work_dir):
1071 base_name = os.path.abspath(rel_base_name)
Serhiy Storchaka2504cec2015-09-08 05:47:23 +03001072 res = make_archive(rel_base_name, 'zip', root_dir, base_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001073
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001074 self.assertEqual(res, base_name + '.zip')
1075 self.assertTrue(os.path.isfile(res))
1076 self.assertTrue(zipfile.is_zipfile(res))
1077 with zipfile.ZipFile(res) as zf:
1078 self.assertCountEqual(zf.namelist(),
Serhiy Storchaka2504cec2015-09-08 05:47:23 +03001079 ['dist/', 'dist/sub/', 'dist/sub2/',
1080 'dist/file1', 'dist/file2', 'dist/sub/file3'])
Tarek Ziadé396fad72010-02-23 05:30:31 +00001081
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001082 @support.requires_zlib
Serhiy Storchakab42de2f2015-11-21 14:09:26 +02001083 @unittest.skipUnless(shutil.which('zip'),
Serhiy Storchaka2504cec2015-09-08 05:47:23 +03001084 'Need the zip command to run')
1085 def test_zipfile_vs_zip(self):
1086 root_dir, base_dir = self._create_files()
1087 base_name = os.path.join(self.mkdtemp(), 'archive')
1088 archive = make_archive(base_name, 'zip', root_dir, base_dir)
1089
1090 # check if ZIP file was created
1091 self.assertEqual(archive, base_name + '.zip')
1092 self.assertTrue(os.path.isfile(archive))
1093
1094 # now create another ZIP file using `zip`
1095 archive2 = os.path.join(root_dir, 'archive2.zip')
1096 zip_cmd = ['zip', '-q', '-r', 'archive2.zip', base_dir]
Serhiy Storchakab42de2f2015-11-21 14:09:26 +02001097 subprocess.check_call(zip_cmd, cwd=root_dir,
1098 stdout=subprocess.DEVNULL)
Serhiy Storchaka2504cec2015-09-08 05:47:23 +03001099
1100 self.assertTrue(os.path.isfile(archive2))
1101 # let's compare both ZIP files
1102 with zipfile.ZipFile(archive) as zf:
1103 names = zf.namelist()
1104 with zipfile.ZipFile(archive2) as zf:
1105 names2 = zf.namelist()
1106 self.assertEqual(sorted(names), sorted(names2))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001107
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001108 @support.requires_zlib
Serhiy Storchaka8bc792a2015-11-22 14:49:58 +02001109 @unittest.skipUnless(shutil.which('unzip'),
1110 'Need the unzip command to run')
1111 def test_unzip_zipfile(self):
1112 root_dir, base_dir = self._create_files()
1113 base_name = os.path.join(self.mkdtemp(), 'archive')
1114 archive = make_archive(base_name, 'zip', root_dir, base_dir)
1115
1116 # check if ZIP file was created
1117 self.assertEqual(archive, base_name + '.zip')
1118 self.assertTrue(os.path.isfile(archive))
1119
1120 # now check the ZIP file using `unzip -t`
1121 zip_cmd = ['unzip', '-t', archive]
1122 with support.change_cwd(root_dir):
1123 try:
1124 subprocess.check_output(zip_cmd, stderr=subprocess.STDOUT)
1125 except subprocess.CalledProcessError as exc:
1126 details = exc.output.decode(errors="replace")
Miss Islington (bot)1550b732018-09-13 10:27:52 -07001127 if 'unrecognized option: t' in details:
Miss Islington (bot)218b4bf2018-09-13 11:35:18 -07001128 self.skipTest("unzip doesn't support -t")
Serhiy Storchaka8bc792a2015-11-22 14:49:58 +02001129 msg = "{}\n\n**Unzip Output**\n{}"
1130 self.fail(msg.format(exc, details))
1131
Tarek Ziadé396fad72010-02-23 05:30:31 +00001132 def test_make_archive(self):
1133 tmpdir = self.mkdtemp()
1134 base_name = os.path.join(tmpdir, 'archive')
1135 self.assertRaises(ValueError, make_archive, base_name, 'xxx')
1136
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001137 @support.requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001138 def test_make_archive_owner_group(self):
1139 # testing make_archive with owner and group, with various combinations
1140 # this works even if there's not gid/uid support
1141 if UID_GID_SUPPORT:
1142 group = grp.getgrgid(0)[0]
1143 owner = pwd.getpwuid(0)[0]
1144 else:
1145 group = owner = 'root'
1146
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001147 root_dir, base_dir = self._create_files()
1148 base_name = os.path.join(self.mkdtemp(), 'archive')
Tarek Ziadé396fad72010-02-23 05:30:31 +00001149 res = make_archive(base_name, 'zip', root_dir, base_dir, owner=owner,
1150 group=group)
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001151 self.assertTrue(os.path.isfile(res))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001152
1153 res = make_archive(base_name, 'zip', root_dir, base_dir)
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001154 self.assertTrue(os.path.isfile(res))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001155
1156 res = make_archive(base_name, 'tar', root_dir, base_dir,
1157 owner=owner, group=group)
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001158 self.assertTrue(os.path.isfile(res))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001159
1160 res = make_archive(base_name, 'tar', root_dir, base_dir,
1161 owner='kjhkjhkjg', group='oihohoh')
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001162 self.assertTrue(os.path.isfile(res))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001163
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001164
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001165 @support.requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001166 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1167 def test_tarfile_root_owner(self):
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001168 root_dir, base_dir = self._create_files()
1169 base_name = os.path.join(self.mkdtemp(), 'archive')
Tarek Ziadé396fad72010-02-23 05:30:31 +00001170 group = grp.getgrgid(0)[0]
1171 owner = pwd.getpwuid(0)[0]
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001172 with support.change_cwd(root_dir):
1173 archive_name = make_archive(base_name, 'gztar', root_dir, 'dist',
1174 owner=owner, group=group)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001175
1176 # check if the compressed tarball was created
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001177 self.assertTrue(os.path.isfile(archive_name))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001178
1179 # now checks the rights
1180 archive = tarfile.open(archive_name)
1181 try:
1182 for member in archive.getmembers():
Ezio Melottib3aedd42010-11-20 19:04:17 +00001183 self.assertEqual(member.uid, 0)
1184 self.assertEqual(member.gid, 0)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001185 finally:
1186 archive.close()
1187
1188 def test_make_archive_cwd(self):
1189 current_dir = os.getcwd()
1190 def _breaks(*args, **kw):
1191 raise RuntimeError()
1192
1193 register_archive_format('xxx', _breaks, [], 'xxx file')
1194 try:
1195 try:
1196 make_archive('xxx', 'xxx', root_dir=self.mkdtemp())
1197 except Exception:
1198 pass
Ezio Melottib3aedd42010-11-20 19:04:17 +00001199 self.assertEqual(os.getcwd(), current_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001200 finally:
1201 unregister_archive_format('xxx')
1202
Serhiy Storchaka9a4fc192014-11-28 00:48:46 +02001203 def test_make_tarfile_in_curdir(self):
1204 # Issue #21280
1205 root_dir = self.mkdtemp()
1206 with support.change_cwd(root_dir):
1207 self.assertEqual(make_archive('test', 'tar'), 'test.tar')
1208 self.assertTrue(os.path.isfile('test.tar'))
1209
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001210 @support.requires_zlib
Serhiy Storchaka9a4fc192014-11-28 00:48:46 +02001211 def test_make_zipfile_in_curdir(self):
1212 # Issue #21280
1213 root_dir = self.mkdtemp()
1214 with support.change_cwd(root_dir):
1215 self.assertEqual(make_archive('test', 'zip'), 'test.zip')
1216 self.assertTrue(os.path.isfile('test.zip'))
1217
Tarek Ziadé396fad72010-02-23 05:30:31 +00001218 def test_register_archive_format(self):
1219
1220 self.assertRaises(TypeError, register_archive_format, 'xxx', 1)
1221 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1222 1)
1223 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1224 [(1, 2), (1, 2, 3)])
1225
1226 register_archive_format('xxx', lambda: x, [(1, 2)], 'xxx file')
1227 formats = [name for name, params in get_archive_formats()]
1228 self.assertIn('xxx', formats)
1229
1230 unregister_archive_format('xxx')
1231 formats = [name for name, params in get_archive_formats()]
1232 self.assertNotIn('xxx', formats)
1233
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001234 def check_unpack_archive(self, format):
Jelle Zijlstraa12df7b2017-05-05 14:27:12 -07001235 self.check_unpack_archive_with_converter(format, lambda path: path)
1236 self.check_unpack_archive_with_converter(format, pathlib.Path)
Miss Islington (bot)a13b6542018-03-02 02:17:51 -08001237 self.check_unpack_archive_with_converter(format, FakePath)
Jelle Zijlstraa12df7b2017-05-05 14:27:12 -07001238
1239 def check_unpack_archive_with_converter(self, format, converter):
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001240 root_dir, base_dir = self._create_files()
Serhiy Storchaka2504cec2015-09-08 05:47:23 +03001241 expected = rlistdir(root_dir)
1242 expected.remove('outer')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001243
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001244 base_name = os.path.join(self.mkdtemp(), 'archive')
1245 filename = make_archive(base_name, format, root_dir, base_dir)
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001246
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001247 # let's try to unpack it now
1248 tmpdir2 = self.mkdtemp()
Jelle Zijlstraa12df7b2017-05-05 14:27:12 -07001249 unpack_archive(converter(filename), converter(tmpdir2))
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001250 self.assertEqual(rlistdir(tmpdir2), expected)
1251
1252 # and again, this time with the format specified
1253 tmpdir3 = self.mkdtemp()
Jelle Zijlstraa12df7b2017-05-05 14:27:12 -07001254 unpack_archive(converter(filename), converter(tmpdir3), format=format)
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001255 self.assertEqual(rlistdir(tmpdir3), expected)
1256
Jelle Zijlstraa12df7b2017-05-05 14:27:12 -07001257 self.assertRaises(shutil.ReadError, unpack_archive, converter(TESTFN))
1258 self.assertRaises(ValueError, unpack_archive, converter(TESTFN), format='xxx')
Nick Coghlanabf202d2011-03-16 13:52:20 -04001259
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001260 def test_unpack_archive_tar(self):
1261 self.check_unpack_archive('tar')
1262
1263 @support.requires_zlib
1264 def test_unpack_archive_gztar(self):
1265 self.check_unpack_archive('gztar')
1266
1267 @support.requires_bz2
1268 def test_unpack_archive_bztar(self):
1269 self.check_unpack_archive('bztar')
1270
1271 @support.requires_lzma
1272 def test_unpack_archive_xztar(self):
1273 self.check_unpack_archive('xztar')
1274
1275 @support.requires_zlib
1276 def test_unpack_archive_zip(self):
1277 self.check_unpack_archive('zip')
1278
Martin Pantereb995702016-07-28 01:11:04 +00001279 def test_unpack_registry(self):
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001280
1281 formats = get_unpack_formats()
1282
1283 def _boo(filename, extract_dir, extra):
Ezio Melottib3aedd42010-11-20 19:04:17 +00001284 self.assertEqual(extra, 1)
1285 self.assertEqual(filename, 'stuff.boo')
1286 self.assertEqual(extract_dir, 'xx')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001287
1288 register_unpack_format('Boo', ['.boo', '.b2'], _boo, [('extra', 1)])
1289 unpack_archive('stuff.boo', 'xx')
1290
1291 # trying to register a .boo unpacker again
1292 self.assertRaises(RegistryError, register_unpack_format, 'Boo2',
1293 ['.boo'], _boo)
1294
1295 # should work now
1296 unregister_unpack_format('Boo')
1297 register_unpack_format('Boo2', ['.boo'], _boo)
1298 self.assertIn(('Boo2', ['.boo'], ''), get_unpack_formats())
1299 self.assertNotIn(('Boo', ['.boo'], ''), get_unpack_formats())
1300
1301 # let's leave a clean state
1302 unregister_unpack_format('Boo2')
Ezio Melottib3aedd42010-11-20 19:04:17 +00001303 self.assertEqual(get_unpack_formats(), formats)
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001304
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001305 @unittest.skipUnless(hasattr(shutil, 'disk_usage'),
1306 "disk_usage not available on this platform")
1307 def test_disk_usage(self):
Gregory P. Smith529746c2017-07-06 17:11:27 -07001308 usage = shutil.disk_usage(os.path.dirname(__file__))
Éric Araujo2ee61882011-07-02 16:45:45 +02001309 self.assertGreater(usage.total, 0)
1310 self.assertGreater(usage.used, 0)
1311 self.assertGreaterEqual(usage.free, 0)
1312 self.assertGreaterEqual(usage.total, usage.used)
1313 self.assertGreater(usage.total, usage.free)
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001314
Sandro Tosid902a142011-08-22 23:28:27 +02001315 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1316 @unittest.skipUnless(hasattr(os, 'chown'), 'requires os.chown')
1317 def test_chown(self):
1318
1319 # cleaned-up automatically by TestShutil.tearDown method
1320 dirname = self.mkdtemp()
1321 filename = tempfile.mktemp(dir=dirname)
1322 write_file(filename, 'testing chown function')
1323
1324 with self.assertRaises(ValueError):
1325 shutil.chown(filename)
1326
1327 with self.assertRaises(LookupError):
Raymond Hettinger15f44ab2016-08-30 10:47:49 -07001328 shutil.chown(filename, user='non-existing username')
Sandro Tosid902a142011-08-22 23:28:27 +02001329
1330 with self.assertRaises(LookupError):
Raymond Hettinger15f44ab2016-08-30 10:47:49 -07001331 shutil.chown(filename, group='non-existing groupname')
Sandro Tosid902a142011-08-22 23:28:27 +02001332
1333 with self.assertRaises(TypeError):
1334 shutil.chown(filename, b'spam')
1335
1336 with self.assertRaises(TypeError):
1337 shutil.chown(filename, 3.14)
1338
1339 uid = os.getuid()
1340 gid = os.getgid()
1341
1342 def check_chown(path, uid=None, gid=None):
1343 s = os.stat(filename)
1344 if uid is not None:
1345 self.assertEqual(uid, s.st_uid)
1346 if gid is not None:
1347 self.assertEqual(gid, s.st_gid)
1348
1349 shutil.chown(filename, uid, gid)
1350 check_chown(filename, uid, gid)
1351 shutil.chown(filename, uid)
1352 check_chown(filename, uid)
1353 shutil.chown(filename, user=uid)
1354 check_chown(filename, uid)
1355 shutil.chown(filename, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001356 check_chown(filename, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001357
1358 shutil.chown(dirname, uid, gid)
1359 check_chown(dirname, uid, gid)
1360 shutil.chown(dirname, uid)
1361 check_chown(dirname, uid)
1362 shutil.chown(dirname, user=uid)
1363 check_chown(dirname, uid)
1364 shutil.chown(dirname, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001365 check_chown(dirname, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001366
1367 user = pwd.getpwuid(uid)[0]
1368 group = grp.getgrgid(gid)[0]
1369 shutil.chown(filename, user, group)
1370 check_chown(filename, uid, gid)
1371 shutil.chown(dirname, user, group)
1372 check_chown(dirname, uid, gid)
1373
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001374 def test_copy_return_value(self):
1375 # copy and copy2 both return their destination path.
1376 for fn in (shutil.copy, shutil.copy2):
1377 src_dir = self.mkdtemp()
1378 dst_dir = self.mkdtemp()
1379 src = os.path.join(src_dir, 'foo')
1380 write_file(src, 'foo')
1381 rv = fn(src, dst_dir)
1382 self.assertEqual(rv, os.path.join(dst_dir, 'foo'))
1383 rv = fn(src, os.path.join(dst_dir, 'bar'))
1384 self.assertEqual(rv, os.path.join(dst_dir, 'bar'))
1385
1386 def test_copyfile_return_value(self):
1387 # copytree returns its destination path.
1388 src_dir = self.mkdtemp()
1389 dst_dir = self.mkdtemp()
1390 dst_file = os.path.join(dst_dir, 'bar')
1391 src_file = os.path.join(src_dir, 'foo')
1392 write_file(src_file, 'foo')
1393 rv = shutil.copyfile(src_file, dst_file)
1394 self.assertTrue(os.path.exists(rv))
1395 self.assertEqual(read_file(src_file), read_file(dst_file))
1396
Hynek Schlawack48653762012-10-07 12:49:58 +02001397 def test_copyfile_same_file(self):
1398 # copyfile() should raise SameFileError if the source and destination
1399 # are the same.
1400 src_dir = self.mkdtemp()
1401 src_file = os.path.join(src_dir, 'foo')
1402 write_file(src_file, 'foo')
1403 self.assertRaises(SameFileError, shutil.copyfile, src_file, src_file)
Hynek Schlawack27ddb572012-10-28 13:59:27 +01001404 # But Error should work too, to stay backward compatible.
1405 self.assertRaises(Error, shutil.copyfile, src_file, src_file)
Hynek Schlawack48653762012-10-07 12:49:58 +02001406
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001407 def test_copytree_return_value(self):
1408 # copytree returns its destination path.
1409 src_dir = self.mkdtemp()
1410 dst_dir = src_dir + "dest"
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001411 self.addCleanup(shutil.rmtree, dst_dir, True)
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001412 src = os.path.join(src_dir, 'foo')
1413 write_file(src, 'foo')
1414 rv = shutil.copytree(src_dir, dst_dir)
1415 self.assertEqual(['foo'], os.listdir(rv))
1416
Christian Heimes9bd667a2008-01-20 15:14:11 +00001417
Brian Curtinc57a3452012-06-22 16:00:30 -05001418class TestWhich(unittest.TestCase):
1419
1420 def setUp(self):
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001421 self.temp_dir = tempfile.mkdtemp(prefix="Tmp")
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001422 self.addCleanup(shutil.rmtree, self.temp_dir, True)
Brian Curtinc57a3452012-06-22 16:00:30 -05001423 # Give the temp_file an ".exe" suffix for all.
1424 # It's needed on Windows and not harmful on other platforms.
1425 self.temp_file = tempfile.NamedTemporaryFile(dir=self.temp_dir,
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001426 prefix="Tmp",
1427 suffix=".Exe")
Brian Curtinc57a3452012-06-22 16:00:30 -05001428 os.chmod(self.temp_file.name, stat.S_IXUSR)
1429 self.addCleanup(self.temp_file.close)
1430 self.dir, self.file = os.path.split(self.temp_file.name)
1431
1432 def test_basic(self):
1433 # Given an EXE in a directory, it should be returned.
1434 rv = shutil.which(self.file, path=self.dir)
1435 self.assertEqual(rv, self.temp_file.name)
1436
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001437 def test_absolute_cmd(self):
Brian Curtinc57a3452012-06-22 16:00:30 -05001438 # When given the fully qualified path to an executable that exists,
1439 # it should be returned.
1440 rv = shutil.which(self.temp_file.name, path=self.temp_dir)
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001441 self.assertEqual(rv, self.temp_file.name)
1442
1443 def test_relative_cmd(self):
1444 # When given the relative path with a directory part to an executable
1445 # that exists, it should be returned.
1446 base_dir, tail_dir = os.path.split(self.dir)
1447 relpath = os.path.join(tail_dir, self.file)
Nick Coghlan55175962013-07-28 22:11:50 +10001448 with support.change_cwd(path=base_dir):
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001449 rv = shutil.which(relpath, path=self.temp_dir)
1450 self.assertEqual(rv, relpath)
1451 # But it shouldn't be searched in PATH directories (issue #16957).
Nick Coghlan55175962013-07-28 22:11:50 +10001452 with support.change_cwd(path=self.dir):
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001453 rv = shutil.which(relpath, path=base_dir)
1454 self.assertIsNone(rv)
1455
1456 def test_cwd(self):
1457 # Issue #16957
1458 base_dir = os.path.dirname(self.dir)
Nick Coghlan55175962013-07-28 22:11:50 +10001459 with support.change_cwd(path=self.dir):
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001460 rv = shutil.which(self.file, path=base_dir)
1461 if sys.platform == "win32":
1462 # Windows: current directory implicitly on PATH
1463 self.assertEqual(rv, os.path.join(os.curdir, self.file))
1464 else:
1465 # Other platforms: shouldn't match in the current directory.
1466 self.assertIsNone(rv)
Brian Curtinc57a3452012-06-22 16:00:30 -05001467
Serhiy Storchaka12516e22013-05-28 15:50:15 +03001468 @unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0,
1469 'non-root user required')
Brian Curtinc57a3452012-06-22 16:00:30 -05001470 def test_non_matching_mode(self):
1471 # Set the file read-only and ask for writeable files.
1472 os.chmod(self.temp_file.name, stat.S_IREAD)
Serhiy Storchaka12516e22013-05-28 15:50:15 +03001473 if os.access(self.temp_file.name, os.W_OK):
1474 self.skipTest("can't set the file read-only")
Brian Curtinc57a3452012-06-22 16:00:30 -05001475 rv = shutil.which(self.file, path=self.dir, mode=os.W_OK)
1476 self.assertIsNone(rv)
1477
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001478 def test_relative_path(self):
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001479 base_dir, tail_dir = os.path.split(self.dir)
Nick Coghlan55175962013-07-28 22:11:50 +10001480 with support.change_cwd(path=base_dir):
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001481 rv = shutil.which(self.file, path=tail_dir)
1482 self.assertEqual(rv, os.path.join(tail_dir, self.file))
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001483
Brian Curtinc57a3452012-06-22 16:00:30 -05001484 def test_nonexistent_file(self):
1485 # Return None when no matching executable file is found on the path.
1486 rv = shutil.which("foo.exe", path=self.dir)
1487 self.assertIsNone(rv)
1488
1489 @unittest.skipUnless(sys.platform == "win32",
1490 "pathext check is Windows-only")
1491 def test_pathext_checking(self):
1492 # Ask for the file without the ".exe" extension, then ensure that
1493 # it gets found properly with the extension.
Serhiy Storchakad70127a2013-01-24 20:03:49 +02001494 rv = shutil.which(self.file[:-4], path=self.dir)
Serhiy Storchaka80c88f42013-01-22 10:31:36 +02001495 self.assertEqual(rv, self.temp_file.name[:-4] + ".EXE")
Brian Curtinc57a3452012-06-22 16:00:30 -05001496
Barry Warsaw618738b2013-04-16 11:05:03 -04001497 def test_environ_path(self):
1498 with support.EnvironmentVarGuard() as env:
Victor Stinner1d006a22013-12-16 23:39:40 +01001499 env['PATH'] = self.dir
Barry Warsaw618738b2013-04-16 11:05:03 -04001500 rv = shutil.which(self.file)
1501 self.assertEqual(rv, self.temp_file.name)
1502
1503 def test_empty_path(self):
1504 base_dir = os.path.dirname(self.dir)
Nick Coghlan55175962013-07-28 22:11:50 +10001505 with support.change_cwd(path=self.dir), \
Barry Warsaw618738b2013-04-16 11:05:03 -04001506 support.EnvironmentVarGuard() as env:
Victor Stinner1d006a22013-12-16 23:39:40 +01001507 env['PATH'] = self.dir
Barry Warsaw618738b2013-04-16 11:05:03 -04001508 rv = shutil.which(self.file, path='')
1509 self.assertIsNone(rv)
1510
1511 def test_empty_path_no_PATH(self):
1512 with support.EnvironmentVarGuard() as env:
1513 env.pop('PATH', None)
1514 rv = shutil.which(self.file)
1515 self.assertIsNone(rv)
1516
Brian Curtinc57a3452012-06-22 16:00:30 -05001517
Christian Heimesada8c3b2008-03-18 18:26:33 +00001518class TestMove(unittest.TestCase):
1519
1520 def setUp(self):
1521 filename = "foo"
1522 self.src_dir = tempfile.mkdtemp()
1523 self.dst_dir = tempfile.mkdtemp()
1524 self.src_file = os.path.join(self.src_dir, filename)
1525 self.dst_file = os.path.join(self.dst_dir, filename)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001526 with open(self.src_file, "wb") as f:
1527 f.write(b"spam")
1528
1529 def tearDown(self):
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001530 for d in (self.src_dir, self.dst_dir):
Christian Heimesada8c3b2008-03-18 18:26:33 +00001531 try:
1532 if d:
1533 shutil.rmtree(d)
1534 except:
1535 pass
1536
1537 def _check_move_file(self, src, dst, real_dst):
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001538 with open(src, "rb") as f:
1539 contents = f.read()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001540 shutil.move(src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001541 with open(real_dst, "rb") as f:
1542 self.assertEqual(contents, f.read())
Christian Heimesada8c3b2008-03-18 18:26:33 +00001543 self.assertFalse(os.path.exists(src))
1544
1545 def _check_move_dir(self, src, dst, real_dst):
1546 contents = sorted(os.listdir(src))
1547 shutil.move(src, dst)
1548 self.assertEqual(contents, sorted(os.listdir(real_dst)))
1549 self.assertFalse(os.path.exists(src))
1550
1551 def test_move_file(self):
1552 # Move a file to another location on the same filesystem.
1553 self._check_move_file(self.src_file, self.dst_file, self.dst_file)
1554
1555 def test_move_file_to_dir(self):
1556 # Move a file inside an existing dir on the same filesystem.
1557 self._check_move_file(self.src_file, self.dst_dir, self.dst_file)
1558
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001559 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001560 def test_move_file_other_fs(self):
1561 # Move a file to an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001562 self.test_move_file()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001563
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001564 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001565 def test_move_file_to_dir_other_fs(self):
1566 # Move a file to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001567 self.test_move_file_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001568
1569 def test_move_dir(self):
1570 # Move a dir to another location on the same filesystem.
1571 dst_dir = tempfile.mktemp()
1572 try:
1573 self._check_move_dir(self.src_dir, dst_dir, dst_dir)
1574 finally:
1575 try:
1576 shutil.rmtree(dst_dir)
1577 except:
1578 pass
1579
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001580 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001581 def test_move_dir_other_fs(self):
1582 # Move a dir to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001583 self.test_move_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001584
1585 def test_move_dir_to_dir(self):
1586 # Move a dir inside an existing dir on the same filesystem.
1587 self._check_move_dir(self.src_dir, self.dst_dir,
1588 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1589
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001590 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001591 def test_move_dir_to_dir_other_fs(self):
1592 # Move a dir inside an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001593 self.test_move_dir_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001594
Serhiy Storchaka3a308b92014-02-11 10:30:59 +02001595 def test_move_dir_sep_to_dir(self):
1596 self._check_move_dir(self.src_dir + os.path.sep, self.dst_dir,
1597 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1598
1599 @unittest.skipUnless(os.path.altsep, 'requires os.path.altsep')
1600 def test_move_dir_altsep_to_dir(self):
1601 self._check_move_dir(self.src_dir + os.path.altsep, self.dst_dir,
1602 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1603
Christian Heimesada8c3b2008-03-18 18:26:33 +00001604 def test_existing_file_inside_dest_dir(self):
1605 # A file with the same name inside the destination dir already exists.
1606 with open(self.dst_file, "wb"):
1607 pass
1608 self.assertRaises(shutil.Error, shutil.move, self.src_file, self.dst_dir)
1609
1610 def test_dont_move_dir_in_itself(self):
1611 # Moving a dir inside itself raises an Error.
1612 dst = os.path.join(self.src_dir, "bar")
1613 self.assertRaises(shutil.Error, shutil.move, self.src_dir, dst)
1614
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001615 def test_destinsrc_false_negative(self):
1616 os.mkdir(TESTFN)
1617 try:
1618 for src, dst in [('srcdir', 'srcdir/dest')]:
1619 src = os.path.join(TESTFN, src)
1620 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001621 self.assertTrue(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001622 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001623 'dst (%s) is not in src (%s)' % (dst, src))
1624 finally:
1625 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001626
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001627 def test_destinsrc_false_positive(self):
1628 os.mkdir(TESTFN)
1629 try:
1630 for src, dst in [('srcdir', 'src/dest'), ('srcdir', 'srcdir.new')]:
1631 src = os.path.join(TESTFN, src)
1632 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001633 self.assertFalse(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001634 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001635 'dst (%s) is in src (%s)' % (dst, src))
1636 finally:
1637 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimes9bd667a2008-01-20 15:14:11 +00001638
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +01001639 @support.skip_unless_symlink
1640 @mock_rename
1641 def test_move_file_symlink(self):
1642 dst = os.path.join(self.src_dir, 'bar')
1643 os.symlink(self.src_file, dst)
1644 shutil.move(dst, self.dst_file)
1645 self.assertTrue(os.path.islink(self.dst_file))
1646 self.assertTrue(os.path.samefile(self.src_file, self.dst_file))
1647
1648 @support.skip_unless_symlink
1649 @mock_rename
1650 def test_move_file_symlink_to_dir(self):
1651 filename = "bar"
1652 dst = os.path.join(self.src_dir, filename)
1653 os.symlink(self.src_file, dst)
1654 shutil.move(dst, self.dst_dir)
1655 final_link = os.path.join(self.dst_dir, filename)
1656 self.assertTrue(os.path.islink(final_link))
1657 self.assertTrue(os.path.samefile(self.src_file, final_link))
1658
1659 @support.skip_unless_symlink
1660 @mock_rename
1661 def test_move_dangling_symlink(self):
1662 src = os.path.join(self.src_dir, 'baz')
1663 dst = os.path.join(self.src_dir, 'bar')
1664 os.symlink(src, dst)
1665 dst_link = os.path.join(self.dst_dir, 'quux')
1666 shutil.move(dst, dst_link)
1667 self.assertTrue(os.path.islink(dst_link))
Antoine Pitrou3f48ac92014-01-01 02:50:45 +01001668 # On Windows, os.path.realpath does not follow symlinks (issue #9949)
1669 if os.name == 'nt':
1670 self.assertEqual(os.path.realpath(src), os.readlink(dst_link))
1671 else:
1672 self.assertEqual(os.path.realpath(src), os.path.realpath(dst_link))
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +01001673
1674 @support.skip_unless_symlink
1675 @mock_rename
1676 def test_move_dir_symlink(self):
1677 src = os.path.join(self.src_dir, 'baz')
1678 dst = os.path.join(self.src_dir, 'bar')
1679 os.mkdir(src)
1680 os.symlink(src, dst)
1681 dst_link = os.path.join(self.dst_dir, 'quux')
1682 shutil.move(dst, dst_link)
1683 self.assertTrue(os.path.islink(dst_link))
1684 self.assertTrue(os.path.samefile(src, dst_link))
1685
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001686 def test_move_return_value(self):
1687 rv = shutil.move(self.src_file, self.dst_dir)
1688 self.assertEqual(rv,
1689 os.path.join(self.dst_dir, os.path.basename(self.src_file)))
1690
1691 def test_move_as_rename_return_value(self):
1692 rv = shutil.move(self.src_file, os.path.join(self.dst_dir, 'bar'))
1693 self.assertEqual(rv, os.path.join(self.dst_dir, 'bar'))
1694
R David Murray6ffface2014-06-11 14:40:13 -04001695 @mock_rename
1696 def test_move_file_special_function(self):
1697 moved = []
1698 def _copy(src, dst):
1699 moved.append((src, dst))
1700 shutil.move(self.src_file, self.dst_dir, copy_function=_copy)
1701 self.assertEqual(len(moved), 1)
1702
1703 @mock_rename
1704 def test_move_dir_special_function(self):
1705 moved = []
1706 def _copy(src, dst):
1707 moved.append((src, dst))
1708 support.create_empty_file(os.path.join(self.src_dir, 'child'))
1709 support.create_empty_file(os.path.join(self.src_dir, 'child1'))
1710 shutil.move(self.src_dir, self.dst_dir, copy_function=_copy)
1711 self.assertEqual(len(moved), 3)
1712
Tarek Ziadé5340db32010-04-19 22:30:51 +00001713
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001714class TestCopyFile(unittest.TestCase):
1715
1716 _delete = False
1717
1718 class Faux(object):
1719 _entered = False
1720 _exited_with = None
1721 _raised = False
1722 def __init__(self, raise_in_exit=False, suppress_at_exit=True):
1723 self._raise_in_exit = raise_in_exit
1724 self._suppress_at_exit = suppress_at_exit
1725 def read(self, *args):
1726 return ''
1727 def __enter__(self):
1728 self._entered = True
1729 def __exit__(self, exc_type, exc_val, exc_tb):
1730 self._exited_with = exc_type, exc_val, exc_tb
1731 if self._raise_in_exit:
1732 self._raised = True
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001733 raise OSError("Cannot close")
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001734 return self._suppress_at_exit
1735
1736 def tearDown(self):
1737 if self._delete:
1738 del shutil.open
1739
1740 def _set_shutil_open(self, func):
1741 shutil.open = func
1742 self._delete = True
1743
1744 def test_w_source_open_fails(self):
1745 def _open(filename, mode='r'):
1746 if filename == 'srcfile':
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001747 raise OSError('Cannot open "srcfile"')
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001748 assert 0 # shouldn't reach here.
1749
1750 self._set_shutil_open(_open)
1751
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001752 self.assertRaises(OSError, shutil.copyfile, 'srcfile', 'destfile')
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001753
1754 def test_w_dest_open_fails(self):
1755
1756 srcfile = self.Faux()
1757
1758 def _open(filename, mode='r'):
1759 if filename == 'srcfile':
1760 return srcfile
1761 if filename == 'destfile':
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001762 raise OSError('Cannot open "destfile"')
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001763 assert 0 # shouldn't reach here.
1764
1765 self._set_shutil_open(_open)
1766
1767 shutil.copyfile('srcfile', 'destfile')
1768 self.assertTrue(srcfile._entered)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001769 self.assertTrue(srcfile._exited_with[0] is OSError)
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001770 self.assertEqual(srcfile._exited_with[1].args,
1771 ('Cannot open "destfile"',))
1772
1773 def test_w_dest_close_fails(self):
1774
1775 srcfile = self.Faux()
1776 destfile = self.Faux(True)
1777
1778 def _open(filename, mode='r'):
1779 if filename == 'srcfile':
1780 return srcfile
1781 if filename == 'destfile':
1782 return destfile
1783 assert 0 # shouldn't reach here.
1784
1785 self._set_shutil_open(_open)
1786
1787 shutil.copyfile('srcfile', 'destfile')
1788 self.assertTrue(srcfile._entered)
1789 self.assertTrue(destfile._entered)
1790 self.assertTrue(destfile._raised)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001791 self.assertTrue(srcfile._exited_with[0] is OSError)
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001792 self.assertEqual(srcfile._exited_with[1].args,
1793 ('Cannot close',))
1794
1795 def test_w_source_close_fails(self):
1796
1797 srcfile = self.Faux(True)
1798 destfile = self.Faux()
1799
1800 def _open(filename, mode='r'):
1801 if filename == 'srcfile':
1802 return srcfile
1803 if filename == 'destfile':
1804 return destfile
1805 assert 0 # shouldn't reach here.
1806
1807 self._set_shutil_open(_open)
1808
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001809 self.assertRaises(OSError,
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001810 shutil.copyfile, 'srcfile', 'destfile')
1811 self.assertTrue(srcfile._entered)
1812 self.assertTrue(destfile._entered)
1813 self.assertFalse(destfile._raised)
1814 self.assertTrue(srcfile._exited_with[0] is None)
1815 self.assertTrue(srcfile._raised)
1816
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001817 def test_move_dir_caseinsensitive(self):
1818 # Renames a folder to the same name
1819 # but a different case.
1820
1821 self.src_dir = tempfile.mkdtemp()
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001822 self.addCleanup(shutil.rmtree, self.src_dir, True)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001823 dst_dir = os.path.join(
1824 os.path.dirname(self.src_dir),
1825 os.path.basename(self.src_dir).upper())
1826 self.assertNotEqual(self.src_dir, dst_dir)
1827
1828 try:
1829 shutil.move(self.src_dir, dst_dir)
1830 self.assertTrue(os.path.isdir(dst_dir))
1831 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +02001832 os.rmdir(dst_dir)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001833
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001834class TermsizeTests(unittest.TestCase):
1835 def test_does_not_crash(self):
1836 """Check if get_terminal_size() returns a meaningful value.
1837
1838 There's no easy portable way to actually check the size of the
1839 terminal, so let's check if it returns something sensible instead.
1840 """
1841 size = shutil.get_terminal_size()
Antoine Pitroucfade362012-02-08 23:48:59 +01001842 self.assertGreaterEqual(size.columns, 0)
1843 self.assertGreaterEqual(size.lines, 0)
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001844
1845 def test_os_environ_first(self):
1846 "Check if environment variables have precedence"
1847
1848 with support.EnvironmentVarGuard() as env:
1849 env['COLUMNS'] = '777'
Serhiy Storchakad30829d2016-04-24 09:58:43 +03001850 del env['LINES']
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001851 size = shutil.get_terminal_size()
1852 self.assertEqual(size.columns, 777)
1853
1854 with support.EnvironmentVarGuard() as env:
Serhiy Storchakad30829d2016-04-24 09:58:43 +03001855 del env['COLUMNS']
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001856 env['LINES'] = '888'
1857 size = shutil.get_terminal_size()
1858 self.assertEqual(size.lines, 888)
1859
Serhiy Storchakad30829d2016-04-24 09:58:43 +03001860 def test_bad_environ(self):
1861 with support.EnvironmentVarGuard() as env:
1862 env['COLUMNS'] = 'xxx'
1863 env['LINES'] = 'yyy'
1864 size = shutil.get_terminal_size()
1865 self.assertGreaterEqual(size.columns, 0)
1866 self.assertGreaterEqual(size.lines, 0)
1867
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001868 @unittest.skipUnless(os.isatty(sys.__stdout__.fileno()), "not on tty")
Victor Stinner119ebb72016-04-19 22:24:56 +02001869 @unittest.skipUnless(hasattr(os, 'get_terminal_size'),
1870 'need os.get_terminal_size()')
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001871 def test_stty_match(self):
1872 """Check if stty returns the same results ignoring env
1873
1874 This test will fail if stdin and stdout are connected to
1875 different terminals with different sizes. Nevertheless, such
1876 situations should be pretty rare.
1877 """
1878 try:
1879 size = subprocess.check_output(['stty', 'size']).decode().split()
Xavier de Gaye38c8b7d2016-11-14 17:14:42 +01001880 except (FileNotFoundError, PermissionError,
1881 subprocess.CalledProcessError):
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001882 self.skipTest("stty invocation failed")
1883 expected = (int(size[1]), int(size[0])) # reversed order
1884
1885 with support.EnvironmentVarGuard() as env:
1886 del env['LINES']
1887 del env['COLUMNS']
1888 actual = shutil.get_terminal_size()
1889
1890 self.assertEqual(expected, actual)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001891
Serhiy Storchakad30829d2016-04-24 09:58:43 +03001892 def test_fallback(self):
1893 with support.EnvironmentVarGuard() as env:
1894 del env['LINES']
1895 del env['COLUMNS']
1896
1897 # sys.__stdout__ has no fileno()
1898 with support.swap_attr(sys, '__stdout__', None):
1899 size = shutil.get_terminal_size(fallback=(10, 20))
1900 self.assertEqual(size.columns, 10)
1901 self.assertEqual(size.lines, 20)
1902
1903 # sys.__stdout__ is not a terminal on Unix
1904 # or fileno() not in (0, 1, 2) on Windows
1905 with open(os.devnull, 'w') as f, \
1906 support.swap_attr(sys, '__stdout__', f):
1907 size = shutil.get_terminal_size(fallback=(30, 40))
1908 self.assertEqual(size.columns, 30)
1909 self.assertEqual(size.lines, 40)
1910
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001911
Berker Peksag8083cd62014-11-01 11:04:06 +02001912class PublicAPITests(unittest.TestCase):
1913 """Ensures that the correct values are exposed in the public API."""
1914
1915 def test_module_all_attribute(self):
1916 self.assertTrue(hasattr(shutil, '__all__'))
1917 target_api = ['copyfileobj', 'copyfile', 'copymode', 'copystat',
1918 'copy', 'copy2', 'copytree', 'move', 'rmtree', 'Error',
1919 'SpecialFileError', 'ExecError', 'make_archive',
1920 'get_archive_formats', 'register_archive_format',
1921 'unregister_archive_format', 'get_unpack_formats',
1922 'register_unpack_format', 'unregister_unpack_format',
1923 'unpack_archive', 'ignore_patterns', 'chown', 'which',
1924 'get_terminal_size', 'SameFileError']
1925 if hasattr(os, 'statvfs') or os.name == 'nt':
1926 target_api.append('disk_usage')
1927 self.assertEqual(set(shutil.__all__), set(target_api))
1928
1929
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001930if __name__ == '__main__':
Brett Cannon3e9a9ae2013-06-12 21:25:59 -04001931 unittest.main()