blob: 9325bc7dc15821da4694c5ada9bd11b29a3559f6 [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
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400898 def _copy_file(self, method):
899 fname = 'test.txt'
900 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200901 write_file((tmpdir, fname), 'xxx')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400902 file1 = os.path.join(tmpdir, fname)
903 tmpdir2 = self.mkdtemp()
904 method(file1, tmpdir2)
905 file2 = os.path.join(tmpdir2, fname)
906 return (file1, file2)
907
908 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
909 def test_copy(self):
910 # Ensure that the copied file exists and has the same mode bits.
911 file1, file2 = self._copy_file(shutil.copy)
912 self.assertTrue(os.path.exists(file2))
913 self.assertEqual(os.stat(file1).st_mode, os.stat(file2).st_mode)
914
915 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
Senthil Kumaran0c2dba52011-07-03 18:21:38 -0700916 @unittest.skipUnless(hasattr(os, 'utime'), 'requires os.utime')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400917 def test_copy2(self):
918 # Ensure that the copied file exists and has the same mode and
919 # modification time bits.
920 file1, file2 = self._copy_file(shutil.copy2)
921 self.assertTrue(os.path.exists(file2))
922 file1_stat = os.stat(file1)
923 file2_stat = os.stat(file2)
924 self.assertEqual(file1_stat.st_mode, file2_stat.st_mode)
925 for attr in 'st_atime', 'st_mtime':
926 # The modification times may be truncated in the new file.
927 self.assertLessEqual(getattr(file1_stat, attr),
928 getattr(file2_stat, attr) + 1)
929 if hasattr(os, 'chflags') and hasattr(file1_stat, 'st_flags'):
930 self.assertEqual(getattr(file1_stat, 'st_flags'),
931 getattr(file2_stat, 'st_flags'))
932
Ezio Melotti975077a2011-05-19 22:03:22 +0300933 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000934 def test_make_tarball(self):
935 # creating something to tar
936 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200937 write_file((tmpdir, 'file1'), 'xxx')
938 write_file((tmpdir, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000939 os.mkdir(os.path.join(tmpdir, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200940 write_file((tmpdir, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000941
942 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400943 # force shutil to create the directory
944 os.rmdir(tmpdir2)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000945 unittest.skipUnless(splitdrive(tmpdir)[0] == splitdrive(tmpdir2)[0],
946 "source and target should be on same drive")
947
948 base_name = os.path.join(tmpdir2, 'archive')
949
950 # working with relative paths to avoid tar warnings
951 old_dir = os.getcwd()
952 os.chdir(tmpdir)
953 try:
954 _make_tarball(splitdrive(base_name)[1], '.')
955 finally:
956 os.chdir(old_dir)
957
958 # check if the compressed tarball was created
959 tarball = base_name + '.tar.gz'
960 self.assertTrue(os.path.exists(tarball))
961
962 # trying an uncompressed one
963 base_name = os.path.join(tmpdir2, 'archive')
964 old_dir = os.getcwd()
965 os.chdir(tmpdir)
966 try:
967 _make_tarball(splitdrive(base_name)[1], '.', compress=None)
968 finally:
969 os.chdir(old_dir)
970 tarball = base_name + '.tar'
971 self.assertTrue(os.path.exists(tarball))
972
973 def _tarinfo(self, path):
974 tar = tarfile.open(path)
975 try:
976 names = tar.getnames()
977 names.sort()
978 return tuple(names)
979 finally:
980 tar.close()
981
982 def _create_files(self):
983 # creating something to tar
984 tmpdir = self.mkdtemp()
985 dist = os.path.join(tmpdir, 'dist')
986 os.mkdir(dist)
Éric Araujoa7e33a12011-08-12 19:51:35 +0200987 write_file((dist, 'file1'), 'xxx')
988 write_file((dist, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000989 os.mkdir(os.path.join(dist, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200990 write_file((dist, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000991 os.mkdir(os.path.join(dist, 'sub2'))
992 tmpdir2 = self.mkdtemp()
993 base_name = os.path.join(tmpdir2, 'archive')
994 return tmpdir, tmpdir2, base_name
995
Ezio Melotti975077a2011-05-19 22:03:22 +0300996 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000997 @unittest.skipUnless(find_executable('tar') and find_executable('gzip'),
998 'Need the tar command to run')
999 def test_tarfile_vs_tar(self):
1000 tmpdir, tmpdir2, base_name = self._create_files()
1001 old_dir = os.getcwd()
1002 os.chdir(tmpdir)
1003 try:
1004 _make_tarball(base_name, 'dist')
1005 finally:
1006 os.chdir(old_dir)
1007
1008 # check if the compressed tarball was created
1009 tarball = base_name + '.tar.gz'
1010 self.assertTrue(os.path.exists(tarball))
1011
1012 # now create another tarball using `tar`
1013 tarball2 = os.path.join(tmpdir, 'archive2.tar.gz')
1014 tar_cmd = ['tar', '-cf', 'archive2.tar', 'dist']
1015 gzip_cmd = ['gzip', '-f9', 'archive2.tar']
1016 old_dir = os.getcwd()
1017 os.chdir(tmpdir)
1018 try:
1019 with captured_stdout() as s:
1020 spawn(tar_cmd)
1021 spawn(gzip_cmd)
1022 finally:
1023 os.chdir(old_dir)
1024
1025 self.assertTrue(os.path.exists(tarball2))
1026 # let's compare both tarballs
Ezio Melottib3aedd42010-11-20 19:04:17 +00001027 self.assertEqual(self._tarinfo(tarball), self._tarinfo(tarball2))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001028
1029 # trying an uncompressed one
1030 base_name = os.path.join(tmpdir2, 'archive')
1031 old_dir = os.getcwd()
1032 os.chdir(tmpdir)
1033 try:
1034 _make_tarball(base_name, 'dist', compress=None)
1035 finally:
1036 os.chdir(old_dir)
1037 tarball = base_name + '.tar'
1038 self.assertTrue(os.path.exists(tarball))
1039
1040 # now for a dry_run
1041 base_name = os.path.join(tmpdir2, 'archive')
1042 old_dir = os.getcwd()
1043 os.chdir(tmpdir)
1044 try:
1045 _make_tarball(base_name, 'dist', compress=None, dry_run=True)
1046 finally:
1047 os.chdir(old_dir)
1048 tarball = base_name + '.tar'
1049 self.assertTrue(os.path.exists(tarball))
1050
Ezio Melotti975077a2011-05-19 22:03:22 +03001051 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001052 @unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run')
1053 def test_make_zipfile(self):
1054 # creating something to tar
1055 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +02001056 write_file((tmpdir, 'file1'), 'xxx')
1057 write_file((tmpdir, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +00001058
1059 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001060 # force shutil to create the directory
1061 os.rmdir(tmpdir2)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001062 base_name = os.path.join(tmpdir2, 'archive')
1063 _make_zipfile(base_name, tmpdir)
1064
1065 # check if the compressed tarball was created
1066 tarball = base_name + '.zip'
Éric Araujo1c505492010-11-06 02:12:51 +00001067 self.assertTrue(os.path.exists(tarball))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001068
1069
1070 def test_make_archive(self):
1071 tmpdir = self.mkdtemp()
1072 base_name = os.path.join(tmpdir, 'archive')
1073 self.assertRaises(ValueError, make_archive, base_name, 'xxx')
1074
Ezio Melotti975077a2011-05-19 22:03:22 +03001075 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001076 def test_make_archive_owner_group(self):
1077 # testing make_archive with owner and group, with various combinations
1078 # this works even if there's not gid/uid support
1079 if UID_GID_SUPPORT:
1080 group = grp.getgrgid(0)[0]
1081 owner = pwd.getpwuid(0)[0]
1082 else:
1083 group = owner = 'root'
1084
1085 base_dir, root_dir, base_name = self._create_files()
1086 base_name = os.path.join(self.mkdtemp() , 'archive')
1087 res = make_archive(base_name, 'zip', root_dir, base_dir, owner=owner,
1088 group=group)
1089 self.assertTrue(os.path.exists(res))
1090
1091 res = make_archive(base_name, 'zip', root_dir, base_dir)
1092 self.assertTrue(os.path.exists(res))
1093
1094 res = make_archive(base_name, 'tar', root_dir, base_dir,
1095 owner=owner, group=group)
1096 self.assertTrue(os.path.exists(res))
1097
1098 res = make_archive(base_name, 'tar', root_dir, base_dir,
1099 owner='kjhkjhkjg', group='oihohoh')
1100 self.assertTrue(os.path.exists(res))
1101
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001102
Ezio Melotti975077a2011-05-19 22:03:22 +03001103 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001104 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1105 def test_tarfile_root_owner(self):
1106 tmpdir, tmpdir2, base_name = self._create_files()
1107 old_dir = os.getcwd()
1108 os.chdir(tmpdir)
1109 group = grp.getgrgid(0)[0]
1110 owner = pwd.getpwuid(0)[0]
1111 try:
1112 archive_name = _make_tarball(base_name, 'dist', compress=None,
1113 owner=owner, group=group)
1114 finally:
1115 os.chdir(old_dir)
1116
1117 # check if the compressed tarball was created
1118 self.assertTrue(os.path.exists(archive_name))
1119
1120 # now checks the rights
1121 archive = tarfile.open(archive_name)
1122 try:
1123 for member in archive.getmembers():
Ezio Melottib3aedd42010-11-20 19:04:17 +00001124 self.assertEqual(member.uid, 0)
1125 self.assertEqual(member.gid, 0)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001126 finally:
1127 archive.close()
1128
1129 def test_make_archive_cwd(self):
1130 current_dir = os.getcwd()
1131 def _breaks(*args, **kw):
1132 raise RuntimeError()
1133
1134 register_archive_format('xxx', _breaks, [], 'xxx file')
1135 try:
1136 try:
1137 make_archive('xxx', 'xxx', root_dir=self.mkdtemp())
1138 except Exception:
1139 pass
Ezio Melottib3aedd42010-11-20 19:04:17 +00001140 self.assertEqual(os.getcwd(), current_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001141 finally:
1142 unregister_archive_format('xxx')
1143
Serhiy Storchaka9a4fc192014-11-28 00:48:46 +02001144 def test_make_tarfile_in_curdir(self):
1145 # Issue #21280
1146 root_dir = self.mkdtemp()
1147 with support.change_cwd(root_dir):
1148 self.assertEqual(make_archive('test', 'tar'), 'test.tar')
1149 self.assertTrue(os.path.isfile('test.tar'))
1150
1151 @requires_zlib
1152 def test_make_zipfile_in_curdir(self):
1153 # Issue #21280
1154 root_dir = self.mkdtemp()
1155 with support.change_cwd(root_dir):
1156 self.assertEqual(make_archive('test', 'zip'), 'test.zip')
1157 self.assertTrue(os.path.isfile('test.zip'))
1158
Tarek Ziadé396fad72010-02-23 05:30:31 +00001159 def test_register_archive_format(self):
1160
1161 self.assertRaises(TypeError, register_archive_format, 'xxx', 1)
1162 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1163 1)
1164 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1165 [(1, 2), (1, 2, 3)])
1166
1167 register_archive_format('xxx', lambda: x, [(1, 2)], 'xxx file')
1168 formats = [name for name, params in get_archive_formats()]
1169 self.assertIn('xxx', formats)
1170
1171 unregister_archive_format('xxx')
1172 formats = [name for name, params in get_archive_formats()]
1173 self.assertNotIn('xxx', formats)
1174
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001175 def _compare_dirs(self, dir1, dir2):
1176 # check that dir1 and dir2 are equivalent,
1177 # return the diff
1178 diff = []
1179 for root, dirs, files in os.walk(dir1):
1180 for file_ in files:
1181 path = os.path.join(root, file_)
1182 target_path = os.path.join(dir2, os.path.split(path)[-1])
1183 if not os.path.exists(target_path):
1184 diff.append(file_)
1185 return diff
1186
Ezio Melotti975077a2011-05-19 22:03:22 +03001187 @requires_zlib
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001188 def test_unpack_archive(self):
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001189 formats = ['tar', 'gztar', 'zip']
1190 if BZ2_SUPPORTED:
1191 formats.append('bztar')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001192
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001193 for format in formats:
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001194 tmpdir = self.mkdtemp()
1195 base_dir, root_dir, base_name = self._create_files()
1196 tmpdir2 = self.mkdtemp()
1197 filename = make_archive(base_name, format, root_dir, base_dir)
1198
1199 # let's try to unpack it now
1200 unpack_archive(filename, tmpdir2)
1201 diff = self._compare_dirs(tmpdir, tmpdir2)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001202 self.assertEqual(diff, [])
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001203
Nick Coghlanabf202d2011-03-16 13:52:20 -04001204 # and again, this time with the format specified
1205 tmpdir3 = self.mkdtemp()
1206 unpack_archive(filename, tmpdir3, format=format)
1207 diff = self._compare_dirs(tmpdir, tmpdir3)
1208 self.assertEqual(diff, [])
1209 self.assertRaises(shutil.ReadError, unpack_archive, TESTFN)
1210 self.assertRaises(ValueError, unpack_archive, TESTFN, format='xxx')
1211
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001212 def test_unpack_registery(self):
1213
1214 formats = get_unpack_formats()
1215
1216 def _boo(filename, extract_dir, extra):
Ezio Melottib3aedd42010-11-20 19:04:17 +00001217 self.assertEqual(extra, 1)
1218 self.assertEqual(filename, 'stuff.boo')
1219 self.assertEqual(extract_dir, 'xx')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001220
1221 register_unpack_format('Boo', ['.boo', '.b2'], _boo, [('extra', 1)])
1222 unpack_archive('stuff.boo', 'xx')
1223
1224 # trying to register a .boo unpacker again
1225 self.assertRaises(RegistryError, register_unpack_format, 'Boo2',
1226 ['.boo'], _boo)
1227
1228 # should work now
1229 unregister_unpack_format('Boo')
1230 register_unpack_format('Boo2', ['.boo'], _boo)
1231 self.assertIn(('Boo2', ['.boo'], ''), get_unpack_formats())
1232 self.assertNotIn(('Boo', ['.boo'], ''), get_unpack_formats())
1233
1234 # let's leave a clean state
1235 unregister_unpack_format('Boo2')
Ezio Melottib3aedd42010-11-20 19:04:17 +00001236 self.assertEqual(get_unpack_formats(), formats)
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001237
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001238 @unittest.skipUnless(hasattr(shutil, 'disk_usage'),
1239 "disk_usage not available on this platform")
1240 def test_disk_usage(self):
1241 usage = shutil.disk_usage(os.getcwd())
Éric Araujo2ee61882011-07-02 16:45:45 +02001242 self.assertGreater(usage.total, 0)
1243 self.assertGreater(usage.used, 0)
1244 self.assertGreaterEqual(usage.free, 0)
1245 self.assertGreaterEqual(usage.total, usage.used)
1246 self.assertGreater(usage.total, usage.free)
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001247
Sandro Tosid902a142011-08-22 23:28:27 +02001248 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1249 @unittest.skipUnless(hasattr(os, 'chown'), 'requires os.chown')
1250 def test_chown(self):
1251
1252 # cleaned-up automatically by TestShutil.tearDown method
1253 dirname = self.mkdtemp()
1254 filename = tempfile.mktemp(dir=dirname)
1255 write_file(filename, 'testing chown function')
1256
1257 with self.assertRaises(ValueError):
1258 shutil.chown(filename)
1259
1260 with self.assertRaises(LookupError):
1261 shutil.chown(filename, user='non-exising username')
1262
1263 with self.assertRaises(LookupError):
1264 shutil.chown(filename, group='non-exising groupname')
1265
1266 with self.assertRaises(TypeError):
1267 shutil.chown(filename, b'spam')
1268
1269 with self.assertRaises(TypeError):
1270 shutil.chown(filename, 3.14)
1271
1272 uid = os.getuid()
1273 gid = os.getgid()
1274
1275 def check_chown(path, uid=None, gid=None):
1276 s = os.stat(filename)
1277 if uid is not None:
1278 self.assertEqual(uid, s.st_uid)
1279 if gid is not None:
1280 self.assertEqual(gid, s.st_gid)
1281
1282 shutil.chown(filename, uid, gid)
1283 check_chown(filename, uid, gid)
1284 shutil.chown(filename, uid)
1285 check_chown(filename, uid)
1286 shutil.chown(filename, user=uid)
1287 check_chown(filename, uid)
1288 shutil.chown(filename, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001289 check_chown(filename, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001290
1291 shutil.chown(dirname, uid, gid)
1292 check_chown(dirname, uid, gid)
1293 shutil.chown(dirname, uid)
1294 check_chown(dirname, uid)
1295 shutil.chown(dirname, user=uid)
1296 check_chown(dirname, uid)
1297 shutil.chown(dirname, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001298 check_chown(dirname, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001299
1300 user = pwd.getpwuid(uid)[0]
1301 group = grp.getgrgid(gid)[0]
1302 shutil.chown(filename, user, group)
1303 check_chown(filename, uid, gid)
1304 shutil.chown(dirname, user, group)
1305 check_chown(dirname, uid, gid)
1306
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001307 def test_copy_return_value(self):
1308 # copy and copy2 both return their destination path.
1309 for fn in (shutil.copy, shutil.copy2):
1310 src_dir = self.mkdtemp()
1311 dst_dir = self.mkdtemp()
1312 src = os.path.join(src_dir, 'foo')
1313 write_file(src, 'foo')
1314 rv = fn(src, dst_dir)
1315 self.assertEqual(rv, os.path.join(dst_dir, 'foo'))
1316 rv = fn(src, os.path.join(dst_dir, 'bar'))
1317 self.assertEqual(rv, os.path.join(dst_dir, 'bar'))
1318
1319 def test_copyfile_return_value(self):
1320 # copytree returns its destination path.
1321 src_dir = self.mkdtemp()
1322 dst_dir = self.mkdtemp()
1323 dst_file = os.path.join(dst_dir, 'bar')
1324 src_file = os.path.join(src_dir, 'foo')
1325 write_file(src_file, 'foo')
1326 rv = shutil.copyfile(src_file, dst_file)
1327 self.assertTrue(os.path.exists(rv))
1328 self.assertEqual(read_file(src_file), read_file(dst_file))
1329
Hynek Schlawack48653762012-10-07 12:49:58 +02001330 def test_copyfile_same_file(self):
1331 # copyfile() should raise SameFileError if the source and destination
1332 # are the same.
1333 src_dir = self.mkdtemp()
1334 src_file = os.path.join(src_dir, 'foo')
1335 write_file(src_file, 'foo')
1336 self.assertRaises(SameFileError, shutil.copyfile, src_file, src_file)
Hynek Schlawack27ddb572012-10-28 13:59:27 +01001337 # But Error should work too, to stay backward compatible.
1338 self.assertRaises(Error, shutil.copyfile, src_file, src_file)
Hynek Schlawack48653762012-10-07 12:49:58 +02001339
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001340 def test_copytree_return_value(self):
1341 # copytree returns its destination path.
1342 src_dir = self.mkdtemp()
1343 dst_dir = src_dir + "dest"
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001344 self.addCleanup(shutil.rmtree, dst_dir, True)
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001345 src = os.path.join(src_dir, 'foo')
1346 write_file(src, 'foo')
1347 rv = shutil.copytree(src_dir, dst_dir)
1348 self.assertEqual(['foo'], os.listdir(rv))
1349
Christian Heimes9bd667a2008-01-20 15:14:11 +00001350
Brian Curtinc57a3452012-06-22 16:00:30 -05001351class TestWhich(unittest.TestCase):
1352
1353 def setUp(self):
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001354 self.temp_dir = tempfile.mkdtemp(prefix="Tmp")
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001355 self.addCleanup(shutil.rmtree, self.temp_dir, True)
Brian Curtinc57a3452012-06-22 16:00:30 -05001356 # Give the temp_file an ".exe" suffix for all.
1357 # It's needed on Windows and not harmful on other platforms.
1358 self.temp_file = tempfile.NamedTemporaryFile(dir=self.temp_dir,
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001359 prefix="Tmp",
1360 suffix=".Exe")
Brian Curtinc57a3452012-06-22 16:00:30 -05001361 os.chmod(self.temp_file.name, stat.S_IXUSR)
1362 self.addCleanup(self.temp_file.close)
1363 self.dir, self.file = os.path.split(self.temp_file.name)
1364
1365 def test_basic(self):
1366 # Given an EXE in a directory, it should be returned.
1367 rv = shutil.which(self.file, path=self.dir)
1368 self.assertEqual(rv, self.temp_file.name)
1369
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001370 def test_absolute_cmd(self):
Brian Curtinc57a3452012-06-22 16:00:30 -05001371 # When given the fully qualified path to an executable that exists,
1372 # it should be returned.
1373 rv = shutil.which(self.temp_file.name, path=self.temp_dir)
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001374 self.assertEqual(rv, self.temp_file.name)
1375
1376 def test_relative_cmd(self):
1377 # When given the relative path with a directory part to an executable
1378 # that exists, it should be returned.
1379 base_dir, tail_dir = os.path.split(self.dir)
1380 relpath = os.path.join(tail_dir, self.file)
Nick Coghlan55175962013-07-28 22:11:50 +10001381 with support.change_cwd(path=base_dir):
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001382 rv = shutil.which(relpath, path=self.temp_dir)
1383 self.assertEqual(rv, relpath)
1384 # But it shouldn't be searched in PATH directories (issue #16957).
Nick Coghlan55175962013-07-28 22:11:50 +10001385 with support.change_cwd(path=self.dir):
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001386 rv = shutil.which(relpath, path=base_dir)
1387 self.assertIsNone(rv)
1388
1389 def test_cwd(self):
1390 # Issue #16957
1391 base_dir = os.path.dirname(self.dir)
Nick Coghlan55175962013-07-28 22:11:50 +10001392 with support.change_cwd(path=self.dir):
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001393 rv = shutil.which(self.file, path=base_dir)
1394 if sys.platform == "win32":
1395 # Windows: current directory implicitly on PATH
1396 self.assertEqual(rv, os.path.join(os.curdir, self.file))
1397 else:
1398 # Other platforms: shouldn't match in the current directory.
1399 self.assertIsNone(rv)
Brian Curtinc57a3452012-06-22 16:00:30 -05001400
Serhiy Storchaka12516e22013-05-28 15:50:15 +03001401 @unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0,
1402 'non-root user required')
Brian Curtinc57a3452012-06-22 16:00:30 -05001403 def test_non_matching_mode(self):
1404 # Set the file read-only and ask for writeable files.
1405 os.chmod(self.temp_file.name, stat.S_IREAD)
Serhiy Storchaka12516e22013-05-28 15:50:15 +03001406 if os.access(self.temp_file.name, os.W_OK):
1407 self.skipTest("can't set the file read-only")
Brian Curtinc57a3452012-06-22 16:00:30 -05001408 rv = shutil.which(self.file, path=self.dir, mode=os.W_OK)
1409 self.assertIsNone(rv)
1410
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001411 def test_relative_path(self):
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001412 base_dir, tail_dir = os.path.split(self.dir)
Nick Coghlan55175962013-07-28 22:11:50 +10001413 with support.change_cwd(path=base_dir):
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001414 rv = shutil.which(self.file, path=tail_dir)
1415 self.assertEqual(rv, os.path.join(tail_dir, self.file))
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001416
Brian Curtinc57a3452012-06-22 16:00:30 -05001417 def test_nonexistent_file(self):
1418 # Return None when no matching executable file is found on the path.
1419 rv = shutil.which("foo.exe", path=self.dir)
1420 self.assertIsNone(rv)
1421
1422 @unittest.skipUnless(sys.platform == "win32",
1423 "pathext check is Windows-only")
1424 def test_pathext_checking(self):
1425 # Ask for the file without the ".exe" extension, then ensure that
1426 # it gets found properly with the extension.
Serhiy Storchakad70127a2013-01-24 20:03:49 +02001427 rv = shutil.which(self.file[:-4], path=self.dir)
Serhiy Storchaka80c88f42013-01-22 10:31:36 +02001428 self.assertEqual(rv, self.temp_file.name[:-4] + ".EXE")
Brian Curtinc57a3452012-06-22 16:00:30 -05001429
Barry Warsaw618738b2013-04-16 11:05:03 -04001430 def test_environ_path(self):
1431 with support.EnvironmentVarGuard() as env:
Victor Stinner1d006a22013-12-16 23:39:40 +01001432 env['PATH'] = self.dir
Barry Warsaw618738b2013-04-16 11:05:03 -04001433 rv = shutil.which(self.file)
1434 self.assertEqual(rv, self.temp_file.name)
1435
1436 def test_empty_path(self):
1437 base_dir = os.path.dirname(self.dir)
Nick Coghlan55175962013-07-28 22:11:50 +10001438 with support.change_cwd(path=self.dir), \
Barry Warsaw618738b2013-04-16 11:05:03 -04001439 support.EnvironmentVarGuard() as env:
Victor Stinner1d006a22013-12-16 23:39:40 +01001440 env['PATH'] = self.dir
Barry Warsaw618738b2013-04-16 11:05:03 -04001441 rv = shutil.which(self.file, path='')
1442 self.assertIsNone(rv)
1443
1444 def test_empty_path_no_PATH(self):
1445 with support.EnvironmentVarGuard() as env:
1446 env.pop('PATH', None)
1447 rv = shutil.which(self.file)
1448 self.assertIsNone(rv)
1449
Brian Curtinc57a3452012-06-22 16:00:30 -05001450
Christian Heimesada8c3b2008-03-18 18:26:33 +00001451class TestMove(unittest.TestCase):
1452
1453 def setUp(self):
1454 filename = "foo"
1455 self.src_dir = tempfile.mkdtemp()
1456 self.dst_dir = tempfile.mkdtemp()
1457 self.src_file = os.path.join(self.src_dir, filename)
1458 self.dst_file = os.path.join(self.dst_dir, filename)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001459 with open(self.src_file, "wb") as f:
1460 f.write(b"spam")
1461
1462 def tearDown(self):
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001463 for d in (self.src_dir, self.dst_dir):
Christian Heimesada8c3b2008-03-18 18:26:33 +00001464 try:
1465 if d:
1466 shutil.rmtree(d)
1467 except:
1468 pass
1469
1470 def _check_move_file(self, src, dst, real_dst):
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001471 with open(src, "rb") as f:
1472 contents = f.read()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001473 shutil.move(src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001474 with open(real_dst, "rb") as f:
1475 self.assertEqual(contents, f.read())
Christian Heimesada8c3b2008-03-18 18:26:33 +00001476 self.assertFalse(os.path.exists(src))
1477
1478 def _check_move_dir(self, src, dst, real_dst):
1479 contents = sorted(os.listdir(src))
1480 shutil.move(src, dst)
1481 self.assertEqual(contents, sorted(os.listdir(real_dst)))
1482 self.assertFalse(os.path.exists(src))
1483
1484 def test_move_file(self):
1485 # Move a file to another location on the same filesystem.
1486 self._check_move_file(self.src_file, self.dst_file, self.dst_file)
1487
1488 def test_move_file_to_dir(self):
1489 # Move a file inside an existing dir on the same filesystem.
1490 self._check_move_file(self.src_file, self.dst_dir, self.dst_file)
1491
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001492 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001493 def test_move_file_other_fs(self):
1494 # Move a file to an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001495 self.test_move_file()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001496
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001497 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001498 def test_move_file_to_dir_other_fs(self):
1499 # Move a file to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001500 self.test_move_file_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001501
1502 def test_move_dir(self):
1503 # Move a dir to another location on the same filesystem.
1504 dst_dir = tempfile.mktemp()
1505 try:
1506 self._check_move_dir(self.src_dir, dst_dir, dst_dir)
1507 finally:
1508 try:
1509 shutil.rmtree(dst_dir)
1510 except:
1511 pass
1512
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001513 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001514 def test_move_dir_other_fs(self):
1515 # Move a dir to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001516 self.test_move_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001517
1518 def test_move_dir_to_dir(self):
1519 # Move a dir inside an existing dir on the same filesystem.
1520 self._check_move_dir(self.src_dir, self.dst_dir,
1521 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1522
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001523 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001524 def test_move_dir_to_dir_other_fs(self):
1525 # Move a dir inside an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001526 self.test_move_dir_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001527
Serhiy Storchaka3a308b92014-02-11 10:30:59 +02001528 def test_move_dir_sep_to_dir(self):
1529 self._check_move_dir(self.src_dir + os.path.sep, self.dst_dir,
1530 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1531
1532 @unittest.skipUnless(os.path.altsep, 'requires os.path.altsep')
1533 def test_move_dir_altsep_to_dir(self):
1534 self._check_move_dir(self.src_dir + os.path.altsep, self.dst_dir,
1535 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1536
Christian Heimesada8c3b2008-03-18 18:26:33 +00001537 def test_existing_file_inside_dest_dir(self):
1538 # A file with the same name inside the destination dir already exists.
1539 with open(self.dst_file, "wb"):
1540 pass
1541 self.assertRaises(shutil.Error, shutil.move, self.src_file, self.dst_dir)
1542
1543 def test_dont_move_dir_in_itself(self):
1544 # Moving a dir inside itself raises an Error.
1545 dst = os.path.join(self.src_dir, "bar")
1546 self.assertRaises(shutil.Error, shutil.move, self.src_dir, dst)
1547
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001548 def test_destinsrc_false_negative(self):
1549 os.mkdir(TESTFN)
1550 try:
1551 for src, dst in [('srcdir', 'srcdir/dest')]:
1552 src = os.path.join(TESTFN, src)
1553 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001554 self.assertTrue(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001555 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001556 'dst (%s) is not in src (%s)' % (dst, src))
1557 finally:
1558 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001559
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001560 def test_destinsrc_false_positive(self):
1561 os.mkdir(TESTFN)
1562 try:
1563 for src, dst in [('srcdir', 'src/dest'), ('srcdir', 'srcdir.new')]:
1564 src = os.path.join(TESTFN, src)
1565 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001566 self.assertFalse(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001567 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001568 'dst (%s) is in src (%s)' % (dst, src))
1569 finally:
1570 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimes9bd667a2008-01-20 15:14:11 +00001571
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +01001572 @support.skip_unless_symlink
1573 @mock_rename
1574 def test_move_file_symlink(self):
1575 dst = os.path.join(self.src_dir, 'bar')
1576 os.symlink(self.src_file, dst)
1577 shutil.move(dst, self.dst_file)
1578 self.assertTrue(os.path.islink(self.dst_file))
1579 self.assertTrue(os.path.samefile(self.src_file, self.dst_file))
1580
1581 @support.skip_unless_symlink
1582 @mock_rename
1583 def test_move_file_symlink_to_dir(self):
1584 filename = "bar"
1585 dst = os.path.join(self.src_dir, filename)
1586 os.symlink(self.src_file, dst)
1587 shutil.move(dst, self.dst_dir)
1588 final_link = os.path.join(self.dst_dir, filename)
1589 self.assertTrue(os.path.islink(final_link))
1590 self.assertTrue(os.path.samefile(self.src_file, final_link))
1591
1592 @support.skip_unless_symlink
1593 @mock_rename
1594 def test_move_dangling_symlink(self):
1595 src = os.path.join(self.src_dir, 'baz')
1596 dst = os.path.join(self.src_dir, 'bar')
1597 os.symlink(src, dst)
1598 dst_link = os.path.join(self.dst_dir, 'quux')
1599 shutil.move(dst, dst_link)
1600 self.assertTrue(os.path.islink(dst_link))
Antoine Pitrou3f48ac92014-01-01 02:50:45 +01001601 # On Windows, os.path.realpath does not follow symlinks (issue #9949)
1602 if os.name == 'nt':
1603 self.assertEqual(os.path.realpath(src), os.readlink(dst_link))
1604 else:
1605 self.assertEqual(os.path.realpath(src), os.path.realpath(dst_link))
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +01001606
1607 @support.skip_unless_symlink
1608 @mock_rename
1609 def test_move_dir_symlink(self):
1610 src = os.path.join(self.src_dir, 'baz')
1611 dst = os.path.join(self.src_dir, 'bar')
1612 os.mkdir(src)
1613 os.symlink(src, dst)
1614 dst_link = os.path.join(self.dst_dir, 'quux')
1615 shutil.move(dst, dst_link)
1616 self.assertTrue(os.path.islink(dst_link))
1617 self.assertTrue(os.path.samefile(src, dst_link))
1618
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001619 def test_move_return_value(self):
1620 rv = shutil.move(self.src_file, self.dst_dir)
1621 self.assertEqual(rv,
1622 os.path.join(self.dst_dir, os.path.basename(self.src_file)))
1623
1624 def test_move_as_rename_return_value(self):
1625 rv = shutil.move(self.src_file, os.path.join(self.dst_dir, 'bar'))
1626 self.assertEqual(rv, os.path.join(self.dst_dir, 'bar'))
1627
Tarek Ziadé5340db32010-04-19 22:30:51 +00001628
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001629class TestCopyFile(unittest.TestCase):
1630
1631 _delete = False
1632
1633 class Faux(object):
1634 _entered = False
1635 _exited_with = None
1636 _raised = False
1637 def __init__(self, raise_in_exit=False, suppress_at_exit=True):
1638 self._raise_in_exit = raise_in_exit
1639 self._suppress_at_exit = suppress_at_exit
1640 def read(self, *args):
1641 return ''
1642 def __enter__(self):
1643 self._entered = True
1644 def __exit__(self, exc_type, exc_val, exc_tb):
1645 self._exited_with = exc_type, exc_val, exc_tb
1646 if self._raise_in_exit:
1647 self._raised = True
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001648 raise OSError("Cannot close")
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001649 return self._suppress_at_exit
1650
1651 def tearDown(self):
1652 if self._delete:
1653 del shutil.open
1654
1655 def _set_shutil_open(self, func):
1656 shutil.open = func
1657 self._delete = True
1658
1659 def test_w_source_open_fails(self):
1660 def _open(filename, mode='r'):
1661 if filename == 'srcfile':
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001662 raise OSError('Cannot open "srcfile"')
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001663 assert 0 # shouldn't reach here.
1664
1665 self._set_shutil_open(_open)
1666
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001667 self.assertRaises(OSError, shutil.copyfile, 'srcfile', 'destfile')
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001668
1669 def test_w_dest_open_fails(self):
1670
1671 srcfile = self.Faux()
1672
1673 def _open(filename, mode='r'):
1674 if filename == 'srcfile':
1675 return srcfile
1676 if filename == 'destfile':
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001677 raise OSError('Cannot open "destfile"')
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001678 assert 0 # shouldn't reach here.
1679
1680 self._set_shutil_open(_open)
1681
1682 shutil.copyfile('srcfile', 'destfile')
1683 self.assertTrue(srcfile._entered)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001684 self.assertTrue(srcfile._exited_with[0] is OSError)
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001685 self.assertEqual(srcfile._exited_with[1].args,
1686 ('Cannot open "destfile"',))
1687
1688 def test_w_dest_close_fails(self):
1689
1690 srcfile = self.Faux()
1691 destfile = self.Faux(True)
1692
1693 def _open(filename, mode='r'):
1694 if filename == 'srcfile':
1695 return srcfile
1696 if filename == 'destfile':
1697 return destfile
1698 assert 0 # shouldn't reach here.
1699
1700 self._set_shutil_open(_open)
1701
1702 shutil.copyfile('srcfile', 'destfile')
1703 self.assertTrue(srcfile._entered)
1704 self.assertTrue(destfile._entered)
1705 self.assertTrue(destfile._raised)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001706 self.assertTrue(srcfile._exited_with[0] is OSError)
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001707 self.assertEqual(srcfile._exited_with[1].args,
1708 ('Cannot close',))
1709
1710 def test_w_source_close_fails(self):
1711
1712 srcfile = self.Faux(True)
1713 destfile = self.Faux()
1714
1715 def _open(filename, mode='r'):
1716 if filename == 'srcfile':
1717 return srcfile
1718 if filename == 'destfile':
1719 return destfile
1720 assert 0 # shouldn't reach here.
1721
1722 self._set_shutil_open(_open)
1723
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001724 self.assertRaises(OSError,
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001725 shutil.copyfile, 'srcfile', 'destfile')
1726 self.assertTrue(srcfile._entered)
1727 self.assertTrue(destfile._entered)
1728 self.assertFalse(destfile._raised)
1729 self.assertTrue(srcfile._exited_with[0] is None)
1730 self.assertTrue(srcfile._raised)
1731
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001732 def test_move_dir_caseinsensitive(self):
1733 # Renames a folder to the same name
1734 # but a different case.
1735
1736 self.src_dir = tempfile.mkdtemp()
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001737 self.addCleanup(shutil.rmtree, self.src_dir, True)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001738 dst_dir = os.path.join(
1739 os.path.dirname(self.src_dir),
1740 os.path.basename(self.src_dir).upper())
1741 self.assertNotEqual(self.src_dir, dst_dir)
1742
1743 try:
1744 shutil.move(self.src_dir, dst_dir)
1745 self.assertTrue(os.path.isdir(dst_dir))
1746 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +02001747 os.rmdir(dst_dir)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001748
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001749class TermsizeTests(unittest.TestCase):
1750 def test_does_not_crash(self):
1751 """Check if get_terminal_size() returns a meaningful value.
1752
1753 There's no easy portable way to actually check the size of the
1754 terminal, so let's check if it returns something sensible instead.
1755 """
1756 size = shutil.get_terminal_size()
Antoine Pitroucfade362012-02-08 23:48:59 +01001757 self.assertGreaterEqual(size.columns, 0)
1758 self.assertGreaterEqual(size.lines, 0)
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001759
1760 def test_os_environ_first(self):
1761 "Check if environment variables have precedence"
1762
1763 with support.EnvironmentVarGuard() as env:
1764 env['COLUMNS'] = '777'
1765 size = shutil.get_terminal_size()
1766 self.assertEqual(size.columns, 777)
1767
1768 with support.EnvironmentVarGuard() as env:
1769 env['LINES'] = '888'
1770 size = shutil.get_terminal_size()
1771 self.assertEqual(size.lines, 888)
1772
1773 @unittest.skipUnless(os.isatty(sys.__stdout__.fileno()), "not on tty")
1774 def test_stty_match(self):
1775 """Check if stty returns the same results ignoring env
1776
1777 This test will fail if stdin and stdout are connected to
1778 different terminals with different sizes. Nevertheless, such
1779 situations should be pretty rare.
1780 """
1781 try:
1782 size = subprocess.check_output(['stty', 'size']).decode().split()
1783 except (FileNotFoundError, subprocess.CalledProcessError):
1784 self.skipTest("stty invocation failed")
1785 expected = (int(size[1]), int(size[0])) # reversed order
1786
1787 with support.EnvironmentVarGuard() as env:
1788 del env['LINES']
1789 del env['COLUMNS']
1790 actual = shutil.get_terminal_size()
1791
1792 self.assertEqual(expected, actual)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001793
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001794
Berker Peksag8083cd62014-11-01 11:04:06 +02001795class PublicAPITests(unittest.TestCase):
1796 """Ensures that the correct values are exposed in the public API."""
1797
1798 def test_module_all_attribute(self):
1799 self.assertTrue(hasattr(shutil, '__all__'))
1800 target_api = ['copyfileobj', 'copyfile', 'copymode', 'copystat',
1801 'copy', 'copy2', 'copytree', 'move', 'rmtree', 'Error',
1802 'SpecialFileError', 'ExecError', 'make_archive',
1803 'get_archive_formats', 'register_archive_format',
1804 'unregister_archive_format', 'get_unpack_formats',
1805 'register_unpack_format', 'unregister_unpack_format',
1806 'unpack_archive', 'ignore_patterns', 'chown', 'which',
1807 'get_terminal_size', 'SameFileError']
1808 if hasattr(os, 'statvfs') or os.name == 'nt':
1809 target_api.append('disk_usage')
1810 self.assertEqual(set(shutil.__all__), set(target_api))
1811
1812
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001813if __name__ == '__main__':
Brett Cannon3e9a9ae2013-06-12 21:25:59 -04001814 unittest.main()