blob: 46e2c57746d2887050133bebe0615c0d185d8f83 [file] [log] [blame]
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001# Copyright (C) 2003 Python Software Foundation
2
3import unittest
Berker Peksag884afd92014-12-10 02:50:32 +02004import unittest.mock
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00005import shutil
6import tempfile
Johannes Gijsbers8e6f2de2004-11-23 09:27:27 +00007import sys
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +00008import stat
Brett Cannon1c3fa182004-06-19 21:11:35 +00009import os
10import os.path
Antoine Pitrouc041ab62012-01-02 19:18:02 +010011import errno
Nick Coghlan8ed3cf32011-03-16 14:05:35 -040012import functools
Antoine Pitroubcf2b592012-02-08 23:28:36 +010013import subprocess
Serhiy Storchaka41ad77c2014-08-07 19:38:37 +030014from contextlib import ExitStack
Serhiy Storchaka527ef072015-09-06 18:33:19 +030015from shutil import (make_archive,
Tarek Ziadé396fad72010-02-23 05:30:31 +000016 register_archive_format, unregister_archive_format,
Tarek Ziadé6ac91722010-04-28 17:51:36 +000017 get_archive_formats, Error, unpack_archive,
18 register_unpack_format, RegistryError,
Hynek Schlawack48653762012-10-07 12:49:58 +020019 unregister_unpack_format, get_unpack_formats,
20 SameFileError)
Tarek Ziadé396fad72010-02-23 05:30:31 +000021import tarfile
22import warnings
23
24from test import support
Xavier de Gaye3a4e9892016-12-13 10:00:01 +010025from test.support import (TESTFN, check_warnings, captured_stdout,
26 requires_zlib, android_not_root)
Tarek Ziadé396fad72010-02-23 05:30:31 +000027
Tarek Ziadéffa155a2010-04-29 13:34:35 +000028try:
29 import bz2
30 BZ2_SUPPORTED = True
31except ImportError:
32 BZ2_SUPPORTED = False
33
Serhiy Storchaka11213772014-08-06 18:50:19 +030034try:
35 import lzma
36 LZMA_SUPPORTED = True
37except ImportError:
38 LZMA_SUPPORTED = False
39
Antoine Pitrou7fff0962009-05-01 21:09:44 +000040TESTFN2 = TESTFN + "2"
Barry Warsaw7fc2cca2003-01-24 17:34:13 +000041
Tarek Ziadé396fad72010-02-23 05:30:31 +000042try:
43 import grp
44 import pwd
45 UID_GID_SUPPORT = True
46except ImportError:
47 UID_GID_SUPPORT = False
48
49try:
Tarek Ziadé396fad72010-02-23 05:30:31 +000050 import zipfile
51 ZIP_SUPPORT = True
52except ImportError:
Serhiy Storchakab42de2f2015-11-21 14:09:26 +020053 ZIP_SUPPORT = shutil.which('zip')
Tarek Ziadé396fad72010-02-23 05:30:31 +000054
Nick Coghlan8ed3cf32011-03-16 14:05:35 -040055def _fake_rename(*args, **kwargs):
56 # Pretend the destination path is on a different filesystem.
Antoine Pitrouc041ab62012-01-02 19:18:02 +010057 raise OSError(getattr(errno, 'EXDEV', 18), "Invalid cross-device link")
Nick Coghlan8ed3cf32011-03-16 14:05:35 -040058
59def mock_rename(func):
60 @functools.wraps(func)
61 def wrap(*args, **kwargs):
62 try:
63 builtin_rename = os.rename
64 os.rename = _fake_rename
65 return func(*args, **kwargs)
66 finally:
67 os.rename = builtin_rename
68 return wrap
69
Éric Araujoa7e33a12011-08-12 19:51:35 +020070def write_file(path, content, binary=False):
71 """Write *content* to a file located at *path*.
72
73 If *path* is a tuple instead of a string, os.path.join will be used to
74 make a path. If *binary* is true, the file will be opened in binary
75 mode.
76 """
77 if isinstance(path, tuple):
78 path = os.path.join(*path)
79 with open(path, 'wb' if binary else 'w') as fp:
80 fp.write(content)
81
82def read_file(path, binary=False):
83 """Return contents from a file located at *path*.
84
85 If *path* is a tuple instead of a string, os.path.join will be used to
86 make a path. If *binary* is true, the file will be opened in binary
87 mode.
88 """
89 if isinstance(path, tuple):
90 path = os.path.join(*path)
91 with open(path, 'rb' if binary else 'r') as fp:
92 return fp.read()
93
Serhiy Storchaka527ef072015-09-06 18:33:19 +030094def rlistdir(path):
95 res = []
96 for name in sorted(os.listdir(path)):
97 p = os.path.join(path, name)
98 if os.path.isdir(p) and not os.path.islink(p):
99 res.append(name + '/')
100 for n in rlistdir(p):
101 res.append(name + '/' + n)
102 else:
103 res.append(name)
104 return res
105
Éric Araujoa7e33a12011-08-12 19:51:35 +0200106
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000107class TestShutil(unittest.TestCase):
Tarek Ziadé396fad72010-02-23 05:30:31 +0000108
109 def setUp(self):
110 super(TestShutil, self).setUp()
111 self.tempdirs = []
112
113 def tearDown(self):
114 super(TestShutil, self).tearDown()
115 while self.tempdirs:
116 d = self.tempdirs.pop()
117 shutil.rmtree(d, os.name in ('nt', 'cygwin'))
118
Tarek Ziadé396fad72010-02-23 05:30:31 +0000119
120 def mkdtemp(self):
121 """Create a temporary directory that will be cleaned up.
122
123 Returns the path of the directory.
124 """
125 d = tempfile.mkdtemp()
126 self.tempdirs.append(d)
127 return d
Tarek Ziadé5340db32010-04-19 22:30:51 +0000128
Hynek Schlawack3b527782012-06-25 13:27:31 +0200129 def test_rmtree_works_on_bytes(self):
130 tmp = self.mkdtemp()
131 victim = os.path.join(tmp, 'killme')
132 os.mkdir(victim)
133 write_file(os.path.join(victim, 'somefile'), 'foo')
134 victim = os.fsencode(victim)
135 self.assertIsInstance(victim, bytes)
Steve Dowere58571b2016-09-08 11:11:13 -0700136 shutil.rmtree(victim)
Hynek Schlawack3b527782012-06-25 13:27:31 +0200137
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200138 @support.skip_unless_symlink
139 def test_rmtree_fails_on_symlink(self):
140 tmp = self.mkdtemp()
141 dir_ = os.path.join(tmp, 'dir')
142 os.mkdir(dir_)
143 link = os.path.join(tmp, 'link')
144 os.symlink(dir_, link)
145 self.assertRaises(OSError, shutil.rmtree, link)
146 self.assertTrue(os.path.exists(dir_))
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100147 self.assertTrue(os.path.lexists(link))
148 errors = []
149 def onerror(*args):
150 errors.append(args)
151 shutil.rmtree(link, onerror=onerror)
152 self.assertEqual(len(errors), 1)
153 self.assertIs(errors[0][0], os.path.islink)
154 self.assertEqual(errors[0][1], link)
155 self.assertIsInstance(errors[0][2][1], OSError)
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200156
157 @support.skip_unless_symlink
158 def test_rmtree_works_on_symlinks(self):
159 tmp = self.mkdtemp()
160 dir1 = os.path.join(tmp, 'dir1')
161 dir2 = os.path.join(dir1, 'dir2')
162 dir3 = os.path.join(tmp, 'dir3')
163 for d in dir1, dir2, dir3:
164 os.mkdir(d)
165 file1 = os.path.join(tmp, 'file1')
166 write_file(file1, 'foo')
167 link1 = os.path.join(dir1, 'link1')
168 os.symlink(dir2, link1)
169 link2 = os.path.join(dir1, 'link2')
170 os.symlink(dir3, link2)
171 link3 = os.path.join(dir1, 'link3')
172 os.symlink(file1, link3)
173 # make sure symlinks are removed but not followed
174 shutil.rmtree(dir1)
175 self.assertFalse(os.path.exists(dir1))
176 self.assertTrue(os.path.exists(dir3))
177 self.assertTrue(os.path.exists(file1))
178
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000179 def test_rmtree_errors(self):
180 # filename is guaranteed not to exist
181 filename = tempfile.mktemp()
Hynek Schlawackb5501102012-12-10 09:11:25 +0100182 self.assertRaises(FileNotFoundError, shutil.rmtree, filename)
183 # test that ignore_errors option is honored
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100184 shutil.rmtree(filename, ignore_errors=True)
185
186 # existing file
187 tmpdir = self.mkdtemp()
Hynek Schlawackb5501102012-12-10 09:11:25 +0100188 write_file((tmpdir, "tstfile"), "")
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100189 filename = os.path.join(tmpdir, "tstfile")
Hynek Schlawackb5501102012-12-10 09:11:25 +0100190 with self.assertRaises(NotADirectoryError) as cm:
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100191 shutil.rmtree(filename)
Hynek Schlawack87f9b462012-12-10 16:29:57 +0100192 # The reason for this rather odd construct is that Windows sprinkles
193 # a \*.* at the end of file names. But only sometimes on some buildbots
194 possible_args = [filename, os.path.join(filename, '*.*')]
195 self.assertIn(cm.exception.filename, possible_args)
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100196 self.assertTrue(os.path.exists(filename))
Hynek Schlawackb5501102012-12-10 09:11:25 +0100197 # test that ignore_errors option is honored
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100198 shutil.rmtree(filename, ignore_errors=True)
199 self.assertTrue(os.path.exists(filename))
200 errors = []
201 def onerror(*args):
202 errors.append(args)
203 shutil.rmtree(filename, onerror=onerror)
204 self.assertEqual(len(errors), 2)
205 self.assertIs(errors[0][0], os.listdir)
206 self.assertEqual(errors[0][1], filename)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100207 self.assertIsInstance(errors[0][2][1], NotADirectoryError)
Hynek Schlawack87f9b462012-12-10 16:29:57 +0100208 self.assertIn(errors[0][2][1].filename, possible_args)
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100209 self.assertIs(errors[1][0], os.rmdir)
210 self.assertEqual(errors[1][1], filename)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100211 self.assertIsInstance(errors[1][2][1], NotADirectoryError)
Hynek Schlawack87f9b462012-12-10 16:29:57 +0100212 self.assertIn(errors[1][2][1].filename, possible_args)
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000213
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000214
Serhiy Storchaka43767632013-11-03 21:31:38 +0200215 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod()')
216 @unittest.skipIf(sys.platform[:6] == 'cygwin',
217 "This test can't be run on Cygwin (issue #1071513).")
218 @unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0,
219 "This test can't be run reliably as root (issue #1076467).")
220 def test_on_error(self):
221 self.errorState = 0
222 os.mkdir(TESTFN)
223 self.addCleanup(shutil.rmtree, TESTFN)
Antoine Pitrou2f8a75c2012-06-23 21:28:15 +0200224
Serhiy Storchaka43767632013-11-03 21:31:38 +0200225 self.child_file_path = os.path.join(TESTFN, 'a')
226 self.child_dir_path = os.path.join(TESTFN, 'b')
227 support.create_empty_file(self.child_file_path)
228 os.mkdir(self.child_dir_path)
229 old_dir_mode = os.stat(TESTFN).st_mode
230 old_child_file_mode = os.stat(self.child_file_path).st_mode
231 old_child_dir_mode = os.stat(self.child_dir_path).st_mode
232 # Make unwritable.
233 new_mode = stat.S_IREAD|stat.S_IEXEC
234 os.chmod(self.child_file_path, new_mode)
235 os.chmod(self.child_dir_path, new_mode)
236 os.chmod(TESTFN, new_mode)
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000237
Serhiy Storchaka43767632013-11-03 21:31:38 +0200238 self.addCleanup(os.chmod, TESTFN, old_dir_mode)
239 self.addCleanup(os.chmod, self.child_file_path, old_child_file_mode)
240 self.addCleanup(os.chmod, self.child_dir_path, old_child_dir_mode)
Antoine Pitrou2f8a75c2012-06-23 21:28:15 +0200241
Serhiy Storchaka43767632013-11-03 21:31:38 +0200242 shutil.rmtree(TESTFN, onerror=self.check_args_to_onerror)
243 # Test whether onerror has actually been called.
244 self.assertEqual(self.errorState, 3,
245 "Expected call to onerror function did not happen.")
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000246
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000247 def check_args_to_onerror(self, func, arg, exc):
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000248 # test_rmtree_errors deliberately runs rmtree
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200249 # on a directory that is chmod 500, which will fail.
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000250 # This function is run when shutil.rmtree fails.
251 # 99.9% of the time it initially fails to remove
252 # a file in the directory, so the first time through
253 # func is os.remove.
254 # However, some Linux machines running ZFS on
255 # FUSE experienced a failure earlier in the process
256 # at os.listdir. The first failure may legally
257 # be either.
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200258 if self.errorState < 2:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200259 if func is os.unlink:
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200260 self.assertEqual(arg, self.child_file_path)
261 elif func is os.rmdir:
262 self.assertEqual(arg, self.child_dir_path)
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000263 else:
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200264 self.assertIs(func, os.listdir)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200265 self.assertIn(arg, [TESTFN, self.child_dir_path])
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000266 self.assertTrue(issubclass(exc[0], OSError))
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200267 self.errorState += 1
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000268 else:
269 self.assertEqual(func, os.rmdir)
270 self.assertEqual(arg, TESTFN)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000271 self.assertTrue(issubclass(exc[0], OSError))
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200272 self.errorState = 3
273
274 def test_rmtree_does_not_choke_on_failing_lstat(self):
275 try:
276 orig_lstat = os.lstat
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200277 def raiser(fn, *args, **kwargs):
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200278 if fn != TESTFN:
279 raise OSError()
280 else:
281 return orig_lstat(fn)
282 os.lstat = raiser
283
284 os.mkdir(TESTFN)
285 write_file((TESTFN, 'foo'), 'foo')
286 shutil.rmtree(TESTFN)
287 finally:
288 os.lstat = orig_lstat
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000289
Antoine Pitrou78091e62011-12-29 18:54:15 +0100290 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
291 @support.skip_unless_symlink
292 def test_copymode_follow_symlinks(self):
293 tmp_dir = self.mkdtemp()
294 src = os.path.join(tmp_dir, 'foo')
295 dst = os.path.join(tmp_dir, 'bar')
296 src_link = os.path.join(tmp_dir, 'baz')
297 dst_link = os.path.join(tmp_dir, 'quux')
298 write_file(src, 'foo')
299 write_file(dst, 'foo')
300 os.symlink(src, src_link)
301 os.symlink(dst, dst_link)
302 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
303 # file to file
304 os.chmod(dst, stat.S_IRWXO)
305 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
306 shutil.copymode(src, dst)
307 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
Antoine Pitrou3f48ac92014-01-01 02:50:45 +0100308 # On Windows, os.chmod does not follow symlinks (issue #15411)
309 if os.name != 'nt':
310 # follow src link
311 os.chmod(dst, stat.S_IRWXO)
312 shutil.copymode(src_link, dst)
313 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
314 # follow dst link
315 os.chmod(dst, stat.S_IRWXO)
316 shutil.copymode(src, dst_link)
317 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
318 # follow both links
319 os.chmod(dst, stat.S_IRWXO)
320 shutil.copymode(src_link, dst_link)
321 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100322
323 @unittest.skipUnless(hasattr(os, 'lchmod'), 'requires os.lchmod')
324 @support.skip_unless_symlink
325 def test_copymode_symlink_to_symlink(self):
326 tmp_dir = self.mkdtemp()
327 src = os.path.join(tmp_dir, 'foo')
328 dst = os.path.join(tmp_dir, 'bar')
329 src_link = os.path.join(tmp_dir, 'baz')
330 dst_link = os.path.join(tmp_dir, 'quux')
331 write_file(src, 'foo')
332 write_file(dst, 'foo')
333 os.symlink(src, src_link)
334 os.symlink(dst, dst_link)
335 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
336 os.chmod(dst, stat.S_IRWXU)
337 os.lchmod(src_link, stat.S_IRWXO|stat.S_IRWXG)
338 # link to link
339 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700340 shutil.copymode(src_link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100341 self.assertEqual(os.lstat(src_link).st_mode,
342 os.lstat(dst_link).st_mode)
343 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
344 # src link - use chmod
345 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700346 shutil.copymode(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100347 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
348 # dst link - use chmod
349 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700350 shutil.copymode(src, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100351 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
352
353 @unittest.skipIf(hasattr(os, 'lchmod'), 'requires os.lchmod to be missing')
354 @support.skip_unless_symlink
355 def test_copymode_symlink_to_symlink_wo_lchmod(self):
356 tmp_dir = self.mkdtemp()
357 src = os.path.join(tmp_dir, 'foo')
358 dst = os.path.join(tmp_dir, 'bar')
359 src_link = os.path.join(tmp_dir, 'baz')
360 dst_link = os.path.join(tmp_dir, 'quux')
361 write_file(src, 'foo')
362 write_file(dst, 'foo')
363 os.symlink(src, src_link)
364 os.symlink(dst, dst_link)
Larry Hastingsb4038062012-07-15 10:57:38 -0700365 shutil.copymode(src_link, dst_link, follow_symlinks=False) # silent fail
Antoine Pitrou78091e62011-12-29 18:54:15 +0100366
367 @support.skip_unless_symlink
368 def test_copystat_symlinks(self):
369 tmp_dir = self.mkdtemp()
370 src = os.path.join(tmp_dir, 'foo')
371 dst = os.path.join(tmp_dir, 'bar')
372 src_link = os.path.join(tmp_dir, 'baz')
373 dst_link = os.path.join(tmp_dir, 'qux')
374 write_file(src, 'foo')
375 src_stat = os.stat(src)
376 os.utime(src, (src_stat.st_atime,
377 src_stat.st_mtime - 42.0)) # ensure different mtimes
378 write_file(dst, 'bar')
379 self.assertNotEqual(os.stat(src).st_mtime, os.stat(dst).st_mtime)
380 os.symlink(src, src_link)
381 os.symlink(dst, dst_link)
382 if hasattr(os, 'lchmod'):
383 os.lchmod(src_link, stat.S_IRWXO)
384 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
385 os.lchflags(src_link, stat.UF_NODUMP)
386 src_link_stat = os.lstat(src_link)
387 # follow
388 if hasattr(os, 'lchmod'):
Larry Hastingsb4038062012-07-15 10:57:38 -0700389 shutil.copystat(src_link, dst_link, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100390 self.assertNotEqual(src_link_stat.st_mode, os.stat(dst).st_mode)
391 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700392 shutil.copystat(src_link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100393 dst_link_stat = os.lstat(dst_link)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700394 if os.utime in os.supports_follow_symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100395 for attr in 'st_atime', 'st_mtime':
396 # The modification times may be truncated in the new file.
397 self.assertLessEqual(getattr(src_link_stat, attr),
398 getattr(dst_link_stat, attr) + 1)
399 if hasattr(os, 'lchmod'):
400 self.assertEqual(src_link_stat.st_mode, dst_link_stat.st_mode)
401 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
402 self.assertEqual(src_link_stat.st_flags, dst_link_stat.st_flags)
403 # tell to follow but dst is not a link
Larry Hastingsb4038062012-07-15 10:57:38 -0700404 shutil.copystat(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100405 self.assertTrue(abs(os.stat(src).st_mtime - os.stat(dst).st_mtime) <
406 00000.1)
407
Ned Deilybaf75712012-05-10 17:05:19 -0700408 @unittest.skipUnless(hasattr(os, 'chflags') and
409 hasattr(errno, 'EOPNOTSUPP') and
410 hasattr(errno, 'ENOTSUP'),
411 "requires os.chflags, EOPNOTSUPP & ENOTSUP")
412 def test_copystat_handles_harmless_chflags_errors(self):
413 tmpdir = self.mkdtemp()
414 file1 = os.path.join(tmpdir, 'file1')
415 file2 = os.path.join(tmpdir, 'file2')
416 write_file(file1, 'xxx')
417 write_file(file2, 'xxx')
418
419 def make_chflags_raiser(err):
420 ex = OSError()
421
Larry Hastings90867a52012-06-22 17:01:41 -0700422 def _chflags_raiser(path, flags, *, follow_symlinks=True):
Ned Deilybaf75712012-05-10 17:05:19 -0700423 ex.errno = err
424 raise ex
425 return _chflags_raiser
426 old_chflags = os.chflags
427 try:
428 for err in errno.EOPNOTSUPP, errno.ENOTSUP:
429 os.chflags = make_chflags_raiser(err)
430 shutil.copystat(file1, file2)
431 # assert others errors break it
432 os.chflags = make_chflags_raiser(errno.EOPNOTSUPP + errno.ENOTSUP)
433 self.assertRaises(OSError, shutil.copystat, file1, file2)
434 finally:
435 os.chflags = old_chflags
436
Antoine Pitrou424246f2012-05-12 19:02:01 +0200437 @support.skip_unless_xattr
438 def test_copyxattr(self):
439 tmp_dir = self.mkdtemp()
440 src = os.path.join(tmp_dir, 'foo')
441 write_file(src, 'foo')
442 dst = os.path.join(tmp_dir, 'bar')
443 write_file(dst, 'bar')
444
445 # no xattr == no problem
446 shutil._copyxattr(src, dst)
447 # common case
448 os.setxattr(src, 'user.foo', b'42')
449 os.setxattr(src, 'user.bar', b'43')
450 shutil._copyxattr(src, dst)
Gregory P. Smith1093bf22014-01-17 12:01:22 -0800451 self.assertEqual(sorted(os.listxattr(src)), sorted(os.listxattr(dst)))
Antoine Pitrou424246f2012-05-12 19:02:01 +0200452 self.assertEqual(
453 os.getxattr(src, 'user.foo'),
454 os.getxattr(dst, 'user.foo'))
455 # check errors don't affect other attrs
456 os.remove(dst)
457 write_file(dst, 'bar')
458 os_error = OSError(errno.EPERM, 'EPERM')
459
Larry Hastings9cf065c2012-06-22 16:30:09 -0700460 def _raise_on_user_foo(fname, attr, val, **kwargs):
Antoine Pitrou424246f2012-05-12 19:02:01 +0200461 if attr == 'user.foo':
462 raise os_error
463 else:
Larry Hastings9cf065c2012-06-22 16:30:09 -0700464 orig_setxattr(fname, attr, val, **kwargs)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200465 try:
466 orig_setxattr = os.setxattr
467 os.setxattr = _raise_on_user_foo
468 shutil._copyxattr(src, dst)
Antoine Pitrou61597d32012-05-12 23:37:35 +0200469 self.assertIn('user.bar', os.listxattr(dst))
Antoine Pitrou424246f2012-05-12 19:02:01 +0200470 finally:
471 os.setxattr = orig_setxattr
Hynek Schlawack0beab052013-02-05 08:22:44 +0100472 # the source filesystem not supporting xattrs should be ok, too.
473 def _raise_on_src(fname, *, follow_symlinks=True):
474 if fname == src:
475 raise OSError(errno.ENOTSUP, 'Operation not supported')
476 return orig_listxattr(fname, follow_symlinks=follow_symlinks)
477 try:
478 orig_listxattr = os.listxattr
479 os.listxattr = _raise_on_src
480 shutil._copyxattr(src, dst)
481 finally:
482 os.listxattr = orig_listxattr
Antoine Pitrou424246f2012-05-12 19:02:01 +0200483
Larry Hastingsad5ae042012-07-14 17:55:11 -0700484 # test that shutil.copystat copies xattrs
485 src = os.path.join(tmp_dir, 'the_original')
486 write_file(src, src)
487 os.setxattr(src, 'user.the_value', b'fiddly')
488 dst = os.path.join(tmp_dir, 'the_copy')
489 write_file(dst, dst)
490 shutil.copystat(src, dst)
Hynek Schlawackc2d481f2012-07-16 17:11:10 +0200491 self.assertEqual(os.getxattr(dst, 'user.the_value'), b'fiddly')
Larry Hastingsad5ae042012-07-14 17:55:11 -0700492
Antoine Pitrou424246f2012-05-12 19:02:01 +0200493 @support.skip_unless_symlink
494 @support.skip_unless_xattr
495 @unittest.skipUnless(hasattr(os, 'geteuid') and os.geteuid() == 0,
496 'root privileges required')
497 def test_copyxattr_symlinks(self):
498 # On Linux, it's only possible to access non-user xattr for symlinks;
499 # which in turn require root privileges. This test should be expanded
500 # as soon as other platforms gain support for extended attributes.
501 tmp_dir = self.mkdtemp()
502 src = os.path.join(tmp_dir, 'foo')
503 src_link = os.path.join(tmp_dir, 'baz')
504 write_file(src, 'foo')
505 os.symlink(src, src_link)
506 os.setxattr(src, 'trusted.foo', b'42')
Larry Hastings9cf065c2012-06-22 16:30:09 -0700507 os.setxattr(src_link, 'trusted.foo', b'43', follow_symlinks=False)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200508 dst = os.path.join(tmp_dir, 'bar')
509 dst_link = os.path.join(tmp_dir, 'qux')
510 write_file(dst, 'bar')
511 os.symlink(dst, dst_link)
Larry Hastingsb4038062012-07-15 10:57:38 -0700512 shutil._copyxattr(src_link, dst_link, follow_symlinks=False)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700513 self.assertEqual(os.getxattr(dst_link, 'trusted.foo', follow_symlinks=False), b'43')
Antoine Pitrou424246f2012-05-12 19:02:01 +0200514 self.assertRaises(OSError, os.getxattr, dst, 'trusted.foo')
Larry Hastingsb4038062012-07-15 10:57:38 -0700515 shutil._copyxattr(src_link, dst, follow_symlinks=False)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200516 self.assertEqual(os.getxattr(dst, 'trusted.foo'), b'43')
517
Antoine Pitrou78091e62011-12-29 18:54:15 +0100518 @support.skip_unless_symlink
519 def test_copy_symlinks(self):
520 tmp_dir = self.mkdtemp()
521 src = os.path.join(tmp_dir, 'foo')
522 dst = os.path.join(tmp_dir, 'bar')
523 src_link = os.path.join(tmp_dir, 'baz')
524 write_file(src, 'foo')
525 os.symlink(src, src_link)
526 if hasattr(os, 'lchmod'):
527 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
528 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700529 shutil.copy(src_link, dst, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100530 self.assertFalse(os.path.islink(dst))
531 self.assertEqual(read_file(src), read_file(dst))
532 os.remove(dst)
533 # follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700534 shutil.copy(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100535 self.assertTrue(os.path.islink(dst))
536 self.assertEqual(os.readlink(dst), os.readlink(src_link))
537 if hasattr(os, 'lchmod'):
538 self.assertEqual(os.lstat(src_link).st_mode,
539 os.lstat(dst).st_mode)
540
541 @support.skip_unless_symlink
542 def test_copy2_symlinks(self):
543 tmp_dir = self.mkdtemp()
544 src = os.path.join(tmp_dir, 'foo')
545 dst = os.path.join(tmp_dir, 'bar')
546 src_link = os.path.join(tmp_dir, 'baz')
547 write_file(src, 'foo')
548 os.symlink(src, src_link)
549 if hasattr(os, 'lchmod'):
550 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
551 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
552 os.lchflags(src_link, stat.UF_NODUMP)
553 src_stat = os.stat(src)
554 src_link_stat = os.lstat(src_link)
555 # follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700556 shutil.copy2(src_link, dst, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100557 self.assertFalse(os.path.islink(dst))
558 self.assertEqual(read_file(src), read_file(dst))
559 os.remove(dst)
560 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700561 shutil.copy2(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100562 self.assertTrue(os.path.islink(dst))
563 self.assertEqual(os.readlink(dst), os.readlink(src_link))
564 dst_stat = os.lstat(dst)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700565 if os.utime in os.supports_follow_symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100566 for attr in 'st_atime', 'st_mtime':
567 # The modification times may be truncated in the new file.
568 self.assertLessEqual(getattr(src_link_stat, attr),
569 getattr(dst_stat, attr) + 1)
570 if hasattr(os, 'lchmod'):
571 self.assertEqual(src_link_stat.st_mode, dst_stat.st_mode)
572 self.assertNotEqual(src_stat.st_mode, dst_stat.st_mode)
573 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
574 self.assertEqual(src_link_stat.st_flags, dst_stat.st_flags)
575
Antoine Pitrou424246f2012-05-12 19:02:01 +0200576 @support.skip_unless_xattr
577 def test_copy2_xattr(self):
578 tmp_dir = self.mkdtemp()
579 src = os.path.join(tmp_dir, 'foo')
580 dst = os.path.join(tmp_dir, 'bar')
581 write_file(src, 'foo')
582 os.setxattr(src, 'user.foo', b'42')
583 shutil.copy2(src, dst)
584 self.assertEqual(
585 os.getxattr(src, 'user.foo'),
586 os.getxattr(dst, 'user.foo'))
587 os.remove(dst)
588
Antoine Pitrou78091e62011-12-29 18:54:15 +0100589 @support.skip_unless_symlink
590 def test_copyfile_symlinks(self):
591 tmp_dir = self.mkdtemp()
592 src = os.path.join(tmp_dir, 'src')
593 dst = os.path.join(tmp_dir, 'dst')
594 dst_link = os.path.join(tmp_dir, 'dst_link')
595 link = os.path.join(tmp_dir, 'link')
596 write_file(src, 'foo')
597 os.symlink(src, link)
598 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700599 shutil.copyfile(link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100600 self.assertTrue(os.path.islink(dst_link))
601 self.assertEqual(os.readlink(link), os.readlink(dst_link))
602 # follow
603 shutil.copyfile(link, dst)
604 self.assertFalse(os.path.islink(dst))
605
Hynek Schlawack2100b422012-06-23 20:28:32 +0200606 def test_rmtree_uses_safe_fd_version_if_available(self):
Hynek Schlawackd0f6e0a2012-06-29 08:28:20 +0200607 _use_fd_functions = ({os.open, os.stat, os.unlink, os.rmdir} <=
608 os.supports_dir_fd and
609 os.listdir in os.supports_fd and
610 os.stat in os.supports_follow_symlinks)
611 if _use_fd_functions:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200612 self.assertTrue(shutil._use_fd_functions)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000613 self.assertTrue(shutil.rmtree.avoids_symlink_attacks)
Hynek Schlawack2100b422012-06-23 20:28:32 +0200614 tmp_dir = self.mkdtemp()
615 d = os.path.join(tmp_dir, 'a')
616 os.mkdir(d)
617 try:
618 real_rmtree = shutil._rmtree_safe_fd
619 class Called(Exception): pass
620 def _raiser(*args, **kwargs):
621 raise Called
622 shutil._rmtree_safe_fd = _raiser
623 self.assertRaises(Called, shutil.rmtree, d)
624 finally:
625 shutil._rmtree_safe_fd = real_rmtree
626 else:
627 self.assertFalse(shutil._use_fd_functions)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000628 self.assertFalse(shutil.rmtree.avoids_symlink_attacks)
Hynek Schlawack2100b422012-06-23 20:28:32 +0200629
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000630 def test_rmtree_dont_delete_file(self):
631 # When called on a file instead of a directory, don't delete it.
632 handle, path = tempfile.mkstemp()
Victor Stinnerbf816222011-06-30 23:25:47 +0200633 os.close(handle)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200634 self.assertRaises(NotADirectoryError, shutil.rmtree, path)
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000635 os.remove(path)
636
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000637 def test_copytree_simple(self):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000638 src_dir = tempfile.mkdtemp()
639 dst_dir = os.path.join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200640 self.addCleanup(shutil.rmtree, src_dir)
641 self.addCleanup(shutil.rmtree, os.path.dirname(dst_dir))
642 write_file((src_dir, 'test.txt'), '123')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000643 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200644 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000645
Éric Araujoa7e33a12011-08-12 19:51:35 +0200646 shutil.copytree(src_dir, dst_dir)
647 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test.txt')))
648 self.assertTrue(os.path.isdir(os.path.join(dst_dir, 'test_dir')))
649 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test_dir',
650 'test.txt')))
651 actual = read_file((dst_dir, 'test.txt'))
652 self.assertEqual(actual, '123')
653 actual = read_file((dst_dir, 'test_dir', 'test.txt'))
654 self.assertEqual(actual, '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000655
Antoine Pitrou78091e62011-12-29 18:54:15 +0100656 @support.skip_unless_symlink
657 def test_copytree_symlinks(self):
658 tmp_dir = self.mkdtemp()
659 src_dir = os.path.join(tmp_dir, 'src')
660 dst_dir = os.path.join(tmp_dir, 'dst')
661 sub_dir = os.path.join(src_dir, 'sub')
662 os.mkdir(src_dir)
663 os.mkdir(sub_dir)
664 write_file((src_dir, 'file.txt'), 'foo')
665 src_link = os.path.join(sub_dir, 'link')
666 dst_link = os.path.join(dst_dir, 'sub/link')
667 os.symlink(os.path.join(src_dir, 'file.txt'),
668 src_link)
669 if hasattr(os, 'lchmod'):
670 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
671 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
672 os.lchflags(src_link, stat.UF_NODUMP)
673 src_stat = os.lstat(src_link)
674 shutil.copytree(src_dir, dst_dir, symlinks=True)
675 self.assertTrue(os.path.islink(os.path.join(dst_dir, 'sub', 'link')))
676 self.assertEqual(os.readlink(os.path.join(dst_dir, 'sub', 'link')),
677 os.path.join(src_dir, 'file.txt'))
678 dst_stat = os.lstat(dst_link)
679 if hasattr(os, 'lchmod'):
680 self.assertEqual(dst_stat.st_mode, src_stat.st_mode)
681 if hasattr(os, 'lchflags'):
682 self.assertEqual(dst_stat.st_flags, src_stat.st_flags)
683
Georg Brandl2ee470f2008-07-16 12:55:28 +0000684 def test_copytree_with_exclude(self):
Georg Brandl2ee470f2008-07-16 12:55:28 +0000685 # creating data
686 join = os.path.join
687 exists = os.path.exists
688 src_dir = tempfile.mkdtemp()
Georg Brandl2ee470f2008-07-16 12:55:28 +0000689 try:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000690 dst_dir = join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200691 write_file((src_dir, 'test.txt'), '123')
692 write_file((src_dir, 'test.tmp'), '123')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000693 os.mkdir(join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200694 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000695 os.mkdir(join(src_dir, 'test_dir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200696 write_file((src_dir, 'test_dir2', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000697 os.mkdir(join(src_dir, 'test_dir2', 'subdir'))
698 os.mkdir(join(src_dir, 'test_dir2', 'subdir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200699 write_file((src_dir, 'test_dir2', 'subdir', 'test.txt'), '456')
700 write_file((src_dir, 'test_dir2', 'subdir2', 'test.py'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000701
702 # testing glob-like patterns
703 try:
704 patterns = shutil.ignore_patterns('*.tmp', 'test_dir2')
705 shutil.copytree(src_dir, dst_dir, ignore=patterns)
706 # checking the result: some elements should not be copied
707 self.assertTrue(exists(join(dst_dir, 'test.txt')))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200708 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
709 self.assertFalse(exists(join(dst_dir, 'test_dir2')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000710 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200711 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000712 try:
713 patterns = shutil.ignore_patterns('*.tmp', 'subdir*')
714 shutil.copytree(src_dir, dst_dir, ignore=patterns)
715 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200716 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
717 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2')))
718 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000719 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200720 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000721
722 # testing callable-style
723 try:
724 def _filter(src, names):
725 res = []
726 for name in names:
727 path = os.path.join(src, name)
728
729 if (os.path.isdir(path) and
730 path.split()[-1] == 'subdir'):
731 res.append(name)
732 elif os.path.splitext(path)[-1] in ('.py'):
733 res.append(name)
734 return res
735
736 shutil.copytree(src_dir, dst_dir, ignore=_filter)
737
738 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200739 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2',
740 'test.py')))
741 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000742
743 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200744 shutil.rmtree(dst_dir)
Georg Brandl2ee470f2008-07-16 12:55:28 +0000745 finally:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000746 shutil.rmtree(src_dir)
747 shutil.rmtree(os.path.dirname(dst_dir))
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000748
Antoine Pitrouac601602013-08-16 19:35:02 +0200749 def test_copytree_retains_permissions(self):
750 tmp_dir = tempfile.mkdtemp()
751 src_dir = os.path.join(tmp_dir, 'source')
752 os.mkdir(src_dir)
753 dst_dir = os.path.join(tmp_dir, 'destination')
754 self.addCleanup(shutil.rmtree, tmp_dir)
755
756 os.chmod(src_dir, 0o777)
757 write_file((src_dir, 'permissive.txt'), '123')
758 os.chmod(os.path.join(src_dir, 'permissive.txt'), 0o777)
759 write_file((src_dir, 'restrictive.txt'), '456')
760 os.chmod(os.path.join(src_dir, 'restrictive.txt'), 0o600)
761 restrictive_subdir = tempfile.mkdtemp(dir=src_dir)
762 os.chmod(restrictive_subdir, 0o600)
763
764 shutil.copytree(src_dir, dst_dir)
Brett Cannon9c7eb552013-08-23 14:38:11 -0400765 self.assertEqual(os.stat(src_dir).st_mode, os.stat(dst_dir).st_mode)
766 self.assertEqual(os.stat(os.path.join(src_dir, 'permissive.txt')).st_mode,
Antoine Pitrouac601602013-08-16 19:35:02 +0200767 os.stat(os.path.join(dst_dir, 'permissive.txt')).st_mode)
Brett Cannon9c7eb552013-08-23 14:38:11 -0400768 self.assertEqual(os.stat(os.path.join(src_dir, 'restrictive.txt')).st_mode,
Antoine Pitrouac601602013-08-16 19:35:02 +0200769 os.stat(os.path.join(dst_dir, 'restrictive.txt')).st_mode)
770 restrictive_subdir_dst = os.path.join(dst_dir,
771 os.path.split(restrictive_subdir)[1])
Brett Cannon9c7eb552013-08-23 14:38:11 -0400772 self.assertEqual(os.stat(restrictive_subdir).st_mode,
Antoine Pitrouac601602013-08-16 19:35:02 +0200773 os.stat(restrictive_subdir_dst).st_mode)
774
Berker Peksag884afd92014-12-10 02:50:32 +0200775 @unittest.mock.patch('os.chmod')
776 def test_copytree_winerror(self, mock_patch):
777 # When copying to VFAT, copystat() raises OSError. On Windows, the
778 # exception object has a meaningful 'winerror' attribute, but not
779 # on other operating systems. Do not assume 'winerror' is set.
780 src_dir = tempfile.mkdtemp()
781 dst_dir = os.path.join(tempfile.mkdtemp(), 'destination')
782 self.addCleanup(shutil.rmtree, src_dir)
783 self.addCleanup(shutil.rmtree, os.path.dirname(dst_dir))
784
785 mock_patch.side_effect = PermissionError('ka-boom')
786 with self.assertRaises(shutil.Error):
787 shutil.copytree(src_dir, dst_dir)
788
Zachary Ware9fe6d862013-12-08 00:20:35 -0600789 @unittest.skipIf(os.name == 'nt', 'temporarily disabled on Windows')
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000790 @unittest.skipUnless(hasattr(os, 'link'), 'requires os.link')
Xavier de Gaye3a4e9892016-12-13 10:00:01 +0100791 @unittest.skipIf(android_not_root, "hard links not allowed, non root user")
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000792 def test_dont_copy_file_onto_link_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:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000798 with open(src, 'w') as f:
799 f.write('cheddar')
800 os.link(src, dst)
Hynek Schlawack48653762012-10-07 12:49:58 +0200801 self.assertRaises(shutil.SameFileError, shutil.copyfile, src, dst)
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000802 with open(src, 'r') as f:
803 self.assertEqual(f.read(), 'cheddar')
804 os.remove(dst)
805 finally:
806 shutil.rmtree(TESTFN, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000807
Brian Curtin3b4499c2010-12-28 14:31:47 +0000808 @support.skip_unless_symlink
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000809 def test_dont_copy_file_onto_symlink_to_itself(self):
810 # bug 851123.
811 os.mkdir(TESTFN)
812 src = os.path.join(TESTFN, 'cheese')
813 dst = os.path.join(TESTFN, 'shop')
814 try:
815 with open(src, 'w') as f:
816 f.write('cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000817 # Using `src` here would mean we end up with a symlink pointing
818 # to TESTFN/TESTFN/cheese, while it should point at
819 # TESTFN/cheese.
820 os.symlink('cheese', dst)
Hynek Schlawack48653762012-10-07 12:49:58 +0200821 self.assertRaises(shutil.SameFileError, shutil.copyfile, src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +0000822 with open(src, 'r') as f:
823 self.assertEqual(f.read(), 'cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000824 os.remove(dst)
825 finally:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000826 shutil.rmtree(TESTFN, ignore_errors=True)
Johannes Gijsbers68128712004-08-14 13:57:08 +0000827
Brian Curtin3b4499c2010-12-28 14:31:47 +0000828 @support.skip_unless_symlink
Brian Curtind40e6f72010-07-08 21:39:08 +0000829 def test_rmtree_on_symlink(self):
830 # bug 1669.
831 os.mkdir(TESTFN)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000832 try:
Brian Curtind40e6f72010-07-08 21:39:08 +0000833 src = os.path.join(TESTFN, 'cheese')
834 dst = os.path.join(TESTFN, 'shop')
835 os.mkdir(src)
836 os.symlink(src, dst)
837 self.assertRaises(OSError, shutil.rmtree, dst)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200838 shutil.rmtree(dst, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000839 finally:
Brian Curtind40e6f72010-07-08 21:39:08 +0000840 shutil.rmtree(TESTFN, ignore_errors=True)
841
Serhiy Storchaka43767632013-11-03 21:31:38 +0200842 # Issue #3002: copyfile and copytree block indefinitely on named pipes
843 @unittest.skipUnless(hasattr(os, "mkfifo"), 'requires os.mkfifo()')
Xavier de Gaye3a4e9892016-12-13 10:00:01 +0100844 @unittest.skipIf(android_not_root, "mkfifo not allowed, non root user")
Serhiy Storchaka43767632013-11-03 21:31:38 +0200845 def test_copyfile_named_pipe(self):
846 os.mkfifo(TESTFN)
847 try:
848 self.assertRaises(shutil.SpecialFileError,
849 shutil.copyfile, TESTFN, TESTFN2)
850 self.assertRaises(shutil.SpecialFileError,
851 shutil.copyfile, __file__, TESTFN)
852 finally:
853 os.remove(TESTFN)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000854
Xavier de Gaye3a4e9892016-12-13 10:00:01 +0100855 @unittest.skipIf(android_not_root, "mkfifo not allowed, non root user")
Serhiy Storchaka43767632013-11-03 21:31:38 +0200856 @unittest.skipUnless(hasattr(os, "mkfifo"), 'requires os.mkfifo()')
857 @support.skip_unless_symlink
858 def test_copytree_named_pipe(self):
859 os.mkdir(TESTFN)
860 try:
861 subdir = os.path.join(TESTFN, "subdir")
862 os.mkdir(subdir)
863 pipe = os.path.join(subdir, "mypipe")
864 os.mkfifo(pipe)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000865 try:
Serhiy Storchaka43767632013-11-03 21:31:38 +0200866 shutil.copytree(TESTFN, TESTFN2)
867 except shutil.Error as e:
868 errors = e.args[0]
869 self.assertEqual(len(errors), 1)
870 src, dst, error_msg = errors[0]
871 self.assertEqual("`%s` is a named pipe" % pipe, error_msg)
872 else:
873 self.fail("shutil.Error should have been raised")
874 finally:
875 shutil.rmtree(TESTFN, ignore_errors=True)
876 shutil.rmtree(TESTFN2, ignore_errors=True)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000877
Tarek Ziadé5340db32010-04-19 22:30:51 +0000878 def test_copytree_special_func(self):
879
880 src_dir = self.mkdtemp()
881 dst_dir = os.path.join(self.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200882 write_file((src_dir, 'test.txt'), '123')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000883 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200884 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000885
886 copied = []
887 def _copy(src, dst):
888 copied.append((src, dst))
889
890 shutil.copytree(src_dir, dst_dir, copy_function=_copy)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000891 self.assertEqual(len(copied), 2)
Tarek Ziadé5340db32010-04-19 22:30:51 +0000892
Brian Curtin3b4499c2010-12-28 14:31:47 +0000893 @support.skip_unless_symlink
Tarek Ziadéfb437512010-04-20 08:57:33 +0000894 def test_copytree_dangling_symlinks(self):
895
896 # a dangling symlink raises an error at the end
897 src_dir = self.mkdtemp()
898 dst_dir = os.path.join(self.mkdtemp(), 'destination')
899 os.symlink('IDONTEXIST', os.path.join(src_dir, 'test.txt'))
900 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200901 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadéfb437512010-04-20 08:57:33 +0000902 self.assertRaises(Error, shutil.copytree, src_dir, dst_dir)
903
904 # a dangling symlink is ignored with the proper flag
905 dst_dir = os.path.join(self.mkdtemp(), 'destination2')
906 shutil.copytree(src_dir, dst_dir, ignore_dangling_symlinks=True)
907 self.assertNotIn('test.txt', os.listdir(dst_dir))
908
909 # a dangling symlink is copied if symlinks=True
910 dst_dir = os.path.join(self.mkdtemp(), 'destination3')
911 shutil.copytree(src_dir, dst_dir, symlinks=True)
912 self.assertIn('test.txt', os.listdir(dst_dir))
913
Berker Peksag5a294d82015-07-25 14:53:48 +0300914 @support.skip_unless_symlink
915 def test_copytree_symlink_dir(self):
916 src_dir = self.mkdtemp()
917 dst_dir = os.path.join(self.mkdtemp(), 'destination')
918 os.mkdir(os.path.join(src_dir, 'real_dir'))
919 with open(os.path.join(src_dir, 'real_dir', 'test.txt'), 'w'):
920 pass
921 os.symlink(os.path.join(src_dir, 'real_dir'),
922 os.path.join(src_dir, 'link_to_dir'),
923 target_is_directory=True)
924
925 shutil.copytree(src_dir, dst_dir, symlinks=False)
926 self.assertFalse(os.path.islink(os.path.join(dst_dir, 'link_to_dir')))
927 self.assertIn('test.txt', os.listdir(os.path.join(dst_dir, 'link_to_dir')))
928
929 dst_dir = os.path.join(self.mkdtemp(), 'destination2')
930 shutil.copytree(src_dir, dst_dir, symlinks=True)
931 self.assertTrue(os.path.islink(os.path.join(dst_dir, 'link_to_dir')))
932 self.assertIn('test.txt', os.listdir(os.path.join(dst_dir, 'link_to_dir')))
933
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400934 def _copy_file(self, method):
935 fname = 'test.txt'
936 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200937 write_file((tmpdir, fname), 'xxx')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400938 file1 = os.path.join(tmpdir, fname)
939 tmpdir2 = self.mkdtemp()
940 method(file1, tmpdir2)
941 file2 = os.path.join(tmpdir2, fname)
942 return (file1, file2)
943
944 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
945 def test_copy(self):
946 # Ensure that the copied file exists and has the same mode bits.
947 file1, file2 = self._copy_file(shutil.copy)
948 self.assertTrue(os.path.exists(file2))
949 self.assertEqual(os.stat(file1).st_mode, os.stat(file2).st_mode)
950
951 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
Senthil Kumaran0c2dba52011-07-03 18:21:38 -0700952 @unittest.skipUnless(hasattr(os, 'utime'), 'requires os.utime')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400953 def test_copy2(self):
954 # Ensure that the copied file exists and has the same mode and
955 # modification time bits.
956 file1, file2 = self._copy_file(shutil.copy2)
957 self.assertTrue(os.path.exists(file2))
958 file1_stat = os.stat(file1)
959 file2_stat = os.stat(file2)
960 self.assertEqual(file1_stat.st_mode, file2_stat.st_mode)
961 for attr in 'st_atime', 'st_mtime':
962 # The modification times may be truncated in the new file.
963 self.assertLessEqual(getattr(file1_stat, attr),
964 getattr(file2_stat, attr) + 1)
965 if hasattr(os, 'chflags') and hasattr(file1_stat, 'st_flags'):
966 self.assertEqual(getattr(file1_stat, 'st_flags'),
967 getattr(file2_stat, 'st_flags'))
968
Ezio Melotti975077a2011-05-19 22:03:22 +0300969 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000970 def test_make_tarball(self):
971 # creating something to tar
Serhiy Storchaka527ef072015-09-06 18:33:19 +0300972 root_dir, base_dir = self._create_files('')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000973
974 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400975 # force shutil to create the directory
976 os.rmdir(tmpdir2)
Serhiy Storchakaeba8fee2015-09-07 19:58:23 +0300977 # working with relative paths
978 work_dir = os.path.dirname(tmpdir2)
979 rel_base_name = os.path.join(os.path.basename(tmpdir2), 'archive')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000980
Serhiy Storchakaeba8fee2015-09-07 19:58:23 +0300981 with support.change_cwd(work_dir):
Serhiy Storchaka5558d4f2015-09-08 09:59:02 +0300982 base_name = os.path.abspath(rel_base_name)
Serhiy Storchakaeba8fee2015-09-07 19:58:23 +0300983 tarball = make_archive(rel_base_name, 'gztar', root_dir, '.')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000984
985 # check if the compressed tarball was created
Serhiy Storchakaa091a822015-09-07 13:55:25 +0300986 self.assertEqual(tarball, base_name + '.tar.gz')
Serhiy Storchaka527ef072015-09-06 18:33:19 +0300987 self.assertTrue(os.path.isfile(tarball))
988 self.assertTrue(tarfile.is_tarfile(tarball))
989 with tarfile.open(tarball, 'r:gz') as tf:
990 self.assertCountEqual(tf.getnames(),
991 ['.', './sub', './sub2',
992 './file1', './file2', './sub/file3'])
Tarek Ziadé396fad72010-02-23 05:30:31 +0000993
994 # trying an uncompressed one
Serhiy Storchakaeba8fee2015-09-07 19:58:23 +0300995 with support.change_cwd(work_dir):
996 tarball = make_archive(rel_base_name, 'tar', root_dir, '.')
Serhiy Storchakaa091a822015-09-07 13:55:25 +0300997 self.assertEqual(tarball, base_name + '.tar')
Serhiy Storchaka527ef072015-09-06 18:33:19 +0300998 self.assertTrue(os.path.isfile(tarball))
999 self.assertTrue(tarfile.is_tarfile(tarball))
1000 with tarfile.open(tarball, 'r') as tf:
1001 self.assertCountEqual(tf.getnames(),
1002 ['.', './sub', './sub2',
1003 './file1', './file2', './sub/file3'])
Tarek Ziadé396fad72010-02-23 05:30:31 +00001004
1005 def _tarinfo(self, path):
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001006 with tarfile.open(path) as tar:
Tarek Ziadé396fad72010-02-23 05:30:31 +00001007 names = tar.getnames()
1008 names.sort()
1009 return tuple(names)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001010
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001011 def _create_files(self, base_dir='dist'):
Tarek Ziadé396fad72010-02-23 05:30:31 +00001012 # creating something to tar
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001013 root_dir = self.mkdtemp()
1014 dist = os.path.join(root_dir, base_dir)
1015 os.makedirs(dist, exist_ok=True)
Éric Araujoa7e33a12011-08-12 19:51:35 +02001016 write_file((dist, 'file1'), 'xxx')
1017 write_file((dist, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +00001018 os.mkdir(os.path.join(dist, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +02001019 write_file((dist, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +00001020 os.mkdir(os.path.join(dist, 'sub2'))
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001021 if base_dir:
1022 write_file((root_dir, 'outer'), 'xxx')
1023 return root_dir, base_dir
Tarek Ziadé396fad72010-02-23 05:30:31 +00001024
Ezio Melotti975077a2011-05-19 22:03:22 +03001025 @requires_zlib
Serhiy Storchakab42de2f2015-11-21 14:09:26 +02001026 @unittest.skipUnless(shutil.which('tar'),
Tarek Ziadé396fad72010-02-23 05:30:31 +00001027 'Need the tar command to run')
1028 def test_tarfile_vs_tar(self):
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001029 root_dir, base_dir = self._create_files()
1030 base_name = os.path.join(self.mkdtemp(), 'archive')
Serhiy Storchakaa091a822015-09-07 13:55:25 +03001031 tarball = make_archive(base_name, 'gztar', root_dir, base_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001032
1033 # check if the compressed tarball was created
Serhiy Storchakaa091a822015-09-07 13:55:25 +03001034 self.assertEqual(tarball, base_name + '.tar.gz')
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001035 self.assertTrue(os.path.isfile(tarball))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001036
1037 # now create another tarball using `tar`
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001038 tarball2 = os.path.join(root_dir, 'archive2.tar')
1039 tar_cmd = ['tar', '-cf', 'archive2.tar', base_dir]
Serhiy Storchakab42de2f2015-11-21 14:09:26 +02001040 subprocess.check_call(tar_cmd, cwd=root_dir,
1041 stdout=subprocess.DEVNULL)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001042
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001043 self.assertTrue(os.path.isfile(tarball2))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001044 # let's compare both tarballs
Ezio Melottib3aedd42010-11-20 19:04:17 +00001045 self.assertEqual(self._tarinfo(tarball), self._tarinfo(tarball2))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001046
1047 # trying an uncompressed one
Serhiy Storchakaa091a822015-09-07 13:55:25 +03001048 tarball = make_archive(base_name, 'tar', root_dir, base_dir)
1049 self.assertEqual(tarball, base_name + '.tar')
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001050 self.assertTrue(os.path.isfile(tarball))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001051
1052 # now for a dry_run
Serhiy Storchakaa091a822015-09-07 13:55:25 +03001053 tarball = make_archive(base_name, 'tar', root_dir, base_dir,
1054 dry_run=True)
1055 self.assertEqual(tarball, base_name + '.tar')
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001056 self.assertTrue(os.path.isfile(tarball))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001057
Ezio Melotti975077a2011-05-19 22:03:22 +03001058 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001059 @unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run')
1060 def test_make_zipfile(self):
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001061 # creating something to zip
1062 root_dir, base_dir = self._create_files()
Serhiy Storchakaeba8fee2015-09-07 19:58:23 +03001063
1064 tmpdir2 = self.mkdtemp()
1065 # force shutil to create the directory
1066 os.rmdir(tmpdir2)
1067 # working with relative paths
1068 work_dir = os.path.dirname(tmpdir2)
1069 rel_base_name = os.path.join(os.path.basename(tmpdir2), 'archive')
Serhiy Storchakaeba8fee2015-09-07 19:58:23 +03001070
1071 with support.change_cwd(work_dir):
Serhiy Storchaka5558d4f2015-09-08 09:59:02 +03001072 base_name = os.path.abspath(rel_base_name)
Serhiy Storchaka666de772016-10-23 15:55:09 +03001073 res = make_archive(rel_base_name, 'zip', root_dir)
1074
1075 self.assertEqual(res, base_name + '.zip')
1076 self.assertTrue(os.path.isfile(res))
1077 self.assertTrue(zipfile.is_zipfile(res))
1078 with zipfile.ZipFile(res) as zf:
1079 self.assertCountEqual(zf.namelist(),
1080 ['dist/', 'dist/sub/', 'dist/sub2/',
1081 'dist/file1', 'dist/file2', 'dist/sub/file3',
1082 'outer'])
1083
1084 with support.change_cwd(work_dir):
1085 base_name = os.path.abspath(rel_base_name)
Serhiy Storchaka2504cec2015-09-08 05:47:23 +03001086 res = make_archive(rel_base_name, 'zip', root_dir, base_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001087
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001088 self.assertEqual(res, base_name + '.zip')
1089 self.assertTrue(os.path.isfile(res))
1090 self.assertTrue(zipfile.is_zipfile(res))
1091 with zipfile.ZipFile(res) as zf:
1092 self.assertCountEqual(zf.namelist(),
Serhiy Storchaka2504cec2015-09-08 05:47:23 +03001093 ['dist/', 'dist/sub/', 'dist/sub2/',
1094 'dist/file1', 'dist/file2', 'dist/sub/file3'])
Tarek Ziadé396fad72010-02-23 05:30:31 +00001095
Serhiy Storchaka2504cec2015-09-08 05:47:23 +03001096 @requires_zlib
1097 @unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run')
Serhiy Storchakab42de2f2015-11-21 14:09:26 +02001098 @unittest.skipUnless(shutil.which('zip'),
Serhiy Storchaka2504cec2015-09-08 05:47:23 +03001099 'Need the zip command to run')
1100 def test_zipfile_vs_zip(self):
1101 root_dir, base_dir = self._create_files()
1102 base_name = os.path.join(self.mkdtemp(), 'archive')
1103 archive = make_archive(base_name, 'zip', root_dir, base_dir)
1104
1105 # check if ZIP file was created
1106 self.assertEqual(archive, base_name + '.zip')
1107 self.assertTrue(os.path.isfile(archive))
1108
1109 # now create another ZIP file using `zip`
1110 archive2 = os.path.join(root_dir, 'archive2.zip')
1111 zip_cmd = ['zip', '-q', '-r', 'archive2.zip', base_dir]
Serhiy Storchakab42de2f2015-11-21 14:09:26 +02001112 subprocess.check_call(zip_cmd, cwd=root_dir,
1113 stdout=subprocess.DEVNULL)
Serhiy Storchaka2504cec2015-09-08 05:47:23 +03001114
1115 self.assertTrue(os.path.isfile(archive2))
1116 # let's compare both ZIP files
1117 with zipfile.ZipFile(archive) as zf:
1118 names = zf.namelist()
1119 with zipfile.ZipFile(archive2) as zf:
1120 names2 = zf.namelist()
1121 self.assertEqual(sorted(names), sorted(names2))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001122
Serhiy Storchaka8bc792a2015-11-22 14:49:58 +02001123 @requires_zlib
1124 @unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run')
1125 @unittest.skipUnless(shutil.which('unzip'),
1126 'Need the unzip command to run')
1127 def test_unzip_zipfile(self):
1128 root_dir, base_dir = self._create_files()
1129 base_name = os.path.join(self.mkdtemp(), 'archive')
1130 archive = make_archive(base_name, 'zip', root_dir, base_dir)
1131
1132 # check if ZIP file was created
1133 self.assertEqual(archive, base_name + '.zip')
1134 self.assertTrue(os.path.isfile(archive))
1135
1136 # now check the ZIP file using `unzip -t`
1137 zip_cmd = ['unzip', '-t', archive]
1138 with support.change_cwd(root_dir):
1139 try:
1140 subprocess.check_output(zip_cmd, stderr=subprocess.STDOUT)
1141 except subprocess.CalledProcessError as exc:
1142 details = exc.output.decode(errors="replace")
1143 msg = "{}\n\n**Unzip Output**\n{}"
1144 self.fail(msg.format(exc, details))
1145
Tarek Ziadé396fad72010-02-23 05:30:31 +00001146 def test_make_archive(self):
1147 tmpdir = self.mkdtemp()
1148 base_name = os.path.join(tmpdir, 'archive')
1149 self.assertRaises(ValueError, make_archive, base_name, 'xxx')
1150
Ezio Melotti975077a2011-05-19 22:03:22 +03001151 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001152 def test_make_archive_owner_group(self):
1153 # testing make_archive with owner and group, with various combinations
1154 # this works even if there's not gid/uid support
1155 if UID_GID_SUPPORT:
1156 group = grp.getgrgid(0)[0]
1157 owner = pwd.getpwuid(0)[0]
1158 else:
1159 group = owner = 'root'
1160
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001161 root_dir, base_dir = self._create_files()
1162 base_name = os.path.join(self.mkdtemp(), 'archive')
Tarek Ziadé396fad72010-02-23 05:30:31 +00001163 res = make_archive(base_name, 'zip', root_dir, base_dir, owner=owner,
1164 group=group)
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001165 self.assertTrue(os.path.isfile(res))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001166
1167 res = make_archive(base_name, 'zip', root_dir, base_dir)
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001168 self.assertTrue(os.path.isfile(res))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001169
1170 res = make_archive(base_name, 'tar', root_dir, base_dir,
1171 owner=owner, group=group)
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001172 self.assertTrue(os.path.isfile(res))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001173
1174 res = make_archive(base_name, 'tar', root_dir, base_dir,
1175 owner='kjhkjhkjg', group='oihohoh')
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001176 self.assertTrue(os.path.isfile(res))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001177
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001178
Ezio Melotti975077a2011-05-19 22:03:22 +03001179 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001180 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1181 def test_tarfile_root_owner(self):
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001182 root_dir, base_dir = self._create_files()
1183 base_name = os.path.join(self.mkdtemp(), 'archive')
Tarek Ziadé396fad72010-02-23 05:30:31 +00001184 group = grp.getgrgid(0)[0]
1185 owner = pwd.getpwuid(0)[0]
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001186 with support.change_cwd(root_dir):
1187 archive_name = make_archive(base_name, 'gztar', root_dir, 'dist',
1188 owner=owner, group=group)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001189
1190 # check if the compressed tarball was created
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001191 self.assertTrue(os.path.isfile(archive_name))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001192
1193 # now checks the rights
1194 archive = tarfile.open(archive_name)
1195 try:
1196 for member in archive.getmembers():
Ezio Melottib3aedd42010-11-20 19:04:17 +00001197 self.assertEqual(member.uid, 0)
1198 self.assertEqual(member.gid, 0)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001199 finally:
1200 archive.close()
1201
1202 def test_make_archive_cwd(self):
1203 current_dir = os.getcwd()
1204 def _breaks(*args, **kw):
1205 raise RuntimeError()
1206
1207 register_archive_format('xxx', _breaks, [], 'xxx file')
1208 try:
1209 try:
1210 make_archive('xxx', 'xxx', root_dir=self.mkdtemp())
1211 except Exception:
1212 pass
Ezio Melottib3aedd42010-11-20 19:04:17 +00001213 self.assertEqual(os.getcwd(), current_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001214 finally:
1215 unregister_archive_format('xxx')
1216
Serhiy Storchaka9a4fc192014-11-28 00:48:46 +02001217 def test_make_tarfile_in_curdir(self):
1218 # Issue #21280
1219 root_dir = self.mkdtemp()
1220 with support.change_cwd(root_dir):
1221 self.assertEqual(make_archive('test', 'tar'), 'test.tar')
1222 self.assertTrue(os.path.isfile('test.tar'))
1223
1224 @requires_zlib
1225 def test_make_zipfile_in_curdir(self):
1226 # Issue #21280
1227 root_dir = self.mkdtemp()
1228 with support.change_cwd(root_dir):
1229 self.assertEqual(make_archive('test', 'zip'), 'test.zip')
1230 self.assertTrue(os.path.isfile('test.zip'))
1231
Tarek Ziadé396fad72010-02-23 05:30:31 +00001232 def test_register_archive_format(self):
1233
1234 self.assertRaises(TypeError, register_archive_format, 'xxx', 1)
1235 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1236 1)
1237 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1238 [(1, 2), (1, 2, 3)])
1239
1240 register_archive_format('xxx', lambda: x, [(1, 2)], 'xxx file')
1241 formats = [name for name, params in get_archive_formats()]
1242 self.assertIn('xxx', formats)
1243
1244 unregister_archive_format('xxx')
1245 formats = [name for name, params in get_archive_formats()]
1246 self.assertNotIn('xxx', formats)
1247
Ezio Melotti975077a2011-05-19 22:03:22 +03001248 @requires_zlib
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001249 def test_unpack_archive(self):
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001250 formats = ['tar', 'gztar', 'zip']
1251 if BZ2_SUPPORTED:
1252 formats.append('bztar')
Serhiy Storchaka11213772014-08-06 18:50:19 +03001253 if LZMA_SUPPORTED:
1254 formats.append('xztar')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001255
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001256 root_dir, base_dir = self._create_files()
Serhiy Storchaka2504cec2015-09-08 05:47:23 +03001257 expected = rlistdir(root_dir)
1258 expected.remove('outer')
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001259 for format in formats:
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001260 base_name = os.path.join(self.mkdtemp(), 'archive')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001261 filename = make_archive(base_name, format, root_dir, base_dir)
1262
1263 # let's try to unpack it now
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001264 tmpdir2 = self.mkdtemp()
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001265 unpack_archive(filename, tmpdir2)
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001266 self.assertEqual(rlistdir(tmpdir2), expected)
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001267
Nick Coghlanabf202d2011-03-16 13:52:20 -04001268 # and again, this time with the format specified
1269 tmpdir3 = self.mkdtemp()
1270 unpack_archive(filename, tmpdir3, format=format)
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001271 self.assertEqual(rlistdir(tmpdir3), expected)
Nick Coghlanabf202d2011-03-16 13:52:20 -04001272 self.assertRaises(shutil.ReadError, unpack_archive, TESTFN)
1273 self.assertRaises(ValueError, unpack_archive, TESTFN, format='xxx')
1274
Martin Pantereb995702016-07-28 01:11:04 +00001275 def test_unpack_registry(self):
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001276
1277 formats = get_unpack_formats()
1278
1279 def _boo(filename, extract_dir, extra):
Ezio Melottib3aedd42010-11-20 19:04:17 +00001280 self.assertEqual(extra, 1)
1281 self.assertEqual(filename, 'stuff.boo')
1282 self.assertEqual(extract_dir, 'xx')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001283
1284 register_unpack_format('Boo', ['.boo', '.b2'], _boo, [('extra', 1)])
1285 unpack_archive('stuff.boo', 'xx')
1286
1287 # trying to register a .boo unpacker again
1288 self.assertRaises(RegistryError, register_unpack_format, 'Boo2',
1289 ['.boo'], _boo)
1290
1291 # should work now
1292 unregister_unpack_format('Boo')
1293 register_unpack_format('Boo2', ['.boo'], _boo)
1294 self.assertIn(('Boo2', ['.boo'], ''), get_unpack_formats())
1295 self.assertNotIn(('Boo', ['.boo'], ''), get_unpack_formats())
1296
1297 # let's leave a clean state
1298 unregister_unpack_format('Boo2')
Ezio Melottib3aedd42010-11-20 19:04:17 +00001299 self.assertEqual(get_unpack_formats(), formats)
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001300
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001301 @unittest.skipUnless(hasattr(shutil, 'disk_usage'),
1302 "disk_usage not available on this platform")
1303 def test_disk_usage(self):
1304 usage = shutil.disk_usage(os.getcwd())
Éric Araujo2ee61882011-07-02 16:45:45 +02001305 self.assertGreater(usage.total, 0)
1306 self.assertGreater(usage.used, 0)
1307 self.assertGreaterEqual(usage.free, 0)
1308 self.assertGreaterEqual(usage.total, usage.used)
1309 self.assertGreater(usage.total, usage.free)
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001310
Sandro Tosid902a142011-08-22 23:28:27 +02001311 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1312 @unittest.skipUnless(hasattr(os, 'chown'), 'requires os.chown')
1313 def test_chown(self):
1314
1315 # cleaned-up automatically by TestShutil.tearDown method
1316 dirname = self.mkdtemp()
1317 filename = tempfile.mktemp(dir=dirname)
1318 write_file(filename, 'testing chown function')
1319
1320 with self.assertRaises(ValueError):
1321 shutil.chown(filename)
1322
1323 with self.assertRaises(LookupError):
Raymond Hettinger15f44ab2016-08-30 10:47:49 -07001324 shutil.chown(filename, user='non-existing username')
Sandro Tosid902a142011-08-22 23:28:27 +02001325
1326 with self.assertRaises(LookupError):
Raymond Hettinger15f44ab2016-08-30 10:47:49 -07001327 shutil.chown(filename, group='non-existing groupname')
Sandro Tosid902a142011-08-22 23:28:27 +02001328
1329 with self.assertRaises(TypeError):
1330 shutil.chown(filename, b'spam')
1331
1332 with self.assertRaises(TypeError):
1333 shutil.chown(filename, 3.14)
1334
1335 uid = os.getuid()
1336 gid = os.getgid()
1337
1338 def check_chown(path, uid=None, gid=None):
1339 s = os.stat(filename)
1340 if uid is not None:
1341 self.assertEqual(uid, s.st_uid)
1342 if gid is not None:
1343 self.assertEqual(gid, s.st_gid)
1344
1345 shutil.chown(filename, uid, gid)
1346 check_chown(filename, uid, gid)
1347 shutil.chown(filename, uid)
1348 check_chown(filename, uid)
1349 shutil.chown(filename, user=uid)
1350 check_chown(filename, uid)
1351 shutil.chown(filename, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001352 check_chown(filename, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001353
1354 shutil.chown(dirname, uid, gid)
1355 check_chown(dirname, uid, gid)
1356 shutil.chown(dirname, uid)
1357 check_chown(dirname, uid)
1358 shutil.chown(dirname, user=uid)
1359 check_chown(dirname, uid)
1360 shutil.chown(dirname, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001361 check_chown(dirname, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001362
1363 user = pwd.getpwuid(uid)[0]
1364 group = grp.getgrgid(gid)[0]
1365 shutil.chown(filename, user, group)
1366 check_chown(filename, uid, gid)
1367 shutil.chown(dirname, user, group)
1368 check_chown(dirname, uid, gid)
1369
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001370 def test_copy_return_value(self):
1371 # copy and copy2 both return their destination path.
1372 for fn in (shutil.copy, shutil.copy2):
1373 src_dir = self.mkdtemp()
1374 dst_dir = self.mkdtemp()
1375 src = os.path.join(src_dir, 'foo')
1376 write_file(src, 'foo')
1377 rv = fn(src, dst_dir)
1378 self.assertEqual(rv, os.path.join(dst_dir, 'foo'))
1379 rv = fn(src, os.path.join(dst_dir, 'bar'))
1380 self.assertEqual(rv, os.path.join(dst_dir, 'bar'))
1381
1382 def test_copyfile_return_value(self):
1383 # copytree returns its destination path.
1384 src_dir = self.mkdtemp()
1385 dst_dir = self.mkdtemp()
1386 dst_file = os.path.join(dst_dir, 'bar')
1387 src_file = os.path.join(src_dir, 'foo')
1388 write_file(src_file, 'foo')
1389 rv = shutil.copyfile(src_file, dst_file)
1390 self.assertTrue(os.path.exists(rv))
1391 self.assertEqual(read_file(src_file), read_file(dst_file))
1392
Hynek Schlawack48653762012-10-07 12:49:58 +02001393 def test_copyfile_same_file(self):
1394 # copyfile() should raise SameFileError if the source and destination
1395 # are the same.
1396 src_dir = self.mkdtemp()
1397 src_file = os.path.join(src_dir, 'foo')
1398 write_file(src_file, 'foo')
1399 self.assertRaises(SameFileError, shutil.copyfile, src_file, src_file)
Hynek Schlawack27ddb572012-10-28 13:59:27 +01001400 # But Error should work too, to stay backward compatible.
1401 self.assertRaises(Error, shutil.copyfile, src_file, src_file)
Hynek Schlawack48653762012-10-07 12:49:58 +02001402
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001403 def test_copytree_return_value(self):
1404 # copytree returns its destination path.
1405 src_dir = self.mkdtemp()
1406 dst_dir = src_dir + "dest"
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001407 self.addCleanup(shutil.rmtree, dst_dir, True)
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001408 src = os.path.join(src_dir, 'foo')
1409 write_file(src, 'foo')
1410 rv = shutil.copytree(src_dir, dst_dir)
1411 self.assertEqual(['foo'], os.listdir(rv))
1412
Christian Heimes9bd667a2008-01-20 15:14:11 +00001413
Brian Curtinc57a3452012-06-22 16:00:30 -05001414class TestWhich(unittest.TestCase):
1415
1416 def setUp(self):
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001417 self.temp_dir = tempfile.mkdtemp(prefix="Tmp")
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001418 self.addCleanup(shutil.rmtree, self.temp_dir, True)
Brian Curtinc57a3452012-06-22 16:00:30 -05001419 # Give the temp_file an ".exe" suffix for all.
1420 # It's needed on Windows and not harmful on other platforms.
1421 self.temp_file = tempfile.NamedTemporaryFile(dir=self.temp_dir,
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001422 prefix="Tmp",
1423 suffix=".Exe")
Brian Curtinc57a3452012-06-22 16:00:30 -05001424 os.chmod(self.temp_file.name, stat.S_IXUSR)
1425 self.addCleanup(self.temp_file.close)
1426 self.dir, self.file = os.path.split(self.temp_file.name)
1427
1428 def test_basic(self):
1429 # Given an EXE in a directory, it should be returned.
1430 rv = shutil.which(self.file, path=self.dir)
1431 self.assertEqual(rv, self.temp_file.name)
1432
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001433 def test_absolute_cmd(self):
Brian Curtinc57a3452012-06-22 16:00:30 -05001434 # When given the fully qualified path to an executable that exists,
1435 # it should be returned.
1436 rv = shutil.which(self.temp_file.name, path=self.temp_dir)
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001437 self.assertEqual(rv, self.temp_file.name)
1438
1439 def test_relative_cmd(self):
1440 # When given the relative path with a directory part to an executable
1441 # that exists, it should be returned.
1442 base_dir, tail_dir = os.path.split(self.dir)
1443 relpath = os.path.join(tail_dir, self.file)
Nick Coghlan55175962013-07-28 22:11:50 +10001444 with support.change_cwd(path=base_dir):
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001445 rv = shutil.which(relpath, path=self.temp_dir)
1446 self.assertEqual(rv, relpath)
1447 # But it shouldn't be searched in PATH directories (issue #16957).
Nick Coghlan55175962013-07-28 22:11:50 +10001448 with support.change_cwd(path=self.dir):
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001449 rv = shutil.which(relpath, path=base_dir)
1450 self.assertIsNone(rv)
1451
1452 def test_cwd(self):
1453 # Issue #16957
1454 base_dir = os.path.dirname(self.dir)
Nick Coghlan55175962013-07-28 22:11:50 +10001455 with support.change_cwd(path=self.dir):
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001456 rv = shutil.which(self.file, path=base_dir)
1457 if sys.platform == "win32":
1458 # Windows: current directory implicitly on PATH
1459 self.assertEqual(rv, os.path.join(os.curdir, self.file))
1460 else:
1461 # Other platforms: shouldn't match in the current directory.
1462 self.assertIsNone(rv)
Brian Curtinc57a3452012-06-22 16:00:30 -05001463
Serhiy Storchaka12516e22013-05-28 15:50:15 +03001464 @unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0,
1465 'non-root user required')
Brian Curtinc57a3452012-06-22 16:00:30 -05001466 def test_non_matching_mode(self):
1467 # Set the file read-only and ask for writeable files.
1468 os.chmod(self.temp_file.name, stat.S_IREAD)
Serhiy Storchaka12516e22013-05-28 15:50:15 +03001469 if os.access(self.temp_file.name, os.W_OK):
1470 self.skipTest("can't set the file read-only")
Brian Curtinc57a3452012-06-22 16:00:30 -05001471 rv = shutil.which(self.file, path=self.dir, mode=os.W_OK)
1472 self.assertIsNone(rv)
1473
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001474 def test_relative_path(self):
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001475 base_dir, tail_dir = os.path.split(self.dir)
Nick Coghlan55175962013-07-28 22:11:50 +10001476 with support.change_cwd(path=base_dir):
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001477 rv = shutil.which(self.file, path=tail_dir)
1478 self.assertEqual(rv, os.path.join(tail_dir, self.file))
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001479
Brian Curtinc57a3452012-06-22 16:00:30 -05001480 def test_nonexistent_file(self):
1481 # Return None when no matching executable file is found on the path.
1482 rv = shutil.which("foo.exe", path=self.dir)
1483 self.assertIsNone(rv)
1484
1485 @unittest.skipUnless(sys.platform == "win32",
1486 "pathext check is Windows-only")
1487 def test_pathext_checking(self):
1488 # Ask for the file without the ".exe" extension, then ensure that
1489 # it gets found properly with the extension.
Serhiy Storchakad70127a2013-01-24 20:03:49 +02001490 rv = shutil.which(self.file[:-4], path=self.dir)
Serhiy Storchaka80c88f42013-01-22 10:31:36 +02001491 self.assertEqual(rv, self.temp_file.name[:-4] + ".EXE")
Brian Curtinc57a3452012-06-22 16:00:30 -05001492
Barry Warsaw618738b2013-04-16 11:05:03 -04001493 def test_environ_path(self):
1494 with support.EnvironmentVarGuard() as env:
Victor Stinner1d006a22013-12-16 23:39:40 +01001495 env['PATH'] = self.dir
Barry Warsaw618738b2013-04-16 11:05:03 -04001496 rv = shutil.which(self.file)
1497 self.assertEqual(rv, self.temp_file.name)
1498
1499 def test_empty_path(self):
1500 base_dir = os.path.dirname(self.dir)
Nick Coghlan55175962013-07-28 22:11:50 +10001501 with support.change_cwd(path=self.dir), \
Barry Warsaw618738b2013-04-16 11:05:03 -04001502 support.EnvironmentVarGuard() as env:
Victor Stinner1d006a22013-12-16 23:39:40 +01001503 env['PATH'] = self.dir
Barry Warsaw618738b2013-04-16 11:05:03 -04001504 rv = shutil.which(self.file, path='')
1505 self.assertIsNone(rv)
1506
1507 def test_empty_path_no_PATH(self):
1508 with support.EnvironmentVarGuard() as env:
1509 env.pop('PATH', None)
1510 rv = shutil.which(self.file)
1511 self.assertIsNone(rv)
1512
Brian Curtinc57a3452012-06-22 16:00:30 -05001513
Christian Heimesada8c3b2008-03-18 18:26:33 +00001514class TestMove(unittest.TestCase):
1515
1516 def setUp(self):
1517 filename = "foo"
1518 self.src_dir = tempfile.mkdtemp()
1519 self.dst_dir = tempfile.mkdtemp()
1520 self.src_file = os.path.join(self.src_dir, filename)
1521 self.dst_file = os.path.join(self.dst_dir, filename)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001522 with open(self.src_file, "wb") as f:
1523 f.write(b"spam")
1524
1525 def tearDown(self):
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001526 for d in (self.src_dir, self.dst_dir):
Christian Heimesada8c3b2008-03-18 18:26:33 +00001527 try:
1528 if d:
1529 shutil.rmtree(d)
1530 except:
1531 pass
1532
1533 def _check_move_file(self, src, dst, real_dst):
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001534 with open(src, "rb") as f:
1535 contents = f.read()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001536 shutil.move(src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001537 with open(real_dst, "rb") as f:
1538 self.assertEqual(contents, f.read())
Christian Heimesada8c3b2008-03-18 18:26:33 +00001539 self.assertFalse(os.path.exists(src))
1540
1541 def _check_move_dir(self, src, dst, real_dst):
1542 contents = sorted(os.listdir(src))
1543 shutil.move(src, dst)
1544 self.assertEqual(contents, sorted(os.listdir(real_dst)))
1545 self.assertFalse(os.path.exists(src))
1546
1547 def test_move_file(self):
1548 # Move a file to another location on the same filesystem.
1549 self._check_move_file(self.src_file, self.dst_file, self.dst_file)
1550
1551 def test_move_file_to_dir(self):
1552 # Move a file inside an existing dir on the same filesystem.
1553 self._check_move_file(self.src_file, self.dst_dir, self.dst_file)
1554
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001555 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001556 def test_move_file_other_fs(self):
1557 # Move a file to an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001558 self.test_move_file()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001559
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001560 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001561 def test_move_file_to_dir_other_fs(self):
1562 # Move a file to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001563 self.test_move_file_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001564
1565 def test_move_dir(self):
1566 # Move a dir to another location on the same filesystem.
1567 dst_dir = tempfile.mktemp()
1568 try:
1569 self._check_move_dir(self.src_dir, dst_dir, dst_dir)
1570 finally:
1571 try:
1572 shutil.rmtree(dst_dir)
1573 except:
1574 pass
1575
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001576 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001577 def test_move_dir_other_fs(self):
1578 # Move a dir to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001579 self.test_move_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001580
1581 def test_move_dir_to_dir(self):
1582 # Move a dir inside an existing dir on the same filesystem.
1583 self._check_move_dir(self.src_dir, self.dst_dir,
1584 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1585
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001586 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001587 def test_move_dir_to_dir_other_fs(self):
1588 # Move a dir inside an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001589 self.test_move_dir_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001590
Serhiy Storchaka3a308b92014-02-11 10:30:59 +02001591 def test_move_dir_sep_to_dir(self):
1592 self._check_move_dir(self.src_dir + os.path.sep, self.dst_dir,
1593 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1594
1595 @unittest.skipUnless(os.path.altsep, 'requires os.path.altsep')
1596 def test_move_dir_altsep_to_dir(self):
1597 self._check_move_dir(self.src_dir + os.path.altsep, self.dst_dir,
1598 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1599
Christian Heimesada8c3b2008-03-18 18:26:33 +00001600 def test_existing_file_inside_dest_dir(self):
1601 # A file with the same name inside the destination dir already exists.
1602 with open(self.dst_file, "wb"):
1603 pass
1604 self.assertRaises(shutil.Error, shutil.move, self.src_file, self.dst_dir)
1605
1606 def test_dont_move_dir_in_itself(self):
1607 # Moving a dir inside itself raises an Error.
1608 dst = os.path.join(self.src_dir, "bar")
1609 self.assertRaises(shutil.Error, shutil.move, self.src_dir, dst)
1610
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001611 def test_destinsrc_false_negative(self):
1612 os.mkdir(TESTFN)
1613 try:
1614 for src, dst in [('srcdir', 'srcdir/dest')]:
1615 src = os.path.join(TESTFN, src)
1616 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001617 self.assertTrue(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001618 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001619 'dst (%s) is not in src (%s)' % (dst, src))
1620 finally:
1621 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001622
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001623 def test_destinsrc_false_positive(self):
1624 os.mkdir(TESTFN)
1625 try:
1626 for src, dst in [('srcdir', 'src/dest'), ('srcdir', 'srcdir.new')]:
1627 src = os.path.join(TESTFN, src)
1628 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001629 self.assertFalse(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001630 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001631 'dst (%s) is in src (%s)' % (dst, src))
1632 finally:
1633 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimes9bd667a2008-01-20 15:14:11 +00001634
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +01001635 @support.skip_unless_symlink
1636 @mock_rename
1637 def test_move_file_symlink(self):
1638 dst = os.path.join(self.src_dir, 'bar')
1639 os.symlink(self.src_file, dst)
1640 shutil.move(dst, self.dst_file)
1641 self.assertTrue(os.path.islink(self.dst_file))
1642 self.assertTrue(os.path.samefile(self.src_file, self.dst_file))
1643
1644 @support.skip_unless_symlink
1645 @mock_rename
1646 def test_move_file_symlink_to_dir(self):
1647 filename = "bar"
1648 dst = os.path.join(self.src_dir, filename)
1649 os.symlink(self.src_file, dst)
1650 shutil.move(dst, self.dst_dir)
1651 final_link = os.path.join(self.dst_dir, filename)
1652 self.assertTrue(os.path.islink(final_link))
1653 self.assertTrue(os.path.samefile(self.src_file, final_link))
1654
1655 @support.skip_unless_symlink
1656 @mock_rename
1657 def test_move_dangling_symlink(self):
1658 src = os.path.join(self.src_dir, 'baz')
1659 dst = os.path.join(self.src_dir, 'bar')
1660 os.symlink(src, dst)
1661 dst_link = os.path.join(self.dst_dir, 'quux')
1662 shutil.move(dst, dst_link)
1663 self.assertTrue(os.path.islink(dst_link))
Antoine Pitrou3f48ac92014-01-01 02:50:45 +01001664 # On Windows, os.path.realpath does not follow symlinks (issue #9949)
1665 if os.name == 'nt':
1666 self.assertEqual(os.path.realpath(src), os.readlink(dst_link))
1667 else:
1668 self.assertEqual(os.path.realpath(src), os.path.realpath(dst_link))
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +01001669
1670 @support.skip_unless_symlink
1671 @mock_rename
1672 def test_move_dir_symlink(self):
1673 src = os.path.join(self.src_dir, 'baz')
1674 dst = os.path.join(self.src_dir, 'bar')
1675 os.mkdir(src)
1676 os.symlink(src, dst)
1677 dst_link = os.path.join(self.dst_dir, 'quux')
1678 shutil.move(dst, dst_link)
1679 self.assertTrue(os.path.islink(dst_link))
1680 self.assertTrue(os.path.samefile(src, dst_link))
1681
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001682 def test_move_return_value(self):
1683 rv = shutil.move(self.src_file, self.dst_dir)
1684 self.assertEqual(rv,
1685 os.path.join(self.dst_dir, os.path.basename(self.src_file)))
1686
1687 def test_move_as_rename_return_value(self):
1688 rv = shutil.move(self.src_file, os.path.join(self.dst_dir, 'bar'))
1689 self.assertEqual(rv, os.path.join(self.dst_dir, 'bar'))
1690
R David Murray6ffface2014-06-11 14:40:13 -04001691 @mock_rename
1692 def test_move_file_special_function(self):
1693 moved = []
1694 def _copy(src, dst):
1695 moved.append((src, dst))
1696 shutil.move(self.src_file, self.dst_dir, copy_function=_copy)
1697 self.assertEqual(len(moved), 1)
1698
1699 @mock_rename
1700 def test_move_dir_special_function(self):
1701 moved = []
1702 def _copy(src, dst):
1703 moved.append((src, dst))
1704 support.create_empty_file(os.path.join(self.src_dir, 'child'))
1705 support.create_empty_file(os.path.join(self.src_dir, 'child1'))
1706 shutil.move(self.src_dir, self.dst_dir, copy_function=_copy)
1707 self.assertEqual(len(moved), 3)
1708
Tarek Ziadé5340db32010-04-19 22:30:51 +00001709
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001710class TestCopyFile(unittest.TestCase):
1711
1712 _delete = False
1713
1714 class Faux(object):
1715 _entered = False
1716 _exited_with = None
1717 _raised = False
1718 def __init__(self, raise_in_exit=False, suppress_at_exit=True):
1719 self._raise_in_exit = raise_in_exit
1720 self._suppress_at_exit = suppress_at_exit
1721 def read(self, *args):
1722 return ''
1723 def __enter__(self):
1724 self._entered = True
1725 def __exit__(self, exc_type, exc_val, exc_tb):
1726 self._exited_with = exc_type, exc_val, exc_tb
1727 if self._raise_in_exit:
1728 self._raised = True
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001729 raise OSError("Cannot close")
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001730 return self._suppress_at_exit
1731
1732 def tearDown(self):
1733 if self._delete:
1734 del shutil.open
1735
1736 def _set_shutil_open(self, func):
1737 shutil.open = func
1738 self._delete = True
1739
1740 def test_w_source_open_fails(self):
1741 def _open(filename, mode='r'):
1742 if filename == 'srcfile':
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001743 raise OSError('Cannot open "srcfile"')
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001744 assert 0 # shouldn't reach here.
1745
1746 self._set_shutil_open(_open)
1747
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001748 self.assertRaises(OSError, shutil.copyfile, 'srcfile', 'destfile')
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001749
1750 def test_w_dest_open_fails(self):
1751
1752 srcfile = self.Faux()
1753
1754 def _open(filename, mode='r'):
1755 if filename == 'srcfile':
1756 return srcfile
1757 if filename == 'destfile':
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001758 raise OSError('Cannot open "destfile"')
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001759 assert 0 # shouldn't reach here.
1760
1761 self._set_shutil_open(_open)
1762
1763 shutil.copyfile('srcfile', 'destfile')
1764 self.assertTrue(srcfile._entered)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001765 self.assertTrue(srcfile._exited_with[0] is OSError)
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001766 self.assertEqual(srcfile._exited_with[1].args,
1767 ('Cannot open "destfile"',))
1768
1769 def test_w_dest_close_fails(self):
1770
1771 srcfile = self.Faux()
1772 destfile = self.Faux(True)
1773
1774 def _open(filename, mode='r'):
1775 if filename == 'srcfile':
1776 return srcfile
1777 if filename == 'destfile':
1778 return destfile
1779 assert 0 # shouldn't reach here.
1780
1781 self._set_shutil_open(_open)
1782
1783 shutil.copyfile('srcfile', 'destfile')
1784 self.assertTrue(srcfile._entered)
1785 self.assertTrue(destfile._entered)
1786 self.assertTrue(destfile._raised)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001787 self.assertTrue(srcfile._exited_with[0] is OSError)
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001788 self.assertEqual(srcfile._exited_with[1].args,
1789 ('Cannot close',))
1790
1791 def test_w_source_close_fails(self):
1792
1793 srcfile = self.Faux(True)
1794 destfile = self.Faux()
1795
1796 def _open(filename, mode='r'):
1797 if filename == 'srcfile':
1798 return srcfile
1799 if filename == 'destfile':
1800 return destfile
1801 assert 0 # shouldn't reach here.
1802
1803 self._set_shutil_open(_open)
1804
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001805 self.assertRaises(OSError,
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001806 shutil.copyfile, 'srcfile', 'destfile')
1807 self.assertTrue(srcfile._entered)
1808 self.assertTrue(destfile._entered)
1809 self.assertFalse(destfile._raised)
1810 self.assertTrue(srcfile._exited_with[0] is None)
1811 self.assertTrue(srcfile._raised)
1812
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001813 def test_move_dir_caseinsensitive(self):
1814 # Renames a folder to the same name
1815 # but a different case.
1816
1817 self.src_dir = tempfile.mkdtemp()
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001818 self.addCleanup(shutil.rmtree, self.src_dir, True)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001819 dst_dir = os.path.join(
1820 os.path.dirname(self.src_dir),
1821 os.path.basename(self.src_dir).upper())
1822 self.assertNotEqual(self.src_dir, dst_dir)
1823
1824 try:
1825 shutil.move(self.src_dir, dst_dir)
1826 self.assertTrue(os.path.isdir(dst_dir))
1827 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +02001828 os.rmdir(dst_dir)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001829
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001830class TermsizeTests(unittest.TestCase):
1831 def test_does_not_crash(self):
1832 """Check if get_terminal_size() returns a meaningful value.
1833
1834 There's no easy portable way to actually check the size of the
1835 terminal, so let's check if it returns something sensible instead.
1836 """
1837 size = shutil.get_terminal_size()
Antoine Pitroucfade362012-02-08 23:48:59 +01001838 self.assertGreaterEqual(size.columns, 0)
1839 self.assertGreaterEqual(size.lines, 0)
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001840
1841 def test_os_environ_first(self):
1842 "Check if environment variables have precedence"
1843
1844 with support.EnvironmentVarGuard() as env:
1845 env['COLUMNS'] = '777'
Serhiy Storchakad30829d2016-04-24 09:58:43 +03001846 del env['LINES']
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001847 size = shutil.get_terminal_size()
1848 self.assertEqual(size.columns, 777)
1849
1850 with support.EnvironmentVarGuard() as env:
Serhiy Storchakad30829d2016-04-24 09:58:43 +03001851 del env['COLUMNS']
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001852 env['LINES'] = '888'
1853 size = shutil.get_terminal_size()
1854 self.assertEqual(size.lines, 888)
1855
Serhiy Storchakad30829d2016-04-24 09:58:43 +03001856 def test_bad_environ(self):
1857 with support.EnvironmentVarGuard() as env:
1858 env['COLUMNS'] = 'xxx'
1859 env['LINES'] = 'yyy'
1860 size = shutil.get_terminal_size()
1861 self.assertGreaterEqual(size.columns, 0)
1862 self.assertGreaterEqual(size.lines, 0)
1863
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001864 @unittest.skipUnless(os.isatty(sys.__stdout__.fileno()), "not on tty")
Victor Stinner119ebb72016-04-19 22:24:56 +02001865 @unittest.skipUnless(hasattr(os, 'get_terminal_size'),
1866 'need os.get_terminal_size()')
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001867 def test_stty_match(self):
1868 """Check if stty returns the same results ignoring env
1869
1870 This test will fail if stdin and stdout are connected to
1871 different terminals with different sizes. Nevertheless, such
1872 situations should be pretty rare.
1873 """
1874 try:
1875 size = subprocess.check_output(['stty', 'size']).decode().split()
Xavier de Gaye38c8b7d2016-11-14 17:14:42 +01001876 except (FileNotFoundError, PermissionError,
1877 subprocess.CalledProcessError):
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001878 self.skipTest("stty invocation failed")
1879 expected = (int(size[1]), int(size[0])) # reversed order
1880
1881 with support.EnvironmentVarGuard() as env:
1882 del env['LINES']
1883 del env['COLUMNS']
1884 actual = shutil.get_terminal_size()
1885
1886 self.assertEqual(expected, actual)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001887
Serhiy Storchakad30829d2016-04-24 09:58:43 +03001888 def test_fallback(self):
1889 with support.EnvironmentVarGuard() as env:
1890 del env['LINES']
1891 del env['COLUMNS']
1892
1893 # sys.__stdout__ has no fileno()
1894 with support.swap_attr(sys, '__stdout__', None):
1895 size = shutil.get_terminal_size(fallback=(10, 20))
1896 self.assertEqual(size.columns, 10)
1897 self.assertEqual(size.lines, 20)
1898
1899 # sys.__stdout__ is not a terminal on Unix
1900 # or fileno() not in (0, 1, 2) on Windows
1901 with open(os.devnull, 'w') as f, \
1902 support.swap_attr(sys, '__stdout__', f):
1903 size = shutil.get_terminal_size(fallback=(30, 40))
1904 self.assertEqual(size.columns, 30)
1905 self.assertEqual(size.lines, 40)
1906
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001907
Berker Peksag8083cd62014-11-01 11:04:06 +02001908class PublicAPITests(unittest.TestCase):
1909 """Ensures that the correct values are exposed in the public API."""
1910
1911 def test_module_all_attribute(self):
1912 self.assertTrue(hasattr(shutil, '__all__'))
1913 target_api = ['copyfileobj', 'copyfile', 'copymode', 'copystat',
1914 'copy', 'copy2', 'copytree', 'move', 'rmtree', 'Error',
1915 'SpecialFileError', 'ExecError', 'make_archive',
1916 'get_archive_formats', 'register_archive_format',
1917 'unregister_archive_format', 'get_unpack_formats',
1918 'register_unpack_format', 'unregister_unpack_format',
1919 'unpack_archive', 'ignore_patterns', 'chown', 'which',
1920 'get_terminal_size', 'SameFileError']
1921 if hasattr(os, 'statvfs') or os.name == 'nt':
1922 target_api.append('disk_usage')
1923 self.assertEqual(set(shutil.__all__), set(target_api))
1924
1925
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001926if __name__ == '__main__':
Brett Cannon3e9a9ae2013-06-12 21:25:59 -04001927 unittest.main()