blob: 990fae55dbfd65c108032a7c4bb942576bee1690 [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 Storchaka2504cec2015-09-08 05:47:23 +03001069 res = make_archive(rel_base_name, 'zip', root_dir, base_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001070
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001071 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(),
Serhiy Storchaka2504cec2015-09-08 05:47:23 +03001076 ['dist/', 'dist/sub/', 'dist/sub2/',
1077 'dist/file1', 'dist/file2', 'dist/sub/file3'])
Tarek Ziadé396fad72010-02-23 05:30:31 +00001078
Serhiy Storchaka2504cec2015-09-08 05:47:23 +03001079 @requires_zlib
1080 @unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run')
Serhiy Storchakab42de2f2015-11-21 14:09:26 +02001081 @unittest.skipUnless(shutil.which('zip'),
Serhiy Storchaka2504cec2015-09-08 05:47:23 +03001082 'Need the zip command to run')
1083 def test_zipfile_vs_zip(self):
1084 root_dir, base_dir = self._create_files()
1085 base_name = os.path.join(self.mkdtemp(), 'archive')
1086 archive = make_archive(base_name, 'zip', root_dir, base_dir)
1087
1088 # check if ZIP file was created
1089 self.assertEqual(archive, base_name + '.zip')
1090 self.assertTrue(os.path.isfile(archive))
1091
1092 # now create another ZIP file using `zip`
1093 archive2 = os.path.join(root_dir, 'archive2.zip')
1094 zip_cmd = ['zip', '-q', '-r', 'archive2.zip', base_dir]
Serhiy Storchakab42de2f2015-11-21 14:09:26 +02001095 subprocess.check_call(zip_cmd, cwd=root_dir,
1096 stdout=subprocess.DEVNULL)
Serhiy Storchaka2504cec2015-09-08 05:47:23 +03001097
1098 self.assertTrue(os.path.isfile(archive2))
1099 # let's compare both ZIP files
1100 with zipfile.ZipFile(archive) as zf:
1101 names = zf.namelist()
1102 with zipfile.ZipFile(archive2) as zf:
1103 names2 = zf.namelist()
1104 self.assertEqual(sorted(names), sorted(names2))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001105
Serhiy Storchaka8bc792a2015-11-22 14:49:58 +02001106 @requires_zlib
1107 @unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run')
1108 @unittest.skipUnless(shutil.which('unzip'),
1109 'Need the unzip command to run')
1110 def test_unzip_zipfile(self):
1111 root_dir, base_dir = self._create_files()
1112 base_name = os.path.join(self.mkdtemp(), 'archive')
1113 archive = make_archive(base_name, 'zip', root_dir, base_dir)
1114
1115 # check if ZIP file was created
1116 self.assertEqual(archive, base_name + '.zip')
1117 self.assertTrue(os.path.isfile(archive))
1118
1119 # now check the ZIP file using `unzip -t`
1120 zip_cmd = ['unzip', '-t', archive]
1121 with support.change_cwd(root_dir):
1122 try:
1123 subprocess.check_output(zip_cmd, stderr=subprocess.STDOUT)
1124 except subprocess.CalledProcessError as exc:
1125 details = exc.output.decode(errors="replace")
1126 msg = "{}\n\n**Unzip Output**\n{}"
1127 self.fail(msg.format(exc, details))
1128
Tarek Ziadé396fad72010-02-23 05:30:31 +00001129 def test_make_archive(self):
1130 tmpdir = self.mkdtemp()
1131 base_name = os.path.join(tmpdir, 'archive')
1132 self.assertRaises(ValueError, make_archive, base_name, 'xxx')
1133
Ezio Melotti975077a2011-05-19 22:03:22 +03001134 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001135 def test_make_archive_owner_group(self):
1136 # testing make_archive with owner and group, with various combinations
1137 # this works even if there's not gid/uid support
1138 if UID_GID_SUPPORT:
1139 group = grp.getgrgid(0)[0]
1140 owner = pwd.getpwuid(0)[0]
1141 else:
1142 group = owner = 'root'
1143
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001144 root_dir, base_dir = self._create_files()
1145 base_name = os.path.join(self.mkdtemp(), 'archive')
Tarek Ziadé396fad72010-02-23 05:30:31 +00001146 res = make_archive(base_name, 'zip', root_dir, base_dir, owner=owner,
1147 group=group)
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001148 self.assertTrue(os.path.isfile(res))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001149
1150 res = make_archive(base_name, 'zip', root_dir, base_dir)
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001151 self.assertTrue(os.path.isfile(res))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001152
1153 res = make_archive(base_name, 'tar', root_dir, base_dir,
1154 owner=owner, group=group)
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001155 self.assertTrue(os.path.isfile(res))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001156
1157 res = make_archive(base_name, 'tar', root_dir, base_dir,
1158 owner='kjhkjhkjg', group='oihohoh')
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001159 self.assertTrue(os.path.isfile(res))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001160
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001161
Ezio Melotti975077a2011-05-19 22:03:22 +03001162 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001163 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1164 def test_tarfile_root_owner(self):
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001165 root_dir, base_dir = self._create_files()
1166 base_name = os.path.join(self.mkdtemp(), 'archive')
Tarek Ziadé396fad72010-02-23 05:30:31 +00001167 group = grp.getgrgid(0)[0]
1168 owner = pwd.getpwuid(0)[0]
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001169 with support.change_cwd(root_dir):
1170 archive_name = make_archive(base_name, 'gztar', root_dir, 'dist',
1171 owner=owner, group=group)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001172
1173 # check if the compressed tarball was created
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001174 self.assertTrue(os.path.isfile(archive_name))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001175
1176 # now checks the rights
1177 archive = tarfile.open(archive_name)
1178 try:
1179 for member in archive.getmembers():
Ezio Melottib3aedd42010-11-20 19:04:17 +00001180 self.assertEqual(member.uid, 0)
1181 self.assertEqual(member.gid, 0)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001182 finally:
1183 archive.close()
1184
1185 def test_make_archive_cwd(self):
1186 current_dir = os.getcwd()
1187 def _breaks(*args, **kw):
1188 raise RuntimeError()
1189
1190 register_archive_format('xxx', _breaks, [], 'xxx file')
1191 try:
1192 try:
1193 make_archive('xxx', 'xxx', root_dir=self.mkdtemp())
1194 except Exception:
1195 pass
Ezio Melottib3aedd42010-11-20 19:04:17 +00001196 self.assertEqual(os.getcwd(), current_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001197 finally:
1198 unregister_archive_format('xxx')
1199
Serhiy Storchaka9a4fc192014-11-28 00:48:46 +02001200 def test_make_tarfile_in_curdir(self):
1201 # Issue #21280
1202 root_dir = self.mkdtemp()
1203 with support.change_cwd(root_dir):
1204 self.assertEqual(make_archive('test', 'tar'), 'test.tar')
1205 self.assertTrue(os.path.isfile('test.tar'))
1206
1207 @requires_zlib
1208 def test_make_zipfile_in_curdir(self):
1209 # Issue #21280
1210 root_dir = self.mkdtemp()
1211 with support.change_cwd(root_dir):
1212 self.assertEqual(make_archive('test', 'zip'), 'test.zip')
1213 self.assertTrue(os.path.isfile('test.zip'))
1214
Tarek Ziadé396fad72010-02-23 05:30:31 +00001215 def test_register_archive_format(self):
1216
1217 self.assertRaises(TypeError, register_archive_format, 'xxx', 1)
1218 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1219 1)
1220 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1221 [(1, 2), (1, 2, 3)])
1222
1223 register_archive_format('xxx', lambda: x, [(1, 2)], 'xxx file')
1224 formats = [name for name, params in get_archive_formats()]
1225 self.assertIn('xxx', formats)
1226
1227 unregister_archive_format('xxx')
1228 formats = [name for name, params in get_archive_formats()]
1229 self.assertNotIn('xxx', formats)
1230
Ezio Melotti975077a2011-05-19 22:03:22 +03001231 @requires_zlib
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001232 def test_unpack_archive(self):
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001233 formats = ['tar', 'gztar', 'zip']
1234 if BZ2_SUPPORTED:
1235 formats.append('bztar')
Serhiy Storchaka11213772014-08-06 18:50:19 +03001236 if LZMA_SUPPORTED:
1237 formats.append('xztar')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001238
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001239 root_dir, base_dir = self._create_files()
Serhiy Storchaka2504cec2015-09-08 05:47:23 +03001240 expected = rlistdir(root_dir)
1241 expected.remove('outer')
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001242 for format in formats:
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001243 base_name = os.path.join(self.mkdtemp(), 'archive')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001244 filename = make_archive(base_name, format, root_dir, base_dir)
1245
1246 # let's try to unpack it now
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001247 tmpdir2 = self.mkdtemp()
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001248 unpack_archive(filename, tmpdir2)
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001249 self.assertEqual(rlistdir(tmpdir2), expected)
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001250
Nick Coghlanabf202d2011-03-16 13:52:20 -04001251 # and again, this time with the format specified
1252 tmpdir3 = self.mkdtemp()
1253 unpack_archive(filename, tmpdir3, format=format)
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001254 self.assertEqual(rlistdir(tmpdir3), expected)
Nick Coghlanabf202d2011-03-16 13:52:20 -04001255 self.assertRaises(shutil.ReadError, unpack_archive, TESTFN)
1256 self.assertRaises(ValueError, unpack_archive, TESTFN, format='xxx')
1257
Martin Pantereb995702016-07-28 01:11:04 +00001258 def test_unpack_registry(self):
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001259
1260 formats = get_unpack_formats()
1261
1262 def _boo(filename, extract_dir, extra):
Ezio Melottib3aedd42010-11-20 19:04:17 +00001263 self.assertEqual(extra, 1)
1264 self.assertEqual(filename, 'stuff.boo')
1265 self.assertEqual(extract_dir, 'xx')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001266
1267 register_unpack_format('Boo', ['.boo', '.b2'], _boo, [('extra', 1)])
1268 unpack_archive('stuff.boo', 'xx')
1269
1270 # trying to register a .boo unpacker again
1271 self.assertRaises(RegistryError, register_unpack_format, 'Boo2',
1272 ['.boo'], _boo)
1273
1274 # should work now
1275 unregister_unpack_format('Boo')
1276 register_unpack_format('Boo2', ['.boo'], _boo)
1277 self.assertIn(('Boo2', ['.boo'], ''), get_unpack_formats())
1278 self.assertNotIn(('Boo', ['.boo'], ''), get_unpack_formats())
1279
1280 # let's leave a clean state
1281 unregister_unpack_format('Boo2')
Ezio Melottib3aedd42010-11-20 19:04:17 +00001282 self.assertEqual(get_unpack_formats(), formats)
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001283
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001284 @unittest.skipUnless(hasattr(shutil, 'disk_usage'),
1285 "disk_usage not available on this platform")
1286 def test_disk_usage(self):
1287 usage = shutil.disk_usage(os.getcwd())
Éric Araujo2ee61882011-07-02 16:45:45 +02001288 self.assertGreater(usage.total, 0)
1289 self.assertGreater(usage.used, 0)
1290 self.assertGreaterEqual(usage.free, 0)
1291 self.assertGreaterEqual(usage.total, usage.used)
1292 self.assertGreater(usage.total, usage.free)
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001293
Sandro Tosid902a142011-08-22 23:28:27 +02001294 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1295 @unittest.skipUnless(hasattr(os, 'chown'), 'requires os.chown')
1296 def test_chown(self):
1297
1298 # cleaned-up automatically by TestShutil.tearDown method
1299 dirname = self.mkdtemp()
1300 filename = tempfile.mktemp(dir=dirname)
1301 write_file(filename, 'testing chown function')
1302
1303 with self.assertRaises(ValueError):
1304 shutil.chown(filename)
1305
1306 with self.assertRaises(LookupError):
Raymond Hettinger15f44ab2016-08-30 10:47:49 -07001307 shutil.chown(filename, user='non-existing username')
Sandro Tosid902a142011-08-22 23:28:27 +02001308
1309 with self.assertRaises(LookupError):
Raymond Hettinger15f44ab2016-08-30 10:47:49 -07001310 shutil.chown(filename, group='non-existing groupname')
Sandro Tosid902a142011-08-22 23:28:27 +02001311
1312 with self.assertRaises(TypeError):
1313 shutil.chown(filename, b'spam')
1314
1315 with self.assertRaises(TypeError):
1316 shutil.chown(filename, 3.14)
1317
1318 uid = os.getuid()
1319 gid = os.getgid()
1320
1321 def check_chown(path, uid=None, gid=None):
1322 s = os.stat(filename)
1323 if uid is not None:
1324 self.assertEqual(uid, s.st_uid)
1325 if gid is not None:
1326 self.assertEqual(gid, s.st_gid)
1327
1328 shutil.chown(filename, uid, gid)
1329 check_chown(filename, uid, gid)
1330 shutil.chown(filename, uid)
1331 check_chown(filename, uid)
1332 shutil.chown(filename, user=uid)
1333 check_chown(filename, uid)
1334 shutil.chown(filename, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001335 check_chown(filename, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001336
1337 shutil.chown(dirname, uid, gid)
1338 check_chown(dirname, uid, gid)
1339 shutil.chown(dirname, uid)
1340 check_chown(dirname, uid)
1341 shutil.chown(dirname, user=uid)
1342 check_chown(dirname, uid)
1343 shutil.chown(dirname, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001344 check_chown(dirname, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001345
1346 user = pwd.getpwuid(uid)[0]
1347 group = grp.getgrgid(gid)[0]
1348 shutil.chown(filename, user, group)
1349 check_chown(filename, uid, gid)
1350 shutil.chown(dirname, user, group)
1351 check_chown(dirname, uid, gid)
1352
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001353 def test_copy_return_value(self):
1354 # copy and copy2 both return their destination path.
1355 for fn in (shutil.copy, shutil.copy2):
1356 src_dir = self.mkdtemp()
1357 dst_dir = self.mkdtemp()
1358 src = os.path.join(src_dir, 'foo')
1359 write_file(src, 'foo')
1360 rv = fn(src, dst_dir)
1361 self.assertEqual(rv, os.path.join(dst_dir, 'foo'))
1362 rv = fn(src, os.path.join(dst_dir, 'bar'))
1363 self.assertEqual(rv, os.path.join(dst_dir, 'bar'))
1364
1365 def test_copyfile_return_value(self):
1366 # copytree returns its destination path.
1367 src_dir = self.mkdtemp()
1368 dst_dir = self.mkdtemp()
1369 dst_file = os.path.join(dst_dir, 'bar')
1370 src_file = os.path.join(src_dir, 'foo')
1371 write_file(src_file, 'foo')
1372 rv = shutil.copyfile(src_file, dst_file)
1373 self.assertTrue(os.path.exists(rv))
1374 self.assertEqual(read_file(src_file), read_file(dst_file))
1375
Hynek Schlawack48653762012-10-07 12:49:58 +02001376 def test_copyfile_same_file(self):
1377 # copyfile() should raise SameFileError if the source and destination
1378 # are the same.
1379 src_dir = self.mkdtemp()
1380 src_file = os.path.join(src_dir, 'foo')
1381 write_file(src_file, 'foo')
1382 self.assertRaises(SameFileError, shutil.copyfile, src_file, src_file)
Hynek Schlawack27ddb572012-10-28 13:59:27 +01001383 # But Error should work too, to stay backward compatible.
1384 self.assertRaises(Error, shutil.copyfile, src_file, src_file)
Hynek Schlawack48653762012-10-07 12:49:58 +02001385
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001386 def test_copytree_return_value(self):
1387 # copytree returns its destination path.
1388 src_dir = self.mkdtemp()
1389 dst_dir = src_dir + "dest"
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001390 self.addCleanup(shutil.rmtree, dst_dir, True)
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001391 src = os.path.join(src_dir, 'foo')
1392 write_file(src, 'foo')
1393 rv = shutil.copytree(src_dir, dst_dir)
1394 self.assertEqual(['foo'], os.listdir(rv))
1395
Christian Heimes9bd667a2008-01-20 15:14:11 +00001396
Brian Curtinc57a3452012-06-22 16:00:30 -05001397class TestWhich(unittest.TestCase):
1398
1399 def setUp(self):
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001400 self.temp_dir = tempfile.mkdtemp(prefix="Tmp")
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001401 self.addCleanup(shutil.rmtree, self.temp_dir, True)
Brian Curtinc57a3452012-06-22 16:00:30 -05001402 # Give the temp_file an ".exe" suffix for all.
1403 # It's needed on Windows and not harmful on other platforms.
1404 self.temp_file = tempfile.NamedTemporaryFile(dir=self.temp_dir,
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001405 prefix="Tmp",
1406 suffix=".Exe")
Brian Curtinc57a3452012-06-22 16:00:30 -05001407 os.chmod(self.temp_file.name, stat.S_IXUSR)
1408 self.addCleanup(self.temp_file.close)
1409 self.dir, self.file = os.path.split(self.temp_file.name)
1410
1411 def test_basic(self):
1412 # Given an EXE in a directory, it should be returned.
1413 rv = shutil.which(self.file, path=self.dir)
1414 self.assertEqual(rv, self.temp_file.name)
1415
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001416 def test_absolute_cmd(self):
Brian Curtinc57a3452012-06-22 16:00:30 -05001417 # When given the fully qualified path to an executable that exists,
1418 # it should be returned.
1419 rv = shutil.which(self.temp_file.name, path=self.temp_dir)
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001420 self.assertEqual(rv, self.temp_file.name)
1421
1422 def test_relative_cmd(self):
1423 # When given the relative path with a directory part to an executable
1424 # that exists, it should be returned.
1425 base_dir, tail_dir = os.path.split(self.dir)
1426 relpath = os.path.join(tail_dir, self.file)
Nick Coghlan55175962013-07-28 22:11:50 +10001427 with support.change_cwd(path=base_dir):
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001428 rv = shutil.which(relpath, path=self.temp_dir)
1429 self.assertEqual(rv, relpath)
1430 # But it shouldn't be searched in PATH directories (issue #16957).
Nick Coghlan55175962013-07-28 22:11:50 +10001431 with support.change_cwd(path=self.dir):
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001432 rv = shutil.which(relpath, path=base_dir)
1433 self.assertIsNone(rv)
1434
1435 def test_cwd(self):
1436 # Issue #16957
1437 base_dir = os.path.dirname(self.dir)
Nick Coghlan55175962013-07-28 22:11:50 +10001438 with support.change_cwd(path=self.dir):
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001439 rv = shutil.which(self.file, path=base_dir)
1440 if sys.platform == "win32":
1441 # Windows: current directory implicitly on PATH
1442 self.assertEqual(rv, os.path.join(os.curdir, self.file))
1443 else:
1444 # Other platforms: shouldn't match in the current directory.
1445 self.assertIsNone(rv)
Brian Curtinc57a3452012-06-22 16:00:30 -05001446
Serhiy Storchaka12516e22013-05-28 15:50:15 +03001447 @unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0,
1448 'non-root user required')
Brian Curtinc57a3452012-06-22 16:00:30 -05001449 def test_non_matching_mode(self):
1450 # Set the file read-only and ask for writeable files.
1451 os.chmod(self.temp_file.name, stat.S_IREAD)
Serhiy Storchaka12516e22013-05-28 15:50:15 +03001452 if os.access(self.temp_file.name, os.W_OK):
1453 self.skipTest("can't set the file read-only")
Brian Curtinc57a3452012-06-22 16:00:30 -05001454 rv = shutil.which(self.file, path=self.dir, mode=os.W_OK)
1455 self.assertIsNone(rv)
1456
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001457 def test_relative_path(self):
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001458 base_dir, tail_dir = os.path.split(self.dir)
Nick Coghlan55175962013-07-28 22:11:50 +10001459 with support.change_cwd(path=base_dir):
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001460 rv = shutil.which(self.file, path=tail_dir)
1461 self.assertEqual(rv, os.path.join(tail_dir, self.file))
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001462
Brian Curtinc57a3452012-06-22 16:00:30 -05001463 def test_nonexistent_file(self):
1464 # Return None when no matching executable file is found on the path.
1465 rv = shutil.which("foo.exe", path=self.dir)
1466 self.assertIsNone(rv)
1467
1468 @unittest.skipUnless(sys.platform == "win32",
1469 "pathext check is Windows-only")
1470 def test_pathext_checking(self):
1471 # Ask for the file without the ".exe" extension, then ensure that
1472 # it gets found properly with the extension.
Serhiy Storchakad70127a2013-01-24 20:03:49 +02001473 rv = shutil.which(self.file[:-4], path=self.dir)
Serhiy Storchaka80c88f42013-01-22 10:31:36 +02001474 self.assertEqual(rv, self.temp_file.name[:-4] + ".EXE")
Brian Curtinc57a3452012-06-22 16:00:30 -05001475
Barry Warsaw618738b2013-04-16 11:05:03 -04001476 def test_environ_path(self):
1477 with support.EnvironmentVarGuard() as env:
Victor Stinner1d006a22013-12-16 23:39:40 +01001478 env['PATH'] = self.dir
Barry Warsaw618738b2013-04-16 11:05:03 -04001479 rv = shutil.which(self.file)
1480 self.assertEqual(rv, self.temp_file.name)
1481
1482 def test_empty_path(self):
1483 base_dir = os.path.dirname(self.dir)
Nick Coghlan55175962013-07-28 22:11:50 +10001484 with support.change_cwd(path=self.dir), \
Barry Warsaw618738b2013-04-16 11:05:03 -04001485 support.EnvironmentVarGuard() as env:
Victor Stinner1d006a22013-12-16 23:39:40 +01001486 env['PATH'] = self.dir
Barry Warsaw618738b2013-04-16 11:05:03 -04001487 rv = shutil.which(self.file, path='')
1488 self.assertIsNone(rv)
1489
1490 def test_empty_path_no_PATH(self):
1491 with support.EnvironmentVarGuard() as env:
1492 env.pop('PATH', None)
1493 rv = shutil.which(self.file)
1494 self.assertIsNone(rv)
1495
Brian Curtinc57a3452012-06-22 16:00:30 -05001496
Christian Heimesada8c3b2008-03-18 18:26:33 +00001497class TestMove(unittest.TestCase):
1498
1499 def setUp(self):
1500 filename = "foo"
1501 self.src_dir = tempfile.mkdtemp()
1502 self.dst_dir = tempfile.mkdtemp()
1503 self.src_file = os.path.join(self.src_dir, filename)
1504 self.dst_file = os.path.join(self.dst_dir, filename)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001505 with open(self.src_file, "wb") as f:
1506 f.write(b"spam")
1507
1508 def tearDown(self):
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001509 for d in (self.src_dir, self.dst_dir):
Christian Heimesada8c3b2008-03-18 18:26:33 +00001510 try:
1511 if d:
1512 shutil.rmtree(d)
1513 except:
1514 pass
1515
1516 def _check_move_file(self, src, dst, real_dst):
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001517 with open(src, "rb") as f:
1518 contents = f.read()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001519 shutil.move(src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001520 with open(real_dst, "rb") as f:
1521 self.assertEqual(contents, f.read())
Christian Heimesada8c3b2008-03-18 18:26:33 +00001522 self.assertFalse(os.path.exists(src))
1523
1524 def _check_move_dir(self, src, dst, real_dst):
1525 contents = sorted(os.listdir(src))
1526 shutil.move(src, dst)
1527 self.assertEqual(contents, sorted(os.listdir(real_dst)))
1528 self.assertFalse(os.path.exists(src))
1529
1530 def test_move_file(self):
1531 # Move a file to another location on the same filesystem.
1532 self._check_move_file(self.src_file, self.dst_file, self.dst_file)
1533
1534 def test_move_file_to_dir(self):
1535 # Move a file inside an existing dir on the same filesystem.
1536 self._check_move_file(self.src_file, self.dst_dir, self.dst_file)
1537
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001538 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001539 def test_move_file_other_fs(self):
1540 # Move a file to an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001541 self.test_move_file()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001542
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001543 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001544 def test_move_file_to_dir_other_fs(self):
1545 # Move a file to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001546 self.test_move_file_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001547
1548 def test_move_dir(self):
1549 # Move a dir to another location on the same filesystem.
1550 dst_dir = tempfile.mktemp()
1551 try:
1552 self._check_move_dir(self.src_dir, dst_dir, dst_dir)
1553 finally:
1554 try:
1555 shutil.rmtree(dst_dir)
1556 except:
1557 pass
1558
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001559 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001560 def test_move_dir_other_fs(self):
1561 # Move a dir to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001562 self.test_move_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001563
1564 def test_move_dir_to_dir(self):
1565 # Move a dir inside an existing dir on the same filesystem.
1566 self._check_move_dir(self.src_dir, self.dst_dir,
1567 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1568
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001569 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001570 def test_move_dir_to_dir_other_fs(self):
1571 # Move a dir inside an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001572 self.test_move_dir_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001573
Serhiy Storchaka3a308b92014-02-11 10:30:59 +02001574 def test_move_dir_sep_to_dir(self):
1575 self._check_move_dir(self.src_dir + os.path.sep, self.dst_dir,
1576 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1577
1578 @unittest.skipUnless(os.path.altsep, 'requires os.path.altsep')
1579 def test_move_dir_altsep_to_dir(self):
1580 self._check_move_dir(self.src_dir + os.path.altsep, self.dst_dir,
1581 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1582
Christian Heimesada8c3b2008-03-18 18:26:33 +00001583 def test_existing_file_inside_dest_dir(self):
1584 # A file with the same name inside the destination dir already exists.
1585 with open(self.dst_file, "wb"):
1586 pass
1587 self.assertRaises(shutil.Error, shutil.move, self.src_file, self.dst_dir)
1588
1589 def test_dont_move_dir_in_itself(self):
1590 # Moving a dir inside itself raises an Error.
1591 dst = os.path.join(self.src_dir, "bar")
1592 self.assertRaises(shutil.Error, shutil.move, self.src_dir, dst)
1593
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001594 def test_destinsrc_false_negative(self):
1595 os.mkdir(TESTFN)
1596 try:
1597 for src, dst in [('srcdir', 'srcdir/dest')]:
1598 src = os.path.join(TESTFN, src)
1599 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001600 self.assertTrue(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001601 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001602 'dst (%s) is not in src (%s)' % (dst, src))
1603 finally:
1604 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001605
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001606 def test_destinsrc_false_positive(self):
1607 os.mkdir(TESTFN)
1608 try:
1609 for src, dst in [('srcdir', 'src/dest'), ('srcdir', 'srcdir.new')]:
1610 src = os.path.join(TESTFN, src)
1611 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001612 self.assertFalse(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001613 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001614 'dst (%s) is in src (%s)' % (dst, src))
1615 finally:
1616 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimes9bd667a2008-01-20 15:14:11 +00001617
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +01001618 @support.skip_unless_symlink
1619 @mock_rename
1620 def test_move_file_symlink(self):
1621 dst = os.path.join(self.src_dir, 'bar')
1622 os.symlink(self.src_file, dst)
1623 shutil.move(dst, self.dst_file)
1624 self.assertTrue(os.path.islink(self.dst_file))
1625 self.assertTrue(os.path.samefile(self.src_file, self.dst_file))
1626
1627 @support.skip_unless_symlink
1628 @mock_rename
1629 def test_move_file_symlink_to_dir(self):
1630 filename = "bar"
1631 dst = os.path.join(self.src_dir, filename)
1632 os.symlink(self.src_file, dst)
1633 shutil.move(dst, self.dst_dir)
1634 final_link = os.path.join(self.dst_dir, filename)
1635 self.assertTrue(os.path.islink(final_link))
1636 self.assertTrue(os.path.samefile(self.src_file, final_link))
1637
1638 @support.skip_unless_symlink
1639 @mock_rename
1640 def test_move_dangling_symlink(self):
1641 src = os.path.join(self.src_dir, 'baz')
1642 dst = os.path.join(self.src_dir, 'bar')
1643 os.symlink(src, dst)
1644 dst_link = os.path.join(self.dst_dir, 'quux')
1645 shutil.move(dst, dst_link)
1646 self.assertTrue(os.path.islink(dst_link))
Antoine Pitrou3f48ac92014-01-01 02:50:45 +01001647 # On Windows, os.path.realpath does not follow symlinks (issue #9949)
1648 if os.name == 'nt':
1649 self.assertEqual(os.path.realpath(src), os.readlink(dst_link))
1650 else:
1651 self.assertEqual(os.path.realpath(src), os.path.realpath(dst_link))
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +01001652
1653 @support.skip_unless_symlink
1654 @mock_rename
1655 def test_move_dir_symlink(self):
1656 src = os.path.join(self.src_dir, 'baz')
1657 dst = os.path.join(self.src_dir, 'bar')
1658 os.mkdir(src)
1659 os.symlink(src, dst)
1660 dst_link = os.path.join(self.dst_dir, 'quux')
1661 shutil.move(dst, dst_link)
1662 self.assertTrue(os.path.islink(dst_link))
1663 self.assertTrue(os.path.samefile(src, dst_link))
1664
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001665 def test_move_return_value(self):
1666 rv = shutil.move(self.src_file, self.dst_dir)
1667 self.assertEqual(rv,
1668 os.path.join(self.dst_dir, os.path.basename(self.src_file)))
1669
1670 def test_move_as_rename_return_value(self):
1671 rv = shutil.move(self.src_file, os.path.join(self.dst_dir, 'bar'))
1672 self.assertEqual(rv, os.path.join(self.dst_dir, 'bar'))
1673
R David Murray6ffface2014-06-11 14:40:13 -04001674 @mock_rename
1675 def test_move_file_special_function(self):
1676 moved = []
1677 def _copy(src, dst):
1678 moved.append((src, dst))
1679 shutil.move(self.src_file, self.dst_dir, copy_function=_copy)
1680 self.assertEqual(len(moved), 1)
1681
1682 @mock_rename
1683 def test_move_dir_special_function(self):
1684 moved = []
1685 def _copy(src, dst):
1686 moved.append((src, dst))
1687 support.create_empty_file(os.path.join(self.src_dir, 'child'))
1688 support.create_empty_file(os.path.join(self.src_dir, 'child1'))
1689 shutil.move(self.src_dir, self.dst_dir, copy_function=_copy)
1690 self.assertEqual(len(moved), 3)
1691
Tarek Ziadé5340db32010-04-19 22:30:51 +00001692
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001693class TestCopyFile(unittest.TestCase):
1694
1695 _delete = False
1696
1697 class Faux(object):
1698 _entered = False
1699 _exited_with = None
1700 _raised = False
1701 def __init__(self, raise_in_exit=False, suppress_at_exit=True):
1702 self._raise_in_exit = raise_in_exit
1703 self._suppress_at_exit = suppress_at_exit
1704 def read(self, *args):
1705 return ''
1706 def __enter__(self):
1707 self._entered = True
1708 def __exit__(self, exc_type, exc_val, exc_tb):
1709 self._exited_with = exc_type, exc_val, exc_tb
1710 if self._raise_in_exit:
1711 self._raised = True
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001712 raise OSError("Cannot close")
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001713 return self._suppress_at_exit
1714
1715 def tearDown(self):
1716 if self._delete:
1717 del shutil.open
1718
1719 def _set_shutil_open(self, func):
1720 shutil.open = func
1721 self._delete = True
1722
1723 def test_w_source_open_fails(self):
1724 def _open(filename, mode='r'):
1725 if filename == 'srcfile':
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001726 raise OSError('Cannot open "srcfile"')
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001727 assert 0 # shouldn't reach here.
1728
1729 self._set_shutil_open(_open)
1730
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001731 self.assertRaises(OSError, shutil.copyfile, 'srcfile', 'destfile')
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001732
1733 def test_w_dest_open_fails(self):
1734
1735 srcfile = self.Faux()
1736
1737 def _open(filename, mode='r'):
1738 if filename == 'srcfile':
1739 return srcfile
1740 if filename == 'destfile':
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001741 raise OSError('Cannot open "destfile"')
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001742 assert 0 # shouldn't reach here.
1743
1744 self._set_shutil_open(_open)
1745
1746 shutil.copyfile('srcfile', 'destfile')
1747 self.assertTrue(srcfile._entered)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001748 self.assertTrue(srcfile._exited_with[0] is OSError)
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001749 self.assertEqual(srcfile._exited_with[1].args,
1750 ('Cannot open "destfile"',))
1751
1752 def test_w_dest_close_fails(self):
1753
1754 srcfile = self.Faux()
1755 destfile = self.Faux(True)
1756
1757 def _open(filename, mode='r'):
1758 if filename == 'srcfile':
1759 return srcfile
1760 if filename == 'destfile':
1761 return destfile
1762 assert 0 # shouldn't reach here.
1763
1764 self._set_shutil_open(_open)
1765
1766 shutil.copyfile('srcfile', 'destfile')
1767 self.assertTrue(srcfile._entered)
1768 self.assertTrue(destfile._entered)
1769 self.assertTrue(destfile._raised)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001770 self.assertTrue(srcfile._exited_with[0] is OSError)
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001771 self.assertEqual(srcfile._exited_with[1].args,
1772 ('Cannot close',))
1773
1774 def test_w_source_close_fails(self):
1775
1776 srcfile = self.Faux(True)
1777 destfile = self.Faux()
1778
1779 def _open(filename, mode='r'):
1780 if filename == 'srcfile':
1781 return srcfile
1782 if filename == 'destfile':
1783 return destfile
1784 assert 0 # shouldn't reach here.
1785
1786 self._set_shutil_open(_open)
1787
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001788 self.assertRaises(OSError,
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001789 shutil.copyfile, 'srcfile', 'destfile')
1790 self.assertTrue(srcfile._entered)
1791 self.assertTrue(destfile._entered)
1792 self.assertFalse(destfile._raised)
1793 self.assertTrue(srcfile._exited_with[0] is None)
1794 self.assertTrue(srcfile._raised)
1795
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001796 def test_move_dir_caseinsensitive(self):
1797 # Renames a folder to the same name
1798 # but a different case.
1799
1800 self.src_dir = tempfile.mkdtemp()
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001801 self.addCleanup(shutil.rmtree, self.src_dir, True)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001802 dst_dir = os.path.join(
1803 os.path.dirname(self.src_dir),
1804 os.path.basename(self.src_dir).upper())
1805 self.assertNotEqual(self.src_dir, dst_dir)
1806
1807 try:
1808 shutil.move(self.src_dir, dst_dir)
1809 self.assertTrue(os.path.isdir(dst_dir))
1810 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +02001811 os.rmdir(dst_dir)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001812
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001813class TermsizeTests(unittest.TestCase):
1814 def test_does_not_crash(self):
1815 """Check if get_terminal_size() returns a meaningful value.
1816
1817 There's no easy portable way to actually check the size of the
1818 terminal, so let's check if it returns something sensible instead.
1819 """
1820 size = shutil.get_terminal_size()
Antoine Pitroucfade362012-02-08 23:48:59 +01001821 self.assertGreaterEqual(size.columns, 0)
1822 self.assertGreaterEqual(size.lines, 0)
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001823
1824 def test_os_environ_first(self):
1825 "Check if environment variables have precedence"
1826
1827 with support.EnvironmentVarGuard() as env:
1828 env['COLUMNS'] = '777'
Serhiy Storchakad30829d2016-04-24 09:58:43 +03001829 del env['LINES']
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001830 size = shutil.get_terminal_size()
1831 self.assertEqual(size.columns, 777)
1832
1833 with support.EnvironmentVarGuard() as env:
Serhiy Storchakad30829d2016-04-24 09:58:43 +03001834 del env['COLUMNS']
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001835 env['LINES'] = '888'
1836 size = shutil.get_terminal_size()
1837 self.assertEqual(size.lines, 888)
1838
Serhiy Storchakad30829d2016-04-24 09:58:43 +03001839 def test_bad_environ(self):
1840 with support.EnvironmentVarGuard() as env:
1841 env['COLUMNS'] = 'xxx'
1842 env['LINES'] = 'yyy'
1843 size = shutil.get_terminal_size()
1844 self.assertGreaterEqual(size.columns, 0)
1845 self.assertGreaterEqual(size.lines, 0)
1846
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001847 @unittest.skipUnless(os.isatty(sys.__stdout__.fileno()), "not on tty")
Victor Stinner119ebb72016-04-19 22:24:56 +02001848 @unittest.skipUnless(hasattr(os, 'get_terminal_size'),
1849 'need os.get_terminal_size()')
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001850 def test_stty_match(self):
1851 """Check if stty returns the same results ignoring env
1852
1853 This test will fail if stdin and stdout are connected to
1854 different terminals with different sizes. Nevertheless, such
1855 situations should be pretty rare.
1856 """
1857 try:
1858 size = subprocess.check_output(['stty', 'size']).decode().split()
1859 except (FileNotFoundError, subprocess.CalledProcessError):
1860 self.skipTest("stty invocation failed")
1861 expected = (int(size[1]), int(size[0])) # reversed order
1862
1863 with support.EnvironmentVarGuard() as env:
1864 del env['LINES']
1865 del env['COLUMNS']
1866 actual = shutil.get_terminal_size()
1867
1868 self.assertEqual(expected, actual)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001869
Serhiy Storchakad30829d2016-04-24 09:58:43 +03001870 def test_fallback(self):
1871 with support.EnvironmentVarGuard() as env:
1872 del env['LINES']
1873 del env['COLUMNS']
1874
1875 # sys.__stdout__ has no fileno()
1876 with support.swap_attr(sys, '__stdout__', None):
1877 size = shutil.get_terminal_size(fallback=(10, 20))
1878 self.assertEqual(size.columns, 10)
1879 self.assertEqual(size.lines, 20)
1880
1881 # sys.__stdout__ is not a terminal on Unix
1882 # or fileno() not in (0, 1, 2) on Windows
1883 with open(os.devnull, 'w') as f, \
1884 support.swap_attr(sys, '__stdout__', f):
1885 size = shutil.get_terminal_size(fallback=(30, 40))
1886 self.assertEqual(size.columns, 30)
1887 self.assertEqual(size.lines, 40)
1888
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001889
Berker Peksag8083cd62014-11-01 11:04:06 +02001890class PublicAPITests(unittest.TestCase):
1891 """Ensures that the correct values are exposed in the public API."""
1892
1893 def test_module_all_attribute(self):
1894 self.assertTrue(hasattr(shutil, '__all__'))
1895 target_api = ['copyfileobj', 'copyfile', 'copymode', 'copystat',
1896 'copy', 'copy2', 'copytree', 'move', 'rmtree', 'Error',
1897 'SpecialFileError', 'ExecError', 'make_archive',
1898 'get_archive_formats', 'register_archive_format',
1899 'unregister_archive_format', 'get_unpack_formats',
1900 'register_unpack_format', 'unregister_unpack_format',
1901 'unpack_archive', 'ignore_patterns', 'chown', 'which',
1902 'get_terminal_size', 'SameFileError']
1903 if hasattr(os, 'statvfs') or os.name == 'nt':
1904 target_api.append('disk_usage')
1905 self.assertEqual(set(shutil.__all__), set(target_api))
1906
1907
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001908if __name__ == '__main__':
Brett Cannon3e9a9ae2013-06-12 21:25:59 -04001909 unittest.main()