blob: ca2bfc4bfeb4f5a84878bacee5483ed9453328a4 [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
Benjamin Petersonee8712c2008-05-20 21:35:26 +000015from test import support
16from test.support import TESTFN
Tarek Ziadé396fad72010-02-23 05:30:31 +000017from os.path import splitdrive
18from distutils.spawn import find_executable, spawn
19from shutil import (_make_tarball, _make_zipfile, make_archive,
20 register_archive_format, unregister_archive_format,
Tarek Ziadé6ac91722010-04-28 17:51:36 +000021 get_archive_formats, Error, unpack_archive,
22 register_unpack_format, RegistryError,
Hynek Schlawack48653762012-10-07 12:49:58 +020023 unregister_unpack_format, get_unpack_formats,
24 SameFileError)
Tarek Ziadé396fad72010-02-23 05:30:31 +000025import tarfile
26import warnings
27
28from test import support
Ezio Melotti975077a2011-05-19 22:03:22 +030029from test.support import TESTFN, check_warnings, captured_stdout, requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +000030
Tarek Ziadéffa155a2010-04-29 13:34:35 +000031try:
32 import bz2
33 BZ2_SUPPORTED = True
34except ImportError:
35 BZ2_SUPPORTED = False
36
Antoine Pitrou7fff0962009-05-01 21:09:44 +000037TESTFN2 = TESTFN + "2"
Barry Warsaw7fc2cca2003-01-24 17:34:13 +000038
Tarek Ziadé396fad72010-02-23 05:30:31 +000039try:
40 import grp
41 import pwd
42 UID_GID_SUPPORT = True
43except ImportError:
44 UID_GID_SUPPORT = False
45
46try:
Tarek Ziadé396fad72010-02-23 05:30:31 +000047 import zipfile
48 ZIP_SUPPORT = True
49except ImportError:
50 ZIP_SUPPORT = find_executable('zip')
51
Nick Coghlan8ed3cf32011-03-16 14:05:35 -040052def _fake_rename(*args, **kwargs):
53 # Pretend the destination path is on a different filesystem.
Antoine Pitrouc041ab62012-01-02 19:18:02 +010054 raise OSError(getattr(errno, 'EXDEV', 18), "Invalid cross-device link")
Nick Coghlan8ed3cf32011-03-16 14:05:35 -040055
56def mock_rename(func):
57 @functools.wraps(func)
58 def wrap(*args, **kwargs):
59 try:
60 builtin_rename = os.rename
61 os.rename = _fake_rename
62 return func(*args, **kwargs)
63 finally:
64 os.rename = builtin_rename
65 return wrap
66
Éric Araujoa7e33a12011-08-12 19:51:35 +020067def write_file(path, content, binary=False):
68 """Write *content* to a file located at *path*.
69
70 If *path* is a tuple instead of a string, os.path.join will be used to
71 make a path. If *binary* is true, the file will be opened in binary
72 mode.
73 """
74 if isinstance(path, tuple):
75 path = os.path.join(*path)
76 with open(path, 'wb' if binary else 'w') as fp:
77 fp.write(content)
78
79def read_file(path, binary=False):
80 """Return contents from a file located at *path*.
81
82 If *path* is a tuple instead of a string, os.path.join will be used to
83 make a path. If *binary* is true, the file will be opened in binary
84 mode.
85 """
86 if isinstance(path, tuple):
87 path = os.path.join(*path)
88 with open(path, 'rb' if binary else 'r') as fp:
89 return fp.read()
90
91
Barry Warsaw7fc2cca2003-01-24 17:34:13 +000092class TestShutil(unittest.TestCase):
Tarek Ziadé396fad72010-02-23 05:30:31 +000093
94 def setUp(self):
95 super(TestShutil, self).setUp()
96 self.tempdirs = []
97
98 def tearDown(self):
99 super(TestShutil, self).tearDown()
100 while self.tempdirs:
101 d = self.tempdirs.pop()
102 shutil.rmtree(d, os.name in ('nt', 'cygwin'))
103
Tarek Ziadé396fad72010-02-23 05:30:31 +0000104
105 def mkdtemp(self):
106 """Create a temporary directory that will be cleaned up.
107
108 Returns the path of the directory.
109 """
110 d = tempfile.mkdtemp()
111 self.tempdirs.append(d)
112 return d
Tarek Ziadé5340db32010-04-19 22:30:51 +0000113
Hynek Schlawack3b527782012-06-25 13:27:31 +0200114 def test_rmtree_works_on_bytes(self):
115 tmp = self.mkdtemp()
116 victim = os.path.join(tmp, 'killme')
117 os.mkdir(victim)
118 write_file(os.path.join(victim, 'somefile'), 'foo')
119 victim = os.fsencode(victim)
120 self.assertIsInstance(victim, bytes)
Serhiy Storchaka41ad77c2014-08-07 19:38:37 +0300121 win = (os.name == 'nt')
122 with self.assertWarns(DeprecationWarning) if win else ExitStack():
123 shutil.rmtree(victim)
Hynek Schlawack3b527782012-06-25 13:27:31 +0200124
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200125 @support.skip_unless_symlink
126 def test_rmtree_fails_on_symlink(self):
127 tmp = self.mkdtemp()
128 dir_ = os.path.join(tmp, 'dir')
129 os.mkdir(dir_)
130 link = os.path.join(tmp, 'link')
131 os.symlink(dir_, link)
132 self.assertRaises(OSError, shutil.rmtree, link)
133 self.assertTrue(os.path.exists(dir_))
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100134 self.assertTrue(os.path.lexists(link))
135 errors = []
136 def onerror(*args):
137 errors.append(args)
138 shutil.rmtree(link, onerror=onerror)
139 self.assertEqual(len(errors), 1)
140 self.assertIs(errors[0][0], os.path.islink)
141 self.assertEqual(errors[0][1], link)
142 self.assertIsInstance(errors[0][2][1], OSError)
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200143
144 @support.skip_unless_symlink
145 def test_rmtree_works_on_symlinks(self):
146 tmp = self.mkdtemp()
147 dir1 = os.path.join(tmp, 'dir1')
148 dir2 = os.path.join(dir1, 'dir2')
149 dir3 = os.path.join(tmp, 'dir3')
150 for d in dir1, dir2, dir3:
151 os.mkdir(d)
152 file1 = os.path.join(tmp, 'file1')
153 write_file(file1, 'foo')
154 link1 = os.path.join(dir1, 'link1')
155 os.symlink(dir2, link1)
156 link2 = os.path.join(dir1, 'link2')
157 os.symlink(dir3, link2)
158 link3 = os.path.join(dir1, 'link3')
159 os.symlink(file1, link3)
160 # make sure symlinks are removed but not followed
161 shutil.rmtree(dir1)
162 self.assertFalse(os.path.exists(dir1))
163 self.assertTrue(os.path.exists(dir3))
164 self.assertTrue(os.path.exists(file1))
165
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000166 def test_rmtree_errors(self):
167 # filename is guaranteed not to exist
168 filename = tempfile.mktemp()
Hynek Schlawackb5501102012-12-10 09:11:25 +0100169 self.assertRaises(FileNotFoundError, shutil.rmtree, filename)
170 # test that ignore_errors option is honored
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100171 shutil.rmtree(filename, ignore_errors=True)
172
173 # existing file
174 tmpdir = self.mkdtemp()
Hynek Schlawackb5501102012-12-10 09:11:25 +0100175 write_file((tmpdir, "tstfile"), "")
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100176 filename = os.path.join(tmpdir, "tstfile")
Hynek Schlawackb5501102012-12-10 09:11:25 +0100177 with self.assertRaises(NotADirectoryError) as cm:
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100178 shutil.rmtree(filename)
Hynek Schlawack87f9b462012-12-10 16:29:57 +0100179 # The reason for this rather odd construct is that Windows sprinkles
180 # a \*.* at the end of file names. But only sometimes on some buildbots
181 possible_args = [filename, os.path.join(filename, '*.*')]
182 self.assertIn(cm.exception.filename, possible_args)
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100183 self.assertTrue(os.path.exists(filename))
Hynek Schlawackb5501102012-12-10 09:11:25 +0100184 # test that ignore_errors option is honored
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100185 shutil.rmtree(filename, ignore_errors=True)
186 self.assertTrue(os.path.exists(filename))
187 errors = []
188 def onerror(*args):
189 errors.append(args)
190 shutil.rmtree(filename, onerror=onerror)
191 self.assertEqual(len(errors), 2)
192 self.assertIs(errors[0][0], os.listdir)
193 self.assertEqual(errors[0][1], filename)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100194 self.assertIsInstance(errors[0][2][1], NotADirectoryError)
Hynek Schlawack87f9b462012-12-10 16:29:57 +0100195 self.assertIn(errors[0][2][1].filename, possible_args)
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100196 self.assertIs(errors[1][0], os.rmdir)
197 self.assertEqual(errors[1][1], filename)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100198 self.assertIsInstance(errors[1][2][1], NotADirectoryError)
Hynek Schlawack87f9b462012-12-10 16:29:57 +0100199 self.assertIn(errors[1][2][1].filename, possible_args)
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000200
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000201
Serhiy Storchaka43767632013-11-03 21:31:38 +0200202 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod()')
203 @unittest.skipIf(sys.platform[:6] == 'cygwin',
204 "This test can't be run on Cygwin (issue #1071513).")
205 @unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0,
206 "This test can't be run reliably as root (issue #1076467).")
207 def test_on_error(self):
208 self.errorState = 0
209 os.mkdir(TESTFN)
210 self.addCleanup(shutil.rmtree, TESTFN)
Antoine Pitrou2f8a75c2012-06-23 21:28:15 +0200211
Serhiy Storchaka43767632013-11-03 21:31:38 +0200212 self.child_file_path = os.path.join(TESTFN, 'a')
213 self.child_dir_path = os.path.join(TESTFN, 'b')
214 support.create_empty_file(self.child_file_path)
215 os.mkdir(self.child_dir_path)
216 old_dir_mode = os.stat(TESTFN).st_mode
217 old_child_file_mode = os.stat(self.child_file_path).st_mode
218 old_child_dir_mode = os.stat(self.child_dir_path).st_mode
219 # Make unwritable.
220 new_mode = stat.S_IREAD|stat.S_IEXEC
221 os.chmod(self.child_file_path, new_mode)
222 os.chmod(self.child_dir_path, new_mode)
223 os.chmod(TESTFN, new_mode)
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000224
Serhiy Storchaka43767632013-11-03 21:31:38 +0200225 self.addCleanup(os.chmod, TESTFN, old_dir_mode)
226 self.addCleanup(os.chmod, self.child_file_path, old_child_file_mode)
227 self.addCleanup(os.chmod, self.child_dir_path, old_child_dir_mode)
Antoine Pitrou2f8a75c2012-06-23 21:28:15 +0200228
Serhiy Storchaka43767632013-11-03 21:31:38 +0200229 shutil.rmtree(TESTFN, onerror=self.check_args_to_onerror)
230 # Test whether onerror has actually been called.
231 self.assertEqual(self.errorState, 3,
232 "Expected call to onerror function did not happen.")
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000233
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000234 def check_args_to_onerror(self, func, arg, exc):
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000235 # test_rmtree_errors deliberately runs rmtree
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200236 # on a directory that is chmod 500, which will fail.
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000237 # This function is run when shutil.rmtree fails.
238 # 99.9% of the time it initially fails to remove
239 # a file in the directory, so the first time through
240 # func is os.remove.
241 # However, some Linux machines running ZFS on
242 # FUSE experienced a failure earlier in the process
243 # at os.listdir. The first failure may legally
244 # be either.
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200245 if self.errorState < 2:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200246 if func is os.unlink:
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200247 self.assertEqual(arg, self.child_file_path)
248 elif func is os.rmdir:
249 self.assertEqual(arg, self.child_dir_path)
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000250 else:
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200251 self.assertIs(func, os.listdir)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200252 self.assertIn(arg, [TESTFN, self.child_dir_path])
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000253 self.assertTrue(issubclass(exc[0], OSError))
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200254 self.errorState += 1
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000255 else:
256 self.assertEqual(func, os.rmdir)
257 self.assertEqual(arg, TESTFN)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000258 self.assertTrue(issubclass(exc[0], OSError))
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200259 self.errorState = 3
260
261 def test_rmtree_does_not_choke_on_failing_lstat(self):
262 try:
263 orig_lstat = os.lstat
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200264 def raiser(fn, *args, **kwargs):
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200265 if fn != TESTFN:
266 raise OSError()
267 else:
268 return orig_lstat(fn)
269 os.lstat = raiser
270
271 os.mkdir(TESTFN)
272 write_file((TESTFN, 'foo'), 'foo')
273 shutil.rmtree(TESTFN)
274 finally:
275 os.lstat = orig_lstat
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000276
Antoine Pitrou78091e62011-12-29 18:54:15 +0100277 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
278 @support.skip_unless_symlink
279 def test_copymode_follow_symlinks(self):
280 tmp_dir = self.mkdtemp()
281 src = os.path.join(tmp_dir, 'foo')
282 dst = os.path.join(tmp_dir, 'bar')
283 src_link = os.path.join(tmp_dir, 'baz')
284 dst_link = os.path.join(tmp_dir, 'quux')
285 write_file(src, 'foo')
286 write_file(dst, 'foo')
287 os.symlink(src, src_link)
288 os.symlink(dst, dst_link)
289 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
290 # file to file
291 os.chmod(dst, stat.S_IRWXO)
292 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
293 shutil.copymode(src, dst)
294 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
Antoine Pitrou3f48ac92014-01-01 02:50:45 +0100295 # On Windows, os.chmod does not follow symlinks (issue #15411)
296 if os.name != 'nt':
297 # follow src link
298 os.chmod(dst, stat.S_IRWXO)
299 shutil.copymode(src_link, dst)
300 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
301 # follow dst link
302 os.chmod(dst, stat.S_IRWXO)
303 shutil.copymode(src, dst_link)
304 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
305 # follow both links
306 os.chmod(dst, stat.S_IRWXO)
307 shutil.copymode(src_link, dst_link)
308 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100309
310 @unittest.skipUnless(hasattr(os, 'lchmod'), 'requires os.lchmod')
311 @support.skip_unless_symlink
312 def test_copymode_symlink_to_symlink(self):
313 tmp_dir = self.mkdtemp()
314 src = os.path.join(tmp_dir, 'foo')
315 dst = os.path.join(tmp_dir, 'bar')
316 src_link = os.path.join(tmp_dir, 'baz')
317 dst_link = os.path.join(tmp_dir, 'quux')
318 write_file(src, 'foo')
319 write_file(dst, 'foo')
320 os.symlink(src, src_link)
321 os.symlink(dst, dst_link)
322 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
323 os.chmod(dst, stat.S_IRWXU)
324 os.lchmod(src_link, stat.S_IRWXO|stat.S_IRWXG)
325 # link to link
326 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700327 shutil.copymode(src_link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100328 self.assertEqual(os.lstat(src_link).st_mode,
329 os.lstat(dst_link).st_mode)
330 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
331 # src link - use chmod
332 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700333 shutil.copymode(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100334 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
335 # dst link - use chmod
336 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700337 shutil.copymode(src, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100338 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
339
340 @unittest.skipIf(hasattr(os, 'lchmod'), 'requires os.lchmod to be missing')
341 @support.skip_unless_symlink
342 def test_copymode_symlink_to_symlink_wo_lchmod(self):
343 tmp_dir = self.mkdtemp()
344 src = os.path.join(tmp_dir, 'foo')
345 dst = os.path.join(tmp_dir, 'bar')
346 src_link = os.path.join(tmp_dir, 'baz')
347 dst_link = os.path.join(tmp_dir, 'quux')
348 write_file(src, 'foo')
349 write_file(dst, 'foo')
350 os.symlink(src, src_link)
351 os.symlink(dst, dst_link)
Larry Hastingsb4038062012-07-15 10:57:38 -0700352 shutil.copymode(src_link, dst_link, follow_symlinks=False) # silent fail
Antoine Pitrou78091e62011-12-29 18:54:15 +0100353
354 @support.skip_unless_symlink
355 def test_copystat_symlinks(self):
356 tmp_dir = self.mkdtemp()
357 src = os.path.join(tmp_dir, 'foo')
358 dst = os.path.join(tmp_dir, 'bar')
359 src_link = os.path.join(tmp_dir, 'baz')
360 dst_link = os.path.join(tmp_dir, 'qux')
361 write_file(src, 'foo')
362 src_stat = os.stat(src)
363 os.utime(src, (src_stat.st_atime,
364 src_stat.st_mtime - 42.0)) # ensure different mtimes
365 write_file(dst, 'bar')
366 self.assertNotEqual(os.stat(src).st_mtime, os.stat(dst).st_mtime)
367 os.symlink(src, src_link)
368 os.symlink(dst, dst_link)
369 if hasattr(os, 'lchmod'):
370 os.lchmod(src_link, stat.S_IRWXO)
371 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
372 os.lchflags(src_link, stat.UF_NODUMP)
373 src_link_stat = os.lstat(src_link)
374 # follow
375 if hasattr(os, 'lchmod'):
Larry Hastingsb4038062012-07-15 10:57:38 -0700376 shutil.copystat(src_link, dst_link, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100377 self.assertNotEqual(src_link_stat.st_mode, os.stat(dst).st_mode)
378 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700379 shutil.copystat(src_link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100380 dst_link_stat = os.lstat(dst_link)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700381 if os.utime in os.supports_follow_symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100382 for attr in 'st_atime', 'st_mtime':
383 # The modification times may be truncated in the new file.
384 self.assertLessEqual(getattr(src_link_stat, attr),
385 getattr(dst_link_stat, attr) + 1)
386 if hasattr(os, 'lchmod'):
387 self.assertEqual(src_link_stat.st_mode, dst_link_stat.st_mode)
388 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
389 self.assertEqual(src_link_stat.st_flags, dst_link_stat.st_flags)
390 # tell to follow but dst is not a link
Larry Hastingsb4038062012-07-15 10:57:38 -0700391 shutil.copystat(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100392 self.assertTrue(abs(os.stat(src).st_mtime - os.stat(dst).st_mtime) <
393 00000.1)
394
Ned Deilybaf75712012-05-10 17:05:19 -0700395 @unittest.skipUnless(hasattr(os, 'chflags') and
396 hasattr(errno, 'EOPNOTSUPP') and
397 hasattr(errno, 'ENOTSUP'),
398 "requires os.chflags, EOPNOTSUPP & ENOTSUP")
399 def test_copystat_handles_harmless_chflags_errors(self):
400 tmpdir = self.mkdtemp()
401 file1 = os.path.join(tmpdir, 'file1')
402 file2 = os.path.join(tmpdir, 'file2')
403 write_file(file1, 'xxx')
404 write_file(file2, 'xxx')
405
406 def make_chflags_raiser(err):
407 ex = OSError()
408
Larry Hastings90867a52012-06-22 17:01:41 -0700409 def _chflags_raiser(path, flags, *, follow_symlinks=True):
Ned Deilybaf75712012-05-10 17:05:19 -0700410 ex.errno = err
411 raise ex
412 return _chflags_raiser
413 old_chflags = os.chflags
414 try:
415 for err in errno.EOPNOTSUPP, errno.ENOTSUP:
416 os.chflags = make_chflags_raiser(err)
417 shutil.copystat(file1, file2)
418 # assert others errors break it
419 os.chflags = make_chflags_raiser(errno.EOPNOTSUPP + errno.ENOTSUP)
420 self.assertRaises(OSError, shutil.copystat, file1, file2)
421 finally:
422 os.chflags = old_chflags
423
Antoine Pitrou424246f2012-05-12 19:02:01 +0200424 @support.skip_unless_xattr
425 def test_copyxattr(self):
426 tmp_dir = self.mkdtemp()
427 src = os.path.join(tmp_dir, 'foo')
428 write_file(src, 'foo')
429 dst = os.path.join(tmp_dir, 'bar')
430 write_file(dst, 'bar')
431
432 # no xattr == no problem
433 shutil._copyxattr(src, dst)
434 # common case
435 os.setxattr(src, 'user.foo', b'42')
436 os.setxattr(src, 'user.bar', b'43')
437 shutil._copyxattr(src, dst)
Gregory P. Smith1093bf22014-01-17 12:01:22 -0800438 self.assertEqual(sorted(os.listxattr(src)), sorted(os.listxattr(dst)))
Antoine Pitrou424246f2012-05-12 19:02:01 +0200439 self.assertEqual(
440 os.getxattr(src, 'user.foo'),
441 os.getxattr(dst, 'user.foo'))
442 # check errors don't affect other attrs
443 os.remove(dst)
444 write_file(dst, 'bar')
445 os_error = OSError(errno.EPERM, 'EPERM')
446
Larry Hastings9cf065c2012-06-22 16:30:09 -0700447 def _raise_on_user_foo(fname, attr, val, **kwargs):
Antoine Pitrou424246f2012-05-12 19:02:01 +0200448 if attr == 'user.foo':
449 raise os_error
450 else:
Larry Hastings9cf065c2012-06-22 16:30:09 -0700451 orig_setxattr(fname, attr, val, **kwargs)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200452 try:
453 orig_setxattr = os.setxattr
454 os.setxattr = _raise_on_user_foo
455 shutil._copyxattr(src, dst)
Antoine Pitrou61597d32012-05-12 23:37:35 +0200456 self.assertIn('user.bar', os.listxattr(dst))
Antoine Pitrou424246f2012-05-12 19:02:01 +0200457 finally:
458 os.setxattr = orig_setxattr
Hynek Schlawack0beab052013-02-05 08:22:44 +0100459 # the source filesystem not supporting xattrs should be ok, too.
460 def _raise_on_src(fname, *, follow_symlinks=True):
461 if fname == src:
462 raise OSError(errno.ENOTSUP, 'Operation not supported')
463 return orig_listxattr(fname, follow_symlinks=follow_symlinks)
464 try:
465 orig_listxattr = os.listxattr
466 os.listxattr = _raise_on_src
467 shutil._copyxattr(src, dst)
468 finally:
469 os.listxattr = orig_listxattr
Antoine Pitrou424246f2012-05-12 19:02:01 +0200470
Larry Hastingsad5ae042012-07-14 17:55:11 -0700471 # test that shutil.copystat copies xattrs
472 src = os.path.join(tmp_dir, 'the_original')
473 write_file(src, src)
474 os.setxattr(src, 'user.the_value', b'fiddly')
475 dst = os.path.join(tmp_dir, 'the_copy')
476 write_file(dst, dst)
477 shutil.copystat(src, dst)
Hynek Schlawackc2d481f2012-07-16 17:11:10 +0200478 self.assertEqual(os.getxattr(dst, 'user.the_value'), b'fiddly')
Larry Hastingsad5ae042012-07-14 17:55:11 -0700479
Antoine Pitrou424246f2012-05-12 19:02:01 +0200480 @support.skip_unless_symlink
481 @support.skip_unless_xattr
482 @unittest.skipUnless(hasattr(os, 'geteuid') and os.geteuid() == 0,
483 'root privileges required')
484 def test_copyxattr_symlinks(self):
485 # On Linux, it's only possible to access non-user xattr for symlinks;
486 # which in turn require root privileges. This test should be expanded
487 # as soon as other platforms gain support for extended attributes.
488 tmp_dir = self.mkdtemp()
489 src = os.path.join(tmp_dir, 'foo')
490 src_link = os.path.join(tmp_dir, 'baz')
491 write_file(src, 'foo')
492 os.symlink(src, src_link)
493 os.setxattr(src, 'trusted.foo', b'42')
Larry Hastings9cf065c2012-06-22 16:30:09 -0700494 os.setxattr(src_link, 'trusted.foo', b'43', follow_symlinks=False)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200495 dst = os.path.join(tmp_dir, 'bar')
496 dst_link = os.path.join(tmp_dir, 'qux')
497 write_file(dst, 'bar')
498 os.symlink(dst, dst_link)
Larry Hastingsb4038062012-07-15 10:57:38 -0700499 shutil._copyxattr(src_link, dst_link, follow_symlinks=False)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700500 self.assertEqual(os.getxattr(dst_link, 'trusted.foo', follow_symlinks=False), b'43')
Antoine Pitrou424246f2012-05-12 19:02:01 +0200501 self.assertRaises(OSError, os.getxattr, dst, 'trusted.foo')
Larry Hastingsb4038062012-07-15 10:57:38 -0700502 shutil._copyxattr(src_link, dst, follow_symlinks=False)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200503 self.assertEqual(os.getxattr(dst, 'trusted.foo'), b'43')
504
Antoine Pitrou78091e62011-12-29 18:54:15 +0100505 @support.skip_unless_symlink
506 def test_copy_symlinks(self):
507 tmp_dir = self.mkdtemp()
508 src = os.path.join(tmp_dir, 'foo')
509 dst = os.path.join(tmp_dir, 'bar')
510 src_link = os.path.join(tmp_dir, 'baz')
511 write_file(src, 'foo')
512 os.symlink(src, src_link)
513 if hasattr(os, 'lchmod'):
514 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
515 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700516 shutil.copy(src_link, dst, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100517 self.assertFalse(os.path.islink(dst))
518 self.assertEqual(read_file(src), read_file(dst))
519 os.remove(dst)
520 # follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700521 shutil.copy(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100522 self.assertTrue(os.path.islink(dst))
523 self.assertEqual(os.readlink(dst), os.readlink(src_link))
524 if hasattr(os, 'lchmod'):
525 self.assertEqual(os.lstat(src_link).st_mode,
526 os.lstat(dst).st_mode)
527
528 @support.skip_unless_symlink
529 def test_copy2_symlinks(self):
530 tmp_dir = self.mkdtemp()
531 src = os.path.join(tmp_dir, 'foo')
532 dst = os.path.join(tmp_dir, 'bar')
533 src_link = os.path.join(tmp_dir, 'baz')
534 write_file(src, 'foo')
535 os.symlink(src, src_link)
536 if hasattr(os, 'lchmod'):
537 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
538 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
539 os.lchflags(src_link, stat.UF_NODUMP)
540 src_stat = os.stat(src)
541 src_link_stat = os.lstat(src_link)
542 # follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700543 shutil.copy2(src_link, dst, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100544 self.assertFalse(os.path.islink(dst))
545 self.assertEqual(read_file(src), read_file(dst))
546 os.remove(dst)
547 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700548 shutil.copy2(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100549 self.assertTrue(os.path.islink(dst))
550 self.assertEqual(os.readlink(dst), os.readlink(src_link))
551 dst_stat = os.lstat(dst)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700552 if os.utime in os.supports_follow_symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100553 for attr in 'st_atime', 'st_mtime':
554 # The modification times may be truncated in the new file.
555 self.assertLessEqual(getattr(src_link_stat, attr),
556 getattr(dst_stat, attr) + 1)
557 if hasattr(os, 'lchmod'):
558 self.assertEqual(src_link_stat.st_mode, dst_stat.st_mode)
559 self.assertNotEqual(src_stat.st_mode, dst_stat.st_mode)
560 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
561 self.assertEqual(src_link_stat.st_flags, dst_stat.st_flags)
562
Antoine Pitrou424246f2012-05-12 19:02:01 +0200563 @support.skip_unless_xattr
564 def test_copy2_xattr(self):
565 tmp_dir = self.mkdtemp()
566 src = os.path.join(tmp_dir, 'foo')
567 dst = os.path.join(tmp_dir, 'bar')
568 write_file(src, 'foo')
569 os.setxattr(src, 'user.foo', b'42')
570 shutil.copy2(src, dst)
571 self.assertEqual(
572 os.getxattr(src, 'user.foo'),
573 os.getxattr(dst, 'user.foo'))
574 os.remove(dst)
575
Antoine Pitrou78091e62011-12-29 18:54:15 +0100576 @support.skip_unless_symlink
577 def test_copyfile_symlinks(self):
578 tmp_dir = self.mkdtemp()
579 src = os.path.join(tmp_dir, 'src')
580 dst = os.path.join(tmp_dir, 'dst')
581 dst_link = os.path.join(tmp_dir, 'dst_link')
582 link = os.path.join(tmp_dir, 'link')
583 write_file(src, 'foo')
584 os.symlink(src, link)
585 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700586 shutil.copyfile(link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100587 self.assertTrue(os.path.islink(dst_link))
588 self.assertEqual(os.readlink(link), os.readlink(dst_link))
589 # follow
590 shutil.copyfile(link, dst)
591 self.assertFalse(os.path.islink(dst))
592
Hynek Schlawack2100b422012-06-23 20:28:32 +0200593 def test_rmtree_uses_safe_fd_version_if_available(self):
Hynek Schlawackd0f6e0a2012-06-29 08:28:20 +0200594 _use_fd_functions = ({os.open, os.stat, os.unlink, os.rmdir} <=
595 os.supports_dir_fd and
596 os.listdir in os.supports_fd and
597 os.stat in os.supports_follow_symlinks)
598 if _use_fd_functions:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200599 self.assertTrue(shutil._use_fd_functions)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000600 self.assertTrue(shutil.rmtree.avoids_symlink_attacks)
Hynek Schlawack2100b422012-06-23 20:28:32 +0200601 tmp_dir = self.mkdtemp()
602 d = os.path.join(tmp_dir, 'a')
603 os.mkdir(d)
604 try:
605 real_rmtree = shutil._rmtree_safe_fd
606 class Called(Exception): pass
607 def _raiser(*args, **kwargs):
608 raise Called
609 shutil._rmtree_safe_fd = _raiser
610 self.assertRaises(Called, shutil.rmtree, d)
611 finally:
612 shutil._rmtree_safe_fd = real_rmtree
613 else:
614 self.assertFalse(shutil._use_fd_functions)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000615 self.assertFalse(shutil.rmtree.avoids_symlink_attacks)
Hynek Schlawack2100b422012-06-23 20:28:32 +0200616
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000617 def test_rmtree_dont_delete_file(self):
618 # When called on a file instead of a directory, don't delete it.
619 handle, path = tempfile.mkstemp()
Victor Stinnerbf816222011-06-30 23:25:47 +0200620 os.close(handle)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200621 self.assertRaises(NotADirectoryError, shutil.rmtree, path)
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000622 os.remove(path)
623
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000624 def test_copytree_simple(self):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000625 src_dir = tempfile.mkdtemp()
626 dst_dir = os.path.join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200627 self.addCleanup(shutil.rmtree, src_dir)
628 self.addCleanup(shutil.rmtree, os.path.dirname(dst_dir))
629 write_file((src_dir, 'test.txt'), '123')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000630 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200631 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000632
Éric Araujoa7e33a12011-08-12 19:51:35 +0200633 shutil.copytree(src_dir, dst_dir)
634 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test.txt')))
635 self.assertTrue(os.path.isdir(os.path.join(dst_dir, 'test_dir')))
636 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test_dir',
637 'test.txt')))
638 actual = read_file((dst_dir, 'test.txt'))
639 self.assertEqual(actual, '123')
640 actual = read_file((dst_dir, 'test_dir', 'test.txt'))
641 self.assertEqual(actual, '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000642
Antoine Pitrou78091e62011-12-29 18:54:15 +0100643 @support.skip_unless_symlink
644 def test_copytree_symlinks(self):
645 tmp_dir = self.mkdtemp()
646 src_dir = os.path.join(tmp_dir, 'src')
647 dst_dir = os.path.join(tmp_dir, 'dst')
648 sub_dir = os.path.join(src_dir, 'sub')
649 os.mkdir(src_dir)
650 os.mkdir(sub_dir)
651 write_file((src_dir, 'file.txt'), 'foo')
652 src_link = os.path.join(sub_dir, 'link')
653 dst_link = os.path.join(dst_dir, 'sub/link')
654 os.symlink(os.path.join(src_dir, 'file.txt'),
655 src_link)
656 if hasattr(os, 'lchmod'):
657 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
658 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
659 os.lchflags(src_link, stat.UF_NODUMP)
660 src_stat = os.lstat(src_link)
661 shutil.copytree(src_dir, dst_dir, symlinks=True)
662 self.assertTrue(os.path.islink(os.path.join(dst_dir, 'sub', 'link')))
663 self.assertEqual(os.readlink(os.path.join(dst_dir, 'sub', 'link')),
664 os.path.join(src_dir, 'file.txt'))
665 dst_stat = os.lstat(dst_link)
666 if hasattr(os, 'lchmod'):
667 self.assertEqual(dst_stat.st_mode, src_stat.st_mode)
668 if hasattr(os, 'lchflags'):
669 self.assertEqual(dst_stat.st_flags, src_stat.st_flags)
670
Georg Brandl2ee470f2008-07-16 12:55:28 +0000671 def test_copytree_with_exclude(self):
Georg Brandl2ee470f2008-07-16 12:55:28 +0000672 # creating data
673 join = os.path.join
674 exists = os.path.exists
675 src_dir = tempfile.mkdtemp()
Georg Brandl2ee470f2008-07-16 12:55:28 +0000676 try:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000677 dst_dir = join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200678 write_file((src_dir, 'test.txt'), '123')
679 write_file((src_dir, 'test.tmp'), '123')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000680 os.mkdir(join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200681 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000682 os.mkdir(join(src_dir, 'test_dir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200683 write_file((src_dir, 'test_dir2', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000684 os.mkdir(join(src_dir, 'test_dir2', 'subdir'))
685 os.mkdir(join(src_dir, 'test_dir2', 'subdir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200686 write_file((src_dir, 'test_dir2', 'subdir', 'test.txt'), '456')
687 write_file((src_dir, 'test_dir2', 'subdir2', 'test.py'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000688
689 # testing glob-like patterns
690 try:
691 patterns = shutil.ignore_patterns('*.tmp', 'test_dir2')
692 shutil.copytree(src_dir, dst_dir, ignore=patterns)
693 # checking the result: some elements should not be copied
694 self.assertTrue(exists(join(dst_dir, 'test.txt')))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200695 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
696 self.assertFalse(exists(join(dst_dir, 'test_dir2')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000697 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200698 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000699 try:
700 patterns = shutil.ignore_patterns('*.tmp', 'subdir*')
701 shutil.copytree(src_dir, dst_dir, ignore=patterns)
702 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200703 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
704 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2')))
705 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000706 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200707 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000708
709 # testing callable-style
710 try:
711 def _filter(src, names):
712 res = []
713 for name in names:
714 path = os.path.join(src, name)
715
716 if (os.path.isdir(path) and
717 path.split()[-1] == 'subdir'):
718 res.append(name)
719 elif os.path.splitext(path)[-1] in ('.py'):
720 res.append(name)
721 return res
722
723 shutil.copytree(src_dir, dst_dir, ignore=_filter)
724
725 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200726 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2',
727 'test.py')))
728 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000729
730 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200731 shutil.rmtree(dst_dir)
Georg Brandl2ee470f2008-07-16 12:55:28 +0000732 finally:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000733 shutil.rmtree(src_dir)
734 shutil.rmtree(os.path.dirname(dst_dir))
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000735
Antoine Pitrouac601602013-08-16 19:35:02 +0200736 def test_copytree_retains_permissions(self):
737 tmp_dir = tempfile.mkdtemp()
738 src_dir = os.path.join(tmp_dir, 'source')
739 os.mkdir(src_dir)
740 dst_dir = os.path.join(tmp_dir, 'destination')
741 self.addCleanup(shutil.rmtree, tmp_dir)
742
743 os.chmod(src_dir, 0o777)
744 write_file((src_dir, 'permissive.txt'), '123')
745 os.chmod(os.path.join(src_dir, 'permissive.txt'), 0o777)
746 write_file((src_dir, 'restrictive.txt'), '456')
747 os.chmod(os.path.join(src_dir, 'restrictive.txt'), 0o600)
748 restrictive_subdir = tempfile.mkdtemp(dir=src_dir)
749 os.chmod(restrictive_subdir, 0o600)
750
751 shutil.copytree(src_dir, dst_dir)
Brett Cannon9c7eb552013-08-23 14:38:11 -0400752 self.assertEqual(os.stat(src_dir).st_mode, os.stat(dst_dir).st_mode)
753 self.assertEqual(os.stat(os.path.join(src_dir, 'permissive.txt')).st_mode,
Antoine Pitrouac601602013-08-16 19:35:02 +0200754 os.stat(os.path.join(dst_dir, 'permissive.txt')).st_mode)
Brett Cannon9c7eb552013-08-23 14:38:11 -0400755 self.assertEqual(os.stat(os.path.join(src_dir, 'restrictive.txt')).st_mode,
Antoine Pitrouac601602013-08-16 19:35:02 +0200756 os.stat(os.path.join(dst_dir, 'restrictive.txt')).st_mode)
757 restrictive_subdir_dst = os.path.join(dst_dir,
758 os.path.split(restrictive_subdir)[1])
Brett Cannon9c7eb552013-08-23 14:38:11 -0400759 self.assertEqual(os.stat(restrictive_subdir).st_mode,
Antoine Pitrouac601602013-08-16 19:35:02 +0200760 os.stat(restrictive_subdir_dst).st_mode)
761
Berker Peksag884afd92014-12-10 02:50:32 +0200762 @unittest.mock.patch('os.chmod')
763 def test_copytree_winerror(self, mock_patch):
764 # When copying to VFAT, copystat() raises OSError. On Windows, the
765 # exception object has a meaningful 'winerror' attribute, but not
766 # on other operating systems. Do not assume 'winerror' is set.
767 src_dir = tempfile.mkdtemp()
768 dst_dir = os.path.join(tempfile.mkdtemp(), 'destination')
769 self.addCleanup(shutil.rmtree, src_dir)
770 self.addCleanup(shutil.rmtree, os.path.dirname(dst_dir))
771
772 mock_patch.side_effect = PermissionError('ka-boom')
773 with self.assertRaises(shutil.Error):
774 shutil.copytree(src_dir, dst_dir)
775
Zachary Ware9fe6d862013-12-08 00:20:35 -0600776 @unittest.skipIf(os.name == 'nt', 'temporarily disabled on Windows')
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000777 @unittest.skipUnless(hasattr(os, 'link'), 'requires os.link')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000778 def test_dont_copy_file_onto_link_to_itself(self):
779 # bug 851123.
780 os.mkdir(TESTFN)
781 src = os.path.join(TESTFN, 'cheese')
782 dst = os.path.join(TESTFN, 'shop')
783 try:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000784 with open(src, 'w') as f:
785 f.write('cheddar')
786 os.link(src, dst)
Hynek Schlawack48653762012-10-07 12:49:58 +0200787 self.assertRaises(shutil.SameFileError, shutil.copyfile, src, dst)
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000788 with open(src, 'r') as f:
789 self.assertEqual(f.read(), 'cheddar')
790 os.remove(dst)
791 finally:
792 shutil.rmtree(TESTFN, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000793
Brian Curtin3b4499c2010-12-28 14:31:47 +0000794 @support.skip_unless_symlink
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000795 def test_dont_copy_file_onto_symlink_to_itself(self):
796 # bug 851123.
797 os.mkdir(TESTFN)
798 src = os.path.join(TESTFN, 'cheese')
799 dst = os.path.join(TESTFN, 'shop')
800 try:
801 with open(src, 'w') as f:
802 f.write('cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000803 # Using `src` here would mean we end up with a symlink pointing
804 # to TESTFN/TESTFN/cheese, while it should point at
805 # TESTFN/cheese.
806 os.symlink('cheese', dst)
Hynek Schlawack48653762012-10-07 12:49:58 +0200807 self.assertRaises(shutil.SameFileError, shutil.copyfile, src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +0000808 with open(src, 'r') as f:
809 self.assertEqual(f.read(), 'cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000810 os.remove(dst)
811 finally:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000812 shutil.rmtree(TESTFN, ignore_errors=True)
Johannes Gijsbers68128712004-08-14 13:57:08 +0000813
Brian Curtin3b4499c2010-12-28 14:31:47 +0000814 @support.skip_unless_symlink
Brian Curtind40e6f72010-07-08 21:39:08 +0000815 def test_rmtree_on_symlink(self):
816 # bug 1669.
817 os.mkdir(TESTFN)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000818 try:
Brian Curtind40e6f72010-07-08 21:39:08 +0000819 src = os.path.join(TESTFN, 'cheese')
820 dst = os.path.join(TESTFN, 'shop')
821 os.mkdir(src)
822 os.symlink(src, dst)
823 self.assertRaises(OSError, shutil.rmtree, dst)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200824 shutil.rmtree(dst, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000825 finally:
Brian Curtind40e6f72010-07-08 21:39:08 +0000826 shutil.rmtree(TESTFN, ignore_errors=True)
827
Serhiy Storchaka43767632013-11-03 21:31:38 +0200828 # Issue #3002: copyfile and copytree block indefinitely on named pipes
829 @unittest.skipUnless(hasattr(os, "mkfifo"), 'requires os.mkfifo()')
830 def test_copyfile_named_pipe(self):
831 os.mkfifo(TESTFN)
832 try:
833 self.assertRaises(shutil.SpecialFileError,
834 shutil.copyfile, TESTFN, TESTFN2)
835 self.assertRaises(shutil.SpecialFileError,
836 shutil.copyfile, __file__, TESTFN)
837 finally:
838 os.remove(TESTFN)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000839
Serhiy Storchaka43767632013-11-03 21:31:38 +0200840 @unittest.skipUnless(hasattr(os, "mkfifo"), 'requires os.mkfifo()')
841 @support.skip_unless_symlink
842 def test_copytree_named_pipe(self):
843 os.mkdir(TESTFN)
844 try:
845 subdir = os.path.join(TESTFN, "subdir")
846 os.mkdir(subdir)
847 pipe = os.path.join(subdir, "mypipe")
848 os.mkfifo(pipe)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000849 try:
Serhiy Storchaka43767632013-11-03 21:31:38 +0200850 shutil.copytree(TESTFN, TESTFN2)
851 except shutil.Error as e:
852 errors = e.args[0]
853 self.assertEqual(len(errors), 1)
854 src, dst, error_msg = errors[0]
855 self.assertEqual("`%s` is a named pipe" % pipe, error_msg)
856 else:
857 self.fail("shutil.Error should have been raised")
858 finally:
859 shutil.rmtree(TESTFN, ignore_errors=True)
860 shutil.rmtree(TESTFN2, ignore_errors=True)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000861
Tarek Ziadé5340db32010-04-19 22:30:51 +0000862 def test_copytree_special_func(self):
863
864 src_dir = self.mkdtemp()
865 dst_dir = os.path.join(self.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200866 write_file((src_dir, 'test.txt'), '123')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000867 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200868 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000869
870 copied = []
871 def _copy(src, dst):
872 copied.append((src, dst))
873
874 shutil.copytree(src_dir, dst_dir, copy_function=_copy)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000875 self.assertEqual(len(copied), 2)
Tarek Ziadé5340db32010-04-19 22:30:51 +0000876
Brian Curtin3b4499c2010-12-28 14:31:47 +0000877 @support.skip_unless_symlink
Tarek Ziadéfb437512010-04-20 08:57:33 +0000878 def test_copytree_dangling_symlinks(self):
879
880 # a dangling symlink raises an error at the end
881 src_dir = self.mkdtemp()
882 dst_dir = os.path.join(self.mkdtemp(), 'destination')
883 os.symlink('IDONTEXIST', os.path.join(src_dir, 'test.txt'))
884 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200885 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadéfb437512010-04-20 08:57:33 +0000886 self.assertRaises(Error, shutil.copytree, src_dir, dst_dir)
887
888 # a dangling symlink is ignored with the proper flag
889 dst_dir = os.path.join(self.mkdtemp(), 'destination2')
890 shutil.copytree(src_dir, dst_dir, ignore_dangling_symlinks=True)
891 self.assertNotIn('test.txt', os.listdir(dst_dir))
892
893 # a dangling symlink is copied if symlinks=True
894 dst_dir = os.path.join(self.mkdtemp(), 'destination3')
895 shutil.copytree(src_dir, dst_dir, symlinks=True)
896 self.assertIn('test.txt', os.listdir(dst_dir))
897
Berker Peksag5a294d82015-07-25 14:53:48 +0300898 @support.skip_unless_symlink
899 def test_copytree_symlink_dir(self):
900 src_dir = self.mkdtemp()
901 dst_dir = os.path.join(self.mkdtemp(), 'destination')
902 os.mkdir(os.path.join(src_dir, 'real_dir'))
903 with open(os.path.join(src_dir, 'real_dir', 'test.txt'), 'w'):
904 pass
905 os.symlink(os.path.join(src_dir, 'real_dir'),
906 os.path.join(src_dir, 'link_to_dir'),
907 target_is_directory=True)
908
909 shutil.copytree(src_dir, dst_dir, symlinks=False)
910 self.assertFalse(os.path.islink(os.path.join(dst_dir, 'link_to_dir')))
911 self.assertIn('test.txt', os.listdir(os.path.join(dst_dir, 'link_to_dir')))
912
913 dst_dir = os.path.join(self.mkdtemp(), 'destination2')
914 shutil.copytree(src_dir, dst_dir, symlinks=True)
915 self.assertTrue(os.path.islink(os.path.join(dst_dir, 'link_to_dir')))
916 self.assertIn('test.txt', os.listdir(os.path.join(dst_dir, 'link_to_dir')))
917
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400918 def _copy_file(self, method):
919 fname = 'test.txt'
920 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200921 write_file((tmpdir, fname), 'xxx')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400922 file1 = os.path.join(tmpdir, fname)
923 tmpdir2 = self.mkdtemp()
924 method(file1, tmpdir2)
925 file2 = os.path.join(tmpdir2, fname)
926 return (file1, file2)
927
928 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
929 def test_copy(self):
930 # Ensure that the copied file exists and has the same mode bits.
931 file1, file2 = self._copy_file(shutil.copy)
932 self.assertTrue(os.path.exists(file2))
933 self.assertEqual(os.stat(file1).st_mode, os.stat(file2).st_mode)
934
935 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
Senthil Kumaran0c2dba52011-07-03 18:21:38 -0700936 @unittest.skipUnless(hasattr(os, 'utime'), 'requires os.utime')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400937 def test_copy2(self):
938 # Ensure that the copied file exists and has the same mode and
939 # modification time bits.
940 file1, file2 = self._copy_file(shutil.copy2)
941 self.assertTrue(os.path.exists(file2))
942 file1_stat = os.stat(file1)
943 file2_stat = os.stat(file2)
944 self.assertEqual(file1_stat.st_mode, file2_stat.st_mode)
945 for attr in 'st_atime', 'st_mtime':
946 # The modification times may be truncated in the new file.
947 self.assertLessEqual(getattr(file1_stat, attr),
948 getattr(file2_stat, attr) + 1)
949 if hasattr(os, 'chflags') and hasattr(file1_stat, 'st_flags'):
950 self.assertEqual(getattr(file1_stat, 'st_flags'),
951 getattr(file2_stat, 'st_flags'))
952
Ezio Melotti975077a2011-05-19 22:03:22 +0300953 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000954 def test_make_tarball(self):
955 # creating something to tar
956 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200957 write_file((tmpdir, 'file1'), 'xxx')
958 write_file((tmpdir, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000959 os.mkdir(os.path.join(tmpdir, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200960 write_file((tmpdir, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000961
962 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400963 # force shutil to create the directory
964 os.rmdir(tmpdir2)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000965 unittest.skipUnless(splitdrive(tmpdir)[0] == splitdrive(tmpdir2)[0],
966 "source and target should be on same drive")
967
968 base_name = os.path.join(tmpdir2, 'archive')
969
970 # working with relative paths to avoid tar warnings
971 old_dir = os.getcwd()
972 os.chdir(tmpdir)
973 try:
974 _make_tarball(splitdrive(base_name)[1], '.')
975 finally:
976 os.chdir(old_dir)
977
978 # check if the compressed tarball was created
979 tarball = base_name + '.tar.gz'
980 self.assertTrue(os.path.exists(tarball))
981
982 # trying an uncompressed one
983 base_name = os.path.join(tmpdir2, 'archive')
984 old_dir = os.getcwd()
985 os.chdir(tmpdir)
986 try:
987 _make_tarball(splitdrive(base_name)[1], '.', compress=None)
988 finally:
989 os.chdir(old_dir)
990 tarball = base_name + '.tar'
991 self.assertTrue(os.path.exists(tarball))
992
993 def _tarinfo(self, path):
994 tar = tarfile.open(path)
995 try:
996 names = tar.getnames()
997 names.sort()
998 return tuple(names)
999 finally:
1000 tar.close()
1001
1002 def _create_files(self):
1003 # creating something to tar
1004 tmpdir = self.mkdtemp()
1005 dist = os.path.join(tmpdir, 'dist')
1006 os.mkdir(dist)
Éric Araujoa7e33a12011-08-12 19:51:35 +02001007 write_file((dist, 'file1'), 'xxx')
1008 write_file((dist, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +00001009 os.mkdir(os.path.join(dist, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +02001010 write_file((dist, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +00001011 os.mkdir(os.path.join(dist, 'sub2'))
1012 tmpdir2 = self.mkdtemp()
1013 base_name = os.path.join(tmpdir2, 'archive')
1014 return tmpdir, tmpdir2, base_name
1015
Ezio Melotti975077a2011-05-19 22:03:22 +03001016 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001017 @unittest.skipUnless(find_executable('tar') and find_executable('gzip'),
1018 'Need the tar command to run')
1019 def test_tarfile_vs_tar(self):
1020 tmpdir, tmpdir2, base_name = self._create_files()
1021 old_dir = os.getcwd()
1022 os.chdir(tmpdir)
1023 try:
1024 _make_tarball(base_name, 'dist')
1025 finally:
1026 os.chdir(old_dir)
1027
1028 # check if the compressed tarball was created
1029 tarball = base_name + '.tar.gz'
1030 self.assertTrue(os.path.exists(tarball))
1031
1032 # now create another tarball using `tar`
1033 tarball2 = os.path.join(tmpdir, 'archive2.tar.gz')
1034 tar_cmd = ['tar', '-cf', 'archive2.tar', 'dist']
1035 gzip_cmd = ['gzip', '-f9', 'archive2.tar']
1036 old_dir = os.getcwd()
1037 os.chdir(tmpdir)
1038 try:
1039 with captured_stdout() as s:
1040 spawn(tar_cmd)
1041 spawn(gzip_cmd)
1042 finally:
1043 os.chdir(old_dir)
1044
1045 self.assertTrue(os.path.exists(tarball2))
1046 # let's compare both tarballs
Ezio Melottib3aedd42010-11-20 19:04:17 +00001047 self.assertEqual(self._tarinfo(tarball), self._tarinfo(tarball2))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001048
1049 # trying an uncompressed one
1050 base_name = os.path.join(tmpdir2, 'archive')
1051 old_dir = os.getcwd()
1052 os.chdir(tmpdir)
1053 try:
1054 _make_tarball(base_name, 'dist', compress=None)
1055 finally:
1056 os.chdir(old_dir)
1057 tarball = base_name + '.tar'
1058 self.assertTrue(os.path.exists(tarball))
1059
1060 # now for a dry_run
1061 base_name = os.path.join(tmpdir2, 'archive')
1062 old_dir = os.getcwd()
1063 os.chdir(tmpdir)
1064 try:
1065 _make_tarball(base_name, 'dist', compress=None, dry_run=True)
1066 finally:
1067 os.chdir(old_dir)
1068 tarball = base_name + '.tar'
1069 self.assertTrue(os.path.exists(tarball))
1070
Ezio Melotti975077a2011-05-19 22:03:22 +03001071 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001072 @unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run')
1073 def test_make_zipfile(self):
1074 # creating something to tar
1075 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +02001076 write_file((tmpdir, 'file1'), 'xxx')
1077 write_file((tmpdir, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +00001078
1079 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001080 # force shutil to create the directory
1081 os.rmdir(tmpdir2)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001082 base_name = os.path.join(tmpdir2, 'archive')
1083 _make_zipfile(base_name, tmpdir)
1084
1085 # check if the compressed tarball was created
1086 tarball = base_name + '.zip'
Éric Araujo1c505492010-11-06 02:12:51 +00001087 self.assertTrue(os.path.exists(tarball))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001088
1089
1090 def test_make_archive(self):
1091 tmpdir = self.mkdtemp()
1092 base_name = os.path.join(tmpdir, 'archive')
1093 self.assertRaises(ValueError, make_archive, base_name, 'xxx')
1094
Ezio Melotti975077a2011-05-19 22:03:22 +03001095 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001096 def test_make_archive_owner_group(self):
1097 # testing make_archive with owner and group, with various combinations
1098 # this works even if there's not gid/uid support
1099 if UID_GID_SUPPORT:
1100 group = grp.getgrgid(0)[0]
1101 owner = pwd.getpwuid(0)[0]
1102 else:
1103 group = owner = 'root'
1104
1105 base_dir, root_dir, base_name = self._create_files()
1106 base_name = os.path.join(self.mkdtemp() , 'archive')
1107 res = make_archive(base_name, 'zip', root_dir, base_dir, owner=owner,
1108 group=group)
1109 self.assertTrue(os.path.exists(res))
1110
1111 res = make_archive(base_name, 'zip', root_dir, base_dir)
1112 self.assertTrue(os.path.exists(res))
1113
1114 res = make_archive(base_name, 'tar', root_dir, base_dir,
1115 owner=owner, group=group)
1116 self.assertTrue(os.path.exists(res))
1117
1118 res = make_archive(base_name, 'tar', root_dir, base_dir,
1119 owner='kjhkjhkjg', group='oihohoh')
1120 self.assertTrue(os.path.exists(res))
1121
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001122
Ezio Melotti975077a2011-05-19 22:03:22 +03001123 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001124 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1125 def test_tarfile_root_owner(self):
1126 tmpdir, tmpdir2, base_name = self._create_files()
1127 old_dir = os.getcwd()
1128 os.chdir(tmpdir)
1129 group = grp.getgrgid(0)[0]
1130 owner = pwd.getpwuid(0)[0]
1131 try:
1132 archive_name = _make_tarball(base_name, 'dist', compress=None,
1133 owner=owner, group=group)
1134 finally:
1135 os.chdir(old_dir)
1136
1137 # check if the compressed tarball was created
1138 self.assertTrue(os.path.exists(archive_name))
1139
1140 # now checks the rights
1141 archive = tarfile.open(archive_name)
1142 try:
1143 for member in archive.getmembers():
Ezio Melottib3aedd42010-11-20 19:04:17 +00001144 self.assertEqual(member.uid, 0)
1145 self.assertEqual(member.gid, 0)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001146 finally:
1147 archive.close()
1148
1149 def test_make_archive_cwd(self):
1150 current_dir = os.getcwd()
1151 def _breaks(*args, **kw):
1152 raise RuntimeError()
1153
1154 register_archive_format('xxx', _breaks, [], 'xxx file')
1155 try:
1156 try:
1157 make_archive('xxx', 'xxx', root_dir=self.mkdtemp())
1158 except Exception:
1159 pass
Ezio Melottib3aedd42010-11-20 19:04:17 +00001160 self.assertEqual(os.getcwd(), current_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001161 finally:
1162 unregister_archive_format('xxx')
1163
Serhiy Storchaka9a4fc192014-11-28 00:48:46 +02001164 def test_make_tarfile_in_curdir(self):
1165 # Issue #21280
1166 root_dir = self.mkdtemp()
1167 with support.change_cwd(root_dir):
1168 self.assertEqual(make_archive('test', 'tar'), 'test.tar')
1169 self.assertTrue(os.path.isfile('test.tar'))
1170
1171 @requires_zlib
1172 def test_make_zipfile_in_curdir(self):
1173 # Issue #21280
1174 root_dir = self.mkdtemp()
1175 with support.change_cwd(root_dir):
1176 self.assertEqual(make_archive('test', 'zip'), 'test.zip')
1177 self.assertTrue(os.path.isfile('test.zip'))
1178
Tarek Ziadé396fad72010-02-23 05:30:31 +00001179 def test_register_archive_format(self):
1180
1181 self.assertRaises(TypeError, register_archive_format, 'xxx', 1)
1182 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1183 1)
1184 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1185 [(1, 2), (1, 2, 3)])
1186
1187 register_archive_format('xxx', lambda: x, [(1, 2)], 'xxx file')
1188 formats = [name for name, params in get_archive_formats()]
1189 self.assertIn('xxx', formats)
1190
1191 unregister_archive_format('xxx')
1192 formats = [name for name, params in get_archive_formats()]
1193 self.assertNotIn('xxx', formats)
1194
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001195 def _compare_dirs(self, dir1, dir2):
1196 # check that dir1 and dir2 are equivalent,
1197 # return the diff
1198 diff = []
1199 for root, dirs, files in os.walk(dir1):
1200 for file_ in files:
1201 path = os.path.join(root, file_)
1202 target_path = os.path.join(dir2, os.path.split(path)[-1])
1203 if not os.path.exists(target_path):
1204 diff.append(file_)
1205 return diff
1206
Ezio Melotti975077a2011-05-19 22:03:22 +03001207 @requires_zlib
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001208 def test_unpack_archive(self):
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001209 formats = ['tar', 'gztar', 'zip']
1210 if BZ2_SUPPORTED:
1211 formats.append('bztar')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001212
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001213 for format in formats:
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001214 tmpdir = self.mkdtemp()
1215 base_dir, root_dir, base_name = self._create_files()
1216 tmpdir2 = self.mkdtemp()
1217 filename = make_archive(base_name, format, root_dir, base_dir)
1218
1219 # let's try to unpack it now
1220 unpack_archive(filename, tmpdir2)
1221 diff = self._compare_dirs(tmpdir, tmpdir2)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001222 self.assertEqual(diff, [])
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001223
Nick Coghlanabf202d2011-03-16 13:52:20 -04001224 # and again, this time with the format specified
1225 tmpdir3 = self.mkdtemp()
1226 unpack_archive(filename, tmpdir3, format=format)
1227 diff = self._compare_dirs(tmpdir, tmpdir3)
1228 self.assertEqual(diff, [])
1229 self.assertRaises(shutil.ReadError, unpack_archive, TESTFN)
1230 self.assertRaises(ValueError, unpack_archive, TESTFN, format='xxx')
1231
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001232 def test_unpack_registery(self):
1233
1234 formats = get_unpack_formats()
1235
1236 def _boo(filename, extract_dir, extra):
Ezio Melottib3aedd42010-11-20 19:04:17 +00001237 self.assertEqual(extra, 1)
1238 self.assertEqual(filename, 'stuff.boo')
1239 self.assertEqual(extract_dir, 'xx')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001240
1241 register_unpack_format('Boo', ['.boo', '.b2'], _boo, [('extra', 1)])
1242 unpack_archive('stuff.boo', 'xx')
1243
1244 # trying to register a .boo unpacker again
1245 self.assertRaises(RegistryError, register_unpack_format, 'Boo2',
1246 ['.boo'], _boo)
1247
1248 # should work now
1249 unregister_unpack_format('Boo')
1250 register_unpack_format('Boo2', ['.boo'], _boo)
1251 self.assertIn(('Boo2', ['.boo'], ''), get_unpack_formats())
1252 self.assertNotIn(('Boo', ['.boo'], ''), get_unpack_formats())
1253
1254 # let's leave a clean state
1255 unregister_unpack_format('Boo2')
Ezio Melottib3aedd42010-11-20 19:04:17 +00001256 self.assertEqual(get_unpack_formats(), formats)
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001257
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001258 @unittest.skipUnless(hasattr(shutil, 'disk_usage'),
1259 "disk_usage not available on this platform")
1260 def test_disk_usage(self):
1261 usage = shutil.disk_usage(os.getcwd())
Éric Araujo2ee61882011-07-02 16:45:45 +02001262 self.assertGreater(usage.total, 0)
1263 self.assertGreater(usage.used, 0)
1264 self.assertGreaterEqual(usage.free, 0)
1265 self.assertGreaterEqual(usage.total, usage.used)
1266 self.assertGreater(usage.total, usage.free)
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001267
Sandro Tosid902a142011-08-22 23:28:27 +02001268 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1269 @unittest.skipUnless(hasattr(os, 'chown'), 'requires os.chown')
1270 def test_chown(self):
1271
1272 # cleaned-up automatically by TestShutil.tearDown method
1273 dirname = self.mkdtemp()
1274 filename = tempfile.mktemp(dir=dirname)
1275 write_file(filename, 'testing chown function')
1276
1277 with self.assertRaises(ValueError):
1278 shutil.chown(filename)
1279
1280 with self.assertRaises(LookupError):
1281 shutil.chown(filename, user='non-exising username')
1282
1283 with self.assertRaises(LookupError):
1284 shutil.chown(filename, group='non-exising groupname')
1285
1286 with self.assertRaises(TypeError):
1287 shutil.chown(filename, b'spam')
1288
1289 with self.assertRaises(TypeError):
1290 shutil.chown(filename, 3.14)
1291
1292 uid = os.getuid()
1293 gid = os.getgid()
1294
1295 def check_chown(path, uid=None, gid=None):
1296 s = os.stat(filename)
1297 if uid is not None:
1298 self.assertEqual(uid, s.st_uid)
1299 if gid is not None:
1300 self.assertEqual(gid, s.st_gid)
1301
1302 shutil.chown(filename, uid, gid)
1303 check_chown(filename, uid, gid)
1304 shutil.chown(filename, uid)
1305 check_chown(filename, uid)
1306 shutil.chown(filename, user=uid)
1307 check_chown(filename, uid)
1308 shutil.chown(filename, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001309 check_chown(filename, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001310
1311 shutil.chown(dirname, uid, gid)
1312 check_chown(dirname, uid, gid)
1313 shutil.chown(dirname, uid)
1314 check_chown(dirname, uid)
1315 shutil.chown(dirname, user=uid)
1316 check_chown(dirname, uid)
1317 shutil.chown(dirname, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001318 check_chown(dirname, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001319
1320 user = pwd.getpwuid(uid)[0]
1321 group = grp.getgrgid(gid)[0]
1322 shutil.chown(filename, user, group)
1323 check_chown(filename, uid, gid)
1324 shutil.chown(dirname, user, group)
1325 check_chown(dirname, uid, gid)
1326
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001327 def test_copy_return_value(self):
1328 # copy and copy2 both return their destination path.
1329 for fn in (shutil.copy, shutil.copy2):
1330 src_dir = self.mkdtemp()
1331 dst_dir = self.mkdtemp()
1332 src = os.path.join(src_dir, 'foo')
1333 write_file(src, 'foo')
1334 rv = fn(src, dst_dir)
1335 self.assertEqual(rv, os.path.join(dst_dir, 'foo'))
1336 rv = fn(src, os.path.join(dst_dir, 'bar'))
1337 self.assertEqual(rv, os.path.join(dst_dir, 'bar'))
1338
1339 def test_copyfile_return_value(self):
1340 # copytree returns its destination path.
1341 src_dir = self.mkdtemp()
1342 dst_dir = self.mkdtemp()
1343 dst_file = os.path.join(dst_dir, 'bar')
1344 src_file = os.path.join(src_dir, 'foo')
1345 write_file(src_file, 'foo')
1346 rv = shutil.copyfile(src_file, dst_file)
1347 self.assertTrue(os.path.exists(rv))
1348 self.assertEqual(read_file(src_file), read_file(dst_file))
1349
Hynek Schlawack48653762012-10-07 12:49:58 +02001350 def test_copyfile_same_file(self):
1351 # copyfile() should raise SameFileError if the source and destination
1352 # are the same.
1353 src_dir = self.mkdtemp()
1354 src_file = os.path.join(src_dir, 'foo')
1355 write_file(src_file, 'foo')
1356 self.assertRaises(SameFileError, shutil.copyfile, src_file, src_file)
Hynek Schlawack27ddb572012-10-28 13:59:27 +01001357 # But Error should work too, to stay backward compatible.
1358 self.assertRaises(Error, shutil.copyfile, src_file, src_file)
Hynek Schlawack48653762012-10-07 12:49:58 +02001359
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001360 def test_copytree_return_value(self):
1361 # copytree returns its destination path.
1362 src_dir = self.mkdtemp()
1363 dst_dir = src_dir + "dest"
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001364 self.addCleanup(shutil.rmtree, dst_dir, True)
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001365 src = os.path.join(src_dir, 'foo')
1366 write_file(src, 'foo')
1367 rv = shutil.copytree(src_dir, dst_dir)
1368 self.assertEqual(['foo'], os.listdir(rv))
1369
Christian Heimes9bd667a2008-01-20 15:14:11 +00001370
Brian Curtinc57a3452012-06-22 16:00:30 -05001371class TestWhich(unittest.TestCase):
1372
1373 def setUp(self):
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001374 self.temp_dir = tempfile.mkdtemp(prefix="Tmp")
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001375 self.addCleanup(shutil.rmtree, self.temp_dir, True)
Brian Curtinc57a3452012-06-22 16:00:30 -05001376 # Give the temp_file an ".exe" suffix for all.
1377 # It's needed on Windows and not harmful on other platforms.
1378 self.temp_file = tempfile.NamedTemporaryFile(dir=self.temp_dir,
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001379 prefix="Tmp",
1380 suffix=".Exe")
Brian Curtinc57a3452012-06-22 16:00:30 -05001381 os.chmod(self.temp_file.name, stat.S_IXUSR)
1382 self.addCleanup(self.temp_file.close)
1383 self.dir, self.file = os.path.split(self.temp_file.name)
1384
1385 def test_basic(self):
1386 # Given an EXE in a directory, it should be returned.
1387 rv = shutil.which(self.file, path=self.dir)
1388 self.assertEqual(rv, self.temp_file.name)
1389
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001390 def test_absolute_cmd(self):
Brian Curtinc57a3452012-06-22 16:00:30 -05001391 # When given the fully qualified path to an executable that exists,
1392 # it should be returned.
1393 rv = shutil.which(self.temp_file.name, path=self.temp_dir)
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001394 self.assertEqual(rv, self.temp_file.name)
1395
1396 def test_relative_cmd(self):
1397 # When given the relative path with a directory part to an executable
1398 # that exists, it should be returned.
1399 base_dir, tail_dir = os.path.split(self.dir)
1400 relpath = os.path.join(tail_dir, self.file)
Nick Coghlan55175962013-07-28 22:11:50 +10001401 with support.change_cwd(path=base_dir):
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001402 rv = shutil.which(relpath, path=self.temp_dir)
1403 self.assertEqual(rv, relpath)
1404 # But it shouldn't be searched in PATH directories (issue #16957).
Nick Coghlan55175962013-07-28 22:11:50 +10001405 with support.change_cwd(path=self.dir):
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001406 rv = shutil.which(relpath, path=base_dir)
1407 self.assertIsNone(rv)
1408
1409 def test_cwd(self):
1410 # Issue #16957
1411 base_dir = os.path.dirname(self.dir)
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(self.file, path=base_dir)
1414 if sys.platform == "win32":
1415 # Windows: current directory implicitly on PATH
1416 self.assertEqual(rv, os.path.join(os.curdir, self.file))
1417 else:
1418 # Other platforms: shouldn't match in the current directory.
1419 self.assertIsNone(rv)
Brian Curtinc57a3452012-06-22 16:00:30 -05001420
Serhiy Storchaka12516e22013-05-28 15:50:15 +03001421 @unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0,
1422 'non-root user required')
Brian Curtinc57a3452012-06-22 16:00:30 -05001423 def test_non_matching_mode(self):
1424 # Set the file read-only and ask for writeable files.
1425 os.chmod(self.temp_file.name, stat.S_IREAD)
Serhiy Storchaka12516e22013-05-28 15:50:15 +03001426 if os.access(self.temp_file.name, os.W_OK):
1427 self.skipTest("can't set the file read-only")
Brian Curtinc57a3452012-06-22 16:00:30 -05001428 rv = shutil.which(self.file, path=self.dir, mode=os.W_OK)
1429 self.assertIsNone(rv)
1430
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001431 def test_relative_path(self):
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001432 base_dir, tail_dir = os.path.split(self.dir)
Nick Coghlan55175962013-07-28 22:11:50 +10001433 with support.change_cwd(path=base_dir):
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001434 rv = shutil.which(self.file, path=tail_dir)
1435 self.assertEqual(rv, os.path.join(tail_dir, self.file))
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001436
Brian Curtinc57a3452012-06-22 16:00:30 -05001437 def test_nonexistent_file(self):
1438 # Return None when no matching executable file is found on the path.
1439 rv = shutil.which("foo.exe", path=self.dir)
1440 self.assertIsNone(rv)
1441
1442 @unittest.skipUnless(sys.platform == "win32",
1443 "pathext check is Windows-only")
1444 def test_pathext_checking(self):
1445 # Ask for the file without the ".exe" extension, then ensure that
1446 # it gets found properly with the extension.
Serhiy Storchakad70127a2013-01-24 20:03:49 +02001447 rv = shutil.which(self.file[:-4], path=self.dir)
Serhiy Storchaka80c88f42013-01-22 10:31:36 +02001448 self.assertEqual(rv, self.temp_file.name[:-4] + ".EXE")
Brian Curtinc57a3452012-06-22 16:00:30 -05001449
Barry Warsaw618738b2013-04-16 11:05:03 -04001450 def test_environ_path(self):
1451 with support.EnvironmentVarGuard() as env:
Victor Stinner1d006a22013-12-16 23:39:40 +01001452 env['PATH'] = self.dir
Barry Warsaw618738b2013-04-16 11:05:03 -04001453 rv = shutil.which(self.file)
1454 self.assertEqual(rv, self.temp_file.name)
1455
1456 def test_empty_path(self):
1457 base_dir = os.path.dirname(self.dir)
Nick Coghlan55175962013-07-28 22:11:50 +10001458 with support.change_cwd(path=self.dir), \
Barry Warsaw618738b2013-04-16 11:05:03 -04001459 support.EnvironmentVarGuard() as env:
Victor Stinner1d006a22013-12-16 23:39:40 +01001460 env['PATH'] = self.dir
Barry Warsaw618738b2013-04-16 11:05:03 -04001461 rv = shutil.which(self.file, path='')
1462 self.assertIsNone(rv)
1463
1464 def test_empty_path_no_PATH(self):
1465 with support.EnvironmentVarGuard() as env:
1466 env.pop('PATH', None)
1467 rv = shutil.which(self.file)
1468 self.assertIsNone(rv)
1469
Brian Curtinc57a3452012-06-22 16:00:30 -05001470
Christian Heimesada8c3b2008-03-18 18:26:33 +00001471class TestMove(unittest.TestCase):
1472
1473 def setUp(self):
1474 filename = "foo"
1475 self.src_dir = tempfile.mkdtemp()
1476 self.dst_dir = tempfile.mkdtemp()
1477 self.src_file = os.path.join(self.src_dir, filename)
1478 self.dst_file = os.path.join(self.dst_dir, filename)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001479 with open(self.src_file, "wb") as f:
1480 f.write(b"spam")
1481
1482 def tearDown(self):
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001483 for d in (self.src_dir, self.dst_dir):
Christian Heimesada8c3b2008-03-18 18:26:33 +00001484 try:
1485 if d:
1486 shutil.rmtree(d)
1487 except:
1488 pass
1489
1490 def _check_move_file(self, src, dst, real_dst):
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001491 with open(src, "rb") as f:
1492 contents = f.read()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001493 shutil.move(src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001494 with open(real_dst, "rb") as f:
1495 self.assertEqual(contents, f.read())
Christian Heimesada8c3b2008-03-18 18:26:33 +00001496 self.assertFalse(os.path.exists(src))
1497
1498 def _check_move_dir(self, src, dst, real_dst):
1499 contents = sorted(os.listdir(src))
1500 shutil.move(src, dst)
1501 self.assertEqual(contents, sorted(os.listdir(real_dst)))
1502 self.assertFalse(os.path.exists(src))
1503
1504 def test_move_file(self):
1505 # Move a file to another location on the same filesystem.
1506 self._check_move_file(self.src_file, self.dst_file, self.dst_file)
1507
1508 def test_move_file_to_dir(self):
1509 # Move a file inside an existing dir on the same filesystem.
1510 self._check_move_file(self.src_file, self.dst_dir, self.dst_file)
1511
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001512 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001513 def test_move_file_other_fs(self):
1514 # Move a file to an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001515 self.test_move_file()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001516
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001517 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001518 def test_move_file_to_dir_other_fs(self):
1519 # Move a file to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001520 self.test_move_file_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001521
1522 def test_move_dir(self):
1523 # Move a dir to another location on the same filesystem.
1524 dst_dir = tempfile.mktemp()
1525 try:
1526 self._check_move_dir(self.src_dir, dst_dir, dst_dir)
1527 finally:
1528 try:
1529 shutil.rmtree(dst_dir)
1530 except:
1531 pass
1532
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001533 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001534 def test_move_dir_other_fs(self):
1535 # Move a dir to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001536 self.test_move_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001537
1538 def test_move_dir_to_dir(self):
1539 # Move a dir inside an existing dir on the same filesystem.
1540 self._check_move_dir(self.src_dir, self.dst_dir,
1541 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1542
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001543 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001544 def test_move_dir_to_dir_other_fs(self):
1545 # Move a dir inside an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001546 self.test_move_dir_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001547
Serhiy Storchaka3a308b92014-02-11 10:30:59 +02001548 def test_move_dir_sep_to_dir(self):
1549 self._check_move_dir(self.src_dir + os.path.sep, self.dst_dir,
1550 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1551
1552 @unittest.skipUnless(os.path.altsep, 'requires os.path.altsep')
1553 def test_move_dir_altsep_to_dir(self):
1554 self._check_move_dir(self.src_dir + os.path.altsep, self.dst_dir,
1555 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1556
Christian Heimesada8c3b2008-03-18 18:26:33 +00001557 def test_existing_file_inside_dest_dir(self):
1558 # A file with the same name inside the destination dir already exists.
1559 with open(self.dst_file, "wb"):
1560 pass
1561 self.assertRaises(shutil.Error, shutil.move, self.src_file, self.dst_dir)
1562
1563 def test_dont_move_dir_in_itself(self):
1564 # Moving a dir inside itself raises an Error.
1565 dst = os.path.join(self.src_dir, "bar")
1566 self.assertRaises(shutil.Error, shutil.move, self.src_dir, dst)
1567
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001568 def test_destinsrc_false_negative(self):
1569 os.mkdir(TESTFN)
1570 try:
1571 for src, dst in [('srcdir', 'srcdir/dest')]:
1572 src = os.path.join(TESTFN, src)
1573 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001574 self.assertTrue(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001575 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001576 'dst (%s) is not in src (%s)' % (dst, src))
1577 finally:
1578 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001579
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001580 def test_destinsrc_false_positive(self):
1581 os.mkdir(TESTFN)
1582 try:
1583 for src, dst in [('srcdir', 'src/dest'), ('srcdir', 'srcdir.new')]:
1584 src = os.path.join(TESTFN, src)
1585 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001586 self.assertFalse(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001587 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001588 'dst (%s) is in src (%s)' % (dst, src))
1589 finally:
1590 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimes9bd667a2008-01-20 15:14:11 +00001591
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +01001592 @support.skip_unless_symlink
1593 @mock_rename
1594 def test_move_file_symlink(self):
1595 dst = os.path.join(self.src_dir, 'bar')
1596 os.symlink(self.src_file, dst)
1597 shutil.move(dst, self.dst_file)
1598 self.assertTrue(os.path.islink(self.dst_file))
1599 self.assertTrue(os.path.samefile(self.src_file, self.dst_file))
1600
1601 @support.skip_unless_symlink
1602 @mock_rename
1603 def test_move_file_symlink_to_dir(self):
1604 filename = "bar"
1605 dst = os.path.join(self.src_dir, filename)
1606 os.symlink(self.src_file, dst)
1607 shutil.move(dst, self.dst_dir)
1608 final_link = os.path.join(self.dst_dir, filename)
1609 self.assertTrue(os.path.islink(final_link))
1610 self.assertTrue(os.path.samefile(self.src_file, final_link))
1611
1612 @support.skip_unless_symlink
1613 @mock_rename
1614 def test_move_dangling_symlink(self):
1615 src = os.path.join(self.src_dir, 'baz')
1616 dst = os.path.join(self.src_dir, 'bar')
1617 os.symlink(src, dst)
1618 dst_link = os.path.join(self.dst_dir, 'quux')
1619 shutil.move(dst, dst_link)
1620 self.assertTrue(os.path.islink(dst_link))
Antoine Pitrou3f48ac92014-01-01 02:50:45 +01001621 # On Windows, os.path.realpath does not follow symlinks (issue #9949)
1622 if os.name == 'nt':
1623 self.assertEqual(os.path.realpath(src), os.readlink(dst_link))
1624 else:
1625 self.assertEqual(os.path.realpath(src), os.path.realpath(dst_link))
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +01001626
1627 @support.skip_unless_symlink
1628 @mock_rename
1629 def test_move_dir_symlink(self):
1630 src = os.path.join(self.src_dir, 'baz')
1631 dst = os.path.join(self.src_dir, 'bar')
1632 os.mkdir(src)
1633 os.symlink(src, dst)
1634 dst_link = os.path.join(self.dst_dir, 'quux')
1635 shutil.move(dst, dst_link)
1636 self.assertTrue(os.path.islink(dst_link))
1637 self.assertTrue(os.path.samefile(src, dst_link))
1638
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001639 def test_move_return_value(self):
1640 rv = shutil.move(self.src_file, self.dst_dir)
1641 self.assertEqual(rv,
1642 os.path.join(self.dst_dir, os.path.basename(self.src_file)))
1643
1644 def test_move_as_rename_return_value(self):
1645 rv = shutil.move(self.src_file, os.path.join(self.dst_dir, 'bar'))
1646 self.assertEqual(rv, os.path.join(self.dst_dir, 'bar'))
1647
Tarek Ziadé5340db32010-04-19 22:30:51 +00001648
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001649class TestCopyFile(unittest.TestCase):
1650
1651 _delete = False
1652
1653 class Faux(object):
1654 _entered = False
1655 _exited_with = None
1656 _raised = False
1657 def __init__(self, raise_in_exit=False, suppress_at_exit=True):
1658 self._raise_in_exit = raise_in_exit
1659 self._suppress_at_exit = suppress_at_exit
1660 def read(self, *args):
1661 return ''
1662 def __enter__(self):
1663 self._entered = True
1664 def __exit__(self, exc_type, exc_val, exc_tb):
1665 self._exited_with = exc_type, exc_val, exc_tb
1666 if self._raise_in_exit:
1667 self._raised = True
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001668 raise OSError("Cannot close")
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001669 return self._suppress_at_exit
1670
1671 def tearDown(self):
1672 if self._delete:
1673 del shutil.open
1674
1675 def _set_shutil_open(self, func):
1676 shutil.open = func
1677 self._delete = True
1678
1679 def test_w_source_open_fails(self):
1680 def _open(filename, mode='r'):
1681 if filename == 'srcfile':
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001682 raise OSError('Cannot open "srcfile"')
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001683 assert 0 # shouldn't reach here.
1684
1685 self._set_shutil_open(_open)
1686
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001687 self.assertRaises(OSError, shutil.copyfile, 'srcfile', 'destfile')
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001688
1689 def test_w_dest_open_fails(self):
1690
1691 srcfile = self.Faux()
1692
1693 def _open(filename, mode='r'):
1694 if filename == 'srcfile':
1695 return srcfile
1696 if filename == 'destfile':
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001697 raise OSError('Cannot open "destfile"')
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001698 assert 0 # shouldn't reach here.
1699
1700 self._set_shutil_open(_open)
1701
1702 shutil.copyfile('srcfile', 'destfile')
1703 self.assertTrue(srcfile._entered)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001704 self.assertTrue(srcfile._exited_with[0] is OSError)
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001705 self.assertEqual(srcfile._exited_with[1].args,
1706 ('Cannot open "destfile"',))
1707
1708 def test_w_dest_close_fails(self):
1709
1710 srcfile = self.Faux()
1711 destfile = self.Faux(True)
1712
1713 def _open(filename, mode='r'):
1714 if filename == 'srcfile':
1715 return srcfile
1716 if filename == 'destfile':
1717 return destfile
1718 assert 0 # shouldn't reach here.
1719
1720 self._set_shutil_open(_open)
1721
1722 shutil.copyfile('srcfile', 'destfile')
1723 self.assertTrue(srcfile._entered)
1724 self.assertTrue(destfile._entered)
1725 self.assertTrue(destfile._raised)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001726 self.assertTrue(srcfile._exited_with[0] is OSError)
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001727 self.assertEqual(srcfile._exited_with[1].args,
1728 ('Cannot close',))
1729
1730 def test_w_source_close_fails(self):
1731
1732 srcfile = self.Faux(True)
1733 destfile = self.Faux()
1734
1735 def _open(filename, mode='r'):
1736 if filename == 'srcfile':
1737 return srcfile
1738 if filename == 'destfile':
1739 return destfile
1740 assert 0 # shouldn't reach here.
1741
1742 self._set_shutil_open(_open)
1743
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001744 self.assertRaises(OSError,
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001745 shutil.copyfile, 'srcfile', 'destfile')
1746 self.assertTrue(srcfile._entered)
1747 self.assertTrue(destfile._entered)
1748 self.assertFalse(destfile._raised)
1749 self.assertTrue(srcfile._exited_with[0] is None)
1750 self.assertTrue(srcfile._raised)
1751
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001752 def test_move_dir_caseinsensitive(self):
1753 # Renames a folder to the same name
1754 # but a different case.
1755
1756 self.src_dir = tempfile.mkdtemp()
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001757 self.addCleanup(shutil.rmtree, self.src_dir, True)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001758 dst_dir = os.path.join(
1759 os.path.dirname(self.src_dir),
1760 os.path.basename(self.src_dir).upper())
1761 self.assertNotEqual(self.src_dir, dst_dir)
1762
1763 try:
1764 shutil.move(self.src_dir, dst_dir)
1765 self.assertTrue(os.path.isdir(dst_dir))
1766 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +02001767 os.rmdir(dst_dir)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001768
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001769class TermsizeTests(unittest.TestCase):
1770 def test_does_not_crash(self):
1771 """Check if get_terminal_size() returns a meaningful value.
1772
1773 There's no easy portable way to actually check the size of the
1774 terminal, so let's check if it returns something sensible instead.
1775 """
1776 size = shutil.get_terminal_size()
Antoine Pitroucfade362012-02-08 23:48:59 +01001777 self.assertGreaterEqual(size.columns, 0)
1778 self.assertGreaterEqual(size.lines, 0)
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001779
1780 def test_os_environ_first(self):
1781 "Check if environment variables have precedence"
1782
1783 with support.EnvironmentVarGuard() as env:
1784 env['COLUMNS'] = '777'
1785 size = shutil.get_terminal_size()
1786 self.assertEqual(size.columns, 777)
1787
1788 with support.EnvironmentVarGuard() as env:
1789 env['LINES'] = '888'
1790 size = shutil.get_terminal_size()
1791 self.assertEqual(size.lines, 888)
1792
1793 @unittest.skipUnless(os.isatty(sys.__stdout__.fileno()), "not on tty")
1794 def test_stty_match(self):
1795 """Check if stty returns the same results ignoring env
1796
1797 This test will fail if stdin and stdout are connected to
1798 different terminals with different sizes. Nevertheless, such
1799 situations should be pretty rare.
1800 """
1801 try:
1802 size = subprocess.check_output(['stty', 'size']).decode().split()
1803 except (FileNotFoundError, subprocess.CalledProcessError):
1804 self.skipTest("stty invocation failed")
1805 expected = (int(size[1]), int(size[0])) # reversed order
1806
1807 with support.EnvironmentVarGuard() as env:
1808 del env['LINES']
1809 del env['COLUMNS']
1810 actual = shutil.get_terminal_size()
1811
1812 self.assertEqual(expected, actual)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001813
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001814
Berker Peksag8083cd62014-11-01 11:04:06 +02001815class PublicAPITests(unittest.TestCase):
1816 """Ensures that the correct values are exposed in the public API."""
1817
1818 def test_module_all_attribute(self):
1819 self.assertTrue(hasattr(shutil, '__all__'))
1820 target_api = ['copyfileobj', 'copyfile', 'copymode', 'copystat',
1821 'copy', 'copy2', 'copytree', 'move', 'rmtree', 'Error',
1822 'SpecialFileError', 'ExecError', 'make_archive',
1823 'get_archive_formats', 'register_archive_format',
1824 'unregister_archive_format', 'get_unpack_formats',
1825 'register_unpack_format', 'unregister_unpack_format',
1826 'unpack_archive', 'ignore_patterns', 'chown', 'which',
1827 'get_terminal_size', 'SameFileError']
1828 if hasattr(os, 'statvfs') or os.name == 'nt':
1829 target_api.append('disk_usage')
1830 self.assertEqual(set(shutil.__all__), set(target_api))
1831
1832
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001833if __name__ == '__main__':
Brett Cannon3e9a9ae2013-06-12 21:25:59 -04001834 unittest.main()