blob: d93efb8867ac703d27f0684337867daa430eca74 [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)
Steve Dowere58571b2016-09-08 11:11:13 -0700135 shutil.rmtree(victim)
Hynek Schlawack3b527782012-06-25 13:27:31 +0200136
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200137 @support.skip_unless_symlink
138 def test_rmtree_fails_on_symlink(self):
139 tmp = self.mkdtemp()
140 dir_ = os.path.join(tmp, 'dir')
141 os.mkdir(dir_)
142 link = os.path.join(tmp, 'link')
143 os.symlink(dir_, link)
144 self.assertRaises(OSError, shutil.rmtree, link)
145 self.assertTrue(os.path.exists(dir_))
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100146 self.assertTrue(os.path.lexists(link))
147 errors = []
148 def onerror(*args):
149 errors.append(args)
150 shutil.rmtree(link, onerror=onerror)
151 self.assertEqual(len(errors), 1)
152 self.assertIs(errors[0][0], os.path.islink)
153 self.assertEqual(errors[0][1], link)
154 self.assertIsInstance(errors[0][2][1], OSError)
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200155
156 @support.skip_unless_symlink
157 def test_rmtree_works_on_symlinks(self):
158 tmp = self.mkdtemp()
159 dir1 = os.path.join(tmp, 'dir1')
160 dir2 = os.path.join(dir1, 'dir2')
161 dir3 = os.path.join(tmp, 'dir3')
162 for d in dir1, dir2, dir3:
163 os.mkdir(d)
164 file1 = os.path.join(tmp, 'file1')
165 write_file(file1, 'foo')
166 link1 = os.path.join(dir1, 'link1')
167 os.symlink(dir2, link1)
168 link2 = os.path.join(dir1, 'link2')
169 os.symlink(dir3, link2)
170 link3 = os.path.join(dir1, 'link3')
171 os.symlink(file1, link3)
172 # make sure symlinks are removed but not followed
173 shutil.rmtree(dir1)
174 self.assertFalse(os.path.exists(dir1))
175 self.assertTrue(os.path.exists(dir3))
176 self.assertTrue(os.path.exists(file1))
177
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000178 def test_rmtree_errors(self):
179 # filename is guaranteed not to exist
180 filename = tempfile.mktemp()
Hynek Schlawackb5501102012-12-10 09:11:25 +0100181 self.assertRaises(FileNotFoundError, shutil.rmtree, filename)
182 # test that ignore_errors option is honored
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100183 shutil.rmtree(filename, ignore_errors=True)
184
185 # existing file
186 tmpdir = self.mkdtemp()
Hynek Schlawackb5501102012-12-10 09:11:25 +0100187 write_file((tmpdir, "tstfile"), "")
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100188 filename = os.path.join(tmpdir, "tstfile")
Hynek Schlawackb5501102012-12-10 09:11:25 +0100189 with self.assertRaises(NotADirectoryError) as cm:
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100190 shutil.rmtree(filename)
Hynek Schlawack87f9b462012-12-10 16:29:57 +0100191 # The reason for this rather odd construct is that Windows sprinkles
192 # a \*.* at the end of file names. But only sometimes on some buildbots
193 possible_args = [filename, os.path.join(filename, '*.*')]
194 self.assertIn(cm.exception.filename, possible_args)
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100195 self.assertTrue(os.path.exists(filename))
Hynek Schlawackb5501102012-12-10 09:11:25 +0100196 # test that ignore_errors option is honored
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100197 shutil.rmtree(filename, ignore_errors=True)
198 self.assertTrue(os.path.exists(filename))
199 errors = []
200 def onerror(*args):
201 errors.append(args)
202 shutil.rmtree(filename, onerror=onerror)
203 self.assertEqual(len(errors), 2)
204 self.assertIs(errors[0][0], os.listdir)
205 self.assertEqual(errors[0][1], filename)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100206 self.assertIsInstance(errors[0][2][1], NotADirectoryError)
Hynek Schlawack87f9b462012-12-10 16:29:57 +0100207 self.assertIn(errors[0][2][1].filename, possible_args)
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100208 self.assertIs(errors[1][0], os.rmdir)
209 self.assertEqual(errors[1][1], filename)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100210 self.assertIsInstance(errors[1][2][1], NotADirectoryError)
Hynek Schlawack87f9b462012-12-10 16:29:57 +0100211 self.assertIn(errors[1][2][1].filename, possible_args)
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000212
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000213
Serhiy Storchaka43767632013-11-03 21:31:38 +0200214 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod()')
215 @unittest.skipIf(sys.platform[:6] == 'cygwin',
216 "This test can't be run on Cygwin (issue #1071513).")
217 @unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0,
218 "This test can't be run reliably as root (issue #1076467).")
219 def test_on_error(self):
220 self.errorState = 0
221 os.mkdir(TESTFN)
222 self.addCleanup(shutil.rmtree, TESTFN)
Antoine Pitrou2f8a75c2012-06-23 21:28:15 +0200223
Serhiy Storchaka43767632013-11-03 21:31:38 +0200224 self.child_file_path = os.path.join(TESTFN, 'a')
225 self.child_dir_path = os.path.join(TESTFN, 'b')
226 support.create_empty_file(self.child_file_path)
227 os.mkdir(self.child_dir_path)
228 old_dir_mode = os.stat(TESTFN).st_mode
229 old_child_file_mode = os.stat(self.child_file_path).st_mode
230 old_child_dir_mode = os.stat(self.child_dir_path).st_mode
231 # Make unwritable.
232 new_mode = stat.S_IREAD|stat.S_IEXEC
233 os.chmod(self.child_file_path, new_mode)
234 os.chmod(self.child_dir_path, new_mode)
235 os.chmod(TESTFN, new_mode)
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000236
Serhiy Storchaka43767632013-11-03 21:31:38 +0200237 self.addCleanup(os.chmod, TESTFN, old_dir_mode)
238 self.addCleanup(os.chmod, self.child_file_path, old_child_file_mode)
239 self.addCleanup(os.chmod, self.child_dir_path, old_child_dir_mode)
Antoine Pitrou2f8a75c2012-06-23 21:28:15 +0200240
Serhiy Storchaka43767632013-11-03 21:31:38 +0200241 shutil.rmtree(TESTFN, onerror=self.check_args_to_onerror)
242 # Test whether onerror has actually been called.
243 self.assertEqual(self.errorState, 3,
244 "Expected call to onerror function did not happen.")
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000245
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000246 def check_args_to_onerror(self, func, arg, exc):
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000247 # test_rmtree_errors deliberately runs rmtree
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200248 # on a directory that is chmod 500, which will fail.
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000249 # This function is run when shutil.rmtree fails.
250 # 99.9% of the time it initially fails to remove
251 # a file in the directory, so the first time through
252 # func is os.remove.
253 # However, some Linux machines running ZFS on
254 # FUSE experienced a failure earlier in the process
255 # at os.listdir. The first failure may legally
256 # be either.
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200257 if self.errorState < 2:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200258 if func is os.unlink:
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200259 self.assertEqual(arg, self.child_file_path)
260 elif func is os.rmdir:
261 self.assertEqual(arg, self.child_dir_path)
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000262 else:
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200263 self.assertIs(func, os.listdir)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200264 self.assertIn(arg, [TESTFN, self.child_dir_path])
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000265 self.assertTrue(issubclass(exc[0], OSError))
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200266 self.errorState += 1
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000267 else:
268 self.assertEqual(func, os.rmdir)
269 self.assertEqual(arg, TESTFN)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000270 self.assertTrue(issubclass(exc[0], OSError))
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200271 self.errorState = 3
272
273 def test_rmtree_does_not_choke_on_failing_lstat(self):
274 try:
275 orig_lstat = os.lstat
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200276 def raiser(fn, *args, **kwargs):
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200277 if fn != TESTFN:
278 raise OSError()
279 else:
280 return orig_lstat(fn)
281 os.lstat = raiser
282
283 os.mkdir(TESTFN)
284 write_file((TESTFN, 'foo'), 'foo')
285 shutil.rmtree(TESTFN)
286 finally:
287 os.lstat = orig_lstat
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000288
Antoine Pitrou78091e62011-12-29 18:54:15 +0100289 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
290 @support.skip_unless_symlink
291 def test_copymode_follow_symlinks(self):
292 tmp_dir = self.mkdtemp()
293 src = os.path.join(tmp_dir, 'foo')
294 dst = os.path.join(tmp_dir, 'bar')
295 src_link = os.path.join(tmp_dir, 'baz')
296 dst_link = os.path.join(tmp_dir, 'quux')
297 write_file(src, 'foo')
298 write_file(dst, 'foo')
299 os.symlink(src, src_link)
300 os.symlink(dst, dst_link)
301 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
302 # file to file
303 os.chmod(dst, stat.S_IRWXO)
304 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
305 shutil.copymode(src, dst)
306 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
Antoine Pitrou3f48ac92014-01-01 02:50:45 +0100307 # On Windows, os.chmod does not follow symlinks (issue #15411)
308 if os.name != 'nt':
309 # follow src link
310 os.chmod(dst, stat.S_IRWXO)
311 shutil.copymode(src_link, dst)
312 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
313 # follow dst link
314 os.chmod(dst, stat.S_IRWXO)
315 shutil.copymode(src, dst_link)
316 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
317 # follow both links
318 os.chmod(dst, stat.S_IRWXO)
319 shutil.copymode(src_link, dst_link)
320 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100321
322 @unittest.skipUnless(hasattr(os, 'lchmod'), 'requires os.lchmod')
323 @support.skip_unless_symlink
324 def test_copymode_symlink_to_symlink(self):
325 tmp_dir = self.mkdtemp()
326 src = os.path.join(tmp_dir, 'foo')
327 dst = os.path.join(tmp_dir, 'bar')
328 src_link = os.path.join(tmp_dir, 'baz')
329 dst_link = os.path.join(tmp_dir, 'quux')
330 write_file(src, 'foo')
331 write_file(dst, 'foo')
332 os.symlink(src, src_link)
333 os.symlink(dst, dst_link)
334 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
335 os.chmod(dst, stat.S_IRWXU)
336 os.lchmod(src_link, stat.S_IRWXO|stat.S_IRWXG)
337 # link to link
338 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700339 shutil.copymode(src_link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100340 self.assertEqual(os.lstat(src_link).st_mode,
341 os.lstat(dst_link).st_mode)
342 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
343 # src link - use chmod
344 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700345 shutil.copymode(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100346 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
347 # dst link - use chmod
348 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700349 shutil.copymode(src, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100350 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
351
352 @unittest.skipIf(hasattr(os, 'lchmod'), 'requires os.lchmod to be missing')
353 @support.skip_unless_symlink
354 def test_copymode_symlink_to_symlink_wo_lchmod(self):
355 tmp_dir = self.mkdtemp()
356 src = os.path.join(tmp_dir, 'foo')
357 dst = os.path.join(tmp_dir, 'bar')
358 src_link = os.path.join(tmp_dir, 'baz')
359 dst_link = os.path.join(tmp_dir, 'quux')
360 write_file(src, 'foo')
361 write_file(dst, 'foo')
362 os.symlink(src, src_link)
363 os.symlink(dst, dst_link)
Larry Hastingsb4038062012-07-15 10:57:38 -0700364 shutil.copymode(src_link, dst_link, follow_symlinks=False) # silent fail
Antoine Pitrou78091e62011-12-29 18:54:15 +0100365
366 @support.skip_unless_symlink
367 def test_copystat_symlinks(self):
368 tmp_dir = self.mkdtemp()
369 src = os.path.join(tmp_dir, 'foo')
370 dst = os.path.join(tmp_dir, 'bar')
371 src_link = os.path.join(tmp_dir, 'baz')
372 dst_link = os.path.join(tmp_dir, 'qux')
373 write_file(src, 'foo')
374 src_stat = os.stat(src)
375 os.utime(src, (src_stat.st_atime,
376 src_stat.st_mtime - 42.0)) # ensure different mtimes
377 write_file(dst, 'bar')
378 self.assertNotEqual(os.stat(src).st_mtime, os.stat(dst).st_mtime)
379 os.symlink(src, src_link)
380 os.symlink(dst, dst_link)
381 if hasattr(os, 'lchmod'):
382 os.lchmod(src_link, stat.S_IRWXO)
383 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
384 os.lchflags(src_link, stat.UF_NODUMP)
385 src_link_stat = os.lstat(src_link)
386 # follow
387 if hasattr(os, 'lchmod'):
Larry Hastingsb4038062012-07-15 10:57:38 -0700388 shutil.copystat(src_link, dst_link, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100389 self.assertNotEqual(src_link_stat.st_mode, os.stat(dst).st_mode)
390 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700391 shutil.copystat(src_link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100392 dst_link_stat = os.lstat(dst_link)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700393 if os.utime in os.supports_follow_symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100394 for attr in 'st_atime', 'st_mtime':
395 # The modification times may be truncated in the new file.
396 self.assertLessEqual(getattr(src_link_stat, attr),
397 getattr(dst_link_stat, attr) + 1)
398 if hasattr(os, 'lchmod'):
399 self.assertEqual(src_link_stat.st_mode, dst_link_stat.st_mode)
400 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
401 self.assertEqual(src_link_stat.st_flags, dst_link_stat.st_flags)
402 # tell to follow but dst is not a link
Larry Hastingsb4038062012-07-15 10:57:38 -0700403 shutil.copystat(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100404 self.assertTrue(abs(os.stat(src).st_mtime - os.stat(dst).st_mtime) <
405 00000.1)
406
Ned Deilybaf75712012-05-10 17:05:19 -0700407 @unittest.skipUnless(hasattr(os, 'chflags') and
408 hasattr(errno, 'EOPNOTSUPP') and
409 hasattr(errno, 'ENOTSUP'),
410 "requires os.chflags, EOPNOTSUPP & ENOTSUP")
411 def test_copystat_handles_harmless_chflags_errors(self):
412 tmpdir = self.mkdtemp()
413 file1 = os.path.join(tmpdir, 'file1')
414 file2 = os.path.join(tmpdir, 'file2')
415 write_file(file1, 'xxx')
416 write_file(file2, 'xxx')
417
418 def make_chflags_raiser(err):
419 ex = OSError()
420
Larry Hastings90867a52012-06-22 17:01:41 -0700421 def _chflags_raiser(path, flags, *, follow_symlinks=True):
Ned Deilybaf75712012-05-10 17:05:19 -0700422 ex.errno = err
423 raise ex
424 return _chflags_raiser
425 old_chflags = os.chflags
426 try:
427 for err in errno.EOPNOTSUPP, errno.ENOTSUP:
428 os.chflags = make_chflags_raiser(err)
429 shutil.copystat(file1, file2)
430 # assert others errors break it
431 os.chflags = make_chflags_raiser(errno.EOPNOTSUPP + errno.ENOTSUP)
432 self.assertRaises(OSError, shutil.copystat, file1, file2)
433 finally:
434 os.chflags = old_chflags
435
Antoine Pitrou424246f2012-05-12 19:02:01 +0200436 @support.skip_unless_xattr
437 def test_copyxattr(self):
438 tmp_dir = self.mkdtemp()
439 src = os.path.join(tmp_dir, 'foo')
440 write_file(src, 'foo')
441 dst = os.path.join(tmp_dir, 'bar')
442 write_file(dst, 'bar')
443
444 # no xattr == no problem
445 shutil._copyxattr(src, dst)
446 # common case
447 os.setxattr(src, 'user.foo', b'42')
448 os.setxattr(src, 'user.bar', b'43')
449 shutil._copyxattr(src, dst)
Gregory P. Smith1093bf22014-01-17 12:01:22 -0800450 self.assertEqual(sorted(os.listxattr(src)), sorted(os.listxattr(dst)))
Antoine Pitrou424246f2012-05-12 19:02:01 +0200451 self.assertEqual(
452 os.getxattr(src, 'user.foo'),
453 os.getxattr(dst, 'user.foo'))
454 # check errors don't affect other attrs
455 os.remove(dst)
456 write_file(dst, 'bar')
457 os_error = OSError(errno.EPERM, 'EPERM')
458
Larry Hastings9cf065c2012-06-22 16:30:09 -0700459 def _raise_on_user_foo(fname, attr, val, **kwargs):
Antoine Pitrou424246f2012-05-12 19:02:01 +0200460 if attr == 'user.foo':
461 raise os_error
462 else:
Larry Hastings9cf065c2012-06-22 16:30:09 -0700463 orig_setxattr(fname, attr, val, **kwargs)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200464 try:
465 orig_setxattr = os.setxattr
466 os.setxattr = _raise_on_user_foo
467 shutil._copyxattr(src, dst)
Antoine Pitrou61597d32012-05-12 23:37:35 +0200468 self.assertIn('user.bar', os.listxattr(dst))
Antoine Pitrou424246f2012-05-12 19:02:01 +0200469 finally:
470 os.setxattr = orig_setxattr
Hynek Schlawack0beab052013-02-05 08:22:44 +0100471 # the source filesystem not supporting xattrs should be ok, too.
472 def _raise_on_src(fname, *, follow_symlinks=True):
473 if fname == src:
474 raise OSError(errno.ENOTSUP, 'Operation not supported')
475 return orig_listxattr(fname, follow_symlinks=follow_symlinks)
476 try:
477 orig_listxattr = os.listxattr
478 os.listxattr = _raise_on_src
479 shutil._copyxattr(src, dst)
480 finally:
481 os.listxattr = orig_listxattr
Antoine Pitrou424246f2012-05-12 19:02:01 +0200482
Larry Hastingsad5ae042012-07-14 17:55:11 -0700483 # test that shutil.copystat copies xattrs
484 src = os.path.join(tmp_dir, 'the_original')
485 write_file(src, src)
486 os.setxattr(src, 'user.the_value', b'fiddly')
487 dst = os.path.join(tmp_dir, 'the_copy')
488 write_file(dst, dst)
489 shutil.copystat(src, dst)
Hynek Schlawackc2d481f2012-07-16 17:11:10 +0200490 self.assertEqual(os.getxattr(dst, 'user.the_value'), b'fiddly')
Larry Hastingsad5ae042012-07-14 17:55:11 -0700491
Antoine Pitrou424246f2012-05-12 19:02:01 +0200492 @support.skip_unless_symlink
493 @support.skip_unless_xattr
494 @unittest.skipUnless(hasattr(os, 'geteuid') and os.geteuid() == 0,
495 'root privileges required')
496 def test_copyxattr_symlinks(self):
497 # On Linux, it's only possible to access non-user xattr for symlinks;
498 # which in turn require root privileges. This test should be expanded
499 # as soon as other platforms gain support for extended attributes.
500 tmp_dir = self.mkdtemp()
501 src = os.path.join(tmp_dir, 'foo')
502 src_link = os.path.join(tmp_dir, 'baz')
503 write_file(src, 'foo')
504 os.symlink(src, src_link)
505 os.setxattr(src, 'trusted.foo', b'42')
Larry Hastings9cf065c2012-06-22 16:30:09 -0700506 os.setxattr(src_link, 'trusted.foo', b'43', follow_symlinks=False)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200507 dst = os.path.join(tmp_dir, 'bar')
508 dst_link = os.path.join(tmp_dir, 'qux')
509 write_file(dst, 'bar')
510 os.symlink(dst, dst_link)
Larry Hastingsb4038062012-07-15 10:57:38 -0700511 shutil._copyxattr(src_link, dst_link, follow_symlinks=False)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700512 self.assertEqual(os.getxattr(dst_link, 'trusted.foo', follow_symlinks=False), b'43')
Antoine Pitrou424246f2012-05-12 19:02:01 +0200513 self.assertRaises(OSError, os.getxattr, dst, 'trusted.foo')
Larry Hastingsb4038062012-07-15 10:57:38 -0700514 shutil._copyxattr(src_link, dst, follow_symlinks=False)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200515 self.assertEqual(os.getxattr(dst, 'trusted.foo'), b'43')
516
Antoine Pitrou78091e62011-12-29 18:54:15 +0100517 @support.skip_unless_symlink
518 def test_copy_symlinks(self):
519 tmp_dir = self.mkdtemp()
520 src = os.path.join(tmp_dir, 'foo')
521 dst = os.path.join(tmp_dir, 'bar')
522 src_link = os.path.join(tmp_dir, 'baz')
523 write_file(src, 'foo')
524 os.symlink(src, src_link)
525 if hasattr(os, 'lchmod'):
526 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
527 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700528 shutil.copy(src_link, dst, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100529 self.assertFalse(os.path.islink(dst))
530 self.assertEqual(read_file(src), read_file(dst))
531 os.remove(dst)
532 # follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700533 shutil.copy(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100534 self.assertTrue(os.path.islink(dst))
535 self.assertEqual(os.readlink(dst), os.readlink(src_link))
536 if hasattr(os, 'lchmod'):
537 self.assertEqual(os.lstat(src_link).st_mode,
538 os.lstat(dst).st_mode)
539
540 @support.skip_unless_symlink
541 def test_copy2_symlinks(self):
542 tmp_dir = self.mkdtemp()
543 src = os.path.join(tmp_dir, 'foo')
544 dst = os.path.join(tmp_dir, 'bar')
545 src_link = os.path.join(tmp_dir, 'baz')
546 write_file(src, 'foo')
547 os.symlink(src, src_link)
548 if hasattr(os, 'lchmod'):
549 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
550 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
551 os.lchflags(src_link, stat.UF_NODUMP)
552 src_stat = os.stat(src)
553 src_link_stat = os.lstat(src_link)
554 # follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700555 shutil.copy2(src_link, dst, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100556 self.assertFalse(os.path.islink(dst))
557 self.assertEqual(read_file(src), read_file(dst))
558 os.remove(dst)
559 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700560 shutil.copy2(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100561 self.assertTrue(os.path.islink(dst))
562 self.assertEqual(os.readlink(dst), os.readlink(src_link))
563 dst_stat = os.lstat(dst)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700564 if os.utime in os.supports_follow_symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100565 for attr in 'st_atime', 'st_mtime':
566 # The modification times may be truncated in the new file.
567 self.assertLessEqual(getattr(src_link_stat, attr),
568 getattr(dst_stat, attr) + 1)
569 if hasattr(os, 'lchmod'):
570 self.assertEqual(src_link_stat.st_mode, dst_stat.st_mode)
571 self.assertNotEqual(src_stat.st_mode, dst_stat.st_mode)
572 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
573 self.assertEqual(src_link_stat.st_flags, dst_stat.st_flags)
574
Antoine Pitrou424246f2012-05-12 19:02:01 +0200575 @support.skip_unless_xattr
576 def test_copy2_xattr(self):
577 tmp_dir = self.mkdtemp()
578 src = os.path.join(tmp_dir, 'foo')
579 dst = os.path.join(tmp_dir, 'bar')
580 write_file(src, 'foo')
581 os.setxattr(src, 'user.foo', b'42')
582 shutil.copy2(src, dst)
583 self.assertEqual(
584 os.getxattr(src, 'user.foo'),
585 os.getxattr(dst, 'user.foo'))
586 os.remove(dst)
587
Antoine Pitrou78091e62011-12-29 18:54:15 +0100588 @support.skip_unless_symlink
589 def test_copyfile_symlinks(self):
590 tmp_dir = self.mkdtemp()
591 src = os.path.join(tmp_dir, 'src')
592 dst = os.path.join(tmp_dir, 'dst')
593 dst_link = os.path.join(tmp_dir, 'dst_link')
594 link = os.path.join(tmp_dir, 'link')
595 write_file(src, 'foo')
596 os.symlink(src, link)
597 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700598 shutil.copyfile(link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100599 self.assertTrue(os.path.islink(dst_link))
600 self.assertEqual(os.readlink(link), os.readlink(dst_link))
601 # follow
602 shutil.copyfile(link, dst)
603 self.assertFalse(os.path.islink(dst))
604
Hynek Schlawack2100b422012-06-23 20:28:32 +0200605 def test_rmtree_uses_safe_fd_version_if_available(self):
Hynek Schlawackd0f6e0a2012-06-29 08:28:20 +0200606 _use_fd_functions = ({os.open, os.stat, os.unlink, os.rmdir} <=
607 os.supports_dir_fd and
608 os.listdir in os.supports_fd and
609 os.stat in os.supports_follow_symlinks)
610 if _use_fd_functions:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200611 self.assertTrue(shutil._use_fd_functions)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000612 self.assertTrue(shutil.rmtree.avoids_symlink_attacks)
Hynek Schlawack2100b422012-06-23 20:28:32 +0200613 tmp_dir = self.mkdtemp()
614 d = os.path.join(tmp_dir, 'a')
615 os.mkdir(d)
616 try:
617 real_rmtree = shutil._rmtree_safe_fd
618 class Called(Exception): pass
619 def _raiser(*args, **kwargs):
620 raise Called
621 shutil._rmtree_safe_fd = _raiser
622 self.assertRaises(Called, shutil.rmtree, d)
623 finally:
624 shutil._rmtree_safe_fd = real_rmtree
625 else:
626 self.assertFalse(shutil._use_fd_functions)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000627 self.assertFalse(shutil.rmtree.avoids_symlink_attacks)
Hynek Schlawack2100b422012-06-23 20:28:32 +0200628
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000629 def test_rmtree_dont_delete_file(self):
630 # When called on a file instead of a directory, don't delete it.
631 handle, path = tempfile.mkstemp()
Victor Stinnerbf816222011-06-30 23:25:47 +0200632 os.close(handle)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200633 self.assertRaises(NotADirectoryError, shutil.rmtree, path)
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000634 os.remove(path)
635
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000636 def test_copytree_simple(self):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000637 src_dir = tempfile.mkdtemp()
638 dst_dir = os.path.join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200639 self.addCleanup(shutil.rmtree, src_dir)
640 self.addCleanup(shutil.rmtree, os.path.dirname(dst_dir))
641 write_file((src_dir, 'test.txt'), '123')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000642 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200643 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000644
Éric Araujoa7e33a12011-08-12 19:51:35 +0200645 shutil.copytree(src_dir, dst_dir)
646 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test.txt')))
647 self.assertTrue(os.path.isdir(os.path.join(dst_dir, 'test_dir')))
648 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test_dir',
649 'test.txt')))
650 actual = read_file((dst_dir, 'test.txt'))
651 self.assertEqual(actual, '123')
652 actual = read_file((dst_dir, 'test_dir', 'test.txt'))
653 self.assertEqual(actual, '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000654
Antoine Pitrou78091e62011-12-29 18:54:15 +0100655 @support.skip_unless_symlink
656 def test_copytree_symlinks(self):
657 tmp_dir = self.mkdtemp()
658 src_dir = os.path.join(tmp_dir, 'src')
659 dst_dir = os.path.join(tmp_dir, 'dst')
660 sub_dir = os.path.join(src_dir, 'sub')
661 os.mkdir(src_dir)
662 os.mkdir(sub_dir)
663 write_file((src_dir, 'file.txt'), 'foo')
664 src_link = os.path.join(sub_dir, 'link')
665 dst_link = os.path.join(dst_dir, 'sub/link')
666 os.symlink(os.path.join(src_dir, 'file.txt'),
667 src_link)
668 if hasattr(os, 'lchmod'):
669 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
670 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
671 os.lchflags(src_link, stat.UF_NODUMP)
672 src_stat = os.lstat(src_link)
673 shutil.copytree(src_dir, dst_dir, symlinks=True)
674 self.assertTrue(os.path.islink(os.path.join(dst_dir, 'sub', 'link')))
675 self.assertEqual(os.readlink(os.path.join(dst_dir, 'sub', 'link')),
676 os.path.join(src_dir, 'file.txt'))
677 dst_stat = os.lstat(dst_link)
678 if hasattr(os, 'lchmod'):
679 self.assertEqual(dst_stat.st_mode, src_stat.st_mode)
680 if hasattr(os, 'lchflags'):
681 self.assertEqual(dst_stat.st_flags, src_stat.st_flags)
682
Georg Brandl2ee470f2008-07-16 12:55:28 +0000683 def test_copytree_with_exclude(self):
Georg Brandl2ee470f2008-07-16 12:55:28 +0000684 # creating data
685 join = os.path.join
686 exists = os.path.exists
687 src_dir = tempfile.mkdtemp()
Georg Brandl2ee470f2008-07-16 12:55:28 +0000688 try:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000689 dst_dir = join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200690 write_file((src_dir, 'test.txt'), '123')
691 write_file((src_dir, 'test.tmp'), '123')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000692 os.mkdir(join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200693 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000694 os.mkdir(join(src_dir, 'test_dir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200695 write_file((src_dir, 'test_dir2', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000696 os.mkdir(join(src_dir, 'test_dir2', 'subdir'))
697 os.mkdir(join(src_dir, 'test_dir2', 'subdir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200698 write_file((src_dir, 'test_dir2', 'subdir', 'test.txt'), '456')
699 write_file((src_dir, 'test_dir2', 'subdir2', 'test.py'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000700
701 # testing glob-like patterns
702 try:
703 patterns = shutil.ignore_patterns('*.tmp', 'test_dir2')
704 shutil.copytree(src_dir, dst_dir, ignore=patterns)
705 # checking the result: some elements should not be copied
706 self.assertTrue(exists(join(dst_dir, 'test.txt')))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200707 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
708 self.assertFalse(exists(join(dst_dir, 'test_dir2')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000709 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200710 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000711 try:
712 patterns = shutil.ignore_patterns('*.tmp', 'subdir*')
713 shutil.copytree(src_dir, dst_dir, ignore=patterns)
714 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200715 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
716 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2')))
717 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000718 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200719 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000720
721 # testing callable-style
722 try:
723 def _filter(src, names):
724 res = []
725 for name in names:
726 path = os.path.join(src, name)
727
728 if (os.path.isdir(path) and
729 path.split()[-1] == 'subdir'):
730 res.append(name)
731 elif os.path.splitext(path)[-1] in ('.py'):
732 res.append(name)
733 return res
734
735 shutil.copytree(src_dir, dst_dir, ignore=_filter)
736
737 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200738 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2',
739 'test.py')))
740 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000741
742 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200743 shutil.rmtree(dst_dir)
Georg Brandl2ee470f2008-07-16 12:55:28 +0000744 finally:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000745 shutil.rmtree(src_dir)
746 shutil.rmtree(os.path.dirname(dst_dir))
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000747
Antoine Pitrouac601602013-08-16 19:35:02 +0200748 def test_copytree_retains_permissions(self):
749 tmp_dir = tempfile.mkdtemp()
750 src_dir = os.path.join(tmp_dir, 'source')
751 os.mkdir(src_dir)
752 dst_dir = os.path.join(tmp_dir, 'destination')
753 self.addCleanup(shutil.rmtree, tmp_dir)
754
755 os.chmod(src_dir, 0o777)
756 write_file((src_dir, 'permissive.txt'), '123')
757 os.chmod(os.path.join(src_dir, 'permissive.txt'), 0o777)
758 write_file((src_dir, 'restrictive.txt'), '456')
759 os.chmod(os.path.join(src_dir, 'restrictive.txt'), 0o600)
760 restrictive_subdir = tempfile.mkdtemp(dir=src_dir)
761 os.chmod(restrictive_subdir, 0o600)
762
763 shutil.copytree(src_dir, dst_dir)
Brett Cannon9c7eb552013-08-23 14:38:11 -0400764 self.assertEqual(os.stat(src_dir).st_mode, os.stat(dst_dir).st_mode)
765 self.assertEqual(os.stat(os.path.join(src_dir, 'permissive.txt')).st_mode,
Antoine Pitrouac601602013-08-16 19:35:02 +0200766 os.stat(os.path.join(dst_dir, 'permissive.txt')).st_mode)
Brett Cannon9c7eb552013-08-23 14:38:11 -0400767 self.assertEqual(os.stat(os.path.join(src_dir, 'restrictive.txt')).st_mode,
Antoine Pitrouac601602013-08-16 19:35:02 +0200768 os.stat(os.path.join(dst_dir, 'restrictive.txt')).st_mode)
769 restrictive_subdir_dst = os.path.join(dst_dir,
770 os.path.split(restrictive_subdir)[1])
Brett Cannon9c7eb552013-08-23 14:38:11 -0400771 self.assertEqual(os.stat(restrictive_subdir).st_mode,
Antoine Pitrouac601602013-08-16 19:35:02 +0200772 os.stat(restrictive_subdir_dst).st_mode)
773
Berker Peksag884afd92014-12-10 02:50:32 +0200774 @unittest.mock.patch('os.chmod')
775 def test_copytree_winerror(self, mock_patch):
776 # When copying to VFAT, copystat() raises OSError. On Windows, the
777 # exception object has a meaningful 'winerror' attribute, but not
778 # on other operating systems. Do not assume 'winerror' is set.
779 src_dir = tempfile.mkdtemp()
780 dst_dir = os.path.join(tempfile.mkdtemp(), 'destination')
781 self.addCleanup(shutil.rmtree, src_dir)
782 self.addCleanup(shutil.rmtree, os.path.dirname(dst_dir))
783
784 mock_patch.side_effect = PermissionError('ka-boom')
785 with self.assertRaises(shutil.Error):
786 shutil.copytree(src_dir, dst_dir)
787
Zachary Ware9fe6d862013-12-08 00:20:35 -0600788 @unittest.skipIf(os.name == 'nt', 'temporarily disabled on Windows')
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000789 @unittest.skipUnless(hasattr(os, 'link'), 'requires os.link')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000790 def test_dont_copy_file_onto_link_to_itself(self):
791 # bug 851123.
792 os.mkdir(TESTFN)
793 src = os.path.join(TESTFN, 'cheese')
794 dst = os.path.join(TESTFN, 'shop')
795 try:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000796 with open(src, 'w') as f:
797 f.write('cheddar')
798 os.link(src, dst)
Hynek Schlawack48653762012-10-07 12:49:58 +0200799 self.assertRaises(shutil.SameFileError, shutil.copyfile, src, dst)
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000800 with open(src, 'r') as f:
801 self.assertEqual(f.read(), 'cheddar')
802 os.remove(dst)
803 finally:
804 shutil.rmtree(TESTFN, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000805
Brian Curtin3b4499c2010-12-28 14:31:47 +0000806 @support.skip_unless_symlink
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000807 def test_dont_copy_file_onto_symlink_to_itself(self):
808 # bug 851123.
809 os.mkdir(TESTFN)
810 src = os.path.join(TESTFN, 'cheese')
811 dst = os.path.join(TESTFN, 'shop')
812 try:
813 with open(src, 'w') as f:
814 f.write('cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000815 # Using `src` here would mean we end up with a symlink pointing
816 # to TESTFN/TESTFN/cheese, while it should point at
817 # TESTFN/cheese.
818 os.symlink('cheese', dst)
Hynek Schlawack48653762012-10-07 12:49:58 +0200819 self.assertRaises(shutil.SameFileError, shutil.copyfile, src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +0000820 with open(src, 'r') as f:
821 self.assertEqual(f.read(), 'cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000822 os.remove(dst)
823 finally:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000824 shutil.rmtree(TESTFN, ignore_errors=True)
Johannes Gijsbers68128712004-08-14 13:57:08 +0000825
Brian Curtin3b4499c2010-12-28 14:31:47 +0000826 @support.skip_unless_symlink
Brian Curtind40e6f72010-07-08 21:39:08 +0000827 def test_rmtree_on_symlink(self):
828 # bug 1669.
829 os.mkdir(TESTFN)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000830 try:
Brian Curtind40e6f72010-07-08 21:39:08 +0000831 src = os.path.join(TESTFN, 'cheese')
832 dst = os.path.join(TESTFN, 'shop')
833 os.mkdir(src)
834 os.symlink(src, dst)
835 self.assertRaises(OSError, shutil.rmtree, dst)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200836 shutil.rmtree(dst, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000837 finally:
Brian Curtind40e6f72010-07-08 21:39:08 +0000838 shutil.rmtree(TESTFN, ignore_errors=True)
839
Serhiy Storchaka43767632013-11-03 21:31:38 +0200840 # Issue #3002: copyfile and copytree block indefinitely on named pipes
841 @unittest.skipUnless(hasattr(os, "mkfifo"), 'requires os.mkfifo()')
842 def test_copyfile_named_pipe(self):
843 os.mkfifo(TESTFN)
844 try:
845 self.assertRaises(shutil.SpecialFileError,
846 shutil.copyfile, TESTFN, TESTFN2)
847 self.assertRaises(shutil.SpecialFileError,
848 shutil.copyfile, __file__, TESTFN)
849 finally:
850 os.remove(TESTFN)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000851
Serhiy Storchaka43767632013-11-03 21:31:38 +0200852 @unittest.skipUnless(hasattr(os, "mkfifo"), 'requires os.mkfifo()')
853 @support.skip_unless_symlink
854 def test_copytree_named_pipe(self):
855 os.mkdir(TESTFN)
856 try:
857 subdir = os.path.join(TESTFN, "subdir")
858 os.mkdir(subdir)
859 pipe = os.path.join(subdir, "mypipe")
860 os.mkfifo(pipe)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000861 try:
Serhiy Storchaka43767632013-11-03 21:31:38 +0200862 shutil.copytree(TESTFN, TESTFN2)
863 except shutil.Error as e:
864 errors = e.args[0]
865 self.assertEqual(len(errors), 1)
866 src, dst, error_msg = errors[0]
867 self.assertEqual("`%s` is a named pipe" % pipe, error_msg)
868 else:
869 self.fail("shutil.Error should have been raised")
870 finally:
871 shutil.rmtree(TESTFN, ignore_errors=True)
872 shutil.rmtree(TESTFN2, ignore_errors=True)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000873
Tarek Ziadé5340db32010-04-19 22:30:51 +0000874 def test_copytree_special_func(self):
875
876 src_dir = self.mkdtemp()
877 dst_dir = os.path.join(self.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200878 write_file((src_dir, 'test.txt'), '123')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000879 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200880 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000881
882 copied = []
883 def _copy(src, dst):
884 copied.append((src, dst))
885
886 shutil.copytree(src_dir, dst_dir, copy_function=_copy)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000887 self.assertEqual(len(copied), 2)
Tarek Ziadé5340db32010-04-19 22:30:51 +0000888
Brian Curtin3b4499c2010-12-28 14:31:47 +0000889 @support.skip_unless_symlink
Tarek Ziadéfb437512010-04-20 08:57:33 +0000890 def test_copytree_dangling_symlinks(self):
891
892 # a dangling symlink raises an error at the end
893 src_dir = self.mkdtemp()
894 dst_dir = os.path.join(self.mkdtemp(), 'destination')
895 os.symlink('IDONTEXIST', os.path.join(src_dir, 'test.txt'))
896 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200897 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadéfb437512010-04-20 08:57:33 +0000898 self.assertRaises(Error, shutil.copytree, src_dir, dst_dir)
899
900 # a dangling symlink is ignored with the proper flag
901 dst_dir = os.path.join(self.mkdtemp(), 'destination2')
902 shutil.copytree(src_dir, dst_dir, ignore_dangling_symlinks=True)
903 self.assertNotIn('test.txt', os.listdir(dst_dir))
904
905 # a dangling symlink is copied if symlinks=True
906 dst_dir = os.path.join(self.mkdtemp(), 'destination3')
907 shutil.copytree(src_dir, dst_dir, symlinks=True)
908 self.assertIn('test.txt', os.listdir(dst_dir))
909
Berker Peksag5a294d82015-07-25 14:53:48 +0300910 @support.skip_unless_symlink
911 def test_copytree_symlink_dir(self):
912 src_dir = self.mkdtemp()
913 dst_dir = os.path.join(self.mkdtemp(), 'destination')
914 os.mkdir(os.path.join(src_dir, 'real_dir'))
915 with open(os.path.join(src_dir, 'real_dir', 'test.txt'), 'w'):
916 pass
917 os.symlink(os.path.join(src_dir, 'real_dir'),
918 os.path.join(src_dir, 'link_to_dir'),
919 target_is_directory=True)
920
921 shutil.copytree(src_dir, dst_dir, symlinks=False)
922 self.assertFalse(os.path.islink(os.path.join(dst_dir, 'link_to_dir')))
923 self.assertIn('test.txt', os.listdir(os.path.join(dst_dir, 'link_to_dir')))
924
925 dst_dir = os.path.join(self.mkdtemp(), 'destination2')
926 shutil.copytree(src_dir, dst_dir, symlinks=True)
927 self.assertTrue(os.path.islink(os.path.join(dst_dir, 'link_to_dir')))
928 self.assertIn('test.txt', os.listdir(os.path.join(dst_dir, 'link_to_dir')))
929
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400930 def _copy_file(self, method):
931 fname = 'test.txt'
932 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200933 write_file((tmpdir, fname), 'xxx')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400934 file1 = os.path.join(tmpdir, fname)
935 tmpdir2 = self.mkdtemp()
936 method(file1, tmpdir2)
937 file2 = os.path.join(tmpdir2, fname)
938 return (file1, file2)
939
940 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
941 def test_copy(self):
942 # Ensure that the copied file exists and has the same mode bits.
943 file1, file2 = self._copy_file(shutil.copy)
944 self.assertTrue(os.path.exists(file2))
945 self.assertEqual(os.stat(file1).st_mode, os.stat(file2).st_mode)
946
947 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
Senthil Kumaran0c2dba52011-07-03 18:21:38 -0700948 @unittest.skipUnless(hasattr(os, 'utime'), 'requires os.utime')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400949 def test_copy2(self):
950 # Ensure that the copied file exists and has the same mode and
951 # modification time bits.
952 file1, file2 = self._copy_file(shutil.copy2)
953 self.assertTrue(os.path.exists(file2))
954 file1_stat = os.stat(file1)
955 file2_stat = os.stat(file2)
956 self.assertEqual(file1_stat.st_mode, file2_stat.st_mode)
957 for attr in 'st_atime', 'st_mtime':
958 # The modification times may be truncated in the new file.
959 self.assertLessEqual(getattr(file1_stat, attr),
960 getattr(file2_stat, attr) + 1)
961 if hasattr(os, 'chflags') and hasattr(file1_stat, 'st_flags'):
962 self.assertEqual(getattr(file1_stat, 'st_flags'),
963 getattr(file2_stat, 'st_flags'))
964
Ezio Melotti975077a2011-05-19 22:03:22 +0300965 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000966 def test_make_tarball(self):
967 # creating something to tar
Serhiy Storchaka527ef072015-09-06 18:33:19 +0300968 root_dir, base_dir = self._create_files('')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000969
970 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400971 # force shutil to create the directory
972 os.rmdir(tmpdir2)
Serhiy Storchakaeba8fee2015-09-07 19:58:23 +0300973 # working with relative paths
974 work_dir = os.path.dirname(tmpdir2)
975 rel_base_name = os.path.join(os.path.basename(tmpdir2), 'archive')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000976
Serhiy Storchakaeba8fee2015-09-07 19:58:23 +0300977 with support.change_cwd(work_dir):
Serhiy Storchaka5558d4f2015-09-08 09:59:02 +0300978 base_name = os.path.abspath(rel_base_name)
Serhiy Storchakaeba8fee2015-09-07 19:58:23 +0300979 tarball = make_archive(rel_base_name, 'gztar', root_dir, '.')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000980
981 # check if the compressed tarball was created
Serhiy Storchakaa091a822015-09-07 13:55:25 +0300982 self.assertEqual(tarball, base_name + '.tar.gz')
Serhiy Storchaka527ef072015-09-06 18:33:19 +0300983 self.assertTrue(os.path.isfile(tarball))
984 self.assertTrue(tarfile.is_tarfile(tarball))
985 with tarfile.open(tarball, 'r:gz') as tf:
986 self.assertCountEqual(tf.getnames(),
987 ['.', './sub', './sub2',
988 './file1', './file2', './sub/file3'])
Tarek Ziadé396fad72010-02-23 05:30:31 +0000989
990 # trying an uncompressed one
Serhiy Storchakaeba8fee2015-09-07 19:58:23 +0300991 with support.change_cwd(work_dir):
992 tarball = make_archive(rel_base_name, 'tar', root_dir, '.')
Serhiy Storchakaa091a822015-09-07 13:55:25 +0300993 self.assertEqual(tarball, base_name + '.tar')
Serhiy Storchaka527ef072015-09-06 18:33:19 +0300994 self.assertTrue(os.path.isfile(tarball))
995 self.assertTrue(tarfile.is_tarfile(tarball))
996 with tarfile.open(tarball, 'r') as tf:
997 self.assertCountEqual(tf.getnames(),
998 ['.', './sub', './sub2',
999 './file1', './file2', './sub/file3'])
Tarek Ziadé396fad72010-02-23 05:30:31 +00001000
1001 def _tarinfo(self, path):
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001002 with tarfile.open(path) as tar:
Tarek Ziadé396fad72010-02-23 05:30:31 +00001003 names = tar.getnames()
1004 names.sort()
1005 return tuple(names)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001006
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001007 def _create_files(self, base_dir='dist'):
Tarek Ziadé396fad72010-02-23 05:30:31 +00001008 # creating something to tar
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001009 root_dir = self.mkdtemp()
1010 dist = os.path.join(root_dir, base_dir)
1011 os.makedirs(dist, exist_ok=True)
Éric Araujoa7e33a12011-08-12 19:51:35 +02001012 write_file((dist, 'file1'), 'xxx')
1013 write_file((dist, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +00001014 os.mkdir(os.path.join(dist, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +02001015 write_file((dist, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +00001016 os.mkdir(os.path.join(dist, 'sub2'))
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001017 if base_dir:
1018 write_file((root_dir, 'outer'), 'xxx')
1019 return root_dir, base_dir
Tarek Ziadé396fad72010-02-23 05:30:31 +00001020
Ezio Melotti975077a2011-05-19 22:03:22 +03001021 @requires_zlib
Serhiy Storchakab42de2f2015-11-21 14:09:26 +02001022 @unittest.skipUnless(shutil.which('tar'),
Tarek Ziadé396fad72010-02-23 05:30:31 +00001023 'Need the tar command to run')
1024 def test_tarfile_vs_tar(self):
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001025 root_dir, base_dir = self._create_files()
1026 base_name = os.path.join(self.mkdtemp(), 'archive')
Serhiy Storchakaa091a822015-09-07 13:55:25 +03001027 tarball = make_archive(base_name, 'gztar', root_dir, base_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001028
1029 # check if the compressed tarball was created
Serhiy Storchakaa091a822015-09-07 13:55:25 +03001030 self.assertEqual(tarball, base_name + '.tar.gz')
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001031 self.assertTrue(os.path.isfile(tarball))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001032
1033 # now create another tarball using `tar`
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001034 tarball2 = os.path.join(root_dir, 'archive2.tar')
1035 tar_cmd = ['tar', '-cf', 'archive2.tar', base_dir]
Serhiy Storchakab42de2f2015-11-21 14:09:26 +02001036 subprocess.check_call(tar_cmd, cwd=root_dir,
1037 stdout=subprocess.DEVNULL)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001038
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001039 self.assertTrue(os.path.isfile(tarball2))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001040 # let's compare both tarballs
Ezio Melottib3aedd42010-11-20 19:04:17 +00001041 self.assertEqual(self._tarinfo(tarball), self._tarinfo(tarball2))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001042
1043 # trying an uncompressed one
Serhiy Storchakaa091a822015-09-07 13:55:25 +03001044 tarball = make_archive(base_name, 'tar', root_dir, base_dir)
1045 self.assertEqual(tarball, base_name + '.tar')
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001046 self.assertTrue(os.path.isfile(tarball))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001047
1048 # now for a dry_run
Serhiy Storchakaa091a822015-09-07 13:55:25 +03001049 tarball = make_archive(base_name, 'tar', root_dir, base_dir,
1050 dry_run=True)
1051 self.assertEqual(tarball, base_name + '.tar')
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001052 self.assertTrue(os.path.isfile(tarball))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001053
Ezio Melotti975077a2011-05-19 22:03:22 +03001054 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001055 @unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run')
1056 def test_make_zipfile(self):
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001057 # creating something to zip
1058 root_dir, base_dir = self._create_files()
Serhiy Storchakaeba8fee2015-09-07 19:58:23 +03001059
1060 tmpdir2 = self.mkdtemp()
1061 # force shutil to create the directory
1062 os.rmdir(tmpdir2)
1063 # working with relative paths
1064 work_dir = os.path.dirname(tmpdir2)
1065 rel_base_name = os.path.join(os.path.basename(tmpdir2), 'archive')
Serhiy Storchakaeba8fee2015-09-07 19:58:23 +03001066
1067 with support.change_cwd(work_dir):
Serhiy Storchaka5558d4f2015-09-08 09:59:02 +03001068 base_name = os.path.abspath(rel_base_name)
Serhiy Storchaka666de772016-10-23 15:55:09 +03001069 res = make_archive(rel_base_name, 'zip', root_dir)
1070
1071 self.assertEqual(res, base_name + '.zip')
1072 self.assertTrue(os.path.isfile(res))
1073 self.assertTrue(zipfile.is_zipfile(res))
1074 with zipfile.ZipFile(res) as zf:
1075 self.assertCountEqual(zf.namelist(),
1076 ['dist/', 'dist/sub/', 'dist/sub2/',
1077 'dist/file1', 'dist/file2', 'dist/sub/file3',
1078 'outer'])
1079
1080 with support.change_cwd(work_dir):
1081 base_name = os.path.abspath(rel_base_name)
Serhiy Storchaka2504cec2015-09-08 05:47:23 +03001082 res = make_archive(rel_base_name, 'zip', root_dir, base_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001083
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001084 self.assertEqual(res, base_name + '.zip')
1085 self.assertTrue(os.path.isfile(res))
1086 self.assertTrue(zipfile.is_zipfile(res))
1087 with zipfile.ZipFile(res) as zf:
1088 self.assertCountEqual(zf.namelist(),
Serhiy Storchaka2504cec2015-09-08 05:47:23 +03001089 ['dist/', 'dist/sub/', 'dist/sub2/',
1090 'dist/file1', 'dist/file2', 'dist/sub/file3'])
Tarek Ziadé396fad72010-02-23 05:30:31 +00001091
Serhiy Storchaka2504cec2015-09-08 05:47:23 +03001092 @requires_zlib
1093 @unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run')
Serhiy Storchakab42de2f2015-11-21 14:09:26 +02001094 @unittest.skipUnless(shutil.which('zip'),
Serhiy Storchaka2504cec2015-09-08 05:47:23 +03001095 'Need the zip command to run')
1096 def test_zipfile_vs_zip(self):
1097 root_dir, base_dir = self._create_files()
1098 base_name = os.path.join(self.mkdtemp(), 'archive')
1099 archive = make_archive(base_name, 'zip', root_dir, base_dir)
1100
1101 # check if ZIP file was created
1102 self.assertEqual(archive, base_name + '.zip')
1103 self.assertTrue(os.path.isfile(archive))
1104
1105 # now create another ZIP file using `zip`
1106 archive2 = os.path.join(root_dir, 'archive2.zip')
1107 zip_cmd = ['zip', '-q', '-r', 'archive2.zip', base_dir]
Serhiy Storchakab42de2f2015-11-21 14:09:26 +02001108 subprocess.check_call(zip_cmd, cwd=root_dir,
1109 stdout=subprocess.DEVNULL)
Serhiy Storchaka2504cec2015-09-08 05:47:23 +03001110
1111 self.assertTrue(os.path.isfile(archive2))
1112 # let's compare both ZIP files
1113 with zipfile.ZipFile(archive) as zf:
1114 names = zf.namelist()
1115 with zipfile.ZipFile(archive2) as zf:
1116 names2 = zf.namelist()
1117 self.assertEqual(sorted(names), sorted(names2))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001118
Serhiy Storchaka8bc792a2015-11-22 14:49:58 +02001119 @requires_zlib
1120 @unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run')
1121 @unittest.skipUnless(shutil.which('unzip'),
1122 'Need the unzip command to run')
1123 def test_unzip_zipfile(self):
1124 root_dir, base_dir = self._create_files()
1125 base_name = os.path.join(self.mkdtemp(), 'archive')
1126 archive = make_archive(base_name, 'zip', root_dir, base_dir)
1127
1128 # check if ZIP file was created
1129 self.assertEqual(archive, base_name + '.zip')
1130 self.assertTrue(os.path.isfile(archive))
1131
1132 # now check the ZIP file using `unzip -t`
1133 zip_cmd = ['unzip', '-t', archive]
1134 with support.change_cwd(root_dir):
1135 try:
1136 subprocess.check_output(zip_cmd, stderr=subprocess.STDOUT)
1137 except subprocess.CalledProcessError as exc:
1138 details = exc.output.decode(errors="replace")
1139 msg = "{}\n\n**Unzip Output**\n{}"
1140 self.fail(msg.format(exc, details))
1141
Tarek Ziadé396fad72010-02-23 05:30:31 +00001142 def test_make_archive(self):
1143 tmpdir = self.mkdtemp()
1144 base_name = os.path.join(tmpdir, 'archive')
1145 self.assertRaises(ValueError, make_archive, base_name, 'xxx')
1146
Ezio Melotti975077a2011-05-19 22:03:22 +03001147 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001148 def test_make_archive_owner_group(self):
1149 # testing make_archive with owner and group, with various combinations
1150 # this works even if there's not gid/uid support
1151 if UID_GID_SUPPORT:
1152 group = grp.getgrgid(0)[0]
1153 owner = pwd.getpwuid(0)[0]
1154 else:
1155 group = owner = 'root'
1156
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001157 root_dir, base_dir = self._create_files()
1158 base_name = os.path.join(self.mkdtemp(), 'archive')
Tarek Ziadé396fad72010-02-23 05:30:31 +00001159 res = make_archive(base_name, 'zip', root_dir, base_dir, owner=owner,
1160 group=group)
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001161 self.assertTrue(os.path.isfile(res))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001162
1163 res = make_archive(base_name, 'zip', root_dir, base_dir)
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001164 self.assertTrue(os.path.isfile(res))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001165
1166 res = make_archive(base_name, 'tar', root_dir, base_dir,
1167 owner=owner, group=group)
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001168 self.assertTrue(os.path.isfile(res))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001169
1170 res = make_archive(base_name, 'tar', root_dir, base_dir,
1171 owner='kjhkjhkjg', group='oihohoh')
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001172 self.assertTrue(os.path.isfile(res))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001173
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001174
Ezio Melotti975077a2011-05-19 22:03:22 +03001175 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001176 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1177 def test_tarfile_root_owner(self):
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001178 root_dir, base_dir = self._create_files()
1179 base_name = os.path.join(self.mkdtemp(), 'archive')
Tarek Ziadé396fad72010-02-23 05:30:31 +00001180 group = grp.getgrgid(0)[0]
1181 owner = pwd.getpwuid(0)[0]
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001182 with support.change_cwd(root_dir):
1183 archive_name = make_archive(base_name, 'gztar', root_dir, 'dist',
1184 owner=owner, group=group)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001185
1186 # check if the compressed tarball was created
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001187 self.assertTrue(os.path.isfile(archive_name))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001188
1189 # now checks the rights
1190 archive = tarfile.open(archive_name)
1191 try:
1192 for member in archive.getmembers():
Ezio Melottib3aedd42010-11-20 19:04:17 +00001193 self.assertEqual(member.uid, 0)
1194 self.assertEqual(member.gid, 0)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001195 finally:
1196 archive.close()
1197
1198 def test_make_archive_cwd(self):
1199 current_dir = os.getcwd()
1200 def _breaks(*args, **kw):
1201 raise RuntimeError()
1202
1203 register_archive_format('xxx', _breaks, [], 'xxx file')
1204 try:
1205 try:
1206 make_archive('xxx', 'xxx', root_dir=self.mkdtemp())
1207 except Exception:
1208 pass
Ezio Melottib3aedd42010-11-20 19:04:17 +00001209 self.assertEqual(os.getcwd(), current_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001210 finally:
1211 unregister_archive_format('xxx')
1212
Serhiy Storchaka9a4fc192014-11-28 00:48:46 +02001213 def test_make_tarfile_in_curdir(self):
1214 # Issue #21280
1215 root_dir = self.mkdtemp()
1216 with support.change_cwd(root_dir):
1217 self.assertEqual(make_archive('test', 'tar'), 'test.tar')
1218 self.assertTrue(os.path.isfile('test.tar'))
1219
1220 @requires_zlib
1221 def test_make_zipfile_in_curdir(self):
1222 # Issue #21280
1223 root_dir = self.mkdtemp()
1224 with support.change_cwd(root_dir):
1225 self.assertEqual(make_archive('test', 'zip'), 'test.zip')
1226 self.assertTrue(os.path.isfile('test.zip'))
1227
Tarek Ziadé396fad72010-02-23 05:30:31 +00001228 def test_register_archive_format(self):
1229
1230 self.assertRaises(TypeError, register_archive_format, 'xxx', 1)
1231 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1232 1)
1233 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1234 [(1, 2), (1, 2, 3)])
1235
1236 register_archive_format('xxx', lambda: x, [(1, 2)], 'xxx file')
1237 formats = [name for name, params in get_archive_formats()]
1238 self.assertIn('xxx', formats)
1239
1240 unregister_archive_format('xxx')
1241 formats = [name for name, params in get_archive_formats()]
1242 self.assertNotIn('xxx', formats)
1243
Ezio Melotti975077a2011-05-19 22:03:22 +03001244 @requires_zlib
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001245 def test_unpack_archive(self):
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001246 formats = ['tar', 'gztar', 'zip']
1247 if BZ2_SUPPORTED:
1248 formats.append('bztar')
Serhiy Storchaka11213772014-08-06 18:50:19 +03001249 if LZMA_SUPPORTED:
1250 formats.append('xztar')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001251
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001252 root_dir, base_dir = self._create_files()
Serhiy Storchaka2504cec2015-09-08 05:47:23 +03001253 expected = rlistdir(root_dir)
1254 expected.remove('outer')
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001255 for format in formats:
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001256 base_name = os.path.join(self.mkdtemp(), 'archive')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001257 filename = make_archive(base_name, format, root_dir, base_dir)
1258
1259 # let's try to unpack it now
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001260 tmpdir2 = self.mkdtemp()
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001261 unpack_archive(filename, tmpdir2)
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001262 self.assertEqual(rlistdir(tmpdir2), expected)
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001263
Nick Coghlanabf202d2011-03-16 13:52:20 -04001264 # and again, this time with the format specified
1265 tmpdir3 = self.mkdtemp()
1266 unpack_archive(filename, tmpdir3, format=format)
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001267 self.assertEqual(rlistdir(tmpdir3), expected)
Nick Coghlanabf202d2011-03-16 13:52:20 -04001268 self.assertRaises(shutil.ReadError, unpack_archive, TESTFN)
1269 self.assertRaises(ValueError, unpack_archive, TESTFN, format='xxx')
1270
Martin Pantereb995702016-07-28 01:11:04 +00001271 def test_unpack_registry(self):
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001272
1273 formats = get_unpack_formats()
1274
1275 def _boo(filename, extract_dir, extra):
Ezio Melottib3aedd42010-11-20 19:04:17 +00001276 self.assertEqual(extra, 1)
1277 self.assertEqual(filename, 'stuff.boo')
1278 self.assertEqual(extract_dir, 'xx')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001279
1280 register_unpack_format('Boo', ['.boo', '.b2'], _boo, [('extra', 1)])
1281 unpack_archive('stuff.boo', 'xx')
1282
1283 # trying to register a .boo unpacker again
1284 self.assertRaises(RegistryError, register_unpack_format, 'Boo2',
1285 ['.boo'], _boo)
1286
1287 # should work now
1288 unregister_unpack_format('Boo')
1289 register_unpack_format('Boo2', ['.boo'], _boo)
1290 self.assertIn(('Boo2', ['.boo'], ''), get_unpack_formats())
1291 self.assertNotIn(('Boo', ['.boo'], ''), get_unpack_formats())
1292
1293 # let's leave a clean state
1294 unregister_unpack_format('Boo2')
Ezio Melottib3aedd42010-11-20 19:04:17 +00001295 self.assertEqual(get_unpack_formats(), formats)
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001296
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001297 @unittest.skipUnless(hasattr(shutil, 'disk_usage'),
1298 "disk_usage not available on this platform")
1299 def test_disk_usage(self):
1300 usage = shutil.disk_usage(os.getcwd())
Éric Araujo2ee61882011-07-02 16:45:45 +02001301 self.assertGreater(usage.total, 0)
1302 self.assertGreater(usage.used, 0)
1303 self.assertGreaterEqual(usage.free, 0)
1304 self.assertGreaterEqual(usage.total, usage.used)
1305 self.assertGreater(usage.total, usage.free)
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001306
Sandro Tosid902a142011-08-22 23:28:27 +02001307 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1308 @unittest.skipUnless(hasattr(os, 'chown'), 'requires os.chown')
1309 def test_chown(self):
1310
1311 # cleaned-up automatically by TestShutil.tearDown method
1312 dirname = self.mkdtemp()
1313 filename = tempfile.mktemp(dir=dirname)
1314 write_file(filename, 'testing chown function')
1315
1316 with self.assertRaises(ValueError):
1317 shutil.chown(filename)
1318
1319 with self.assertRaises(LookupError):
Raymond Hettinger15f44ab2016-08-30 10:47:49 -07001320 shutil.chown(filename, user='non-existing username')
Sandro Tosid902a142011-08-22 23:28:27 +02001321
1322 with self.assertRaises(LookupError):
Raymond Hettinger15f44ab2016-08-30 10:47:49 -07001323 shutil.chown(filename, group='non-existing groupname')
Sandro Tosid902a142011-08-22 23:28:27 +02001324
1325 with self.assertRaises(TypeError):
1326 shutil.chown(filename, b'spam')
1327
1328 with self.assertRaises(TypeError):
1329 shutil.chown(filename, 3.14)
1330
1331 uid = os.getuid()
1332 gid = os.getgid()
1333
1334 def check_chown(path, uid=None, gid=None):
1335 s = os.stat(filename)
1336 if uid is not None:
1337 self.assertEqual(uid, s.st_uid)
1338 if gid is not None:
1339 self.assertEqual(gid, s.st_gid)
1340
1341 shutil.chown(filename, uid, gid)
1342 check_chown(filename, uid, gid)
1343 shutil.chown(filename, uid)
1344 check_chown(filename, uid)
1345 shutil.chown(filename, user=uid)
1346 check_chown(filename, uid)
1347 shutil.chown(filename, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001348 check_chown(filename, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001349
1350 shutil.chown(dirname, uid, gid)
1351 check_chown(dirname, uid, gid)
1352 shutil.chown(dirname, uid)
1353 check_chown(dirname, uid)
1354 shutil.chown(dirname, user=uid)
1355 check_chown(dirname, uid)
1356 shutil.chown(dirname, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001357 check_chown(dirname, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001358
1359 user = pwd.getpwuid(uid)[0]
1360 group = grp.getgrgid(gid)[0]
1361 shutil.chown(filename, user, group)
1362 check_chown(filename, uid, gid)
1363 shutil.chown(dirname, user, group)
1364 check_chown(dirname, uid, gid)
1365
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001366 def test_copy_return_value(self):
1367 # copy and copy2 both return their destination path.
1368 for fn in (shutil.copy, shutil.copy2):
1369 src_dir = self.mkdtemp()
1370 dst_dir = self.mkdtemp()
1371 src = os.path.join(src_dir, 'foo')
1372 write_file(src, 'foo')
1373 rv = fn(src, dst_dir)
1374 self.assertEqual(rv, os.path.join(dst_dir, 'foo'))
1375 rv = fn(src, os.path.join(dst_dir, 'bar'))
1376 self.assertEqual(rv, os.path.join(dst_dir, 'bar'))
1377
1378 def test_copyfile_return_value(self):
1379 # copytree returns its destination path.
1380 src_dir = self.mkdtemp()
1381 dst_dir = self.mkdtemp()
1382 dst_file = os.path.join(dst_dir, 'bar')
1383 src_file = os.path.join(src_dir, 'foo')
1384 write_file(src_file, 'foo')
1385 rv = shutil.copyfile(src_file, dst_file)
1386 self.assertTrue(os.path.exists(rv))
1387 self.assertEqual(read_file(src_file), read_file(dst_file))
1388
Hynek Schlawack48653762012-10-07 12:49:58 +02001389 def test_copyfile_same_file(self):
1390 # copyfile() should raise SameFileError if the source and destination
1391 # are the same.
1392 src_dir = self.mkdtemp()
1393 src_file = os.path.join(src_dir, 'foo')
1394 write_file(src_file, 'foo')
1395 self.assertRaises(SameFileError, shutil.copyfile, src_file, src_file)
Hynek Schlawack27ddb572012-10-28 13:59:27 +01001396 # But Error should work too, to stay backward compatible.
1397 self.assertRaises(Error, shutil.copyfile, src_file, src_file)
Hynek Schlawack48653762012-10-07 12:49:58 +02001398
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001399 def test_copytree_return_value(self):
1400 # copytree returns its destination path.
1401 src_dir = self.mkdtemp()
1402 dst_dir = src_dir + "dest"
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001403 self.addCleanup(shutil.rmtree, dst_dir, True)
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001404 src = os.path.join(src_dir, 'foo')
1405 write_file(src, 'foo')
1406 rv = shutil.copytree(src_dir, dst_dir)
1407 self.assertEqual(['foo'], os.listdir(rv))
1408
Christian Heimes9bd667a2008-01-20 15:14:11 +00001409
Brian Curtinc57a3452012-06-22 16:00:30 -05001410class TestWhich(unittest.TestCase):
1411
1412 def setUp(self):
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001413 self.temp_dir = tempfile.mkdtemp(prefix="Tmp")
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001414 self.addCleanup(shutil.rmtree, self.temp_dir, True)
Brian Curtinc57a3452012-06-22 16:00:30 -05001415 # Give the temp_file an ".exe" suffix for all.
1416 # It's needed on Windows and not harmful on other platforms.
1417 self.temp_file = tempfile.NamedTemporaryFile(dir=self.temp_dir,
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001418 prefix="Tmp",
1419 suffix=".Exe")
Brian Curtinc57a3452012-06-22 16:00:30 -05001420 os.chmod(self.temp_file.name, stat.S_IXUSR)
1421 self.addCleanup(self.temp_file.close)
1422 self.dir, self.file = os.path.split(self.temp_file.name)
1423
1424 def test_basic(self):
1425 # Given an EXE in a directory, it should be returned.
1426 rv = shutil.which(self.file, path=self.dir)
1427 self.assertEqual(rv, self.temp_file.name)
1428
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001429 def test_absolute_cmd(self):
Brian Curtinc57a3452012-06-22 16:00:30 -05001430 # When given the fully qualified path to an executable that exists,
1431 # it should be returned.
1432 rv = shutil.which(self.temp_file.name, path=self.temp_dir)
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001433 self.assertEqual(rv, self.temp_file.name)
1434
1435 def test_relative_cmd(self):
1436 # When given the relative path with a directory part to an executable
1437 # that exists, it should be returned.
1438 base_dir, tail_dir = os.path.split(self.dir)
1439 relpath = os.path.join(tail_dir, self.file)
Nick Coghlan55175962013-07-28 22:11:50 +10001440 with support.change_cwd(path=base_dir):
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001441 rv = shutil.which(relpath, path=self.temp_dir)
1442 self.assertEqual(rv, relpath)
1443 # But it shouldn't be searched in PATH directories (issue #16957).
Nick Coghlan55175962013-07-28 22:11:50 +10001444 with support.change_cwd(path=self.dir):
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001445 rv = shutil.which(relpath, path=base_dir)
1446 self.assertIsNone(rv)
1447
1448 def test_cwd(self):
1449 # Issue #16957
1450 base_dir = os.path.dirname(self.dir)
Nick Coghlan55175962013-07-28 22:11:50 +10001451 with support.change_cwd(path=self.dir):
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001452 rv = shutil.which(self.file, path=base_dir)
1453 if sys.platform == "win32":
1454 # Windows: current directory implicitly on PATH
1455 self.assertEqual(rv, os.path.join(os.curdir, self.file))
1456 else:
1457 # Other platforms: shouldn't match in the current directory.
1458 self.assertIsNone(rv)
Brian Curtinc57a3452012-06-22 16:00:30 -05001459
Serhiy Storchaka12516e22013-05-28 15:50:15 +03001460 @unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0,
1461 'non-root user required')
Brian Curtinc57a3452012-06-22 16:00:30 -05001462 def test_non_matching_mode(self):
1463 # Set the file read-only and ask for writeable files.
1464 os.chmod(self.temp_file.name, stat.S_IREAD)
Serhiy Storchaka12516e22013-05-28 15:50:15 +03001465 if os.access(self.temp_file.name, os.W_OK):
1466 self.skipTest("can't set the file read-only")
Brian Curtinc57a3452012-06-22 16:00:30 -05001467 rv = shutil.which(self.file, path=self.dir, mode=os.W_OK)
1468 self.assertIsNone(rv)
1469
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001470 def test_relative_path(self):
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001471 base_dir, tail_dir = os.path.split(self.dir)
Nick Coghlan55175962013-07-28 22:11:50 +10001472 with support.change_cwd(path=base_dir):
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001473 rv = shutil.which(self.file, path=tail_dir)
1474 self.assertEqual(rv, os.path.join(tail_dir, self.file))
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001475
Brian Curtinc57a3452012-06-22 16:00:30 -05001476 def test_nonexistent_file(self):
1477 # Return None when no matching executable file is found on the path.
1478 rv = shutil.which("foo.exe", path=self.dir)
1479 self.assertIsNone(rv)
1480
1481 @unittest.skipUnless(sys.platform == "win32",
1482 "pathext check is Windows-only")
1483 def test_pathext_checking(self):
1484 # Ask for the file without the ".exe" extension, then ensure that
1485 # it gets found properly with the extension.
Serhiy Storchakad70127a2013-01-24 20:03:49 +02001486 rv = shutil.which(self.file[:-4], path=self.dir)
Serhiy Storchaka80c88f42013-01-22 10:31:36 +02001487 self.assertEqual(rv, self.temp_file.name[:-4] + ".EXE")
Brian Curtinc57a3452012-06-22 16:00:30 -05001488
Barry Warsaw618738b2013-04-16 11:05:03 -04001489 def test_environ_path(self):
1490 with support.EnvironmentVarGuard() as env:
Victor Stinner1d006a22013-12-16 23:39:40 +01001491 env['PATH'] = self.dir
Barry Warsaw618738b2013-04-16 11:05:03 -04001492 rv = shutil.which(self.file)
1493 self.assertEqual(rv, self.temp_file.name)
1494
1495 def test_empty_path(self):
1496 base_dir = os.path.dirname(self.dir)
Nick Coghlan55175962013-07-28 22:11:50 +10001497 with support.change_cwd(path=self.dir), \
Barry Warsaw618738b2013-04-16 11:05:03 -04001498 support.EnvironmentVarGuard() as env:
Victor Stinner1d006a22013-12-16 23:39:40 +01001499 env['PATH'] = self.dir
Barry Warsaw618738b2013-04-16 11:05:03 -04001500 rv = shutil.which(self.file, path='')
1501 self.assertIsNone(rv)
1502
1503 def test_empty_path_no_PATH(self):
1504 with support.EnvironmentVarGuard() as env:
1505 env.pop('PATH', None)
1506 rv = shutil.which(self.file)
1507 self.assertIsNone(rv)
1508
Brian Curtinc57a3452012-06-22 16:00:30 -05001509
Christian Heimesada8c3b2008-03-18 18:26:33 +00001510class TestMove(unittest.TestCase):
1511
1512 def setUp(self):
1513 filename = "foo"
1514 self.src_dir = tempfile.mkdtemp()
1515 self.dst_dir = tempfile.mkdtemp()
1516 self.src_file = os.path.join(self.src_dir, filename)
1517 self.dst_file = os.path.join(self.dst_dir, filename)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001518 with open(self.src_file, "wb") as f:
1519 f.write(b"spam")
1520
1521 def tearDown(self):
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001522 for d in (self.src_dir, self.dst_dir):
Christian Heimesada8c3b2008-03-18 18:26:33 +00001523 try:
1524 if d:
1525 shutil.rmtree(d)
1526 except:
1527 pass
1528
1529 def _check_move_file(self, src, dst, real_dst):
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001530 with open(src, "rb") as f:
1531 contents = f.read()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001532 shutil.move(src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001533 with open(real_dst, "rb") as f:
1534 self.assertEqual(contents, f.read())
Christian Heimesada8c3b2008-03-18 18:26:33 +00001535 self.assertFalse(os.path.exists(src))
1536
1537 def _check_move_dir(self, src, dst, real_dst):
1538 contents = sorted(os.listdir(src))
1539 shutil.move(src, dst)
1540 self.assertEqual(contents, sorted(os.listdir(real_dst)))
1541 self.assertFalse(os.path.exists(src))
1542
1543 def test_move_file(self):
1544 # Move a file to another location on the same filesystem.
1545 self._check_move_file(self.src_file, self.dst_file, self.dst_file)
1546
1547 def test_move_file_to_dir(self):
1548 # Move a file inside an existing dir on the same filesystem.
1549 self._check_move_file(self.src_file, self.dst_dir, self.dst_file)
1550
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001551 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001552 def test_move_file_other_fs(self):
1553 # Move a file to an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001554 self.test_move_file()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001555
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001556 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001557 def test_move_file_to_dir_other_fs(self):
1558 # Move a file to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001559 self.test_move_file_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001560
1561 def test_move_dir(self):
1562 # Move a dir to another location on the same filesystem.
1563 dst_dir = tempfile.mktemp()
1564 try:
1565 self._check_move_dir(self.src_dir, dst_dir, dst_dir)
1566 finally:
1567 try:
1568 shutil.rmtree(dst_dir)
1569 except:
1570 pass
1571
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001572 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001573 def test_move_dir_other_fs(self):
1574 # Move a dir to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001575 self.test_move_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001576
1577 def test_move_dir_to_dir(self):
1578 # Move a dir inside an existing dir on the same filesystem.
1579 self._check_move_dir(self.src_dir, self.dst_dir,
1580 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1581
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001582 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001583 def test_move_dir_to_dir_other_fs(self):
1584 # Move a dir inside an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001585 self.test_move_dir_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001586
Serhiy Storchaka3a308b92014-02-11 10:30:59 +02001587 def test_move_dir_sep_to_dir(self):
1588 self._check_move_dir(self.src_dir + os.path.sep, self.dst_dir,
1589 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1590
1591 @unittest.skipUnless(os.path.altsep, 'requires os.path.altsep')
1592 def test_move_dir_altsep_to_dir(self):
1593 self._check_move_dir(self.src_dir + os.path.altsep, self.dst_dir,
1594 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1595
Christian Heimesada8c3b2008-03-18 18:26:33 +00001596 def test_existing_file_inside_dest_dir(self):
1597 # A file with the same name inside the destination dir already exists.
1598 with open(self.dst_file, "wb"):
1599 pass
1600 self.assertRaises(shutil.Error, shutil.move, self.src_file, self.dst_dir)
1601
1602 def test_dont_move_dir_in_itself(self):
1603 # Moving a dir inside itself raises an Error.
1604 dst = os.path.join(self.src_dir, "bar")
1605 self.assertRaises(shutil.Error, shutil.move, self.src_dir, dst)
1606
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001607 def test_destinsrc_false_negative(self):
1608 os.mkdir(TESTFN)
1609 try:
1610 for src, dst in [('srcdir', 'srcdir/dest')]:
1611 src = os.path.join(TESTFN, src)
1612 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001613 self.assertTrue(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001614 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001615 'dst (%s) is not in src (%s)' % (dst, src))
1616 finally:
1617 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001618
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001619 def test_destinsrc_false_positive(self):
1620 os.mkdir(TESTFN)
1621 try:
1622 for src, dst in [('srcdir', 'src/dest'), ('srcdir', 'srcdir.new')]:
1623 src = os.path.join(TESTFN, src)
1624 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001625 self.assertFalse(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001626 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001627 'dst (%s) is in src (%s)' % (dst, src))
1628 finally:
1629 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimes9bd667a2008-01-20 15:14:11 +00001630
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +01001631 @support.skip_unless_symlink
1632 @mock_rename
1633 def test_move_file_symlink(self):
1634 dst = os.path.join(self.src_dir, 'bar')
1635 os.symlink(self.src_file, dst)
1636 shutil.move(dst, self.dst_file)
1637 self.assertTrue(os.path.islink(self.dst_file))
1638 self.assertTrue(os.path.samefile(self.src_file, self.dst_file))
1639
1640 @support.skip_unless_symlink
1641 @mock_rename
1642 def test_move_file_symlink_to_dir(self):
1643 filename = "bar"
1644 dst = os.path.join(self.src_dir, filename)
1645 os.symlink(self.src_file, dst)
1646 shutil.move(dst, self.dst_dir)
1647 final_link = os.path.join(self.dst_dir, filename)
1648 self.assertTrue(os.path.islink(final_link))
1649 self.assertTrue(os.path.samefile(self.src_file, final_link))
1650
1651 @support.skip_unless_symlink
1652 @mock_rename
1653 def test_move_dangling_symlink(self):
1654 src = os.path.join(self.src_dir, 'baz')
1655 dst = os.path.join(self.src_dir, 'bar')
1656 os.symlink(src, dst)
1657 dst_link = os.path.join(self.dst_dir, 'quux')
1658 shutil.move(dst, dst_link)
1659 self.assertTrue(os.path.islink(dst_link))
Antoine Pitrou3f48ac92014-01-01 02:50:45 +01001660 # On Windows, os.path.realpath does not follow symlinks (issue #9949)
1661 if os.name == 'nt':
1662 self.assertEqual(os.path.realpath(src), os.readlink(dst_link))
1663 else:
1664 self.assertEqual(os.path.realpath(src), os.path.realpath(dst_link))
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +01001665
1666 @support.skip_unless_symlink
1667 @mock_rename
1668 def test_move_dir_symlink(self):
1669 src = os.path.join(self.src_dir, 'baz')
1670 dst = os.path.join(self.src_dir, 'bar')
1671 os.mkdir(src)
1672 os.symlink(src, dst)
1673 dst_link = os.path.join(self.dst_dir, 'quux')
1674 shutil.move(dst, dst_link)
1675 self.assertTrue(os.path.islink(dst_link))
1676 self.assertTrue(os.path.samefile(src, dst_link))
1677
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001678 def test_move_return_value(self):
1679 rv = shutil.move(self.src_file, self.dst_dir)
1680 self.assertEqual(rv,
1681 os.path.join(self.dst_dir, os.path.basename(self.src_file)))
1682
1683 def test_move_as_rename_return_value(self):
1684 rv = shutil.move(self.src_file, os.path.join(self.dst_dir, 'bar'))
1685 self.assertEqual(rv, os.path.join(self.dst_dir, 'bar'))
1686
R David Murray6ffface2014-06-11 14:40:13 -04001687 @mock_rename
1688 def test_move_file_special_function(self):
1689 moved = []
1690 def _copy(src, dst):
1691 moved.append((src, dst))
1692 shutil.move(self.src_file, self.dst_dir, copy_function=_copy)
1693 self.assertEqual(len(moved), 1)
1694
1695 @mock_rename
1696 def test_move_dir_special_function(self):
1697 moved = []
1698 def _copy(src, dst):
1699 moved.append((src, dst))
1700 support.create_empty_file(os.path.join(self.src_dir, 'child'))
1701 support.create_empty_file(os.path.join(self.src_dir, 'child1'))
1702 shutil.move(self.src_dir, self.dst_dir, copy_function=_copy)
1703 self.assertEqual(len(moved), 3)
1704
Tarek Ziadé5340db32010-04-19 22:30:51 +00001705
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001706class TestCopyFile(unittest.TestCase):
1707
1708 _delete = False
1709
1710 class Faux(object):
1711 _entered = False
1712 _exited_with = None
1713 _raised = False
1714 def __init__(self, raise_in_exit=False, suppress_at_exit=True):
1715 self._raise_in_exit = raise_in_exit
1716 self._suppress_at_exit = suppress_at_exit
1717 def read(self, *args):
1718 return ''
1719 def __enter__(self):
1720 self._entered = True
1721 def __exit__(self, exc_type, exc_val, exc_tb):
1722 self._exited_with = exc_type, exc_val, exc_tb
1723 if self._raise_in_exit:
1724 self._raised = True
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001725 raise OSError("Cannot close")
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001726 return self._suppress_at_exit
1727
1728 def tearDown(self):
1729 if self._delete:
1730 del shutil.open
1731
1732 def _set_shutil_open(self, func):
1733 shutil.open = func
1734 self._delete = True
1735
1736 def test_w_source_open_fails(self):
1737 def _open(filename, mode='r'):
1738 if filename == 'srcfile':
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001739 raise OSError('Cannot open "srcfile"')
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001740 assert 0 # shouldn't reach here.
1741
1742 self._set_shutil_open(_open)
1743
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001744 self.assertRaises(OSError, shutil.copyfile, 'srcfile', 'destfile')
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001745
1746 def test_w_dest_open_fails(self):
1747
1748 srcfile = self.Faux()
1749
1750 def _open(filename, mode='r'):
1751 if filename == 'srcfile':
1752 return srcfile
1753 if filename == 'destfile':
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001754 raise OSError('Cannot open "destfile"')
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001755 assert 0 # shouldn't reach here.
1756
1757 self._set_shutil_open(_open)
1758
1759 shutil.copyfile('srcfile', 'destfile')
1760 self.assertTrue(srcfile._entered)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001761 self.assertTrue(srcfile._exited_with[0] is OSError)
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001762 self.assertEqual(srcfile._exited_with[1].args,
1763 ('Cannot open "destfile"',))
1764
1765 def test_w_dest_close_fails(self):
1766
1767 srcfile = self.Faux()
1768 destfile = self.Faux(True)
1769
1770 def _open(filename, mode='r'):
1771 if filename == 'srcfile':
1772 return srcfile
1773 if filename == 'destfile':
1774 return destfile
1775 assert 0 # shouldn't reach here.
1776
1777 self._set_shutil_open(_open)
1778
1779 shutil.copyfile('srcfile', 'destfile')
1780 self.assertTrue(srcfile._entered)
1781 self.assertTrue(destfile._entered)
1782 self.assertTrue(destfile._raised)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001783 self.assertTrue(srcfile._exited_with[0] is OSError)
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001784 self.assertEqual(srcfile._exited_with[1].args,
1785 ('Cannot close',))
1786
1787 def test_w_source_close_fails(self):
1788
1789 srcfile = self.Faux(True)
1790 destfile = self.Faux()
1791
1792 def _open(filename, mode='r'):
1793 if filename == 'srcfile':
1794 return srcfile
1795 if filename == 'destfile':
1796 return destfile
1797 assert 0 # shouldn't reach here.
1798
1799 self._set_shutil_open(_open)
1800
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001801 self.assertRaises(OSError,
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001802 shutil.copyfile, 'srcfile', 'destfile')
1803 self.assertTrue(srcfile._entered)
1804 self.assertTrue(destfile._entered)
1805 self.assertFalse(destfile._raised)
1806 self.assertTrue(srcfile._exited_with[0] is None)
1807 self.assertTrue(srcfile._raised)
1808
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001809 def test_move_dir_caseinsensitive(self):
1810 # Renames a folder to the same name
1811 # but a different case.
1812
1813 self.src_dir = tempfile.mkdtemp()
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001814 self.addCleanup(shutil.rmtree, self.src_dir, True)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001815 dst_dir = os.path.join(
1816 os.path.dirname(self.src_dir),
1817 os.path.basename(self.src_dir).upper())
1818 self.assertNotEqual(self.src_dir, dst_dir)
1819
1820 try:
1821 shutil.move(self.src_dir, dst_dir)
1822 self.assertTrue(os.path.isdir(dst_dir))
1823 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +02001824 os.rmdir(dst_dir)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001825
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001826class TermsizeTests(unittest.TestCase):
1827 def test_does_not_crash(self):
1828 """Check if get_terminal_size() returns a meaningful value.
1829
1830 There's no easy portable way to actually check the size of the
1831 terminal, so let's check if it returns something sensible instead.
1832 """
1833 size = shutil.get_terminal_size()
Antoine Pitroucfade362012-02-08 23:48:59 +01001834 self.assertGreaterEqual(size.columns, 0)
1835 self.assertGreaterEqual(size.lines, 0)
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001836
1837 def test_os_environ_first(self):
1838 "Check if environment variables have precedence"
1839
1840 with support.EnvironmentVarGuard() as env:
1841 env['COLUMNS'] = '777'
Serhiy Storchakad30829d2016-04-24 09:58:43 +03001842 del env['LINES']
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001843 size = shutil.get_terminal_size()
1844 self.assertEqual(size.columns, 777)
1845
1846 with support.EnvironmentVarGuard() as env:
Serhiy Storchakad30829d2016-04-24 09:58:43 +03001847 del env['COLUMNS']
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001848 env['LINES'] = '888'
1849 size = shutil.get_terminal_size()
1850 self.assertEqual(size.lines, 888)
1851
Serhiy Storchakad30829d2016-04-24 09:58:43 +03001852 def test_bad_environ(self):
1853 with support.EnvironmentVarGuard() as env:
1854 env['COLUMNS'] = 'xxx'
1855 env['LINES'] = 'yyy'
1856 size = shutil.get_terminal_size()
1857 self.assertGreaterEqual(size.columns, 0)
1858 self.assertGreaterEqual(size.lines, 0)
1859
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001860 @unittest.skipUnless(os.isatty(sys.__stdout__.fileno()), "not on tty")
Victor Stinner119ebb72016-04-19 22:24:56 +02001861 @unittest.skipUnless(hasattr(os, 'get_terminal_size'),
1862 'need os.get_terminal_size()')
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001863 def test_stty_match(self):
1864 """Check if stty returns the same results ignoring env
1865
1866 This test will fail if stdin and stdout are connected to
1867 different terminals with different sizes. Nevertheless, such
1868 situations should be pretty rare.
1869 """
1870 try:
1871 size = subprocess.check_output(['stty', 'size']).decode().split()
1872 except (FileNotFoundError, subprocess.CalledProcessError):
1873 self.skipTest("stty invocation failed")
1874 expected = (int(size[1]), int(size[0])) # reversed order
1875
1876 with support.EnvironmentVarGuard() as env:
1877 del env['LINES']
1878 del env['COLUMNS']
1879 actual = shutil.get_terminal_size()
1880
1881 self.assertEqual(expected, actual)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001882
Serhiy Storchakad30829d2016-04-24 09:58:43 +03001883 def test_fallback(self):
1884 with support.EnvironmentVarGuard() as env:
1885 del env['LINES']
1886 del env['COLUMNS']
1887
1888 # sys.__stdout__ has no fileno()
1889 with support.swap_attr(sys, '__stdout__', None):
1890 size = shutil.get_terminal_size(fallback=(10, 20))
1891 self.assertEqual(size.columns, 10)
1892 self.assertEqual(size.lines, 20)
1893
1894 # sys.__stdout__ is not a terminal on Unix
1895 # or fileno() not in (0, 1, 2) on Windows
1896 with open(os.devnull, 'w') as f, \
1897 support.swap_attr(sys, '__stdout__', f):
1898 size = shutil.get_terminal_size(fallback=(30, 40))
1899 self.assertEqual(size.columns, 30)
1900 self.assertEqual(size.lines, 40)
1901
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001902
Berker Peksag8083cd62014-11-01 11:04:06 +02001903class PublicAPITests(unittest.TestCase):
1904 """Ensures that the correct values are exposed in the public API."""
1905
1906 def test_module_all_attribute(self):
1907 self.assertTrue(hasattr(shutil, '__all__'))
1908 target_api = ['copyfileobj', 'copyfile', 'copymode', 'copystat',
1909 'copy', 'copy2', 'copytree', 'move', 'rmtree', 'Error',
1910 'SpecialFileError', 'ExecError', 'make_archive',
1911 'get_archive_formats', 'register_archive_format',
1912 'unregister_archive_format', 'get_unpack_formats',
1913 'register_unpack_format', 'unregister_unpack_format',
1914 'unpack_archive', 'ignore_patterns', 'chown', 'which',
1915 'get_terminal_size', 'SameFileError']
1916 if hasattr(os, 'statvfs') or os.name == 'nt':
1917 target_api.append('disk_usage')
1918 self.assertEqual(set(shutil.__all__), set(target_api))
1919
1920
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001921if __name__ == '__main__':
Brett Cannon3e9a9ae2013-06-12 21:25:59 -04001922 unittest.main()