blob: 3688eae9470c5d0eb875adfd184bd1c057cfc909 [file] [log] [blame]
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001# Copyright (C) 2003 Python Software Foundation
2
3import unittest
Berker Peksag884afd92014-12-10 02:50:32 +02004import unittest.mock
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00005import shutil
6import tempfile
Johannes Gijsbers8e6f2de2004-11-23 09:27:27 +00007import sys
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +00008import stat
Brett Cannon1c3fa182004-06-19 21:11:35 +00009import os
10import os.path
Antoine Pitrouc041ab62012-01-02 19:18:02 +010011import errno
Nick Coghlan8ed3cf32011-03-16 14:05:35 -040012import functools
Antoine Pitroubcf2b592012-02-08 23:28:36 +010013import subprocess
Serhiy Storchaka41ad77c2014-08-07 19:38:37 +030014from contextlib import ExitStack
Serhiy Storchaka527ef072015-09-06 18:33:19 +030015from shutil import (make_archive,
Tarek Ziadé396fad72010-02-23 05:30:31 +000016 register_archive_format, unregister_archive_format,
Tarek Ziadé6ac91722010-04-28 17:51:36 +000017 get_archive_formats, Error, unpack_archive,
18 register_unpack_format, RegistryError,
Hynek Schlawack48653762012-10-07 12:49:58 +020019 unregister_unpack_format, get_unpack_formats,
20 SameFileError)
Tarek Ziadé396fad72010-02-23 05:30:31 +000021import tarfile
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +020022import zipfile
Tarek Ziadé396fad72010-02-23 05:30:31 +000023
24from test import support
Xavier de Gaye3a4e9892016-12-13 10:00:01 +010025from test.support import (TESTFN, check_warnings, captured_stdout,
Serhiy Storchaka9bb6fe52016-12-16 19:00:55 +020026 android_not_root)
Serhiy Storchaka11213772014-08-06 18:50:19 +030027
Antoine Pitrou7fff0962009-05-01 21:09:44 +000028TESTFN2 = TESTFN + "2"
Barry Warsaw7fc2cca2003-01-24 17:34:13 +000029
Tarek Ziadé396fad72010-02-23 05:30:31 +000030try:
31 import grp
32 import pwd
33 UID_GID_SUPPORT = True
34except ImportError:
35 UID_GID_SUPPORT = False
36
Nick Coghlan8ed3cf32011-03-16 14:05:35 -040037def _fake_rename(*args, **kwargs):
38 # Pretend the destination path is on a different filesystem.
Antoine Pitrouc041ab62012-01-02 19:18:02 +010039 raise OSError(getattr(errno, 'EXDEV', 18), "Invalid cross-device link")
Nick Coghlan8ed3cf32011-03-16 14:05:35 -040040
41def mock_rename(func):
42 @functools.wraps(func)
43 def wrap(*args, **kwargs):
44 try:
45 builtin_rename = os.rename
46 os.rename = _fake_rename
47 return func(*args, **kwargs)
48 finally:
49 os.rename = builtin_rename
50 return wrap
51
Éric Araujoa7e33a12011-08-12 19:51:35 +020052def write_file(path, content, binary=False):
53 """Write *content* to a file located at *path*.
54
55 If *path* is a tuple instead of a string, os.path.join will be used to
56 make a path. If *binary* is true, the file will be opened in binary
57 mode.
58 """
59 if isinstance(path, tuple):
60 path = os.path.join(*path)
61 with open(path, 'wb' if binary else 'w') as fp:
62 fp.write(content)
63
64def read_file(path, binary=False):
65 """Return contents from a file located at *path*.
66
67 If *path* is a tuple instead of a string, os.path.join will be used to
68 make a path. If *binary* is true, the file will be opened in binary
69 mode.
70 """
71 if isinstance(path, tuple):
72 path = os.path.join(*path)
73 with open(path, 'rb' if binary else 'r') as fp:
74 return fp.read()
75
Serhiy Storchaka527ef072015-09-06 18:33:19 +030076def rlistdir(path):
77 res = []
78 for name in sorted(os.listdir(path)):
79 p = os.path.join(path, name)
80 if os.path.isdir(p) and not os.path.islink(p):
81 res.append(name + '/')
82 for n in rlistdir(p):
83 res.append(name + '/' + n)
84 else:
85 res.append(name)
86 return res
87
Éric Araujoa7e33a12011-08-12 19:51:35 +020088
Barry Warsaw7fc2cca2003-01-24 17:34:13 +000089class TestShutil(unittest.TestCase):
Tarek Ziadé396fad72010-02-23 05:30:31 +000090
91 def setUp(self):
92 super(TestShutil, self).setUp()
93 self.tempdirs = []
94
95 def tearDown(self):
96 super(TestShutil, self).tearDown()
97 while self.tempdirs:
98 d = self.tempdirs.pop()
99 shutil.rmtree(d, os.name in ('nt', 'cygwin'))
100
Tarek Ziadé396fad72010-02-23 05:30:31 +0000101
102 def mkdtemp(self):
103 """Create a temporary directory that will be cleaned up.
104
105 Returns the path of the directory.
106 """
107 d = tempfile.mkdtemp()
108 self.tempdirs.append(d)
109 return d
Tarek Ziadé5340db32010-04-19 22:30:51 +0000110
Hynek Schlawack3b527782012-06-25 13:27:31 +0200111 def test_rmtree_works_on_bytes(self):
112 tmp = self.mkdtemp()
113 victim = os.path.join(tmp, 'killme')
114 os.mkdir(victim)
115 write_file(os.path.join(victim, 'somefile'), 'foo')
116 victim = os.fsencode(victim)
117 self.assertIsInstance(victim, bytes)
Steve Dowere58571b2016-09-08 11:11:13 -0700118 shutil.rmtree(victim)
Hynek Schlawack3b527782012-06-25 13:27:31 +0200119
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200120 @support.skip_unless_symlink
121 def test_rmtree_fails_on_symlink(self):
122 tmp = self.mkdtemp()
123 dir_ = os.path.join(tmp, 'dir')
124 os.mkdir(dir_)
125 link = os.path.join(tmp, 'link')
126 os.symlink(dir_, link)
127 self.assertRaises(OSError, shutil.rmtree, link)
128 self.assertTrue(os.path.exists(dir_))
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100129 self.assertTrue(os.path.lexists(link))
130 errors = []
131 def onerror(*args):
132 errors.append(args)
133 shutil.rmtree(link, onerror=onerror)
134 self.assertEqual(len(errors), 1)
135 self.assertIs(errors[0][0], os.path.islink)
136 self.assertEqual(errors[0][1], link)
137 self.assertIsInstance(errors[0][2][1], OSError)
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200138
139 @support.skip_unless_symlink
140 def test_rmtree_works_on_symlinks(self):
141 tmp = self.mkdtemp()
142 dir1 = os.path.join(tmp, 'dir1')
143 dir2 = os.path.join(dir1, 'dir2')
144 dir3 = os.path.join(tmp, 'dir3')
145 for d in dir1, dir2, dir3:
146 os.mkdir(d)
147 file1 = os.path.join(tmp, 'file1')
148 write_file(file1, 'foo')
149 link1 = os.path.join(dir1, 'link1')
150 os.symlink(dir2, link1)
151 link2 = os.path.join(dir1, 'link2')
152 os.symlink(dir3, link2)
153 link3 = os.path.join(dir1, 'link3')
154 os.symlink(file1, link3)
155 # make sure symlinks are removed but not followed
156 shutil.rmtree(dir1)
157 self.assertFalse(os.path.exists(dir1))
158 self.assertTrue(os.path.exists(dir3))
159 self.assertTrue(os.path.exists(file1))
160
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000161 def test_rmtree_errors(self):
162 # filename is guaranteed not to exist
163 filename = tempfile.mktemp()
Hynek Schlawackb5501102012-12-10 09:11:25 +0100164 self.assertRaises(FileNotFoundError, shutil.rmtree, filename)
165 # test that ignore_errors option is honored
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100166 shutil.rmtree(filename, ignore_errors=True)
167
168 # existing file
169 tmpdir = self.mkdtemp()
Hynek Schlawackb5501102012-12-10 09:11:25 +0100170 write_file((tmpdir, "tstfile"), "")
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100171 filename = os.path.join(tmpdir, "tstfile")
Hynek Schlawackb5501102012-12-10 09:11:25 +0100172 with self.assertRaises(NotADirectoryError) as cm:
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100173 shutil.rmtree(filename)
Hynek Schlawack87f9b462012-12-10 16:29:57 +0100174 # The reason for this rather odd construct is that Windows sprinkles
175 # a \*.* at the end of file names. But only sometimes on some buildbots
176 possible_args = [filename, os.path.join(filename, '*.*')]
177 self.assertIn(cm.exception.filename, possible_args)
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100178 self.assertTrue(os.path.exists(filename))
Hynek Schlawackb5501102012-12-10 09:11:25 +0100179 # test that ignore_errors option is honored
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100180 shutil.rmtree(filename, ignore_errors=True)
181 self.assertTrue(os.path.exists(filename))
182 errors = []
183 def onerror(*args):
184 errors.append(args)
185 shutil.rmtree(filename, onerror=onerror)
186 self.assertEqual(len(errors), 2)
187 self.assertIs(errors[0][0], os.listdir)
188 self.assertEqual(errors[0][1], filename)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100189 self.assertIsInstance(errors[0][2][1], NotADirectoryError)
Hynek Schlawack87f9b462012-12-10 16:29:57 +0100190 self.assertIn(errors[0][2][1].filename, possible_args)
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100191 self.assertIs(errors[1][0], os.rmdir)
192 self.assertEqual(errors[1][1], filename)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100193 self.assertIsInstance(errors[1][2][1], NotADirectoryError)
Hynek Schlawack87f9b462012-12-10 16:29:57 +0100194 self.assertIn(errors[1][2][1].filename, possible_args)
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000195
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000196
Serhiy Storchaka43767632013-11-03 21:31:38 +0200197 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod()')
198 @unittest.skipIf(sys.platform[:6] == 'cygwin',
199 "This test can't be run on Cygwin (issue #1071513).")
200 @unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0,
201 "This test can't be run reliably as root (issue #1076467).")
202 def test_on_error(self):
203 self.errorState = 0
204 os.mkdir(TESTFN)
205 self.addCleanup(shutil.rmtree, TESTFN)
Antoine Pitrou2f8a75c2012-06-23 21:28:15 +0200206
Serhiy Storchaka43767632013-11-03 21:31:38 +0200207 self.child_file_path = os.path.join(TESTFN, 'a')
208 self.child_dir_path = os.path.join(TESTFN, 'b')
209 support.create_empty_file(self.child_file_path)
210 os.mkdir(self.child_dir_path)
211 old_dir_mode = os.stat(TESTFN).st_mode
212 old_child_file_mode = os.stat(self.child_file_path).st_mode
213 old_child_dir_mode = os.stat(self.child_dir_path).st_mode
214 # Make unwritable.
215 new_mode = stat.S_IREAD|stat.S_IEXEC
216 os.chmod(self.child_file_path, new_mode)
217 os.chmod(self.child_dir_path, new_mode)
218 os.chmod(TESTFN, new_mode)
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000219
Serhiy Storchaka43767632013-11-03 21:31:38 +0200220 self.addCleanup(os.chmod, TESTFN, old_dir_mode)
221 self.addCleanup(os.chmod, self.child_file_path, old_child_file_mode)
222 self.addCleanup(os.chmod, self.child_dir_path, old_child_dir_mode)
Antoine Pitrou2f8a75c2012-06-23 21:28:15 +0200223
Serhiy Storchaka43767632013-11-03 21:31:38 +0200224 shutil.rmtree(TESTFN, onerror=self.check_args_to_onerror)
225 # Test whether onerror has actually been called.
226 self.assertEqual(self.errorState, 3,
227 "Expected call to onerror function did not happen.")
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000228
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000229 def check_args_to_onerror(self, func, arg, exc):
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000230 # test_rmtree_errors deliberately runs rmtree
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200231 # on a directory that is chmod 500, which will fail.
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000232 # This function is run when shutil.rmtree fails.
233 # 99.9% of the time it initially fails to remove
234 # a file in the directory, so the first time through
235 # func is os.remove.
236 # However, some Linux machines running ZFS on
237 # FUSE experienced a failure earlier in the process
238 # at os.listdir. The first failure may legally
239 # be either.
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200240 if self.errorState < 2:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200241 if func is os.unlink:
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200242 self.assertEqual(arg, self.child_file_path)
243 elif func is os.rmdir:
244 self.assertEqual(arg, self.child_dir_path)
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000245 else:
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200246 self.assertIs(func, os.listdir)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200247 self.assertIn(arg, [TESTFN, self.child_dir_path])
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000248 self.assertTrue(issubclass(exc[0], OSError))
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200249 self.errorState += 1
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000250 else:
251 self.assertEqual(func, os.rmdir)
252 self.assertEqual(arg, TESTFN)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000253 self.assertTrue(issubclass(exc[0], OSError))
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200254 self.errorState = 3
255
256 def test_rmtree_does_not_choke_on_failing_lstat(self):
257 try:
258 orig_lstat = os.lstat
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200259 def raiser(fn, *args, **kwargs):
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200260 if fn != TESTFN:
261 raise OSError()
262 else:
263 return orig_lstat(fn)
264 os.lstat = raiser
265
266 os.mkdir(TESTFN)
267 write_file((TESTFN, 'foo'), 'foo')
268 shutil.rmtree(TESTFN)
269 finally:
270 os.lstat = orig_lstat
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000271
Antoine Pitrou78091e62011-12-29 18:54:15 +0100272 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
273 @support.skip_unless_symlink
274 def test_copymode_follow_symlinks(self):
275 tmp_dir = self.mkdtemp()
276 src = os.path.join(tmp_dir, 'foo')
277 dst = os.path.join(tmp_dir, 'bar')
278 src_link = os.path.join(tmp_dir, 'baz')
279 dst_link = os.path.join(tmp_dir, 'quux')
280 write_file(src, 'foo')
281 write_file(dst, 'foo')
282 os.symlink(src, src_link)
283 os.symlink(dst, dst_link)
284 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
285 # file to file
286 os.chmod(dst, stat.S_IRWXO)
287 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
288 shutil.copymode(src, dst)
289 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
Antoine Pitrou3f48ac92014-01-01 02:50:45 +0100290 # On Windows, os.chmod does not follow symlinks (issue #15411)
291 if os.name != 'nt':
292 # follow src link
293 os.chmod(dst, stat.S_IRWXO)
294 shutil.copymode(src_link, dst)
295 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
296 # follow dst link
297 os.chmod(dst, stat.S_IRWXO)
298 shutil.copymode(src, dst_link)
299 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
300 # follow both links
301 os.chmod(dst, stat.S_IRWXO)
302 shutil.copymode(src_link, dst_link)
303 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100304
305 @unittest.skipUnless(hasattr(os, 'lchmod'), 'requires os.lchmod')
306 @support.skip_unless_symlink
307 def test_copymode_symlink_to_symlink(self):
308 tmp_dir = self.mkdtemp()
309 src = os.path.join(tmp_dir, 'foo')
310 dst = os.path.join(tmp_dir, 'bar')
311 src_link = os.path.join(tmp_dir, 'baz')
312 dst_link = os.path.join(tmp_dir, 'quux')
313 write_file(src, 'foo')
314 write_file(dst, 'foo')
315 os.symlink(src, src_link)
316 os.symlink(dst, dst_link)
317 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
318 os.chmod(dst, stat.S_IRWXU)
319 os.lchmod(src_link, stat.S_IRWXO|stat.S_IRWXG)
320 # link to link
321 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700322 shutil.copymode(src_link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100323 self.assertEqual(os.lstat(src_link).st_mode,
324 os.lstat(dst_link).st_mode)
325 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
326 # src link - use chmod
327 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700328 shutil.copymode(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100329 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
330 # dst link - use chmod
331 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700332 shutil.copymode(src, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100333 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
334
335 @unittest.skipIf(hasattr(os, 'lchmod'), 'requires os.lchmod to be missing')
336 @support.skip_unless_symlink
337 def test_copymode_symlink_to_symlink_wo_lchmod(self):
338 tmp_dir = self.mkdtemp()
339 src = os.path.join(tmp_dir, 'foo')
340 dst = os.path.join(tmp_dir, 'bar')
341 src_link = os.path.join(tmp_dir, 'baz')
342 dst_link = os.path.join(tmp_dir, 'quux')
343 write_file(src, 'foo')
344 write_file(dst, 'foo')
345 os.symlink(src, src_link)
346 os.symlink(dst, dst_link)
Larry Hastingsb4038062012-07-15 10:57:38 -0700347 shutil.copymode(src_link, dst_link, follow_symlinks=False) # silent fail
Antoine Pitrou78091e62011-12-29 18:54:15 +0100348
349 @support.skip_unless_symlink
350 def test_copystat_symlinks(self):
351 tmp_dir = self.mkdtemp()
352 src = os.path.join(tmp_dir, 'foo')
353 dst = os.path.join(tmp_dir, 'bar')
354 src_link = os.path.join(tmp_dir, 'baz')
355 dst_link = os.path.join(tmp_dir, 'qux')
356 write_file(src, 'foo')
357 src_stat = os.stat(src)
358 os.utime(src, (src_stat.st_atime,
359 src_stat.st_mtime - 42.0)) # ensure different mtimes
360 write_file(dst, 'bar')
361 self.assertNotEqual(os.stat(src).st_mtime, os.stat(dst).st_mtime)
362 os.symlink(src, src_link)
363 os.symlink(dst, dst_link)
364 if hasattr(os, 'lchmod'):
365 os.lchmod(src_link, stat.S_IRWXO)
366 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
367 os.lchflags(src_link, stat.UF_NODUMP)
368 src_link_stat = os.lstat(src_link)
369 # follow
370 if hasattr(os, 'lchmod'):
Larry Hastingsb4038062012-07-15 10:57:38 -0700371 shutil.copystat(src_link, dst_link, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100372 self.assertNotEqual(src_link_stat.st_mode, os.stat(dst).st_mode)
373 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700374 shutil.copystat(src_link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100375 dst_link_stat = os.lstat(dst_link)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700376 if os.utime in os.supports_follow_symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100377 for attr in 'st_atime', 'st_mtime':
378 # The modification times may be truncated in the new file.
379 self.assertLessEqual(getattr(src_link_stat, attr),
380 getattr(dst_link_stat, attr) + 1)
381 if hasattr(os, 'lchmod'):
382 self.assertEqual(src_link_stat.st_mode, dst_link_stat.st_mode)
383 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
384 self.assertEqual(src_link_stat.st_flags, dst_link_stat.st_flags)
385 # tell to follow but dst is not a link
Larry Hastingsb4038062012-07-15 10:57:38 -0700386 shutil.copystat(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100387 self.assertTrue(abs(os.stat(src).st_mtime - os.stat(dst).st_mtime) <
388 00000.1)
389
Ned Deilybaf75712012-05-10 17:05:19 -0700390 @unittest.skipUnless(hasattr(os, 'chflags') and
391 hasattr(errno, 'EOPNOTSUPP') and
392 hasattr(errno, 'ENOTSUP'),
393 "requires os.chflags, EOPNOTSUPP & ENOTSUP")
394 def test_copystat_handles_harmless_chflags_errors(self):
395 tmpdir = self.mkdtemp()
396 file1 = os.path.join(tmpdir, 'file1')
397 file2 = os.path.join(tmpdir, 'file2')
398 write_file(file1, 'xxx')
399 write_file(file2, 'xxx')
400
401 def make_chflags_raiser(err):
402 ex = OSError()
403
Larry Hastings90867a52012-06-22 17:01:41 -0700404 def _chflags_raiser(path, flags, *, follow_symlinks=True):
Ned Deilybaf75712012-05-10 17:05:19 -0700405 ex.errno = err
406 raise ex
407 return _chflags_raiser
408 old_chflags = os.chflags
409 try:
410 for err in errno.EOPNOTSUPP, errno.ENOTSUP:
411 os.chflags = make_chflags_raiser(err)
412 shutil.copystat(file1, file2)
413 # assert others errors break it
414 os.chflags = make_chflags_raiser(errno.EOPNOTSUPP + errno.ENOTSUP)
415 self.assertRaises(OSError, shutil.copystat, file1, file2)
416 finally:
417 os.chflags = old_chflags
418
Antoine Pitrou424246f2012-05-12 19:02:01 +0200419 @support.skip_unless_xattr
420 def test_copyxattr(self):
421 tmp_dir = self.mkdtemp()
422 src = os.path.join(tmp_dir, 'foo')
423 write_file(src, 'foo')
424 dst = os.path.join(tmp_dir, 'bar')
425 write_file(dst, 'bar')
426
427 # no xattr == no problem
428 shutil._copyxattr(src, dst)
429 # common case
430 os.setxattr(src, 'user.foo', b'42')
431 os.setxattr(src, 'user.bar', b'43')
432 shutil._copyxattr(src, dst)
Gregory P. Smith1093bf22014-01-17 12:01:22 -0800433 self.assertEqual(sorted(os.listxattr(src)), sorted(os.listxattr(dst)))
Antoine Pitrou424246f2012-05-12 19:02:01 +0200434 self.assertEqual(
435 os.getxattr(src, 'user.foo'),
436 os.getxattr(dst, 'user.foo'))
437 # check errors don't affect other attrs
438 os.remove(dst)
439 write_file(dst, 'bar')
440 os_error = OSError(errno.EPERM, 'EPERM')
441
Larry Hastings9cf065c2012-06-22 16:30:09 -0700442 def _raise_on_user_foo(fname, attr, val, **kwargs):
Antoine Pitrou424246f2012-05-12 19:02:01 +0200443 if attr == 'user.foo':
444 raise os_error
445 else:
Larry Hastings9cf065c2012-06-22 16:30:09 -0700446 orig_setxattr(fname, attr, val, **kwargs)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200447 try:
448 orig_setxattr = os.setxattr
449 os.setxattr = _raise_on_user_foo
450 shutil._copyxattr(src, dst)
Antoine Pitrou61597d32012-05-12 23:37:35 +0200451 self.assertIn('user.bar', os.listxattr(dst))
Antoine Pitrou424246f2012-05-12 19:02:01 +0200452 finally:
453 os.setxattr = orig_setxattr
Hynek Schlawack0beab052013-02-05 08:22:44 +0100454 # the source filesystem not supporting xattrs should be ok, too.
455 def _raise_on_src(fname, *, follow_symlinks=True):
456 if fname == src:
457 raise OSError(errno.ENOTSUP, 'Operation not supported')
458 return orig_listxattr(fname, follow_symlinks=follow_symlinks)
459 try:
460 orig_listxattr = os.listxattr
461 os.listxattr = _raise_on_src
462 shutil._copyxattr(src, dst)
463 finally:
464 os.listxattr = orig_listxattr
Antoine Pitrou424246f2012-05-12 19:02:01 +0200465
Larry Hastingsad5ae042012-07-14 17:55:11 -0700466 # test that shutil.copystat copies xattrs
467 src = os.path.join(tmp_dir, 'the_original')
468 write_file(src, src)
469 os.setxattr(src, 'user.the_value', b'fiddly')
470 dst = os.path.join(tmp_dir, 'the_copy')
471 write_file(dst, dst)
472 shutil.copystat(src, dst)
Hynek Schlawackc2d481f2012-07-16 17:11:10 +0200473 self.assertEqual(os.getxattr(dst, 'user.the_value'), b'fiddly')
Larry Hastingsad5ae042012-07-14 17:55:11 -0700474
Antoine Pitrou424246f2012-05-12 19:02:01 +0200475 @support.skip_unless_symlink
476 @support.skip_unless_xattr
477 @unittest.skipUnless(hasattr(os, 'geteuid') and os.geteuid() == 0,
478 'root privileges required')
479 def test_copyxattr_symlinks(self):
480 # On Linux, it's only possible to access non-user xattr for symlinks;
481 # which in turn require root privileges. This test should be expanded
482 # as soon as other platforms gain support for extended attributes.
483 tmp_dir = self.mkdtemp()
484 src = os.path.join(tmp_dir, 'foo')
485 src_link = os.path.join(tmp_dir, 'baz')
486 write_file(src, 'foo')
487 os.symlink(src, src_link)
488 os.setxattr(src, 'trusted.foo', b'42')
Larry Hastings9cf065c2012-06-22 16:30:09 -0700489 os.setxattr(src_link, 'trusted.foo', b'43', follow_symlinks=False)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200490 dst = os.path.join(tmp_dir, 'bar')
491 dst_link = os.path.join(tmp_dir, 'qux')
492 write_file(dst, 'bar')
493 os.symlink(dst, dst_link)
Larry Hastingsb4038062012-07-15 10:57:38 -0700494 shutil._copyxattr(src_link, dst_link, follow_symlinks=False)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700495 self.assertEqual(os.getxattr(dst_link, 'trusted.foo', follow_symlinks=False), b'43')
Antoine Pitrou424246f2012-05-12 19:02:01 +0200496 self.assertRaises(OSError, os.getxattr, dst, 'trusted.foo')
Larry Hastingsb4038062012-07-15 10:57:38 -0700497 shutil._copyxattr(src_link, dst, follow_symlinks=False)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200498 self.assertEqual(os.getxattr(dst, 'trusted.foo'), b'43')
499
Antoine Pitrou78091e62011-12-29 18:54:15 +0100500 @support.skip_unless_symlink
501 def test_copy_symlinks(self):
502 tmp_dir = self.mkdtemp()
503 src = os.path.join(tmp_dir, 'foo')
504 dst = os.path.join(tmp_dir, 'bar')
505 src_link = os.path.join(tmp_dir, 'baz')
506 write_file(src, 'foo')
507 os.symlink(src, src_link)
508 if hasattr(os, 'lchmod'):
509 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
510 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700511 shutil.copy(src_link, dst, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100512 self.assertFalse(os.path.islink(dst))
513 self.assertEqual(read_file(src), read_file(dst))
514 os.remove(dst)
515 # follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700516 shutil.copy(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100517 self.assertTrue(os.path.islink(dst))
518 self.assertEqual(os.readlink(dst), os.readlink(src_link))
519 if hasattr(os, 'lchmod'):
520 self.assertEqual(os.lstat(src_link).st_mode,
521 os.lstat(dst).st_mode)
522
523 @support.skip_unless_symlink
524 def test_copy2_symlinks(self):
525 tmp_dir = self.mkdtemp()
526 src = os.path.join(tmp_dir, 'foo')
527 dst = os.path.join(tmp_dir, 'bar')
528 src_link = os.path.join(tmp_dir, 'baz')
529 write_file(src, 'foo')
530 os.symlink(src, src_link)
531 if hasattr(os, 'lchmod'):
532 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
533 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
534 os.lchflags(src_link, stat.UF_NODUMP)
535 src_stat = os.stat(src)
536 src_link_stat = os.lstat(src_link)
537 # follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700538 shutil.copy2(src_link, dst, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100539 self.assertFalse(os.path.islink(dst))
540 self.assertEqual(read_file(src), read_file(dst))
541 os.remove(dst)
542 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700543 shutil.copy2(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100544 self.assertTrue(os.path.islink(dst))
545 self.assertEqual(os.readlink(dst), os.readlink(src_link))
546 dst_stat = os.lstat(dst)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700547 if os.utime in os.supports_follow_symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100548 for attr in 'st_atime', 'st_mtime':
549 # The modification times may be truncated in the new file.
550 self.assertLessEqual(getattr(src_link_stat, attr),
551 getattr(dst_stat, attr) + 1)
552 if hasattr(os, 'lchmod'):
553 self.assertEqual(src_link_stat.st_mode, dst_stat.st_mode)
554 self.assertNotEqual(src_stat.st_mode, dst_stat.st_mode)
555 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
556 self.assertEqual(src_link_stat.st_flags, dst_stat.st_flags)
557
Antoine Pitrou424246f2012-05-12 19:02:01 +0200558 @support.skip_unless_xattr
559 def test_copy2_xattr(self):
560 tmp_dir = self.mkdtemp()
561 src = os.path.join(tmp_dir, 'foo')
562 dst = os.path.join(tmp_dir, 'bar')
563 write_file(src, 'foo')
564 os.setxattr(src, 'user.foo', b'42')
565 shutil.copy2(src, dst)
566 self.assertEqual(
567 os.getxattr(src, 'user.foo'),
568 os.getxattr(dst, 'user.foo'))
569 os.remove(dst)
570
Antoine Pitrou78091e62011-12-29 18:54:15 +0100571 @support.skip_unless_symlink
572 def test_copyfile_symlinks(self):
573 tmp_dir = self.mkdtemp()
574 src = os.path.join(tmp_dir, 'src')
575 dst = os.path.join(tmp_dir, 'dst')
576 dst_link = os.path.join(tmp_dir, 'dst_link')
577 link = os.path.join(tmp_dir, 'link')
578 write_file(src, 'foo')
579 os.symlink(src, link)
580 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700581 shutil.copyfile(link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100582 self.assertTrue(os.path.islink(dst_link))
583 self.assertEqual(os.readlink(link), os.readlink(dst_link))
584 # follow
585 shutil.copyfile(link, dst)
586 self.assertFalse(os.path.islink(dst))
587
Hynek Schlawack2100b422012-06-23 20:28:32 +0200588 def test_rmtree_uses_safe_fd_version_if_available(self):
Hynek Schlawackd0f6e0a2012-06-29 08:28:20 +0200589 _use_fd_functions = ({os.open, os.stat, os.unlink, os.rmdir} <=
590 os.supports_dir_fd and
591 os.listdir in os.supports_fd and
592 os.stat in os.supports_follow_symlinks)
593 if _use_fd_functions:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200594 self.assertTrue(shutil._use_fd_functions)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000595 self.assertTrue(shutil.rmtree.avoids_symlink_attacks)
Hynek Schlawack2100b422012-06-23 20:28:32 +0200596 tmp_dir = self.mkdtemp()
597 d = os.path.join(tmp_dir, 'a')
598 os.mkdir(d)
599 try:
600 real_rmtree = shutil._rmtree_safe_fd
601 class Called(Exception): pass
602 def _raiser(*args, **kwargs):
603 raise Called
604 shutil._rmtree_safe_fd = _raiser
605 self.assertRaises(Called, shutil.rmtree, d)
606 finally:
607 shutil._rmtree_safe_fd = real_rmtree
608 else:
609 self.assertFalse(shutil._use_fd_functions)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000610 self.assertFalse(shutil.rmtree.avoids_symlink_attacks)
Hynek Schlawack2100b422012-06-23 20:28:32 +0200611
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000612 def test_rmtree_dont_delete_file(self):
613 # When called on a file instead of a directory, don't delete it.
614 handle, path = tempfile.mkstemp()
Victor Stinnerbf816222011-06-30 23:25:47 +0200615 os.close(handle)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200616 self.assertRaises(NotADirectoryError, shutil.rmtree, path)
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000617 os.remove(path)
618
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000619 def test_copytree_simple(self):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000620 src_dir = tempfile.mkdtemp()
621 dst_dir = os.path.join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200622 self.addCleanup(shutil.rmtree, src_dir)
623 self.addCleanup(shutil.rmtree, os.path.dirname(dst_dir))
624 write_file((src_dir, 'test.txt'), '123')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000625 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200626 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000627
Éric Araujoa7e33a12011-08-12 19:51:35 +0200628 shutil.copytree(src_dir, dst_dir)
629 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test.txt')))
630 self.assertTrue(os.path.isdir(os.path.join(dst_dir, 'test_dir')))
631 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test_dir',
632 'test.txt')))
633 actual = read_file((dst_dir, 'test.txt'))
634 self.assertEqual(actual, '123')
635 actual = read_file((dst_dir, 'test_dir', 'test.txt'))
636 self.assertEqual(actual, '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000637
Antoine Pitrou78091e62011-12-29 18:54:15 +0100638 @support.skip_unless_symlink
639 def test_copytree_symlinks(self):
640 tmp_dir = self.mkdtemp()
641 src_dir = os.path.join(tmp_dir, 'src')
642 dst_dir = os.path.join(tmp_dir, 'dst')
643 sub_dir = os.path.join(src_dir, 'sub')
644 os.mkdir(src_dir)
645 os.mkdir(sub_dir)
646 write_file((src_dir, 'file.txt'), 'foo')
647 src_link = os.path.join(sub_dir, 'link')
648 dst_link = os.path.join(dst_dir, 'sub/link')
649 os.symlink(os.path.join(src_dir, 'file.txt'),
650 src_link)
651 if hasattr(os, 'lchmod'):
652 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
653 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
654 os.lchflags(src_link, stat.UF_NODUMP)
655 src_stat = os.lstat(src_link)
656 shutil.copytree(src_dir, dst_dir, symlinks=True)
657 self.assertTrue(os.path.islink(os.path.join(dst_dir, 'sub', 'link')))
658 self.assertEqual(os.readlink(os.path.join(dst_dir, 'sub', 'link')),
659 os.path.join(src_dir, 'file.txt'))
660 dst_stat = os.lstat(dst_link)
661 if hasattr(os, 'lchmod'):
662 self.assertEqual(dst_stat.st_mode, src_stat.st_mode)
663 if hasattr(os, 'lchflags'):
664 self.assertEqual(dst_stat.st_flags, src_stat.st_flags)
665
Georg Brandl2ee470f2008-07-16 12:55:28 +0000666 def test_copytree_with_exclude(self):
Georg Brandl2ee470f2008-07-16 12:55:28 +0000667 # creating data
668 join = os.path.join
669 exists = os.path.exists
670 src_dir = tempfile.mkdtemp()
Georg Brandl2ee470f2008-07-16 12:55:28 +0000671 try:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000672 dst_dir = join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200673 write_file((src_dir, 'test.txt'), '123')
674 write_file((src_dir, 'test.tmp'), '123')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000675 os.mkdir(join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200676 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000677 os.mkdir(join(src_dir, 'test_dir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200678 write_file((src_dir, 'test_dir2', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000679 os.mkdir(join(src_dir, 'test_dir2', 'subdir'))
680 os.mkdir(join(src_dir, 'test_dir2', 'subdir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200681 write_file((src_dir, 'test_dir2', 'subdir', 'test.txt'), '456')
682 write_file((src_dir, 'test_dir2', 'subdir2', 'test.py'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000683
684 # testing glob-like patterns
685 try:
686 patterns = shutil.ignore_patterns('*.tmp', 'test_dir2')
687 shutil.copytree(src_dir, dst_dir, ignore=patterns)
688 # checking the result: some elements should not be copied
689 self.assertTrue(exists(join(dst_dir, 'test.txt')))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200690 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
691 self.assertFalse(exists(join(dst_dir, 'test_dir2')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000692 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200693 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000694 try:
695 patterns = shutil.ignore_patterns('*.tmp', 'subdir*')
696 shutil.copytree(src_dir, dst_dir, ignore=patterns)
697 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200698 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
699 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2')))
700 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000701 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200702 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000703
704 # testing callable-style
705 try:
706 def _filter(src, names):
707 res = []
708 for name in names:
709 path = os.path.join(src, name)
710
711 if (os.path.isdir(path) and
712 path.split()[-1] == 'subdir'):
713 res.append(name)
714 elif os.path.splitext(path)[-1] in ('.py'):
715 res.append(name)
716 return res
717
718 shutil.copytree(src_dir, dst_dir, ignore=_filter)
719
720 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200721 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2',
722 'test.py')))
723 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000724
725 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200726 shutil.rmtree(dst_dir)
Georg Brandl2ee470f2008-07-16 12:55:28 +0000727 finally:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000728 shutil.rmtree(src_dir)
729 shutil.rmtree(os.path.dirname(dst_dir))
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000730
Antoine Pitrouac601602013-08-16 19:35:02 +0200731 def test_copytree_retains_permissions(self):
732 tmp_dir = tempfile.mkdtemp()
733 src_dir = os.path.join(tmp_dir, 'source')
734 os.mkdir(src_dir)
735 dst_dir = os.path.join(tmp_dir, 'destination')
736 self.addCleanup(shutil.rmtree, tmp_dir)
737
738 os.chmod(src_dir, 0o777)
739 write_file((src_dir, 'permissive.txt'), '123')
740 os.chmod(os.path.join(src_dir, 'permissive.txt'), 0o777)
741 write_file((src_dir, 'restrictive.txt'), '456')
742 os.chmod(os.path.join(src_dir, 'restrictive.txt'), 0o600)
743 restrictive_subdir = tempfile.mkdtemp(dir=src_dir)
744 os.chmod(restrictive_subdir, 0o600)
745
746 shutil.copytree(src_dir, dst_dir)
Brett Cannon9c7eb552013-08-23 14:38:11 -0400747 self.assertEqual(os.stat(src_dir).st_mode, os.stat(dst_dir).st_mode)
748 self.assertEqual(os.stat(os.path.join(src_dir, 'permissive.txt')).st_mode,
Antoine Pitrouac601602013-08-16 19:35:02 +0200749 os.stat(os.path.join(dst_dir, 'permissive.txt')).st_mode)
Brett Cannon9c7eb552013-08-23 14:38:11 -0400750 self.assertEqual(os.stat(os.path.join(src_dir, 'restrictive.txt')).st_mode,
Antoine Pitrouac601602013-08-16 19:35:02 +0200751 os.stat(os.path.join(dst_dir, 'restrictive.txt')).st_mode)
752 restrictive_subdir_dst = os.path.join(dst_dir,
753 os.path.split(restrictive_subdir)[1])
Brett Cannon9c7eb552013-08-23 14:38:11 -0400754 self.assertEqual(os.stat(restrictive_subdir).st_mode,
Antoine Pitrouac601602013-08-16 19:35:02 +0200755 os.stat(restrictive_subdir_dst).st_mode)
756
Berker Peksag884afd92014-12-10 02:50:32 +0200757 @unittest.mock.patch('os.chmod')
758 def test_copytree_winerror(self, mock_patch):
759 # When copying to VFAT, copystat() raises OSError. On Windows, the
760 # exception object has a meaningful 'winerror' attribute, but not
761 # on other operating systems. Do not assume 'winerror' is set.
762 src_dir = tempfile.mkdtemp()
763 dst_dir = os.path.join(tempfile.mkdtemp(), 'destination')
764 self.addCleanup(shutil.rmtree, src_dir)
765 self.addCleanup(shutil.rmtree, os.path.dirname(dst_dir))
766
767 mock_patch.side_effect = PermissionError('ka-boom')
768 with self.assertRaises(shutil.Error):
769 shutil.copytree(src_dir, dst_dir)
770
Zachary Ware9fe6d862013-12-08 00:20:35 -0600771 @unittest.skipIf(os.name == 'nt', 'temporarily disabled on Windows')
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000772 @unittest.skipUnless(hasattr(os, 'link'), 'requires os.link')
Xavier de Gaye3a4e9892016-12-13 10:00:01 +0100773 @unittest.skipIf(android_not_root, "hard links not allowed, non root user")
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000774 def test_dont_copy_file_onto_link_to_itself(self):
775 # bug 851123.
776 os.mkdir(TESTFN)
777 src = os.path.join(TESTFN, 'cheese')
778 dst = os.path.join(TESTFN, 'shop')
779 try:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000780 with open(src, 'w') as f:
781 f.write('cheddar')
782 os.link(src, dst)
Hynek Schlawack48653762012-10-07 12:49:58 +0200783 self.assertRaises(shutil.SameFileError, shutil.copyfile, src, dst)
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000784 with open(src, 'r') as f:
785 self.assertEqual(f.read(), 'cheddar')
786 os.remove(dst)
787 finally:
788 shutil.rmtree(TESTFN, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000789
Brian Curtin3b4499c2010-12-28 14:31:47 +0000790 @support.skip_unless_symlink
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000791 def test_dont_copy_file_onto_symlink_to_itself(self):
792 # bug 851123.
793 os.mkdir(TESTFN)
794 src = os.path.join(TESTFN, 'cheese')
795 dst = os.path.join(TESTFN, 'shop')
796 try:
797 with open(src, 'w') as f:
798 f.write('cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000799 # Using `src` here would mean we end up with a symlink pointing
800 # to TESTFN/TESTFN/cheese, while it should point at
801 # TESTFN/cheese.
802 os.symlink('cheese', dst)
Hynek Schlawack48653762012-10-07 12:49:58 +0200803 self.assertRaises(shutil.SameFileError, shutil.copyfile, src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +0000804 with open(src, 'r') as f:
805 self.assertEqual(f.read(), 'cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000806 os.remove(dst)
807 finally:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000808 shutil.rmtree(TESTFN, ignore_errors=True)
Johannes Gijsbers68128712004-08-14 13:57:08 +0000809
Brian Curtin3b4499c2010-12-28 14:31:47 +0000810 @support.skip_unless_symlink
Brian Curtind40e6f72010-07-08 21:39:08 +0000811 def test_rmtree_on_symlink(self):
812 # bug 1669.
813 os.mkdir(TESTFN)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000814 try:
Brian Curtind40e6f72010-07-08 21:39:08 +0000815 src = os.path.join(TESTFN, 'cheese')
816 dst = os.path.join(TESTFN, 'shop')
817 os.mkdir(src)
818 os.symlink(src, dst)
819 self.assertRaises(OSError, shutil.rmtree, dst)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200820 shutil.rmtree(dst, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000821 finally:
Brian Curtind40e6f72010-07-08 21:39:08 +0000822 shutil.rmtree(TESTFN, ignore_errors=True)
823
Serhiy Storchaka43767632013-11-03 21:31:38 +0200824 # Issue #3002: copyfile and copytree block indefinitely on named pipes
825 @unittest.skipUnless(hasattr(os, "mkfifo"), 'requires os.mkfifo()')
Xavier de Gaye3a4e9892016-12-13 10:00:01 +0100826 @unittest.skipIf(android_not_root, "mkfifo not allowed, non root user")
Serhiy Storchaka43767632013-11-03 21:31:38 +0200827 def test_copyfile_named_pipe(self):
828 os.mkfifo(TESTFN)
829 try:
830 self.assertRaises(shutil.SpecialFileError,
831 shutil.copyfile, TESTFN, TESTFN2)
832 self.assertRaises(shutil.SpecialFileError,
833 shutil.copyfile, __file__, TESTFN)
834 finally:
835 os.remove(TESTFN)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000836
Xavier de Gaye3a4e9892016-12-13 10:00:01 +0100837 @unittest.skipIf(android_not_root, "mkfifo not allowed, non root user")
Serhiy Storchaka43767632013-11-03 21:31:38 +0200838 @unittest.skipUnless(hasattr(os, "mkfifo"), 'requires os.mkfifo()')
839 @support.skip_unless_symlink
840 def test_copytree_named_pipe(self):
841 os.mkdir(TESTFN)
842 try:
843 subdir = os.path.join(TESTFN, "subdir")
844 os.mkdir(subdir)
845 pipe = os.path.join(subdir, "mypipe")
846 os.mkfifo(pipe)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000847 try:
Serhiy Storchaka43767632013-11-03 21:31:38 +0200848 shutil.copytree(TESTFN, TESTFN2)
849 except shutil.Error as e:
850 errors = e.args[0]
851 self.assertEqual(len(errors), 1)
852 src, dst, error_msg = errors[0]
853 self.assertEqual("`%s` is a named pipe" % pipe, error_msg)
854 else:
855 self.fail("shutil.Error should have been raised")
856 finally:
857 shutil.rmtree(TESTFN, ignore_errors=True)
858 shutil.rmtree(TESTFN2, ignore_errors=True)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000859
Tarek Ziadé5340db32010-04-19 22:30:51 +0000860 def test_copytree_special_func(self):
861
862 src_dir = self.mkdtemp()
863 dst_dir = os.path.join(self.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200864 write_file((src_dir, 'test.txt'), '123')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000865 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200866 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000867
868 copied = []
869 def _copy(src, dst):
870 copied.append((src, dst))
871
872 shutil.copytree(src_dir, dst_dir, copy_function=_copy)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000873 self.assertEqual(len(copied), 2)
Tarek Ziadé5340db32010-04-19 22:30:51 +0000874
Brian Curtin3b4499c2010-12-28 14:31:47 +0000875 @support.skip_unless_symlink
Tarek Ziadéfb437512010-04-20 08:57:33 +0000876 def test_copytree_dangling_symlinks(self):
877
878 # a dangling symlink raises an error at the end
879 src_dir = self.mkdtemp()
880 dst_dir = os.path.join(self.mkdtemp(), 'destination')
881 os.symlink('IDONTEXIST', os.path.join(src_dir, 'test.txt'))
882 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200883 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadéfb437512010-04-20 08:57:33 +0000884 self.assertRaises(Error, shutil.copytree, src_dir, dst_dir)
885
886 # a dangling symlink is ignored with the proper flag
887 dst_dir = os.path.join(self.mkdtemp(), 'destination2')
888 shutil.copytree(src_dir, dst_dir, ignore_dangling_symlinks=True)
889 self.assertNotIn('test.txt', os.listdir(dst_dir))
890
891 # a dangling symlink is copied if symlinks=True
892 dst_dir = os.path.join(self.mkdtemp(), 'destination3')
893 shutil.copytree(src_dir, dst_dir, symlinks=True)
894 self.assertIn('test.txt', os.listdir(dst_dir))
895
Berker Peksag5a294d82015-07-25 14:53:48 +0300896 @support.skip_unless_symlink
897 def test_copytree_symlink_dir(self):
898 src_dir = self.mkdtemp()
899 dst_dir = os.path.join(self.mkdtemp(), 'destination')
900 os.mkdir(os.path.join(src_dir, 'real_dir'))
901 with open(os.path.join(src_dir, 'real_dir', 'test.txt'), 'w'):
902 pass
903 os.symlink(os.path.join(src_dir, 'real_dir'),
904 os.path.join(src_dir, 'link_to_dir'),
905 target_is_directory=True)
906
907 shutil.copytree(src_dir, dst_dir, symlinks=False)
908 self.assertFalse(os.path.islink(os.path.join(dst_dir, 'link_to_dir')))
909 self.assertIn('test.txt', os.listdir(os.path.join(dst_dir, 'link_to_dir')))
910
911 dst_dir = os.path.join(self.mkdtemp(), 'destination2')
912 shutil.copytree(src_dir, dst_dir, symlinks=True)
913 self.assertTrue(os.path.islink(os.path.join(dst_dir, 'link_to_dir')))
914 self.assertIn('test.txt', os.listdir(os.path.join(dst_dir, 'link_to_dir')))
915
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400916 def _copy_file(self, method):
917 fname = 'test.txt'
918 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200919 write_file((tmpdir, fname), 'xxx')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400920 file1 = os.path.join(tmpdir, fname)
921 tmpdir2 = self.mkdtemp()
922 method(file1, tmpdir2)
923 file2 = os.path.join(tmpdir2, fname)
924 return (file1, file2)
925
926 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
927 def test_copy(self):
928 # Ensure that the copied file exists and has the same mode bits.
929 file1, file2 = self._copy_file(shutil.copy)
930 self.assertTrue(os.path.exists(file2))
931 self.assertEqual(os.stat(file1).st_mode, os.stat(file2).st_mode)
932
933 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
Senthil Kumaran0c2dba52011-07-03 18:21:38 -0700934 @unittest.skipUnless(hasattr(os, 'utime'), 'requires os.utime')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400935 def test_copy2(self):
936 # Ensure that the copied file exists and has the same mode and
937 # modification time bits.
938 file1, file2 = self._copy_file(shutil.copy2)
939 self.assertTrue(os.path.exists(file2))
940 file1_stat = os.stat(file1)
941 file2_stat = os.stat(file2)
942 self.assertEqual(file1_stat.st_mode, file2_stat.st_mode)
943 for attr in 'st_atime', 'st_mtime':
944 # The modification times may be truncated in the new file.
945 self.assertLessEqual(getattr(file1_stat, attr),
946 getattr(file2_stat, attr) + 1)
947 if hasattr(os, 'chflags') and hasattr(file1_stat, 'st_flags'):
948 self.assertEqual(getattr(file1_stat, 'st_flags'),
949 getattr(file2_stat, 'st_flags'))
950
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +0200951 @support.requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000952 def test_make_tarball(self):
953 # creating something to tar
Serhiy Storchaka527ef072015-09-06 18:33:19 +0300954 root_dir, base_dir = self._create_files('')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000955
956 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400957 # force shutil to create the directory
958 os.rmdir(tmpdir2)
Serhiy Storchakaeba8fee2015-09-07 19:58:23 +0300959 # working with relative paths
960 work_dir = os.path.dirname(tmpdir2)
961 rel_base_name = os.path.join(os.path.basename(tmpdir2), 'archive')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000962
Serhiy Storchakaeba8fee2015-09-07 19:58:23 +0300963 with support.change_cwd(work_dir):
Serhiy Storchaka5558d4f2015-09-08 09:59:02 +0300964 base_name = os.path.abspath(rel_base_name)
Serhiy Storchakaeba8fee2015-09-07 19:58:23 +0300965 tarball = make_archive(rel_base_name, 'gztar', root_dir, '.')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000966
967 # check if the compressed tarball was created
Serhiy Storchakaa091a822015-09-07 13:55:25 +0300968 self.assertEqual(tarball, base_name + '.tar.gz')
Serhiy Storchaka527ef072015-09-06 18:33:19 +0300969 self.assertTrue(os.path.isfile(tarball))
970 self.assertTrue(tarfile.is_tarfile(tarball))
971 with tarfile.open(tarball, 'r:gz') as tf:
972 self.assertCountEqual(tf.getnames(),
973 ['.', './sub', './sub2',
974 './file1', './file2', './sub/file3'])
Tarek Ziadé396fad72010-02-23 05:30:31 +0000975
976 # trying an uncompressed one
Serhiy Storchakaeba8fee2015-09-07 19:58:23 +0300977 with support.change_cwd(work_dir):
978 tarball = make_archive(rel_base_name, 'tar', root_dir, '.')
Serhiy Storchakaa091a822015-09-07 13:55:25 +0300979 self.assertEqual(tarball, base_name + '.tar')
Serhiy Storchaka527ef072015-09-06 18:33:19 +0300980 self.assertTrue(os.path.isfile(tarball))
981 self.assertTrue(tarfile.is_tarfile(tarball))
982 with tarfile.open(tarball, 'r') as tf:
983 self.assertCountEqual(tf.getnames(),
984 ['.', './sub', './sub2',
985 './file1', './file2', './sub/file3'])
Tarek Ziadé396fad72010-02-23 05:30:31 +0000986
987 def _tarinfo(self, path):
Serhiy Storchaka527ef072015-09-06 18:33:19 +0300988 with tarfile.open(path) as tar:
Tarek Ziadé396fad72010-02-23 05:30:31 +0000989 names = tar.getnames()
990 names.sort()
991 return tuple(names)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000992
Serhiy Storchaka527ef072015-09-06 18:33:19 +0300993 def _create_files(self, base_dir='dist'):
Tarek Ziadé396fad72010-02-23 05:30:31 +0000994 # creating something to tar
Serhiy Storchaka527ef072015-09-06 18:33:19 +0300995 root_dir = self.mkdtemp()
996 dist = os.path.join(root_dir, base_dir)
997 os.makedirs(dist, exist_ok=True)
Éric Araujoa7e33a12011-08-12 19:51:35 +0200998 write_file((dist, 'file1'), 'xxx')
999 write_file((dist, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +00001000 os.mkdir(os.path.join(dist, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +02001001 write_file((dist, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +00001002 os.mkdir(os.path.join(dist, 'sub2'))
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001003 if base_dir:
1004 write_file((root_dir, 'outer'), 'xxx')
1005 return root_dir, base_dir
Tarek Ziadé396fad72010-02-23 05:30:31 +00001006
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001007 @support.requires_zlib
Serhiy Storchakab42de2f2015-11-21 14:09:26 +02001008 @unittest.skipUnless(shutil.which('tar'),
Tarek Ziadé396fad72010-02-23 05:30:31 +00001009 'Need the tar command to run')
1010 def test_tarfile_vs_tar(self):
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001011 root_dir, base_dir = self._create_files()
1012 base_name = os.path.join(self.mkdtemp(), 'archive')
Serhiy Storchakaa091a822015-09-07 13:55:25 +03001013 tarball = make_archive(base_name, 'gztar', root_dir, base_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001014
1015 # check if the compressed tarball was created
Serhiy Storchakaa091a822015-09-07 13:55:25 +03001016 self.assertEqual(tarball, base_name + '.tar.gz')
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001017 self.assertTrue(os.path.isfile(tarball))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001018
1019 # now create another tarball using `tar`
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001020 tarball2 = os.path.join(root_dir, 'archive2.tar')
1021 tar_cmd = ['tar', '-cf', 'archive2.tar', base_dir]
Serhiy Storchakab42de2f2015-11-21 14:09:26 +02001022 subprocess.check_call(tar_cmd, cwd=root_dir,
1023 stdout=subprocess.DEVNULL)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001024
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001025 self.assertTrue(os.path.isfile(tarball2))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001026 # let's compare both tarballs
Ezio Melottib3aedd42010-11-20 19:04:17 +00001027 self.assertEqual(self._tarinfo(tarball), self._tarinfo(tarball2))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001028
1029 # trying an uncompressed one
Serhiy Storchakaa091a822015-09-07 13:55:25 +03001030 tarball = make_archive(base_name, 'tar', root_dir, base_dir)
1031 self.assertEqual(tarball, base_name + '.tar')
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001032 self.assertTrue(os.path.isfile(tarball))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001033
1034 # now for a dry_run
Serhiy Storchakaa091a822015-09-07 13:55:25 +03001035 tarball = make_archive(base_name, 'tar', root_dir, base_dir,
1036 dry_run=True)
1037 self.assertEqual(tarball, base_name + '.tar')
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001038 self.assertTrue(os.path.isfile(tarball))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001039
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001040 @support.requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001041 def test_make_zipfile(self):
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001042 # creating something to zip
1043 root_dir, base_dir = self._create_files()
Serhiy Storchakaeba8fee2015-09-07 19:58:23 +03001044
1045 tmpdir2 = self.mkdtemp()
1046 # force shutil to create the directory
1047 os.rmdir(tmpdir2)
1048 # working with relative paths
1049 work_dir = os.path.dirname(tmpdir2)
1050 rel_base_name = os.path.join(os.path.basename(tmpdir2), 'archive')
Serhiy Storchakaeba8fee2015-09-07 19:58:23 +03001051
1052 with support.change_cwd(work_dir):
Serhiy Storchaka5558d4f2015-09-08 09:59:02 +03001053 base_name = os.path.abspath(rel_base_name)
Serhiy Storchaka666de772016-10-23 15:55:09 +03001054 res = make_archive(rel_base_name, 'zip', root_dir)
1055
1056 self.assertEqual(res, base_name + '.zip')
1057 self.assertTrue(os.path.isfile(res))
1058 self.assertTrue(zipfile.is_zipfile(res))
1059 with zipfile.ZipFile(res) as zf:
1060 self.assertCountEqual(zf.namelist(),
1061 ['dist/', 'dist/sub/', 'dist/sub2/',
1062 'dist/file1', 'dist/file2', 'dist/sub/file3',
1063 'outer'])
1064
1065 with support.change_cwd(work_dir):
1066 base_name = os.path.abspath(rel_base_name)
Serhiy Storchaka2504cec2015-09-08 05:47:23 +03001067 res = make_archive(rel_base_name, 'zip', root_dir, base_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001068
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001069 self.assertEqual(res, base_name + '.zip')
1070 self.assertTrue(os.path.isfile(res))
1071 self.assertTrue(zipfile.is_zipfile(res))
1072 with zipfile.ZipFile(res) as zf:
1073 self.assertCountEqual(zf.namelist(),
Serhiy Storchaka2504cec2015-09-08 05:47:23 +03001074 ['dist/', 'dist/sub/', 'dist/sub2/',
1075 'dist/file1', 'dist/file2', 'dist/sub/file3'])
Tarek Ziadé396fad72010-02-23 05:30:31 +00001076
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001077 @support.requires_zlib
Serhiy Storchakab42de2f2015-11-21 14:09:26 +02001078 @unittest.skipUnless(shutil.which('zip'),
Serhiy Storchaka2504cec2015-09-08 05:47:23 +03001079 'Need the zip command to run')
1080 def test_zipfile_vs_zip(self):
1081 root_dir, base_dir = self._create_files()
1082 base_name = os.path.join(self.mkdtemp(), 'archive')
1083 archive = make_archive(base_name, 'zip', root_dir, base_dir)
1084
1085 # check if ZIP file was created
1086 self.assertEqual(archive, base_name + '.zip')
1087 self.assertTrue(os.path.isfile(archive))
1088
1089 # now create another ZIP file using `zip`
1090 archive2 = os.path.join(root_dir, 'archive2.zip')
1091 zip_cmd = ['zip', '-q', '-r', 'archive2.zip', base_dir]
Serhiy Storchakab42de2f2015-11-21 14:09:26 +02001092 subprocess.check_call(zip_cmd, cwd=root_dir,
1093 stdout=subprocess.DEVNULL)
Serhiy Storchaka2504cec2015-09-08 05:47:23 +03001094
1095 self.assertTrue(os.path.isfile(archive2))
1096 # let's compare both ZIP files
1097 with zipfile.ZipFile(archive) as zf:
1098 names = zf.namelist()
1099 with zipfile.ZipFile(archive2) as zf:
1100 names2 = zf.namelist()
1101 self.assertEqual(sorted(names), sorted(names2))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001102
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001103 @support.requires_zlib
Serhiy Storchaka8bc792a2015-11-22 14:49:58 +02001104 @unittest.skipUnless(shutil.which('unzip'),
1105 'Need the unzip command to run')
1106 def test_unzip_zipfile(self):
1107 root_dir, base_dir = self._create_files()
1108 base_name = os.path.join(self.mkdtemp(), 'archive')
1109 archive = make_archive(base_name, 'zip', root_dir, base_dir)
1110
1111 # check if ZIP file was created
1112 self.assertEqual(archive, base_name + '.zip')
1113 self.assertTrue(os.path.isfile(archive))
1114
1115 # now check the ZIP file using `unzip -t`
1116 zip_cmd = ['unzip', '-t', archive]
1117 with support.change_cwd(root_dir):
1118 try:
1119 subprocess.check_output(zip_cmd, stderr=subprocess.STDOUT)
1120 except subprocess.CalledProcessError as exc:
1121 details = exc.output.decode(errors="replace")
1122 msg = "{}\n\n**Unzip Output**\n{}"
1123 self.fail(msg.format(exc, details))
1124
Tarek Ziadé396fad72010-02-23 05:30:31 +00001125 def test_make_archive(self):
1126 tmpdir = self.mkdtemp()
1127 base_name = os.path.join(tmpdir, 'archive')
1128 self.assertRaises(ValueError, make_archive, base_name, 'xxx')
1129
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001130 @support.requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001131 def test_make_archive_owner_group(self):
1132 # testing make_archive with owner and group, with various combinations
1133 # this works even if there's not gid/uid support
1134 if UID_GID_SUPPORT:
1135 group = grp.getgrgid(0)[0]
1136 owner = pwd.getpwuid(0)[0]
1137 else:
1138 group = owner = 'root'
1139
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001140 root_dir, base_dir = self._create_files()
1141 base_name = os.path.join(self.mkdtemp(), 'archive')
Tarek Ziadé396fad72010-02-23 05:30:31 +00001142 res = make_archive(base_name, 'zip', root_dir, base_dir, owner=owner,
1143 group=group)
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001144 self.assertTrue(os.path.isfile(res))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001145
1146 res = make_archive(base_name, 'zip', root_dir, base_dir)
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001147 self.assertTrue(os.path.isfile(res))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001148
1149 res = make_archive(base_name, 'tar', root_dir, base_dir,
1150 owner=owner, group=group)
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001151 self.assertTrue(os.path.isfile(res))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001152
1153 res = make_archive(base_name, 'tar', root_dir, base_dir,
1154 owner='kjhkjhkjg', group='oihohoh')
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001155 self.assertTrue(os.path.isfile(res))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001156
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001157
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001158 @support.requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001159 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1160 def test_tarfile_root_owner(self):
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 group = grp.getgrgid(0)[0]
1164 owner = pwd.getpwuid(0)[0]
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001165 with support.change_cwd(root_dir):
1166 archive_name = make_archive(base_name, 'gztar', root_dir, 'dist',
1167 owner=owner, group=group)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001168
1169 # check if the compressed tarball was created
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001170 self.assertTrue(os.path.isfile(archive_name))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001171
1172 # now checks the rights
1173 archive = tarfile.open(archive_name)
1174 try:
1175 for member in archive.getmembers():
Ezio Melottib3aedd42010-11-20 19:04:17 +00001176 self.assertEqual(member.uid, 0)
1177 self.assertEqual(member.gid, 0)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001178 finally:
1179 archive.close()
1180
1181 def test_make_archive_cwd(self):
1182 current_dir = os.getcwd()
1183 def _breaks(*args, **kw):
1184 raise RuntimeError()
1185
1186 register_archive_format('xxx', _breaks, [], 'xxx file')
1187 try:
1188 try:
1189 make_archive('xxx', 'xxx', root_dir=self.mkdtemp())
1190 except Exception:
1191 pass
Ezio Melottib3aedd42010-11-20 19:04:17 +00001192 self.assertEqual(os.getcwd(), current_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001193 finally:
1194 unregister_archive_format('xxx')
1195
Serhiy Storchaka9a4fc192014-11-28 00:48:46 +02001196 def test_make_tarfile_in_curdir(self):
1197 # Issue #21280
1198 root_dir = self.mkdtemp()
1199 with support.change_cwd(root_dir):
1200 self.assertEqual(make_archive('test', 'tar'), 'test.tar')
1201 self.assertTrue(os.path.isfile('test.tar'))
1202
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001203 @support.requires_zlib
Serhiy Storchaka9a4fc192014-11-28 00:48:46 +02001204 def test_make_zipfile_in_curdir(self):
1205 # Issue #21280
1206 root_dir = self.mkdtemp()
1207 with support.change_cwd(root_dir):
1208 self.assertEqual(make_archive('test', 'zip'), 'test.zip')
1209 self.assertTrue(os.path.isfile('test.zip'))
1210
Tarek Ziadé396fad72010-02-23 05:30:31 +00001211 def test_register_archive_format(self):
1212
1213 self.assertRaises(TypeError, register_archive_format, 'xxx', 1)
1214 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1215 1)
1216 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1217 [(1, 2), (1, 2, 3)])
1218
1219 register_archive_format('xxx', lambda: x, [(1, 2)], 'xxx file')
1220 formats = [name for name, params in get_archive_formats()]
1221 self.assertIn('xxx', formats)
1222
1223 unregister_archive_format('xxx')
1224 formats = [name for name, params in get_archive_formats()]
1225 self.assertNotIn('xxx', formats)
1226
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001227 def check_unpack_archive(self, format):
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001228 root_dir, base_dir = self._create_files()
Serhiy Storchaka2504cec2015-09-08 05:47:23 +03001229 expected = rlistdir(root_dir)
1230 expected.remove('outer')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001231
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001232 base_name = os.path.join(self.mkdtemp(), 'archive')
1233 filename = make_archive(base_name, format, root_dir, base_dir)
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001234
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001235 # let's try to unpack it now
1236 tmpdir2 = self.mkdtemp()
1237 unpack_archive(filename, tmpdir2)
1238 self.assertEqual(rlistdir(tmpdir2), expected)
1239
1240 # and again, this time with the format specified
1241 tmpdir3 = self.mkdtemp()
1242 unpack_archive(filename, tmpdir3, format=format)
1243 self.assertEqual(rlistdir(tmpdir3), expected)
1244
Nick Coghlanabf202d2011-03-16 13:52:20 -04001245 self.assertRaises(shutil.ReadError, unpack_archive, TESTFN)
1246 self.assertRaises(ValueError, unpack_archive, TESTFN, format='xxx')
1247
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001248 def test_unpack_archive_tar(self):
1249 self.check_unpack_archive('tar')
1250
1251 @support.requires_zlib
1252 def test_unpack_archive_gztar(self):
1253 self.check_unpack_archive('gztar')
1254
1255 @support.requires_bz2
1256 def test_unpack_archive_bztar(self):
1257 self.check_unpack_archive('bztar')
1258
1259 @support.requires_lzma
1260 def test_unpack_archive_xztar(self):
1261 self.check_unpack_archive('xztar')
1262
1263 @support.requires_zlib
1264 def test_unpack_archive_zip(self):
1265 self.check_unpack_archive('zip')
1266
Martin Pantereb995702016-07-28 01:11:04 +00001267 def test_unpack_registry(self):
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001268
1269 formats = get_unpack_formats()
1270
1271 def _boo(filename, extract_dir, extra):
Ezio Melottib3aedd42010-11-20 19:04:17 +00001272 self.assertEqual(extra, 1)
1273 self.assertEqual(filename, 'stuff.boo')
1274 self.assertEqual(extract_dir, 'xx')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001275
1276 register_unpack_format('Boo', ['.boo', '.b2'], _boo, [('extra', 1)])
1277 unpack_archive('stuff.boo', 'xx')
1278
1279 # trying to register a .boo unpacker again
1280 self.assertRaises(RegistryError, register_unpack_format, 'Boo2',
1281 ['.boo'], _boo)
1282
1283 # should work now
1284 unregister_unpack_format('Boo')
1285 register_unpack_format('Boo2', ['.boo'], _boo)
1286 self.assertIn(('Boo2', ['.boo'], ''), get_unpack_formats())
1287 self.assertNotIn(('Boo', ['.boo'], ''), get_unpack_formats())
1288
1289 # let's leave a clean state
1290 unregister_unpack_format('Boo2')
Ezio Melottib3aedd42010-11-20 19:04:17 +00001291 self.assertEqual(get_unpack_formats(), formats)
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001292
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001293 @unittest.skipUnless(hasattr(shutil, 'disk_usage'),
1294 "disk_usage not available on this platform")
1295 def test_disk_usage(self):
1296 usage = shutil.disk_usage(os.getcwd())
Éric Araujo2ee61882011-07-02 16:45:45 +02001297 self.assertGreater(usage.total, 0)
1298 self.assertGreater(usage.used, 0)
1299 self.assertGreaterEqual(usage.free, 0)
1300 self.assertGreaterEqual(usage.total, usage.used)
1301 self.assertGreater(usage.total, usage.free)
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001302
Sandro Tosid902a142011-08-22 23:28:27 +02001303 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1304 @unittest.skipUnless(hasattr(os, 'chown'), 'requires os.chown')
1305 def test_chown(self):
1306
1307 # cleaned-up automatically by TestShutil.tearDown method
1308 dirname = self.mkdtemp()
1309 filename = tempfile.mktemp(dir=dirname)
1310 write_file(filename, 'testing chown function')
1311
1312 with self.assertRaises(ValueError):
1313 shutil.chown(filename)
1314
1315 with self.assertRaises(LookupError):
Raymond Hettinger15f44ab2016-08-30 10:47:49 -07001316 shutil.chown(filename, user='non-existing username')
Sandro Tosid902a142011-08-22 23:28:27 +02001317
1318 with self.assertRaises(LookupError):
Raymond Hettinger15f44ab2016-08-30 10:47:49 -07001319 shutil.chown(filename, group='non-existing groupname')
Sandro Tosid902a142011-08-22 23:28:27 +02001320
1321 with self.assertRaises(TypeError):
1322 shutil.chown(filename, b'spam')
1323
1324 with self.assertRaises(TypeError):
1325 shutil.chown(filename, 3.14)
1326
1327 uid = os.getuid()
1328 gid = os.getgid()
1329
1330 def check_chown(path, uid=None, gid=None):
1331 s = os.stat(filename)
1332 if uid is not None:
1333 self.assertEqual(uid, s.st_uid)
1334 if gid is not None:
1335 self.assertEqual(gid, s.st_gid)
1336
1337 shutil.chown(filename, uid, gid)
1338 check_chown(filename, uid, gid)
1339 shutil.chown(filename, uid)
1340 check_chown(filename, uid)
1341 shutil.chown(filename, user=uid)
1342 check_chown(filename, uid)
1343 shutil.chown(filename, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001344 check_chown(filename, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001345
1346 shutil.chown(dirname, uid, gid)
1347 check_chown(dirname, uid, gid)
1348 shutil.chown(dirname, uid)
1349 check_chown(dirname, uid)
1350 shutil.chown(dirname, user=uid)
1351 check_chown(dirname, uid)
1352 shutil.chown(dirname, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001353 check_chown(dirname, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001354
1355 user = pwd.getpwuid(uid)[0]
1356 group = grp.getgrgid(gid)[0]
1357 shutil.chown(filename, user, group)
1358 check_chown(filename, uid, gid)
1359 shutil.chown(dirname, user, group)
1360 check_chown(dirname, uid, gid)
1361
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001362 def test_copy_return_value(self):
1363 # copy and copy2 both return their destination path.
1364 for fn in (shutil.copy, shutil.copy2):
1365 src_dir = self.mkdtemp()
1366 dst_dir = self.mkdtemp()
1367 src = os.path.join(src_dir, 'foo')
1368 write_file(src, 'foo')
1369 rv = fn(src, dst_dir)
1370 self.assertEqual(rv, os.path.join(dst_dir, 'foo'))
1371 rv = fn(src, os.path.join(dst_dir, 'bar'))
1372 self.assertEqual(rv, os.path.join(dst_dir, 'bar'))
1373
1374 def test_copyfile_return_value(self):
1375 # copytree returns its destination path.
1376 src_dir = self.mkdtemp()
1377 dst_dir = self.mkdtemp()
1378 dst_file = os.path.join(dst_dir, 'bar')
1379 src_file = os.path.join(src_dir, 'foo')
1380 write_file(src_file, 'foo')
1381 rv = shutil.copyfile(src_file, dst_file)
1382 self.assertTrue(os.path.exists(rv))
1383 self.assertEqual(read_file(src_file), read_file(dst_file))
1384
Hynek Schlawack48653762012-10-07 12:49:58 +02001385 def test_copyfile_same_file(self):
1386 # copyfile() should raise SameFileError if the source and destination
1387 # are the same.
1388 src_dir = self.mkdtemp()
1389 src_file = os.path.join(src_dir, 'foo')
1390 write_file(src_file, 'foo')
1391 self.assertRaises(SameFileError, shutil.copyfile, src_file, src_file)
Hynek Schlawack27ddb572012-10-28 13:59:27 +01001392 # But Error should work too, to stay backward compatible.
1393 self.assertRaises(Error, shutil.copyfile, src_file, src_file)
Hynek Schlawack48653762012-10-07 12:49:58 +02001394
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001395 def test_copytree_return_value(self):
1396 # copytree returns its destination path.
1397 src_dir = self.mkdtemp()
1398 dst_dir = src_dir + "dest"
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001399 self.addCleanup(shutil.rmtree, dst_dir, True)
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001400 src = os.path.join(src_dir, 'foo')
1401 write_file(src, 'foo')
1402 rv = shutil.copytree(src_dir, dst_dir)
1403 self.assertEqual(['foo'], os.listdir(rv))
1404
Christian Heimes9bd667a2008-01-20 15:14:11 +00001405
Brian Curtinc57a3452012-06-22 16:00:30 -05001406class TestWhich(unittest.TestCase):
1407
1408 def setUp(self):
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001409 self.temp_dir = tempfile.mkdtemp(prefix="Tmp")
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001410 self.addCleanup(shutil.rmtree, self.temp_dir, True)
Brian Curtinc57a3452012-06-22 16:00:30 -05001411 # Give the temp_file an ".exe" suffix for all.
1412 # It's needed on Windows and not harmful on other platforms.
1413 self.temp_file = tempfile.NamedTemporaryFile(dir=self.temp_dir,
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001414 prefix="Tmp",
1415 suffix=".Exe")
Brian Curtinc57a3452012-06-22 16:00:30 -05001416 os.chmod(self.temp_file.name, stat.S_IXUSR)
1417 self.addCleanup(self.temp_file.close)
1418 self.dir, self.file = os.path.split(self.temp_file.name)
1419
1420 def test_basic(self):
1421 # Given an EXE in a directory, it should be returned.
1422 rv = shutil.which(self.file, path=self.dir)
1423 self.assertEqual(rv, self.temp_file.name)
1424
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001425 def test_absolute_cmd(self):
Brian Curtinc57a3452012-06-22 16:00:30 -05001426 # When given the fully qualified path to an executable that exists,
1427 # it should be returned.
1428 rv = shutil.which(self.temp_file.name, path=self.temp_dir)
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001429 self.assertEqual(rv, self.temp_file.name)
1430
1431 def test_relative_cmd(self):
1432 # When given the relative path with a directory part to an executable
1433 # that exists, it should be returned.
1434 base_dir, tail_dir = os.path.split(self.dir)
1435 relpath = os.path.join(tail_dir, self.file)
Nick Coghlan55175962013-07-28 22:11:50 +10001436 with support.change_cwd(path=base_dir):
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001437 rv = shutil.which(relpath, path=self.temp_dir)
1438 self.assertEqual(rv, relpath)
1439 # But it shouldn't be searched in PATH directories (issue #16957).
Nick Coghlan55175962013-07-28 22:11:50 +10001440 with support.change_cwd(path=self.dir):
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001441 rv = shutil.which(relpath, path=base_dir)
1442 self.assertIsNone(rv)
1443
1444 def test_cwd(self):
1445 # Issue #16957
1446 base_dir = os.path.dirname(self.dir)
Nick Coghlan55175962013-07-28 22:11:50 +10001447 with support.change_cwd(path=self.dir):
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001448 rv = shutil.which(self.file, path=base_dir)
1449 if sys.platform == "win32":
1450 # Windows: current directory implicitly on PATH
1451 self.assertEqual(rv, os.path.join(os.curdir, self.file))
1452 else:
1453 # Other platforms: shouldn't match in the current directory.
1454 self.assertIsNone(rv)
Brian Curtinc57a3452012-06-22 16:00:30 -05001455
Serhiy Storchaka12516e22013-05-28 15:50:15 +03001456 @unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0,
1457 'non-root user required')
Brian Curtinc57a3452012-06-22 16:00:30 -05001458 def test_non_matching_mode(self):
1459 # Set the file read-only and ask for writeable files.
1460 os.chmod(self.temp_file.name, stat.S_IREAD)
Serhiy Storchaka12516e22013-05-28 15:50:15 +03001461 if os.access(self.temp_file.name, os.W_OK):
1462 self.skipTest("can't set the file read-only")
Brian Curtinc57a3452012-06-22 16:00:30 -05001463 rv = shutil.which(self.file, path=self.dir, mode=os.W_OK)
1464 self.assertIsNone(rv)
1465
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001466 def test_relative_path(self):
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001467 base_dir, tail_dir = os.path.split(self.dir)
Nick Coghlan55175962013-07-28 22:11:50 +10001468 with support.change_cwd(path=base_dir):
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001469 rv = shutil.which(self.file, path=tail_dir)
1470 self.assertEqual(rv, os.path.join(tail_dir, self.file))
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001471
Brian Curtinc57a3452012-06-22 16:00:30 -05001472 def test_nonexistent_file(self):
1473 # Return None when no matching executable file is found on the path.
1474 rv = shutil.which("foo.exe", path=self.dir)
1475 self.assertIsNone(rv)
1476
1477 @unittest.skipUnless(sys.platform == "win32",
1478 "pathext check is Windows-only")
1479 def test_pathext_checking(self):
1480 # Ask for the file without the ".exe" extension, then ensure that
1481 # it gets found properly with the extension.
Serhiy Storchakad70127a2013-01-24 20:03:49 +02001482 rv = shutil.which(self.file[:-4], path=self.dir)
Serhiy Storchaka80c88f42013-01-22 10:31:36 +02001483 self.assertEqual(rv, self.temp_file.name[:-4] + ".EXE")
Brian Curtinc57a3452012-06-22 16:00:30 -05001484
Barry Warsaw618738b2013-04-16 11:05:03 -04001485 def test_environ_path(self):
1486 with support.EnvironmentVarGuard() as env:
Victor Stinner1d006a22013-12-16 23:39:40 +01001487 env['PATH'] = self.dir
Barry Warsaw618738b2013-04-16 11:05:03 -04001488 rv = shutil.which(self.file)
1489 self.assertEqual(rv, self.temp_file.name)
1490
1491 def test_empty_path(self):
1492 base_dir = os.path.dirname(self.dir)
Nick Coghlan55175962013-07-28 22:11:50 +10001493 with support.change_cwd(path=self.dir), \
Barry Warsaw618738b2013-04-16 11:05:03 -04001494 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, path='')
1497 self.assertIsNone(rv)
1498
1499 def test_empty_path_no_PATH(self):
1500 with support.EnvironmentVarGuard() as env:
1501 env.pop('PATH', None)
1502 rv = shutil.which(self.file)
1503 self.assertIsNone(rv)
1504
Brian Curtinc57a3452012-06-22 16:00:30 -05001505
Christian Heimesada8c3b2008-03-18 18:26:33 +00001506class TestMove(unittest.TestCase):
1507
1508 def setUp(self):
1509 filename = "foo"
1510 self.src_dir = tempfile.mkdtemp()
1511 self.dst_dir = tempfile.mkdtemp()
1512 self.src_file = os.path.join(self.src_dir, filename)
1513 self.dst_file = os.path.join(self.dst_dir, filename)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001514 with open(self.src_file, "wb") as f:
1515 f.write(b"spam")
1516
1517 def tearDown(self):
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001518 for d in (self.src_dir, self.dst_dir):
Christian Heimesada8c3b2008-03-18 18:26:33 +00001519 try:
1520 if d:
1521 shutil.rmtree(d)
1522 except:
1523 pass
1524
1525 def _check_move_file(self, src, dst, real_dst):
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001526 with open(src, "rb") as f:
1527 contents = f.read()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001528 shutil.move(src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001529 with open(real_dst, "rb") as f:
1530 self.assertEqual(contents, f.read())
Christian Heimesada8c3b2008-03-18 18:26:33 +00001531 self.assertFalse(os.path.exists(src))
1532
1533 def _check_move_dir(self, src, dst, real_dst):
1534 contents = sorted(os.listdir(src))
1535 shutil.move(src, dst)
1536 self.assertEqual(contents, sorted(os.listdir(real_dst)))
1537 self.assertFalse(os.path.exists(src))
1538
1539 def test_move_file(self):
1540 # Move a file to another location on the same filesystem.
1541 self._check_move_file(self.src_file, self.dst_file, self.dst_file)
1542
1543 def test_move_file_to_dir(self):
1544 # Move a file inside an existing dir on the same filesystem.
1545 self._check_move_file(self.src_file, self.dst_dir, self.dst_file)
1546
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001547 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001548 def test_move_file_other_fs(self):
1549 # Move a file to an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001550 self.test_move_file()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001551
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001552 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001553 def test_move_file_to_dir_other_fs(self):
1554 # Move a file to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001555 self.test_move_file_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001556
1557 def test_move_dir(self):
1558 # Move a dir to another location on the same filesystem.
1559 dst_dir = tempfile.mktemp()
1560 try:
1561 self._check_move_dir(self.src_dir, dst_dir, dst_dir)
1562 finally:
1563 try:
1564 shutil.rmtree(dst_dir)
1565 except:
1566 pass
1567
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001568 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001569 def test_move_dir_other_fs(self):
1570 # Move a dir to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001571 self.test_move_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001572
1573 def test_move_dir_to_dir(self):
1574 # Move a dir inside an existing dir on the same filesystem.
1575 self._check_move_dir(self.src_dir, self.dst_dir,
1576 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1577
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001578 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001579 def test_move_dir_to_dir_other_fs(self):
1580 # Move a dir inside an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001581 self.test_move_dir_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001582
Serhiy Storchaka3a308b92014-02-11 10:30:59 +02001583 def test_move_dir_sep_to_dir(self):
1584 self._check_move_dir(self.src_dir + os.path.sep, self.dst_dir,
1585 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1586
1587 @unittest.skipUnless(os.path.altsep, 'requires os.path.altsep')
1588 def test_move_dir_altsep_to_dir(self):
1589 self._check_move_dir(self.src_dir + os.path.altsep, self.dst_dir,
1590 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1591
Christian Heimesada8c3b2008-03-18 18:26:33 +00001592 def test_existing_file_inside_dest_dir(self):
1593 # A file with the same name inside the destination dir already exists.
1594 with open(self.dst_file, "wb"):
1595 pass
1596 self.assertRaises(shutil.Error, shutil.move, self.src_file, self.dst_dir)
1597
1598 def test_dont_move_dir_in_itself(self):
1599 # Moving a dir inside itself raises an Error.
1600 dst = os.path.join(self.src_dir, "bar")
1601 self.assertRaises(shutil.Error, shutil.move, self.src_dir, dst)
1602
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001603 def test_destinsrc_false_negative(self):
1604 os.mkdir(TESTFN)
1605 try:
1606 for src, dst in [('srcdir', 'srcdir/dest')]:
1607 src = os.path.join(TESTFN, src)
1608 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001609 self.assertTrue(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001610 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001611 'dst (%s) is not in src (%s)' % (dst, src))
1612 finally:
1613 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001614
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001615 def test_destinsrc_false_positive(self):
1616 os.mkdir(TESTFN)
1617 try:
1618 for src, dst in [('srcdir', 'src/dest'), ('srcdir', 'srcdir.new')]:
1619 src = os.path.join(TESTFN, src)
1620 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001621 self.assertFalse(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001622 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001623 'dst (%s) is in src (%s)' % (dst, src))
1624 finally:
1625 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimes9bd667a2008-01-20 15:14:11 +00001626
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +01001627 @support.skip_unless_symlink
1628 @mock_rename
1629 def test_move_file_symlink(self):
1630 dst = os.path.join(self.src_dir, 'bar')
1631 os.symlink(self.src_file, dst)
1632 shutil.move(dst, self.dst_file)
1633 self.assertTrue(os.path.islink(self.dst_file))
1634 self.assertTrue(os.path.samefile(self.src_file, self.dst_file))
1635
1636 @support.skip_unless_symlink
1637 @mock_rename
1638 def test_move_file_symlink_to_dir(self):
1639 filename = "bar"
1640 dst = os.path.join(self.src_dir, filename)
1641 os.symlink(self.src_file, dst)
1642 shutil.move(dst, self.dst_dir)
1643 final_link = os.path.join(self.dst_dir, filename)
1644 self.assertTrue(os.path.islink(final_link))
1645 self.assertTrue(os.path.samefile(self.src_file, final_link))
1646
1647 @support.skip_unless_symlink
1648 @mock_rename
1649 def test_move_dangling_symlink(self):
1650 src = os.path.join(self.src_dir, 'baz')
1651 dst = os.path.join(self.src_dir, 'bar')
1652 os.symlink(src, dst)
1653 dst_link = os.path.join(self.dst_dir, 'quux')
1654 shutil.move(dst, dst_link)
1655 self.assertTrue(os.path.islink(dst_link))
Antoine Pitrou3f48ac92014-01-01 02:50:45 +01001656 # On Windows, os.path.realpath does not follow symlinks (issue #9949)
1657 if os.name == 'nt':
1658 self.assertEqual(os.path.realpath(src), os.readlink(dst_link))
1659 else:
1660 self.assertEqual(os.path.realpath(src), os.path.realpath(dst_link))
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +01001661
1662 @support.skip_unless_symlink
1663 @mock_rename
1664 def test_move_dir_symlink(self):
1665 src = os.path.join(self.src_dir, 'baz')
1666 dst = os.path.join(self.src_dir, 'bar')
1667 os.mkdir(src)
1668 os.symlink(src, dst)
1669 dst_link = os.path.join(self.dst_dir, 'quux')
1670 shutil.move(dst, dst_link)
1671 self.assertTrue(os.path.islink(dst_link))
1672 self.assertTrue(os.path.samefile(src, dst_link))
1673
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001674 def test_move_return_value(self):
1675 rv = shutil.move(self.src_file, self.dst_dir)
1676 self.assertEqual(rv,
1677 os.path.join(self.dst_dir, os.path.basename(self.src_file)))
1678
1679 def test_move_as_rename_return_value(self):
1680 rv = shutil.move(self.src_file, os.path.join(self.dst_dir, 'bar'))
1681 self.assertEqual(rv, os.path.join(self.dst_dir, 'bar'))
1682
R David Murray6ffface2014-06-11 14:40:13 -04001683 @mock_rename
1684 def test_move_file_special_function(self):
1685 moved = []
1686 def _copy(src, dst):
1687 moved.append((src, dst))
1688 shutil.move(self.src_file, self.dst_dir, copy_function=_copy)
1689 self.assertEqual(len(moved), 1)
1690
1691 @mock_rename
1692 def test_move_dir_special_function(self):
1693 moved = []
1694 def _copy(src, dst):
1695 moved.append((src, dst))
1696 support.create_empty_file(os.path.join(self.src_dir, 'child'))
1697 support.create_empty_file(os.path.join(self.src_dir, 'child1'))
1698 shutil.move(self.src_dir, self.dst_dir, copy_function=_copy)
1699 self.assertEqual(len(moved), 3)
1700
Tarek Ziadé5340db32010-04-19 22:30:51 +00001701
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001702class TestCopyFile(unittest.TestCase):
1703
1704 _delete = False
1705
1706 class Faux(object):
1707 _entered = False
1708 _exited_with = None
1709 _raised = False
1710 def __init__(self, raise_in_exit=False, suppress_at_exit=True):
1711 self._raise_in_exit = raise_in_exit
1712 self._suppress_at_exit = suppress_at_exit
1713 def read(self, *args):
1714 return ''
1715 def __enter__(self):
1716 self._entered = True
1717 def __exit__(self, exc_type, exc_val, exc_tb):
1718 self._exited_with = exc_type, exc_val, exc_tb
1719 if self._raise_in_exit:
1720 self._raised = True
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001721 raise OSError("Cannot close")
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001722 return self._suppress_at_exit
1723
1724 def tearDown(self):
1725 if self._delete:
1726 del shutil.open
1727
1728 def _set_shutil_open(self, func):
1729 shutil.open = func
1730 self._delete = True
1731
1732 def test_w_source_open_fails(self):
1733 def _open(filename, mode='r'):
1734 if filename == 'srcfile':
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001735 raise OSError('Cannot open "srcfile"')
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001736 assert 0 # shouldn't reach here.
1737
1738 self._set_shutil_open(_open)
1739
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001740 self.assertRaises(OSError, shutil.copyfile, 'srcfile', 'destfile')
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001741
1742 def test_w_dest_open_fails(self):
1743
1744 srcfile = self.Faux()
1745
1746 def _open(filename, mode='r'):
1747 if filename == 'srcfile':
1748 return srcfile
1749 if filename == 'destfile':
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001750 raise OSError('Cannot open "destfile"')
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001751 assert 0 # shouldn't reach here.
1752
1753 self._set_shutil_open(_open)
1754
1755 shutil.copyfile('srcfile', 'destfile')
1756 self.assertTrue(srcfile._entered)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001757 self.assertTrue(srcfile._exited_with[0] is OSError)
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001758 self.assertEqual(srcfile._exited_with[1].args,
1759 ('Cannot open "destfile"',))
1760
1761 def test_w_dest_close_fails(self):
1762
1763 srcfile = self.Faux()
1764 destfile = self.Faux(True)
1765
1766 def _open(filename, mode='r'):
1767 if filename == 'srcfile':
1768 return srcfile
1769 if filename == 'destfile':
1770 return destfile
1771 assert 0 # shouldn't reach here.
1772
1773 self._set_shutil_open(_open)
1774
1775 shutil.copyfile('srcfile', 'destfile')
1776 self.assertTrue(srcfile._entered)
1777 self.assertTrue(destfile._entered)
1778 self.assertTrue(destfile._raised)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001779 self.assertTrue(srcfile._exited_with[0] is OSError)
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001780 self.assertEqual(srcfile._exited_with[1].args,
1781 ('Cannot close',))
1782
1783 def test_w_source_close_fails(self):
1784
1785 srcfile = self.Faux(True)
1786 destfile = self.Faux()
1787
1788 def _open(filename, mode='r'):
1789 if filename == 'srcfile':
1790 return srcfile
1791 if filename == 'destfile':
1792 return destfile
1793 assert 0 # shouldn't reach here.
1794
1795 self._set_shutil_open(_open)
1796
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001797 self.assertRaises(OSError,
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001798 shutil.copyfile, 'srcfile', 'destfile')
1799 self.assertTrue(srcfile._entered)
1800 self.assertTrue(destfile._entered)
1801 self.assertFalse(destfile._raised)
1802 self.assertTrue(srcfile._exited_with[0] is None)
1803 self.assertTrue(srcfile._raised)
1804
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001805 def test_move_dir_caseinsensitive(self):
1806 # Renames a folder to the same name
1807 # but a different case.
1808
1809 self.src_dir = tempfile.mkdtemp()
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001810 self.addCleanup(shutil.rmtree, self.src_dir, True)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001811 dst_dir = os.path.join(
1812 os.path.dirname(self.src_dir),
1813 os.path.basename(self.src_dir).upper())
1814 self.assertNotEqual(self.src_dir, dst_dir)
1815
1816 try:
1817 shutil.move(self.src_dir, dst_dir)
1818 self.assertTrue(os.path.isdir(dst_dir))
1819 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +02001820 os.rmdir(dst_dir)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001821
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001822class TermsizeTests(unittest.TestCase):
1823 def test_does_not_crash(self):
1824 """Check if get_terminal_size() returns a meaningful value.
1825
1826 There's no easy portable way to actually check the size of the
1827 terminal, so let's check if it returns something sensible instead.
1828 """
1829 size = shutil.get_terminal_size()
Antoine Pitroucfade362012-02-08 23:48:59 +01001830 self.assertGreaterEqual(size.columns, 0)
1831 self.assertGreaterEqual(size.lines, 0)
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001832
1833 def test_os_environ_first(self):
1834 "Check if environment variables have precedence"
1835
1836 with support.EnvironmentVarGuard() as env:
1837 env['COLUMNS'] = '777'
Serhiy Storchakad30829d2016-04-24 09:58:43 +03001838 del env['LINES']
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001839 size = shutil.get_terminal_size()
1840 self.assertEqual(size.columns, 777)
1841
1842 with support.EnvironmentVarGuard() as env:
Serhiy Storchakad30829d2016-04-24 09:58:43 +03001843 del env['COLUMNS']
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001844 env['LINES'] = '888'
1845 size = shutil.get_terminal_size()
1846 self.assertEqual(size.lines, 888)
1847
Serhiy Storchakad30829d2016-04-24 09:58:43 +03001848 def test_bad_environ(self):
1849 with support.EnvironmentVarGuard() as env:
1850 env['COLUMNS'] = 'xxx'
1851 env['LINES'] = 'yyy'
1852 size = shutil.get_terminal_size()
1853 self.assertGreaterEqual(size.columns, 0)
1854 self.assertGreaterEqual(size.lines, 0)
1855
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001856 @unittest.skipUnless(os.isatty(sys.__stdout__.fileno()), "not on tty")
Victor Stinner119ebb72016-04-19 22:24:56 +02001857 @unittest.skipUnless(hasattr(os, 'get_terminal_size'),
1858 'need os.get_terminal_size()')
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001859 def test_stty_match(self):
1860 """Check if stty returns the same results ignoring env
1861
1862 This test will fail if stdin and stdout are connected to
1863 different terminals with different sizes. Nevertheless, such
1864 situations should be pretty rare.
1865 """
1866 try:
1867 size = subprocess.check_output(['stty', 'size']).decode().split()
Xavier de Gaye38c8b7d2016-11-14 17:14:42 +01001868 except (FileNotFoundError, PermissionError,
1869 subprocess.CalledProcessError):
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001870 self.skipTest("stty invocation failed")
1871 expected = (int(size[1]), int(size[0])) # reversed order
1872
1873 with support.EnvironmentVarGuard() as env:
1874 del env['LINES']
1875 del env['COLUMNS']
1876 actual = shutil.get_terminal_size()
1877
1878 self.assertEqual(expected, actual)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001879
Serhiy Storchakad30829d2016-04-24 09:58:43 +03001880 def test_fallback(self):
1881 with support.EnvironmentVarGuard() as env:
1882 del env['LINES']
1883 del env['COLUMNS']
1884
1885 # sys.__stdout__ has no fileno()
1886 with support.swap_attr(sys, '__stdout__', None):
1887 size = shutil.get_terminal_size(fallback=(10, 20))
1888 self.assertEqual(size.columns, 10)
1889 self.assertEqual(size.lines, 20)
1890
1891 # sys.__stdout__ is not a terminal on Unix
1892 # or fileno() not in (0, 1, 2) on Windows
1893 with open(os.devnull, 'w') as f, \
1894 support.swap_attr(sys, '__stdout__', f):
1895 size = shutil.get_terminal_size(fallback=(30, 40))
1896 self.assertEqual(size.columns, 30)
1897 self.assertEqual(size.lines, 40)
1898
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001899
Berker Peksag8083cd62014-11-01 11:04:06 +02001900class PublicAPITests(unittest.TestCase):
1901 """Ensures that the correct values are exposed in the public API."""
1902
1903 def test_module_all_attribute(self):
1904 self.assertTrue(hasattr(shutil, '__all__'))
1905 target_api = ['copyfileobj', 'copyfile', 'copymode', 'copystat',
1906 'copy', 'copy2', 'copytree', 'move', 'rmtree', 'Error',
1907 'SpecialFileError', 'ExecError', 'make_archive',
1908 'get_archive_formats', 'register_archive_format',
1909 'unregister_archive_format', 'get_unpack_formats',
1910 'register_unpack_format', 'unregister_unpack_format',
1911 'unpack_archive', 'ignore_patterns', 'chown', 'which',
1912 'get_terminal_size', 'SameFileError']
1913 if hasattr(os, 'statvfs') or os.name == 'nt':
1914 target_api.append('disk_usage')
1915 self.assertEqual(set(shutil.__all__), set(target_api))
1916
1917
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001918if __name__ == '__main__':
Brett Cannon3e9a9ae2013-06-12 21:25:59 -04001919 unittest.main()