blob: 2ad3a21c86d2c1bd2813219c2ee3a1a907905b43 [file] [log] [blame]
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001# Copyright (C) 2003 Python Software Foundation
2
3import unittest
Berker Peksag884afd92014-12-10 02:50:32 +02004import unittest.mock
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00005import shutil
6import tempfile
Johannes Gijsbers8e6f2de2004-11-23 09:27:27 +00007import sys
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +00008import stat
Brett Cannon1c3fa182004-06-19 21:11:35 +00009import os
10import os.path
Antoine Pitrouc041ab62012-01-02 19:18:02 +010011import errno
Nick Coghlan8ed3cf32011-03-16 14:05:35 -040012import functools
Antoine Pitroubcf2b592012-02-08 23:28:36 +010013import subprocess
Serhiy Storchaka41ad77c2014-08-07 19:38:37 +030014from contextlib import ExitStack
Serhiy Storchaka527ef072015-09-06 18:33:19 +030015from shutil import (make_archive,
Tarek Ziadé396fad72010-02-23 05:30:31 +000016 register_archive_format, unregister_archive_format,
Tarek Ziadé6ac91722010-04-28 17:51:36 +000017 get_archive_formats, Error, unpack_archive,
18 register_unpack_format, RegistryError,
Hynek Schlawack48653762012-10-07 12:49:58 +020019 unregister_unpack_format, get_unpack_formats,
20 SameFileError)
Tarek Ziadé396fad72010-02-23 05:30:31 +000021import tarfile
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +020022import zipfile
Tarek Ziadé396fad72010-02-23 05:30:31 +000023import warnings
24
25from test import support
Xavier de Gaye3a4e9892016-12-13 10:00:01 +010026from test.support import (TESTFN, check_warnings, captured_stdout,
Serhiy Storchaka9bb6fe52016-12-16 19:00:55 +020027 android_not_root)
Serhiy Storchaka11213772014-08-06 18:50:19 +030028
Antoine Pitrou7fff0962009-05-01 21:09:44 +000029TESTFN2 = TESTFN + "2"
Barry Warsaw7fc2cca2003-01-24 17:34:13 +000030
Tarek Ziadé396fad72010-02-23 05:30:31 +000031try:
32 import grp
33 import pwd
34 UID_GID_SUPPORT = True
35except ImportError:
36 UID_GID_SUPPORT = False
37
Nick Coghlan8ed3cf32011-03-16 14:05:35 -040038def _fake_rename(*args, **kwargs):
39 # Pretend the destination path is on a different filesystem.
Antoine Pitrouc041ab62012-01-02 19:18:02 +010040 raise OSError(getattr(errno, 'EXDEV', 18), "Invalid cross-device link")
Nick Coghlan8ed3cf32011-03-16 14:05:35 -040041
42def mock_rename(func):
43 @functools.wraps(func)
44 def wrap(*args, **kwargs):
45 try:
46 builtin_rename = os.rename
47 os.rename = _fake_rename
48 return func(*args, **kwargs)
49 finally:
50 os.rename = builtin_rename
51 return wrap
52
Éric Araujoa7e33a12011-08-12 19:51:35 +020053def write_file(path, content, binary=False):
54 """Write *content* to a file located at *path*.
55
56 If *path* is a tuple instead of a string, os.path.join will be used to
57 make a path. If *binary* is true, the file will be opened in binary
58 mode.
59 """
60 if isinstance(path, tuple):
61 path = os.path.join(*path)
62 with open(path, 'wb' if binary else 'w') as fp:
63 fp.write(content)
64
65def read_file(path, binary=False):
66 """Return contents from a file located at *path*.
67
68 If *path* is a tuple instead of a string, os.path.join will be used to
69 make a path. If *binary* is true, the file will be opened in binary
70 mode.
71 """
72 if isinstance(path, tuple):
73 path = os.path.join(*path)
74 with open(path, 'rb' if binary else 'r') as fp:
75 return fp.read()
76
Serhiy Storchaka527ef072015-09-06 18:33:19 +030077def rlistdir(path):
78 res = []
79 for name in sorted(os.listdir(path)):
80 p = os.path.join(path, name)
81 if os.path.isdir(p) and not os.path.islink(p):
82 res.append(name + '/')
83 for n in rlistdir(p):
84 res.append(name + '/' + n)
85 else:
86 res.append(name)
87 return res
88
Éric Araujoa7e33a12011-08-12 19:51:35 +020089
Barry Warsaw7fc2cca2003-01-24 17:34:13 +000090class TestShutil(unittest.TestCase):
Tarek Ziadé396fad72010-02-23 05:30:31 +000091
92 def setUp(self):
93 super(TestShutil, self).setUp()
94 self.tempdirs = []
95
96 def tearDown(self):
97 super(TestShutil, self).tearDown()
98 while self.tempdirs:
99 d = self.tempdirs.pop()
100 shutil.rmtree(d, os.name in ('nt', 'cygwin'))
101
Tarek Ziadé396fad72010-02-23 05:30:31 +0000102
103 def mkdtemp(self):
104 """Create a temporary directory that will be cleaned up.
105
106 Returns the path of the directory.
107 """
108 d = tempfile.mkdtemp()
109 self.tempdirs.append(d)
110 return d
Tarek Ziadé5340db32010-04-19 22:30:51 +0000111
Hynek Schlawack3b527782012-06-25 13:27:31 +0200112 def test_rmtree_works_on_bytes(self):
113 tmp = self.mkdtemp()
114 victim = os.path.join(tmp, 'killme')
115 os.mkdir(victim)
116 write_file(os.path.join(victim, 'somefile'), 'foo')
117 victim = os.fsencode(victim)
118 self.assertIsInstance(victim, bytes)
Steve Dowere58571b2016-09-08 11:11:13 -0700119 shutil.rmtree(victim)
Hynek Schlawack3b527782012-06-25 13:27:31 +0200120
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200121 @support.skip_unless_symlink
122 def test_rmtree_fails_on_symlink(self):
123 tmp = self.mkdtemp()
124 dir_ = os.path.join(tmp, 'dir')
125 os.mkdir(dir_)
126 link = os.path.join(tmp, 'link')
127 os.symlink(dir_, link)
128 self.assertRaises(OSError, shutil.rmtree, link)
129 self.assertTrue(os.path.exists(dir_))
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100130 self.assertTrue(os.path.lexists(link))
131 errors = []
132 def onerror(*args):
133 errors.append(args)
134 shutil.rmtree(link, onerror=onerror)
135 self.assertEqual(len(errors), 1)
136 self.assertIs(errors[0][0], os.path.islink)
137 self.assertEqual(errors[0][1], link)
138 self.assertIsInstance(errors[0][2][1], OSError)
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200139
140 @support.skip_unless_symlink
141 def test_rmtree_works_on_symlinks(self):
142 tmp = self.mkdtemp()
143 dir1 = os.path.join(tmp, 'dir1')
144 dir2 = os.path.join(dir1, 'dir2')
145 dir3 = os.path.join(tmp, 'dir3')
146 for d in dir1, dir2, dir3:
147 os.mkdir(d)
148 file1 = os.path.join(tmp, 'file1')
149 write_file(file1, 'foo')
150 link1 = os.path.join(dir1, 'link1')
151 os.symlink(dir2, link1)
152 link2 = os.path.join(dir1, 'link2')
153 os.symlink(dir3, link2)
154 link3 = os.path.join(dir1, 'link3')
155 os.symlink(file1, link3)
156 # make sure symlinks are removed but not followed
157 shutil.rmtree(dir1)
158 self.assertFalse(os.path.exists(dir1))
159 self.assertTrue(os.path.exists(dir3))
160 self.assertTrue(os.path.exists(file1))
161
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000162 def test_rmtree_errors(self):
163 # filename is guaranteed not to exist
164 filename = tempfile.mktemp()
Hynek Schlawackb5501102012-12-10 09:11:25 +0100165 self.assertRaises(FileNotFoundError, shutil.rmtree, filename)
166 # test that ignore_errors option is honored
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100167 shutil.rmtree(filename, ignore_errors=True)
168
169 # existing file
170 tmpdir = self.mkdtemp()
Hynek Schlawackb5501102012-12-10 09:11:25 +0100171 write_file((tmpdir, "tstfile"), "")
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100172 filename = os.path.join(tmpdir, "tstfile")
Hynek Schlawackb5501102012-12-10 09:11:25 +0100173 with self.assertRaises(NotADirectoryError) as cm:
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100174 shutil.rmtree(filename)
Hynek Schlawack87f9b462012-12-10 16:29:57 +0100175 # The reason for this rather odd construct is that Windows sprinkles
176 # a \*.* at the end of file names. But only sometimes on some buildbots
177 possible_args = [filename, os.path.join(filename, '*.*')]
178 self.assertIn(cm.exception.filename, possible_args)
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100179 self.assertTrue(os.path.exists(filename))
Hynek Schlawackb5501102012-12-10 09:11:25 +0100180 # test that ignore_errors option is honored
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100181 shutil.rmtree(filename, ignore_errors=True)
182 self.assertTrue(os.path.exists(filename))
183 errors = []
184 def onerror(*args):
185 errors.append(args)
186 shutil.rmtree(filename, onerror=onerror)
187 self.assertEqual(len(errors), 2)
188 self.assertIs(errors[0][0], os.listdir)
189 self.assertEqual(errors[0][1], filename)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100190 self.assertIsInstance(errors[0][2][1], NotADirectoryError)
Hynek Schlawack87f9b462012-12-10 16:29:57 +0100191 self.assertIn(errors[0][2][1].filename, possible_args)
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100192 self.assertIs(errors[1][0], os.rmdir)
193 self.assertEqual(errors[1][1], filename)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100194 self.assertIsInstance(errors[1][2][1], NotADirectoryError)
Hynek Schlawack87f9b462012-12-10 16:29:57 +0100195 self.assertIn(errors[1][2][1].filename, possible_args)
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000196
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000197
Serhiy Storchaka43767632013-11-03 21:31:38 +0200198 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod()')
199 @unittest.skipIf(sys.platform[:6] == 'cygwin',
200 "This test can't be run on Cygwin (issue #1071513).")
201 @unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0,
202 "This test can't be run reliably as root (issue #1076467).")
203 def test_on_error(self):
204 self.errorState = 0
205 os.mkdir(TESTFN)
206 self.addCleanup(shutil.rmtree, TESTFN)
Antoine Pitrou2f8a75c2012-06-23 21:28:15 +0200207
Serhiy Storchaka43767632013-11-03 21:31:38 +0200208 self.child_file_path = os.path.join(TESTFN, 'a')
209 self.child_dir_path = os.path.join(TESTFN, 'b')
210 support.create_empty_file(self.child_file_path)
211 os.mkdir(self.child_dir_path)
212 old_dir_mode = os.stat(TESTFN).st_mode
213 old_child_file_mode = os.stat(self.child_file_path).st_mode
214 old_child_dir_mode = os.stat(self.child_dir_path).st_mode
215 # Make unwritable.
216 new_mode = stat.S_IREAD|stat.S_IEXEC
217 os.chmod(self.child_file_path, new_mode)
218 os.chmod(self.child_dir_path, new_mode)
219 os.chmod(TESTFN, new_mode)
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000220
Serhiy Storchaka43767632013-11-03 21:31:38 +0200221 self.addCleanup(os.chmod, TESTFN, old_dir_mode)
222 self.addCleanup(os.chmod, self.child_file_path, old_child_file_mode)
223 self.addCleanup(os.chmod, self.child_dir_path, old_child_dir_mode)
Antoine Pitrou2f8a75c2012-06-23 21:28:15 +0200224
Serhiy Storchaka43767632013-11-03 21:31:38 +0200225 shutil.rmtree(TESTFN, onerror=self.check_args_to_onerror)
226 # Test whether onerror has actually been called.
227 self.assertEqual(self.errorState, 3,
228 "Expected call to onerror function did not happen.")
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000229
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000230 def check_args_to_onerror(self, func, arg, exc):
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000231 # test_rmtree_errors deliberately runs rmtree
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200232 # on a directory that is chmod 500, which will fail.
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000233 # This function is run when shutil.rmtree fails.
234 # 99.9% of the time it initially fails to remove
235 # a file in the directory, so the first time through
236 # func is os.remove.
237 # However, some Linux machines running ZFS on
238 # FUSE experienced a failure earlier in the process
239 # at os.listdir. The first failure may legally
240 # be either.
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200241 if self.errorState < 2:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200242 if func is os.unlink:
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200243 self.assertEqual(arg, self.child_file_path)
244 elif func is os.rmdir:
245 self.assertEqual(arg, self.child_dir_path)
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000246 else:
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200247 self.assertIs(func, os.listdir)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200248 self.assertIn(arg, [TESTFN, self.child_dir_path])
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000249 self.assertTrue(issubclass(exc[0], OSError))
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200250 self.errorState += 1
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000251 else:
252 self.assertEqual(func, os.rmdir)
253 self.assertEqual(arg, TESTFN)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000254 self.assertTrue(issubclass(exc[0], OSError))
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200255 self.errorState = 3
256
257 def test_rmtree_does_not_choke_on_failing_lstat(self):
258 try:
259 orig_lstat = os.lstat
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200260 def raiser(fn, *args, **kwargs):
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200261 if fn != TESTFN:
262 raise OSError()
263 else:
264 return orig_lstat(fn)
265 os.lstat = raiser
266
267 os.mkdir(TESTFN)
268 write_file((TESTFN, 'foo'), 'foo')
269 shutil.rmtree(TESTFN)
270 finally:
271 os.lstat = orig_lstat
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000272
Antoine Pitrou78091e62011-12-29 18:54:15 +0100273 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
274 @support.skip_unless_symlink
275 def test_copymode_follow_symlinks(self):
276 tmp_dir = self.mkdtemp()
277 src = os.path.join(tmp_dir, 'foo')
278 dst = os.path.join(tmp_dir, 'bar')
279 src_link = os.path.join(tmp_dir, 'baz')
280 dst_link = os.path.join(tmp_dir, 'quux')
281 write_file(src, 'foo')
282 write_file(dst, 'foo')
283 os.symlink(src, src_link)
284 os.symlink(dst, dst_link)
285 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
286 # file to file
287 os.chmod(dst, stat.S_IRWXO)
288 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
289 shutil.copymode(src, dst)
290 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
Antoine Pitrou3f48ac92014-01-01 02:50:45 +0100291 # On Windows, os.chmod does not follow symlinks (issue #15411)
292 if os.name != 'nt':
293 # follow src link
294 os.chmod(dst, stat.S_IRWXO)
295 shutil.copymode(src_link, dst)
296 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
297 # follow dst link
298 os.chmod(dst, stat.S_IRWXO)
299 shutil.copymode(src, dst_link)
300 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
301 # follow both links
302 os.chmod(dst, stat.S_IRWXO)
303 shutil.copymode(src_link, dst_link)
304 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100305
306 @unittest.skipUnless(hasattr(os, 'lchmod'), 'requires os.lchmod')
307 @support.skip_unless_symlink
308 def test_copymode_symlink_to_symlink(self):
309 tmp_dir = self.mkdtemp()
310 src = os.path.join(tmp_dir, 'foo')
311 dst = os.path.join(tmp_dir, 'bar')
312 src_link = os.path.join(tmp_dir, 'baz')
313 dst_link = os.path.join(tmp_dir, 'quux')
314 write_file(src, 'foo')
315 write_file(dst, 'foo')
316 os.symlink(src, src_link)
317 os.symlink(dst, dst_link)
318 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
319 os.chmod(dst, stat.S_IRWXU)
320 os.lchmod(src_link, stat.S_IRWXO|stat.S_IRWXG)
321 # link to link
322 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700323 shutil.copymode(src_link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100324 self.assertEqual(os.lstat(src_link).st_mode,
325 os.lstat(dst_link).st_mode)
326 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
327 # src link - use chmod
328 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700329 shutil.copymode(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100330 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
331 # dst link - use chmod
332 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700333 shutil.copymode(src, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100334 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
335
336 @unittest.skipIf(hasattr(os, 'lchmod'), 'requires os.lchmod to be missing')
337 @support.skip_unless_symlink
338 def test_copymode_symlink_to_symlink_wo_lchmod(self):
339 tmp_dir = self.mkdtemp()
340 src = os.path.join(tmp_dir, 'foo')
341 dst = os.path.join(tmp_dir, 'bar')
342 src_link = os.path.join(tmp_dir, 'baz')
343 dst_link = os.path.join(tmp_dir, 'quux')
344 write_file(src, 'foo')
345 write_file(dst, 'foo')
346 os.symlink(src, src_link)
347 os.symlink(dst, dst_link)
Larry Hastingsb4038062012-07-15 10:57:38 -0700348 shutil.copymode(src_link, dst_link, follow_symlinks=False) # silent fail
Antoine Pitrou78091e62011-12-29 18:54:15 +0100349
350 @support.skip_unless_symlink
351 def test_copystat_symlinks(self):
352 tmp_dir = self.mkdtemp()
353 src = os.path.join(tmp_dir, 'foo')
354 dst = os.path.join(tmp_dir, 'bar')
355 src_link = os.path.join(tmp_dir, 'baz')
356 dst_link = os.path.join(tmp_dir, 'qux')
357 write_file(src, 'foo')
358 src_stat = os.stat(src)
359 os.utime(src, (src_stat.st_atime,
360 src_stat.st_mtime - 42.0)) # ensure different mtimes
361 write_file(dst, 'bar')
362 self.assertNotEqual(os.stat(src).st_mtime, os.stat(dst).st_mtime)
363 os.symlink(src, src_link)
364 os.symlink(dst, dst_link)
365 if hasattr(os, 'lchmod'):
366 os.lchmod(src_link, stat.S_IRWXO)
367 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
368 os.lchflags(src_link, stat.UF_NODUMP)
369 src_link_stat = os.lstat(src_link)
370 # follow
371 if hasattr(os, 'lchmod'):
Larry Hastingsb4038062012-07-15 10:57:38 -0700372 shutil.copystat(src_link, dst_link, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100373 self.assertNotEqual(src_link_stat.st_mode, os.stat(dst).st_mode)
374 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700375 shutil.copystat(src_link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100376 dst_link_stat = os.lstat(dst_link)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700377 if os.utime in os.supports_follow_symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100378 for attr in 'st_atime', 'st_mtime':
379 # The modification times may be truncated in the new file.
380 self.assertLessEqual(getattr(src_link_stat, attr),
381 getattr(dst_link_stat, attr) + 1)
382 if hasattr(os, 'lchmod'):
383 self.assertEqual(src_link_stat.st_mode, dst_link_stat.st_mode)
384 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
385 self.assertEqual(src_link_stat.st_flags, dst_link_stat.st_flags)
386 # tell to follow but dst is not a link
Larry Hastingsb4038062012-07-15 10:57:38 -0700387 shutil.copystat(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100388 self.assertTrue(abs(os.stat(src).st_mtime - os.stat(dst).st_mtime) <
389 00000.1)
390
Ned Deilybaf75712012-05-10 17:05:19 -0700391 @unittest.skipUnless(hasattr(os, 'chflags') and
392 hasattr(errno, 'EOPNOTSUPP') and
393 hasattr(errno, 'ENOTSUP'),
394 "requires os.chflags, EOPNOTSUPP & ENOTSUP")
395 def test_copystat_handles_harmless_chflags_errors(self):
396 tmpdir = self.mkdtemp()
397 file1 = os.path.join(tmpdir, 'file1')
398 file2 = os.path.join(tmpdir, 'file2')
399 write_file(file1, 'xxx')
400 write_file(file2, 'xxx')
401
402 def make_chflags_raiser(err):
403 ex = OSError()
404
Larry Hastings90867a52012-06-22 17:01:41 -0700405 def _chflags_raiser(path, flags, *, follow_symlinks=True):
Ned Deilybaf75712012-05-10 17:05:19 -0700406 ex.errno = err
407 raise ex
408 return _chflags_raiser
409 old_chflags = os.chflags
410 try:
411 for err in errno.EOPNOTSUPP, errno.ENOTSUP:
412 os.chflags = make_chflags_raiser(err)
413 shutil.copystat(file1, file2)
414 # assert others errors break it
415 os.chflags = make_chflags_raiser(errno.EOPNOTSUPP + errno.ENOTSUP)
416 self.assertRaises(OSError, shutil.copystat, file1, file2)
417 finally:
418 os.chflags = old_chflags
419
Antoine Pitrou424246f2012-05-12 19:02:01 +0200420 @support.skip_unless_xattr
421 def test_copyxattr(self):
422 tmp_dir = self.mkdtemp()
423 src = os.path.join(tmp_dir, 'foo')
424 write_file(src, 'foo')
425 dst = os.path.join(tmp_dir, 'bar')
426 write_file(dst, 'bar')
427
428 # no xattr == no problem
429 shutil._copyxattr(src, dst)
430 # common case
431 os.setxattr(src, 'user.foo', b'42')
432 os.setxattr(src, 'user.bar', b'43')
433 shutil._copyxattr(src, dst)
Gregory P. Smith1093bf22014-01-17 12:01:22 -0800434 self.assertEqual(sorted(os.listxattr(src)), sorted(os.listxattr(dst)))
Antoine Pitrou424246f2012-05-12 19:02:01 +0200435 self.assertEqual(
436 os.getxattr(src, 'user.foo'),
437 os.getxattr(dst, 'user.foo'))
438 # check errors don't affect other attrs
439 os.remove(dst)
440 write_file(dst, 'bar')
441 os_error = OSError(errno.EPERM, 'EPERM')
442
Larry Hastings9cf065c2012-06-22 16:30:09 -0700443 def _raise_on_user_foo(fname, attr, val, **kwargs):
Antoine Pitrou424246f2012-05-12 19:02:01 +0200444 if attr == 'user.foo':
445 raise os_error
446 else:
Larry Hastings9cf065c2012-06-22 16:30:09 -0700447 orig_setxattr(fname, attr, val, **kwargs)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200448 try:
449 orig_setxattr = os.setxattr
450 os.setxattr = _raise_on_user_foo
451 shutil._copyxattr(src, dst)
Antoine Pitrou61597d32012-05-12 23:37:35 +0200452 self.assertIn('user.bar', os.listxattr(dst))
Antoine Pitrou424246f2012-05-12 19:02:01 +0200453 finally:
454 os.setxattr = orig_setxattr
Hynek Schlawack0beab052013-02-05 08:22:44 +0100455 # the source filesystem not supporting xattrs should be ok, too.
456 def _raise_on_src(fname, *, follow_symlinks=True):
457 if fname == src:
458 raise OSError(errno.ENOTSUP, 'Operation not supported')
459 return orig_listxattr(fname, follow_symlinks=follow_symlinks)
460 try:
461 orig_listxattr = os.listxattr
462 os.listxattr = _raise_on_src
463 shutil._copyxattr(src, dst)
464 finally:
465 os.listxattr = orig_listxattr
Antoine Pitrou424246f2012-05-12 19:02:01 +0200466
Larry Hastingsad5ae042012-07-14 17:55:11 -0700467 # test that shutil.copystat copies xattrs
468 src = os.path.join(tmp_dir, 'the_original')
469 write_file(src, src)
470 os.setxattr(src, 'user.the_value', b'fiddly')
471 dst = os.path.join(tmp_dir, 'the_copy')
472 write_file(dst, dst)
473 shutil.copystat(src, dst)
Hynek Schlawackc2d481f2012-07-16 17:11:10 +0200474 self.assertEqual(os.getxattr(dst, 'user.the_value'), b'fiddly')
Larry Hastingsad5ae042012-07-14 17:55:11 -0700475
Antoine Pitrou424246f2012-05-12 19:02:01 +0200476 @support.skip_unless_symlink
477 @support.skip_unless_xattr
478 @unittest.skipUnless(hasattr(os, 'geteuid') and os.geteuid() == 0,
479 'root privileges required')
480 def test_copyxattr_symlinks(self):
481 # On Linux, it's only possible to access non-user xattr for symlinks;
482 # which in turn require root privileges. This test should be expanded
483 # as soon as other platforms gain support for extended attributes.
484 tmp_dir = self.mkdtemp()
485 src = os.path.join(tmp_dir, 'foo')
486 src_link = os.path.join(tmp_dir, 'baz')
487 write_file(src, 'foo')
488 os.symlink(src, src_link)
489 os.setxattr(src, 'trusted.foo', b'42')
Larry Hastings9cf065c2012-06-22 16:30:09 -0700490 os.setxattr(src_link, 'trusted.foo', b'43', follow_symlinks=False)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200491 dst = os.path.join(tmp_dir, 'bar')
492 dst_link = os.path.join(tmp_dir, 'qux')
493 write_file(dst, 'bar')
494 os.symlink(dst, dst_link)
Larry Hastingsb4038062012-07-15 10:57:38 -0700495 shutil._copyxattr(src_link, dst_link, follow_symlinks=False)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700496 self.assertEqual(os.getxattr(dst_link, 'trusted.foo', follow_symlinks=False), b'43')
Antoine Pitrou424246f2012-05-12 19:02:01 +0200497 self.assertRaises(OSError, os.getxattr, dst, 'trusted.foo')
Larry Hastingsb4038062012-07-15 10:57:38 -0700498 shutil._copyxattr(src_link, dst, follow_symlinks=False)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200499 self.assertEqual(os.getxattr(dst, 'trusted.foo'), b'43')
500
Antoine Pitrou78091e62011-12-29 18:54:15 +0100501 @support.skip_unless_symlink
502 def test_copy_symlinks(self):
503 tmp_dir = self.mkdtemp()
504 src = os.path.join(tmp_dir, 'foo')
505 dst = os.path.join(tmp_dir, 'bar')
506 src_link = os.path.join(tmp_dir, 'baz')
507 write_file(src, 'foo')
508 os.symlink(src, src_link)
509 if hasattr(os, 'lchmod'):
510 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
511 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700512 shutil.copy(src_link, dst, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100513 self.assertFalse(os.path.islink(dst))
514 self.assertEqual(read_file(src), read_file(dst))
515 os.remove(dst)
516 # follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700517 shutil.copy(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100518 self.assertTrue(os.path.islink(dst))
519 self.assertEqual(os.readlink(dst), os.readlink(src_link))
520 if hasattr(os, 'lchmod'):
521 self.assertEqual(os.lstat(src_link).st_mode,
522 os.lstat(dst).st_mode)
523
524 @support.skip_unless_symlink
525 def test_copy2_symlinks(self):
526 tmp_dir = self.mkdtemp()
527 src = os.path.join(tmp_dir, 'foo')
528 dst = os.path.join(tmp_dir, 'bar')
529 src_link = os.path.join(tmp_dir, 'baz')
530 write_file(src, 'foo')
531 os.symlink(src, src_link)
532 if hasattr(os, 'lchmod'):
533 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
534 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
535 os.lchflags(src_link, stat.UF_NODUMP)
536 src_stat = os.stat(src)
537 src_link_stat = os.lstat(src_link)
538 # follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700539 shutil.copy2(src_link, dst, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100540 self.assertFalse(os.path.islink(dst))
541 self.assertEqual(read_file(src), read_file(dst))
542 os.remove(dst)
543 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700544 shutil.copy2(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100545 self.assertTrue(os.path.islink(dst))
546 self.assertEqual(os.readlink(dst), os.readlink(src_link))
547 dst_stat = os.lstat(dst)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700548 if os.utime in os.supports_follow_symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100549 for attr in 'st_atime', 'st_mtime':
550 # The modification times may be truncated in the new file.
551 self.assertLessEqual(getattr(src_link_stat, attr),
552 getattr(dst_stat, attr) + 1)
553 if hasattr(os, 'lchmod'):
554 self.assertEqual(src_link_stat.st_mode, dst_stat.st_mode)
555 self.assertNotEqual(src_stat.st_mode, dst_stat.st_mode)
556 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
557 self.assertEqual(src_link_stat.st_flags, dst_stat.st_flags)
558
Antoine Pitrou424246f2012-05-12 19:02:01 +0200559 @support.skip_unless_xattr
560 def test_copy2_xattr(self):
561 tmp_dir = self.mkdtemp()
562 src = os.path.join(tmp_dir, 'foo')
563 dst = os.path.join(tmp_dir, 'bar')
564 write_file(src, 'foo')
565 os.setxattr(src, 'user.foo', b'42')
566 shutil.copy2(src, dst)
567 self.assertEqual(
568 os.getxattr(src, 'user.foo'),
569 os.getxattr(dst, 'user.foo'))
570 os.remove(dst)
571
Antoine Pitrou78091e62011-12-29 18:54:15 +0100572 @support.skip_unless_symlink
573 def test_copyfile_symlinks(self):
574 tmp_dir = self.mkdtemp()
575 src = os.path.join(tmp_dir, 'src')
576 dst = os.path.join(tmp_dir, 'dst')
577 dst_link = os.path.join(tmp_dir, 'dst_link')
578 link = os.path.join(tmp_dir, 'link')
579 write_file(src, 'foo')
580 os.symlink(src, link)
581 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700582 shutil.copyfile(link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100583 self.assertTrue(os.path.islink(dst_link))
584 self.assertEqual(os.readlink(link), os.readlink(dst_link))
585 # follow
586 shutil.copyfile(link, dst)
587 self.assertFalse(os.path.islink(dst))
588
Hynek Schlawack2100b422012-06-23 20:28:32 +0200589 def test_rmtree_uses_safe_fd_version_if_available(self):
Hynek Schlawackd0f6e0a2012-06-29 08:28:20 +0200590 _use_fd_functions = ({os.open, os.stat, os.unlink, os.rmdir} <=
591 os.supports_dir_fd and
592 os.listdir in os.supports_fd and
593 os.stat in os.supports_follow_symlinks)
594 if _use_fd_functions:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200595 self.assertTrue(shutil._use_fd_functions)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000596 self.assertTrue(shutil.rmtree.avoids_symlink_attacks)
Hynek Schlawack2100b422012-06-23 20:28:32 +0200597 tmp_dir = self.mkdtemp()
598 d = os.path.join(tmp_dir, 'a')
599 os.mkdir(d)
600 try:
601 real_rmtree = shutil._rmtree_safe_fd
602 class Called(Exception): pass
603 def _raiser(*args, **kwargs):
604 raise Called
605 shutil._rmtree_safe_fd = _raiser
606 self.assertRaises(Called, shutil.rmtree, d)
607 finally:
608 shutil._rmtree_safe_fd = real_rmtree
609 else:
610 self.assertFalse(shutil._use_fd_functions)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000611 self.assertFalse(shutil.rmtree.avoids_symlink_attacks)
Hynek Schlawack2100b422012-06-23 20:28:32 +0200612
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000613 def test_rmtree_dont_delete_file(self):
614 # When called on a file instead of a directory, don't delete it.
615 handle, path = tempfile.mkstemp()
Victor Stinnerbf816222011-06-30 23:25:47 +0200616 os.close(handle)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200617 self.assertRaises(NotADirectoryError, shutil.rmtree, path)
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000618 os.remove(path)
619
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000620 def test_copytree_simple(self):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000621 src_dir = tempfile.mkdtemp()
622 dst_dir = os.path.join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200623 self.addCleanup(shutil.rmtree, src_dir)
624 self.addCleanup(shutil.rmtree, os.path.dirname(dst_dir))
625 write_file((src_dir, 'test.txt'), '123')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000626 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200627 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000628
Éric Araujoa7e33a12011-08-12 19:51:35 +0200629 shutil.copytree(src_dir, dst_dir)
630 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test.txt')))
631 self.assertTrue(os.path.isdir(os.path.join(dst_dir, 'test_dir')))
632 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test_dir',
633 'test.txt')))
634 actual = read_file((dst_dir, 'test.txt'))
635 self.assertEqual(actual, '123')
636 actual = read_file((dst_dir, 'test_dir', 'test.txt'))
637 self.assertEqual(actual, '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000638
Antoine Pitrou78091e62011-12-29 18:54:15 +0100639 @support.skip_unless_symlink
640 def test_copytree_symlinks(self):
641 tmp_dir = self.mkdtemp()
642 src_dir = os.path.join(tmp_dir, 'src')
643 dst_dir = os.path.join(tmp_dir, 'dst')
644 sub_dir = os.path.join(src_dir, 'sub')
645 os.mkdir(src_dir)
646 os.mkdir(sub_dir)
647 write_file((src_dir, 'file.txt'), 'foo')
648 src_link = os.path.join(sub_dir, 'link')
649 dst_link = os.path.join(dst_dir, 'sub/link')
650 os.symlink(os.path.join(src_dir, 'file.txt'),
651 src_link)
652 if hasattr(os, 'lchmod'):
653 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
654 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
655 os.lchflags(src_link, stat.UF_NODUMP)
656 src_stat = os.lstat(src_link)
657 shutil.copytree(src_dir, dst_dir, symlinks=True)
658 self.assertTrue(os.path.islink(os.path.join(dst_dir, 'sub', 'link')))
659 self.assertEqual(os.readlink(os.path.join(dst_dir, 'sub', 'link')),
660 os.path.join(src_dir, 'file.txt'))
661 dst_stat = os.lstat(dst_link)
662 if hasattr(os, 'lchmod'):
663 self.assertEqual(dst_stat.st_mode, src_stat.st_mode)
664 if hasattr(os, 'lchflags'):
665 self.assertEqual(dst_stat.st_flags, src_stat.st_flags)
666
Georg Brandl2ee470f2008-07-16 12:55:28 +0000667 def test_copytree_with_exclude(self):
Georg Brandl2ee470f2008-07-16 12:55:28 +0000668 # creating data
669 join = os.path.join
670 exists = os.path.exists
671 src_dir = tempfile.mkdtemp()
Georg Brandl2ee470f2008-07-16 12:55:28 +0000672 try:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000673 dst_dir = join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200674 write_file((src_dir, 'test.txt'), '123')
675 write_file((src_dir, 'test.tmp'), '123')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000676 os.mkdir(join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200677 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000678 os.mkdir(join(src_dir, 'test_dir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200679 write_file((src_dir, 'test_dir2', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000680 os.mkdir(join(src_dir, 'test_dir2', 'subdir'))
681 os.mkdir(join(src_dir, 'test_dir2', 'subdir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200682 write_file((src_dir, 'test_dir2', 'subdir', 'test.txt'), '456')
683 write_file((src_dir, 'test_dir2', 'subdir2', 'test.py'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000684
685 # testing glob-like patterns
686 try:
687 patterns = shutil.ignore_patterns('*.tmp', 'test_dir2')
688 shutil.copytree(src_dir, dst_dir, ignore=patterns)
689 # checking the result: some elements should not be copied
690 self.assertTrue(exists(join(dst_dir, 'test.txt')))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200691 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
692 self.assertFalse(exists(join(dst_dir, 'test_dir2')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000693 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200694 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000695 try:
696 patterns = shutil.ignore_patterns('*.tmp', 'subdir*')
697 shutil.copytree(src_dir, dst_dir, ignore=patterns)
698 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200699 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
700 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2')))
701 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000702 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200703 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000704
705 # testing callable-style
706 try:
707 def _filter(src, names):
708 res = []
709 for name in names:
710 path = os.path.join(src, name)
711
712 if (os.path.isdir(path) and
713 path.split()[-1] == 'subdir'):
714 res.append(name)
715 elif os.path.splitext(path)[-1] in ('.py'):
716 res.append(name)
717 return res
718
719 shutil.copytree(src_dir, dst_dir, ignore=_filter)
720
721 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200722 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2',
723 'test.py')))
724 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000725
726 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200727 shutil.rmtree(dst_dir)
Georg Brandl2ee470f2008-07-16 12:55:28 +0000728 finally:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000729 shutil.rmtree(src_dir)
730 shutil.rmtree(os.path.dirname(dst_dir))
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000731
Antoine Pitrouac601602013-08-16 19:35:02 +0200732 def test_copytree_retains_permissions(self):
733 tmp_dir = tempfile.mkdtemp()
734 src_dir = os.path.join(tmp_dir, 'source')
735 os.mkdir(src_dir)
736 dst_dir = os.path.join(tmp_dir, 'destination')
737 self.addCleanup(shutil.rmtree, tmp_dir)
738
739 os.chmod(src_dir, 0o777)
740 write_file((src_dir, 'permissive.txt'), '123')
741 os.chmod(os.path.join(src_dir, 'permissive.txt'), 0o777)
742 write_file((src_dir, 'restrictive.txt'), '456')
743 os.chmod(os.path.join(src_dir, 'restrictive.txt'), 0o600)
744 restrictive_subdir = tempfile.mkdtemp(dir=src_dir)
745 os.chmod(restrictive_subdir, 0o600)
746
747 shutil.copytree(src_dir, dst_dir)
Brett Cannon9c7eb552013-08-23 14:38:11 -0400748 self.assertEqual(os.stat(src_dir).st_mode, os.stat(dst_dir).st_mode)
749 self.assertEqual(os.stat(os.path.join(src_dir, 'permissive.txt')).st_mode,
Antoine Pitrouac601602013-08-16 19:35:02 +0200750 os.stat(os.path.join(dst_dir, 'permissive.txt')).st_mode)
Brett Cannon9c7eb552013-08-23 14:38:11 -0400751 self.assertEqual(os.stat(os.path.join(src_dir, 'restrictive.txt')).st_mode,
Antoine Pitrouac601602013-08-16 19:35:02 +0200752 os.stat(os.path.join(dst_dir, 'restrictive.txt')).st_mode)
753 restrictive_subdir_dst = os.path.join(dst_dir,
754 os.path.split(restrictive_subdir)[1])
Brett Cannon9c7eb552013-08-23 14:38:11 -0400755 self.assertEqual(os.stat(restrictive_subdir).st_mode,
Antoine Pitrouac601602013-08-16 19:35:02 +0200756 os.stat(restrictive_subdir_dst).st_mode)
757
Berker Peksag884afd92014-12-10 02:50:32 +0200758 @unittest.mock.patch('os.chmod')
759 def test_copytree_winerror(self, mock_patch):
760 # When copying to VFAT, copystat() raises OSError. On Windows, the
761 # exception object has a meaningful 'winerror' attribute, but not
762 # on other operating systems. Do not assume 'winerror' is set.
763 src_dir = tempfile.mkdtemp()
764 dst_dir = os.path.join(tempfile.mkdtemp(), 'destination')
765 self.addCleanup(shutil.rmtree, src_dir)
766 self.addCleanup(shutil.rmtree, os.path.dirname(dst_dir))
767
768 mock_patch.side_effect = PermissionError('ka-boom')
769 with self.assertRaises(shutil.Error):
770 shutil.copytree(src_dir, dst_dir)
771
Zachary Ware9fe6d862013-12-08 00:20:35 -0600772 @unittest.skipIf(os.name == 'nt', 'temporarily disabled on Windows')
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000773 @unittest.skipUnless(hasattr(os, 'link'), 'requires os.link')
Xavier de Gaye3a4e9892016-12-13 10:00:01 +0100774 @unittest.skipIf(android_not_root, "hard links not allowed, non root user")
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000775 def test_dont_copy_file_onto_link_to_itself(self):
776 # bug 851123.
777 os.mkdir(TESTFN)
778 src = os.path.join(TESTFN, 'cheese')
779 dst = os.path.join(TESTFN, 'shop')
780 try:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000781 with open(src, 'w') as f:
782 f.write('cheddar')
783 os.link(src, dst)
Hynek Schlawack48653762012-10-07 12:49:58 +0200784 self.assertRaises(shutil.SameFileError, shutil.copyfile, src, dst)
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000785 with open(src, 'r') as f:
786 self.assertEqual(f.read(), 'cheddar')
787 os.remove(dst)
788 finally:
789 shutil.rmtree(TESTFN, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000790
Brian Curtin3b4499c2010-12-28 14:31:47 +0000791 @support.skip_unless_symlink
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000792 def test_dont_copy_file_onto_symlink_to_itself(self):
793 # bug 851123.
794 os.mkdir(TESTFN)
795 src = os.path.join(TESTFN, 'cheese')
796 dst = os.path.join(TESTFN, 'shop')
797 try:
798 with open(src, 'w') as f:
799 f.write('cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000800 # Using `src` here would mean we end up with a symlink pointing
801 # to TESTFN/TESTFN/cheese, while it should point at
802 # TESTFN/cheese.
803 os.symlink('cheese', dst)
Hynek Schlawack48653762012-10-07 12:49:58 +0200804 self.assertRaises(shutil.SameFileError, shutil.copyfile, src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +0000805 with open(src, 'r') as f:
806 self.assertEqual(f.read(), 'cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000807 os.remove(dst)
808 finally:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000809 shutil.rmtree(TESTFN, ignore_errors=True)
Johannes Gijsbers68128712004-08-14 13:57:08 +0000810
Brian Curtin3b4499c2010-12-28 14:31:47 +0000811 @support.skip_unless_symlink
Brian Curtind40e6f72010-07-08 21:39:08 +0000812 def test_rmtree_on_symlink(self):
813 # bug 1669.
814 os.mkdir(TESTFN)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000815 try:
Brian Curtind40e6f72010-07-08 21:39:08 +0000816 src = os.path.join(TESTFN, 'cheese')
817 dst = os.path.join(TESTFN, 'shop')
818 os.mkdir(src)
819 os.symlink(src, dst)
820 self.assertRaises(OSError, shutil.rmtree, dst)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200821 shutil.rmtree(dst, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000822 finally:
Brian Curtind40e6f72010-07-08 21:39:08 +0000823 shutil.rmtree(TESTFN, ignore_errors=True)
824
Serhiy Storchaka43767632013-11-03 21:31:38 +0200825 # Issue #3002: copyfile and copytree block indefinitely on named pipes
826 @unittest.skipUnless(hasattr(os, "mkfifo"), 'requires os.mkfifo()')
Xavier de Gaye3a4e9892016-12-13 10:00:01 +0100827 @unittest.skipIf(android_not_root, "mkfifo not allowed, non root user")
Serhiy Storchaka43767632013-11-03 21:31:38 +0200828 def test_copyfile_named_pipe(self):
829 os.mkfifo(TESTFN)
830 try:
831 self.assertRaises(shutil.SpecialFileError,
832 shutil.copyfile, TESTFN, TESTFN2)
833 self.assertRaises(shutil.SpecialFileError,
834 shutil.copyfile, __file__, TESTFN)
835 finally:
836 os.remove(TESTFN)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000837
Xavier de Gaye3a4e9892016-12-13 10:00:01 +0100838 @unittest.skipIf(android_not_root, "mkfifo not allowed, non root user")
Serhiy Storchaka43767632013-11-03 21:31:38 +0200839 @unittest.skipUnless(hasattr(os, "mkfifo"), 'requires os.mkfifo()')
840 @support.skip_unless_symlink
841 def test_copytree_named_pipe(self):
842 os.mkdir(TESTFN)
843 try:
844 subdir = os.path.join(TESTFN, "subdir")
845 os.mkdir(subdir)
846 pipe = os.path.join(subdir, "mypipe")
847 os.mkfifo(pipe)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000848 try:
Serhiy Storchaka43767632013-11-03 21:31:38 +0200849 shutil.copytree(TESTFN, TESTFN2)
850 except shutil.Error as e:
851 errors = e.args[0]
852 self.assertEqual(len(errors), 1)
853 src, dst, error_msg = errors[0]
854 self.assertEqual("`%s` is a named pipe" % pipe, error_msg)
855 else:
856 self.fail("shutil.Error should have been raised")
857 finally:
858 shutil.rmtree(TESTFN, ignore_errors=True)
859 shutil.rmtree(TESTFN2, ignore_errors=True)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000860
Tarek Ziadé5340db32010-04-19 22:30:51 +0000861 def test_copytree_special_func(self):
862
863 src_dir = self.mkdtemp()
864 dst_dir = os.path.join(self.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200865 write_file((src_dir, 'test.txt'), '123')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000866 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200867 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000868
869 copied = []
870 def _copy(src, dst):
871 copied.append((src, dst))
872
873 shutil.copytree(src_dir, dst_dir, copy_function=_copy)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000874 self.assertEqual(len(copied), 2)
Tarek Ziadé5340db32010-04-19 22:30:51 +0000875
Brian Curtin3b4499c2010-12-28 14:31:47 +0000876 @support.skip_unless_symlink
Tarek Ziadéfb437512010-04-20 08:57:33 +0000877 def test_copytree_dangling_symlinks(self):
878
879 # a dangling symlink raises an error at the end
880 src_dir = self.mkdtemp()
881 dst_dir = os.path.join(self.mkdtemp(), 'destination')
882 os.symlink('IDONTEXIST', os.path.join(src_dir, 'test.txt'))
883 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200884 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadéfb437512010-04-20 08:57:33 +0000885 self.assertRaises(Error, shutil.copytree, src_dir, dst_dir)
886
887 # a dangling symlink is ignored with the proper flag
888 dst_dir = os.path.join(self.mkdtemp(), 'destination2')
889 shutil.copytree(src_dir, dst_dir, ignore_dangling_symlinks=True)
890 self.assertNotIn('test.txt', os.listdir(dst_dir))
891
892 # a dangling symlink is copied if symlinks=True
893 dst_dir = os.path.join(self.mkdtemp(), 'destination3')
894 shutil.copytree(src_dir, dst_dir, symlinks=True)
895 self.assertIn('test.txt', os.listdir(dst_dir))
896
Berker Peksag5a294d82015-07-25 14:53:48 +0300897 @support.skip_unless_symlink
898 def test_copytree_symlink_dir(self):
899 src_dir = self.mkdtemp()
900 dst_dir = os.path.join(self.mkdtemp(), 'destination')
901 os.mkdir(os.path.join(src_dir, 'real_dir'))
902 with open(os.path.join(src_dir, 'real_dir', 'test.txt'), 'w'):
903 pass
904 os.symlink(os.path.join(src_dir, 'real_dir'),
905 os.path.join(src_dir, 'link_to_dir'),
906 target_is_directory=True)
907
908 shutil.copytree(src_dir, dst_dir, symlinks=False)
909 self.assertFalse(os.path.islink(os.path.join(dst_dir, 'link_to_dir')))
910 self.assertIn('test.txt', os.listdir(os.path.join(dst_dir, 'link_to_dir')))
911
912 dst_dir = os.path.join(self.mkdtemp(), 'destination2')
913 shutil.copytree(src_dir, dst_dir, symlinks=True)
914 self.assertTrue(os.path.islink(os.path.join(dst_dir, 'link_to_dir')))
915 self.assertIn('test.txt', os.listdir(os.path.join(dst_dir, 'link_to_dir')))
916
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400917 def _copy_file(self, method):
918 fname = 'test.txt'
919 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200920 write_file((tmpdir, fname), 'xxx')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400921 file1 = os.path.join(tmpdir, fname)
922 tmpdir2 = self.mkdtemp()
923 method(file1, tmpdir2)
924 file2 = os.path.join(tmpdir2, fname)
925 return (file1, file2)
926
927 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
928 def test_copy(self):
929 # Ensure that the copied file exists and has the same mode bits.
930 file1, file2 = self._copy_file(shutil.copy)
931 self.assertTrue(os.path.exists(file2))
932 self.assertEqual(os.stat(file1).st_mode, os.stat(file2).st_mode)
933
934 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
Senthil Kumaran0c2dba52011-07-03 18:21:38 -0700935 @unittest.skipUnless(hasattr(os, 'utime'), 'requires os.utime')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400936 def test_copy2(self):
937 # Ensure that the copied file exists and has the same mode and
938 # modification time bits.
939 file1, file2 = self._copy_file(shutil.copy2)
940 self.assertTrue(os.path.exists(file2))
941 file1_stat = os.stat(file1)
942 file2_stat = os.stat(file2)
943 self.assertEqual(file1_stat.st_mode, file2_stat.st_mode)
944 for attr in 'st_atime', 'st_mtime':
945 # The modification times may be truncated in the new file.
946 self.assertLessEqual(getattr(file1_stat, attr),
947 getattr(file2_stat, attr) + 1)
948 if hasattr(os, 'chflags') and hasattr(file1_stat, 'st_flags'):
949 self.assertEqual(getattr(file1_stat, 'st_flags'),
950 getattr(file2_stat, 'st_flags'))
951
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +0200952 @support.requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000953 def test_make_tarball(self):
954 # creating something to tar
Serhiy Storchaka527ef072015-09-06 18:33:19 +0300955 root_dir, base_dir = self._create_files('')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000956
957 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400958 # force shutil to create the directory
959 os.rmdir(tmpdir2)
Serhiy Storchakaeba8fee2015-09-07 19:58:23 +0300960 # working with relative paths
961 work_dir = os.path.dirname(tmpdir2)
962 rel_base_name = os.path.join(os.path.basename(tmpdir2), 'archive')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000963
Serhiy Storchakaeba8fee2015-09-07 19:58:23 +0300964 with support.change_cwd(work_dir):
Serhiy Storchaka5558d4f2015-09-08 09:59:02 +0300965 base_name = os.path.abspath(rel_base_name)
Serhiy Storchakaeba8fee2015-09-07 19:58:23 +0300966 tarball = make_archive(rel_base_name, 'gztar', root_dir, '.')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000967
968 # check if the compressed tarball was created
Serhiy Storchakaa091a822015-09-07 13:55:25 +0300969 self.assertEqual(tarball, base_name + '.tar.gz')
Serhiy Storchaka527ef072015-09-06 18:33:19 +0300970 self.assertTrue(os.path.isfile(tarball))
971 self.assertTrue(tarfile.is_tarfile(tarball))
972 with tarfile.open(tarball, 'r:gz') as tf:
973 self.assertCountEqual(tf.getnames(),
974 ['.', './sub', './sub2',
975 './file1', './file2', './sub/file3'])
Tarek Ziadé396fad72010-02-23 05:30:31 +0000976
977 # trying an uncompressed one
Serhiy Storchakaeba8fee2015-09-07 19:58:23 +0300978 with support.change_cwd(work_dir):
979 tarball = make_archive(rel_base_name, 'tar', root_dir, '.')
Serhiy Storchakaa091a822015-09-07 13:55:25 +0300980 self.assertEqual(tarball, base_name + '.tar')
Serhiy Storchaka527ef072015-09-06 18:33:19 +0300981 self.assertTrue(os.path.isfile(tarball))
982 self.assertTrue(tarfile.is_tarfile(tarball))
983 with tarfile.open(tarball, 'r') as tf:
984 self.assertCountEqual(tf.getnames(),
985 ['.', './sub', './sub2',
986 './file1', './file2', './sub/file3'])
Tarek Ziadé396fad72010-02-23 05:30:31 +0000987
988 def _tarinfo(self, path):
Serhiy Storchaka527ef072015-09-06 18:33:19 +0300989 with tarfile.open(path) as tar:
Tarek Ziadé396fad72010-02-23 05:30:31 +0000990 names = tar.getnames()
991 names.sort()
992 return tuple(names)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000993
Serhiy Storchaka527ef072015-09-06 18:33:19 +0300994 def _create_files(self, base_dir='dist'):
Tarek Ziadé396fad72010-02-23 05:30:31 +0000995 # creating something to tar
Serhiy Storchaka527ef072015-09-06 18:33:19 +0300996 root_dir = self.mkdtemp()
997 dist = os.path.join(root_dir, base_dir)
998 os.makedirs(dist, exist_ok=True)
Éric Araujoa7e33a12011-08-12 19:51:35 +0200999 write_file((dist, 'file1'), 'xxx')
1000 write_file((dist, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +00001001 os.mkdir(os.path.join(dist, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +02001002 write_file((dist, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +00001003 os.mkdir(os.path.join(dist, 'sub2'))
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001004 if base_dir:
1005 write_file((root_dir, 'outer'), 'xxx')
1006 return root_dir, base_dir
Tarek Ziadé396fad72010-02-23 05:30:31 +00001007
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001008 @support.requires_zlib
Serhiy Storchakab42de2f2015-11-21 14:09:26 +02001009 @unittest.skipUnless(shutil.which('tar'),
Tarek Ziadé396fad72010-02-23 05:30:31 +00001010 'Need the tar command to run')
1011 def test_tarfile_vs_tar(self):
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001012 root_dir, base_dir = self._create_files()
1013 base_name = os.path.join(self.mkdtemp(), 'archive')
Serhiy Storchakaa091a822015-09-07 13:55:25 +03001014 tarball = make_archive(base_name, 'gztar', root_dir, base_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001015
1016 # check if the compressed tarball was created
Serhiy Storchakaa091a822015-09-07 13:55:25 +03001017 self.assertEqual(tarball, base_name + '.tar.gz')
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001018 self.assertTrue(os.path.isfile(tarball))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001019
1020 # now create another tarball using `tar`
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001021 tarball2 = os.path.join(root_dir, 'archive2.tar')
1022 tar_cmd = ['tar', '-cf', 'archive2.tar', base_dir]
Serhiy Storchakab42de2f2015-11-21 14:09:26 +02001023 subprocess.check_call(tar_cmd, cwd=root_dir,
1024 stdout=subprocess.DEVNULL)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001025
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001026 self.assertTrue(os.path.isfile(tarball2))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001027 # let's compare both tarballs
Ezio Melottib3aedd42010-11-20 19:04:17 +00001028 self.assertEqual(self._tarinfo(tarball), self._tarinfo(tarball2))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001029
1030 # trying an uncompressed one
Serhiy Storchakaa091a822015-09-07 13:55:25 +03001031 tarball = make_archive(base_name, 'tar', root_dir, base_dir)
1032 self.assertEqual(tarball, base_name + '.tar')
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001033 self.assertTrue(os.path.isfile(tarball))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001034
1035 # now for a dry_run
Serhiy Storchakaa091a822015-09-07 13:55:25 +03001036 tarball = make_archive(base_name, 'tar', root_dir, base_dir,
1037 dry_run=True)
1038 self.assertEqual(tarball, base_name + '.tar')
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001039 self.assertTrue(os.path.isfile(tarball))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001040
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001041 @support.requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001042 def test_make_zipfile(self):
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001043 # creating something to zip
1044 root_dir, base_dir = self._create_files()
Serhiy Storchakaeba8fee2015-09-07 19:58:23 +03001045
1046 tmpdir2 = self.mkdtemp()
1047 # force shutil to create the directory
1048 os.rmdir(tmpdir2)
1049 # working with relative paths
1050 work_dir = os.path.dirname(tmpdir2)
1051 rel_base_name = os.path.join(os.path.basename(tmpdir2), 'archive')
Serhiy Storchakaeba8fee2015-09-07 19:58:23 +03001052
1053 with support.change_cwd(work_dir):
Serhiy Storchaka5558d4f2015-09-08 09:59:02 +03001054 base_name = os.path.abspath(rel_base_name)
Serhiy Storchaka666de772016-10-23 15:55:09 +03001055 res = make_archive(rel_base_name, 'zip', root_dir)
1056
1057 self.assertEqual(res, base_name + '.zip')
1058 self.assertTrue(os.path.isfile(res))
1059 self.assertTrue(zipfile.is_zipfile(res))
1060 with zipfile.ZipFile(res) as zf:
1061 self.assertCountEqual(zf.namelist(),
1062 ['dist/', 'dist/sub/', 'dist/sub2/',
1063 'dist/file1', 'dist/file2', 'dist/sub/file3',
1064 'outer'])
1065
1066 with support.change_cwd(work_dir):
1067 base_name = os.path.abspath(rel_base_name)
Serhiy Storchaka2504cec2015-09-08 05:47:23 +03001068 res = make_archive(rel_base_name, 'zip', root_dir, base_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001069
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001070 self.assertEqual(res, base_name + '.zip')
1071 self.assertTrue(os.path.isfile(res))
1072 self.assertTrue(zipfile.is_zipfile(res))
1073 with zipfile.ZipFile(res) as zf:
1074 self.assertCountEqual(zf.namelist(),
Serhiy Storchaka2504cec2015-09-08 05:47:23 +03001075 ['dist/', 'dist/sub/', 'dist/sub2/',
1076 'dist/file1', 'dist/file2', 'dist/sub/file3'])
Tarek Ziadé396fad72010-02-23 05:30:31 +00001077
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001078 @support.requires_zlib
Serhiy Storchakab42de2f2015-11-21 14:09:26 +02001079 @unittest.skipUnless(shutil.which('zip'),
Serhiy Storchaka2504cec2015-09-08 05:47:23 +03001080 'Need the zip command to run')
1081 def test_zipfile_vs_zip(self):
1082 root_dir, base_dir = self._create_files()
1083 base_name = os.path.join(self.mkdtemp(), 'archive')
1084 archive = make_archive(base_name, 'zip', root_dir, base_dir)
1085
1086 # check if ZIP file was created
1087 self.assertEqual(archive, base_name + '.zip')
1088 self.assertTrue(os.path.isfile(archive))
1089
1090 # now create another ZIP file using `zip`
1091 archive2 = os.path.join(root_dir, 'archive2.zip')
1092 zip_cmd = ['zip', '-q', '-r', 'archive2.zip', base_dir]
Serhiy Storchakab42de2f2015-11-21 14:09:26 +02001093 subprocess.check_call(zip_cmd, cwd=root_dir,
1094 stdout=subprocess.DEVNULL)
Serhiy Storchaka2504cec2015-09-08 05:47:23 +03001095
1096 self.assertTrue(os.path.isfile(archive2))
1097 # let's compare both ZIP files
1098 with zipfile.ZipFile(archive) as zf:
1099 names = zf.namelist()
1100 with zipfile.ZipFile(archive2) as zf:
1101 names2 = zf.namelist()
1102 self.assertEqual(sorted(names), sorted(names2))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001103
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001104 @support.requires_zlib
Serhiy Storchaka8bc792a2015-11-22 14:49:58 +02001105 @unittest.skipUnless(shutil.which('unzip'),
1106 'Need the unzip command to run')
1107 def test_unzip_zipfile(self):
1108 root_dir, base_dir = self._create_files()
1109 base_name = os.path.join(self.mkdtemp(), 'archive')
1110 archive = make_archive(base_name, 'zip', root_dir, base_dir)
1111
1112 # check if ZIP file was created
1113 self.assertEqual(archive, base_name + '.zip')
1114 self.assertTrue(os.path.isfile(archive))
1115
1116 # now check the ZIP file using `unzip -t`
1117 zip_cmd = ['unzip', '-t', archive]
1118 with support.change_cwd(root_dir):
1119 try:
1120 subprocess.check_output(zip_cmd, stderr=subprocess.STDOUT)
1121 except subprocess.CalledProcessError as exc:
1122 details = exc.output.decode(errors="replace")
1123 msg = "{}\n\n**Unzip Output**\n{}"
1124 self.fail(msg.format(exc, details))
1125
Tarek Ziadé396fad72010-02-23 05:30:31 +00001126 def test_make_archive(self):
1127 tmpdir = self.mkdtemp()
1128 base_name = os.path.join(tmpdir, 'archive')
1129 self.assertRaises(ValueError, make_archive, base_name, 'xxx')
1130
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001131 @support.requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001132 def test_make_archive_owner_group(self):
1133 # testing make_archive with owner and group, with various combinations
1134 # this works even if there's not gid/uid support
1135 if UID_GID_SUPPORT:
1136 group = grp.getgrgid(0)[0]
1137 owner = pwd.getpwuid(0)[0]
1138 else:
1139 group = owner = 'root'
1140
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001141 root_dir, base_dir = self._create_files()
1142 base_name = os.path.join(self.mkdtemp(), 'archive')
Tarek Ziadé396fad72010-02-23 05:30:31 +00001143 res = make_archive(base_name, 'zip', root_dir, base_dir, owner=owner,
1144 group=group)
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001145 self.assertTrue(os.path.isfile(res))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001146
1147 res = make_archive(base_name, 'zip', root_dir, base_dir)
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, 'tar', root_dir, base_dir,
1151 owner=owner, group=group)
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001152 self.assertTrue(os.path.isfile(res))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001153
1154 res = make_archive(base_name, 'tar', root_dir, base_dir,
1155 owner='kjhkjhkjg', group='oihohoh')
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001156 self.assertTrue(os.path.isfile(res))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001157
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001158
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001159 @support.requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001160 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1161 def test_tarfile_root_owner(self):
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001162 root_dir, base_dir = self._create_files()
1163 base_name = os.path.join(self.mkdtemp(), 'archive')
Tarek Ziadé396fad72010-02-23 05:30:31 +00001164 group = grp.getgrgid(0)[0]
1165 owner = pwd.getpwuid(0)[0]
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001166 with support.change_cwd(root_dir):
1167 archive_name = make_archive(base_name, 'gztar', root_dir, 'dist',
1168 owner=owner, group=group)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001169
1170 # check if the compressed tarball was created
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001171 self.assertTrue(os.path.isfile(archive_name))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001172
1173 # now checks the rights
1174 archive = tarfile.open(archive_name)
1175 try:
1176 for member in archive.getmembers():
Ezio Melottib3aedd42010-11-20 19:04:17 +00001177 self.assertEqual(member.uid, 0)
1178 self.assertEqual(member.gid, 0)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001179 finally:
1180 archive.close()
1181
1182 def test_make_archive_cwd(self):
1183 current_dir = os.getcwd()
1184 def _breaks(*args, **kw):
1185 raise RuntimeError()
1186
1187 register_archive_format('xxx', _breaks, [], 'xxx file')
1188 try:
1189 try:
1190 make_archive('xxx', 'xxx', root_dir=self.mkdtemp())
1191 except Exception:
1192 pass
Ezio Melottib3aedd42010-11-20 19:04:17 +00001193 self.assertEqual(os.getcwd(), current_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001194 finally:
1195 unregister_archive_format('xxx')
1196
Serhiy Storchaka9a4fc192014-11-28 00:48:46 +02001197 def test_make_tarfile_in_curdir(self):
1198 # Issue #21280
1199 root_dir = self.mkdtemp()
1200 with support.change_cwd(root_dir):
1201 self.assertEqual(make_archive('test', 'tar'), 'test.tar')
1202 self.assertTrue(os.path.isfile('test.tar'))
1203
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001204 @support.requires_zlib
Serhiy Storchaka9a4fc192014-11-28 00:48:46 +02001205 def test_make_zipfile_in_curdir(self):
1206 # Issue #21280
1207 root_dir = self.mkdtemp()
1208 with support.change_cwd(root_dir):
1209 self.assertEqual(make_archive('test', 'zip'), 'test.zip')
1210 self.assertTrue(os.path.isfile('test.zip'))
1211
Tarek Ziadé396fad72010-02-23 05:30:31 +00001212 def test_register_archive_format(self):
1213
1214 self.assertRaises(TypeError, register_archive_format, 'xxx', 1)
1215 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1216 1)
1217 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1218 [(1, 2), (1, 2, 3)])
1219
1220 register_archive_format('xxx', lambda: x, [(1, 2)], 'xxx file')
1221 formats = [name for name, params in get_archive_formats()]
1222 self.assertIn('xxx', formats)
1223
1224 unregister_archive_format('xxx')
1225 formats = [name for name, params in get_archive_formats()]
1226 self.assertNotIn('xxx', formats)
1227
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001228 def check_unpack_archive(self, format):
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001229 root_dir, base_dir = self._create_files()
Serhiy Storchaka2504cec2015-09-08 05:47:23 +03001230 expected = rlistdir(root_dir)
1231 expected.remove('outer')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001232
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001233 base_name = os.path.join(self.mkdtemp(), 'archive')
1234 filename = make_archive(base_name, format, root_dir, base_dir)
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001235
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001236 # let's try to unpack it now
1237 tmpdir2 = self.mkdtemp()
1238 unpack_archive(filename, tmpdir2)
1239 self.assertEqual(rlistdir(tmpdir2), expected)
1240
1241 # and again, this time with the format specified
1242 tmpdir3 = self.mkdtemp()
1243 unpack_archive(filename, tmpdir3, format=format)
1244 self.assertEqual(rlistdir(tmpdir3), expected)
1245
Nick Coghlanabf202d2011-03-16 13:52:20 -04001246 self.assertRaises(shutil.ReadError, unpack_archive, TESTFN)
1247 self.assertRaises(ValueError, unpack_archive, TESTFN, format='xxx')
1248
Serhiy Storchaka20cdffd2016-12-16 18:58:33 +02001249 def test_unpack_archive_tar(self):
1250 self.check_unpack_archive('tar')
1251
1252 @support.requires_zlib
1253 def test_unpack_archive_gztar(self):
1254 self.check_unpack_archive('gztar')
1255
1256 @support.requires_bz2
1257 def test_unpack_archive_bztar(self):
1258 self.check_unpack_archive('bztar')
1259
1260 @support.requires_lzma
1261 def test_unpack_archive_xztar(self):
1262 self.check_unpack_archive('xztar')
1263
1264 @support.requires_zlib
1265 def test_unpack_archive_zip(self):
1266 self.check_unpack_archive('zip')
1267
Martin Pantereb995702016-07-28 01:11:04 +00001268 def test_unpack_registry(self):
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001269
1270 formats = get_unpack_formats()
1271
1272 def _boo(filename, extract_dir, extra):
Ezio Melottib3aedd42010-11-20 19:04:17 +00001273 self.assertEqual(extra, 1)
1274 self.assertEqual(filename, 'stuff.boo')
1275 self.assertEqual(extract_dir, 'xx')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001276
1277 register_unpack_format('Boo', ['.boo', '.b2'], _boo, [('extra', 1)])
1278 unpack_archive('stuff.boo', 'xx')
1279
1280 # trying to register a .boo unpacker again
1281 self.assertRaises(RegistryError, register_unpack_format, 'Boo2',
1282 ['.boo'], _boo)
1283
1284 # should work now
1285 unregister_unpack_format('Boo')
1286 register_unpack_format('Boo2', ['.boo'], _boo)
1287 self.assertIn(('Boo2', ['.boo'], ''), get_unpack_formats())
1288 self.assertNotIn(('Boo', ['.boo'], ''), get_unpack_formats())
1289
1290 # let's leave a clean state
1291 unregister_unpack_format('Boo2')
Ezio Melottib3aedd42010-11-20 19:04:17 +00001292 self.assertEqual(get_unpack_formats(), formats)
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001293
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001294 @unittest.skipUnless(hasattr(shutil, 'disk_usage'),
1295 "disk_usage not available on this platform")
1296 def test_disk_usage(self):
1297 usage = shutil.disk_usage(os.getcwd())
Éric Araujo2ee61882011-07-02 16:45:45 +02001298 self.assertGreater(usage.total, 0)
1299 self.assertGreater(usage.used, 0)
1300 self.assertGreaterEqual(usage.free, 0)
1301 self.assertGreaterEqual(usage.total, usage.used)
1302 self.assertGreater(usage.total, usage.free)
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001303
Sandro Tosid902a142011-08-22 23:28:27 +02001304 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1305 @unittest.skipUnless(hasattr(os, 'chown'), 'requires os.chown')
1306 def test_chown(self):
1307
1308 # cleaned-up automatically by TestShutil.tearDown method
1309 dirname = self.mkdtemp()
1310 filename = tempfile.mktemp(dir=dirname)
1311 write_file(filename, 'testing chown function')
1312
1313 with self.assertRaises(ValueError):
1314 shutil.chown(filename)
1315
1316 with self.assertRaises(LookupError):
Raymond Hettinger15f44ab2016-08-30 10:47:49 -07001317 shutil.chown(filename, user='non-existing username')
Sandro Tosid902a142011-08-22 23:28:27 +02001318
1319 with self.assertRaises(LookupError):
Raymond Hettinger15f44ab2016-08-30 10:47:49 -07001320 shutil.chown(filename, group='non-existing groupname')
Sandro Tosid902a142011-08-22 23:28:27 +02001321
1322 with self.assertRaises(TypeError):
1323 shutil.chown(filename, b'spam')
1324
1325 with self.assertRaises(TypeError):
1326 shutil.chown(filename, 3.14)
1327
1328 uid = os.getuid()
1329 gid = os.getgid()
1330
1331 def check_chown(path, uid=None, gid=None):
1332 s = os.stat(filename)
1333 if uid is not None:
1334 self.assertEqual(uid, s.st_uid)
1335 if gid is not None:
1336 self.assertEqual(gid, s.st_gid)
1337
1338 shutil.chown(filename, uid, gid)
1339 check_chown(filename, uid, gid)
1340 shutil.chown(filename, uid)
1341 check_chown(filename, uid)
1342 shutil.chown(filename, user=uid)
1343 check_chown(filename, uid)
1344 shutil.chown(filename, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001345 check_chown(filename, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001346
1347 shutil.chown(dirname, uid, gid)
1348 check_chown(dirname, uid, gid)
1349 shutil.chown(dirname, uid)
1350 check_chown(dirname, uid)
1351 shutil.chown(dirname, user=uid)
1352 check_chown(dirname, uid)
1353 shutil.chown(dirname, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001354 check_chown(dirname, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001355
1356 user = pwd.getpwuid(uid)[0]
1357 group = grp.getgrgid(gid)[0]
1358 shutil.chown(filename, user, group)
1359 check_chown(filename, uid, gid)
1360 shutil.chown(dirname, user, group)
1361 check_chown(dirname, uid, gid)
1362
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001363 def test_copy_return_value(self):
1364 # copy and copy2 both return their destination path.
1365 for fn in (shutil.copy, shutil.copy2):
1366 src_dir = self.mkdtemp()
1367 dst_dir = self.mkdtemp()
1368 src = os.path.join(src_dir, 'foo')
1369 write_file(src, 'foo')
1370 rv = fn(src, dst_dir)
1371 self.assertEqual(rv, os.path.join(dst_dir, 'foo'))
1372 rv = fn(src, os.path.join(dst_dir, 'bar'))
1373 self.assertEqual(rv, os.path.join(dst_dir, 'bar'))
1374
1375 def test_copyfile_return_value(self):
1376 # copytree returns its destination path.
1377 src_dir = self.mkdtemp()
1378 dst_dir = self.mkdtemp()
1379 dst_file = os.path.join(dst_dir, 'bar')
1380 src_file = os.path.join(src_dir, 'foo')
1381 write_file(src_file, 'foo')
1382 rv = shutil.copyfile(src_file, dst_file)
1383 self.assertTrue(os.path.exists(rv))
1384 self.assertEqual(read_file(src_file), read_file(dst_file))
1385
Hynek Schlawack48653762012-10-07 12:49:58 +02001386 def test_copyfile_same_file(self):
1387 # copyfile() should raise SameFileError if the source and destination
1388 # are the same.
1389 src_dir = self.mkdtemp()
1390 src_file = os.path.join(src_dir, 'foo')
1391 write_file(src_file, 'foo')
1392 self.assertRaises(SameFileError, shutil.copyfile, src_file, src_file)
Hynek Schlawack27ddb572012-10-28 13:59:27 +01001393 # But Error should work too, to stay backward compatible.
1394 self.assertRaises(Error, shutil.copyfile, src_file, src_file)
Hynek Schlawack48653762012-10-07 12:49:58 +02001395
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001396 def test_copytree_return_value(self):
1397 # copytree returns its destination path.
1398 src_dir = self.mkdtemp()
1399 dst_dir = src_dir + "dest"
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001400 self.addCleanup(shutil.rmtree, dst_dir, True)
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001401 src = os.path.join(src_dir, 'foo')
1402 write_file(src, 'foo')
1403 rv = shutil.copytree(src_dir, dst_dir)
1404 self.assertEqual(['foo'], os.listdir(rv))
1405
Christian Heimes9bd667a2008-01-20 15:14:11 +00001406
Brian Curtinc57a3452012-06-22 16:00:30 -05001407class TestWhich(unittest.TestCase):
1408
1409 def setUp(self):
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001410 self.temp_dir = tempfile.mkdtemp(prefix="Tmp")
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001411 self.addCleanup(shutil.rmtree, self.temp_dir, True)
Brian Curtinc57a3452012-06-22 16:00:30 -05001412 # Give the temp_file an ".exe" suffix for all.
1413 # It's needed on Windows and not harmful on other platforms.
1414 self.temp_file = tempfile.NamedTemporaryFile(dir=self.temp_dir,
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001415 prefix="Tmp",
1416 suffix=".Exe")
Brian Curtinc57a3452012-06-22 16:00:30 -05001417 os.chmod(self.temp_file.name, stat.S_IXUSR)
1418 self.addCleanup(self.temp_file.close)
1419 self.dir, self.file = os.path.split(self.temp_file.name)
1420
1421 def test_basic(self):
1422 # Given an EXE in a directory, it should be returned.
1423 rv = shutil.which(self.file, path=self.dir)
1424 self.assertEqual(rv, self.temp_file.name)
1425
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001426 def test_absolute_cmd(self):
Brian Curtinc57a3452012-06-22 16:00:30 -05001427 # When given the fully qualified path to an executable that exists,
1428 # it should be returned.
1429 rv = shutil.which(self.temp_file.name, path=self.temp_dir)
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001430 self.assertEqual(rv, self.temp_file.name)
1431
1432 def test_relative_cmd(self):
1433 # When given the relative path with a directory part to an executable
1434 # that exists, it should be returned.
1435 base_dir, tail_dir = os.path.split(self.dir)
1436 relpath = os.path.join(tail_dir, self.file)
Nick Coghlan55175962013-07-28 22:11:50 +10001437 with support.change_cwd(path=base_dir):
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001438 rv = shutil.which(relpath, path=self.temp_dir)
1439 self.assertEqual(rv, relpath)
1440 # But it shouldn't be searched in PATH directories (issue #16957).
Nick Coghlan55175962013-07-28 22:11:50 +10001441 with support.change_cwd(path=self.dir):
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001442 rv = shutil.which(relpath, path=base_dir)
1443 self.assertIsNone(rv)
1444
1445 def test_cwd(self):
1446 # Issue #16957
1447 base_dir = os.path.dirname(self.dir)
Nick Coghlan55175962013-07-28 22:11:50 +10001448 with support.change_cwd(path=self.dir):
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001449 rv = shutil.which(self.file, path=base_dir)
1450 if sys.platform == "win32":
1451 # Windows: current directory implicitly on PATH
1452 self.assertEqual(rv, os.path.join(os.curdir, self.file))
1453 else:
1454 # Other platforms: shouldn't match in the current directory.
1455 self.assertIsNone(rv)
Brian Curtinc57a3452012-06-22 16:00:30 -05001456
Serhiy Storchaka12516e22013-05-28 15:50:15 +03001457 @unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0,
1458 'non-root user required')
Brian Curtinc57a3452012-06-22 16:00:30 -05001459 def test_non_matching_mode(self):
1460 # Set the file read-only and ask for writeable files.
1461 os.chmod(self.temp_file.name, stat.S_IREAD)
Serhiy Storchaka12516e22013-05-28 15:50:15 +03001462 if os.access(self.temp_file.name, os.W_OK):
1463 self.skipTest("can't set the file read-only")
Brian Curtinc57a3452012-06-22 16:00:30 -05001464 rv = shutil.which(self.file, path=self.dir, mode=os.W_OK)
1465 self.assertIsNone(rv)
1466
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001467 def test_relative_path(self):
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001468 base_dir, tail_dir = os.path.split(self.dir)
Nick Coghlan55175962013-07-28 22:11:50 +10001469 with support.change_cwd(path=base_dir):
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001470 rv = shutil.which(self.file, path=tail_dir)
1471 self.assertEqual(rv, os.path.join(tail_dir, self.file))
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001472
Brian Curtinc57a3452012-06-22 16:00:30 -05001473 def test_nonexistent_file(self):
1474 # Return None when no matching executable file is found on the path.
1475 rv = shutil.which("foo.exe", path=self.dir)
1476 self.assertIsNone(rv)
1477
1478 @unittest.skipUnless(sys.platform == "win32",
1479 "pathext check is Windows-only")
1480 def test_pathext_checking(self):
1481 # Ask for the file without the ".exe" extension, then ensure that
1482 # it gets found properly with the extension.
Serhiy Storchakad70127a2013-01-24 20:03:49 +02001483 rv = shutil.which(self.file[:-4], path=self.dir)
Serhiy Storchaka80c88f42013-01-22 10:31:36 +02001484 self.assertEqual(rv, self.temp_file.name[:-4] + ".EXE")
Brian Curtinc57a3452012-06-22 16:00:30 -05001485
Barry Warsaw618738b2013-04-16 11:05:03 -04001486 def test_environ_path(self):
1487 with support.EnvironmentVarGuard() as env:
Victor Stinner1d006a22013-12-16 23:39:40 +01001488 env['PATH'] = self.dir
Barry Warsaw618738b2013-04-16 11:05:03 -04001489 rv = shutil.which(self.file)
1490 self.assertEqual(rv, self.temp_file.name)
1491
1492 def test_empty_path(self):
1493 base_dir = os.path.dirname(self.dir)
Nick Coghlan55175962013-07-28 22:11:50 +10001494 with support.change_cwd(path=self.dir), \
Barry Warsaw618738b2013-04-16 11:05:03 -04001495 support.EnvironmentVarGuard() as env:
Victor Stinner1d006a22013-12-16 23:39:40 +01001496 env['PATH'] = self.dir
Barry Warsaw618738b2013-04-16 11:05:03 -04001497 rv = shutil.which(self.file, path='')
1498 self.assertIsNone(rv)
1499
1500 def test_empty_path_no_PATH(self):
1501 with support.EnvironmentVarGuard() as env:
1502 env.pop('PATH', None)
1503 rv = shutil.which(self.file)
1504 self.assertIsNone(rv)
1505
Brian Curtinc57a3452012-06-22 16:00:30 -05001506
Christian Heimesada8c3b2008-03-18 18:26:33 +00001507class TestMove(unittest.TestCase):
1508
1509 def setUp(self):
1510 filename = "foo"
1511 self.src_dir = tempfile.mkdtemp()
1512 self.dst_dir = tempfile.mkdtemp()
1513 self.src_file = os.path.join(self.src_dir, filename)
1514 self.dst_file = os.path.join(self.dst_dir, filename)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001515 with open(self.src_file, "wb") as f:
1516 f.write(b"spam")
1517
1518 def tearDown(self):
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001519 for d in (self.src_dir, self.dst_dir):
Christian Heimesada8c3b2008-03-18 18:26:33 +00001520 try:
1521 if d:
1522 shutil.rmtree(d)
1523 except:
1524 pass
1525
1526 def _check_move_file(self, src, dst, real_dst):
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001527 with open(src, "rb") as f:
1528 contents = f.read()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001529 shutil.move(src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001530 with open(real_dst, "rb") as f:
1531 self.assertEqual(contents, f.read())
Christian Heimesada8c3b2008-03-18 18:26:33 +00001532 self.assertFalse(os.path.exists(src))
1533
1534 def _check_move_dir(self, src, dst, real_dst):
1535 contents = sorted(os.listdir(src))
1536 shutil.move(src, dst)
1537 self.assertEqual(contents, sorted(os.listdir(real_dst)))
1538 self.assertFalse(os.path.exists(src))
1539
1540 def test_move_file(self):
1541 # Move a file to another location on the same filesystem.
1542 self._check_move_file(self.src_file, self.dst_file, self.dst_file)
1543
1544 def test_move_file_to_dir(self):
1545 # Move a file inside an existing dir on the same filesystem.
1546 self._check_move_file(self.src_file, self.dst_dir, self.dst_file)
1547
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001548 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001549 def test_move_file_other_fs(self):
1550 # Move a file to an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001551 self.test_move_file()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001552
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001553 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001554 def test_move_file_to_dir_other_fs(self):
1555 # Move a file to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001556 self.test_move_file_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001557
1558 def test_move_dir(self):
1559 # Move a dir to another location on the same filesystem.
1560 dst_dir = tempfile.mktemp()
1561 try:
1562 self._check_move_dir(self.src_dir, dst_dir, dst_dir)
1563 finally:
1564 try:
1565 shutil.rmtree(dst_dir)
1566 except:
1567 pass
1568
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001569 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001570 def test_move_dir_other_fs(self):
1571 # Move a dir to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001572 self.test_move_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001573
1574 def test_move_dir_to_dir(self):
1575 # Move a dir inside an existing dir on the same filesystem.
1576 self._check_move_dir(self.src_dir, self.dst_dir,
1577 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1578
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001579 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001580 def test_move_dir_to_dir_other_fs(self):
1581 # Move a dir inside an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001582 self.test_move_dir_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001583
Serhiy Storchaka3a308b92014-02-11 10:30:59 +02001584 def test_move_dir_sep_to_dir(self):
1585 self._check_move_dir(self.src_dir + os.path.sep, self.dst_dir,
1586 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1587
1588 @unittest.skipUnless(os.path.altsep, 'requires os.path.altsep')
1589 def test_move_dir_altsep_to_dir(self):
1590 self._check_move_dir(self.src_dir + os.path.altsep, self.dst_dir,
1591 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1592
Christian Heimesada8c3b2008-03-18 18:26:33 +00001593 def test_existing_file_inside_dest_dir(self):
1594 # A file with the same name inside the destination dir already exists.
1595 with open(self.dst_file, "wb"):
1596 pass
1597 self.assertRaises(shutil.Error, shutil.move, self.src_file, self.dst_dir)
1598
1599 def test_dont_move_dir_in_itself(self):
1600 # Moving a dir inside itself raises an Error.
1601 dst = os.path.join(self.src_dir, "bar")
1602 self.assertRaises(shutil.Error, shutil.move, self.src_dir, dst)
1603
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001604 def test_destinsrc_false_negative(self):
1605 os.mkdir(TESTFN)
1606 try:
1607 for src, dst in [('srcdir', 'srcdir/dest')]:
1608 src = os.path.join(TESTFN, src)
1609 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001610 self.assertTrue(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001611 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001612 'dst (%s) is not in src (%s)' % (dst, src))
1613 finally:
1614 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001615
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001616 def test_destinsrc_false_positive(self):
1617 os.mkdir(TESTFN)
1618 try:
1619 for src, dst in [('srcdir', 'src/dest'), ('srcdir', 'srcdir.new')]:
1620 src = os.path.join(TESTFN, src)
1621 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001622 self.assertFalse(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001623 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001624 'dst (%s) is in src (%s)' % (dst, src))
1625 finally:
1626 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimes9bd667a2008-01-20 15:14:11 +00001627
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +01001628 @support.skip_unless_symlink
1629 @mock_rename
1630 def test_move_file_symlink(self):
1631 dst = os.path.join(self.src_dir, 'bar')
1632 os.symlink(self.src_file, dst)
1633 shutil.move(dst, self.dst_file)
1634 self.assertTrue(os.path.islink(self.dst_file))
1635 self.assertTrue(os.path.samefile(self.src_file, self.dst_file))
1636
1637 @support.skip_unless_symlink
1638 @mock_rename
1639 def test_move_file_symlink_to_dir(self):
1640 filename = "bar"
1641 dst = os.path.join(self.src_dir, filename)
1642 os.symlink(self.src_file, dst)
1643 shutil.move(dst, self.dst_dir)
1644 final_link = os.path.join(self.dst_dir, filename)
1645 self.assertTrue(os.path.islink(final_link))
1646 self.assertTrue(os.path.samefile(self.src_file, final_link))
1647
1648 @support.skip_unless_symlink
1649 @mock_rename
1650 def test_move_dangling_symlink(self):
1651 src = os.path.join(self.src_dir, 'baz')
1652 dst = os.path.join(self.src_dir, 'bar')
1653 os.symlink(src, dst)
1654 dst_link = os.path.join(self.dst_dir, 'quux')
1655 shutil.move(dst, dst_link)
1656 self.assertTrue(os.path.islink(dst_link))
Antoine Pitrou3f48ac92014-01-01 02:50:45 +01001657 # On Windows, os.path.realpath does not follow symlinks (issue #9949)
1658 if os.name == 'nt':
1659 self.assertEqual(os.path.realpath(src), os.readlink(dst_link))
1660 else:
1661 self.assertEqual(os.path.realpath(src), os.path.realpath(dst_link))
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +01001662
1663 @support.skip_unless_symlink
1664 @mock_rename
1665 def test_move_dir_symlink(self):
1666 src = os.path.join(self.src_dir, 'baz')
1667 dst = os.path.join(self.src_dir, 'bar')
1668 os.mkdir(src)
1669 os.symlink(src, dst)
1670 dst_link = os.path.join(self.dst_dir, 'quux')
1671 shutil.move(dst, dst_link)
1672 self.assertTrue(os.path.islink(dst_link))
1673 self.assertTrue(os.path.samefile(src, dst_link))
1674
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001675 def test_move_return_value(self):
1676 rv = shutil.move(self.src_file, self.dst_dir)
1677 self.assertEqual(rv,
1678 os.path.join(self.dst_dir, os.path.basename(self.src_file)))
1679
1680 def test_move_as_rename_return_value(self):
1681 rv = shutil.move(self.src_file, os.path.join(self.dst_dir, 'bar'))
1682 self.assertEqual(rv, os.path.join(self.dst_dir, 'bar'))
1683
R David Murray6ffface2014-06-11 14:40:13 -04001684 @mock_rename
1685 def test_move_file_special_function(self):
1686 moved = []
1687 def _copy(src, dst):
1688 moved.append((src, dst))
1689 shutil.move(self.src_file, self.dst_dir, copy_function=_copy)
1690 self.assertEqual(len(moved), 1)
1691
1692 @mock_rename
1693 def test_move_dir_special_function(self):
1694 moved = []
1695 def _copy(src, dst):
1696 moved.append((src, dst))
1697 support.create_empty_file(os.path.join(self.src_dir, 'child'))
1698 support.create_empty_file(os.path.join(self.src_dir, 'child1'))
1699 shutil.move(self.src_dir, self.dst_dir, copy_function=_copy)
1700 self.assertEqual(len(moved), 3)
1701
Tarek Ziadé5340db32010-04-19 22:30:51 +00001702
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001703class TestCopyFile(unittest.TestCase):
1704
1705 _delete = False
1706
1707 class Faux(object):
1708 _entered = False
1709 _exited_with = None
1710 _raised = False
1711 def __init__(self, raise_in_exit=False, suppress_at_exit=True):
1712 self._raise_in_exit = raise_in_exit
1713 self._suppress_at_exit = suppress_at_exit
1714 def read(self, *args):
1715 return ''
1716 def __enter__(self):
1717 self._entered = True
1718 def __exit__(self, exc_type, exc_val, exc_tb):
1719 self._exited_with = exc_type, exc_val, exc_tb
1720 if self._raise_in_exit:
1721 self._raised = True
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001722 raise OSError("Cannot close")
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001723 return self._suppress_at_exit
1724
1725 def tearDown(self):
1726 if self._delete:
1727 del shutil.open
1728
1729 def _set_shutil_open(self, func):
1730 shutil.open = func
1731 self._delete = True
1732
1733 def test_w_source_open_fails(self):
1734 def _open(filename, mode='r'):
1735 if filename == 'srcfile':
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001736 raise OSError('Cannot open "srcfile"')
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001737 assert 0 # shouldn't reach here.
1738
1739 self._set_shutil_open(_open)
1740
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001741 self.assertRaises(OSError, shutil.copyfile, 'srcfile', 'destfile')
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001742
1743 def test_w_dest_open_fails(self):
1744
1745 srcfile = self.Faux()
1746
1747 def _open(filename, mode='r'):
1748 if filename == 'srcfile':
1749 return srcfile
1750 if filename == 'destfile':
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001751 raise OSError('Cannot open "destfile"')
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001752 assert 0 # shouldn't reach here.
1753
1754 self._set_shutil_open(_open)
1755
1756 shutil.copyfile('srcfile', 'destfile')
1757 self.assertTrue(srcfile._entered)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001758 self.assertTrue(srcfile._exited_with[0] is OSError)
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001759 self.assertEqual(srcfile._exited_with[1].args,
1760 ('Cannot open "destfile"',))
1761
1762 def test_w_dest_close_fails(self):
1763
1764 srcfile = self.Faux()
1765 destfile = self.Faux(True)
1766
1767 def _open(filename, mode='r'):
1768 if filename == 'srcfile':
1769 return srcfile
1770 if filename == 'destfile':
1771 return destfile
1772 assert 0 # shouldn't reach here.
1773
1774 self._set_shutil_open(_open)
1775
1776 shutil.copyfile('srcfile', 'destfile')
1777 self.assertTrue(srcfile._entered)
1778 self.assertTrue(destfile._entered)
1779 self.assertTrue(destfile._raised)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001780 self.assertTrue(srcfile._exited_with[0] is OSError)
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001781 self.assertEqual(srcfile._exited_with[1].args,
1782 ('Cannot close',))
1783
1784 def test_w_source_close_fails(self):
1785
1786 srcfile = self.Faux(True)
1787 destfile = self.Faux()
1788
1789 def _open(filename, mode='r'):
1790 if filename == 'srcfile':
1791 return srcfile
1792 if filename == 'destfile':
1793 return destfile
1794 assert 0 # shouldn't reach here.
1795
1796 self._set_shutil_open(_open)
1797
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001798 self.assertRaises(OSError,
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001799 shutil.copyfile, 'srcfile', 'destfile')
1800 self.assertTrue(srcfile._entered)
1801 self.assertTrue(destfile._entered)
1802 self.assertFalse(destfile._raised)
1803 self.assertTrue(srcfile._exited_with[0] is None)
1804 self.assertTrue(srcfile._raised)
1805
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001806 def test_move_dir_caseinsensitive(self):
1807 # Renames a folder to the same name
1808 # but a different case.
1809
1810 self.src_dir = tempfile.mkdtemp()
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001811 self.addCleanup(shutil.rmtree, self.src_dir, True)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001812 dst_dir = os.path.join(
1813 os.path.dirname(self.src_dir),
1814 os.path.basename(self.src_dir).upper())
1815 self.assertNotEqual(self.src_dir, dst_dir)
1816
1817 try:
1818 shutil.move(self.src_dir, dst_dir)
1819 self.assertTrue(os.path.isdir(dst_dir))
1820 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +02001821 os.rmdir(dst_dir)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001822
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001823class TermsizeTests(unittest.TestCase):
1824 def test_does_not_crash(self):
1825 """Check if get_terminal_size() returns a meaningful value.
1826
1827 There's no easy portable way to actually check the size of the
1828 terminal, so let's check if it returns something sensible instead.
1829 """
1830 size = shutil.get_terminal_size()
Antoine Pitroucfade362012-02-08 23:48:59 +01001831 self.assertGreaterEqual(size.columns, 0)
1832 self.assertGreaterEqual(size.lines, 0)
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001833
1834 def test_os_environ_first(self):
1835 "Check if environment variables have precedence"
1836
1837 with support.EnvironmentVarGuard() as env:
1838 env['COLUMNS'] = '777'
Serhiy Storchakad30829d2016-04-24 09:58:43 +03001839 del env['LINES']
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001840 size = shutil.get_terminal_size()
1841 self.assertEqual(size.columns, 777)
1842
1843 with support.EnvironmentVarGuard() as env:
Serhiy Storchakad30829d2016-04-24 09:58:43 +03001844 del env['COLUMNS']
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001845 env['LINES'] = '888'
1846 size = shutil.get_terminal_size()
1847 self.assertEqual(size.lines, 888)
1848
Serhiy Storchakad30829d2016-04-24 09:58:43 +03001849 def test_bad_environ(self):
1850 with support.EnvironmentVarGuard() as env:
1851 env['COLUMNS'] = 'xxx'
1852 env['LINES'] = 'yyy'
1853 size = shutil.get_terminal_size()
1854 self.assertGreaterEqual(size.columns, 0)
1855 self.assertGreaterEqual(size.lines, 0)
1856
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001857 @unittest.skipUnless(os.isatty(sys.__stdout__.fileno()), "not on tty")
Victor Stinner119ebb72016-04-19 22:24:56 +02001858 @unittest.skipUnless(hasattr(os, 'get_terminal_size'),
1859 'need os.get_terminal_size()')
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001860 def test_stty_match(self):
1861 """Check if stty returns the same results ignoring env
1862
1863 This test will fail if stdin and stdout are connected to
1864 different terminals with different sizes. Nevertheless, such
1865 situations should be pretty rare.
1866 """
1867 try:
1868 size = subprocess.check_output(['stty', 'size']).decode().split()
Xavier de Gaye38c8b7d2016-11-14 17:14:42 +01001869 except (FileNotFoundError, PermissionError,
1870 subprocess.CalledProcessError):
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001871 self.skipTest("stty invocation failed")
1872 expected = (int(size[1]), int(size[0])) # reversed order
1873
1874 with support.EnvironmentVarGuard() as env:
1875 del env['LINES']
1876 del env['COLUMNS']
1877 actual = shutil.get_terminal_size()
1878
1879 self.assertEqual(expected, actual)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001880
Serhiy Storchakad30829d2016-04-24 09:58:43 +03001881 def test_fallback(self):
1882 with support.EnvironmentVarGuard() as env:
1883 del env['LINES']
1884 del env['COLUMNS']
1885
1886 # sys.__stdout__ has no fileno()
1887 with support.swap_attr(sys, '__stdout__', None):
1888 size = shutil.get_terminal_size(fallback=(10, 20))
1889 self.assertEqual(size.columns, 10)
1890 self.assertEqual(size.lines, 20)
1891
1892 # sys.__stdout__ is not a terminal on Unix
1893 # or fileno() not in (0, 1, 2) on Windows
1894 with open(os.devnull, 'w') as f, \
1895 support.swap_attr(sys, '__stdout__', f):
1896 size = shutil.get_terminal_size(fallback=(30, 40))
1897 self.assertEqual(size.columns, 30)
1898 self.assertEqual(size.lines, 40)
1899
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001900
Berker Peksag8083cd62014-11-01 11:04:06 +02001901class PublicAPITests(unittest.TestCase):
1902 """Ensures that the correct values are exposed in the public API."""
1903
1904 def test_module_all_attribute(self):
1905 self.assertTrue(hasattr(shutil, '__all__'))
1906 target_api = ['copyfileobj', 'copyfile', 'copymode', 'copystat',
1907 'copy', 'copy2', 'copytree', 'move', 'rmtree', 'Error',
1908 'SpecialFileError', 'ExecError', 'make_archive',
1909 'get_archive_formats', 'register_archive_format',
1910 'unregister_archive_format', 'get_unpack_formats',
1911 'register_unpack_format', 'unregister_unpack_format',
1912 'unpack_archive', 'ignore_patterns', 'chown', 'which',
1913 'get_terminal_size', 'SameFileError']
1914 if hasattr(os, 'statvfs') or os.name == 'nt':
1915 target_api.append('disk_usage')
1916 self.assertEqual(set(shutil.__all__), set(target_api))
1917
1918
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001919if __name__ == '__main__':
Brett Cannon3e9a9ae2013-06-12 21:25:59 -04001920 unittest.main()