blob: 522959a3fc91b17988c4490d73cad1f70e1e24cd [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
Tarek Ziadé396fad72010-02-23 05:30:31 +000015from os.path import splitdrive
16from distutils.spawn import find_executable, spawn
Serhiy Storchaka527ef072015-09-06 18:33:19 +030017from shutil import (make_archive,
Tarek Ziadé396fad72010-02-23 05:30:31 +000018 register_archive_format, unregister_archive_format,
Tarek Ziadé6ac91722010-04-28 17:51:36 +000019 get_archive_formats, Error, unpack_archive,
20 register_unpack_format, RegistryError,
Hynek Schlawack48653762012-10-07 12:49:58 +020021 unregister_unpack_format, get_unpack_formats,
22 SameFileError)
Tarek Ziadé396fad72010-02-23 05:30:31 +000023import tarfile
24import warnings
25
26from test import support
Ezio Melotti975077a2011-05-19 22:03:22 +030027from test.support import TESTFN, check_warnings, captured_stdout, requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +000028
Tarek Ziadéffa155a2010-04-29 13:34:35 +000029try:
30 import bz2
31 BZ2_SUPPORTED = True
32except ImportError:
33 BZ2_SUPPORTED = False
34
Serhiy Storchaka11213772014-08-06 18:50:19 +030035try:
36 import lzma
37 LZMA_SUPPORTED = True
38except ImportError:
39 LZMA_SUPPORTED = False
40
Antoine Pitrou7fff0962009-05-01 21:09:44 +000041TESTFN2 = TESTFN + "2"
Barry Warsaw7fc2cca2003-01-24 17:34:13 +000042
Tarek Ziadé396fad72010-02-23 05:30:31 +000043try:
44 import grp
45 import pwd
46 UID_GID_SUPPORT = True
47except ImportError:
48 UID_GID_SUPPORT = False
49
50try:
Tarek Ziadé396fad72010-02-23 05:30:31 +000051 import zipfile
52 ZIP_SUPPORT = True
53except ImportError:
54 ZIP_SUPPORT = find_executable('zip')
55
Nick Coghlan8ed3cf32011-03-16 14:05:35 -040056def _fake_rename(*args, **kwargs):
57 # Pretend the destination path is on a different filesystem.
Antoine Pitrouc041ab62012-01-02 19:18:02 +010058 raise OSError(getattr(errno, 'EXDEV', 18), "Invalid cross-device link")
Nick Coghlan8ed3cf32011-03-16 14:05:35 -040059
60def mock_rename(func):
61 @functools.wraps(func)
62 def wrap(*args, **kwargs):
63 try:
64 builtin_rename = os.rename
65 os.rename = _fake_rename
66 return func(*args, **kwargs)
67 finally:
68 os.rename = builtin_rename
69 return wrap
70
Éric Araujoa7e33a12011-08-12 19:51:35 +020071def write_file(path, content, binary=False):
72 """Write *content* to a file located at *path*.
73
74 If *path* is a tuple instead of a string, os.path.join will be used to
75 make a path. If *binary* is true, the file will be opened in binary
76 mode.
77 """
78 if isinstance(path, tuple):
79 path = os.path.join(*path)
80 with open(path, 'wb' if binary else 'w') as fp:
81 fp.write(content)
82
83def read_file(path, binary=False):
84 """Return contents from a file located at *path*.
85
86 If *path* is a tuple instead of a string, os.path.join will be used to
87 make a path. If *binary* is true, the file will be opened in binary
88 mode.
89 """
90 if isinstance(path, tuple):
91 path = os.path.join(*path)
92 with open(path, 'rb' if binary else 'r') as fp:
93 return fp.read()
94
Serhiy Storchaka527ef072015-09-06 18:33:19 +030095def rlistdir(path):
96 res = []
97 for name in sorted(os.listdir(path)):
98 p = os.path.join(path, name)
99 if os.path.isdir(p) and not os.path.islink(p):
100 res.append(name + '/')
101 for n in rlistdir(p):
102 res.append(name + '/' + n)
103 else:
104 res.append(name)
105 return res
106
Éric Araujoa7e33a12011-08-12 19:51:35 +0200107
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000108class TestShutil(unittest.TestCase):
Tarek Ziadé396fad72010-02-23 05:30:31 +0000109
110 def setUp(self):
111 super(TestShutil, self).setUp()
112 self.tempdirs = []
113
114 def tearDown(self):
115 super(TestShutil, self).tearDown()
116 while self.tempdirs:
117 d = self.tempdirs.pop()
118 shutil.rmtree(d, os.name in ('nt', 'cygwin'))
119
Tarek Ziadé396fad72010-02-23 05:30:31 +0000120
121 def mkdtemp(self):
122 """Create a temporary directory that will be cleaned up.
123
124 Returns the path of the directory.
125 """
126 d = tempfile.mkdtemp()
127 self.tempdirs.append(d)
128 return d
Tarek Ziadé5340db32010-04-19 22:30:51 +0000129
Hynek Schlawack3b527782012-06-25 13:27:31 +0200130 def test_rmtree_works_on_bytes(self):
131 tmp = self.mkdtemp()
132 victim = os.path.join(tmp, 'killme')
133 os.mkdir(victim)
134 write_file(os.path.join(victim, 'somefile'), 'foo')
135 victim = os.fsencode(victim)
136 self.assertIsInstance(victim, bytes)
Serhiy Storchaka41ad77c2014-08-07 19:38:37 +0300137 win = (os.name == 'nt')
138 with self.assertWarns(DeprecationWarning) if win else ExitStack():
139 shutil.rmtree(victim)
Hynek Schlawack3b527782012-06-25 13:27:31 +0200140
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200141 @support.skip_unless_symlink
142 def test_rmtree_fails_on_symlink(self):
143 tmp = self.mkdtemp()
144 dir_ = os.path.join(tmp, 'dir')
145 os.mkdir(dir_)
146 link = os.path.join(tmp, 'link')
147 os.symlink(dir_, link)
148 self.assertRaises(OSError, shutil.rmtree, link)
149 self.assertTrue(os.path.exists(dir_))
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100150 self.assertTrue(os.path.lexists(link))
151 errors = []
152 def onerror(*args):
153 errors.append(args)
154 shutil.rmtree(link, onerror=onerror)
155 self.assertEqual(len(errors), 1)
156 self.assertIs(errors[0][0], os.path.islink)
157 self.assertEqual(errors[0][1], link)
158 self.assertIsInstance(errors[0][2][1], OSError)
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200159
160 @support.skip_unless_symlink
161 def test_rmtree_works_on_symlinks(self):
162 tmp = self.mkdtemp()
163 dir1 = os.path.join(tmp, 'dir1')
164 dir2 = os.path.join(dir1, 'dir2')
165 dir3 = os.path.join(tmp, 'dir3')
166 for d in dir1, dir2, dir3:
167 os.mkdir(d)
168 file1 = os.path.join(tmp, 'file1')
169 write_file(file1, 'foo')
170 link1 = os.path.join(dir1, 'link1')
171 os.symlink(dir2, link1)
172 link2 = os.path.join(dir1, 'link2')
173 os.symlink(dir3, link2)
174 link3 = os.path.join(dir1, 'link3')
175 os.symlink(file1, link3)
176 # make sure symlinks are removed but not followed
177 shutil.rmtree(dir1)
178 self.assertFalse(os.path.exists(dir1))
179 self.assertTrue(os.path.exists(dir3))
180 self.assertTrue(os.path.exists(file1))
181
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000182 def test_rmtree_errors(self):
183 # filename is guaranteed not to exist
184 filename = tempfile.mktemp()
Hynek Schlawackb5501102012-12-10 09:11:25 +0100185 self.assertRaises(FileNotFoundError, shutil.rmtree, filename)
186 # test that ignore_errors option is honored
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100187 shutil.rmtree(filename, ignore_errors=True)
188
189 # existing file
190 tmpdir = self.mkdtemp()
Hynek Schlawackb5501102012-12-10 09:11:25 +0100191 write_file((tmpdir, "tstfile"), "")
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100192 filename = os.path.join(tmpdir, "tstfile")
Hynek Schlawackb5501102012-12-10 09:11:25 +0100193 with self.assertRaises(NotADirectoryError) as cm:
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100194 shutil.rmtree(filename)
Hynek Schlawack87f9b462012-12-10 16:29:57 +0100195 # The reason for this rather odd construct is that Windows sprinkles
196 # a \*.* at the end of file names. But only sometimes on some buildbots
197 possible_args = [filename, os.path.join(filename, '*.*')]
198 self.assertIn(cm.exception.filename, possible_args)
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100199 self.assertTrue(os.path.exists(filename))
Hynek Schlawackb5501102012-12-10 09:11:25 +0100200 # test that ignore_errors option is honored
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100201 shutil.rmtree(filename, ignore_errors=True)
202 self.assertTrue(os.path.exists(filename))
203 errors = []
204 def onerror(*args):
205 errors.append(args)
206 shutil.rmtree(filename, onerror=onerror)
207 self.assertEqual(len(errors), 2)
208 self.assertIs(errors[0][0], os.listdir)
209 self.assertEqual(errors[0][1], filename)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100210 self.assertIsInstance(errors[0][2][1], NotADirectoryError)
Hynek Schlawack87f9b462012-12-10 16:29:57 +0100211 self.assertIn(errors[0][2][1].filename, possible_args)
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100212 self.assertIs(errors[1][0], os.rmdir)
213 self.assertEqual(errors[1][1], filename)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100214 self.assertIsInstance(errors[1][2][1], NotADirectoryError)
Hynek Schlawack87f9b462012-12-10 16:29:57 +0100215 self.assertIn(errors[1][2][1].filename, possible_args)
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000216
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000217
Serhiy Storchaka43767632013-11-03 21:31:38 +0200218 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod()')
219 @unittest.skipIf(sys.platform[:6] == 'cygwin',
220 "This test can't be run on Cygwin (issue #1071513).")
221 @unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0,
222 "This test can't be run reliably as root (issue #1076467).")
223 def test_on_error(self):
224 self.errorState = 0
225 os.mkdir(TESTFN)
226 self.addCleanup(shutil.rmtree, TESTFN)
Antoine Pitrou2f8a75c2012-06-23 21:28:15 +0200227
Serhiy Storchaka43767632013-11-03 21:31:38 +0200228 self.child_file_path = os.path.join(TESTFN, 'a')
229 self.child_dir_path = os.path.join(TESTFN, 'b')
230 support.create_empty_file(self.child_file_path)
231 os.mkdir(self.child_dir_path)
232 old_dir_mode = os.stat(TESTFN).st_mode
233 old_child_file_mode = os.stat(self.child_file_path).st_mode
234 old_child_dir_mode = os.stat(self.child_dir_path).st_mode
235 # Make unwritable.
236 new_mode = stat.S_IREAD|stat.S_IEXEC
237 os.chmod(self.child_file_path, new_mode)
238 os.chmod(self.child_dir_path, new_mode)
239 os.chmod(TESTFN, new_mode)
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000240
Serhiy Storchaka43767632013-11-03 21:31:38 +0200241 self.addCleanup(os.chmod, TESTFN, old_dir_mode)
242 self.addCleanup(os.chmod, self.child_file_path, old_child_file_mode)
243 self.addCleanup(os.chmod, self.child_dir_path, old_child_dir_mode)
Antoine Pitrou2f8a75c2012-06-23 21:28:15 +0200244
Serhiy Storchaka43767632013-11-03 21:31:38 +0200245 shutil.rmtree(TESTFN, onerror=self.check_args_to_onerror)
246 # Test whether onerror has actually been called.
247 self.assertEqual(self.errorState, 3,
248 "Expected call to onerror function did not happen.")
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000249
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000250 def check_args_to_onerror(self, func, arg, exc):
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000251 # test_rmtree_errors deliberately runs rmtree
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200252 # on a directory that is chmod 500, which will fail.
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000253 # This function is run when shutil.rmtree fails.
254 # 99.9% of the time it initially fails to remove
255 # a file in the directory, so the first time through
256 # func is os.remove.
257 # However, some Linux machines running ZFS on
258 # FUSE experienced a failure earlier in the process
259 # at os.listdir. The first failure may legally
260 # be either.
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200261 if self.errorState < 2:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200262 if func is os.unlink:
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200263 self.assertEqual(arg, self.child_file_path)
264 elif func is os.rmdir:
265 self.assertEqual(arg, self.child_dir_path)
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000266 else:
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200267 self.assertIs(func, os.listdir)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200268 self.assertIn(arg, [TESTFN, self.child_dir_path])
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000269 self.assertTrue(issubclass(exc[0], OSError))
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200270 self.errorState += 1
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000271 else:
272 self.assertEqual(func, os.rmdir)
273 self.assertEqual(arg, TESTFN)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000274 self.assertTrue(issubclass(exc[0], OSError))
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200275 self.errorState = 3
276
277 def test_rmtree_does_not_choke_on_failing_lstat(self):
278 try:
279 orig_lstat = os.lstat
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200280 def raiser(fn, *args, **kwargs):
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200281 if fn != TESTFN:
282 raise OSError()
283 else:
284 return orig_lstat(fn)
285 os.lstat = raiser
286
287 os.mkdir(TESTFN)
288 write_file((TESTFN, 'foo'), 'foo')
289 shutil.rmtree(TESTFN)
290 finally:
291 os.lstat = orig_lstat
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000292
Antoine Pitrou78091e62011-12-29 18:54:15 +0100293 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
294 @support.skip_unless_symlink
295 def test_copymode_follow_symlinks(self):
296 tmp_dir = self.mkdtemp()
297 src = os.path.join(tmp_dir, 'foo')
298 dst = os.path.join(tmp_dir, 'bar')
299 src_link = os.path.join(tmp_dir, 'baz')
300 dst_link = os.path.join(tmp_dir, 'quux')
301 write_file(src, 'foo')
302 write_file(dst, 'foo')
303 os.symlink(src, src_link)
304 os.symlink(dst, dst_link)
305 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
306 # file to file
307 os.chmod(dst, stat.S_IRWXO)
308 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
309 shutil.copymode(src, dst)
310 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
Antoine Pitrou3f48ac92014-01-01 02:50:45 +0100311 # On Windows, os.chmod does not follow symlinks (issue #15411)
312 if os.name != 'nt':
313 # follow src link
314 os.chmod(dst, stat.S_IRWXO)
315 shutil.copymode(src_link, dst)
316 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
317 # follow dst link
318 os.chmod(dst, stat.S_IRWXO)
319 shutil.copymode(src, dst_link)
320 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
321 # follow both links
322 os.chmod(dst, stat.S_IRWXO)
323 shutil.copymode(src_link, dst_link)
324 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100325
326 @unittest.skipUnless(hasattr(os, 'lchmod'), 'requires os.lchmod')
327 @support.skip_unless_symlink
328 def test_copymode_symlink_to_symlink(self):
329 tmp_dir = self.mkdtemp()
330 src = os.path.join(tmp_dir, 'foo')
331 dst = os.path.join(tmp_dir, 'bar')
332 src_link = os.path.join(tmp_dir, 'baz')
333 dst_link = os.path.join(tmp_dir, 'quux')
334 write_file(src, 'foo')
335 write_file(dst, 'foo')
336 os.symlink(src, src_link)
337 os.symlink(dst, dst_link)
338 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
339 os.chmod(dst, stat.S_IRWXU)
340 os.lchmod(src_link, stat.S_IRWXO|stat.S_IRWXG)
341 # link to link
342 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700343 shutil.copymode(src_link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100344 self.assertEqual(os.lstat(src_link).st_mode,
345 os.lstat(dst_link).st_mode)
346 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
347 # src link - use chmod
348 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700349 shutil.copymode(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100350 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
351 # dst link - use chmod
352 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700353 shutil.copymode(src, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100354 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
355
356 @unittest.skipIf(hasattr(os, 'lchmod'), 'requires os.lchmod to be missing')
357 @support.skip_unless_symlink
358 def test_copymode_symlink_to_symlink_wo_lchmod(self):
359 tmp_dir = self.mkdtemp()
360 src = os.path.join(tmp_dir, 'foo')
361 dst = os.path.join(tmp_dir, 'bar')
362 src_link = os.path.join(tmp_dir, 'baz')
363 dst_link = os.path.join(tmp_dir, 'quux')
364 write_file(src, 'foo')
365 write_file(dst, 'foo')
366 os.symlink(src, src_link)
367 os.symlink(dst, dst_link)
Larry Hastingsb4038062012-07-15 10:57:38 -0700368 shutil.copymode(src_link, dst_link, follow_symlinks=False) # silent fail
Antoine Pitrou78091e62011-12-29 18:54:15 +0100369
370 @support.skip_unless_symlink
371 def test_copystat_symlinks(self):
372 tmp_dir = self.mkdtemp()
373 src = os.path.join(tmp_dir, 'foo')
374 dst = os.path.join(tmp_dir, 'bar')
375 src_link = os.path.join(tmp_dir, 'baz')
376 dst_link = os.path.join(tmp_dir, 'qux')
377 write_file(src, 'foo')
378 src_stat = os.stat(src)
379 os.utime(src, (src_stat.st_atime,
380 src_stat.st_mtime - 42.0)) # ensure different mtimes
381 write_file(dst, 'bar')
382 self.assertNotEqual(os.stat(src).st_mtime, os.stat(dst).st_mtime)
383 os.symlink(src, src_link)
384 os.symlink(dst, dst_link)
385 if hasattr(os, 'lchmod'):
386 os.lchmod(src_link, stat.S_IRWXO)
387 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
388 os.lchflags(src_link, stat.UF_NODUMP)
389 src_link_stat = os.lstat(src_link)
390 # follow
391 if hasattr(os, 'lchmod'):
Larry Hastingsb4038062012-07-15 10:57:38 -0700392 shutil.copystat(src_link, dst_link, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100393 self.assertNotEqual(src_link_stat.st_mode, os.stat(dst).st_mode)
394 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700395 shutil.copystat(src_link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100396 dst_link_stat = os.lstat(dst_link)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700397 if os.utime in os.supports_follow_symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100398 for attr in 'st_atime', 'st_mtime':
399 # The modification times may be truncated in the new file.
400 self.assertLessEqual(getattr(src_link_stat, attr),
401 getattr(dst_link_stat, attr) + 1)
402 if hasattr(os, 'lchmod'):
403 self.assertEqual(src_link_stat.st_mode, dst_link_stat.st_mode)
404 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
405 self.assertEqual(src_link_stat.st_flags, dst_link_stat.st_flags)
406 # tell to follow but dst is not a link
Larry Hastingsb4038062012-07-15 10:57:38 -0700407 shutil.copystat(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100408 self.assertTrue(abs(os.stat(src).st_mtime - os.stat(dst).st_mtime) <
409 00000.1)
410
Ned Deilybaf75712012-05-10 17:05:19 -0700411 @unittest.skipUnless(hasattr(os, 'chflags') and
412 hasattr(errno, 'EOPNOTSUPP') and
413 hasattr(errno, 'ENOTSUP'),
414 "requires os.chflags, EOPNOTSUPP & ENOTSUP")
415 def test_copystat_handles_harmless_chflags_errors(self):
416 tmpdir = self.mkdtemp()
417 file1 = os.path.join(tmpdir, 'file1')
418 file2 = os.path.join(tmpdir, 'file2')
419 write_file(file1, 'xxx')
420 write_file(file2, 'xxx')
421
422 def make_chflags_raiser(err):
423 ex = OSError()
424
Larry Hastings90867a52012-06-22 17:01:41 -0700425 def _chflags_raiser(path, flags, *, follow_symlinks=True):
Ned Deilybaf75712012-05-10 17:05:19 -0700426 ex.errno = err
427 raise ex
428 return _chflags_raiser
429 old_chflags = os.chflags
430 try:
431 for err in errno.EOPNOTSUPP, errno.ENOTSUP:
432 os.chflags = make_chflags_raiser(err)
433 shutil.copystat(file1, file2)
434 # assert others errors break it
435 os.chflags = make_chflags_raiser(errno.EOPNOTSUPP + errno.ENOTSUP)
436 self.assertRaises(OSError, shutil.copystat, file1, file2)
437 finally:
438 os.chflags = old_chflags
439
Antoine Pitrou424246f2012-05-12 19:02:01 +0200440 @support.skip_unless_xattr
441 def test_copyxattr(self):
442 tmp_dir = self.mkdtemp()
443 src = os.path.join(tmp_dir, 'foo')
444 write_file(src, 'foo')
445 dst = os.path.join(tmp_dir, 'bar')
446 write_file(dst, 'bar')
447
448 # no xattr == no problem
449 shutil._copyxattr(src, dst)
450 # common case
451 os.setxattr(src, 'user.foo', b'42')
452 os.setxattr(src, 'user.bar', b'43')
453 shutil._copyxattr(src, dst)
Gregory P. Smith1093bf22014-01-17 12:01:22 -0800454 self.assertEqual(sorted(os.listxattr(src)), sorted(os.listxattr(dst)))
Antoine Pitrou424246f2012-05-12 19:02:01 +0200455 self.assertEqual(
456 os.getxattr(src, 'user.foo'),
457 os.getxattr(dst, 'user.foo'))
458 # check errors don't affect other attrs
459 os.remove(dst)
460 write_file(dst, 'bar')
461 os_error = OSError(errno.EPERM, 'EPERM')
462
Larry Hastings9cf065c2012-06-22 16:30:09 -0700463 def _raise_on_user_foo(fname, attr, val, **kwargs):
Antoine Pitrou424246f2012-05-12 19:02:01 +0200464 if attr == 'user.foo':
465 raise os_error
466 else:
Larry Hastings9cf065c2012-06-22 16:30:09 -0700467 orig_setxattr(fname, attr, val, **kwargs)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200468 try:
469 orig_setxattr = os.setxattr
470 os.setxattr = _raise_on_user_foo
471 shutil._copyxattr(src, dst)
Antoine Pitrou61597d32012-05-12 23:37:35 +0200472 self.assertIn('user.bar', os.listxattr(dst))
Antoine Pitrou424246f2012-05-12 19:02:01 +0200473 finally:
474 os.setxattr = orig_setxattr
Hynek Schlawack0beab052013-02-05 08:22:44 +0100475 # the source filesystem not supporting xattrs should be ok, too.
476 def _raise_on_src(fname, *, follow_symlinks=True):
477 if fname == src:
478 raise OSError(errno.ENOTSUP, 'Operation not supported')
479 return orig_listxattr(fname, follow_symlinks=follow_symlinks)
480 try:
481 orig_listxattr = os.listxattr
482 os.listxattr = _raise_on_src
483 shutil._copyxattr(src, dst)
484 finally:
485 os.listxattr = orig_listxattr
Antoine Pitrou424246f2012-05-12 19:02:01 +0200486
Larry Hastingsad5ae042012-07-14 17:55:11 -0700487 # test that shutil.copystat copies xattrs
488 src = os.path.join(tmp_dir, 'the_original')
489 write_file(src, src)
490 os.setxattr(src, 'user.the_value', b'fiddly')
491 dst = os.path.join(tmp_dir, 'the_copy')
492 write_file(dst, dst)
493 shutil.copystat(src, dst)
Hynek Schlawackc2d481f2012-07-16 17:11:10 +0200494 self.assertEqual(os.getxattr(dst, 'user.the_value'), b'fiddly')
Larry Hastingsad5ae042012-07-14 17:55:11 -0700495
Antoine Pitrou424246f2012-05-12 19:02:01 +0200496 @support.skip_unless_symlink
497 @support.skip_unless_xattr
498 @unittest.skipUnless(hasattr(os, 'geteuid') and os.geteuid() == 0,
499 'root privileges required')
500 def test_copyxattr_symlinks(self):
501 # On Linux, it's only possible to access non-user xattr for symlinks;
502 # which in turn require root privileges. This test should be expanded
503 # as soon as other platforms gain support for extended attributes.
504 tmp_dir = self.mkdtemp()
505 src = os.path.join(tmp_dir, 'foo')
506 src_link = os.path.join(tmp_dir, 'baz')
507 write_file(src, 'foo')
508 os.symlink(src, src_link)
509 os.setxattr(src, 'trusted.foo', b'42')
Larry Hastings9cf065c2012-06-22 16:30:09 -0700510 os.setxattr(src_link, 'trusted.foo', b'43', follow_symlinks=False)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200511 dst = os.path.join(tmp_dir, 'bar')
512 dst_link = os.path.join(tmp_dir, 'qux')
513 write_file(dst, 'bar')
514 os.symlink(dst, dst_link)
Larry Hastingsb4038062012-07-15 10:57:38 -0700515 shutil._copyxattr(src_link, dst_link, follow_symlinks=False)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700516 self.assertEqual(os.getxattr(dst_link, 'trusted.foo', follow_symlinks=False), b'43')
Antoine Pitrou424246f2012-05-12 19:02:01 +0200517 self.assertRaises(OSError, os.getxattr, dst, 'trusted.foo')
Larry Hastingsb4038062012-07-15 10:57:38 -0700518 shutil._copyxattr(src_link, dst, follow_symlinks=False)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200519 self.assertEqual(os.getxattr(dst, 'trusted.foo'), b'43')
520
Antoine Pitrou78091e62011-12-29 18:54:15 +0100521 @support.skip_unless_symlink
522 def test_copy_symlinks(self):
523 tmp_dir = self.mkdtemp()
524 src = os.path.join(tmp_dir, 'foo')
525 dst = os.path.join(tmp_dir, 'bar')
526 src_link = os.path.join(tmp_dir, 'baz')
527 write_file(src, 'foo')
528 os.symlink(src, src_link)
529 if hasattr(os, 'lchmod'):
530 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
531 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700532 shutil.copy(src_link, dst, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100533 self.assertFalse(os.path.islink(dst))
534 self.assertEqual(read_file(src), read_file(dst))
535 os.remove(dst)
536 # follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700537 shutil.copy(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100538 self.assertTrue(os.path.islink(dst))
539 self.assertEqual(os.readlink(dst), os.readlink(src_link))
540 if hasattr(os, 'lchmod'):
541 self.assertEqual(os.lstat(src_link).st_mode,
542 os.lstat(dst).st_mode)
543
544 @support.skip_unless_symlink
545 def test_copy2_symlinks(self):
546 tmp_dir = self.mkdtemp()
547 src = os.path.join(tmp_dir, 'foo')
548 dst = os.path.join(tmp_dir, 'bar')
549 src_link = os.path.join(tmp_dir, 'baz')
550 write_file(src, 'foo')
551 os.symlink(src, src_link)
552 if hasattr(os, 'lchmod'):
553 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
554 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
555 os.lchflags(src_link, stat.UF_NODUMP)
556 src_stat = os.stat(src)
557 src_link_stat = os.lstat(src_link)
558 # follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700559 shutil.copy2(src_link, dst, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100560 self.assertFalse(os.path.islink(dst))
561 self.assertEqual(read_file(src), read_file(dst))
562 os.remove(dst)
563 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700564 shutil.copy2(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100565 self.assertTrue(os.path.islink(dst))
566 self.assertEqual(os.readlink(dst), os.readlink(src_link))
567 dst_stat = os.lstat(dst)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700568 if os.utime in os.supports_follow_symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100569 for attr in 'st_atime', 'st_mtime':
570 # The modification times may be truncated in the new file.
571 self.assertLessEqual(getattr(src_link_stat, attr),
572 getattr(dst_stat, attr) + 1)
573 if hasattr(os, 'lchmod'):
574 self.assertEqual(src_link_stat.st_mode, dst_stat.st_mode)
575 self.assertNotEqual(src_stat.st_mode, dst_stat.st_mode)
576 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
577 self.assertEqual(src_link_stat.st_flags, dst_stat.st_flags)
578
Antoine Pitrou424246f2012-05-12 19:02:01 +0200579 @support.skip_unless_xattr
580 def test_copy2_xattr(self):
581 tmp_dir = self.mkdtemp()
582 src = os.path.join(tmp_dir, 'foo')
583 dst = os.path.join(tmp_dir, 'bar')
584 write_file(src, 'foo')
585 os.setxattr(src, 'user.foo', b'42')
586 shutil.copy2(src, dst)
587 self.assertEqual(
588 os.getxattr(src, 'user.foo'),
589 os.getxattr(dst, 'user.foo'))
590 os.remove(dst)
591
Antoine Pitrou78091e62011-12-29 18:54:15 +0100592 @support.skip_unless_symlink
593 def test_copyfile_symlinks(self):
594 tmp_dir = self.mkdtemp()
595 src = os.path.join(tmp_dir, 'src')
596 dst = os.path.join(tmp_dir, 'dst')
597 dst_link = os.path.join(tmp_dir, 'dst_link')
598 link = os.path.join(tmp_dir, 'link')
599 write_file(src, 'foo')
600 os.symlink(src, link)
601 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700602 shutil.copyfile(link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100603 self.assertTrue(os.path.islink(dst_link))
604 self.assertEqual(os.readlink(link), os.readlink(dst_link))
605 # follow
606 shutil.copyfile(link, dst)
607 self.assertFalse(os.path.islink(dst))
608
Hynek Schlawack2100b422012-06-23 20:28:32 +0200609 def test_rmtree_uses_safe_fd_version_if_available(self):
Hynek Schlawackd0f6e0a2012-06-29 08:28:20 +0200610 _use_fd_functions = ({os.open, os.stat, os.unlink, os.rmdir} <=
611 os.supports_dir_fd and
612 os.listdir in os.supports_fd and
613 os.stat in os.supports_follow_symlinks)
614 if _use_fd_functions:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200615 self.assertTrue(shutil._use_fd_functions)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000616 self.assertTrue(shutil.rmtree.avoids_symlink_attacks)
Hynek Schlawack2100b422012-06-23 20:28:32 +0200617 tmp_dir = self.mkdtemp()
618 d = os.path.join(tmp_dir, 'a')
619 os.mkdir(d)
620 try:
621 real_rmtree = shutil._rmtree_safe_fd
622 class Called(Exception): pass
623 def _raiser(*args, **kwargs):
624 raise Called
625 shutil._rmtree_safe_fd = _raiser
626 self.assertRaises(Called, shutil.rmtree, d)
627 finally:
628 shutil._rmtree_safe_fd = real_rmtree
629 else:
630 self.assertFalse(shutil._use_fd_functions)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000631 self.assertFalse(shutil.rmtree.avoids_symlink_attacks)
Hynek Schlawack2100b422012-06-23 20:28:32 +0200632
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000633 def test_rmtree_dont_delete_file(self):
634 # When called on a file instead of a directory, don't delete it.
635 handle, path = tempfile.mkstemp()
Victor Stinnerbf816222011-06-30 23:25:47 +0200636 os.close(handle)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200637 self.assertRaises(NotADirectoryError, shutil.rmtree, path)
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000638 os.remove(path)
639
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000640 def test_copytree_simple(self):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000641 src_dir = tempfile.mkdtemp()
642 dst_dir = os.path.join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200643 self.addCleanup(shutil.rmtree, src_dir)
644 self.addCleanup(shutil.rmtree, os.path.dirname(dst_dir))
645 write_file((src_dir, 'test.txt'), '123')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000646 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200647 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000648
Éric Araujoa7e33a12011-08-12 19:51:35 +0200649 shutil.copytree(src_dir, dst_dir)
650 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test.txt')))
651 self.assertTrue(os.path.isdir(os.path.join(dst_dir, 'test_dir')))
652 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test_dir',
653 'test.txt')))
654 actual = read_file((dst_dir, 'test.txt'))
655 self.assertEqual(actual, '123')
656 actual = read_file((dst_dir, 'test_dir', 'test.txt'))
657 self.assertEqual(actual, '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000658
Antoine Pitrou78091e62011-12-29 18:54:15 +0100659 @support.skip_unless_symlink
660 def test_copytree_symlinks(self):
661 tmp_dir = self.mkdtemp()
662 src_dir = os.path.join(tmp_dir, 'src')
663 dst_dir = os.path.join(tmp_dir, 'dst')
664 sub_dir = os.path.join(src_dir, 'sub')
665 os.mkdir(src_dir)
666 os.mkdir(sub_dir)
667 write_file((src_dir, 'file.txt'), 'foo')
668 src_link = os.path.join(sub_dir, 'link')
669 dst_link = os.path.join(dst_dir, 'sub/link')
670 os.symlink(os.path.join(src_dir, 'file.txt'),
671 src_link)
672 if hasattr(os, 'lchmod'):
673 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
674 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
675 os.lchflags(src_link, stat.UF_NODUMP)
676 src_stat = os.lstat(src_link)
677 shutil.copytree(src_dir, dst_dir, symlinks=True)
678 self.assertTrue(os.path.islink(os.path.join(dst_dir, 'sub', 'link')))
679 self.assertEqual(os.readlink(os.path.join(dst_dir, 'sub', 'link')),
680 os.path.join(src_dir, 'file.txt'))
681 dst_stat = os.lstat(dst_link)
682 if hasattr(os, 'lchmod'):
683 self.assertEqual(dst_stat.st_mode, src_stat.st_mode)
684 if hasattr(os, 'lchflags'):
685 self.assertEqual(dst_stat.st_flags, src_stat.st_flags)
686
Georg Brandl2ee470f2008-07-16 12:55:28 +0000687 def test_copytree_with_exclude(self):
Georg Brandl2ee470f2008-07-16 12:55:28 +0000688 # creating data
689 join = os.path.join
690 exists = os.path.exists
691 src_dir = tempfile.mkdtemp()
Georg Brandl2ee470f2008-07-16 12:55:28 +0000692 try:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000693 dst_dir = join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200694 write_file((src_dir, 'test.txt'), '123')
695 write_file((src_dir, 'test.tmp'), '123')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000696 os.mkdir(join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200697 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000698 os.mkdir(join(src_dir, 'test_dir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200699 write_file((src_dir, 'test_dir2', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000700 os.mkdir(join(src_dir, 'test_dir2', 'subdir'))
701 os.mkdir(join(src_dir, 'test_dir2', 'subdir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200702 write_file((src_dir, 'test_dir2', 'subdir', 'test.txt'), '456')
703 write_file((src_dir, 'test_dir2', 'subdir2', 'test.py'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000704
705 # testing glob-like patterns
706 try:
707 patterns = shutil.ignore_patterns('*.tmp', 'test_dir2')
708 shutil.copytree(src_dir, dst_dir, ignore=patterns)
709 # checking the result: some elements should not be copied
710 self.assertTrue(exists(join(dst_dir, 'test.txt')))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200711 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
712 self.assertFalse(exists(join(dst_dir, 'test_dir2')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000713 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200714 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000715 try:
716 patterns = shutil.ignore_patterns('*.tmp', 'subdir*')
717 shutil.copytree(src_dir, dst_dir, ignore=patterns)
718 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200719 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
720 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2')))
721 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000722 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200723 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000724
725 # testing callable-style
726 try:
727 def _filter(src, names):
728 res = []
729 for name in names:
730 path = os.path.join(src, name)
731
732 if (os.path.isdir(path) and
733 path.split()[-1] == 'subdir'):
734 res.append(name)
735 elif os.path.splitext(path)[-1] in ('.py'):
736 res.append(name)
737 return res
738
739 shutil.copytree(src_dir, dst_dir, ignore=_filter)
740
741 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200742 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2',
743 'test.py')))
744 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000745
746 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200747 shutil.rmtree(dst_dir)
Georg Brandl2ee470f2008-07-16 12:55:28 +0000748 finally:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000749 shutil.rmtree(src_dir)
750 shutil.rmtree(os.path.dirname(dst_dir))
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000751
Antoine Pitrouac601602013-08-16 19:35:02 +0200752 def test_copytree_retains_permissions(self):
753 tmp_dir = tempfile.mkdtemp()
754 src_dir = os.path.join(tmp_dir, 'source')
755 os.mkdir(src_dir)
756 dst_dir = os.path.join(tmp_dir, 'destination')
757 self.addCleanup(shutil.rmtree, tmp_dir)
758
759 os.chmod(src_dir, 0o777)
760 write_file((src_dir, 'permissive.txt'), '123')
761 os.chmod(os.path.join(src_dir, 'permissive.txt'), 0o777)
762 write_file((src_dir, 'restrictive.txt'), '456')
763 os.chmod(os.path.join(src_dir, 'restrictive.txt'), 0o600)
764 restrictive_subdir = tempfile.mkdtemp(dir=src_dir)
765 os.chmod(restrictive_subdir, 0o600)
766
767 shutil.copytree(src_dir, dst_dir)
Brett Cannon9c7eb552013-08-23 14:38:11 -0400768 self.assertEqual(os.stat(src_dir).st_mode, os.stat(dst_dir).st_mode)
769 self.assertEqual(os.stat(os.path.join(src_dir, 'permissive.txt')).st_mode,
Antoine Pitrouac601602013-08-16 19:35:02 +0200770 os.stat(os.path.join(dst_dir, 'permissive.txt')).st_mode)
Brett Cannon9c7eb552013-08-23 14:38:11 -0400771 self.assertEqual(os.stat(os.path.join(src_dir, 'restrictive.txt')).st_mode,
Antoine Pitrouac601602013-08-16 19:35:02 +0200772 os.stat(os.path.join(dst_dir, 'restrictive.txt')).st_mode)
773 restrictive_subdir_dst = os.path.join(dst_dir,
774 os.path.split(restrictive_subdir)[1])
Brett Cannon9c7eb552013-08-23 14:38:11 -0400775 self.assertEqual(os.stat(restrictive_subdir).st_mode,
Antoine Pitrouac601602013-08-16 19:35:02 +0200776 os.stat(restrictive_subdir_dst).st_mode)
777
Berker Peksag884afd92014-12-10 02:50:32 +0200778 @unittest.mock.patch('os.chmod')
779 def test_copytree_winerror(self, mock_patch):
780 # When copying to VFAT, copystat() raises OSError. On Windows, the
781 # exception object has a meaningful 'winerror' attribute, but not
782 # on other operating systems. Do not assume 'winerror' is set.
783 src_dir = tempfile.mkdtemp()
784 dst_dir = os.path.join(tempfile.mkdtemp(), 'destination')
785 self.addCleanup(shutil.rmtree, src_dir)
786 self.addCleanup(shutil.rmtree, os.path.dirname(dst_dir))
787
788 mock_patch.side_effect = PermissionError('ka-boom')
789 with self.assertRaises(shutil.Error):
790 shutil.copytree(src_dir, dst_dir)
791
Zachary Ware9fe6d862013-12-08 00:20:35 -0600792 @unittest.skipIf(os.name == 'nt', 'temporarily disabled on Windows')
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000793 @unittest.skipUnless(hasattr(os, 'link'), 'requires os.link')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000794 def test_dont_copy_file_onto_link_to_itself(self):
795 # bug 851123.
796 os.mkdir(TESTFN)
797 src = os.path.join(TESTFN, 'cheese')
798 dst = os.path.join(TESTFN, 'shop')
799 try:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000800 with open(src, 'w') as f:
801 f.write('cheddar')
802 os.link(src, dst)
Hynek Schlawack48653762012-10-07 12:49:58 +0200803 self.assertRaises(shutil.SameFileError, shutil.copyfile, src, dst)
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000804 with open(src, 'r') as f:
805 self.assertEqual(f.read(), 'cheddar')
806 os.remove(dst)
807 finally:
808 shutil.rmtree(TESTFN, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000809
Brian Curtin3b4499c2010-12-28 14:31:47 +0000810 @support.skip_unless_symlink
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000811 def test_dont_copy_file_onto_symlink_to_itself(self):
812 # bug 851123.
813 os.mkdir(TESTFN)
814 src = os.path.join(TESTFN, 'cheese')
815 dst = os.path.join(TESTFN, 'shop')
816 try:
817 with open(src, 'w') as f:
818 f.write('cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000819 # Using `src` here would mean we end up with a symlink pointing
820 # to TESTFN/TESTFN/cheese, while it should point at
821 # TESTFN/cheese.
822 os.symlink('cheese', dst)
Hynek Schlawack48653762012-10-07 12:49:58 +0200823 self.assertRaises(shutil.SameFileError, shutil.copyfile, src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +0000824 with open(src, 'r') as f:
825 self.assertEqual(f.read(), 'cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000826 os.remove(dst)
827 finally:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000828 shutil.rmtree(TESTFN, ignore_errors=True)
Johannes Gijsbers68128712004-08-14 13:57:08 +0000829
Brian Curtin3b4499c2010-12-28 14:31:47 +0000830 @support.skip_unless_symlink
Brian Curtind40e6f72010-07-08 21:39:08 +0000831 def test_rmtree_on_symlink(self):
832 # bug 1669.
833 os.mkdir(TESTFN)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000834 try:
Brian Curtind40e6f72010-07-08 21:39:08 +0000835 src = os.path.join(TESTFN, 'cheese')
836 dst = os.path.join(TESTFN, 'shop')
837 os.mkdir(src)
838 os.symlink(src, dst)
839 self.assertRaises(OSError, shutil.rmtree, dst)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200840 shutil.rmtree(dst, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000841 finally:
Brian Curtind40e6f72010-07-08 21:39:08 +0000842 shutil.rmtree(TESTFN, ignore_errors=True)
843
Serhiy Storchaka43767632013-11-03 21:31:38 +0200844 # Issue #3002: copyfile and copytree block indefinitely on named pipes
845 @unittest.skipUnless(hasattr(os, "mkfifo"), 'requires os.mkfifo()')
846 def test_copyfile_named_pipe(self):
847 os.mkfifo(TESTFN)
848 try:
849 self.assertRaises(shutil.SpecialFileError,
850 shutil.copyfile, TESTFN, TESTFN2)
851 self.assertRaises(shutil.SpecialFileError,
852 shutil.copyfile, __file__, TESTFN)
853 finally:
854 os.remove(TESTFN)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000855
Serhiy Storchaka43767632013-11-03 21:31:38 +0200856 @unittest.skipUnless(hasattr(os, "mkfifo"), 'requires os.mkfifo()')
857 @support.skip_unless_symlink
858 def test_copytree_named_pipe(self):
859 os.mkdir(TESTFN)
860 try:
861 subdir = os.path.join(TESTFN, "subdir")
862 os.mkdir(subdir)
863 pipe = os.path.join(subdir, "mypipe")
864 os.mkfifo(pipe)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000865 try:
Serhiy Storchaka43767632013-11-03 21:31:38 +0200866 shutil.copytree(TESTFN, TESTFN2)
867 except shutil.Error as e:
868 errors = e.args[0]
869 self.assertEqual(len(errors), 1)
870 src, dst, error_msg = errors[0]
871 self.assertEqual("`%s` is a named pipe" % pipe, error_msg)
872 else:
873 self.fail("shutil.Error should have been raised")
874 finally:
875 shutil.rmtree(TESTFN, ignore_errors=True)
876 shutil.rmtree(TESTFN2, ignore_errors=True)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000877
Tarek Ziadé5340db32010-04-19 22:30:51 +0000878 def test_copytree_special_func(self):
879
880 src_dir = self.mkdtemp()
881 dst_dir = os.path.join(self.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200882 write_file((src_dir, 'test.txt'), '123')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000883 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é5340db32010-04-19 22:30:51 +0000885
886 copied = []
887 def _copy(src, dst):
888 copied.append((src, dst))
889
890 shutil.copytree(src_dir, dst_dir, copy_function=_copy)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000891 self.assertEqual(len(copied), 2)
Tarek Ziadé5340db32010-04-19 22:30:51 +0000892
Brian Curtin3b4499c2010-12-28 14:31:47 +0000893 @support.skip_unless_symlink
Tarek Ziadéfb437512010-04-20 08:57:33 +0000894 def test_copytree_dangling_symlinks(self):
895
896 # a dangling symlink raises an error at the end
897 src_dir = self.mkdtemp()
898 dst_dir = os.path.join(self.mkdtemp(), 'destination')
899 os.symlink('IDONTEXIST', os.path.join(src_dir, 'test.txt'))
900 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200901 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadéfb437512010-04-20 08:57:33 +0000902 self.assertRaises(Error, shutil.copytree, src_dir, dst_dir)
903
904 # a dangling symlink is ignored with the proper flag
905 dst_dir = os.path.join(self.mkdtemp(), 'destination2')
906 shutil.copytree(src_dir, dst_dir, ignore_dangling_symlinks=True)
907 self.assertNotIn('test.txt', os.listdir(dst_dir))
908
909 # a dangling symlink is copied if symlinks=True
910 dst_dir = os.path.join(self.mkdtemp(), 'destination3')
911 shutil.copytree(src_dir, dst_dir, symlinks=True)
912 self.assertIn('test.txt', os.listdir(dst_dir))
913
Berker Peksag5a294d82015-07-25 14:53:48 +0300914 @support.skip_unless_symlink
915 def test_copytree_symlink_dir(self):
916 src_dir = self.mkdtemp()
917 dst_dir = os.path.join(self.mkdtemp(), 'destination')
918 os.mkdir(os.path.join(src_dir, 'real_dir'))
919 with open(os.path.join(src_dir, 'real_dir', 'test.txt'), 'w'):
920 pass
921 os.symlink(os.path.join(src_dir, 'real_dir'),
922 os.path.join(src_dir, 'link_to_dir'),
923 target_is_directory=True)
924
925 shutil.copytree(src_dir, dst_dir, symlinks=False)
926 self.assertFalse(os.path.islink(os.path.join(dst_dir, 'link_to_dir')))
927 self.assertIn('test.txt', os.listdir(os.path.join(dst_dir, 'link_to_dir')))
928
929 dst_dir = os.path.join(self.mkdtemp(), 'destination2')
930 shutil.copytree(src_dir, dst_dir, symlinks=True)
931 self.assertTrue(os.path.islink(os.path.join(dst_dir, 'link_to_dir')))
932 self.assertIn('test.txt', os.listdir(os.path.join(dst_dir, 'link_to_dir')))
933
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400934 def _copy_file(self, method):
935 fname = 'test.txt'
936 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200937 write_file((tmpdir, fname), 'xxx')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400938 file1 = os.path.join(tmpdir, fname)
939 tmpdir2 = self.mkdtemp()
940 method(file1, tmpdir2)
941 file2 = os.path.join(tmpdir2, fname)
942 return (file1, file2)
943
944 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
945 def test_copy(self):
946 # Ensure that the copied file exists and has the same mode bits.
947 file1, file2 = self._copy_file(shutil.copy)
948 self.assertTrue(os.path.exists(file2))
949 self.assertEqual(os.stat(file1).st_mode, os.stat(file2).st_mode)
950
951 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
Senthil Kumaran0c2dba52011-07-03 18:21:38 -0700952 @unittest.skipUnless(hasattr(os, 'utime'), 'requires os.utime')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400953 def test_copy2(self):
954 # Ensure that the copied file exists and has the same mode and
955 # modification time bits.
956 file1, file2 = self._copy_file(shutil.copy2)
957 self.assertTrue(os.path.exists(file2))
958 file1_stat = os.stat(file1)
959 file2_stat = os.stat(file2)
960 self.assertEqual(file1_stat.st_mode, file2_stat.st_mode)
961 for attr in 'st_atime', 'st_mtime':
962 # The modification times may be truncated in the new file.
963 self.assertLessEqual(getattr(file1_stat, attr),
964 getattr(file2_stat, attr) + 1)
965 if hasattr(os, 'chflags') and hasattr(file1_stat, 'st_flags'):
966 self.assertEqual(getattr(file1_stat, 'st_flags'),
967 getattr(file2_stat, 'st_flags'))
968
Ezio Melotti975077a2011-05-19 22:03:22 +0300969 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000970 def test_make_tarball(self):
971 # creating something to tar
Serhiy Storchaka527ef072015-09-06 18:33:19 +0300972 root_dir, base_dir = self._create_files('')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000973
974 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400975 # force shutil to create the directory
976 os.rmdir(tmpdir2)
Serhiy Storchakaeba8fee2015-09-07 19:58:23 +0300977 # working with relative paths
978 work_dir = os.path.dirname(tmpdir2)
979 rel_base_name = os.path.join(os.path.basename(tmpdir2), 'archive')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000980
Serhiy Storchakaeba8fee2015-09-07 19:58:23 +0300981 with support.change_cwd(work_dir):
Serhiy Storchaka5558d4f2015-09-08 09:59:02 +0300982 base_name = os.path.abspath(rel_base_name)
Serhiy Storchakaeba8fee2015-09-07 19:58:23 +0300983 tarball = make_archive(rel_base_name, 'gztar', root_dir, '.')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000984
985 # check if the compressed tarball was created
Serhiy Storchakaa091a822015-09-07 13:55:25 +0300986 self.assertEqual(tarball, base_name + '.tar.gz')
Serhiy Storchaka527ef072015-09-06 18:33:19 +0300987 self.assertTrue(os.path.isfile(tarball))
988 self.assertTrue(tarfile.is_tarfile(tarball))
989 with tarfile.open(tarball, 'r:gz') as tf:
990 self.assertCountEqual(tf.getnames(),
991 ['.', './sub', './sub2',
992 './file1', './file2', './sub/file3'])
Tarek Ziadé396fad72010-02-23 05:30:31 +0000993
994 # trying an uncompressed one
Serhiy Storchakaeba8fee2015-09-07 19:58:23 +0300995 with support.change_cwd(work_dir):
996 tarball = make_archive(rel_base_name, 'tar', root_dir, '.')
Serhiy Storchakaa091a822015-09-07 13:55:25 +0300997 self.assertEqual(tarball, base_name + '.tar')
Serhiy Storchaka527ef072015-09-06 18:33:19 +0300998 self.assertTrue(os.path.isfile(tarball))
999 self.assertTrue(tarfile.is_tarfile(tarball))
1000 with tarfile.open(tarball, 'r') as tf:
1001 self.assertCountEqual(tf.getnames(),
1002 ['.', './sub', './sub2',
1003 './file1', './file2', './sub/file3'])
Tarek Ziadé396fad72010-02-23 05:30:31 +00001004
1005 def _tarinfo(self, path):
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001006 with tarfile.open(path) as tar:
Tarek Ziadé396fad72010-02-23 05:30:31 +00001007 names = tar.getnames()
1008 names.sort()
1009 return tuple(names)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001010
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001011 def _create_files(self, base_dir='dist'):
Tarek Ziadé396fad72010-02-23 05:30:31 +00001012 # creating something to tar
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001013 root_dir = self.mkdtemp()
1014 dist = os.path.join(root_dir, base_dir)
1015 os.makedirs(dist, exist_ok=True)
Éric Araujoa7e33a12011-08-12 19:51:35 +02001016 write_file((dist, 'file1'), 'xxx')
1017 write_file((dist, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +00001018 os.mkdir(os.path.join(dist, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +02001019 write_file((dist, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +00001020 os.mkdir(os.path.join(dist, 'sub2'))
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001021 if base_dir:
1022 write_file((root_dir, 'outer'), 'xxx')
1023 return root_dir, base_dir
Tarek Ziadé396fad72010-02-23 05:30:31 +00001024
Ezio Melotti975077a2011-05-19 22:03:22 +03001025 @requires_zlib
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001026 @unittest.skipUnless(find_executable('tar'),
Tarek Ziadé396fad72010-02-23 05:30:31 +00001027 'Need the tar command to run')
1028 def test_tarfile_vs_tar(self):
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001029 root_dir, base_dir = self._create_files()
1030 base_name = os.path.join(self.mkdtemp(), 'archive')
Serhiy Storchakaa091a822015-09-07 13:55:25 +03001031 tarball = make_archive(base_name, 'gztar', root_dir, base_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001032
1033 # check if the compressed tarball was created
Serhiy Storchakaa091a822015-09-07 13:55:25 +03001034 self.assertEqual(tarball, base_name + '.tar.gz')
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001035 self.assertTrue(os.path.isfile(tarball))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001036
1037 # now create another tarball using `tar`
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001038 tarball2 = os.path.join(root_dir, 'archive2.tar')
1039 tar_cmd = ['tar', '-cf', 'archive2.tar', base_dir]
1040 with support.change_cwd(root_dir), captured_stdout():
1041 spawn(tar_cmd)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001042
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001043 self.assertTrue(os.path.isfile(tarball2))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001044 # let's compare both tarballs
Ezio Melottib3aedd42010-11-20 19:04:17 +00001045 self.assertEqual(self._tarinfo(tarball), self._tarinfo(tarball2))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001046
1047 # trying an uncompressed one
Serhiy Storchakaa091a822015-09-07 13:55:25 +03001048 tarball = make_archive(base_name, 'tar', root_dir, base_dir)
1049 self.assertEqual(tarball, base_name + '.tar')
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001050 self.assertTrue(os.path.isfile(tarball))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001051
1052 # now for a dry_run
Serhiy Storchakaa091a822015-09-07 13:55:25 +03001053 tarball = make_archive(base_name, 'tar', root_dir, base_dir,
1054 dry_run=True)
1055 self.assertEqual(tarball, base_name + '.tar')
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001056 self.assertTrue(os.path.isfile(tarball))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001057
Ezio Melotti975077a2011-05-19 22:03:22 +03001058 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001059 @unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run')
1060 def test_make_zipfile(self):
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001061 # creating something to zip
1062 root_dir, base_dir = self._create_files()
Serhiy Storchakaeba8fee2015-09-07 19:58:23 +03001063
1064 tmpdir2 = self.mkdtemp()
1065 # force shutil to create the directory
1066 os.rmdir(tmpdir2)
1067 # working with relative paths
1068 work_dir = os.path.dirname(tmpdir2)
1069 rel_base_name = os.path.join(os.path.basename(tmpdir2), 'archive')
Serhiy Storchakaeba8fee2015-09-07 19:58:23 +03001070
1071 with support.change_cwd(work_dir):
Serhiy Storchaka5558d4f2015-09-08 09:59:02 +03001072 base_name = os.path.abspath(rel_base_name)
Serhiy Storchaka2504cec2015-09-08 05:47:23 +03001073 res = make_archive(rel_base_name, 'zip', root_dir, base_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001074
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001075 self.assertEqual(res, base_name + '.zip')
1076 self.assertTrue(os.path.isfile(res))
1077 self.assertTrue(zipfile.is_zipfile(res))
1078 with zipfile.ZipFile(res) as zf:
1079 self.assertCountEqual(zf.namelist(),
Serhiy Storchaka2504cec2015-09-08 05:47:23 +03001080 ['dist/', 'dist/sub/', 'dist/sub2/',
1081 'dist/file1', 'dist/file2', 'dist/sub/file3'])
Tarek Ziadé396fad72010-02-23 05:30:31 +00001082
Serhiy Storchaka2504cec2015-09-08 05:47:23 +03001083 @requires_zlib
1084 @unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run')
1085 @unittest.skipUnless(find_executable('zip'),
1086 'Need the zip command to run')
1087 def test_zipfile_vs_zip(self):
1088 root_dir, base_dir = self._create_files()
1089 base_name = os.path.join(self.mkdtemp(), 'archive')
1090 archive = make_archive(base_name, 'zip', root_dir, base_dir)
1091
1092 # check if ZIP file was created
1093 self.assertEqual(archive, base_name + '.zip')
1094 self.assertTrue(os.path.isfile(archive))
1095
1096 # now create another ZIP file using `zip`
1097 archive2 = os.path.join(root_dir, 'archive2.zip')
1098 zip_cmd = ['zip', '-q', '-r', 'archive2.zip', base_dir]
1099 with support.change_cwd(root_dir):
1100 spawn(zip_cmd)
1101
1102 self.assertTrue(os.path.isfile(archive2))
1103 # let's compare both ZIP files
1104 with zipfile.ZipFile(archive) as zf:
1105 names = zf.namelist()
1106 with zipfile.ZipFile(archive2) as zf:
1107 names2 = zf.namelist()
1108 self.assertEqual(sorted(names), sorted(names2))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001109
1110 def test_make_archive(self):
1111 tmpdir = self.mkdtemp()
1112 base_name = os.path.join(tmpdir, 'archive')
1113 self.assertRaises(ValueError, make_archive, base_name, 'xxx')
1114
Ezio Melotti975077a2011-05-19 22:03:22 +03001115 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001116 def test_make_archive_owner_group(self):
1117 # testing make_archive with owner and group, with various combinations
1118 # this works even if there's not gid/uid support
1119 if UID_GID_SUPPORT:
1120 group = grp.getgrgid(0)[0]
1121 owner = pwd.getpwuid(0)[0]
1122 else:
1123 group = owner = 'root'
1124
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001125 root_dir, base_dir = self._create_files()
1126 base_name = os.path.join(self.mkdtemp(), 'archive')
Tarek Ziadé396fad72010-02-23 05:30:31 +00001127 res = make_archive(base_name, 'zip', root_dir, base_dir, owner=owner,
1128 group=group)
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001129 self.assertTrue(os.path.isfile(res))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001130
1131 res = make_archive(base_name, 'zip', root_dir, base_dir)
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001132 self.assertTrue(os.path.isfile(res))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001133
1134 res = make_archive(base_name, 'tar', root_dir, base_dir,
1135 owner=owner, group=group)
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001136 self.assertTrue(os.path.isfile(res))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001137
1138 res = make_archive(base_name, 'tar', root_dir, base_dir,
1139 owner='kjhkjhkjg', group='oihohoh')
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001140 self.assertTrue(os.path.isfile(res))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001141
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001142
Ezio Melotti975077a2011-05-19 22:03:22 +03001143 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001144 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1145 def test_tarfile_root_owner(self):
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001146 root_dir, base_dir = self._create_files()
1147 base_name = os.path.join(self.mkdtemp(), 'archive')
Tarek Ziadé396fad72010-02-23 05:30:31 +00001148 group = grp.getgrgid(0)[0]
1149 owner = pwd.getpwuid(0)[0]
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001150 with support.change_cwd(root_dir):
1151 archive_name = make_archive(base_name, 'gztar', root_dir, 'dist',
1152 owner=owner, group=group)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001153
1154 # check if the compressed tarball was created
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001155 self.assertTrue(os.path.isfile(archive_name))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001156
1157 # now checks the rights
1158 archive = tarfile.open(archive_name)
1159 try:
1160 for member in archive.getmembers():
Ezio Melottib3aedd42010-11-20 19:04:17 +00001161 self.assertEqual(member.uid, 0)
1162 self.assertEqual(member.gid, 0)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001163 finally:
1164 archive.close()
1165
1166 def test_make_archive_cwd(self):
1167 current_dir = os.getcwd()
1168 def _breaks(*args, **kw):
1169 raise RuntimeError()
1170
1171 register_archive_format('xxx', _breaks, [], 'xxx file')
1172 try:
1173 try:
1174 make_archive('xxx', 'xxx', root_dir=self.mkdtemp())
1175 except Exception:
1176 pass
Ezio Melottib3aedd42010-11-20 19:04:17 +00001177 self.assertEqual(os.getcwd(), current_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001178 finally:
1179 unregister_archive_format('xxx')
1180
Serhiy Storchaka9a4fc192014-11-28 00:48:46 +02001181 def test_make_tarfile_in_curdir(self):
1182 # Issue #21280
1183 root_dir = self.mkdtemp()
1184 with support.change_cwd(root_dir):
1185 self.assertEqual(make_archive('test', 'tar'), 'test.tar')
1186 self.assertTrue(os.path.isfile('test.tar'))
1187
1188 @requires_zlib
1189 def test_make_zipfile_in_curdir(self):
1190 # Issue #21280
1191 root_dir = self.mkdtemp()
1192 with support.change_cwd(root_dir):
1193 self.assertEqual(make_archive('test', 'zip'), 'test.zip')
1194 self.assertTrue(os.path.isfile('test.zip'))
1195
Tarek Ziadé396fad72010-02-23 05:30:31 +00001196 def test_register_archive_format(self):
1197
1198 self.assertRaises(TypeError, register_archive_format, 'xxx', 1)
1199 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1200 1)
1201 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1202 [(1, 2), (1, 2, 3)])
1203
1204 register_archive_format('xxx', lambda: x, [(1, 2)], 'xxx file')
1205 formats = [name for name, params in get_archive_formats()]
1206 self.assertIn('xxx', formats)
1207
1208 unregister_archive_format('xxx')
1209 formats = [name for name, params in get_archive_formats()]
1210 self.assertNotIn('xxx', formats)
1211
Ezio Melotti975077a2011-05-19 22:03:22 +03001212 @requires_zlib
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001213 def test_unpack_archive(self):
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001214 formats = ['tar', 'gztar', 'zip']
1215 if BZ2_SUPPORTED:
1216 formats.append('bztar')
Serhiy Storchaka11213772014-08-06 18:50:19 +03001217 if LZMA_SUPPORTED:
1218 formats.append('xztar')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001219
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001220 root_dir, base_dir = self._create_files()
Serhiy Storchaka2504cec2015-09-08 05:47:23 +03001221 expected = rlistdir(root_dir)
1222 expected.remove('outer')
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001223 for format in formats:
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001224 base_name = os.path.join(self.mkdtemp(), 'archive')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001225 filename = make_archive(base_name, format, root_dir, base_dir)
1226
1227 # let's try to unpack it now
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001228 tmpdir2 = self.mkdtemp()
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001229 unpack_archive(filename, tmpdir2)
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001230 self.assertEqual(rlistdir(tmpdir2), expected)
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001231
Nick Coghlanabf202d2011-03-16 13:52:20 -04001232 # and again, this time with the format specified
1233 tmpdir3 = self.mkdtemp()
1234 unpack_archive(filename, tmpdir3, format=format)
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001235 self.assertEqual(rlistdir(tmpdir3), expected)
Nick Coghlanabf202d2011-03-16 13:52:20 -04001236 self.assertRaises(shutil.ReadError, unpack_archive, TESTFN)
1237 self.assertRaises(ValueError, unpack_archive, TESTFN, format='xxx')
1238
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001239 def test_unpack_registery(self):
1240
1241 formats = get_unpack_formats()
1242
1243 def _boo(filename, extract_dir, extra):
Ezio Melottib3aedd42010-11-20 19:04:17 +00001244 self.assertEqual(extra, 1)
1245 self.assertEqual(filename, 'stuff.boo')
1246 self.assertEqual(extract_dir, 'xx')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001247
1248 register_unpack_format('Boo', ['.boo', '.b2'], _boo, [('extra', 1)])
1249 unpack_archive('stuff.boo', 'xx')
1250
1251 # trying to register a .boo unpacker again
1252 self.assertRaises(RegistryError, register_unpack_format, 'Boo2',
1253 ['.boo'], _boo)
1254
1255 # should work now
1256 unregister_unpack_format('Boo')
1257 register_unpack_format('Boo2', ['.boo'], _boo)
1258 self.assertIn(('Boo2', ['.boo'], ''), get_unpack_formats())
1259 self.assertNotIn(('Boo', ['.boo'], ''), get_unpack_formats())
1260
1261 # let's leave a clean state
1262 unregister_unpack_format('Boo2')
Ezio Melottib3aedd42010-11-20 19:04:17 +00001263 self.assertEqual(get_unpack_formats(), formats)
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001264
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001265 @unittest.skipUnless(hasattr(shutil, 'disk_usage'),
1266 "disk_usage not available on this platform")
1267 def test_disk_usage(self):
1268 usage = shutil.disk_usage(os.getcwd())
Éric Araujo2ee61882011-07-02 16:45:45 +02001269 self.assertGreater(usage.total, 0)
1270 self.assertGreater(usage.used, 0)
1271 self.assertGreaterEqual(usage.free, 0)
1272 self.assertGreaterEqual(usage.total, usage.used)
1273 self.assertGreater(usage.total, usage.free)
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001274
Sandro Tosid902a142011-08-22 23:28:27 +02001275 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1276 @unittest.skipUnless(hasattr(os, 'chown'), 'requires os.chown')
1277 def test_chown(self):
1278
1279 # cleaned-up automatically by TestShutil.tearDown method
1280 dirname = self.mkdtemp()
1281 filename = tempfile.mktemp(dir=dirname)
1282 write_file(filename, 'testing chown function')
1283
1284 with self.assertRaises(ValueError):
1285 shutil.chown(filename)
1286
1287 with self.assertRaises(LookupError):
1288 shutil.chown(filename, user='non-exising username')
1289
1290 with self.assertRaises(LookupError):
1291 shutil.chown(filename, group='non-exising groupname')
1292
1293 with self.assertRaises(TypeError):
1294 shutil.chown(filename, b'spam')
1295
1296 with self.assertRaises(TypeError):
1297 shutil.chown(filename, 3.14)
1298
1299 uid = os.getuid()
1300 gid = os.getgid()
1301
1302 def check_chown(path, uid=None, gid=None):
1303 s = os.stat(filename)
1304 if uid is not None:
1305 self.assertEqual(uid, s.st_uid)
1306 if gid is not None:
1307 self.assertEqual(gid, s.st_gid)
1308
1309 shutil.chown(filename, uid, gid)
1310 check_chown(filename, uid, gid)
1311 shutil.chown(filename, uid)
1312 check_chown(filename, uid)
1313 shutil.chown(filename, user=uid)
1314 check_chown(filename, uid)
1315 shutil.chown(filename, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001316 check_chown(filename, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001317
1318 shutil.chown(dirname, uid, gid)
1319 check_chown(dirname, uid, gid)
1320 shutil.chown(dirname, uid)
1321 check_chown(dirname, uid)
1322 shutil.chown(dirname, user=uid)
1323 check_chown(dirname, uid)
1324 shutil.chown(dirname, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001325 check_chown(dirname, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001326
1327 user = pwd.getpwuid(uid)[0]
1328 group = grp.getgrgid(gid)[0]
1329 shutil.chown(filename, user, group)
1330 check_chown(filename, uid, gid)
1331 shutil.chown(dirname, user, group)
1332 check_chown(dirname, uid, gid)
1333
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001334 def test_copy_return_value(self):
1335 # copy and copy2 both return their destination path.
1336 for fn in (shutil.copy, shutil.copy2):
1337 src_dir = self.mkdtemp()
1338 dst_dir = self.mkdtemp()
1339 src = os.path.join(src_dir, 'foo')
1340 write_file(src, 'foo')
1341 rv = fn(src, dst_dir)
1342 self.assertEqual(rv, os.path.join(dst_dir, 'foo'))
1343 rv = fn(src, os.path.join(dst_dir, 'bar'))
1344 self.assertEqual(rv, os.path.join(dst_dir, 'bar'))
1345
1346 def test_copyfile_return_value(self):
1347 # copytree returns its destination path.
1348 src_dir = self.mkdtemp()
1349 dst_dir = self.mkdtemp()
1350 dst_file = os.path.join(dst_dir, 'bar')
1351 src_file = os.path.join(src_dir, 'foo')
1352 write_file(src_file, 'foo')
1353 rv = shutil.copyfile(src_file, dst_file)
1354 self.assertTrue(os.path.exists(rv))
1355 self.assertEqual(read_file(src_file), read_file(dst_file))
1356
Hynek Schlawack48653762012-10-07 12:49:58 +02001357 def test_copyfile_same_file(self):
1358 # copyfile() should raise SameFileError if the source and destination
1359 # are the same.
1360 src_dir = self.mkdtemp()
1361 src_file = os.path.join(src_dir, 'foo')
1362 write_file(src_file, 'foo')
1363 self.assertRaises(SameFileError, shutil.copyfile, src_file, src_file)
Hynek Schlawack27ddb572012-10-28 13:59:27 +01001364 # But Error should work too, to stay backward compatible.
1365 self.assertRaises(Error, shutil.copyfile, src_file, src_file)
Hynek Schlawack48653762012-10-07 12:49:58 +02001366
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001367 def test_copytree_return_value(self):
1368 # copytree returns its destination path.
1369 src_dir = self.mkdtemp()
1370 dst_dir = src_dir + "dest"
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001371 self.addCleanup(shutil.rmtree, dst_dir, True)
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001372 src = os.path.join(src_dir, 'foo')
1373 write_file(src, 'foo')
1374 rv = shutil.copytree(src_dir, dst_dir)
1375 self.assertEqual(['foo'], os.listdir(rv))
1376
Christian Heimes9bd667a2008-01-20 15:14:11 +00001377
Brian Curtinc57a3452012-06-22 16:00:30 -05001378class TestWhich(unittest.TestCase):
1379
1380 def setUp(self):
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001381 self.temp_dir = tempfile.mkdtemp(prefix="Tmp")
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001382 self.addCleanup(shutil.rmtree, self.temp_dir, True)
Brian Curtinc57a3452012-06-22 16:00:30 -05001383 # Give the temp_file an ".exe" suffix for all.
1384 # It's needed on Windows and not harmful on other platforms.
1385 self.temp_file = tempfile.NamedTemporaryFile(dir=self.temp_dir,
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001386 prefix="Tmp",
1387 suffix=".Exe")
Brian Curtinc57a3452012-06-22 16:00:30 -05001388 os.chmod(self.temp_file.name, stat.S_IXUSR)
1389 self.addCleanup(self.temp_file.close)
1390 self.dir, self.file = os.path.split(self.temp_file.name)
1391
1392 def test_basic(self):
1393 # Given an EXE in a directory, it should be returned.
1394 rv = shutil.which(self.file, path=self.dir)
1395 self.assertEqual(rv, self.temp_file.name)
1396
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001397 def test_absolute_cmd(self):
Brian Curtinc57a3452012-06-22 16:00:30 -05001398 # When given the fully qualified path to an executable that exists,
1399 # it should be returned.
1400 rv = shutil.which(self.temp_file.name, path=self.temp_dir)
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001401 self.assertEqual(rv, self.temp_file.name)
1402
1403 def test_relative_cmd(self):
1404 # When given the relative path with a directory part to an executable
1405 # that exists, it should be returned.
1406 base_dir, tail_dir = os.path.split(self.dir)
1407 relpath = os.path.join(tail_dir, self.file)
Nick Coghlan55175962013-07-28 22:11:50 +10001408 with support.change_cwd(path=base_dir):
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001409 rv = shutil.which(relpath, path=self.temp_dir)
1410 self.assertEqual(rv, relpath)
1411 # But it shouldn't be searched in PATH directories (issue #16957).
Nick Coghlan55175962013-07-28 22:11:50 +10001412 with support.change_cwd(path=self.dir):
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001413 rv = shutil.which(relpath, path=base_dir)
1414 self.assertIsNone(rv)
1415
1416 def test_cwd(self):
1417 # Issue #16957
1418 base_dir = os.path.dirname(self.dir)
Nick Coghlan55175962013-07-28 22:11:50 +10001419 with support.change_cwd(path=self.dir):
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001420 rv = shutil.which(self.file, path=base_dir)
1421 if sys.platform == "win32":
1422 # Windows: current directory implicitly on PATH
1423 self.assertEqual(rv, os.path.join(os.curdir, self.file))
1424 else:
1425 # Other platforms: shouldn't match in the current directory.
1426 self.assertIsNone(rv)
Brian Curtinc57a3452012-06-22 16:00:30 -05001427
Serhiy Storchaka12516e22013-05-28 15:50:15 +03001428 @unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0,
1429 'non-root user required')
Brian Curtinc57a3452012-06-22 16:00:30 -05001430 def test_non_matching_mode(self):
1431 # Set the file read-only and ask for writeable files.
1432 os.chmod(self.temp_file.name, stat.S_IREAD)
Serhiy Storchaka12516e22013-05-28 15:50:15 +03001433 if os.access(self.temp_file.name, os.W_OK):
1434 self.skipTest("can't set the file read-only")
Brian Curtinc57a3452012-06-22 16:00:30 -05001435 rv = shutil.which(self.file, path=self.dir, mode=os.W_OK)
1436 self.assertIsNone(rv)
1437
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001438 def test_relative_path(self):
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001439 base_dir, tail_dir = os.path.split(self.dir)
Nick Coghlan55175962013-07-28 22:11:50 +10001440 with support.change_cwd(path=base_dir):
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001441 rv = shutil.which(self.file, path=tail_dir)
1442 self.assertEqual(rv, os.path.join(tail_dir, self.file))
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001443
Brian Curtinc57a3452012-06-22 16:00:30 -05001444 def test_nonexistent_file(self):
1445 # Return None when no matching executable file is found on the path.
1446 rv = shutil.which("foo.exe", path=self.dir)
1447 self.assertIsNone(rv)
1448
1449 @unittest.skipUnless(sys.platform == "win32",
1450 "pathext check is Windows-only")
1451 def test_pathext_checking(self):
1452 # Ask for the file without the ".exe" extension, then ensure that
1453 # it gets found properly with the extension.
Serhiy Storchakad70127a2013-01-24 20:03:49 +02001454 rv = shutil.which(self.file[:-4], path=self.dir)
Serhiy Storchaka80c88f42013-01-22 10:31:36 +02001455 self.assertEqual(rv, self.temp_file.name[:-4] + ".EXE")
Brian Curtinc57a3452012-06-22 16:00:30 -05001456
Barry Warsaw618738b2013-04-16 11:05:03 -04001457 def test_environ_path(self):
1458 with support.EnvironmentVarGuard() as env:
Victor Stinner1d006a22013-12-16 23:39:40 +01001459 env['PATH'] = self.dir
Barry Warsaw618738b2013-04-16 11:05:03 -04001460 rv = shutil.which(self.file)
1461 self.assertEqual(rv, self.temp_file.name)
1462
1463 def test_empty_path(self):
1464 base_dir = os.path.dirname(self.dir)
Nick Coghlan55175962013-07-28 22:11:50 +10001465 with support.change_cwd(path=self.dir), \
Barry Warsaw618738b2013-04-16 11:05:03 -04001466 support.EnvironmentVarGuard() as env:
Victor Stinner1d006a22013-12-16 23:39:40 +01001467 env['PATH'] = self.dir
Barry Warsaw618738b2013-04-16 11:05:03 -04001468 rv = shutil.which(self.file, path='')
1469 self.assertIsNone(rv)
1470
1471 def test_empty_path_no_PATH(self):
1472 with support.EnvironmentVarGuard() as env:
1473 env.pop('PATH', None)
1474 rv = shutil.which(self.file)
1475 self.assertIsNone(rv)
1476
Brian Curtinc57a3452012-06-22 16:00:30 -05001477
Christian Heimesada8c3b2008-03-18 18:26:33 +00001478class TestMove(unittest.TestCase):
1479
1480 def setUp(self):
1481 filename = "foo"
1482 self.src_dir = tempfile.mkdtemp()
1483 self.dst_dir = tempfile.mkdtemp()
1484 self.src_file = os.path.join(self.src_dir, filename)
1485 self.dst_file = os.path.join(self.dst_dir, filename)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001486 with open(self.src_file, "wb") as f:
1487 f.write(b"spam")
1488
1489 def tearDown(self):
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001490 for d in (self.src_dir, self.dst_dir):
Christian Heimesada8c3b2008-03-18 18:26:33 +00001491 try:
1492 if d:
1493 shutil.rmtree(d)
1494 except:
1495 pass
1496
1497 def _check_move_file(self, src, dst, real_dst):
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001498 with open(src, "rb") as f:
1499 contents = f.read()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001500 shutil.move(src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001501 with open(real_dst, "rb") as f:
1502 self.assertEqual(contents, f.read())
Christian Heimesada8c3b2008-03-18 18:26:33 +00001503 self.assertFalse(os.path.exists(src))
1504
1505 def _check_move_dir(self, src, dst, real_dst):
1506 contents = sorted(os.listdir(src))
1507 shutil.move(src, dst)
1508 self.assertEqual(contents, sorted(os.listdir(real_dst)))
1509 self.assertFalse(os.path.exists(src))
1510
1511 def test_move_file(self):
1512 # Move a file to another location on the same filesystem.
1513 self._check_move_file(self.src_file, self.dst_file, self.dst_file)
1514
1515 def test_move_file_to_dir(self):
1516 # Move a file inside an existing dir on the same filesystem.
1517 self._check_move_file(self.src_file, self.dst_dir, self.dst_file)
1518
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001519 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001520 def test_move_file_other_fs(self):
1521 # Move a file to an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001522 self.test_move_file()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001523
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001524 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001525 def test_move_file_to_dir_other_fs(self):
1526 # Move a file to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001527 self.test_move_file_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001528
1529 def test_move_dir(self):
1530 # Move a dir to another location on the same filesystem.
1531 dst_dir = tempfile.mktemp()
1532 try:
1533 self._check_move_dir(self.src_dir, dst_dir, dst_dir)
1534 finally:
1535 try:
1536 shutil.rmtree(dst_dir)
1537 except:
1538 pass
1539
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001540 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001541 def test_move_dir_other_fs(self):
1542 # Move a dir to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001543 self.test_move_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001544
1545 def test_move_dir_to_dir(self):
1546 # Move a dir inside an existing dir on the same filesystem.
1547 self._check_move_dir(self.src_dir, self.dst_dir,
1548 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1549
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001550 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001551 def test_move_dir_to_dir_other_fs(self):
1552 # Move a dir inside an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001553 self.test_move_dir_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001554
Serhiy Storchaka3a308b92014-02-11 10:30:59 +02001555 def test_move_dir_sep_to_dir(self):
1556 self._check_move_dir(self.src_dir + os.path.sep, self.dst_dir,
1557 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1558
1559 @unittest.skipUnless(os.path.altsep, 'requires os.path.altsep')
1560 def test_move_dir_altsep_to_dir(self):
1561 self._check_move_dir(self.src_dir + os.path.altsep, self.dst_dir,
1562 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1563
Christian Heimesada8c3b2008-03-18 18:26:33 +00001564 def test_existing_file_inside_dest_dir(self):
1565 # A file with the same name inside the destination dir already exists.
1566 with open(self.dst_file, "wb"):
1567 pass
1568 self.assertRaises(shutil.Error, shutil.move, self.src_file, self.dst_dir)
1569
1570 def test_dont_move_dir_in_itself(self):
1571 # Moving a dir inside itself raises an Error.
1572 dst = os.path.join(self.src_dir, "bar")
1573 self.assertRaises(shutil.Error, shutil.move, self.src_dir, dst)
1574
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001575 def test_destinsrc_false_negative(self):
1576 os.mkdir(TESTFN)
1577 try:
1578 for src, dst in [('srcdir', 'srcdir/dest')]:
1579 src = os.path.join(TESTFN, src)
1580 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001581 self.assertTrue(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001582 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001583 'dst (%s) is not in src (%s)' % (dst, src))
1584 finally:
1585 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001586
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001587 def test_destinsrc_false_positive(self):
1588 os.mkdir(TESTFN)
1589 try:
1590 for src, dst in [('srcdir', 'src/dest'), ('srcdir', 'srcdir.new')]:
1591 src = os.path.join(TESTFN, src)
1592 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001593 self.assertFalse(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001594 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001595 'dst (%s) is in src (%s)' % (dst, src))
1596 finally:
1597 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimes9bd667a2008-01-20 15:14:11 +00001598
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +01001599 @support.skip_unless_symlink
1600 @mock_rename
1601 def test_move_file_symlink(self):
1602 dst = os.path.join(self.src_dir, 'bar')
1603 os.symlink(self.src_file, dst)
1604 shutil.move(dst, self.dst_file)
1605 self.assertTrue(os.path.islink(self.dst_file))
1606 self.assertTrue(os.path.samefile(self.src_file, self.dst_file))
1607
1608 @support.skip_unless_symlink
1609 @mock_rename
1610 def test_move_file_symlink_to_dir(self):
1611 filename = "bar"
1612 dst = os.path.join(self.src_dir, filename)
1613 os.symlink(self.src_file, dst)
1614 shutil.move(dst, self.dst_dir)
1615 final_link = os.path.join(self.dst_dir, filename)
1616 self.assertTrue(os.path.islink(final_link))
1617 self.assertTrue(os.path.samefile(self.src_file, final_link))
1618
1619 @support.skip_unless_symlink
1620 @mock_rename
1621 def test_move_dangling_symlink(self):
1622 src = os.path.join(self.src_dir, 'baz')
1623 dst = os.path.join(self.src_dir, 'bar')
1624 os.symlink(src, dst)
1625 dst_link = os.path.join(self.dst_dir, 'quux')
1626 shutil.move(dst, dst_link)
1627 self.assertTrue(os.path.islink(dst_link))
Antoine Pitrou3f48ac92014-01-01 02:50:45 +01001628 # On Windows, os.path.realpath does not follow symlinks (issue #9949)
1629 if os.name == 'nt':
1630 self.assertEqual(os.path.realpath(src), os.readlink(dst_link))
1631 else:
1632 self.assertEqual(os.path.realpath(src), os.path.realpath(dst_link))
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +01001633
1634 @support.skip_unless_symlink
1635 @mock_rename
1636 def test_move_dir_symlink(self):
1637 src = os.path.join(self.src_dir, 'baz')
1638 dst = os.path.join(self.src_dir, 'bar')
1639 os.mkdir(src)
1640 os.symlink(src, dst)
1641 dst_link = os.path.join(self.dst_dir, 'quux')
1642 shutil.move(dst, dst_link)
1643 self.assertTrue(os.path.islink(dst_link))
1644 self.assertTrue(os.path.samefile(src, dst_link))
1645
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001646 def test_move_return_value(self):
1647 rv = shutil.move(self.src_file, self.dst_dir)
1648 self.assertEqual(rv,
1649 os.path.join(self.dst_dir, os.path.basename(self.src_file)))
1650
1651 def test_move_as_rename_return_value(self):
1652 rv = shutil.move(self.src_file, os.path.join(self.dst_dir, 'bar'))
1653 self.assertEqual(rv, os.path.join(self.dst_dir, 'bar'))
1654
R David Murray6ffface2014-06-11 14:40:13 -04001655 @mock_rename
1656 def test_move_file_special_function(self):
1657 moved = []
1658 def _copy(src, dst):
1659 moved.append((src, dst))
1660 shutil.move(self.src_file, self.dst_dir, copy_function=_copy)
1661 self.assertEqual(len(moved), 1)
1662
1663 @mock_rename
1664 def test_move_dir_special_function(self):
1665 moved = []
1666 def _copy(src, dst):
1667 moved.append((src, dst))
1668 support.create_empty_file(os.path.join(self.src_dir, 'child'))
1669 support.create_empty_file(os.path.join(self.src_dir, 'child1'))
1670 shutil.move(self.src_dir, self.dst_dir, copy_function=_copy)
1671 self.assertEqual(len(moved), 3)
1672
Tarek Ziadé5340db32010-04-19 22:30:51 +00001673
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001674class TestCopyFile(unittest.TestCase):
1675
1676 _delete = False
1677
1678 class Faux(object):
1679 _entered = False
1680 _exited_with = None
1681 _raised = False
1682 def __init__(self, raise_in_exit=False, suppress_at_exit=True):
1683 self._raise_in_exit = raise_in_exit
1684 self._suppress_at_exit = suppress_at_exit
1685 def read(self, *args):
1686 return ''
1687 def __enter__(self):
1688 self._entered = True
1689 def __exit__(self, exc_type, exc_val, exc_tb):
1690 self._exited_with = exc_type, exc_val, exc_tb
1691 if self._raise_in_exit:
1692 self._raised = True
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001693 raise OSError("Cannot close")
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001694 return self._suppress_at_exit
1695
1696 def tearDown(self):
1697 if self._delete:
1698 del shutil.open
1699
1700 def _set_shutil_open(self, func):
1701 shutil.open = func
1702 self._delete = True
1703
1704 def test_w_source_open_fails(self):
1705 def _open(filename, mode='r'):
1706 if filename == 'srcfile':
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001707 raise OSError('Cannot open "srcfile"')
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001708 assert 0 # shouldn't reach here.
1709
1710 self._set_shutil_open(_open)
1711
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001712 self.assertRaises(OSError, shutil.copyfile, 'srcfile', 'destfile')
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001713
1714 def test_w_dest_open_fails(self):
1715
1716 srcfile = self.Faux()
1717
1718 def _open(filename, mode='r'):
1719 if filename == 'srcfile':
1720 return srcfile
1721 if filename == 'destfile':
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001722 raise OSError('Cannot open "destfile"')
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001723 assert 0 # shouldn't reach here.
1724
1725 self._set_shutil_open(_open)
1726
1727 shutil.copyfile('srcfile', 'destfile')
1728 self.assertTrue(srcfile._entered)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001729 self.assertTrue(srcfile._exited_with[0] is OSError)
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001730 self.assertEqual(srcfile._exited_with[1].args,
1731 ('Cannot open "destfile"',))
1732
1733 def test_w_dest_close_fails(self):
1734
1735 srcfile = self.Faux()
1736 destfile = self.Faux(True)
1737
1738 def _open(filename, mode='r'):
1739 if filename == 'srcfile':
1740 return srcfile
1741 if filename == 'destfile':
1742 return destfile
1743 assert 0 # shouldn't reach here.
1744
1745 self._set_shutil_open(_open)
1746
1747 shutil.copyfile('srcfile', 'destfile')
1748 self.assertTrue(srcfile._entered)
1749 self.assertTrue(destfile._entered)
1750 self.assertTrue(destfile._raised)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001751 self.assertTrue(srcfile._exited_with[0] is OSError)
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001752 self.assertEqual(srcfile._exited_with[1].args,
1753 ('Cannot close',))
1754
1755 def test_w_source_close_fails(self):
1756
1757 srcfile = self.Faux(True)
1758 destfile = self.Faux()
1759
1760 def _open(filename, mode='r'):
1761 if filename == 'srcfile':
1762 return srcfile
1763 if filename == 'destfile':
1764 return destfile
1765 assert 0 # shouldn't reach here.
1766
1767 self._set_shutil_open(_open)
1768
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001769 self.assertRaises(OSError,
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001770 shutil.copyfile, 'srcfile', 'destfile')
1771 self.assertTrue(srcfile._entered)
1772 self.assertTrue(destfile._entered)
1773 self.assertFalse(destfile._raised)
1774 self.assertTrue(srcfile._exited_with[0] is None)
1775 self.assertTrue(srcfile._raised)
1776
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001777 def test_move_dir_caseinsensitive(self):
1778 # Renames a folder to the same name
1779 # but a different case.
1780
1781 self.src_dir = tempfile.mkdtemp()
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001782 self.addCleanup(shutil.rmtree, self.src_dir, True)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001783 dst_dir = os.path.join(
1784 os.path.dirname(self.src_dir),
1785 os.path.basename(self.src_dir).upper())
1786 self.assertNotEqual(self.src_dir, dst_dir)
1787
1788 try:
1789 shutil.move(self.src_dir, dst_dir)
1790 self.assertTrue(os.path.isdir(dst_dir))
1791 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +02001792 os.rmdir(dst_dir)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001793
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001794class TermsizeTests(unittest.TestCase):
1795 def test_does_not_crash(self):
1796 """Check if get_terminal_size() returns a meaningful value.
1797
1798 There's no easy portable way to actually check the size of the
1799 terminal, so let's check if it returns something sensible instead.
1800 """
1801 size = shutil.get_terminal_size()
Antoine Pitroucfade362012-02-08 23:48:59 +01001802 self.assertGreaterEqual(size.columns, 0)
1803 self.assertGreaterEqual(size.lines, 0)
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001804
1805 def test_os_environ_first(self):
1806 "Check if environment variables have precedence"
1807
1808 with support.EnvironmentVarGuard() as env:
1809 env['COLUMNS'] = '777'
1810 size = shutil.get_terminal_size()
1811 self.assertEqual(size.columns, 777)
1812
1813 with support.EnvironmentVarGuard() as env:
1814 env['LINES'] = '888'
1815 size = shutil.get_terminal_size()
1816 self.assertEqual(size.lines, 888)
1817
1818 @unittest.skipUnless(os.isatty(sys.__stdout__.fileno()), "not on tty")
1819 def test_stty_match(self):
1820 """Check if stty returns the same results ignoring env
1821
1822 This test will fail if stdin and stdout are connected to
1823 different terminals with different sizes. Nevertheless, such
1824 situations should be pretty rare.
1825 """
1826 try:
1827 size = subprocess.check_output(['stty', 'size']).decode().split()
1828 except (FileNotFoundError, subprocess.CalledProcessError):
1829 self.skipTest("stty invocation failed")
1830 expected = (int(size[1]), int(size[0])) # reversed order
1831
1832 with support.EnvironmentVarGuard() as env:
1833 del env['LINES']
1834 del env['COLUMNS']
1835 actual = shutil.get_terminal_size()
1836
1837 self.assertEqual(expected, actual)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001838
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001839
Berker Peksag8083cd62014-11-01 11:04:06 +02001840class PublicAPITests(unittest.TestCase):
1841 """Ensures that the correct values are exposed in the public API."""
1842
1843 def test_module_all_attribute(self):
1844 self.assertTrue(hasattr(shutil, '__all__'))
1845 target_api = ['copyfileobj', 'copyfile', 'copymode', 'copystat',
1846 'copy', 'copy2', 'copytree', 'move', 'rmtree', 'Error',
1847 'SpecialFileError', 'ExecError', 'make_archive',
1848 'get_archive_formats', 'register_archive_format',
1849 'unregister_archive_format', 'get_unpack_formats',
1850 'register_unpack_format', 'unregister_unpack_format',
1851 'unpack_archive', 'ignore_patterns', 'chown', 'which',
1852 'get_terminal_size', 'SameFileError']
1853 if hasattr(os, 'statvfs') or os.name == 'nt':
1854 target_api.append('disk_usage')
1855 self.assertEqual(set(shutil.__all__), set(target_api))
1856
1857
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001858if __name__ == '__main__':
Brett Cannon3e9a9ae2013-06-12 21:25:59 -04001859 unittest.main()