blob: 1e65a2a471dc6be7107aa2ccf3899eb637ab03bc [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
Ezio Melotti975077a2011-05-19 22:03:22 +030025from test.support import TESTFN, check_warnings, captured_stdout, requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +000026
Tarek Ziadéffa155a2010-04-29 13:34:35 +000027try:
28 import bz2
29 BZ2_SUPPORTED = True
30except ImportError:
31 BZ2_SUPPORTED = False
32
Serhiy Storchaka11213772014-08-06 18:50:19 +030033try:
34 import lzma
35 LZMA_SUPPORTED = True
36except ImportError:
37 LZMA_SUPPORTED = False
38
Antoine Pitrou7fff0962009-05-01 21:09:44 +000039TESTFN2 = TESTFN + "2"
Barry Warsaw7fc2cca2003-01-24 17:34:13 +000040
Tarek Ziadé396fad72010-02-23 05:30:31 +000041try:
42 import grp
43 import pwd
44 UID_GID_SUPPORT = True
45except ImportError:
46 UID_GID_SUPPORT = False
47
48try:
Tarek Ziadé396fad72010-02-23 05:30:31 +000049 import zipfile
50 ZIP_SUPPORT = True
51except ImportError:
Serhiy Storchakab42de2f2015-11-21 14:09:26 +020052 ZIP_SUPPORT = shutil.which('zip')
Tarek Ziadé396fad72010-02-23 05:30:31 +000053
Nick Coghlan8ed3cf32011-03-16 14:05:35 -040054def _fake_rename(*args, **kwargs):
55 # Pretend the destination path is on a different filesystem.
Antoine Pitrouc041ab62012-01-02 19:18:02 +010056 raise OSError(getattr(errno, 'EXDEV', 18), "Invalid cross-device link")
Nick Coghlan8ed3cf32011-03-16 14:05:35 -040057
58def mock_rename(func):
59 @functools.wraps(func)
60 def wrap(*args, **kwargs):
61 try:
62 builtin_rename = os.rename
63 os.rename = _fake_rename
64 return func(*args, **kwargs)
65 finally:
66 os.rename = builtin_rename
67 return wrap
68
Éric Araujoa7e33a12011-08-12 19:51:35 +020069def write_file(path, content, binary=False):
70 """Write *content* to a file located at *path*.
71
72 If *path* is a tuple instead of a string, os.path.join will be used to
73 make a path. If *binary* is true, the file will be opened in binary
74 mode.
75 """
76 if isinstance(path, tuple):
77 path = os.path.join(*path)
78 with open(path, 'wb' if binary else 'w') as fp:
79 fp.write(content)
80
81def read_file(path, binary=False):
82 """Return contents from a file located at *path*.
83
84 If *path* is a tuple instead of a string, os.path.join will be used to
85 make a path. If *binary* is true, the file will be opened in binary
86 mode.
87 """
88 if isinstance(path, tuple):
89 path = os.path.join(*path)
90 with open(path, 'rb' if binary else 'r') as fp:
91 return fp.read()
92
Serhiy Storchaka527ef072015-09-06 18:33:19 +030093def rlistdir(path):
94 res = []
95 for name in sorted(os.listdir(path)):
96 p = os.path.join(path, name)
97 if os.path.isdir(p) and not os.path.islink(p):
98 res.append(name + '/')
99 for n in rlistdir(p):
100 res.append(name + '/' + n)
101 else:
102 res.append(name)
103 return res
104
Éric Araujoa7e33a12011-08-12 19:51:35 +0200105
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000106class TestShutil(unittest.TestCase):
Tarek Ziadé396fad72010-02-23 05:30:31 +0000107
108 def setUp(self):
109 super(TestShutil, self).setUp()
110 self.tempdirs = []
111
112 def tearDown(self):
113 super(TestShutil, self).tearDown()
114 while self.tempdirs:
115 d = self.tempdirs.pop()
116 shutil.rmtree(d, os.name in ('nt', 'cygwin'))
117
Tarek Ziadé396fad72010-02-23 05:30:31 +0000118
119 def mkdtemp(self):
120 """Create a temporary directory that will be cleaned up.
121
122 Returns the path of the directory.
123 """
124 d = tempfile.mkdtemp()
125 self.tempdirs.append(d)
126 return d
Tarek Ziadé5340db32010-04-19 22:30:51 +0000127
Hynek Schlawack3b527782012-06-25 13:27:31 +0200128 def test_rmtree_works_on_bytes(self):
129 tmp = self.mkdtemp()
130 victim = os.path.join(tmp, 'killme')
131 os.mkdir(victim)
132 write_file(os.path.join(victim, 'somefile'), 'foo')
133 victim = os.fsencode(victim)
134 self.assertIsInstance(victim, bytes)
Serhiy Storchaka41ad77c2014-08-07 19:38:37 +0300135 win = (os.name == 'nt')
136 with self.assertWarns(DeprecationWarning) if win else ExitStack():
137 shutil.rmtree(victim)
Hynek Schlawack3b527782012-06-25 13:27:31 +0200138
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200139 @support.skip_unless_symlink
140 def test_rmtree_fails_on_symlink(self):
141 tmp = self.mkdtemp()
142 dir_ = os.path.join(tmp, 'dir')
143 os.mkdir(dir_)
144 link = os.path.join(tmp, 'link')
145 os.symlink(dir_, link)
146 self.assertRaises(OSError, shutil.rmtree, link)
147 self.assertTrue(os.path.exists(dir_))
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100148 self.assertTrue(os.path.lexists(link))
149 errors = []
150 def onerror(*args):
151 errors.append(args)
152 shutil.rmtree(link, onerror=onerror)
153 self.assertEqual(len(errors), 1)
154 self.assertIs(errors[0][0], os.path.islink)
155 self.assertEqual(errors[0][1], link)
156 self.assertIsInstance(errors[0][2][1], OSError)
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200157
158 @support.skip_unless_symlink
159 def test_rmtree_works_on_symlinks(self):
160 tmp = self.mkdtemp()
161 dir1 = os.path.join(tmp, 'dir1')
162 dir2 = os.path.join(dir1, 'dir2')
163 dir3 = os.path.join(tmp, 'dir3')
164 for d in dir1, dir2, dir3:
165 os.mkdir(d)
166 file1 = os.path.join(tmp, 'file1')
167 write_file(file1, 'foo')
168 link1 = os.path.join(dir1, 'link1')
169 os.symlink(dir2, link1)
170 link2 = os.path.join(dir1, 'link2')
171 os.symlink(dir3, link2)
172 link3 = os.path.join(dir1, 'link3')
173 os.symlink(file1, link3)
174 # make sure symlinks are removed but not followed
175 shutil.rmtree(dir1)
176 self.assertFalse(os.path.exists(dir1))
177 self.assertTrue(os.path.exists(dir3))
178 self.assertTrue(os.path.exists(file1))
179
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000180 def test_rmtree_errors(self):
181 # filename is guaranteed not to exist
182 filename = tempfile.mktemp()
Hynek Schlawackb5501102012-12-10 09:11:25 +0100183 self.assertRaises(FileNotFoundError, shutil.rmtree, filename)
184 # test that ignore_errors option is honored
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100185 shutil.rmtree(filename, ignore_errors=True)
186
187 # existing file
188 tmpdir = self.mkdtemp()
Hynek Schlawackb5501102012-12-10 09:11:25 +0100189 write_file((tmpdir, "tstfile"), "")
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100190 filename = os.path.join(tmpdir, "tstfile")
Hynek Schlawackb5501102012-12-10 09:11:25 +0100191 with self.assertRaises(NotADirectoryError) as cm:
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100192 shutil.rmtree(filename)
Hynek Schlawack87f9b462012-12-10 16:29:57 +0100193 # The reason for this rather odd construct is that Windows sprinkles
194 # a \*.* at the end of file names. But only sometimes on some buildbots
195 possible_args = [filename, os.path.join(filename, '*.*')]
196 self.assertIn(cm.exception.filename, possible_args)
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100197 self.assertTrue(os.path.exists(filename))
Hynek Schlawackb5501102012-12-10 09:11:25 +0100198 # test that ignore_errors option is honored
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100199 shutil.rmtree(filename, ignore_errors=True)
200 self.assertTrue(os.path.exists(filename))
201 errors = []
202 def onerror(*args):
203 errors.append(args)
204 shutil.rmtree(filename, onerror=onerror)
205 self.assertEqual(len(errors), 2)
206 self.assertIs(errors[0][0], os.listdir)
207 self.assertEqual(errors[0][1], filename)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100208 self.assertIsInstance(errors[0][2][1], NotADirectoryError)
Hynek Schlawack87f9b462012-12-10 16:29:57 +0100209 self.assertIn(errors[0][2][1].filename, possible_args)
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100210 self.assertIs(errors[1][0], os.rmdir)
211 self.assertEqual(errors[1][1], filename)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100212 self.assertIsInstance(errors[1][2][1], NotADirectoryError)
Hynek Schlawack87f9b462012-12-10 16:29:57 +0100213 self.assertIn(errors[1][2][1].filename, possible_args)
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000214
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000215
Serhiy Storchaka43767632013-11-03 21:31:38 +0200216 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod()')
217 @unittest.skipIf(sys.platform[:6] == 'cygwin',
218 "This test can't be run on Cygwin (issue #1071513).")
219 @unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0,
220 "This test can't be run reliably as root (issue #1076467).")
221 def test_on_error(self):
222 self.errorState = 0
223 os.mkdir(TESTFN)
224 self.addCleanup(shutil.rmtree, TESTFN)
Antoine Pitrou2f8a75c2012-06-23 21:28:15 +0200225
Serhiy Storchaka43767632013-11-03 21:31:38 +0200226 self.child_file_path = os.path.join(TESTFN, 'a')
227 self.child_dir_path = os.path.join(TESTFN, 'b')
228 support.create_empty_file(self.child_file_path)
229 os.mkdir(self.child_dir_path)
230 old_dir_mode = os.stat(TESTFN).st_mode
231 old_child_file_mode = os.stat(self.child_file_path).st_mode
232 old_child_dir_mode = os.stat(self.child_dir_path).st_mode
233 # Make unwritable.
234 new_mode = stat.S_IREAD|stat.S_IEXEC
235 os.chmod(self.child_file_path, new_mode)
236 os.chmod(self.child_dir_path, new_mode)
237 os.chmod(TESTFN, new_mode)
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000238
Serhiy Storchaka43767632013-11-03 21:31:38 +0200239 self.addCleanup(os.chmod, TESTFN, old_dir_mode)
240 self.addCleanup(os.chmod, self.child_file_path, old_child_file_mode)
241 self.addCleanup(os.chmod, self.child_dir_path, old_child_dir_mode)
Antoine Pitrou2f8a75c2012-06-23 21:28:15 +0200242
Serhiy Storchaka43767632013-11-03 21:31:38 +0200243 shutil.rmtree(TESTFN, onerror=self.check_args_to_onerror)
244 # Test whether onerror has actually been called.
245 self.assertEqual(self.errorState, 3,
246 "Expected call to onerror function did not happen.")
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000247
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000248 def check_args_to_onerror(self, func, arg, exc):
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000249 # test_rmtree_errors deliberately runs rmtree
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200250 # on a directory that is chmod 500, which will fail.
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000251 # This function is run when shutil.rmtree fails.
252 # 99.9% of the time it initially fails to remove
253 # a file in the directory, so the first time through
254 # func is os.remove.
255 # However, some Linux machines running ZFS on
256 # FUSE experienced a failure earlier in the process
257 # at os.listdir. The first failure may legally
258 # be either.
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200259 if self.errorState < 2:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200260 if func is os.unlink:
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200261 self.assertEqual(arg, self.child_file_path)
262 elif func is os.rmdir:
263 self.assertEqual(arg, self.child_dir_path)
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000264 else:
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200265 self.assertIs(func, os.listdir)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200266 self.assertIn(arg, [TESTFN, self.child_dir_path])
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000267 self.assertTrue(issubclass(exc[0], OSError))
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200268 self.errorState += 1
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000269 else:
270 self.assertEqual(func, os.rmdir)
271 self.assertEqual(arg, TESTFN)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000272 self.assertTrue(issubclass(exc[0], OSError))
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200273 self.errorState = 3
274
275 def test_rmtree_does_not_choke_on_failing_lstat(self):
276 try:
277 orig_lstat = os.lstat
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200278 def raiser(fn, *args, **kwargs):
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200279 if fn != TESTFN:
280 raise OSError()
281 else:
282 return orig_lstat(fn)
283 os.lstat = raiser
284
285 os.mkdir(TESTFN)
286 write_file((TESTFN, 'foo'), 'foo')
287 shutil.rmtree(TESTFN)
288 finally:
289 os.lstat = orig_lstat
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000290
Antoine Pitrou78091e62011-12-29 18:54:15 +0100291 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
292 @support.skip_unless_symlink
293 def test_copymode_follow_symlinks(self):
294 tmp_dir = self.mkdtemp()
295 src = os.path.join(tmp_dir, 'foo')
296 dst = os.path.join(tmp_dir, 'bar')
297 src_link = os.path.join(tmp_dir, 'baz')
298 dst_link = os.path.join(tmp_dir, 'quux')
299 write_file(src, 'foo')
300 write_file(dst, 'foo')
301 os.symlink(src, src_link)
302 os.symlink(dst, dst_link)
303 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
304 # file to file
305 os.chmod(dst, stat.S_IRWXO)
306 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
307 shutil.copymode(src, dst)
308 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
Antoine Pitrou3f48ac92014-01-01 02:50:45 +0100309 # On Windows, os.chmod does not follow symlinks (issue #15411)
310 if os.name != 'nt':
311 # follow src link
312 os.chmod(dst, stat.S_IRWXO)
313 shutil.copymode(src_link, dst)
314 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
315 # follow dst link
316 os.chmod(dst, stat.S_IRWXO)
317 shutil.copymode(src, dst_link)
318 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
319 # follow both links
320 os.chmod(dst, stat.S_IRWXO)
321 shutil.copymode(src_link, dst_link)
322 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100323
324 @unittest.skipUnless(hasattr(os, 'lchmod'), 'requires os.lchmod')
325 @support.skip_unless_symlink
326 def test_copymode_symlink_to_symlink(self):
327 tmp_dir = self.mkdtemp()
328 src = os.path.join(tmp_dir, 'foo')
329 dst = os.path.join(tmp_dir, 'bar')
330 src_link = os.path.join(tmp_dir, 'baz')
331 dst_link = os.path.join(tmp_dir, 'quux')
332 write_file(src, 'foo')
333 write_file(dst, 'foo')
334 os.symlink(src, src_link)
335 os.symlink(dst, dst_link)
336 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
337 os.chmod(dst, stat.S_IRWXU)
338 os.lchmod(src_link, stat.S_IRWXO|stat.S_IRWXG)
339 # link to link
340 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700341 shutil.copymode(src_link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100342 self.assertEqual(os.lstat(src_link).st_mode,
343 os.lstat(dst_link).st_mode)
344 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
345 # src link - use chmod
346 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700347 shutil.copymode(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100348 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
349 # dst link - use chmod
350 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700351 shutil.copymode(src, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100352 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
353
354 @unittest.skipIf(hasattr(os, 'lchmod'), 'requires os.lchmod to be missing')
355 @support.skip_unless_symlink
356 def test_copymode_symlink_to_symlink_wo_lchmod(self):
357 tmp_dir = self.mkdtemp()
358 src = os.path.join(tmp_dir, 'foo')
359 dst = os.path.join(tmp_dir, 'bar')
360 src_link = os.path.join(tmp_dir, 'baz')
361 dst_link = os.path.join(tmp_dir, 'quux')
362 write_file(src, 'foo')
363 write_file(dst, 'foo')
364 os.symlink(src, src_link)
365 os.symlink(dst, dst_link)
Larry Hastingsb4038062012-07-15 10:57:38 -0700366 shutil.copymode(src_link, dst_link, follow_symlinks=False) # silent fail
Antoine Pitrou78091e62011-12-29 18:54:15 +0100367
368 @support.skip_unless_symlink
369 def test_copystat_symlinks(self):
370 tmp_dir = self.mkdtemp()
371 src = os.path.join(tmp_dir, 'foo')
372 dst = os.path.join(tmp_dir, 'bar')
373 src_link = os.path.join(tmp_dir, 'baz')
374 dst_link = os.path.join(tmp_dir, 'qux')
375 write_file(src, 'foo')
376 src_stat = os.stat(src)
377 os.utime(src, (src_stat.st_atime,
378 src_stat.st_mtime - 42.0)) # ensure different mtimes
379 write_file(dst, 'bar')
380 self.assertNotEqual(os.stat(src).st_mtime, os.stat(dst).st_mtime)
381 os.symlink(src, src_link)
382 os.symlink(dst, dst_link)
383 if hasattr(os, 'lchmod'):
384 os.lchmod(src_link, stat.S_IRWXO)
385 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
386 os.lchflags(src_link, stat.UF_NODUMP)
387 src_link_stat = os.lstat(src_link)
388 # follow
389 if hasattr(os, 'lchmod'):
Larry Hastingsb4038062012-07-15 10:57:38 -0700390 shutil.copystat(src_link, dst_link, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100391 self.assertNotEqual(src_link_stat.st_mode, os.stat(dst).st_mode)
392 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700393 shutil.copystat(src_link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100394 dst_link_stat = os.lstat(dst_link)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700395 if os.utime in os.supports_follow_symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100396 for attr in 'st_atime', 'st_mtime':
397 # The modification times may be truncated in the new file.
398 self.assertLessEqual(getattr(src_link_stat, attr),
399 getattr(dst_link_stat, attr) + 1)
400 if hasattr(os, 'lchmod'):
401 self.assertEqual(src_link_stat.st_mode, dst_link_stat.st_mode)
402 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
403 self.assertEqual(src_link_stat.st_flags, dst_link_stat.st_flags)
404 # tell to follow but dst is not a link
Larry Hastingsb4038062012-07-15 10:57:38 -0700405 shutil.copystat(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100406 self.assertTrue(abs(os.stat(src).st_mtime - os.stat(dst).st_mtime) <
407 00000.1)
408
Ned Deilybaf75712012-05-10 17:05:19 -0700409 @unittest.skipUnless(hasattr(os, 'chflags') and
410 hasattr(errno, 'EOPNOTSUPP') and
411 hasattr(errno, 'ENOTSUP'),
412 "requires os.chflags, EOPNOTSUPP & ENOTSUP")
413 def test_copystat_handles_harmless_chflags_errors(self):
414 tmpdir = self.mkdtemp()
415 file1 = os.path.join(tmpdir, 'file1')
416 file2 = os.path.join(tmpdir, 'file2')
417 write_file(file1, 'xxx')
418 write_file(file2, 'xxx')
419
420 def make_chflags_raiser(err):
421 ex = OSError()
422
Larry Hastings90867a52012-06-22 17:01:41 -0700423 def _chflags_raiser(path, flags, *, follow_symlinks=True):
Ned Deilybaf75712012-05-10 17:05:19 -0700424 ex.errno = err
425 raise ex
426 return _chflags_raiser
427 old_chflags = os.chflags
428 try:
429 for err in errno.EOPNOTSUPP, errno.ENOTSUP:
430 os.chflags = make_chflags_raiser(err)
431 shutil.copystat(file1, file2)
432 # assert others errors break it
433 os.chflags = make_chflags_raiser(errno.EOPNOTSUPP + errno.ENOTSUP)
434 self.assertRaises(OSError, shutil.copystat, file1, file2)
435 finally:
436 os.chflags = old_chflags
437
Antoine Pitrou424246f2012-05-12 19:02:01 +0200438 @support.skip_unless_xattr
439 def test_copyxattr(self):
440 tmp_dir = self.mkdtemp()
441 src = os.path.join(tmp_dir, 'foo')
442 write_file(src, 'foo')
443 dst = os.path.join(tmp_dir, 'bar')
444 write_file(dst, 'bar')
445
446 # no xattr == no problem
447 shutil._copyxattr(src, dst)
448 # common case
449 os.setxattr(src, 'user.foo', b'42')
450 os.setxattr(src, 'user.bar', b'43')
451 shutil._copyxattr(src, dst)
Gregory P. Smith1093bf22014-01-17 12:01:22 -0800452 self.assertEqual(sorted(os.listxattr(src)), sorted(os.listxattr(dst)))
Antoine Pitrou424246f2012-05-12 19:02:01 +0200453 self.assertEqual(
454 os.getxattr(src, 'user.foo'),
455 os.getxattr(dst, 'user.foo'))
456 # check errors don't affect other attrs
457 os.remove(dst)
458 write_file(dst, 'bar')
459 os_error = OSError(errno.EPERM, 'EPERM')
460
Larry Hastings9cf065c2012-06-22 16:30:09 -0700461 def _raise_on_user_foo(fname, attr, val, **kwargs):
Antoine Pitrou424246f2012-05-12 19:02:01 +0200462 if attr == 'user.foo':
463 raise os_error
464 else:
Larry Hastings9cf065c2012-06-22 16:30:09 -0700465 orig_setxattr(fname, attr, val, **kwargs)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200466 try:
467 orig_setxattr = os.setxattr
468 os.setxattr = _raise_on_user_foo
469 shutil._copyxattr(src, dst)
Antoine Pitrou61597d32012-05-12 23:37:35 +0200470 self.assertIn('user.bar', os.listxattr(dst))
Antoine Pitrou424246f2012-05-12 19:02:01 +0200471 finally:
472 os.setxattr = orig_setxattr
Hynek Schlawack0beab052013-02-05 08:22:44 +0100473 # the source filesystem not supporting xattrs should be ok, too.
474 def _raise_on_src(fname, *, follow_symlinks=True):
475 if fname == src:
476 raise OSError(errno.ENOTSUP, 'Operation not supported')
477 return orig_listxattr(fname, follow_symlinks=follow_symlinks)
478 try:
479 orig_listxattr = os.listxattr
480 os.listxattr = _raise_on_src
481 shutil._copyxattr(src, dst)
482 finally:
483 os.listxattr = orig_listxattr
Antoine Pitrou424246f2012-05-12 19:02:01 +0200484
Larry Hastingsad5ae042012-07-14 17:55:11 -0700485 # test that shutil.copystat copies xattrs
486 src = os.path.join(tmp_dir, 'the_original')
487 write_file(src, src)
488 os.setxattr(src, 'user.the_value', b'fiddly')
489 dst = os.path.join(tmp_dir, 'the_copy')
490 write_file(dst, dst)
491 shutil.copystat(src, dst)
Hynek Schlawackc2d481f2012-07-16 17:11:10 +0200492 self.assertEqual(os.getxattr(dst, 'user.the_value'), b'fiddly')
Larry Hastingsad5ae042012-07-14 17:55:11 -0700493
Antoine Pitrou424246f2012-05-12 19:02:01 +0200494 @support.skip_unless_symlink
495 @support.skip_unless_xattr
496 @unittest.skipUnless(hasattr(os, 'geteuid') and os.geteuid() == 0,
497 'root privileges required')
498 def test_copyxattr_symlinks(self):
499 # On Linux, it's only possible to access non-user xattr for symlinks;
500 # which in turn require root privileges. This test should be expanded
501 # as soon as other platforms gain support for extended attributes.
502 tmp_dir = self.mkdtemp()
503 src = os.path.join(tmp_dir, 'foo')
504 src_link = os.path.join(tmp_dir, 'baz')
505 write_file(src, 'foo')
506 os.symlink(src, src_link)
507 os.setxattr(src, 'trusted.foo', b'42')
Larry Hastings9cf065c2012-06-22 16:30:09 -0700508 os.setxattr(src_link, 'trusted.foo', b'43', follow_symlinks=False)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200509 dst = os.path.join(tmp_dir, 'bar')
510 dst_link = os.path.join(tmp_dir, 'qux')
511 write_file(dst, 'bar')
512 os.symlink(dst, dst_link)
Larry Hastingsb4038062012-07-15 10:57:38 -0700513 shutil._copyxattr(src_link, dst_link, follow_symlinks=False)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700514 self.assertEqual(os.getxattr(dst_link, 'trusted.foo', follow_symlinks=False), b'43')
Antoine Pitrou424246f2012-05-12 19:02:01 +0200515 self.assertRaises(OSError, os.getxattr, dst, 'trusted.foo')
Larry Hastingsb4038062012-07-15 10:57:38 -0700516 shutil._copyxattr(src_link, dst, follow_symlinks=False)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200517 self.assertEqual(os.getxattr(dst, 'trusted.foo'), b'43')
518
Antoine Pitrou78091e62011-12-29 18:54:15 +0100519 @support.skip_unless_symlink
520 def test_copy_symlinks(self):
521 tmp_dir = self.mkdtemp()
522 src = os.path.join(tmp_dir, 'foo')
523 dst = os.path.join(tmp_dir, 'bar')
524 src_link = os.path.join(tmp_dir, 'baz')
525 write_file(src, 'foo')
526 os.symlink(src, src_link)
527 if hasattr(os, 'lchmod'):
528 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
529 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700530 shutil.copy(src_link, dst, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100531 self.assertFalse(os.path.islink(dst))
532 self.assertEqual(read_file(src), read_file(dst))
533 os.remove(dst)
534 # follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700535 shutil.copy(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100536 self.assertTrue(os.path.islink(dst))
537 self.assertEqual(os.readlink(dst), os.readlink(src_link))
538 if hasattr(os, 'lchmod'):
539 self.assertEqual(os.lstat(src_link).st_mode,
540 os.lstat(dst).st_mode)
541
542 @support.skip_unless_symlink
543 def test_copy2_symlinks(self):
544 tmp_dir = self.mkdtemp()
545 src = os.path.join(tmp_dir, 'foo')
546 dst = os.path.join(tmp_dir, 'bar')
547 src_link = os.path.join(tmp_dir, 'baz')
548 write_file(src, 'foo')
549 os.symlink(src, src_link)
550 if hasattr(os, 'lchmod'):
551 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
552 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
553 os.lchflags(src_link, stat.UF_NODUMP)
554 src_stat = os.stat(src)
555 src_link_stat = os.lstat(src_link)
556 # follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700557 shutil.copy2(src_link, dst, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100558 self.assertFalse(os.path.islink(dst))
559 self.assertEqual(read_file(src), read_file(dst))
560 os.remove(dst)
561 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700562 shutil.copy2(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100563 self.assertTrue(os.path.islink(dst))
564 self.assertEqual(os.readlink(dst), os.readlink(src_link))
565 dst_stat = os.lstat(dst)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700566 if os.utime in os.supports_follow_symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100567 for attr in 'st_atime', 'st_mtime':
568 # The modification times may be truncated in the new file.
569 self.assertLessEqual(getattr(src_link_stat, attr),
570 getattr(dst_stat, attr) + 1)
571 if hasattr(os, 'lchmod'):
572 self.assertEqual(src_link_stat.st_mode, dst_stat.st_mode)
573 self.assertNotEqual(src_stat.st_mode, dst_stat.st_mode)
574 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
575 self.assertEqual(src_link_stat.st_flags, dst_stat.st_flags)
576
Antoine Pitrou424246f2012-05-12 19:02:01 +0200577 @support.skip_unless_xattr
578 def test_copy2_xattr(self):
579 tmp_dir = self.mkdtemp()
580 src = os.path.join(tmp_dir, 'foo')
581 dst = os.path.join(tmp_dir, 'bar')
582 write_file(src, 'foo')
583 os.setxattr(src, 'user.foo', b'42')
584 shutil.copy2(src, dst)
585 self.assertEqual(
586 os.getxattr(src, 'user.foo'),
587 os.getxattr(dst, 'user.foo'))
588 os.remove(dst)
589
Antoine Pitrou78091e62011-12-29 18:54:15 +0100590 @support.skip_unless_symlink
591 def test_copyfile_symlinks(self):
592 tmp_dir = self.mkdtemp()
593 src = os.path.join(tmp_dir, 'src')
594 dst = os.path.join(tmp_dir, 'dst')
595 dst_link = os.path.join(tmp_dir, 'dst_link')
596 link = os.path.join(tmp_dir, 'link')
597 write_file(src, 'foo')
598 os.symlink(src, link)
599 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700600 shutil.copyfile(link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100601 self.assertTrue(os.path.islink(dst_link))
602 self.assertEqual(os.readlink(link), os.readlink(dst_link))
603 # follow
604 shutil.copyfile(link, dst)
605 self.assertFalse(os.path.islink(dst))
606
Hynek Schlawack2100b422012-06-23 20:28:32 +0200607 def test_rmtree_uses_safe_fd_version_if_available(self):
Hynek Schlawackd0f6e0a2012-06-29 08:28:20 +0200608 _use_fd_functions = ({os.open, os.stat, os.unlink, os.rmdir} <=
609 os.supports_dir_fd and
610 os.listdir in os.supports_fd and
611 os.stat in os.supports_follow_symlinks)
612 if _use_fd_functions:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200613 self.assertTrue(shutil._use_fd_functions)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000614 self.assertTrue(shutil.rmtree.avoids_symlink_attacks)
Hynek Schlawack2100b422012-06-23 20:28:32 +0200615 tmp_dir = self.mkdtemp()
616 d = os.path.join(tmp_dir, 'a')
617 os.mkdir(d)
618 try:
619 real_rmtree = shutil._rmtree_safe_fd
620 class Called(Exception): pass
621 def _raiser(*args, **kwargs):
622 raise Called
623 shutil._rmtree_safe_fd = _raiser
624 self.assertRaises(Called, shutil.rmtree, d)
625 finally:
626 shutil._rmtree_safe_fd = real_rmtree
627 else:
628 self.assertFalse(shutil._use_fd_functions)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000629 self.assertFalse(shutil.rmtree.avoids_symlink_attacks)
Hynek Schlawack2100b422012-06-23 20:28:32 +0200630
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000631 def test_rmtree_dont_delete_file(self):
632 # When called on a file instead of a directory, don't delete it.
633 handle, path = tempfile.mkstemp()
Victor Stinnerbf816222011-06-30 23:25:47 +0200634 os.close(handle)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200635 self.assertRaises(NotADirectoryError, shutil.rmtree, path)
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000636 os.remove(path)
637
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000638 def test_copytree_simple(self):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000639 src_dir = tempfile.mkdtemp()
640 dst_dir = os.path.join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200641 self.addCleanup(shutil.rmtree, src_dir)
642 self.addCleanup(shutil.rmtree, os.path.dirname(dst_dir))
643 write_file((src_dir, 'test.txt'), '123')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000644 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200645 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000646
Éric Araujoa7e33a12011-08-12 19:51:35 +0200647 shutil.copytree(src_dir, dst_dir)
648 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test.txt')))
649 self.assertTrue(os.path.isdir(os.path.join(dst_dir, 'test_dir')))
650 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test_dir',
651 'test.txt')))
652 actual = read_file((dst_dir, 'test.txt'))
653 self.assertEqual(actual, '123')
654 actual = read_file((dst_dir, 'test_dir', 'test.txt'))
655 self.assertEqual(actual, '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000656
Antoine Pitrou78091e62011-12-29 18:54:15 +0100657 @support.skip_unless_symlink
658 def test_copytree_symlinks(self):
659 tmp_dir = self.mkdtemp()
660 src_dir = os.path.join(tmp_dir, 'src')
661 dst_dir = os.path.join(tmp_dir, 'dst')
662 sub_dir = os.path.join(src_dir, 'sub')
663 os.mkdir(src_dir)
664 os.mkdir(sub_dir)
665 write_file((src_dir, 'file.txt'), 'foo')
666 src_link = os.path.join(sub_dir, 'link')
667 dst_link = os.path.join(dst_dir, 'sub/link')
668 os.symlink(os.path.join(src_dir, 'file.txt'),
669 src_link)
670 if hasattr(os, 'lchmod'):
671 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
672 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
673 os.lchflags(src_link, stat.UF_NODUMP)
674 src_stat = os.lstat(src_link)
675 shutil.copytree(src_dir, dst_dir, symlinks=True)
676 self.assertTrue(os.path.islink(os.path.join(dst_dir, 'sub', 'link')))
677 self.assertEqual(os.readlink(os.path.join(dst_dir, 'sub', 'link')),
678 os.path.join(src_dir, 'file.txt'))
679 dst_stat = os.lstat(dst_link)
680 if hasattr(os, 'lchmod'):
681 self.assertEqual(dst_stat.st_mode, src_stat.st_mode)
682 if hasattr(os, 'lchflags'):
683 self.assertEqual(dst_stat.st_flags, src_stat.st_flags)
684
Georg Brandl2ee470f2008-07-16 12:55:28 +0000685 def test_copytree_with_exclude(self):
Georg Brandl2ee470f2008-07-16 12:55:28 +0000686 # creating data
687 join = os.path.join
688 exists = os.path.exists
689 src_dir = tempfile.mkdtemp()
Georg Brandl2ee470f2008-07-16 12:55:28 +0000690 try:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000691 dst_dir = join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200692 write_file((src_dir, 'test.txt'), '123')
693 write_file((src_dir, 'test.tmp'), '123')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000694 os.mkdir(join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200695 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000696 os.mkdir(join(src_dir, 'test_dir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200697 write_file((src_dir, 'test_dir2', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000698 os.mkdir(join(src_dir, 'test_dir2', 'subdir'))
699 os.mkdir(join(src_dir, 'test_dir2', 'subdir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200700 write_file((src_dir, 'test_dir2', 'subdir', 'test.txt'), '456')
701 write_file((src_dir, 'test_dir2', 'subdir2', 'test.py'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000702
703 # testing glob-like patterns
704 try:
705 patterns = shutil.ignore_patterns('*.tmp', 'test_dir2')
706 shutil.copytree(src_dir, dst_dir, ignore=patterns)
707 # checking the result: some elements should not be copied
708 self.assertTrue(exists(join(dst_dir, 'test.txt')))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200709 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
710 self.assertFalse(exists(join(dst_dir, 'test_dir2')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000711 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200712 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000713 try:
714 patterns = shutil.ignore_patterns('*.tmp', 'subdir*')
715 shutil.copytree(src_dir, dst_dir, ignore=patterns)
716 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200717 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
718 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2')))
719 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000720 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200721 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000722
723 # testing callable-style
724 try:
725 def _filter(src, names):
726 res = []
727 for name in names:
728 path = os.path.join(src, name)
729
730 if (os.path.isdir(path) and
731 path.split()[-1] == 'subdir'):
732 res.append(name)
733 elif os.path.splitext(path)[-1] in ('.py'):
734 res.append(name)
735 return res
736
737 shutil.copytree(src_dir, dst_dir, ignore=_filter)
738
739 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200740 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2',
741 'test.py')))
742 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000743
744 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200745 shutil.rmtree(dst_dir)
Georg Brandl2ee470f2008-07-16 12:55:28 +0000746 finally:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000747 shutil.rmtree(src_dir)
748 shutil.rmtree(os.path.dirname(dst_dir))
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000749
Antoine Pitrouac601602013-08-16 19:35:02 +0200750 def test_copytree_retains_permissions(self):
751 tmp_dir = tempfile.mkdtemp()
752 src_dir = os.path.join(tmp_dir, 'source')
753 os.mkdir(src_dir)
754 dst_dir = os.path.join(tmp_dir, 'destination')
755 self.addCleanup(shutil.rmtree, tmp_dir)
756
757 os.chmod(src_dir, 0o777)
758 write_file((src_dir, 'permissive.txt'), '123')
759 os.chmod(os.path.join(src_dir, 'permissive.txt'), 0o777)
760 write_file((src_dir, 'restrictive.txt'), '456')
761 os.chmod(os.path.join(src_dir, 'restrictive.txt'), 0o600)
762 restrictive_subdir = tempfile.mkdtemp(dir=src_dir)
763 os.chmod(restrictive_subdir, 0o600)
764
765 shutil.copytree(src_dir, dst_dir)
Brett Cannon9c7eb552013-08-23 14:38:11 -0400766 self.assertEqual(os.stat(src_dir).st_mode, os.stat(dst_dir).st_mode)
767 self.assertEqual(os.stat(os.path.join(src_dir, 'permissive.txt')).st_mode,
Antoine Pitrouac601602013-08-16 19:35:02 +0200768 os.stat(os.path.join(dst_dir, 'permissive.txt')).st_mode)
Brett Cannon9c7eb552013-08-23 14:38:11 -0400769 self.assertEqual(os.stat(os.path.join(src_dir, 'restrictive.txt')).st_mode,
Antoine Pitrouac601602013-08-16 19:35:02 +0200770 os.stat(os.path.join(dst_dir, 'restrictive.txt')).st_mode)
771 restrictive_subdir_dst = os.path.join(dst_dir,
772 os.path.split(restrictive_subdir)[1])
Brett Cannon9c7eb552013-08-23 14:38:11 -0400773 self.assertEqual(os.stat(restrictive_subdir).st_mode,
Antoine Pitrouac601602013-08-16 19:35:02 +0200774 os.stat(restrictive_subdir_dst).st_mode)
775
Berker Peksag884afd92014-12-10 02:50:32 +0200776 @unittest.mock.patch('os.chmod')
777 def test_copytree_winerror(self, mock_patch):
778 # When copying to VFAT, copystat() raises OSError. On Windows, the
779 # exception object has a meaningful 'winerror' attribute, but not
780 # on other operating systems. Do not assume 'winerror' is set.
781 src_dir = tempfile.mkdtemp()
782 dst_dir = os.path.join(tempfile.mkdtemp(), 'destination')
783 self.addCleanup(shutil.rmtree, src_dir)
784 self.addCleanup(shutil.rmtree, os.path.dirname(dst_dir))
785
786 mock_patch.side_effect = PermissionError('ka-boom')
787 with self.assertRaises(shutil.Error):
788 shutil.copytree(src_dir, dst_dir)
789
Zachary Ware9fe6d862013-12-08 00:20:35 -0600790 @unittest.skipIf(os.name == 'nt', 'temporarily disabled on Windows')
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000791 @unittest.skipUnless(hasattr(os, 'link'), 'requires os.link')
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()')
844 def test_copyfile_named_pipe(self):
845 os.mkfifo(TESTFN)
846 try:
847 self.assertRaises(shutil.SpecialFileError,
848 shutil.copyfile, TESTFN, TESTFN2)
849 self.assertRaises(shutil.SpecialFileError,
850 shutil.copyfile, __file__, TESTFN)
851 finally:
852 os.remove(TESTFN)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000853
Serhiy Storchaka43767632013-11-03 21:31:38 +0200854 @unittest.skipUnless(hasattr(os, "mkfifo"), 'requires os.mkfifo()')
855 @support.skip_unless_symlink
856 def test_copytree_named_pipe(self):
857 os.mkdir(TESTFN)
858 try:
859 subdir = os.path.join(TESTFN, "subdir")
860 os.mkdir(subdir)
861 pipe = os.path.join(subdir, "mypipe")
862 os.mkfifo(pipe)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000863 try:
Serhiy Storchaka43767632013-11-03 21:31:38 +0200864 shutil.copytree(TESTFN, TESTFN2)
865 except shutil.Error as e:
866 errors = e.args[0]
867 self.assertEqual(len(errors), 1)
868 src, dst, error_msg = errors[0]
869 self.assertEqual("`%s` is a named pipe" % pipe, error_msg)
870 else:
871 self.fail("shutil.Error should have been raised")
872 finally:
873 shutil.rmtree(TESTFN, ignore_errors=True)
874 shutil.rmtree(TESTFN2, ignore_errors=True)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000875
Tarek Ziadé5340db32010-04-19 22:30:51 +0000876 def test_copytree_special_func(self):
877
878 src_dir = self.mkdtemp()
879 dst_dir = os.path.join(self.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200880 write_file((src_dir, 'test.txt'), '123')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000881 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200882 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000883
884 copied = []
885 def _copy(src, dst):
886 copied.append((src, dst))
887
888 shutil.copytree(src_dir, dst_dir, copy_function=_copy)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000889 self.assertEqual(len(copied), 2)
Tarek Ziadé5340db32010-04-19 22:30:51 +0000890
Brian Curtin3b4499c2010-12-28 14:31:47 +0000891 @support.skip_unless_symlink
Tarek Ziadéfb437512010-04-20 08:57:33 +0000892 def test_copytree_dangling_symlinks(self):
893
894 # a dangling symlink raises an error at the end
895 src_dir = self.mkdtemp()
896 dst_dir = os.path.join(self.mkdtemp(), 'destination')
897 os.symlink('IDONTEXIST', os.path.join(src_dir, 'test.txt'))
898 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200899 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadéfb437512010-04-20 08:57:33 +0000900 self.assertRaises(Error, shutil.copytree, src_dir, dst_dir)
901
902 # a dangling symlink is ignored with the proper flag
903 dst_dir = os.path.join(self.mkdtemp(), 'destination2')
904 shutil.copytree(src_dir, dst_dir, ignore_dangling_symlinks=True)
905 self.assertNotIn('test.txt', os.listdir(dst_dir))
906
907 # a dangling symlink is copied if symlinks=True
908 dst_dir = os.path.join(self.mkdtemp(), 'destination3')
909 shutil.copytree(src_dir, dst_dir, symlinks=True)
910 self.assertIn('test.txt', os.listdir(dst_dir))
911
Berker Peksag5a294d82015-07-25 14:53:48 +0300912 @support.skip_unless_symlink
913 def test_copytree_symlink_dir(self):
914 src_dir = self.mkdtemp()
915 dst_dir = os.path.join(self.mkdtemp(), 'destination')
916 os.mkdir(os.path.join(src_dir, 'real_dir'))
917 with open(os.path.join(src_dir, 'real_dir', 'test.txt'), 'w'):
918 pass
919 os.symlink(os.path.join(src_dir, 'real_dir'),
920 os.path.join(src_dir, 'link_to_dir'),
921 target_is_directory=True)
922
923 shutil.copytree(src_dir, dst_dir, symlinks=False)
924 self.assertFalse(os.path.islink(os.path.join(dst_dir, 'link_to_dir')))
925 self.assertIn('test.txt', os.listdir(os.path.join(dst_dir, 'link_to_dir')))
926
927 dst_dir = os.path.join(self.mkdtemp(), 'destination2')
928 shutil.copytree(src_dir, dst_dir, symlinks=True)
929 self.assertTrue(os.path.islink(os.path.join(dst_dir, 'link_to_dir')))
930 self.assertIn('test.txt', os.listdir(os.path.join(dst_dir, 'link_to_dir')))
931
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400932 def _copy_file(self, method):
933 fname = 'test.txt'
934 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200935 write_file((tmpdir, fname), 'xxx')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400936 file1 = os.path.join(tmpdir, fname)
937 tmpdir2 = self.mkdtemp()
938 method(file1, tmpdir2)
939 file2 = os.path.join(tmpdir2, fname)
940 return (file1, file2)
941
942 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
943 def test_copy(self):
944 # Ensure that the copied file exists and has the same mode bits.
945 file1, file2 = self._copy_file(shutil.copy)
946 self.assertTrue(os.path.exists(file2))
947 self.assertEqual(os.stat(file1).st_mode, os.stat(file2).st_mode)
948
949 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
Senthil Kumaran0c2dba52011-07-03 18:21:38 -0700950 @unittest.skipUnless(hasattr(os, 'utime'), 'requires os.utime')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400951 def test_copy2(self):
952 # Ensure that the copied file exists and has the same mode and
953 # modification time bits.
954 file1, file2 = self._copy_file(shutil.copy2)
955 self.assertTrue(os.path.exists(file2))
956 file1_stat = os.stat(file1)
957 file2_stat = os.stat(file2)
958 self.assertEqual(file1_stat.st_mode, file2_stat.st_mode)
959 for attr in 'st_atime', 'st_mtime':
960 # The modification times may be truncated in the new file.
961 self.assertLessEqual(getattr(file1_stat, attr),
962 getattr(file2_stat, attr) + 1)
963 if hasattr(os, 'chflags') and hasattr(file1_stat, 'st_flags'):
964 self.assertEqual(getattr(file1_stat, 'st_flags'),
965 getattr(file2_stat, 'st_flags'))
966
Ezio Melotti975077a2011-05-19 22:03:22 +0300967 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000968 def test_make_tarball(self):
969 # creating something to tar
Serhiy Storchaka527ef072015-09-06 18:33:19 +0300970 root_dir, base_dir = self._create_files('')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000971
972 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400973 # force shutil to create the directory
974 os.rmdir(tmpdir2)
Serhiy Storchakaeba8fee2015-09-07 19:58:23 +0300975 # working with relative paths
976 work_dir = os.path.dirname(tmpdir2)
977 rel_base_name = os.path.join(os.path.basename(tmpdir2), 'archive')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000978
Serhiy Storchakaeba8fee2015-09-07 19:58:23 +0300979 with support.change_cwd(work_dir):
Serhiy Storchaka5558d4f2015-09-08 09:59:02 +0300980 base_name = os.path.abspath(rel_base_name)
Serhiy Storchakaeba8fee2015-09-07 19:58:23 +0300981 tarball = make_archive(rel_base_name, 'gztar', root_dir, '.')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000982
983 # check if the compressed tarball was created
Serhiy Storchakaa091a822015-09-07 13:55:25 +0300984 self.assertEqual(tarball, base_name + '.tar.gz')
Serhiy Storchaka527ef072015-09-06 18:33:19 +0300985 self.assertTrue(os.path.isfile(tarball))
986 self.assertTrue(tarfile.is_tarfile(tarball))
987 with tarfile.open(tarball, 'r:gz') as tf:
988 self.assertCountEqual(tf.getnames(),
989 ['.', './sub', './sub2',
990 './file1', './file2', './sub/file3'])
Tarek Ziadé396fad72010-02-23 05:30:31 +0000991
992 # trying an uncompressed one
Serhiy Storchakaeba8fee2015-09-07 19:58:23 +0300993 with support.change_cwd(work_dir):
994 tarball = make_archive(rel_base_name, 'tar', root_dir, '.')
Serhiy Storchakaa091a822015-09-07 13:55:25 +0300995 self.assertEqual(tarball, base_name + '.tar')
Serhiy Storchaka527ef072015-09-06 18:33:19 +0300996 self.assertTrue(os.path.isfile(tarball))
997 self.assertTrue(tarfile.is_tarfile(tarball))
998 with tarfile.open(tarball, 'r') as tf:
999 self.assertCountEqual(tf.getnames(),
1000 ['.', './sub', './sub2',
1001 './file1', './file2', './sub/file3'])
Tarek Ziadé396fad72010-02-23 05:30:31 +00001002
1003 def _tarinfo(self, path):
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001004 with tarfile.open(path) as tar:
Tarek Ziadé396fad72010-02-23 05:30:31 +00001005 names = tar.getnames()
1006 names.sort()
1007 return tuple(names)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001008
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001009 def _create_files(self, base_dir='dist'):
Tarek Ziadé396fad72010-02-23 05:30:31 +00001010 # creating something to tar
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001011 root_dir = self.mkdtemp()
1012 dist = os.path.join(root_dir, base_dir)
1013 os.makedirs(dist, exist_ok=True)
Éric Araujoa7e33a12011-08-12 19:51:35 +02001014 write_file((dist, 'file1'), 'xxx')
1015 write_file((dist, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +00001016 os.mkdir(os.path.join(dist, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +02001017 write_file((dist, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +00001018 os.mkdir(os.path.join(dist, 'sub2'))
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001019 if base_dir:
1020 write_file((root_dir, 'outer'), 'xxx')
1021 return root_dir, base_dir
Tarek Ziadé396fad72010-02-23 05:30:31 +00001022
Ezio Melotti975077a2011-05-19 22:03:22 +03001023 @requires_zlib
Serhiy Storchakab42de2f2015-11-21 14:09:26 +02001024 @unittest.skipUnless(shutil.which('tar'),
Tarek Ziadé396fad72010-02-23 05:30:31 +00001025 'Need the tar command to run')
1026 def test_tarfile_vs_tar(self):
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001027 root_dir, base_dir = self._create_files()
1028 base_name = os.path.join(self.mkdtemp(), 'archive')
Serhiy Storchakaa091a822015-09-07 13:55:25 +03001029 tarball = make_archive(base_name, 'gztar', root_dir, base_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001030
1031 # check if the compressed tarball was created
Serhiy Storchakaa091a822015-09-07 13:55:25 +03001032 self.assertEqual(tarball, base_name + '.tar.gz')
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001033 self.assertTrue(os.path.isfile(tarball))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001034
1035 # now create another tarball using `tar`
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001036 tarball2 = os.path.join(root_dir, 'archive2.tar')
1037 tar_cmd = ['tar', '-cf', 'archive2.tar', base_dir]
Serhiy Storchakab42de2f2015-11-21 14:09:26 +02001038 subprocess.check_call(tar_cmd, cwd=root_dir,
1039 stdout=subprocess.DEVNULL)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001040
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001041 self.assertTrue(os.path.isfile(tarball2))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001042 # let's compare both tarballs
Ezio Melottib3aedd42010-11-20 19:04:17 +00001043 self.assertEqual(self._tarinfo(tarball), self._tarinfo(tarball2))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001044
1045 # trying an uncompressed one
Serhiy Storchakaa091a822015-09-07 13:55:25 +03001046 tarball = make_archive(base_name, 'tar', root_dir, base_dir)
1047 self.assertEqual(tarball, base_name + '.tar')
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001048 self.assertTrue(os.path.isfile(tarball))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001049
1050 # now for a dry_run
Serhiy Storchakaa091a822015-09-07 13:55:25 +03001051 tarball = make_archive(base_name, 'tar', root_dir, base_dir,
1052 dry_run=True)
1053 self.assertEqual(tarball, base_name + '.tar')
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001054 self.assertTrue(os.path.isfile(tarball))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001055
Ezio Melotti975077a2011-05-19 22:03:22 +03001056 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001057 @unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run')
1058 def test_make_zipfile(self):
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001059 # creating something to zip
1060 root_dir, base_dir = self._create_files()
Serhiy Storchakaeba8fee2015-09-07 19:58:23 +03001061
1062 tmpdir2 = self.mkdtemp()
1063 # force shutil to create the directory
1064 os.rmdir(tmpdir2)
1065 # working with relative paths
1066 work_dir = os.path.dirname(tmpdir2)
1067 rel_base_name = os.path.join(os.path.basename(tmpdir2), 'archive')
Serhiy Storchakaeba8fee2015-09-07 19:58:23 +03001068
1069 with support.change_cwd(work_dir):
Serhiy Storchaka5558d4f2015-09-08 09:59:02 +03001070 base_name = os.path.abspath(rel_base_name)
Serhiy Storchaka666de772016-10-23 15:55:09 +03001071 res = make_archive(rel_base_name, 'zip', root_dir)
1072
1073 self.assertEqual(res, base_name + '.zip')
1074 self.assertTrue(os.path.isfile(res))
1075 self.assertTrue(zipfile.is_zipfile(res))
1076 with zipfile.ZipFile(res) as zf:
1077 self.assertCountEqual(zf.namelist(),
1078 ['dist/', 'dist/sub/', 'dist/sub2/',
1079 'dist/file1', 'dist/file2', 'dist/sub/file3',
1080 'outer'])
1081
1082 with support.change_cwd(work_dir):
1083 base_name = os.path.abspath(rel_base_name)
Serhiy Storchaka2504cec2015-09-08 05:47:23 +03001084 res = make_archive(rel_base_name, 'zip', root_dir, base_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001085
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001086 self.assertEqual(res, base_name + '.zip')
1087 self.assertTrue(os.path.isfile(res))
1088 self.assertTrue(zipfile.is_zipfile(res))
1089 with zipfile.ZipFile(res) as zf:
1090 self.assertCountEqual(zf.namelist(),
Serhiy Storchaka2504cec2015-09-08 05:47:23 +03001091 ['dist/', 'dist/sub/', 'dist/sub2/',
1092 'dist/file1', 'dist/file2', 'dist/sub/file3'])
Tarek Ziadé396fad72010-02-23 05:30:31 +00001093
Serhiy Storchaka2504cec2015-09-08 05:47:23 +03001094 @requires_zlib
1095 @unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run')
Serhiy Storchakab42de2f2015-11-21 14:09:26 +02001096 @unittest.skipUnless(shutil.which('zip'),
Serhiy Storchaka2504cec2015-09-08 05:47:23 +03001097 'Need the zip command to run')
1098 def test_zipfile_vs_zip(self):
1099 root_dir, base_dir = self._create_files()
1100 base_name = os.path.join(self.mkdtemp(), 'archive')
1101 archive = make_archive(base_name, 'zip', root_dir, base_dir)
1102
1103 # check if ZIP file was created
1104 self.assertEqual(archive, base_name + '.zip')
1105 self.assertTrue(os.path.isfile(archive))
1106
1107 # now create another ZIP file using `zip`
1108 archive2 = os.path.join(root_dir, 'archive2.zip')
1109 zip_cmd = ['zip', '-q', '-r', 'archive2.zip', base_dir]
Serhiy Storchakab42de2f2015-11-21 14:09:26 +02001110 subprocess.check_call(zip_cmd, cwd=root_dir,
1111 stdout=subprocess.DEVNULL)
Serhiy Storchaka2504cec2015-09-08 05:47:23 +03001112
1113 self.assertTrue(os.path.isfile(archive2))
1114 # let's compare both ZIP files
1115 with zipfile.ZipFile(archive) as zf:
1116 names = zf.namelist()
1117 with zipfile.ZipFile(archive2) as zf:
1118 names2 = zf.namelist()
1119 self.assertEqual(sorted(names), sorted(names2))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001120
Serhiy Storchaka8bc792a2015-11-22 14:49:58 +02001121 @requires_zlib
1122 @unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run')
1123 @unittest.skipUnless(shutil.which('unzip'),
1124 'Need the unzip command to run')
1125 def test_unzip_zipfile(self):
1126 root_dir, base_dir = self._create_files()
1127 base_name = os.path.join(self.mkdtemp(), 'archive')
1128 archive = make_archive(base_name, 'zip', root_dir, base_dir)
1129
1130 # check if ZIP file was created
1131 self.assertEqual(archive, base_name + '.zip')
1132 self.assertTrue(os.path.isfile(archive))
1133
1134 # now check the ZIP file using `unzip -t`
1135 zip_cmd = ['unzip', '-t', archive]
1136 with support.change_cwd(root_dir):
1137 try:
1138 subprocess.check_output(zip_cmd, stderr=subprocess.STDOUT)
1139 except subprocess.CalledProcessError as exc:
1140 details = exc.output.decode(errors="replace")
1141 msg = "{}\n\n**Unzip Output**\n{}"
1142 self.fail(msg.format(exc, details))
1143
Tarek Ziadé396fad72010-02-23 05:30:31 +00001144 def test_make_archive(self):
1145 tmpdir = self.mkdtemp()
1146 base_name = os.path.join(tmpdir, 'archive')
1147 self.assertRaises(ValueError, make_archive, base_name, 'xxx')
1148
Ezio Melotti975077a2011-05-19 22:03:22 +03001149 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001150 def test_make_archive_owner_group(self):
1151 # testing make_archive with owner and group, with various combinations
1152 # this works even if there's not gid/uid support
1153 if UID_GID_SUPPORT:
1154 group = grp.getgrgid(0)[0]
1155 owner = pwd.getpwuid(0)[0]
1156 else:
1157 group = owner = 'root'
1158
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001159 root_dir, base_dir = self._create_files()
1160 base_name = os.path.join(self.mkdtemp(), 'archive')
Tarek Ziadé396fad72010-02-23 05:30:31 +00001161 res = make_archive(base_name, 'zip', root_dir, base_dir, owner=owner,
1162 group=group)
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001163 self.assertTrue(os.path.isfile(res))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001164
1165 res = make_archive(base_name, 'zip', root_dir, base_dir)
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001166 self.assertTrue(os.path.isfile(res))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001167
1168 res = make_archive(base_name, 'tar', root_dir, base_dir,
1169 owner=owner, group=group)
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001170 self.assertTrue(os.path.isfile(res))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001171
1172 res = make_archive(base_name, 'tar', root_dir, base_dir,
1173 owner='kjhkjhkjg', group='oihohoh')
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001174 self.assertTrue(os.path.isfile(res))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001175
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001176
Ezio Melotti975077a2011-05-19 22:03:22 +03001177 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001178 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1179 def test_tarfile_root_owner(self):
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001180 root_dir, base_dir = self._create_files()
1181 base_name = os.path.join(self.mkdtemp(), 'archive')
Tarek Ziadé396fad72010-02-23 05:30:31 +00001182 group = grp.getgrgid(0)[0]
1183 owner = pwd.getpwuid(0)[0]
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001184 with support.change_cwd(root_dir):
1185 archive_name = make_archive(base_name, 'gztar', root_dir, 'dist',
1186 owner=owner, group=group)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001187
1188 # check if the compressed tarball was created
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001189 self.assertTrue(os.path.isfile(archive_name))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001190
1191 # now checks the rights
1192 archive = tarfile.open(archive_name)
1193 try:
1194 for member in archive.getmembers():
Ezio Melottib3aedd42010-11-20 19:04:17 +00001195 self.assertEqual(member.uid, 0)
1196 self.assertEqual(member.gid, 0)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001197 finally:
1198 archive.close()
1199
1200 def test_make_archive_cwd(self):
1201 current_dir = os.getcwd()
1202 def _breaks(*args, **kw):
1203 raise RuntimeError()
1204
1205 register_archive_format('xxx', _breaks, [], 'xxx file')
1206 try:
1207 try:
1208 make_archive('xxx', 'xxx', root_dir=self.mkdtemp())
1209 except Exception:
1210 pass
Ezio Melottib3aedd42010-11-20 19:04:17 +00001211 self.assertEqual(os.getcwd(), current_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001212 finally:
1213 unregister_archive_format('xxx')
1214
Serhiy Storchaka9a4fc192014-11-28 00:48:46 +02001215 def test_make_tarfile_in_curdir(self):
1216 # Issue #21280
1217 root_dir = self.mkdtemp()
1218 with support.change_cwd(root_dir):
1219 self.assertEqual(make_archive('test', 'tar'), 'test.tar')
1220 self.assertTrue(os.path.isfile('test.tar'))
1221
1222 @requires_zlib
1223 def test_make_zipfile_in_curdir(self):
1224 # Issue #21280
1225 root_dir = self.mkdtemp()
1226 with support.change_cwd(root_dir):
1227 self.assertEqual(make_archive('test', 'zip'), 'test.zip')
1228 self.assertTrue(os.path.isfile('test.zip'))
1229
Tarek Ziadé396fad72010-02-23 05:30:31 +00001230 def test_register_archive_format(self):
1231
1232 self.assertRaises(TypeError, register_archive_format, 'xxx', 1)
1233 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1234 1)
1235 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1236 [(1, 2), (1, 2, 3)])
1237
1238 register_archive_format('xxx', lambda: x, [(1, 2)], 'xxx file')
1239 formats = [name for name, params in get_archive_formats()]
1240 self.assertIn('xxx', formats)
1241
1242 unregister_archive_format('xxx')
1243 formats = [name for name, params in get_archive_formats()]
1244 self.assertNotIn('xxx', formats)
1245
Ezio Melotti975077a2011-05-19 22:03:22 +03001246 @requires_zlib
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001247 def test_unpack_archive(self):
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001248 formats = ['tar', 'gztar', 'zip']
1249 if BZ2_SUPPORTED:
1250 formats.append('bztar')
Serhiy Storchaka11213772014-08-06 18:50:19 +03001251 if LZMA_SUPPORTED:
1252 formats.append('xztar')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001253
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001254 root_dir, base_dir = self._create_files()
Serhiy Storchaka2504cec2015-09-08 05:47:23 +03001255 expected = rlistdir(root_dir)
1256 expected.remove('outer')
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001257 for format in formats:
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001258 base_name = os.path.join(self.mkdtemp(), 'archive')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001259 filename = make_archive(base_name, format, root_dir, base_dir)
1260
1261 # let's try to unpack it now
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001262 tmpdir2 = self.mkdtemp()
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001263 unpack_archive(filename, tmpdir2)
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001264 self.assertEqual(rlistdir(tmpdir2), expected)
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001265
Nick Coghlanabf202d2011-03-16 13:52:20 -04001266 # and again, this time with the format specified
1267 tmpdir3 = self.mkdtemp()
1268 unpack_archive(filename, tmpdir3, format=format)
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001269 self.assertEqual(rlistdir(tmpdir3), expected)
Nick Coghlanabf202d2011-03-16 13:52:20 -04001270 self.assertRaises(shutil.ReadError, unpack_archive, TESTFN)
1271 self.assertRaises(ValueError, unpack_archive, TESTFN, format='xxx')
1272
Martin Pantereb995702016-07-28 01:11:04 +00001273 def test_unpack_registry(self):
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001274
1275 formats = get_unpack_formats()
1276
1277 def _boo(filename, extract_dir, extra):
Ezio Melottib3aedd42010-11-20 19:04:17 +00001278 self.assertEqual(extra, 1)
1279 self.assertEqual(filename, 'stuff.boo')
1280 self.assertEqual(extract_dir, 'xx')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001281
1282 register_unpack_format('Boo', ['.boo', '.b2'], _boo, [('extra', 1)])
1283 unpack_archive('stuff.boo', 'xx')
1284
1285 # trying to register a .boo unpacker again
1286 self.assertRaises(RegistryError, register_unpack_format, 'Boo2',
1287 ['.boo'], _boo)
1288
1289 # should work now
1290 unregister_unpack_format('Boo')
1291 register_unpack_format('Boo2', ['.boo'], _boo)
1292 self.assertIn(('Boo2', ['.boo'], ''), get_unpack_formats())
1293 self.assertNotIn(('Boo', ['.boo'], ''), get_unpack_formats())
1294
1295 # let's leave a clean state
1296 unregister_unpack_format('Boo2')
Ezio Melottib3aedd42010-11-20 19:04:17 +00001297 self.assertEqual(get_unpack_formats(), formats)
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001298
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001299 @unittest.skipUnless(hasattr(shutil, 'disk_usage'),
1300 "disk_usage not available on this platform")
1301 def test_disk_usage(self):
1302 usage = shutil.disk_usage(os.getcwd())
Éric Araujo2ee61882011-07-02 16:45:45 +02001303 self.assertGreater(usage.total, 0)
1304 self.assertGreater(usage.used, 0)
1305 self.assertGreaterEqual(usage.free, 0)
1306 self.assertGreaterEqual(usage.total, usage.used)
1307 self.assertGreater(usage.total, usage.free)
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001308
Sandro Tosid902a142011-08-22 23:28:27 +02001309 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1310 @unittest.skipUnless(hasattr(os, 'chown'), 'requires os.chown')
1311 def test_chown(self):
1312
1313 # cleaned-up automatically by TestShutil.tearDown method
1314 dirname = self.mkdtemp()
1315 filename = tempfile.mktemp(dir=dirname)
1316 write_file(filename, 'testing chown function')
1317
1318 with self.assertRaises(ValueError):
1319 shutil.chown(filename)
1320
1321 with self.assertRaises(LookupError):
1322 shutil.chown(filename, user='non-exising username')
1323
1324 with self.assertRaises(LookupError):
1325 shutil.chown(filename, group='non-exising groupname')
1326
1327 with self.assertRaises(TypeError):
1328 shutil.chown(filename, b'spam')
1329
1330 with self.assertRaises(TypeError):
1331 shutil.chown(filename, 3.14)
1332
1333 uid = os.getuid()
1334 gid = os.getgid()
1335
1336 def check_chown(path, uid=None, gid=None):
1337 s = os.stat(filename)
1338 if uid is not None:
1339 self.assertEqual(uid, s.st_uid)
1340 if gid is not None:
1341 self.assertEqual(gid, s.st_gid)
1342
1343 shutil.chown(filename, uid, gid)
1344 check_chown(filename, uid, gid)
1345 shutil.chown(filename, uid)
1346 check_chown(filename, uid)
1347 shutil.chown(filename, user=uid)
1348 check_chown(filename, uid)
1349 shutil.chown(filename, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001350 check_chown(filename, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001351
1352 shutil.chown(dirname, uid, gid)
1353 check_chown(dirname, uid, gid)
1354 shutil.chown(dirname, uid)
1355 check_chown(dirname, uid)
1356 shutil.chown(dirname, user=uid)
1357 check_chown(dirname, uid)
1358 shutil.chown(dirname, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001359 check_chown(dirname, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001360
1361 user = pwd.getpwuid(uid)[0]
1362 group = grp.getgrgid(gid)[0]
1363 shutil.chown(filename, user, group)
1364 check_chown(filename, uid, gid)
1365 shutil.chown(dirname, user, group)
1366 check_chown(dirname, uid, gid)
1367
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001368 def test_copy_return_value(self):
1369 # copy and copy2 both return their destination path.
1370 for fn in (shutil.copy, shutil.copy2):
1371 src_dir = self.mkdtemp()
1372 dst_dir = self.mkdtemp()
1373 src = os.path.join(src_dir, 'foo')
1374 write_file(src, 'foo')
1375 rv = fn(src, dst_dir)
1376 self.assertEqual(rv, os.path.join(dst_dir, 'foo'))
1377 rv = fn(src, os.path.join(dst_dir, 'bar'))
1378 self.assertEqual(rv, os.path.join(dst_dir, 'bar'))
1379
1380 def test_copyfile_return_value(self):
1381 # copytree returns its destination path.
1382 src_dir = self.mkdtemp()
1383 dst_dir = self.mkdtemp()
1384 dst_file = os.path.join(dst_dir, 'bar')
1385 src_file = os.path.join(src_dir, 'foo')
1386 write_file(src_file, 'foo')
1387 rv = shutil.copyfile(src_file, dst_file)
1388 self.assertTrue(os.path.exists(rv))
1389 self.assertEqual(read_file(src_file), read_file(dst_file))
1390
Hynek Schlawack48653762012-10-07 12:49:58 +02001391 def test_copyfile_same_file(self):
1392 # copyfile() should raise SameFileError if the source and destination
1393 # are the same.
1394 src_dir = self.mkdtemp()
1395 src_file = os.path.join(src_dir, 'foo')
1396 write_file(src_file, 'foo')
1397 self.assertRaises(SameFileError, shutil.copyfile, src_file, src_file)
Hynek Schlawack27ddb572012-10-28 13:59:27 +01001398 # But Error should work too, to stay backward compatible.
1399 self.assertRaises(Error, shutil.copyfile, src_file, src_file)
Hynek Schlawack48653762012-10-07 12:49:58 +02001400
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001401 def test_copytree_return_value(self):
1402 # copytree returns its destination path.
1403 src_dir = self.mkdtemp()
1404 dst_dir = src_dir + "dest"
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001405 self.addCleanup(shutil.rmtree, dst_dir, True)
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001406 src = os.path.join(src_dir, 'foo')
1407 write_file(src, 'foo')
1408 rv = shutil.copytree(src_dir, dst_dir)
1409 self.assertEqual(['foo'], os.listdir(rv))
1410
Christian Heimes9bd667a2008-01-20 15:14:11 +00001411
Brian Curtinc57a3452012-06-22 16:00:30 -05001412class TestWhich(unittest.TestCase):
1413
1414 def setUp(self):
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001415 self.temp_dir = tempfile.mkdtemp(prefix="Tmp")
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001416 self.addCleanup(shutil.rmtree, self.temp_dir, True)
Brian Curtinc57a3452012-06-22 16:00:30 -05001417 # Give the temp_file an ".exe" suffix for all.
1418 # It's needed on Windows and not harmful on other platforms.
1419 self.temp_file = tempfile.NamedTemporaryFile(dir=self.temp_dir,
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001420 prefix="Tmp",
1421 suffix=".Exe")
Brian Curtinc57a3452012-06-22 16:00:30 -05001422 os.chmod(self.temp_file.name, stat.S_IXUSR)
1423 self.addCleanup(self.temp_file.close)
1424 self.dir, self.file = os.path.split(self.temp_file.name)
1425
1426 def test_basic(self):
1427 # Given an EXE in a directory, it should be returned.
1428 rv = shutil.which(self.file, path=self.dir)
1429 self.assertEqual(rv, self.temp_file.name)
1430
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001431 def test_absolute_cmd(self):
Brian Curtinc57a3452012-06-22 16:00:30 -05001432 # When given the fully qualified path to an executable that exists,
1433 # it should be returned.
1434 rv = shutil.which(self.temp_file.name, path=self.temp_dir)
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001435 self.assertEqual(rv, self.temp_file.name)
1436
1437 def test_relative_cmd(self):
1438 # When given the relative path with a directory part to an executable
1439 # that exists, it should be returned.
1440 base_dir, tail_dir = os.path.split(self.dir)
1441 relpath = os.path.join(tail_dir, self.file)
Nick Coghlan55175962013-07-28 22:11:50 +10001442 with support.change_cwd(path=base_dir):
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001443 rv = shutil.which(relpath, path=self.temp_dir)
1444 self.assertEqual(rv, relpath)
1445 # But it shouldn't be searched in PATH directories (issue #16957).
Nick Coghlan55175962013-07-28 22:11:50 +10001446 with support.change_cwd(path=self.dir):
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001447 rv = shutil.which(relpath, path=base_dir)
1448 self.assertIsNone(rv)
1449
1450 def test_cwd(self):
1451 # Issue #16957
1452 base_dir = os.path.dirname(self.dir)
Nick Coghlan55175962013-07-28 22:11:50 +10001453 with support.change_cwd(path=self.dir):
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001454 rv = shutil.which(self.file, path=base_dir)
1455 if sys.platform == "win32":
1456 # Windows: current directory implicitly on PATH
1457 self.assertEqual(rv, os.path.join(os.curdir, self.file))
1458 else:
1459 # Other platforms: shouldn't match in the current directory.
1460 self.assertIsNone(rv)
Brian Curtinc57a3452012-06-22 16:00:30 -05001461
Serhiy Storchaka12516e22013-05-28 15:50:15 +03001462 @unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0,
1463 'non-root user required')
Brian Curtinc57a3452012-06-22 16:00:30 -05001464 def test_non_matching_mode(self):
1465 # Set the file read-only and ask for writeable files.
1466 os.chmod(self.temp_file.name, stat.S_IREAD)
Serhiy Storchaka12516e22013-05-28 15:50:15 +03001467 if os.access(self.temp_file.name, os.W_OK):
1468 self.skipTest("can't set the file read-only")
Brian Curtinc57a3452012-06-22 16:00:30 -05001469 rv = shutil.which(self.file, path=self.dir, mode=os.W_OK)
1470 self.assertIsNone(rv)
1471
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001472 def test_relative_path(self):
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001473 base_dir, tail_dir = os.path.split(self.dir)
Nick Coghlan55175962013-07-28 22:11:50 +10001474 with support.change_cwd(path=base_dir):
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001475 rv = shutil.which(self.file, path=tail_dir)
1476 self.assertEqual(rv, os.path.join(tail_dir, self.file))
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001477
Brian Curtinc57a3452012-06-22 16:00:30 -05001478 def test_nonexistent_file(self):
1479 # Return None when no matching executable file is found on the path.
1480 rv = shutil.which("foo.exe", path=self.dir)
1481 self.assertIsNone(rv)
1482
1483 @unittest.skipUnless(sys.platform == "win32",
1484 "pathext check is Windows-only")
1485 def test_pathext_checking(self):
1486 # Ask for the file without the ".exe" extension, then ensure that
1487 # it gets found properly with the extension.
Serhiy Storchakad70127a2013-01-24 20:03:49 +02001488 rv = shutil.which(self.file[:-4], path=self.dir)
Serhiy Storchaka80c88f42013-01-22 10:31:36 +02001489 self.assertEqual(rv, self.temp_file.name[:-4] + ".EXE")
Brian Curtinc57a3452012-06-22 16:00:30 -05001490
Barry Warsaw618738b2013-04-16 11:05:03 -04001491 def test_environ_path(self):
1492 with support.EnvironmentVarGuard() as env:
Victor Stinner1d006a22013-12-16 23:39:40 +01001493 env['PATH'] = self.dir
Barry Warsaw618738b2013-04-16 11:05:03 -04001494 rv = shutil.which(self.file)
1495 self.assertEqual(rv, self.temp_file.name)
1496
1497 def test_empty_path(self):
1498 base_dir = os.path.dirname(self.dir)
Nick Coghlan55175962013-07-28 22:11:50 +10001499 with support.change_cwd(path=self.dir), \
Barry Warsaw618738b2013-04-16 11:05:03 -04001500 support.EnvironmentVarGuard() as env:
Victor Stinner1d006a22013-12-16 23:39:40 +01001501 env['PATH'] = self.dir
Barry Warsaw618738b2013-04-16 11:05:03 -04001502 rv = shutil.which(self.file, path='')
1503 self.assertIsNone(rv)
1504
1505 def test_empty_path_no_PATH(self):
1506 with support.EnvironmentVarGuard() as env:
1507 env.pop('PATH', None)
1508 rv = shutil.which(self.file)
1509 self.assertIsNone(rv)
1510
Brian Curtinc57a3452012-06-22 16:00:30 -05001511
Christian Heimesada8c3b2008-03-18 18:26:33 +00001512class TestMove(unittest.TestCase):
1513
1514 def setUp(self):
1515 filename = "foo"
1516 self.src_dir = tempfile.mkdtemp()
1517 self.dst_dir = tempfile.mkdtemp()
1518 self.src_file = os.path.join(self.src_dir, filename)
1519 self.dst_file = os.path.join(self.dst_dir, filename)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001520 with open(self.src_file, "wb") as f:
1521 f.write(b"spam")
1522
1523 def tearDown(self):
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001524 for d in (self.src_dir, self.dst_dir):
Christian Heimesada8c3b2008-03-18 18:26:33 +00001525 try:
1526 if d:
1527 shutil.rmtree(d)
1528 except:
1529 pass
1530
1531 def _check_move_file(self, src, dst, real_dst):
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001532 with open(src, "rb") as f:
1533 contents = f.read()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001534 shutil.move(src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001535 with open(real_dst, "rb") as f:
1536 self.assertEqual(contents, f.read())
Christian Heimesada8c3b2008-03-18 18:26:33 +00001537 self.assertFalse(os.path.exists(src))
1538
1539 def _check_move_dir(self, src, dst, real_dst):
1540 contents = sorted(os.listdir(src))
1541 shutil.move(src, dst)
1542 self.assertEqual(contents, sorted(os.listdir(real_dst)))
1543 self.assertFalse(os.path.exists(src))
1544
1545 def test_move_file(self):
1546 # Move a file to another location on the same filesystem.
1547 self._check_move_file(self.src_file, self.dst_file, self.dst_file)
1548
1549 def test_move_file_to_dir(self):
1550 # Move a file inside an existing dir on the same filesystem.
1551 self._check_move_file(self.src_file, self.dst_dir, self.dst_file)
1552
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001553 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001554 def test_move_file_other_fs(self):
1555 # Move a file to an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001556 self.test_move_file()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001557
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001558 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001559 def test_move_file_to_dir_other_fs(self):
1560 # Move a file to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001561 self.test_move_file_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001562
1563 def test_move_dir(self):
1564 # Move a dir to another location on the same filesystem.
1565 dst_dir = tempfile.mktemp()
1566 try:
1567 self._check_move_dir(self.src_dir, dst_dir, dst_dir)
1568 finally:
1569 try:
1570 shutil.rmtree(dst_dir)
1571 except:
1572 pass
1573
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001574 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001575 def test_move_dir_other_fs(self):
1576 # Move a dir to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001577 self.test_move_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001578
1579 def test_move_dir_to_dir(self):
1580 # Move a dir inside an existing dir on the same filesystem.
1581 self._check_move_dir(self.src_dir, self.dst_dir,
1582 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1583
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001584 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001585 def test_move_dir_to_dir_other_fs(self):
1586 # Move a dir inside an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001587 self.test_move_dir_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001588
Serhiy Storchaka3a308b92014-02-11 10:30:59 +02001589 def test_move_dir_sep_to_dir(self):
1590 self._check_move_dir(self.src_dir + os.path.sep, self.dst_dir,
1591 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1592
1593 @unittest.skipUnless(os.path.altsep, 'requires os.path.altsep')
1594 def test_move_dir_altsep_to_dir(self):
1595 self._check_move_dir(self.src_dir + os.path.altsep, self.dst_dir,
1596 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1597
Christian Heimesada8c3b2008-03-18 18:26:33 +00001598 def test_existing_file_inside_dest_dir(self):
1599 # A file with the same name inside the destination dir already exists.
1600 with open(self.dst_file, "wb"):
1601 pass
1602 self.assertRaises(shutil.Error, shutil.move, self.src_file, self.dst_dir)
1603
1604 def test_dont_move_dir_in_itself(self):
1605 # Moving a dir inside itself raises an Error.
1606 dst = os.path.join(self.src_dir, "bar")
1607 self.assertRaises(shutil.Error, shutil.move, self.src_dir, dst)
1608
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001609 def test_destinsrc_false_negative(self):
1610 os.mkdir(TESTFN)
1611 try:
1612 for src, dst in [('srcdir', 'srcdir/dest')]:
1613 src = os.path.join(TESTFN, src)
1614 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001615 self.assertTrue(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001616 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001617 'dst (%s) is not in src (%s)' % (dst, src))
1618 finally:
1619 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001620
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001621 def test_destinsrc_false_positive(self):
1622 os.mkdir(TESTFN)
1623 try:
1624 for src, dst in [('srcdir', 'src/dest'), ('srcdir', 'srcdir.new')]:
1625 src = os.path.join(TESTFN, src)
1626 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001627 self.assertFalse(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001628 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001629 'dst (%s) is in src (%s)' % (dst, src))
1630 finally:
1631 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimes9bd667a2008-01-20 15:14:11 +00001632
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +01001633 @support.skip_unless_symlink
1634 @mock_rename
1635 def test_move_file_symlink(self):
1636 dst = os.path.join(self.src_dir, 'bar')
1637 os.symlink(self.src_file, dst)
1638 shutil.move(dst, self.dst_file)
1639 self.assertTrue(os.path.islink(self.dst_file))
1640 self.assertTrue(os.path.samefile(self.src_file, self.dst_file))
1641
1642 @support.skip_unless_symlink
1643 @mock_rename
1644 def test_move_file_symlink_to_dir(self):
1645 filename = "bar"
1646 dst = os.path.join(self.src_dir, filename)
1647 os.symlink(self.src_file, dst)
1648 shutil.move(dst, self.dst_dir)
1649 final_link = os.path.join(self.dst_dir, filename)
1650 self.assertTrue(os.path.islink(final_link))
1651 self.assertTrue(os.path.samefile(self.src_file, final_link))
1652
1653 @support.skip_unless_symlink
1654 @mock_rename
1655 def test_move_dangling_symlink(self):
1656 src = os.path.join(self.src_dir, 'baz')
1657 dst = os.path.join(self.src_dir, 'bar')
1658 os.symlink(src, dst)
1659 dst_link = os.path.join(self.dst_dir, 'quux')
1660 shutil.move(dst, dst_link)
1661 self.assertTrue(os.path.islink(dst_link))
Antoine Pitrou3f48ac92014-01-01 02:50:45 +01001662 # On Windows, os.path.realpath does not follow symlinks (issue #9949)
1663 if os.name == 'nt':
1664 self.assertEqual(os.path.realpath(src), os.readlink(dst_link))
1665 else:
1666 self.assertEqual(os.path.realpath(src), os.path.realpath(dst_link))
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +01001667
1668 @support.skip_unless_symlink
1669 @mock_rename
1670 def test_move_dir_symlink(self):
1671 src = os.path.join(self.src_dir, 'baz')
1672 dst = os.path.join(self.src_dir, 'bar')
1673 os.mkdir(src)
1674 os.symlink(src, dst)
1675 dst_link = os.path.join(self.dst_dir, 'quux')
1676 shutil.move(dst, dst_link)
1677 self.assertTrue(os.path.islink(dst_link))
1678 self.assertTrue(os.path.samefile(src, dst_link))
1679
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001680 def test_move_return_value(self):
1681 rv = shutil.move(self.src_file, self.dst_dir)
1682 self.assertEqual(rv,
1683 os.path.join(self.dst_dir, os.path.basename(self.src_file)))
1684
1685 def test_move_as_rename_return_value(self):
1686 rv = shutil.move(self.src_file, os.path.join(self.dst_dir, 'bar'))
1687 self.assertEqual(rv, os.path.join(self.dst_dir, 'bar'))
1688
R David Murray6ffface2014-06-11 14:40:13 -04001689 @mock_rename
1690 def test_move_file_special_function(self):
1691 moved = []
1692 def _copy(src, dst):
1693 moved.append((src, dst))
1694 shutil.move(self.src_file, self.dst_dir, copy_function=_copy)
1695 self.assertEqual(len(moved), 1)
1696
1697 @mock_rename
1698 def test_move_dir_special_function(self):
1699 moved = []
1700 def _copy(src, dst):
1701 moved.append((src, dst))
1702 support.create_empty_file(os.path.join(self.src_dir, 'child'))
1703 support.create_empty_file(os.path.join(self.src_dir, 'child1'))
1704 shutil.move(self.src_dir, self.dst_dir, copy_function=_copy)
1705 self.assertEqual(len(moved), 3)
1706
Tarek Ziadé5340db32010-04-19 22:30:51 +00001707
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001708class TestCopyFile(unittest.TestCase):
1709
1710 _delete = False
1711
1712 class Faux(object):
1713 _entered = False
1714 _exited_with = None
1715 _raised = False
1716 def __init__(self, raise_in_exit=False, suppress_at_exit=True):
1717 self._raise_in_exit = raise_in_exit
1718 self._suppress_at_exit = suppress_at_exit
1719 def read(self, *args):
1720 return ''
1721 def __enter__(self):
1722 self._entered = True
1723 def __exit__(self, exc_type, exc_val, exc_tb):
1724 self._exited_with = exc_type, exc_val, exc_tb
1725 if self._raise_in_exit:
1726 self._raised = True
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001727 raise OSError("Cannot close")
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001728 return self._suppress_at_exit
1729
1730 def tearDown(self):
1731 if self._delete:
1732 del shutil.open
1733
1734 def _set_shutil_open(self, func):
1735 shutil.open = func
1736 self._delete = True
1737
1738 def test_w_source_open_fails(self):
1739 def _open(filename, mode='r'):
1740 if filename == 'srcfile':
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001741 raise OSError('Cannot open "srcfile"')
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001742 assert 0 # shouldn't reach here.
1743
1744 self._set_shutil_open(_open)
1745
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001746 self.assertRaises(OSError, shutil.copyfile, 'srcfile', 'destfile')
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001747
1748 def test_w_dest_open_fails(self):
1749
1750 srcfile = self.Faux()
1751
1752 def _open(filename, mode='r'):
1753 if filename == 'srcfile':
1754 return srcfile
1755 if filename == 'destfile':
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001756 raise OSError('Cannot open "destfile"')
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001757 assert 0 # shouldn't reach here.
1758
1759 self._set_shutil_open(_open)
1760
1761 shutil.copyfile('srcfile', 'destfile')
1762 self.assertTrue(srcfile._entered)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001763 self.assertTrue(srcfile._exited_with[0] is OSError)
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001764 self.assertEqual(srcfile._exited_with[1].args,
1765 ('Cannot open "destfile"',))
1766
1767 def test_w_dest_close_fails(self):
1768
1769 srcfile = self.Faux()
1770 destfile = self.Faux(True)
1771
1772 def _open(filename, mode='r'):
1773 if filename == 'srcfile':
1774 return srcfile
1775 if filename == 'destfile':
1776 return destfile
1777 assert 0 # shouldn't reach here.
1778
1779 self._set_shutil_open(_open)
1780
1781 shutil.copyfile('srcfile', 'destfile')
1782 self.assertTrue(srcfile._entered)
1783 self.assertTrue(destfile._entered)
1784 self.assertTrue(destfile._raised)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001785 self.assertTrue(srcfile._exited_with[0] is OSError)
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001786 self.assertEqual(srcfile._exited_with[1].args,
1787 ('Cannot close',))
1788
1789 def test_w_source_close_fails(self):
1790
1791 srcfile = self.Faux(True)
1792 destfile = self.Faux()
1793
1794 def _open(filename, mode='r'):
1795 if filename == 'srcfile':
1796 return srcfile
1797 if filename == 'destfile':
1798 return destfile
1799 assert 0 # shouldn't reach here.
1800
1801 self._set_shutil_open(_open)
1802
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001803 self.assertRaises(OSError,
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001804 shutil.copyfile, 'srcfile', 'destfile')
1805 self.assertTrue(srcfile._entered)
1806 self.assertTrue(destfile._entered)
1807 self.assertFalse(destfile._raised)
1808 self.assertTrue(srcfile._exited_with[0] is None)
1809 self.assertTrue(srcfile._raised)
1810
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001811 def test_move_dir_caseinsensitive(self):
1812 # Renames a folder to the same name
1813 # but a different case.
1814
1815 self.src_dir = tempfile.mkdtemp()
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001816 self.addCleanup(shutil.rmtree, self.src_dir, True)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001817 dst_dir = os.path.join(
1818 os.path.dirname(self.src_dir),
1819 os.path.basename(self.src_dir).upper())
1820 self.assertNotEqual(self.src_dir, dst_dir)
1821
1822 try:
1823 shutil.move(self.src_dir, dst_dir)
1824 self.assertTrue(os.path.isdir(dst_dir))
1825 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +02001826 os.rmdir(dst_dir)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001827
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001828class TermsizeTests(unittest.TestCase):
1829 def test_does_not_crash(self):
1830 """Check if get_terminal_size() returns a meaningful value.
1831
1832 There's no easy portable way to actually check the size of the
1833 terminal, so let's check if it returns something sensible instead.
1834 """
1835 size = shutil.get_terminal_size()
Antoine Pitroucfade362012-02-08 23:48:59 +01001836 self.assertGreaterEqual(size.columns, 0)
1837 self.assertGreaterEqual(size.lines, 0)
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001838
1839 def test_os_environ_first(self):
1840 "Check if environment variables have precedence"
1841
1842 with support.EnvironmentVarGuard() as env:
1843 env['COLUMNS'] = '777'
Serhiy Storchakad30829d2016-04-24 09:58:43 +03001844 del env['LINES']
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001845 size = shutil.get_terminal_size()
1846 self.assertEqual(size.columns, 777)
1847
1848 with support.EnvironmentVarGuard() as env:
Serhiy Storchakad30829d2016-04-24 09:58:43 +03001849 del env['COLUMNS']
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001850 env['LINES'] = '888'
1851 size = shutil.get_terminal_size()
1852 self.assertEqual(size.lines, 888)
1853
Serhiy Storchakad30829d2016-04-24 09:58:43 +03001854 def test_bad_environ(self):
1855 with support.EnvironmentVarGuard() as env:
1856 env['COLUMNS'] = 'xxx'
1857 env['LINES'] = 'yyy'
1858 size = shutil.get_terminal_size()
1859 self.assertGreaterEqual(size.columns, 0)
1860 self.assertGreaterEqual(size.lines, 0)
1861
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001862 @unittest.skipUnless(os.isatty(sys.__stdout__.fileno()), "not on tty")
Victor Stinner119ebb72016-04-19 22:24:56 +02001863 @unittest.skipUnless(hasattr(os, 'get_terminal_size'),
1864 'need os.get_terminal_size()')
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001865 def test_stty_match(self):
1866 """Check if stty returns the same results ignoring env
1867
1868 This test will fail if stdin and stdout are connected to
1869 different terminals with different sizes. Nevertheless, such
1870 situations should be pretty rare.
1871 """
1872 try:
1873 size = subprocess.check_output(['stty', 'size']).decode().split()
1874 except (FileNotFoundError, subprocess.CalledProcessError):
1875 self.skipTest("stty invocation failed")
1876 expected = (int(size[1]), int(size[0])) # reversed order
1877
1878 with support.EnvironmentVarGuard() as env:
1879 del env['LINES']
1880 del env['COLUMNS']
1881 actual = shutil.get_terminal_size()
1882
1883 self.assertEqual(expected, actual)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001884
Serhiy Storchakad30829d2016-04-24 09:58:43 +03001885 def test_fallback(self):
1886 with support.EnvironmentVarGuard() as env:
1887 del env['LINES']
1888 del env['COLUMNS']
1889
1890 # sys.__stdout__ has no fileno()
1891 with support.swap_attr(sys, '__stdout__', None):
1892 size = shutil.get_terminal_size(fallback=(10, 20))
1893 self.assertEqual(size.columns, 10)
1894 self.assertEqual(size.lines, 20)
1895
1896 # sys.__stdout__ is not a terminal on Unix
1897 # or fileno() not in (0, 1, 2) on Windows
1898 with open(os.devnull, 'w') as f, \
1899 support.swap_attr(sys, '__stdout__', f):
1900 size = shutil.get_terminal_size(fallback=(30, 40))
1901 self.assertEqual(size.columns, 30)
1902 self.assertEqual(size.lines, 40)
1903
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001904
Berker Peksag8083cd62014-11-01 11:04:06 +02001905class PublicAPITests(unittest.TestCase):
1906 """Ensures that the correct values are exposed in the public API."""
1907
1908 def test_module_all_attribute(self):
1909 self.assertTrue(hasattr(shutil, '__all__'))
1910 target_api = ['copyfileobj', 'copyfile', 'copymode', 'copystat',
1911 'copy', 'copy2', 'copytree', 'move', 'rmtree', 'Error',
1912 'SpecialFileError', 'ExecError', 'make_archive',
1913 'get_archive_formats', 'register_archive_format',
1914 'unregister_archive_format', 'get_unpack_formats',
1915 'register_unpack_format', 'unregister_unpack_format',
1916 'unpack_archive', 'ignore_patterns', 'chown', 'which',
1917 'get_terminal_size', 'SameFileError']
1918 if hasattr(os, 'statvfs') or os.name == 'nt':
1919 target_api.append('disk_usage')
1920 self.assertEqual(set(shutil.__all__), set(target_api))
1921
1922
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001923if __name__ == '__main__':
Brett Cannon3e9a9ae2013-06-12 21:25:59 -04001924 unittest.main()