blob: 1d5e01a92dae0973e46853b556aeb2ac19471604 [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 Storchaka2504cec2015-09-08 05:47:23 +03001071 res = make_archive(rel_base_name, 'zip', root_dir, base_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001072
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001073 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(),
Serhiy Storchaka2504cec2015-09-08 05:47:23 +03001078 ['dist/', 'dist/sub/', 'dist/sub2/',
1079 'dist/file1', 'dist/file2', 'dist/sub/file3'])
Tarek Ziadé396fad72010-02-23 05:30:31 +00001080
Serhiy Storchaka2504cec2015-09-08 05:47:23 +03001081 @requires_zlib
1082 @unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run')
Serhiy Storchakab42de2f2015-11-21 14:09:26 +02001083 @unittest.skipUnless(shutil.which('zip'),
Serhiy Storchaka2504cec2015-09-08 05:47:23 +03001084 'Need the zip command to run')
1085 def test_zipfile_vs_zip(self):
1086 root_dir, base_dir = self._create_files()
1087 base_name = os.path.join(self.mkdtemp(), 'archive')
1088 archive = make_archive(base_name, 'zip', root_dir, base_dir)
1089
1090 # check if ZIP file was created
1091 self.assertEqual(archive, base_name + '.zip')
1092 self.assertTrue(os.path.isfile(archive))
1093
1094 # now create another ZIP file using `zip`
1095 archive2 = os.path.join(root_dir, 'archive2.zip')
1096 zip_cmd = ['zip', '-q', '-r', 'archive2.zip', base_dir]
Serhiy Storchakab42de2f2015-11-21 14:09:26 +02001097 subprocess.check_call(zip_cmd, cwd=root_dir,
1098 stdout=subprocess.DEVNULL)
Serhiy Storchaka2504cec2015-09-08 05:47:23 +03001099
1100 self.assertTrue(os.path.isfile(archive2))
1101 # let's compare both ZIP files
1102 with zipfile.ZipFile(archive) as zf:
1103 names = zf.namelist()
1104 with zipfile.ZipFile(archive2) as zf:
1105 names2 = zf.namelist()
1106 self.assertEqual(sorted(names), sorted(names2))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001107
Serhiy Storchaka8bc792a2015-11-22 14:49:58 +02001108 @requires_zlib
1109 @unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run')
1110 @unittest.skipUnless(shutil.which('unzip'),
1111 'Need the unzip command to run')
1112 def test_unzip_zipfile(self):
1113 root_dir, base_dir = self._create_files()
1114 base_name = os.path.join(self.mkdtemp(), 'archive')
1115 archive = make_archive(base_name, 'zip', root_dir, base_dir)
1116
1117 # check if ZIP file was created
1118 self.assertEqual(archive, base_name + '.zip')
1119 self.assertTrue(os.path.isfile(archive))
1120
1121 # now check the ZIP file using `unzip -t`
1122 zip_cmd = ['unzip', '-t', archive]
1123 with support.change_cwd(root_dir):
1124 try:
1125 subprocess.check_output(zip_cmd, stderr=subprocess.STDOUT)
1126 except subprocess.CalledProcessError as exc:
1127 details = exc.output.decode(errors="replace")
1128 msg = "{}\n\n**Unzip Output**\n{}"
1129 self.fail(msg.format(exc, details))
1130
Tarek Ziadé396fad72010-02-23 05:30:31 +00001131 def test_make_archive(self):
1132 tmpdir = self.mkdtemp()
1133 base_name = os.path.join(tmpdir, 'archive')
1134 self.assertRaises(ValueError, make_archive, base_name, 'xxx')
1135
Ezio Melotti975077a2011-05-19 22:03:22 +03001136 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001137 def test_make_archive_owner_group(self):
1138 # testing make_archive with owner and group, with various combinations
1139 # this works even if there's not gid/uid support
1140 if UID_GID_SUPPORT:
1141 group = grp.getgrgid(0)[0]
1142 owner = pwd.getpwuid(0)[0]
1143 else:
1144 group = owner = 'root'
1145
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001146 root_dir, base_dir = self._create_files()
1147 base_name = os.path.join(self.mkdtemp(), 'archive')
Tarek Ziadé396fad72010-02-23 05:30:31 +00001148 res = make_archive(base_name, 'zip', root_dir, base_dir, owner=owner,
1149 group=group)
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001150 self.assertTrue(os.path.isfile(res))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001151
1152 res = make_archive(base_name, 'zip', root_dir, base_dir)
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001153 self.assertTrue(os.path.isfile(res))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001154
1155 res = make_archive(base_name, 'tar', root_dir, base_dir,
1156 owner=owner, group=group)
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001157 self.assertTrue(os.path.isfile(res))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001158
1159 res = make_archive(base_name, 'tar', root_dir, base_dir,
1160 owner='kjhkjhkjg', group='oihohoh')
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001161 self.assertTrue(os.path.isfile(res))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001162
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001163
Ezio Melotti975077a2011-05-19 22:03:22 +03001164 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001165 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1166 def test_tarfile_root_owner(self):
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001167 root_dir, base_dir = self._create_files()
1168 base_name = os.path.join(self.mkdtemp(), 'archive')
Tarek Ziadé396fad72010-02-23 05:30:31 +00001169 group = grp.getgrgid(0)[0]
1170 owner = pwd.getpwuid(0)[0]
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001171 with support.change_cwd(root_dir):
1172 archive_name = make_archive(base_name, 'gztar', root_dir, 'dist',
1173 owner=owner, group=group)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001174
1175 # check if the compressed tarball was created
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001176 self.assertTrue(os.path.isfile(archive_name))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001177
1178 # now checks the rights
1179 archive = tarfile.open(archive_name)
1180 try:
1181 for member in archive.getmembers():
Ezio Melottib3aedd42010-11-20 19:04:17 +00001182 self.assertEqual(member.uid, 0)
1183 self.assertEqual(member.gid, 0)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001184 finally:
1185 archive.close()
1186
1187 def test_make_archive_cwd(self):
1188 current_dir = os.getcwd()
1189 def _breaks(*args, **kw):
1190 raise RuntimeError()
1191
1192 register_archive_format('xxx', _breaks, [], 'xxx file')
1193 try:
1194 try:
1195 make_archive('xxx', 'xxx', root_dir=self.mkdtemp())
1196 except Exception:
1197 pass
Ezio Melottib3aedd42010-11-20 19:04:17 +00001198 self.assertEqual(os.getcwd(), current_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001199 finally:
1200 unregister_archive_format('xxx')
1201
Serhiy Storchaka9a4fc192014-11-28 00:48:46 +02001202 def test_make_tarfile_in_curdir(self):
1203 # Issue #21280
1204 root_dir = self.mkdtemp()
1205 with support.change_cwd(root_dir):
1206 self.assertEqual(make_archive('test', 'tar'), 'test.tar')
1207 self.assertTrue(os.path.isfile('test.tar'))
1208
1209 @requires_zlib
1210 def test_make_zipfile_in_curdir(self):
1211 # Issue #21280
1212 root_dir = self.mkdtemp()
1213 with support.change_cwd(root_dir):
1214 self.assertEqual(make_archive('test', 'zip'), 'test.zip')
1215 self.assertTrue(os.path.isfile('test.zip'))
1216
Tarek Ziadé396fad72010-02-23 05:30:31 +00001217 def test_register_archive_format(self):
1218
1219 self.assertRaises(TypeError, register_archive_format, 'xxx', 1)
1220 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1221 1)
1222 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1223 [(1, 2), (1, 2, 3)])
1224
1225 register_archive_format('xxx', lambda: x, [(1, 2)], 'xxx file')
1226 formats = [name for name, params in get_archive_formats()]
1227 self.assertIn('xxx', formats)
1228
1229 unregister_archive_format('xxx')
1230 formats = [name for name, params in get_archive_formats()]
1231 self.assertNotIn('xxx', formats)
1232
Ezio Melotti975077a2011-05-19 22:03:22 +03001233 @requires_zlib
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001234 def test_unpack_archive(self):
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001235 formats = ['tar', 'gztar', 'zip']
1236 if BZ2_SUPPORTED:
1237 formats.append('bztar')
Serhiy Storchaka11213772014-08-06 18:50:19 +03001238 if LZMA_SUPPORTED:
1239 formats.append('xztar')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001240
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001241 root_dir, base_dir = self._create_files()
Serhiy Storchaka2504cec2015-09-08 05:47:23 +03001242 expected = rlistdir(root_dir)
1243 expected.remove('outer')
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001244 for format in formats:
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001245 base_name = os.path.join(self.mkdtemp(), 'archive')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001246 filename = make_archive(base_name, format, root_dir, base_dir)
1247
1248 # let's try to unpack it now
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001249 tmpdir2 = self.mkdtemp()
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001250 unpack_archive(filename, tmpdir2)
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001251 self.assertEqual(rlistdir(tmpdir2), expected)
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001252
Nick Coghlanabf202d2011-03-16 13:52:20 -04001253 # and again, this time with the format specified
1254 tmpdir3 = self.mkdtemp()
1255 unpack_archive(filename, tmpdir3, format=format)
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001256 self.assertEqual(rlistdir(tmpdir3), expected)
Nick Coghlanabf202d2011-03-16 13:52:20 -04001257 self.assertRaises(shutil.ReadError, unpack_archive, TESTFN)
1258 self.assertRaises(ValueError, unpack_archive, TESTFN, format='xxx')
1259
Martin Pantereb995702016-07-28 01:11:04 +00001260 def test_unpack_registry(self):
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001261
1262 formats = get_unpack_formats()
1263
1264 def _boo(filename, extract_dir, extra):
Ezio Melottib3aedd42010-11-20 19:04:17 +00001265 self.assertEqual(extra, 1)
1266 self.assertEqual(filename, 'stuff.boo')
1267 self.assertEqual(extract_dir, 'xx')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001268
1269 register_unpack_format('Boo', ['.boo', '.b2'], _boo, [('extra', 1)])
1270 unpack_archive('stuff.boo', 'xx')
1271
1272 # trying to register a .boo unpacker again
1273 self.assertRaises(RegistryError, register_unpack_format, 'Boo2',
1274 ['.boo'], _boo)
1275
1276 # should work now
1277 unregister_unpack_format('Boo')
1278 register_unpack_format('Boo2', ['.boo'], _boo)
1279 self.assertIn(('Boo2', ['.boo'], ''), get_unpack_formats())
1280 self.assertNotIn(('Boo', ['.boo'], ''), get_unpack_formats())
1281
1282 # let's leave a clean state
1283 unregister_unpack_format('Boo2')
Ezio Melottib3aedd42010-11-20 19:04:17 +00001284 self.assertEqual(get_unpack_formats(), formats)
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001285
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001286 @unittest.skipUnless(hasattr(shutil, 'disk_usage'),
1287 "disk_usage not available on this platform")
1288 def test_disk_usage(self):
1289 usage = shutil.disk_usage(os.getcwd())
Éric Araujo2ee61882011-07-02 16:45:45 +02001290 self.assertGreater(usage.total, 0)
1291 self.assertGreater(usage.used, 0)
1292 self.assertGreaterEqual(usage.free, 0)
1293 self.assertGreaterEqual(usage.total, usage.used)
1294 self.assertGreater(usage.total, usage.free)
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001295
Sandro Tosid902a142011-08-22 23:28:27 +02001296 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1297 @unittest.skipUnless(hasattr(os, 'chown'), 'requires os.chown')
1298 def test_chown(self):
1299
1300 # cleaned-up automatically by TestShutil.tearDown method
1301 dirname = self.mkdtemp()
1302 filename = tempfile.mktemp(dir=dirname)
1303 write_file(filename, 'testing chown function')
1304
1305 with self.assertRaises(ValueError):
1306 shutil.chown(filename)
1307
1308 with self.assertRaises(LookupError):
1309 shutil.chown(filename, user='non-exising username')
1310
1311 with self.assertRaises(LookupError):
1312 shutil.chown(filename, group='non-exising groupname')
1313
1314 with self.assertRaises(TypeError):
1315 shutil.chown(filename, b'spam')
1316
1317 with self.assertRaises(TypeError):
1318 shutil.chown(filename, 3.14)
1319
1320 uid = os.getuid()
1321 gid = os.getgid()
1322
1323 def check_chown(path, uid=None, gid=None):
1324 s = os.stat(filename)
1325 if uid is not None:
1326 self.assertEqual(uid, s.st_uid)
1327 if gid is not None:
1328 self.assertEqual(gid, s.st_gid)
1329
1330 shutil.chown(filename, uid, gid)
1331 check_chown(filename, uid, gid)
1332 shutil.chown(filename, uid)
1333 check_chown(filename, uid)
1334 shutil.chown(filename, user=uid)
1335 check_chown(filename, uid)
1336 shutil.chown(filename, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001337 check_chown(filename, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001338
1339 shutil.chown(dirname, uid, gid)
1340 check_chown(dirname, uid, gid)
1341 shutil.chown(dirname, uid)
1342 check_chown(dirname, uid)
1343 shutil.chown(dirname, user=uid)
1344 check_chown(dirname, uid)
1345 shutil.chown(dirname, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001346 check_chown(dirname, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001347
1348 user = pwd.getpwuid(uid)[0]
1349 group = grp.getgrgid(gid)[0]
1350 shutil.chown(filename, user, group)
1351 check_chown(filename, uid, gid)
1352 shutil.chown(dirname, user, group)
1353 check_chown(dirname, uid, gid)
1354
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001355 def test_copy_return_value(self):
1356 # copy and copy2 both return their destination path.
1357 for fn in (shutil.copy, shutil.copy2):
1358 src_dir = self.mkdtemp()
1359 dst_dir = self.mkdtemp()
1360 src = os.path.join(src_dir, 'foo')
1361 write_file(src, 'foo')
1362 rv = fn(src, dst_dir)
1363 self.assertEqual(rv, os.path.join(dst_dir, 'foo'))
1364 rv = fn(src, os.path.join(dst_dir, 'bar'))
1365 self.assertEqual(rv, os.path.join(dst_dir, 'bar'))
1366
1367 def test_copyfile_return_value(self):
1368 # copytree returns its destination path.
1369 src_dir = self.mkdtemp()
1370 dst_dir = self.mkdtemp()
1371 dst_file = os.path.join(dst_dir, 'bar')
1372 src_file = os.path.join(src_dir, 'foo')
1373 write_file(src_file, 'foo')
1374 rv = shutil.copyfile(src_file, dst_file)
1375 self.assertTrue(os.path.exists(rv))
1376 self.assertEqual(read_file(src_file), read_file(dst_file))
1377
Hynek Schlawack48653762012-10-07 12:49:58 +02001378 def test_copyfile_same_file(self):
1379 # copyfile() should raise SameFileError if the source and destination
1380 # are the same.
1381 src_dir = self.mkdtemp()
1382 src_file = os.path.join(src_dir, 'foo')
1383 write_file(src_file, 'foo')
1384 self.assertRaises(SameFileError, shutil.copyfile, src_file, src_file)
Hynek Schlawack27ddb572012-10-28 13:59:27 +01001385 # But Error should work too, to stay backward compatible.
1386 self.assertRaises(Error, shutil.copyfile, src_file, src_file)
Hynek Schlawack48653762012-10-07 12:49:58 +02001387
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001388 def test_copytree_return_value(self):
1389 # copytree returns its destination path.
1390 src_dir = self.mkdtemp()
1391 dst_dir = src_dir + "dest"
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001392 self.addCleanup(shutil.rmtree, dst_dir, True)
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001393 src = os.path.join(src_dir, 'foo')
1394 write_file(src, 'foo')
1395 rv = shutil.copytree(src_dir, dst_dir)
1396 self.assertEqual(['foo'], os.listdir(rv))
1397
Christian Heimes9bd667a2008-01-20 15:14:11 +00001398
Brian Curtinc57a3452012-06-22 16:00:30 -05001399class TestWhich(unittest.TestCase):
1400
1401 def setUp(self):
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001402 self.temp_dir = tempfile.mkdtemp(prefix="Tmp")
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001403 self.addCleanup(shutil.rmtree, self.temp_dir, True)
Brian Curtinc57a3452012-06-22 16:00:30 -05001404 # Give the temp_file an ".exe" suffix for all.
1405 # It's needed on Windows and not harmful on other platforms.
1406 self.temp_file = tempfile.NamedTemporaryFile(dir=self.temp_dir,
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001407 prefix="Tmp",
1408 suffix=".Exe")
Brian Curtinc57a3452012-06-22 16:00:30 -05001409 os.chmod(self.temp_file.name, stat.S_IXUSR)
1410 self.addCleanup(self.temp_file.close)
1411 self.dir, self.file = os.path.split(self.temp_file.name)
1412
1413 def test_basic(self):
1414 # Given an EXE in a directory, it should be returned.
1415 rv = shutil.which(self.file, path=self.dir)
1416 self.assertEqual(rv, self.temp_file.name)
1417
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001418 def test_absolute_cmd(self):
Brian Curtinc57a3452012-06-22 16:00:30 -05001419 # When given the fully qualified path to an executable that exists,
1420 # it should be returned.
1421 rv = shutil.which(self.temp_file.name, path=self.temp_dir)
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001422 self.assertEqual(rv, self.temp_file.name)
1423
1424 def test_relative_cmd(self):
1425 # When given the relative path with a directory part to an executable
1426 # that exists, it should be returned.
1427 base_dir, tail_dir = os.path.split(self.dir)
1428 relpath = os.path.join(tail_dir, self.file)
Nick Coghlan55175962013-07-28 22:11:50 +10001429 with support.change_cwd(path=base_dir):
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001430 rv = shutil.which(relpath, path=self.temp_dir)
1431 self.assertEqual(rv, relpath)
1432 # But it shouldn't be searched in PATH directories (issue #16957).
Nick Coghlan55175962013-07-28 22:11:50 +10001433 with support.change_cwd(path=self.dir):
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001434 rv = shutil.which(relpath, path=base_dir)
1435 self.assertIsNone(rv)
1436
1437 def test_cwd(self):
1438 # Issue #16957
1439 base_dir = os.path.dirname(self.dir)
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(self.file, path=base_dir)
1442 if sys.platform == "win32":
1443 # Windows: current directory implicitly on PATH
1444 self.assertEqual(rv, os.path.join(os.curdir, self.file))
1445 else:
1446 # Other platforms: shouldn't match in the current directory.
1447 self.assertIsNone(rv)
Brian Curtinc57a3452012-06-22 16:00:30 -05001448
Serhiy Storchaka12516e22013-05-28 15:50:15 +03001449 @unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0,
1450 'non-root user required')
Brian Curtinc57a3452012-06-22 16:00:30 -05001451 def test_non_matching_mode(self):
1452 # Set the file read-only and ask for writeable files.
1453 os.chmod(self.temp_file.name, stat.S_IREAD)
Serhiy Storchaka12516e22013-05-28 15:50:15 +03001454 if os.access(self.temp_file.name, os.W_OK):
1455 self.skipTest("can't set the file read-only")
Brian Curtinc57a3452012-06-22 16:00:30 -05001456 rv = shutil.which(self.file, path=self.dir, mode=os.W_OK)
1457 self.assertIsNone(rv)
1458
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001459 def test_relative_path(self):
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001460 base_dir, tail_dir = os.path.split(self.dir)
Nick Coghlan55175962013-07-28 22:11:50 +10001461 with support.change_cwd(path=base_dir):
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001462 rv = shutil.which(self.file, path=tail_dir)
1463 self.assertEqual(rv, os.path.join(tail_dir, self.file))
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001464
Brian Curtinc57a3452012-06-22 16:00:30 -05001465 def test_nonexistent_file(self):
1466 # Return None when no matching executable file is found on the path.
1467 rv = shutil.which("foo.exe", path=self.dir)
1468 self.assertIsNone(rv)
1469
1470 @unittest.skipUnless(sys.platform == "win32",
1471 "pathext check is Windows-only")
1472 def test_pathext_checking(self):
1473 # Ask for the file without the ".exe" extension, then ensure that
1474 # it gets found properly with the extension.
Serhiy Storchakad70127a2013-01-24 20:03:49 +02001475 rv = shutil.which(self.file[:-4], path=self.dir)
Serhiy Storchaka80c88f42013-01-22 10:31:36 +02001476 self.assertEqual(rv, self.temp_file.name[:-4] + ".EXE")
Brian Curtinc57a3452012-06-22 16:00:30 -05001477
Barry Warsaw618738b2013-04-16 11:05:03 -04001478 def test_environ_path(self):
1479 with support.EnvironmentVarGuard() as env:
Victor Stinner1d006a22013-12-16 23:39:40 +01001480 env['PATH'] = self.dir
Barry Warsaw618738b2013-04-16 11:05:03 -04001481 rv = shutil.which(self.file)
1482 self.assertEqual(rv, self.temp_file.name)
1483
1484 def test_empty_path(self):
1485 base_dir = os.path.dirname(self.dir)
Nick Coghlan55175962013-07-28 22:11:50 +10001486 with support.change_cwd(path=self.dir), \
Barry Warsaw618738b2013-04-16 11:05:03 -04001487 support.EnvironmentVarGuard() as env:
Victor Stinner1d006a22013-12-16 23:39:40 +01001488 env['PATH'] = self.dir
Barry Warsaw618738b2013-04-16 11:05:03 -04001489 rv = shutil.which(self.file, path='')
1490 self.assertIsNone(rv)
1491
1492 def test_empty_path_no_PATH(self):
1493 with support.EnvironmentVarGuard() as env:
1494 env.pop('PATH', None)
1495 rv = shutil.which(self.file)
1496 self.assertIsNone(rv)
1497
Brian Curtinc57a3452012-06-22 16:00:30 -05001498
Christian Heimesada8c3b2008-03-18 18:26:33 +00001499class TestMove(unittest.TestCase):
1500
1501 def setUp(self):
1502 filename = "foo"
1503 self.src_dir = tempfile.mkdtemp()
1504 self.dst_dir = tempfile.mkdtemp()
1505 self.src_file = os.path.join(self.src_dir, filename)
1506 self.dst_file = os.path.join(self.dst_dir, filename)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001507 with open(self.src_file, "wb") as f:
1508 f.write(b"spam")
1509
1510 def tearDown(self):
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001511 for d in (self.src_dir, self.dst_dir):
Christian Heimesada8c3b2008-03-18 18:26:33 +00001512 try:
1513 if d:
1514 shutil.rmtree(d)
1515 except:
1516 pass
1517
1518 def _check_move_file(self, src, dst, real_dst):
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001519 with open(src, "rb") as f:
1520 contents = f.read()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001521 shutil.move(src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001522 with open(real_dst, "rb") as f:
1523 self.assertEqual(contents, f.read())
Christian Heimesada8c3b2008-03-18 18:26:33 +00001524 self.assertFalse(os.path.exists(src))
1525
1526 def _check_move_dir(self, src, dst, real_dst):
1527 contents = sorted(os.listdir(src))
1528 shutil.move(src, dst)
1529 self.assertEqual(contents, sorted(os.listdir(real_dst)))
1530 self.assertFalse(os.path.exists(src))
1531
1532 def test_move_file(self):
1533 # Move a file to another location on the same filesystem.
1534 self._check_move_file(self.src_file, self.dst_file, self.dst_file)
1535
1536 def test_move_file_to_dir(self):
1537 # Move a file inside an existing dir on the same filesystem.
1538 self._check_move_file(self.src_file, self.dst_dir, self.dst_file)
1539
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001540 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001541 def test_move_file_other_fs(self):
1542 # Move a file to an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001543 self.test_move_file()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001544
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001545 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001546 def test_move_file_to_dir_other_fs(self):
1547 # Move a file to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001548 self.test_move_file_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001549
1550 def test_move_dir(self):
1551 # Move a dir to another location on the same filesystem.
1552 dst_dir = tempfile.mktemp()
1553 try:
1554 self._check_move_dir(self.src_dir, dst_dir, dst_dir)
1555 finally:
1556 try:
1557 shutil.rmtree(dst_dir)
1558 except:
1559 pass
1560
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001561 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001562 def test_move_dir_other_fs(self):
1563 # Move a dir to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001564 self.test_move_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001565
1566 def test_move_dir_to_dir(self):
1567 # Move a dir inside an existing dir on the same filesystem.
1568 self._check_move_dir(self.src_dir, self.dst_dir,
1569 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1570
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001571 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001572 def test_move_dir_to_dir_other_fs(self):
1573 # Move a dir inside an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001574 self.test_move_dir_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001575
Serhiy Storchaka3a308b92014-02-11 10:30:59 +02001576 def test_move_dir_sep_to_dir(self):
1577 self._check_move_dir(self.src_dir + os.path.sep, self.dst_dir,
1578 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1579
1580 @unittest.skipUnless(os.path.altsep, 'requires os.path.altsep')
1581 def test_move_dir_altsep_to_dir(self):
1582 self._check_move_dir(self.src_dir + os.path.altsep, self.dst_dir,
1583 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1584
Christian Heimesada8c3b2008-03-18 18:26:33 +00001585 def test_existing_file_inside_dest_dir(self):
1586 # A file with the same name inside the destination dir already exists.
1587 with open(self.dst_file, "wb"):
1588 pass
1589 self.assertRaises(shutil.Error, shutil.move, self.src_file, self.dst_dir)
1590
1591 def test_dont_move_dir_in_itself(self):
1592 # Moving a dir inside itself raises an Error.
1593 dst = os.path.join(self.src_dir, "bar")
1594 self.assertRaises(shutil.Error, shutil.move, self.src_dir, dst)
1595
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001596 def test_destinsrc_false_negative(self):
1597 os.mkdir(TESTFN)
1598 try:
1599 for src, dst in [('srcdir', 'srcdir/dest')]:
1600 src = os.path.join(TESTFN, src)
1601 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001602 self.assertTrue(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001603 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001604 'dst (%s) is not in src (%s)' % (dst, src))
1605 finally:
1606 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001607
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001608 def test_destinsrc_false_positive(self):
1609 os.mkdir(TESTFN)
1610 try:
1611 for src, dst in [('srcdir', 'src/dest'), ('srcdir', 'srcdir.new')]:
1612 src = os.path.join(TESTFN, src)
1613 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001614 self.assertFalse(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001615 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001616 'dst (%s) is in src (%s)' % (dst, src))
1617 finally:
1618 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimes9bd667a2008-01-20 15:14:11 +00001619
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +01001620 @support.skip_unless_symlink
1621 @mock_rename
1622 def test_move_file_symlink(self):
1623 dst = os.path.join(self.src_dir, 'bar')
1624 os.symlink(self.src_file, dst)
1625 shutil.move(dst, self.dst_file)
1626 self.assertTrue(os.path.islink(self.dst_file))
1627 self.assertTrue(os.path.samefile(self.src_file, self.dst_file))
1628
1629 @support.skip_unless_symlink
1630 @mock_rename
1631 def test_move_file_symlink_to_dir(self):
1632 filename = "bar"
1633 dst = os.path.join(self.src_dir, filename)
1634 os.symlink(self.src_file, dst)
1635 shutil.move(dst, self.dst_dir)
1636 final_link = os.path.join(self.dst_dir, filename)
1637 self.assertTrue(os.path.islink(final_link))
1638 self.assertTrue(os.path.samefile(self.src_file, final_link))
1639
1640 @support.skip_unless_symlink
1641 @mock_rename
1642 def test_move_dangling_symlink(self):
1643 src = os.path.join(self.src_dir, 'baz')
1644 dst = os.path.join(self.src_dir, 'bar')
1645 os.symlink(src, dst)
1646 dst_link = os.path.join(self.dst_dir, 'quux')
1647 shutil.move(dst, dst_link)
1648 self.assertTrue(os.path.islink(dst_link))
Antoine Pitrou3f48ac92014-01-01 02:50:45 +01001649 # On Windows, os.path.realpath does not follow symlinks (issue #9949)
1650 if os.name == 'nt':
1651 self.assertEqual(os.path.realpath(src), os.readlink(dst_link))
1652 else:
1653 self.assertEqual(os.path.realpath(src), os.path.realpath(dst_link))
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +01001654
1655 @support.skip_unless_symlink
1656 @mock_rename
1657 def test_move_dir_symlink(self):
1658 src = os.path.join(self.src_dir, 'baz')
1659 dst = os.path.join(self.src_dir, 'bar')
1660 os.mkdir(src)
1661 os.symlink(src, dst)
1662 dst_link = os.path.join(self.dst_dir, 'quux')
1663 shutil.move(dst, dst_link)
1664 self.assertTrue(os.path.islink(dst_link))
1665 self.assertTrue(os.path.samefile(src, dst_link))
1666
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001667 def test_move_return_value(self):
1668 rv = shutil.move(self.src_file, self.dst_dir)
1669 self.assertEqual(rv,
1670 os.path.join(self.dst_dir, os.path.basename(self.src_file)))
1671
1672 def test_move_as_rename_return_value(self):
1673 rv = shutil.move(self.src_file, os.path.join(self.dst_dir, 'bar'))
1674 self.assertEqual(rv, os.path.join(self.dst_dir, 'bar'))
1675
R David Murray6ffface2014-06-11 14:40:13 -04001676 @mock_rename
1677 def test_move_file_special_function(self):
1678 moved = []
1679 def _copy(src, dst):
1680 moved.append((src, dst))
1681 shutil.move(self.src_file, self.dst_dir, copy_function=_copy)
1682 self.assertEqual(len(moved), 1)
1683
1684 @mock_rename
1685 def test_move_dir_special_function(self):
1686 moved = []
1687 def _copy(src, dst):
1688 moved.append((src, dst))
1689 support.create_empty_file(os.path.join(self.src_dir, 'child'))
1690 support.create_empty_file(os.path.join(self.src_dir, 'child1'))
1691 shutil.move(self.src_dir, self.dst_dir, copy_function=_copy)
1692 self.assertEqual(len(moved), 3)
1693
Tarek Ziadé5340db32010-04-19 22:30:51 +00001694
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001695class TestCopyFile(unittest.TestCase):
1696
1697 _delete = False
1698
1699 class Faux(object):
1700 _entered = False
1701 _exited_with = None
1702 _raised = False
1703 def __init__(self, raise_in_exit=False, suppress_at_exit=True):
1704 self._raise_in_exit = raise_in_exit
1705 self._suppress_at_exit = suppress_at_exit
1706 def read(self, *args):
1707 return ''
1708 def __enter__(self):
1709 self._entered = True
1710 def __exit__(self, exc_type, exc_val, exc_tb):
1711 self._exited_with = exc_type, exc_val, exc_tb
1712 if self._raise_in_exit:
1713 self._raised = True
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001714 raise OSError("Cannot close")
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001715 return self._suppress_at_exit
1716
1717 def tearDown(self):
1718 if self._delete:
1719 del shutil.open
1720
1721 def _set_shutil_open(self, func):
1722 shutil.open = func
1723 self._delete = True
1724
1725 def test_w_source_open_fails(self):
1726 def _open(filename, mode='r'):
1727 if filename == 'srcfile':
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001728 raise OSError('Cannot open "srcfile"')
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001729 assert 0 # shouldn't reach here.
1730
1731 self._set_shutil_open(_open)
1732
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001733 self.assertRaises(OSError, shutil.copyfile, 'srcfile', 'destfile')
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001734
1735 def test_w_dest_open_fails(self):
1736
1737 srcfile = self.Faux()
1738
1739 def _open(filename, mode='r'):
1740 if filename == 'srcfile':
1741 return srcfile
1742 if filename == 'destfile':
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001743 raise OSError('Cannot open "destfile"')
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001744 assert 0 # shouldn't reach here.
1745
1746 self._set_shutil_open(_open)
1747
1748 shutil.copyfile('srcfile', 'destfile')
1749 self.assertTrue(srcfile._entered)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001750 self.assertTrue(srcfile._exited_with[0] is OSError)
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001751 self.assertEqual(srcfile._exited_with[1].args,
1752 ('Cannot open "destfile"',))
1753
1754 def test_w_dest_close_fails(self):
1755
1756 srcfile = self.Faux()
1757 destfile = self.Faux(True)
1758
1759 def _open(filename, mode='r'):
1760 if filename == 'srcfile':
1761 return srcfile
1762 if filename == 'destfile':
1763 return destfile
1764 assert 0 # shouldn't reach here.
1765
1766 self._set_shutil_open(_open)
1767
1768 shutil.copyfile('srcfile', 'destfile')
1769 self.assertTrue(srcfile._entered)
1770 self.assertTrue(destfile._entered)
1771 self.assertTrue(destfile._raised)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001772 self.assertTrue(srcfile._exited_with[0] is OSError)
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001773 self.assertEqual(srcfile._exited_with[1].args,
1774 ('Cannot close',))
1775
1776 def test_w_source_close_fails(self):
1777
1778 srcfile = self.Faux(True)
1779 destfile = self.Faux()
1780
1781 def _open(filename, mode='r'):
1782 if filename == 'srcfile':
1783 return srcfile
1784 if filename == 'destfile':
1785 return destfile
1786 assert 0 # shouldn't reach here.
1787
1788 self._set_shutil_open(_open)
1789
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001790 self.assertRaises(OSError,
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001791 shutil.copyfile, 'srcfile', 'destfile')
1792 self.assertTrue(srcfile._entered)
1793 self.assertTrue(destfile._entered)
1794 self.assertFalse(destfile._raised)
1795 self.assertTrue(srcfile._exited_with[0] is None)
1796 self.assertTrue(srcfile._raised)
1797
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001798 def test_move_dir_caseinsensitive(self):
1799 # Renames a folder to the same name
1800 # but a different case.
1801
1802 self.src_dir = tempfile.mkdtemp()
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001803 self.addCleanup(shutil.rmtree, self.src_dir, True)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001804 dst_dir = os.path.join(
1805 os.path.dirname(self.src_dir),
1806 os.path.basename(self.src_dir).upper())
1807 self.assertNotEqual(self.src_dir, dst_dir)
1808
1809 try:
1810 shutil.move(self.src_dir, dst_dir)
1811 self.assertTrue(os.path.isdir(dst_dir))
1812 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +02001813 os.rmdir(dst_dir)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001814
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001815class TermsizeTests(unittest.TestCase):
1816 def test_does_not_crash(self):
1817 """Check if get_terminal_size() returns a meaningful value.
1818
1819 There's no easy portable way to actually check the size of the
1820 terminal, so let's check if it returns something sensible instead.
1821 """
1822 size = shutil.get_terminal_size()
Antoine Pitroucfade362012-02-08 23:48:59 +01001823 self.assertGreaterEqual(size.columns, 0)
1824 self.assertGreaterEqual(size.lines, 0)
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001825
1826 def test_os_environ_first(self):
1827 "Check if environment variables have precedence"
1828
1829 with support.EnvironmentVarGuard() as env:
1830 env['COLUMNS'] = '777'
Serhiy Storchakad30829d2016-04-24 09:58:43 +03001831 del env['LINES']
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001832 size = shutil.get_terminal_size()
1833 self.assertEqual(size.columns, 777)
1834
1835 with support.EnvironmentVarGuard() as env:
Serhiy Storchakad30829d2016-04-24 09:58:43 +03001836 del env['COLUMNS']
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001837 env['LINES'] = '888'
1838 size = shutil.get_terminal_size()
1839 self.assertEqual(size.lines, 888)
1840
Serhiy Storchakad30829d2016-04-24 09:58:43 +03001841 def test_bad_environ(self):
1842 with support.EnvironmentVarGuard() as env:
1843 env['COLUMNS'] = 'xxx'
1844 env['LINES'] = 'yyy'
1845 size = shutil.get_terminal_size()
1846 self.assertGreaterEqual(size.columns, 0)
1847 self.assertGreaterEqual(size.lines, 0)
1848
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001849 @unittest.skipUnless(os.isatty(sys.__stdout__.fileno()), "not on tty")
Victor Stinner119ebb72016-04-19 22:24:56 +02001850 @unittest.skipUnless(hasattr(os, 'get_terminal_size'),
1851 'need os.get_terminal_size()')
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001852 def test_stty_match(self):
1853 """Check if stty returns the same results ignoring env
1854
1855 This test will fail if stdin and stdout are connected to
1856 different terminals with different sizes. Nevertheless, such
1857 situations should be pretty rare.
1858 """
1859 try:
1860 size = subprocess.check_output(['stty', 'size']).decode().split()
1861 except (FileNotFoundError, subprocess.CalledProcessError):
1862 self.skipTest("stty invocation failed")
1863 expected = (int(size[1]), int(size[0])) # reversed order
1864
1865 with support.EnvironmentVarGuard() as env:
1866 del env['LINES']
1867 del env['COLUMNS']
1868 actual = shutil.get_terminal_size()
1869
1870 self.assertEqual(expected, actual)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001871
Serhiy Storchakad30829d2016-04-24 09:58:43 +03001872 def test_fallback(self):
1873 with support.EnvironmentVarGuard() as env:
1874 del env['LINES']
1875 del env['COLUMNS']
1876
1877 # sys.__stdout__ has no fileno()
1878 with support.swap_attr(sys, '__stdout__', None):
1879 size = shutil.get_terminal_size(fallback=(10, 20))
1880 self.assertEqual(size.columns, 10)
1881 self.assertEqual(size.lines, 20)
1882
1883 # sys.__stdout__ is not a terminal on Unix
1884 # or fileno() not in (0, 1, 2) on Windows
1885 with open(os.devnull, 'w') as f, \
1886 support.swap_attr(sys, '__stdout__', f):
1887 size = shutil.get_terminal_size(fallback=(30, 40))
1888 self.assertEqual(size.columns, 30)
1889 self.assertEqual(size.lines, 40)
1890
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001891
Berker Peksag8083cd62014-11-01 11:04:06 +02001892class PublicAPITests(unittest.TestCase):
1893 """Ensures that the correct values are exposed in the public API."""
1894
1895 def test_module_all_attribute(self):
1896 self.assertTrue(hasattr(shutil, '__all__'))
1897 target_api = ['copyfileobj', 'copyfile', 'copymode', 'copystat',
1898 'copy', 'copy2', 'copytree', 'move', 'rmtree', 'Error',
1899 'SpecialFileError', 'ExecError', 'make_archive',
1900 'get_archive_formats', 'register_archive_format',
1901 'unregister_archive_format', 'get_unpack_formats',
1902 'register_unpack_format', 'unregister_unpack_format',
1903 'unpack_archive', 'ignore_patterns', 'chown', 'which',
1904 'get_terminal_size', 'SameFileError']
1905 if hasattr(os, 'statvfs') or os.name == 'nt':
1906 target_api.append('disk_usage')
1907 self.assertEqual(set(shutil.__all__), set(target_api))
1908
1909
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001910if __name__ == '__main__':
Brett Cannon3e9a9ae2013-06-12 21:25:59 -04001911 unittest.main()