blob: 5183c3ca60072401e2c42c3e803ac364fa0d6d1d [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
Serhiy Storchaka11213772014-08-06 18:50:19 +030037try:
38 import lzma
39 LZMA_SUPPORTED = True
40except ImportError:
41 LZMA_SUPPORTED = False
42
Antoine Pitrou7fff0962009-05-01 21:09:44 +000043TESTFN2 = TESTFN + "2"
Barry Warsaw7fc2cca2003-01-24 17:34:13 +000044
Tarek Ziadé396fad72010-02-23 05:30:31 +000045try:
46 import grp
47 import pwd
48 UID_GID_SUPPORT = True
49except ImportError:
50 UID_GID_SUPPORT = False
51
52try:
Tarek Ziadé396fad72010-02-23 05:30:31 +000053 import zipfile
54 ZIP_SUPPORT = True
55except ImportError:
56 ZIP_SUPPORT = find_executable('zip')
57
Nick Coghlan8ed3cf32011-03-16 14:05:35 -040058def _fake_rename(*args, **kwargs):
59 # Pretend the destination path is on a different filesystem.
Antoine Pitrouc041ab62012-01-02 19:18:02 +010060 raise OSError(getattr(errno, 'EXDEV', 18), "Invalid cross-device link")
Nick Coghlan8ed3cf32011-03-16 14:05:35 -040061
62def mock_rename(func):
63 @functools.wraps(func)
64 def wrap(*args, **kwargs):
65 try:
66 builtin_rename = os.rename
67 os.rename = _fake_rename
68 return func(*args, **kwargs)
69 finally:
70 os.rename = builtin_rename
71 return wrap
72
Éric Araujoa7e33a12011-08-12 19:51:35 +020073def write_file(path, content, binary=False):
74 """Write *content* to a file located at *path*.
75
76 If *path* is a tuple instead of a string, os.path.join will be used to
77 make a path. If *binary* is true, the file will be opened in binary
78 mode.
79 """
80 if isinstance(path, tuple):
81 path = os.path.join(*path)
82 with open(path, 'wb' if binary else 'w') as fp:
83 fp.write(content)
84
85def read_file(path, binary=False):
86 """Return contents from a file located at *path*.
87
88 If *path* is a tuple instead of a string, os.path.join will be used to
89 make a path. If *binary* is true, the file will be opened in binary
90 mode.
91 """
92 if isinstance(path, tuple):
93 path = os.path.join(*path)
94 with open(path, 'rb' if binary else 'r') as fp:
95 return fp.read()
96
97
Barry Warsaw7fc2cca2003-01-24 17:34:13 +000098class TestShutil(unittest.TestCase):
Tarek Ziadé396fad72010-02-23 05:30:31 +000099
100 def setUp(self):
101 super(TestShutil, self).setUp()
102 self.tempdirs = []
103
104 def tearDown(self):
105 super(TestShutil, self).tearDown()
106 while self.tempdirs:
107 d = self.tempdirs.pop()
108 shutil.rmtree(d, os.name in ('nt', 'cygwin'))
109
Tarek Ziadé396fad72010-02-23 05:30:31 +0000110
111 def mkdtemp(self):
112 """Create a temporary directory that will be cleaned up.
113
114 Returns the path of the directory.
115 """
116 d = tempfile.mkdtemp()
117 self.tempdirs.append(d)
118 return d
Tarek Ziadé5340db32010-04-19 22:30:51 +0000119
Hynek Schlawack3b527782012-06-25 13:27:31 +0200120 def test_rmtree_works_on_bytes(self):
121 tmp = self.mkdtemp()
122 victim = os.path.join(tmp, 'killme')
123 os.mkdir(victim)
124 write_file(os.path.join(victim, 'somefile'), 'foo')
125 victim = os.fsencode(victim)
126 self.assertIsInstance(victim, bytes)
Serhiy Storchaka41ad77c2014-08-07 19:38:37 +0300127 win = (os.name == 'nt')
128 with self.assertWarns(DeprecationWarning) if win else ExitStack():
129 shutil.rmtree(victim)
Hynek Schlawack3b527782012-06-25 13:27:31 +0200130
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200131 @support.skip_unless_symlink
132 def test_rmtree_fails_on_symlink(self):
133 tmp = self.mkdtemp()
134 dir_ = os.path.join(tmp, 'dir')
135 os.mkdir(dir_)
136 link = os.path.join(tmp, 'link')
137 os.symlink(dir_, link)
138 self.assertRaises(OSError, shutil.rmtree, link)
139 self.assertTrue(os.path.exists(dir_))
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100140 self.assertTrue(os.path.lexists(link))
141 errors = []
142 def onerror(*args):
143 errors.append(args)
144 shutil.rmtree(link, onerror=onerror)
145 self.assertEqual(len(errors), 1)
146 self.assertIs(errors[0][0], os.path.islink)
147 self.assertEqual(errors[0][1], link)
148 self.assertIsInstance(errors[0][2][1], OSError)
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200149
150 @support.skip_unless_symlink
151 def test_rmtree_works_on_symlinks(self):
152 tmp = self.mkdtemp()
153 dir1 = os.path.join(tmp, 'dir1')
154 dir2 = os.path.join(dir1, 'dir2')
155 dir3 = os.path.join(tmp, 'dir3')
156 for d in dir1, dir2, dir3:
157 os.mkdir(d)
158 file1 = os.path.join(tmp, 'file1')
159 write_file(file1, 'foo')
160 link1 = os.path.join(dir1, 'link1')
161 os.symlink(dir2, link1)
162 link2 = os.path.join(dir1, 'link2')
163 os.symlink(dir3, link2)
164 link3 = os.path.join(dir1, 'link3')
165 os.symlink(file1, link3)
166 # make sure symlinks are removed but not followed
167 shutil.rmtree(dir1)
168 self.assertFalse(os.path.exists(dir1))
169 self.assertTrue(os.path.exists(dir3))
170 self.assertTrue(os.path.exists(file1))
171
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000172 def test_rmtree_errors(self):
173 # filename is guaranteed not to exist
174 filename = tempfile.mktemp()
Hynek Schlawackb5501102012-12-10 09:11:25 +0100175 self.assertRaises(FileNotFoundError, shutil.rmtree, filename)
176 # test that ignore_errors option is honored
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100177 shutil.rmtree(filename, ignore_errors=True)
178
179 # existing file
180 tmpdir = self.mkdtemp()
Hynek Schlawackb5501102012-12-10 09:11:25 +0100181 write_file((tmpdir, "tstfile"), "")
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100182 filename = os.path.join(tmpdir, "tstfile")
Hynek Schlawackb5501102012-12-10 09:11:25 +0100183 with self.assertRaises(NotADirectoryError) as cm:
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100184 shutil.rmtree(filename)
Hynek Schlawack87f9b462012-12-10 16:29:57 +0100185 # The reason for this rather odd construct is that Windows sprinkles
186 # a \*.* at the end of file names. But only sometimes on some buildbots
187 possible_args = [filename, os.path.join(filename, '*.*')]
188 self.assertIn(cm.exception.filename, possible_args)
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100189 self.assertTrue(os.path.exists(filename))
Hynek Schlawackb5501102012-12-10 09:11:25 +0100190 # test that ignore_errors option is honored
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100191 shutil.rmtree(filename, ignore_errors=True)
192 self.assertTrue(os.path.exists(filename))
193 errors = []
194 def onerror(*args):
195 errors.append(args)
196 shutil.rmtree(filename, onerror=onerror)
197 self.assertEqual(len(errors), 2)
198 self.assertIs(errors[0][0], os.listdir)
199 self.assertEqual(errors[0][1], filename)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100200 self.assertIsInstance(errors[0][2][1], NotADirectoryError)
Hynek Schlawack87f9b462012-12-10 16:29:57 +0100201 self.assertIn(errors[0][2][1].filename, possible_args)
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100202 self.assertIs(errors[1][0], os.rmdir)
203 self.assertEqual(errors[1][1], filename)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100204 self.assertIsInstance(errors[1][2][1], NotADirectoryError)
Hynek Schlawack87f9b462012-12-10 16:29:57 +0100205 self.assertIn(errors[1][2][1].filename, possible_args)
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000206
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000207
Serhiy Storchaka43767632013-11-03 21:31:38 +0200208 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod()')
209 @unittest.skipIf(sys.platform[:6] == 'cygwin',
210 "This test can't be run on Cygwin (issue #1071513).")
211 @unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0,
212 "This test can't be run reliably as root (issue #1076467).")
213 def test_on_error(self):
214 self.errorState = 0
215 os.mkdir(TESTFN)
216 self.addCleanup(shutil.rmtree, TESTFN)
Antoine Pitrou2f8a75c2012-06-23 21:28:15 +0200217
Serhiy Storchaka43767632013-11-03 21:31:38 +0200218 self.child_file_path = os.path.join(TESTFN, 'a')
219 self.child_dir_path = os.path.join(TESTFN, 'b')
220 support.create_empty_file(self.child_file_path)
221 os.mkdir(self.child_dir_path)
222 old_dir_mode = os.stat(TESTFN).st_mode
223 old_child_file_mode = os.stat(self.child_file_path).st_mode
224 old_child_dir_mode = os.stat(self.child_dir_path).st_mode
225 # Make unwritable.
226 new_mode = stat.S_IREAD|stat.S_IEXEC
227 os.chmod(self.child_file_path, new_mode)
228 os.chmod(self.child_dir_path, new_mode)
229 os.chmod(TESTFN, new_mode)
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000230
Serhiy Storchaka43767632013-11-03 21:31:38 +0200231 self.addCleanup(os.chmod, TESTFN, old_dir_mode)
232 self.addCleanup(os.chmod, self.child_file_path, old_child_file_mode)
233 self.addCleanup(os.chmod, self.child_dir_path, old_child_dir_mode)
Antoine Pitrou2f8a75c2012-06-23 21:28:15 +0200234
Serhiy Storchaka43767632013-11-03 21:31:38 +0200235 shutil.rmtree(TESTFN, onerror=self.check_args_to_onerror)
236 # Test whether onerror has actually been called.
237 self.assertEqual(self.errorState, 3,
238 "Expected call to onerror function did not happen.")
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000239
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000240 def check_args_to_onerror(self, func, arg, exc):
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000241 # test_rmtree_errors deliberately runs rmtree
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200242 # on a directory that is chmod 500, which will fail.
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000243 # This function is run when shutil.rmtree fails.
244 # 99.9% of the time it initially fails to remove
245 # a file in the directory, so the first time through
246 # func is os.remove.
247 # However, some Linux machines running ZFS on
248 # FUSE experienced a failure earlier in the process
249 # at os.listdir. The first failure may legally
250 # be either.
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200251 if self.errorState < 2:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200252 if func is os.unlink:
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200253 self.assertEqual(arg, self.child_file_path)
254 elif func is os.rmdir:
255 self.assertEqual(arg, self.child_dir_path)
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000256 else:
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200257 self.assertIs(func, os.listdir)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200258 self.assertIn(arg, [TESTFN, self.child_dir_path])
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000259 self.assertTrue(issubclass(exc[0], OSError))
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200260 self.errorState += 1
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000261 else:
262 self.assertEqual(func, os.rmdir)
263 self.assertEqual(arg, TESTFN)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000264 self.assertTrue(issubclass(exc[0], OSError))
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200265 self.errorState = 3
266
267 def test_rmtree_does_not_choke_on_failing_lstat(self):
268 try:
269 orig_lstat = os.lstat
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200270 def raiser(fn, *args, **kwargs):
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200271 if fn != TESTFN:
272 raise OSError()
273 else:
274 return orig_lstat(fn)
275 os.lstat = raiser
276
277 os.mkdir(TESTFN)
278 write_file((TESTFN, 'foo'), 'foo')
279 shutil.rmtree(TESTFN)
280 finally:
281 os.lstat = orig_lstat
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000282
Antoine Pitrou78091e62011-12-29 18:54:15 +0100283 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
284 @support.skip_unless_symlink
285 def test_copymode_follow_symlinks(self):
286 tmp_dir = self.mkdtemp()
287 src = os.path.join(tmp_dir, 'foo')
288 dst = os.path.join(tmp_dir, 'bar')
289 src_link = os.path.join(tmp_dir, 'baz')
290 dst_link = os.path.join(tmp_dir, 'quux')
291 write_file(src, 'foo')
292 write_file(dst, 'foo')
293 os.symlink(src, src_link)
294 os.symlink(dst, dst_link)
295 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
296 # file to file
297 os.chmod(dst, stat.S_IRWXO)
298 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
299 shutil.copymode(src, dst)
300 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
Antoine Pitrou3f48ac92014-01-01 02:50:45 +0100301 # On Windows, os.chmod does not follow symlinks (issue #15411)
302 if os.name != 'nt':
303 # follow src link
304 os.chmod(dst, stat.S_IRWXO)
305 shutil.copymode(src_link, dst)
306 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
307 # follow dst link
308 os.chmod(dst, stat.S_IRWXO)
309 shutil.copymode(src, dst_link)
310 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
311 # follow both links
312 os.chmod(dst, stat.S_IRWXO)
313 shutil.copymode(src_link, dst_link)
314 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100315
316 @unittest.skipUnless(hasattr(os, 'lchmod'), 'requires os.lchmod')
317 @support.skip_unless_symlink
318 def test_copymode_symlink_to_symlink(self):
319 tmp_dir = self.mkdtemp()
320 src = os.path.join(tmp_dir, 'foo')
321 dst = os.path.join(tmp_dir, 'bar')
322 src_link = os.path.join(tmp_dir, 'baz')
323 dst_link = os.path.join(tmp_dir, 'quux')
324 write_file(src, 'foo')
325 write_file(dst, 'foo')
326 os.symlink(src, src_link)
327 os.symlink(dst, dst_link)
328 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
329 os.chmod(dst, stat.S_IRWXU)
330 os.lchmod(src_link, stat.S_IRWXO|stat.S_IRWXG)
331 # link to link
332 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700333 shutil.copymode(src_link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100334 self.assertEqual(os.lstat(src_link).st_mode,
335 os.lstat(dst_link).st_mode)
336 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
337 # src link - use chmod
338 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700339 shutil.copymode(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100340 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
341 # dst link - use chmod
342 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700343 shutil.copymode(src, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100344 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
345
346 @unittest.skipIf(hasattr(os, 'lchmod'), 'requires os.lchmod to be missing')
347 @support.skip_unless_symlink
348 def test_copymode_symlink_to_symlink_wo_lchmod(self):
349 tmp_dir = self.mkdtemp()
350 src = os.path.join(tmp_dir, 'foo')
351 dst = os.path.join(tmp_dir, 'bar')
352 src_link = os.path.join(tmp_dir, 'baz')
353 dst_link = os.path.join(tmp_dir, 'quux')
354 write_file(src, 'foo')
355 write_file(dst, 'foo')
356 os.symlink(src, src_link)
357 os.symlink(dst, dst_link)
Larry Hastingsb4038062012-07-15 10:57:38 -0700358 shutil.copymode(src_link, dst_link, follow_symlinks=False) # silent fail
Antoine Pitrou78091e62011-12-29 18:54:15 +0100359
360 @support.skip_unless_symlink
361 def test_copystat_symlinks(self):
362 tmp_dir = self.mkdtemp()
363 src = os.path.join(tmp_dir, 'foo')
364 dst = os.path.join(tmp_dir, 'bar')
365 src_link = os.path.join(tmp_dir, 'baz')
366 dst_link = os.path.join(tmp_dir, 'qux')
367 write_file(src, 'foo')
368 src_stat = os.stat(src)
369 os.utime(src, (src_stat.st_atime,
370 src_stat.st_mtime - 42.0)) # ensure different mtimes
371 write_file(dst, 'bar')
372 self.assertNotEqual(os.stat(src).st_mtime, os.stat(dst).st_mtime)
373 os.symlink(src, src_link)
374 os.symlink(dst, dst_link)
375 if hasattr(os, 'lchmod'):
376 os.lchmod(src_link, stat.S_IRWXO)
377 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
378 os.lchflags(src_link, stat.UF_NODUMP)
379 src_link_stat = os.lstat(src_link)
380 # follow
381 if hasattr(os, 'lchmod'):
Larry Hastingsb4038062012-07-15 10:57:38 -0700382 shutil.copystat(src_link, dst_link, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100383 self.assertNotEqual(src_link_stat.st_mode, os.stat(dst).st_mode)
384 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700385 shutil.copystat(src_link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100386 dst_link_stat = os.lstat(dst_link)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700387 if os.utime in os.supports_follow_symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100388 for attr in 'st_atime', 'st_mtime':
389 # The modification times may be truncated in the new file.
390 self.assertLessEqual(getattr(src_link_stat, attr),
391 getattr(dst_link_stat, attr) + 1)
392 if hasattr(os, 'lchmod'):
393 self.assertEqual(src_link_stat.st_mode, dst_link_stat.st_mode)
394 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
395 self.assertEqual(src_link_stat.st_flags, dst_link_stat.st_flags)
396 # tell to follow but dst is not a link
Larry Hastingsb4038062012-07-15 10:57:38 -0700397 shutil.copystat(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100398 self.assertTrue(abs(os.stat(src).st_mtime - os.stat(dst).st_mtime) <
399 00000.1)
400
Ned Deilybaf75712012-05-10 17:05:19 -0700401 @unittest.skipUnless(hasattr(os, 'chflags') and
402 hasattr(errno, 'EOPNOTSUPP') and
403 hasattr(errno, 'ENOTSUP'),
404 "requires os.chflags, EOPNOTSUPP & ENOTSUP")
405 def test_copystat_handles_harmless_chflags_errors(self):
406 tmpdir = self.mkdtemp()
407 file1 = os.path.join(tmpdir, 'file1')
408 file2 = os.path.join(tmpdir, 'file2')
409 write_file(file1, 'xxx')
410 write_file(file2, 'xxx')
411
412 def make_chflags_raiser(err):
413 ex = OSError()
414
Larry Hastings90867a52012-06-22 17:01:41 -0700415 def _chflags_raiser(path, flags, *, follow_symlinks=True):
Ned Deilybaf75712012-05-10 17:05:19 -0700416 ex.errno = err
417 raise ex
418 return _chflags_raiser
419 old_chflags = os.chflags
420 try:
421 for err in errno.EOPNOTSUPP, errno.ENOTSUP:
422 os.chflags = make_chflags_raiser(err)
423 shutil.copystat(file1, file2)
424 # assert others errors break it
425 os.chflags = make_chflags_raiser(errno.EOPNOTSUPP + errno.ENOTSUP)
426 self.assertRaises(OSError, shutil.copystat, file1, file2)
427 finally:
428 os.chflags = old_chflags
429
Antoine Pitrou424246f2012-05-12 19:02:01 +0200430 @support.skip_unless_xattr
431 def test_copyxattr(self):
432 tmp_dir = self.mkdtemp()
433 src = os.path.join(tmp_dir, 'foo')
434 write_file(src, 'foo')
435 dst = os.path.join(tmp_dir, 'bar')
436 write_file(dst, 'bar')
437
438 # no xattr == no problem
439 shutil._copyxattr(src, dst)
440 # common case
441 os.setxattr(src, 'user.foo', b'42')
442 os.setxattr(src, 'user.bar', b'43')
443 shutil._copyxattr(src, dst)
Gregory P. Smith1093bf22014-01-17 12:01:22 -0800444 self.assertEqual(sorted(os.listxattr(src)), sorted(os.listxattr(dst)))
Antoine Pitrou424246f2012-05-12 19:02:01 +0200445 self.assertEqual(
446 os.getxattr(src, 'user.foo'),
447 os.getxattr(dst, 'user.foo'))
448 # check errors don't affect other attrs
449 os.remove(dst)
450 write_file(dst, 'bar')
451 os_error = OSError(errno.EPERM, 'EPERM')
452
Larry Hastings9cf065c2012-06-22 16:30:09 -0700453 def _raise_on_user_foo(fname, attr, val, **kwargs):
Antoine Pitrou424246f2012-05-12 19:02:01 +0200454 if attr == 'user.foo':
455 raise os_error
456 else:
Larry Hastings9cf065c2012-06-22 16:30:09 -0700457 orig_setxattr(fname, attr, val, **kwargs)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200458 try:
459 orig_setxattr = os.setxattr
460 os.setxattr = _raise_on_user_foo
461 shutil._copyxattr(src, dst)
Antoine Pitrou61597d32012-05-12 23:37:35 +0200462 self.assertIn('user.bar', os.listxattr(dst))
Antoine Pitrou424246f2012-05-12 19:02:01 +0200463 finally:
464 os.setxattr = orig_setxattr
Hynek Schlawack0beab052013-02-05 08:22:44 +0100465 # the source filesystem not supporting xattrs should be ok, too.
466 def _raise_on_src(fname, *, follow_symlinks=True):
467 if fname == src:
468 raise OSError(errno.ENOTSUP, 'Operation not supported')
469 return orig_listxattr(fname, follow_symlinks=follow_symlinks)
470 try:
471 orig_listxattr = os.listxattr
472 os.listxattr = _raise_on_src
473 shutil._copyxattr(src, dst)
474 finally:
475 os.listxattr = orig_listxattr
Antoine Pitrou424246f2012-05-12 19:02:01 +0200476
Larry Hastingsad5ae042012-07-14 17:55:11 -0700477 # test that shutil.copystat copies xattrs
478 src = os.path.join(tmp_dir, 'the_original')
479 write_file(src, src)
480 os.setxattr(src, 'user.the_value', b'fiddly')
481 dst = os.path.join(tmp_dir, 'the_copy')
482 write_file(dst, dst)
483 shutil.copystat(src, dst)
Hynek Schlawackc2d481f2012-07-16 17:11:10 +0200484 self.assertEqual(os.getxattr(dst, 'user.the_value'), b'fiddly')
Larry Hastingsad5ae042012-07-14 17:55:11 -0700485
Antoine Pitrou424246f2012-05-12 19:02:01 +0200486 @support.skip_unless_symlink
487 @support.skip_unless_xattr
488 @unittest.skipUnless(hasattr(os, 'geteuid') and os.geteuid() == 0,
489 'root privileges required')
490 def test_copyxattr_symlinks(self):
491 # On Linux, it's only possible to access non-user xattr for symlinks;
492 # which in turn require root privileges. This test should be expanded
493 # as soon as other platforms gain support for extended attributes.
494 tmp_dir = self.mkdtemp()
495 src = os.path.join(tmp_dir, 'foo')
496 src_link = os.path.join(tmp_dir, 'baz')
497 write_file(src, 'foo')
498 os.symlink(src, src_link)
499 os.setxattr(src, 'trusted.foo', b'42')
Larry Hastings9cf065c2012-06-22 16:30:09 -0700500 os.setxattr(src_link, 'trusted.foo', b'43', follow_symlinks=False)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200501 dst = os.path.join(tmp_dir, 'bar')
502 dst_link = os.path.join(tmp_dir, 'qux')
503 write_file(dst, 'bar')
504 os.symlink(dst, dst_link)
Larry Hastingsb4038062012-07-15 10:57:38 -0700505 shutil._copyxattr(src_link, dst_link, follow_symlinks=False)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700506 self.assertEqual(os.getxattr(dst_link, 'trusted.foo', follow_symlinks=False), b'43')
Antoine Pitrou424246f2012-05-12 19:02:01 +0200507 self.assertRaises(OSError, os.getxattr, dst, 'trusted.foo')
Larry Hastingsb4038062012-07-15 10:57:38 -0700508 shutil._copyxattr(src_link, dst, follow_symlinks=False)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200509 self.assertEqual(os.getxattr(dst, 'trusted.foo'), b'43')
510
Antoine Pitrou78091e62011-12-29 18:54:15 +0100511 @support.skip_unless_symlink
512 def test_copy_symlinks(self):
513 tmp_dir = self.mkdtemp()
514 src = os.path.join(tmp_dir, 'foo')
515 dst = os.path.join(tmp_dir, 'bar')
516 src_link = os.path.join(tmp_dir, 'baz')
517 write_file(src, 'foo')
518 os.symlink(src, src_link)
519 if hasattr(os, 'lchmod'):
520 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
521 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700522 shutil.copy(src_link, dst, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100523 self.assertFalse(os.path.islink(dst))
524 self.assertEqual(read_file(src), read_file(dst))
525 os.remove(dst)
526 # follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700527 shutil.copy(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100528 self.assertTrue(os.path.islink(dst))
529 self.assertEqual(os.readlink(dst), os.readlink(src_link))
530 if hasattr(os, 'lchmod'):
531 self.assertEqual(os.lstat(src_link).st_mode,
532 os.lstat(dst).st_mode)
533
534 @support.skip_unless_symlink
535 def test_copy2_symlinks(self):
536 tmp_dir = self.mkdtemp()
537 src = os.path.join(tmp_dir, 'foo')
538 dst = os.path.join(tmp_dir, 'bar')
539 src_link = os.path.join(tmp_dir, 'baz')
540 write_file(src, 'foo')
541 os.symlink(src, src_link)
542 if hasattr(os, 'lchmod'):
543 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
544 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
545 os.lchflags(src_link, stat.UF_NODUMP)
546 src_stat = os.stat(src)
547 src_link_stat = os.lstat(src_link)
548 # follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700549 shutil.copy2(src_link, dst, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100550 self.assertFalse(os.path.islink(dst))
551 self.assertEqual(read_file(src), read_file(dst))
552 os.remove(dst)
553 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700554 shutil.copy2(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100555 self.assertTrue(os.path.islink(dst))
556 self.assertEqual(os.readlink(dst), os.readlink(src_link))
557 dst_stat = os.lstat(dst)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700558 if os.utime in os.supports_follow_symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100559 for attr in 'st_atime', 'st_mtime':
560 # The modification times may be truncated in the new file.
561 self.assertLessEqual(getattr(src_link_stat, attr),
562 getattr(dst_stat, attr) + 1)
563 if hasattr(os, 'lchmod'):
564 self.assertEqual(src_link_stat.st_mode, dst_stat.st_mode)
565 self.assertNotEqual(src_stat.st_mode, dst_stat.st_mode)
566 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
567 self.assertEqual(src_link_stat.st_flags, dst_stat.st_flags)
568
Antoine Pitrou424246f2012-05-12 19:02:01 +0200569 @support.skip_unless_xattr
570 def test_copy2_xattr(self):
571 tmp_dir = self.mkdtemp()
572 src = os.path.join(tmp_dir, 'foo')
573 dst = os.path.join(tmp_dir, 'bar')
574 write_file(src, 'foo')
575 os.setxattr(src, 'user.foo', b'42')
576 shutil.copy2(src, dst)
577 self.assertEqual(
578 os.getxattr(src, 'user.foo'),
579 os.getxattr(dst, 'user.foo'))
580 os.remove(dst)
581
Antoine Pitrou78091e62011-12-29 18:54:15 +0100582 @support.skip_unless_symlink
583 def test_copyfile_symlinks(self):
584 tmp_dir = self.mkdtemp()
585 src = os.path.join(tmp_dir, 'src')
586 dst = os.path.join(tmp_dir, 'dst')
587 dst_link = os.path.join(tmp_dir, 'dst_link')
588 link = os.path.join(tmp_dir, 'link')
589 write_file(src, 'foo')
590 os.symlink(src, link)
591 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700592 shutil.copyfile(link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100593 self.assertTrue(os.path.islink(dst_link))
594 self.assertEqual(os.readlink(link), os.readlink(dst_link))
595 # follow
596 shutil.copyfile(link, dst)
597 self.assertFalse(os.path.islink(dst))
598
Hynek Schlawack2100b422012-06-23 20:28:32 +0200599 def test_rmtree_uses_safe_fd_version_if_available(self):
Hynek Schlawackd0f6e0a2012-06-29 08:28:20 +0200600 _use_fd_functions = ({os.open, os.stat, os.unlink, os.rmdir} <=
601 os.supports_dir_fd and
602 os.listdir in os.supports_fd and
603 os.stat in os.supports_follow_symlinks)
604 if _use_fd_functions:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200605 self.assertTrue(shutil._use_fd_functions)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000606 self.assertTrue(shutil.rmtree.avoids_symlink_attacks)
Hynek Schlawack2100b422012-06-23 20:28:32 +0200607 tmp_dir = self.mkdtemp()
608 d = os.path.join(tmp_dir, 'a')
609 os.mkdir(d)
610 try:
611 real_rmtree = shutil._rmtree_safe_fd
612 class Called(Exception): pass
613 def _raiser(*args, **kwargs):
614 raise Called
615 shutil._rmtree_safe_fd = _raiser
616 self.assertRaises(Called, shutil.rmtree, d)
617 finally:
618 shutil._rmtree_safe_fd = real_rmtree
619 else:
620 self.assertFalse(shutil._use_fd_functions)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000621 self.assertFalse(shutil.rmtree.avoids_symlink_attacks)
Hynek Schlawack2100b422012-06-23 20:28:32 +0200622
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000623 def test_rmtree_dont_delete_file(self):
624 # When called on a file instead of a directory, don't delete it.
625 handle, path = tempfile.mkstemp()
Victor Stinnerbf816222011-06-30 23:25:47 +0200626 os.close(handle)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200627 self.assertRaises(NotADirectoryError, shutil.rmtree, path)
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000628 os.remove(path)
629
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000630 def test_copytree_simple(self):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000631 src_dir = tempfile.mkdtemp()
632 dst_dir = os.path.join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200633 self.addCleanup(shutil.rmtree, src_dir)
634 self.addCleanup(shutil.rmtree, os.path.dirname(dst_dir))
635 write_file((src_dir, 'test.txt'), '123')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000636 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200637 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000638
Éric Araujoa7e33a12011-08-12 19:51:35 +0200639 shutil.copytree(src_dir, dst_dir)
640 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test.txt')))
641 self.assertTrue(os.path.isdir(os.path.join(dst_dir, 'test_dir')))
642 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test_dir',
643 'test.txt')))
644 actual = read_file((dst_dir, 'test.txt'))
645 self.assertEqual(actual, '123')
646 actual = read_file((dst_dir, 'test_dir', 'test.txt'))
647 self.assertEqual(actual, '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000648
Antoine Pitrou78091e62011-12-29 18:54:15 +0100649 @support.skip_unless_symlink
650 def test_copytree_symlinks(self):
651 tmp_dir = self.mkdtemp()
652 src_dir = os.path.join(tmp_dir, 'src')
653 dst_dir = os.path.join(tmp_dir, 'dst')
654 sub_dir = os.path.join(src_dir, 'sub')
655 os.mkdir(src_dir)
656 os.mkdir(sub_dir)
657 write_file((src_dir, 'file.txt'), 'foo')
658 src_link = os.path.join(sub_dir, 'link')
659 dst_link = os.path.join(dst_dir, 'sub/link')
660 os.symlink(os.path.join(src_dir, 'file.txt'),
661 src_link)
662 if hasattr(os, 'lchmod'):
663 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
664 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
665 os.lchflags(src_link, stat.UF_NODUMP)
666 src_stat = os.lstat(src_link)
667 shutil.copytree(src_dir, dst_dir, symlinks=True)
668 self.assertTrue(os.path.islink(os.path.join(dst_dir, 'sub', 'link')))
669 self.assertEqual(os.readlink(os.path.join(dst_dir, 'sub', 'link')),
670 os.path.join(src_dir, 'file.txt'))
671 dst_stat = os.lstat(dst_link)
672 if hasattr(os, 'lchmod'):
673 self.assertEqual(dst_stat.st_mode, src_stat.st_mode)
674 if hasattr(os, 'lchflags'):
675 self.assertEqual(dst_stat.st_flags, src_stat.st_flags)
676
Georg Brandl2ee470f2008-07-16 12:55:28 +0000677 def test_copytree_with_exclude(self):
Georg Brandl2ee470f2008-07-16 12:55:28 +0000678 # creating data
679 join = os.path.join
680 exists = os.path.exists
681 src_dir = tempfile.mkdtemp()
Georg Brandl2ee470f2008-07-16 12:55:28 +0000682 try:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000683 dst_dir = join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200684 write_file((src_dir, 'test.txt'), '123')
685 write_file((src_dir, 'test.tmp'), '123')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000686 os.mkdir(join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200687 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000688 os.mkdir(join(src_dir, 'test_dir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200689 write_file((src_dir, 'test_dir2', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000690 os.mkdir(join(src_dir, 'test_dir2', 'subdir'))
691 os.mkdir(join(src_dir, 'test_dir2', 'subdir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200692 write_file((src_dir, 'test_dir2', 'subdir', 'test.txt'), '456')
693 write_file((src_dir, 'test_dir2', 'subdir2', 'test.py'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000694
695 # testing glob-like patterns
696 try:
697 patterns = shutil.ignore_patterns('*.tmp', 'test_dir2')
698 shutil.copytree(src_dir, dst_dir, ignore=patterns)
699 # checking the result: some elements should not be copied
700 self.assertTrue(exists(join(dst_dir, 'test.txt')))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200701 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
702 self.assertFalse(exists(join(dst_dir, 'test_dir2')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000703 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200704 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000705 try:
706 patterns = shutil.ignore_patterns('*.tmp', 'subdir*')
707 shutil.copytree(src_dir, dst_dir, ignore=patterns)
708 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200709 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
710 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2')))
711 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000712 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200713 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000714
715 # testing callable-style
716 try:
717 def _filter(src, names):
718 res = []
719 for name in names:
720 path = os.path.join(src, name)
721
722 if (os.path.isdir(path) and
723 path.split()[-1] == 'subdir'):
724 res.append(name)
725 elif os.path.splitext(path)[-1] in ('.py'):
726 res.append(name)
727 return res
728
729 shutil.copytree(src_dir, dst_dir, ignore=_filter)
730
731 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200732 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2',
733 'test.py')))
734 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000735
736 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200737 shutil.rmtree(dst_dir)
Georg Brandl2ee470f2008-07-16 12:55:28 +0000738 finally:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000739 shutil.rmtree(src_dir)
740 shutil.rmtree(os.path.dirname(dst_dir))
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000741
Antoine Pitrouac601602013-08-16 19:35:02 +0200742 def test_copytree_retains_permissions(self):
743 tmp_dir = tempfile.mkdtemp()
744 src_dir = os.path.join(tmp_dir, 'source')
745 os.mkdir(src_dir)
746 dst_dir = os.path.join(tmp_dir, 'destination')
747 self.addCleanup(shutil.rmtree, tmp_dir)
748
749 os.chmod(src_dir, 0o777)
750 write_file((src_dir, 'permissive.txt'), '123')
751 os.chmod(os.path.join(src_dir, 'permissive.txt'), 0o777)
752 write_file((src_dir, 'restrictive.txt'), '456')
753 os.chmod(os.path.join(src_dir, 'restrictive.txt'), 0o600)
754 restrictive_subdir = tempfile.mkdtemp(dir=src_dir)
755 os.chmod(restrictive_subdir, 0o600)
756
757 shutil.copytree(src_dir, dst_dir)
Brett Cannon9c7eb552013-08-23 14:38:11 -0400758 self.assertEqual(os.stat(src_dir).st_mode, os.stat(dst_dir).st_mode)
759 self.assertEqual(os.stat(os.path.join(src_dir, 'permissive.txt')).st_mode,
Antoine Pitrouac601602013-08-16 19:35:02 +0200760 os.stat(os.path.join(dst_dir, 'permissive.txt')).st_mode)
Brett Cannon9c7eb552013-08-23 14:38:11 -0400761 self.assertEqual(os.stat(os.path.join(src_dir, 'restrictive.txt')).st_mode,
Antoine Pitrouac601602013-08-16 19:35:02 +0200762 os.stat(os.path.join(dst_dir, 'restrictive.txt')).st_mode)
763 restrictive_subdir_dst = os.path.join(dst_dir,
764 os.path.split(restrictive_subdir)[1])
Brett Cannon9c7eb552013-08-23 14:38:11 -0400765 self.assertEqual(os.stat(restrictive_subdir).st_mode,
Antoine Pitrouac601602013-08-16 19:35:02 +0200766 os.stat(restrictive_subdir_dst).st_mode)
767
Berker Peksag884afd92014-12-10 02:50:32 +0200768 @unittest.mock.patch('os.chmod')
769 def test_copytree_winerror(self, mock_patch):
770 # When copying to VFAT, copystat() raises OSError. On Windows, the
771 # exception object has a meaningful 'winerror' attribute, but not
772 # on other operating systems. Do not assume 'winerror' is set.
773 src_dir = tempfile.mkdtemp()
774 dst_dir = os.path.join(tempfile.mkdtemp(), 'destination')
775 self.addCleanup(shutil.rmtree, src_dir)
776 self.addCleanup(shutil.rmtree, os.path.dirname(dst_dir))
777
778 mock_patch.side_effect = PermissionError('ka-boom')
779 with self.assertRaises(shutil.Error):
780 shutil.copytree(src_dir, dst_dir)
781
Zachary Ware9fe6d862013-12-08 00:20:35 -0600782 @unittest.skipIf(os.name == 'nt', 'temporarily disabled on Windows')
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000783 @unittest.skipUnless(hasattr(os, 'link'), 'requires os.link')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000784 def test_dont_copy_file_onto_link_to_itself(self):
785 # bug 851123.
786 os.mkdir(TESTFN)
787 src = os.path.join(TESTFN, 'cheese')
788 dst = os.path.join(TESTFN, 'shop')
789 try:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000790 with open(src, 'w') as f:
791 f.write('cheddar')
792 os.link(src, dst)
Hynek Schlawack48653762012-10-07 12:49:58 +0200793 self.assertRaises(shutil.SameFileError, shutil.copyfile, src, dst)
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000794 with open(src, 'r') as f:
795 self.assertEqual(f.read(), 'cheddar')
796 os.remove(dst)
797 finally:
798 shutil.rmtree(TESTFN, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000799
Brian Curtin3b4499c2010-12-28 14:31:47 +0000800 @support.skip_unless_symlink
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000801 def test_dont_copy_file_onto_symlink_to_itself(self):
802 # bug 851123.
803 os.mkdir(TESTFN)
804 src = os.path.join(TESTFN, 'cheese')
805 dst = os.path.join(TESTFN, 'shop')
806 try:
807 with open(src, 'w') as f:
808 f.write('cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000809 # Using `src` here would mean we end up with a symlink pointing
810 # to TESTFN/TESTFN/cheese, while it should point at
811 # TESTFN/cheese.
812 os.symlink('cheese', dst)
Hynek Schlawack48653762012-10-07 12:49:58 +0200813 self.assertRaises(shutil.SameFileError, shutil.copyfile, src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +0000814 with open(src, 'r') as f:
815 self.assertEqual(f.read(), 'cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000816 os.remove(dst)
817 finally:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000818 shutil.rmtree(TESTFN, ignore_errors=True)
Johannes Gijsbers68128712004-08-14 13:57:08 +0000819
Brian Curtin3b4499c2010-12-28 14:31:47 +0000820 @support.skip_unless_symlink
Brian Curtind40e6f72010-07-08 21:39:08 +0000821 def test_rmtree_on_symlink(self):
822 # bug 1669.
823 os.mkdir(TESTFN)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000824 try:
Brian Curtind40e6f72010-07-08 21:39:08 +0000825 src = os.path.join(TESTFN, 'cheese')
826 dst = os.path.join(TESTFN, 'shop')
827 os.mkdir(src)
828 os.symlink(src, dst)
829 self.assertRaises(OSError, shutil.rmtree, dst)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200830 shutil.rmtree(dst, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000831 finally:
Brian Curtind40e6f72010-07-08 21:39:08 +0000832 shutil.rmtree(TESTFN, ignore_errors=True)
833
Serhiy Storchaka43767632013-11-03 21:31:38 +0200834 # Issue #3002: copyfile and copytree block indefinitely on named pipes
835 @unittest.skipUnless(hasattr(os, "mkfifo"), 'requires os.mkfifo()')
836 def test_copyfile_named_pipe(self):
837 os.mkfifo(TESTFN)
838 try:
839 self.assertRaises(shutil.SpecialFileError,
840 shutil.copyfile, TESTFN, TESTFN2)
841 self.assertRaises(shutil.SpecialFileError,
842 shutil.copyfile, __file__, TESTFN)
843 finally:
844 os.remove(TESTFN)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000845
Serhiy Storchaka43767632013-11-03 21:31:38 +0200846 @unittest.skipUnless(hasattr(os, "mkfifo"), 'requires os.mkfifo()')
847 @support.skip_unless_symlink
848 def test_copytree_named_pipe(self):
849 os.mkdir(TESTFN)
850 try:
851 subdir = os.path.join(TESTFN, "subdir")
852 os.mkdir(subdir)
853 pipe = os.path.join(subdir, "mypipe")
854 os.mkfifo(pipe)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000855 try:
Serhiy Storchaka43767632013-11-03 21:31:38 +0200856 shutil.copytree(TESTFN, TESTFN2)
857 except shutil.Error as e:
858 errors = e.args[0]
859 self.assertEqual(len(errors), 1)
860 src, dst, error_msg = errors[0]
861 self.assertEqual("`%s` is a named pipe" % pipe, error_msg)
862 else:
863 self.fail("shutil.Error should have been raised")
864 finally:
865 shutil.rmtree(TESTFN, ignore_errors=True)
866 shutil.rmtree(TESTFN2, ignore_errors=True)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000867
Tarek Ziadé5340db32010-04-19 22:30:51 +0000868 def test_copytree_special_func(self):
869
870 src_dir = self.mkdtemp()
871 dst_dir = os.path.join(self.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200872 write_file((src_dir, 'test.txt'), '123')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000873 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200874 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000875
876 copied = []
877 def _copy(src, dst):
878 copied.append((src, dst))
879
880 shutil.copytree(src_dir, dst_dir, copy_function=_copy)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000881 self.assertEqual(len(copied), 2)
Tarek Ziadé5340db32010-04-19 22:30:51 +0000882
Brian Curtin3b4499c2010-12-28 14:31:47 +0000883 @support.skip_unless_symlink
Tarek Ziadéfb437512010-04-20 08:57:33 +0000884 def test_copytree_dangling_symlinks(self):
885
886 # a dangling symlink raises an error at the end
887 src_dir = self.mkdtemp()
888 dst_dir = os.path.join(self.mkdtemp(), 'destination')
889 os.symlink('IDONTEXIST', os.path.join(src_dir, 'test.txt'))
890 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200891 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadéfb437512010-04-20 08:57:33 +0000892 self.assertRaises(Error, shutil.copytree, src_dir, dst_dir)
893
894 # a dangling symlink is ignored with the proper flag
895 dst_dir = os.path.join(self.mkdtemp(), 'destination2')
896 shutil.copytree(src_dir, dst_dir, ignore_dangling_symlinks=True)
897 self.assertNotIn('test.txt', os.listdir(dst_dir))
898
899 # a dangling symlink is copied if symlinks=True
900 dst_dir = os.path.join(self.mkdtemp(), 'destination3')
901 shutil.copytree(src_dir, dst_dir, symlinks=True)
902 self.assertIn('test.txt', os.listdir(dst_dir))
903
Berker Peksag5a294d82015-07-25 14:53:48 +0300904 @support.skip_unless_symlink
905 def test_copytree_symlink_dir(self):
906 src_dir = self.mkdtemp()
907 dst_dir = os.path.join(self.mkdtemp(), 'destination')
908 os.mkdir(os.path.join(src_dir, 'real_dir'))
909 with open(os.path.join(src_dir, 'real_dir', 'test.txt'), 'w'):
910 pass
911 os.symlink(os.path.join(src_dir, 'real_dir'),
912 os.path.join(src_dir, 'link_to_dir'),
913 target_is_directory=True)
914
915 shutil.copytree(src_dir, dst_dir, symlinks=False)
916 self.assertFalse(os.path.islink(os.path.join(dst_dir, 'link_to_dir')))
917 self.assertIn('test.txt', os.listdir(os.path.join(dst_dir, 'link_to_dir')))
918
919 dst_dir = os.path.join(self.mkdtemp(), 'destination2')
920 shutil.copytree(src_dir, dst_dir, symlinks=True)
921 self.assertTrue(os.path.islink(os.path.join(dst_dir, 'link_to_dir')))
922 self.assertIn('test.txt', os.listdir(os.path.join(dst_dir, 'link_to_dir')))
923
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400924 def _copy_file(self, method):
925 fname = 'test.txt'
926 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200927 write_file((tmpdir, fname), 'xxx')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400928 file1 = os.path.join(tmpdir, fname)
929 tmpdir2 = self.mkdtemp()
930 method(file1, tmpdir2)
931 file2 = os.path.join(tmpdir2, fname)
932 return (file1, file2)
933
934 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
935 def test_copy(self):
936 # Ensure that the copied file exists and has the same mode bits.
937 file1, file2 = self._copy_file(shutil.copy)
938 self.assertTrue(os.path.exists(file2))
939 self.assertEqual(os.stat(file1).st_mode, os.stat(file2).st_mode)
940
941 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
Senthil Kumaran0c2dba52011-07-03 18:21:38 -0700942 @unittest.skipUnless(hasattr(os, 'utime'), 'requires os.utime')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400943 def test_copy2(self):
944 # Ensure that the copied file exists and has the same mode and
945 # modification time bits.
946 file1, file2 = self._copy_file(shutil.copy2)
947 self.assertTrue(os.path.exists(file2))
948 file1_stat = os.stat(file1)
949 file2_stat = os.stat(file2)
950 self.assertEqual(file1_stat.st_mode, file2_stat.st_mode)
951 for attr in 'st_atime', 'st_mtime':
952 # The modification times may be truncated in the new file.
953 self.assertLessEqual(getattr(file1_stat, attr),
954 getattr(file2_stat, attr) + 1)
955 if hasattr(os, 'chflags') and hasattr(file1_stat, 'st_flags'):
956 self.assertEqual(getattr(file1_stat, 'st_flags'),
957 getattr(file2_stat, 'st_flags'))
958
Ezio Melotti975077a2011-05-19 22:03:22 +0300959 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000960 def test_make_tarball(self):
961 # creating something to tar
962 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200963 write_file((tmpdir, 'file1'), 'xxx')
964 write_file((tmpdir, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000965 os.mkdir(os.path.join(tmpdir, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200966 write_file((tmpdir, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000967
968 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400969 # force shutil to create the directory
970 os.rmdir(tmpdir2)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000971 unittest.skipUnless(splitdrive(tmpdir)[0] == splitdrive(tmpdir2)[0],
972 "source and target should be on same drive")
973
974 base_name = os.path.join(tmpdir2, 'archive')
975
976 # working with relative paths to avoid tar warnings
977 old_dir = os.getcwd()
978 os.chdir(tmpdir)
979 try:
980 _make_tarball(splitdrive(base_name)[1], '.')
981 finally:
982 os.chdir(old_dir)
983
984 # check if the compressed tarball was created
985 tarball = base_name + '.tar.gz'
986 self.assertTrue(os.path.exists(tarball))
987
988 # trying an uncompressed one
989 base_name = os.path.join(tmpdir2, 'archive')
990 old_dir = os.getcwd()
991 os.chdir(tmpdir)
992 try:
993 _make_tarball(splitdrive(base_name)[1], '.', compress=None)
994 finally:
995 os.chdir(old_dir)
996 tarball = base_name + '.tar'
997 self.assertTrue(os.path.exists(tarball))
998
999 def _tarinfo(self, path):
1000 tar = tarfile.open(path)
1001 try:
1002 names = tar.getnames()
1003 names.sort()
1004 return tuple(names)
1005 finally:
1006 tar.close()
1007
1008 def _create_files(self):
1009 # creating something to tar
1010 tmpdir = self.mkdtemp()
1011 dist = os.path.join(tmpdir, 'dist')
1012 os.mkdir(dist)
Éric Araujoa7e33a12011-08-12 19:51:35 +02001013 write_file((dist, 'file1'), 'xxx')
1014 write_file((dist, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +00001015 os.mkdir(os.path.join(dist, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +02001016 write_file((dist, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +00001017 os.mkdir(os.path.join(dist, 'sub2'))
1018 tmpdir2 = self.mkdtemp()
1019 base_name = os.path.join(tmpdir2, 'archive')
1020 return tmpdir, tmpdir2, base_name
1021
Ezio Melotti975077a2011-05-19 22:03:22 +03001022 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001023 @unittest.skipUnless(find_executable('tar') and find_executable('gzip'),
1024 'Need the tar command to run')
1025 def test_tarfile_vs_tar(self):
1026 tmpdir, tmpdir2, base_name = self._create_files()
1027 old_dir = os.getcwd()
1028 os.chdir(tmpdir)
1029 try:
1030 _make_tarball(base_name, 'dist')
1031 finally:
1032 os.chdir(old_dir)
1033
1034 # check if the compressed tarball was created
1035 tarball = base_name + '.tar.gz'
1036 self.assertTrue(os.path.exists(tarball))
1037
1038 # now create another tarball using `tar`
1039 tarball2 = os.path.join(tmpdir, 'archive2.tar.gz')
1040 tar_cmd = ['tar', '-cf', 'archive2.tar', 'dist']
1041 gzip_cmd = ['gzip', '-f9', 'archive2.tar']
1042 old_dir = os.getcwd()
1043 os.chdir(tmpdir)
1044 try:
1045 with captured_stdout() as s:
1046 spawn(tar_cmd)
1047 spawn(gzip_cmd)
1048 finally:
1049 os.chdir(old_dir)
1050
1051 self.assertTrue(os.path.exists(tarball2))
1052 # let's compare both tarballs
Ezio Melottib3aedd42010-11-20 19:04:17 +00001053 self.assertEqual(self._tarinfo(tarball), self._tarinfo(tarball2))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001054
1055 # trying an uncompressed one
1056 base_name = os.path.join(tmpdir2, 'archive')
1057 old_dir = os.getcwd()
1058 os.chdir(tmpdir)
1059 try:
1060 _make_tarball(base_name, 'dist', compress=None)
1061 finally:
1062 os.chdir(old_dir)
1063 tarball = base_name + '.tar'
1064 self.assertTrue(os.path.exists(tarball))
1065
1066 # now for a dry_run
1067 base_name = os.path.join(tmpdir2, 'archive')
1068 old_dir = os.getcwd()
1069 os.chdir(tmpdir)
1070 try:
1071 _make_tarball(base_name, 'dist', compress=None, dry_run=True)
1072 finally:
1073 os.chdir(old_dir)
1074 tarball = base_name + '.tar'
1075 self.assertTrue(os.path.exists(tarball))
1076
Ezio Melotti975077a2011-05-19 22:03:22 +03001077 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001078 @unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run')
1079 def test_make_zipfile(self):
1080 # creating something to tar
1081 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +02001082 write_file((tmpdir, 'file1'), 'xxx')
1083 write_file((tmpdir, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +00001084
1085 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001086 # force shutil to create the directory
1087 os.rmdir(tmpdir2)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001088 base_name = os.path.join(tmpdir2, 'archive')
1089 _make_zipfile(base_name, tmpdir)
1090
1091 # check if the compressed tarball was created
1092 tarball = base_name + '.zip'
Éric Araujo1c505492010-11-06 02:12:51 +00001093 self.assertTrue(os.path.exists(tarball))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001094
1095
1096 def test_make_archive(self):
1097 tmpdir = self.mkdtemp()
1098 base_name = os.path.join(tmpdir, 'archive')
1099 self.assertRaises(ValueError, make_archive, base_name, 'xxx')
1100
Ezio Melotti975077a2011-05-19 22:03:22 +03001101 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001102 def test_make_archive_owner_group(self):
1103 # testing make_archive with owner and group, with various combinations
1104 # this works even if there's not gid/uid support
1105 if UID_GID_SUPPORT:
1106 group = grp.getgrgid(0)[0]
1107 owner = pwd.getpwuid(0)[0]
1108 else:
1109 group = owner = 'root'
1110
1111 base_dir, root_dir, base_name = self._create_files()
1112 base_name = os.path.join(self.mkdtemp() , 'archive')
1113 res = make_archive(base_name, 'zip', root_dir, base_dir, owner=owner,
1114 group=group)
1115 self.assertTrue(os.path.exists(res))
1116
1117 res = make_archive(base_name, 'zip', root_dir, base_dir)
1118 self.assertTrue(os.path.exists(res))
1119
1120 res = make_archive(base_name, 'tar', root_dir, base_dir,
1121 owner=owner, group=group)
1122 self.assertTrue(os.path.exists(res))
1123
1124 res = make_archive(base_name, 'tar', root_dir, base_dir,
1125 owner='kjhkjhkjg', group='oihohoh')
1126 self.assertTrue(os.path.exists(res))
1127
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001128
Ezio Melotti975077a2011-05-19 22:03:22 +03001129 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001130 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1131 def test_tarfile_root_owner(self):
1132 tmpdir, tmpdir2, base_name = self._create_files()
1133 old_dir = os.getcwd()
1134 os.chdir(tmpdir)
1135 group = grp.getgrgid(0)[0]
1136 owner = pwd.getpwuid(0)[0]
1137 try:
1138 archive_name = _make_tarball(base_name, 'dist', compress=None,
1139 owner=owner, group=group)
1140 finally:
1141 os.chdir(old_dir)
1142
1143 # check if the compressed tarball was created
1144 self.assertTrue(os.path.exists(archive_name))
1145
1146 # now checks the rights
1147 archive = tarfile.open(archive_name)
1148 try:
1149 for member in archive.getmembers():
Ezio Melottib3aedd42010-11-20 19:04:17 +00001150 self.assertEqual(member.uid, 0)
1151 self.assertEqual(member.gid, 0)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001152 finally:
1153 archive.close()
1154
1155 def test_make_archive_cwd(self):
1156 current_dir = os.getcwd()
1157 def _breaks(*args, **kw):
1158 raise RuntimeError()
1159
1160 register_archive_format('xxx', _breaks, [], 'xxx file')
1161 try:
1162 try:
1163 make_archive('xxx', 'xxx', root_dir=self.mkdtemp())
1164 except Exception:
1165 pass
Ezio Melottib3aedd42010-11-20 19:04:17 +00001166 self.assertEqual(os.getcwd(), current_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001167 finally:
1168 unregister_archive_format('xxx')
1169
Serhiy Storchaka9a4fc192014-11-28 00:48:46 +02001170 def test_make_tarfile_in_curdir(self):
1171 # Issue #21280
1172 root_dir = self.mkdtemp()
1173 with support.change_cwd(root_dir):
1174 self.assertEqual(make_archive('test', 'tar'), 'test.tar')
1175 self.assertTrue(os.path.isfile('test.tar'))
1176
1177 @requires_zlib
1178 def test_make_zipfile_in_curdir(self):
1179 # Issue #21280
1180 root_dir = self.mkdtemp()
1181 with support.change_cwd(root_dir):
1182 self.assertEqual(make_archive('test', 'zip'), 'test.zip')
1183 self.assertTrue(os.path.isfile('test.zip'))
1184
Tarek Ziadé396fad72010-02-23 05:30:31 +00001185 def test_register_archive_format(self):
1186
1187 self.assertRaises(TypeError, register_archive_format, 'xxx', 1)
1188 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1189 1)
1190 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1191 [(1, 2), (1, 2, 3)])
1192
1193 register_archive_format('xxx', lambda: x, [(1, 2)], 'xxx file')
1194 formats = [name for name, params in get_archive_formats()]
1195 self.assertIn('xxx', formats)
1196
1197 unregister_archive_format('xxx')
1198 formats = [name for name, params in get_archive_formats()]
1199 self.assertNotIn('xxx', formats)
1200
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001201 def _compare_dirs(self, dir1, dir2):
1202 # check that dir1 and dir2 are equivalent,
1203 # return the diff
1204 diff = []
1205 for root, dirs, files in os.walk(dir1):
1206 for file_ in files:
1207 path = os.path.join(root, file_)
1208 target_path = os.path.join(dir2, os.path.split(path)[-1])
1209 if not os.path.exists(target_path):
1210 diff.append(file_)
1211 return diff
1212
Ezio Melotti975077a2011-05-19 22:03:22 +03001213 @requires_zlib
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001214 def test_unpack_archive(self):
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001215 formats = ['tar', 'gztar', 'zip']
1216 if BZ2_SUPPORTED:
1217 formats.append('bztar')
Serhiy Storchaka11213772014-08-06 18:50:19 +03001218 if LZMA_SUPPORTED:
1219 formats.append('xztar')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001220
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001221 for format in formats:
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001222 tmpdir = self.mkdtemp()
1223 base_dir, root_dir, base_name = self._create_files()
1224 tmpdir2 = self.mkdtemp()
1225 filename = make_archive(base_name, format, root_dir, base_dir)
1226
1227 # let's try to unpack it now
1228 unpack_archive(filename, tmpdir2)
1229 diff = self._compare_dirs(tmpdir, tmpdir2)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001230 self.assertEqual(diff, [])
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001231
Nick Coghlanabf202d2011-03-16 13:52:20 -04001232 # and again, this time with the format specified
1233 tmpdir3 = self.mkdtemp()
1234 unpack_archive(filename, tmpdir3, format=format)
1235 diff = self._compare_dirs(tmpdir, tmpdir3)
1236 self.assertEqual(diff, [])
1237 self.assertRaises(shutil.ReadError, unpack_archive, TESTFN)
1238 self.assertRaises(ValueError, unpack_archive, TESTFN, format='xxx')
1239
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001240 def test_unpack_registery(self):
1241
1242 formats = get_unpack_formats()
1243
1244 def _boo(filename, extract_dir, extra):
Ezio Melottib3aedd42010-11-20 19:04:17 +00001245 self.assertEqual(extra, 1)
1246 self.assertEqual(filename, 'stuff.boo')
1247 self.assertEqual(extract_dir, 'xx')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001248
1249 register_unpack_format('Boo', ['.boo', '.b2'], _boo, [('extra', 1)])
1250 unpack_archive('stuff.boo', 'xx')
1251
1252 # trying to register a .boo unpacker again
1253 self.assertRaises(RegistryError, register_unpack_format, 'Boo2',
1254 ['.boo'], _boo)
1255
1256 # should work now
1257 unregister_unpack_format('Boo')
1258 register_unpack_format('Boo2', ['.boo'], _boo)
1259 self.assertIn(('Boo2', ['.boo'], ''), get_unpack_formats())
1260 self.assertNotIn(('Boo', ['.boo'], ''), get_unpack_formats())
1261
1262 # let's leave a clean state
1263 unregister_unpack_format('Boo2')
Ezio Melottib3aedd42010-11-20 19:04:17 +00001264 self.assertEqual(get_unpack_formats(), formats)
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001265
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001266 @unittest.skipUnless(hasattr(shutil, 'disk_usage'),
1267 "disk_usage not available on this platform")
1268 def test_disk_usage(self):
1269 usage = shutil.disk_usage(os.getcwd())
Éric Araujo2ee61882011-07-02 16:45:45 +02001270 self.assertGreater(usage.total, 0)
1271 self.assertGreater(usage.used, 0)
1272 self.assertGreaterEqual(usage.free, 0)
1273 self.assertGreaterEqual(usage.total, usage.used)
1274 self.assertGreater(usage.total, usage.free)
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001275
Sandro Tosid902a142011-08-22 23:28:27 +02001276 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1277 @unittest.skipUnless(hasattr(os, 'chown'), 'requires os.chown')
1278 def test_chown(self):
1279
1280 # cleaned-up automatically by TestShutil.tearDown method
1281 dirname = self.mkdtemp()
1282 filename = tempfile.mktemp(dir=dirname)
1283 write_file(filename, 'testing chown function')
1284
1285 with self.assertRaises(ValueError):
1286 shutil.chown(filename)
1287
1288 with self.assertRaises(LookupError):
1289 shutil.chown(filename, user='non-exising username')
1290
1291 with self.assertRaises(LookupError):
1292 shutil.chown(filename, group='non-exising groupname')
1293
1294 with self.assertRaises(TypeError):
1295 shutil.chown(filename, b'spam')
1296
1297 with self.assertRaises(TypeError):
1298 shutil.chown(filename, 3.14)
1299
1300 uid = os.getuid()
1301 gid = os.getgid()
1302
1303 def check_chown(path, uid=None, gid=None):
1304 s = os.stat(filename)
1305 if uid is not None:
1306 self.assertEqual(uid, s.st_uid)
1307 if gid is not None:
1308 self.assertEqual(gid, s.st_gid)
1309
1310 shutil.chown(filename, uid, gid)
1311 check_chown(filename, uid, gid)
1312 shutil.chown(filename, uid)
1313 check_chown(filename, uid)
1314 shutil.chown(filename, user=uid)
1315 check_chown(filename, uid)
1316 shutil.chown(filename, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001317 check_chown(filename, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001318
1319 shutil.chown(dirname, uid, gid)
1320 check_chown(dirname, uid, gid)
1321 shutil.chown(dirname, uid)
1322 check_chown(dirname, uid)
1323 shutil.chown(dirname, user=uid)
1324 check_chown(dirname, uid)
1325 shutil.chown(dirname, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001326 check_chown(dirname, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001327
1328 user = pwd.getpwuid(uid)[0]
1329 group = grp.getgrgid(gid)[0]
1330 shutil.chown(filename, user, group)
1331 check_chown(filename, uid, gid)
1332 shutil.chown(dirname, user, group)
1333 check_chown(dirname, uid, gid)
1334
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001335 def test_copy_return_value(self):
1336 # copy and copy2 both return their destination path.
1337 for fn in (shutil.copy, shutil.copy2):
1338 src_dir = self.mkdtemp()
1339 dst_dir = self.mkdtemp()
1340 src = os.path.join(src_dir, 'foo')
1341 write_file(src, 'foo')
1342 rv = fn(src, dst_dir)
1343 self.assertEqual(rv, os.path.join(dst_dir, 'foo'))
1344 rv = fn(src, os.path.join(dst_dir, 'bar'))
1345 self.assertEqual(rv, os.path.join(dst_dir, 'bar'))
1346
1347 def test_copyfile_return_value(self):
1348 # copytree returns its destination path.
1349 src_dir = self.mkdtemp()
1350 dst_dir = self.mkdtemp()
1351 dst_file = os.path.join(dst_dir, 'bar')
1352 src_file = os.path.join(src_dir, 'foo')
1353 write_file(src_file, 'foo')
1354 rv = shutil.copyfile(src_file, dst_file)
1355 self.assertTrue(os.path.exists(rv))
1356 self.assertEqual(read_file(src_file), read_file(dst_file))
1357
Hynek Schlawack48653762012-10-07 12:49:58 +02001358 def test_copyfile_same_file(self):
1359 # copyfile() should raise SameFileError if the source and destination
1360 # are the same.
1361 src_dir = self.mkdtemp()
1362 src_file = os.path.join(src_dir, 'foo')
1363 write_file(src_file, 'foo')
1364 self.assertRaises(SameFileError, shutil.copyfile, src_file, src_file)
Hynek Schlawack27ddb572012-10-28 13:59:27 +01001365 # But Error should work too, to stay backward compatible.
1366 self.assertRaises(Error, shutil.copyfile, src_file, src_file)
Hynek Schlawack48653762012-10-07 12:49:58 +02001367
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001368 def test_copytree_return_value(self):
1369 # copytree returns its destination path.
1370 src_dir = self.mkdtemp()
1371 dst_dir = src_dir + "dest"
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001372 self.addCleanup(shutil.rmtree, dst_dir, True)
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001373 src = os.path.join(src_dir, 'foo')
1374 write_file(src, 'foo')
1375 rv = shutil.copytree(src_dir, dst_dir)
1376 self.assertEqual(['foo'], os.listdir(rv))
1377
Christian Heimes9bd667a2008-01-20 15:14:11 +00001378
Brian Curtinc57a3452012-06-22 16:00:30 -05001379class TestWhich(unittest.TestCase):
1380
1381 def setUp(self):
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001382 self.temp_dir = tempfile.mkdtemp(prefix="Tmp")
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001383 self.addCleanup(shutil.rmtree, self.temp_dir, True)
Brian Curtinc57a3452012-06-22 16:00:30 -05001384 # Give the temp_file an ".exe" suffix for all.
1385 # It's needed on Windows and not harmful on other platforms.
1386 self.temp_file = tempfile.NamedTemporaryFile(dir=self.temp_dir,
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001387 prefix="Tmp",
1388 suffix=".Exe")
Brian Curtinc57a3452012-06-22 16:00:30 -05001389 os.chmod(self.temp_file.name, stat.S_IXUSR)
1390 self.addCleanup(self.temp_file.close)
1391 self.dir, self.file = os.path.split(self.temp_file.name)
1392
1393 def test_basic(self):
1394 # Given an EXE in a directory, it should be returned.
1395 rv = shutil.which(self.file, path=self.dir)
1396 self.assertEqual(rv, self.temp_file.name)
1397
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001398 def test_absolute_cmd(self):
Brian Curtinc57a3452012-06-22 16:00:30 -05001399 # When given the fully qualified path to an executable that exists,
1400 # it should be returned.
1401 rv = shutil.which(self.temp_file.name, path=self.temp_dir)
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001402 self.assertEqual(rv, self.temp_file.name)
1403
1404 def test_relative_cmd(self):
1405 # When given the relative path with a directory part to an executable
1406 # that exists, it should be returned.
1407 base_dir, tail_dir = os.path.split(self.dir)
1408 relpath = os.path.join(tail_dir, self.file)
Nick Coghlan55175962013-07-28 22:11:50 +10001409 with support.change_cwd(path=base_dir):
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001410 rv = shutil.which(relpath, path=self.temp_dir)
1411 self.assertEqual(rv, relpath)
1412 # But it shouldn't be searched in PATH directories (issue #16957).
Nick Coghlan55175962013-07-28 22:11:50 +10001413 with support.change_cwd(path=self.dir):
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001414 rv = shutil.which(relpath, path=base_dir)
1415 self.assertIsNone(rv)
1416
1417 def test_cwd(self):
1418 # Issue #16957
1419 base_dir = os.path.dirname(self.dir)
Nick Coghlan55175962013-07-28 22:11:50 +10001420 with support.change_cwd(path=self.dir):
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001421 rv = shutil.which(self.file, path=base_dir)
1422 if sys.platform == "win32":
1423 # Windows: current directory implicitly on PATH
1424 self.assertEqual(rv, os.path.join(os.curdir, self.file))
1425 else:
1426 # Other platforms: shouldn't match in the current directory.
1427 self.assertIsNone(rv)
Brian Curtinc57a3452012-06-22 16:00:30 -05001428
Serhiy Storchaka12516e22013-05-28 15:50:15 +03001429 @unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0,
1430 'non-root user required')
Brian Curtinc57a3452012-06-22 16:00:30 -05001431 def test_non_matching_mode(self):
1432 # Set the file read-only and ask for writeable files.
1433 os.chmod(self.temp_file.name, stat.S_IREAD)
Serhiy Storchaka12516e22013-05-28 15:50:15 +03001434 if os.access(self.temp_file.name, os.W_OK):
1435 self.skipTest("can't set the file read-only")
Brian Curtinc57a3452012-06-22 16:00:30 -05001436 rv = shutil.which(self.file, path=self.dir, mode=os.W_OK)
1437 self.assertIsNone(rv)
1438
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001439 def test_relative_path(self):
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001440 base_dir, tail_dir = os.path.split(self.dir)
Nick Coghlan55175962013-07-28 22:11:50 +10001441 with support.change_cwd(path=base_dir):
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001442 rv = shutil.which(self.file, path=tail_dir)
1443 self.assertEqual(rv, os.path.join(tail_dir, self.file))
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001444
Brian Curtinc57a3452012-06-22 16:00:30 -05001445 def test_nonexistent_file(self):
1446 # Return None when no matching executable file is found on the path.
1447 rv = shutil.which("foo.exe", path=self.dir)
1448 self.assertIsNone(rv)
1449
1450 @unittest.skipUnless(sys.platform == "win32",
1451 "pathext check is Windows-only")
1452 def test_pathext_checking(self):
1453 # Ask for the file without the ".exe" extension, then ensure that
1454 # it gets found properly with the extension.
Serhiy Storchakad70127a2013-01-24 20:03:49 +02001455 rv = shutil.which(self.file[:-4], path=self.dir)
Serhiy Storchaka80c88f42013-01-22 10:31:36 +02001456 self.assertEqual(rv, self.temp_file.name[:-4] + ".EXE")
Brian Curtinc57a3452012-06-22 16:00:30 -05001457
Barry Warsaw618738b2013-04-16 11:05:03 -04001458 def test_environ_path(self):
1459 with 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)
1462 self.assertEqual(rv, self.temp_file.name)
1463
1464 def test_empty_path(self):
1465 base_dir = os.path.dirname(self.dir)
Nick Coghlan55175962013-07-28 22:11:50 +10001466 with support.change_cwd(path=self.dir), \
Barry Warsaw618738b2013-04-16 11:05:03 -04001467 support.EnvironmentVarGuard() as env:
Victor Stinner1d006a22013-12-16 23:39:40 +01001468 env['PATH'] = self.dir
Barry Warsaw618738b2013-04-16 11:05:03 -04001469 rv = shutil.which(self.file, path='')
1470 self.assertIsNone(rv)
1471
1472 def test_empty_path_no_PATH(self):
1473 with support.EnvironmentVarGuard() as env:
1474 env.pop('PATH', None)
1475 rv = shutil.which(self.file)
1476 self.assertIsNone(rv)
1477
Brian Curtinc57a3452012-06-22 16:00:30 -05001478
Christian Heimesada8c3b2008-03-18 18:26:33 +00001479class TestMove(unittest.TestCase):
1480
1481 def setUp(self):
1482 filename = "foo"
1483 self.src_dir = tempfile.mkdtemp()
1484 self.dst_dir = tempfile.mkdtemp()
1485 self.src_file = os.path.join(self.src_dir, filename)
1486 self.dst_file = os.path.join(self.dst_dir, filename)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001487 with open(self.src_file, "wb") as f:
1488 f.write(b"spam")
1489
1490 def tearDown(self):
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001491 for d in (self.src_dir, self.dst_dir):
Christian Heimesada8c3b2008-03-18 18:26:33 +00001492 try:
1493 if d:
1494 shutil.rmtree(d)
1495 except:
1496 pass
1497
1498 def _check_move_file(self, src, dst, real_dst):
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001499 with open(src, "rb") as f:
1500 contents = f.read()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001501 shutil.move(src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001502 with open(real_dst, "rb") as f:
1503 self.assertEqual(contents, f.read())
Christian Heimesada8c3b2008-03-18 18:26:33 +00001504 self.assertFalse(os.path.exists(src))
1505
1506 def _check_move_dir(self, src, dst, real_dst):
1507 contents = sorted(os.listdir(src))
1508 shutil.move(src, dst)
1509 self.assertEqual(contents, sorted(os.listdir(real_dst)))
1510 self.assertFalse(os.path.exists(src))
1511
1512 def test_move_file(self):
1513 # Move a file to another location on the same filesystem.
1514 self._check_move_file(self.src_file, self.dst_file, self.dst_file)
1515
1516 def test_move_file_to_dir(self):
1517 # Move a file inside an existing dir on the same filesystem.
1518 self._check_move_file(self.src_file, self.dst_dir, self.dst_file)
1519
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001520 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001521 def test_move_file_other_fs(self):
1522 # Move a file to an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001523 self.test_move_file()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001524
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001525 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001526 def test_move_file_to_dir_other_fs(self):
1527 # Move a file to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001528 self.test_move_file_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001529
1530 def test_move_dir(self):
1531 # Move a dir to another location on the same filesystem.
1532 dst_dir = tempfile.mktemp()
1533 try:
1534 self._check_move_dir(self.src_dir, dst_dir, dst_dir)
1535 finally:
1536 try:
1537 shutil.rmtree(dst_dir)
1538 except:
1539 pass
1540
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001541 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001542 def test_move_dir_other_fs(self):
1543 # Move a dir to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001544 self.test_move_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001545
1546 def test_move_dir_to_dir(self):
1547 # Move a dir inside an existing dir on the same filesystem.
1548 self._check_move_dir(self.src_dir, self.dst_dir,
1549 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1550
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001551 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001552 def test_move_dir_to_dir_other_fs(self):
1553 # Move a dir inside an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001554 self.test_move_dir_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001555
Serhiy Storchaka3a308b92014-02-11 10:30:59 +02001556 def test_move_dir_sep_to_dir(self):
1557 self._check_move_dir(self.src_dir + os.path.sep, self.dst_dir,
1558 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1559
1560 @unittest.skipUnless(os.path.altsep, 'requires os.path.altsep')
1561 def test_move_dir_altsep_to_dir(self):
1562 self._check_move_dir(self.src_dir + os.path.altsep, self.dst_dir,
1563 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1564
Christian Heimesada8c3b2008-03-18 18:26:33 +00001565 def test_existing_file_inside_dest_dir(self):
1566 # A file with the same name inside the destination dir already exists.
1567 with open(self.dst_file, "wb"):
1568 pass
1569 self.assertRaises(shutil.Error, shutil.move, self.src_file, self.dst_dir)
1570
1571 def test_dont_move_dir_in_itself(self):
1572 # Moving a dir inside itself raises an Error.
1573 dst = os.path.join(self.src_dir, "bar")
1574 self.assertRaises(shutil.Error, shutil.move, self.src_dir, dst)
1575
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001576 def test_destinsrc_false_negative(self):
1577 os.mkdir(TESTFN)
1578 try:
1579 for src, dst in [('srcdir', 'srcdir/dest')]:
1580 src = os.path.join(TESTFN, src)
1581 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001582 self.assertTrue(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001583 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001584 'dst (%s) is not in src (%s)' % (dst, src))
1585 finally:
1586 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001587
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001588 def test_destinsrc_false_positive(self):
1589 os.mkdir(TESTFN)
1590 try:
1591 for src, dst in [('srcdir', 'src/dest'), ('srcdir', 'srcdir.new')]:
1592 src = os.path.join(TESTFN, src)
1593 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001594 self.assertFalse(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001595 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001596 'dst (%s) is in src (%s)' % (dst, src))
1597 finally:
1598 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimes9bd667a2008-01-20 15:14:11 +00001599
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +01001600 @support.skip_unless_symlink
1601 @mock_rename
1602 def test_move_file_symlink(self):
1603 dst = os.path.join(self.src_dir, 'bar')
1604 os.symlink(self.src_file, dst)
1605 shutil.move(dst, self.dst_file)
1606 self.assertTrue(os.path.islink(self.dst_file))
1607 self.assertTrue(os.path.samefile(self.src_file, self.dst_file))
1608
1609 @support.skip_unless_symlink
1610 @mock_rename
1611 def test_move_file_symlink_to_dir(self):
1612 filename = "bar"
1613 dst = os.path.join(self.src_dir, filename)
1614 os.symlink(self.src_file, dst)
1615 shutil.move(dst, self.dst_dir)
1616 final_link = os.path.join(self.dst_dir, filename)
1617 self.assertTrue(os.path.islink(final_link))
1618 self.assertTrue(os.path.samefile(self.src_file, final_link))
1619
1620 @support.skip_unless_symlink
1621 @mock_rename
1622 def test_move_dangling_symlink(self):
1623 src = os.path.join(self.src_dir, 'baz')
1624 dst = os.path.join(self.src_dir, 'bar')
1625 os.symlink(src, dst)
1626 dst_link = os.path.join(self.dst_dir, 'quux')
1627 shutil.move(dst, dst_link)
1628 self.assertTrue(os.path.islink(dst_link))
Antoine Pitrou3f48ac92014-01-01 02:50:45 +01001629 # On Windows, os.path.realpath does not follow symlinks (issue #9949)
1630 if os.name == 'nt':
1631 self.assertEqual(os.path.realpath(src), os.readlink(dst_link))
1632 else:
1633 self.assertEqual(os.path.realpath(src), os.path.realpath(dst_link))
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +01001634
1635 @support.skip_unless_symlink
1636 @mock_rename
1637 def test_move_dir_symlink(self):
1638 src = os.path.join(self.src_dir, 'baz')
1639 dst = os.path.join(self.src_dir, 'bar')
1640 os.mkdir(src)
1641 os.symlink(src, dst)
1642 dst_link = os.path.join(self.dst_dir, 'quux')
1643 shutil.move(dst, dst_link)
1644 self.assertTrue(os.path.islink(dst_link))
1645 self.assertTrue(os.path.samefile(src, dst_link))
1646
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001647 def test_move_return_value(self):
1648 rv = shutil.move(self.src_file, self.dst_dir)
1649 self.assertEqual(rv,
1650 os.path.join(self.dst_dir, os.path.basename(self.src_file)))
1651
1652 def test_move_as_rename_return_value(self):
1653 rv = shutil.move(self.src_file, os.path.join(self.dst_dir, 'bar'))
1654 self.assertEqual(rv, os.path.join(self.dst_dir, 'bar'))
1655
R David Murray6ffface2014-06-11 14:40:13 -04001656 @mock_rename
1657 def test_move_file_special_function(self):
1658 moved = []
1659 def _copy(src, dst):
1660 moved.append((src, dst))
1661 shutil.move(self.src_file, self.dst_dir, copy_function=_copy)
1662 self.assertEqual(len(moved), 1)
1663
1664 @mock_rename
1665 def test_move_dir_special_function(self):
1666 moved = []
1667 def _copy(src, dst):
1668 moved.append((src, dst))
1669 support.create_empty_file(os.path.join(self.src_dir, 'child'))
1670 support.create_empty_file(os.path.join(self.src_dir, 'child1'))
1671 shutil.move(self.src_dir, self.dst_dir, copy_function=_copy)
1672 self.assertEqual(len(moved), 3)
1673
Tarek Ziadé5340db32010-04-19 22:30:51 +00001674
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001675class TestCopyFile(unittest.TestCase):
1676
1677 _delete = False
1678
1679 class Faux(object):
1680 _entered = False
1681 _exited_with = None
1682 _raised = False
1683 def __init__(self, raise_in_exit=False, suppress_at_exit=True):
1684 self._raise_in_exit = raise_in_exit
1685 self._suppress_at_exit = suppress_at_exit
1686 def read(self, *args):
1687 return ''
1688 def __enter__(self):
1689 self._entered = True
1690 def __exit__(self, exc_type, exc_val, exc_tb):
1691 self._exited_with = exc_type, exc_val, exc_tb
1692 if self._raise_in_exit:
1693 self._raised = True
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001694 raise OSError("Cannot close")
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001695 return self._suppress_at_exit
1696
1697 def tearDown(self):
1698 if self._delete:
1699 del shutil.open
1700
1701 def _set_shutil_open(self, func):
1702 shutil.open = func
1703 self._delete = True
1704
1705 def test_w_source_open_fails(self):
1706 def _open(filename, mode='r'):
1707 if filename == 'srcfile':
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001708 raise OSError('Cannot open "srcfile"')
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001709 assert 0 # shouldn't reach here.
1710
1711 self._set_shutil_open(_open)
1712
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001713 self.assertRaises(OSError, shutil.copyfile, 'srcfile', 'destfile')
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001714
1715 def test_w_dest_open_fails(self):
1716
1717 srcfile = self.Faux()
1718
1719 def _open(filename, mode='r'):
1720 if filename == 'srcfile':
1721 return srcfile
1722 if filename == 'destfile':
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001723 raise OSError('Cannot open "destfile"')
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001724 assert 0 # shouldn't reach here.
1725
1726 self._set_shutil_open(_open)
1727
1728 shutil.copyfile('srcfile', 'destfile')
1729 self.assertTrue(srcfile._entered)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001730 self.assertTrue(srcfile._exited_with[0] is OSError)
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001731 self.assertEqual(srcfile._exited_with[1].args,
1732 ('Cannot open "destfile"',))
1733
1734 def test_w_dest_close_fails(self):
1735
1736 srcfile = self.Faux()
1737 destfile = self.Faux(True)
1738
1739 def _open(filename, mode='r'):
1740 if filename == 'srcfile':
1741 return srcfile
1742 if filename == 'destfile':
1743 return destfile
1744 assert 0 # shouldn't reach here.
1745
1746 self._set_shutil_open(_open)
1747
1748 shutil.copyfile('srcfile', 'destfile')
1749 self.assertTrue(srcfile._entered)
1750 self.assertTrue(destfile._entered)
1751 self.assertTrue(destfile._raised)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001752 self.assertTrue(srcfile._exited_with[0] is OSError)
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001753 self.assertEqual(srcfile._exited_with[1].args,
1754 ('Cannot close',))
1755
1756 def test_w_source_close_fails(self):
1757
1758 srcfile = self.Faux(True)
1759 destfile = self.Faux()
1760
1761 def _open(filename, mode='r'):
1762 if filename == 'srcfile':
1763 return srcfile
1764 if filename == 'destfile':
1765 return destfile
1766 assert 0 # shouldn't reach here.
1767
1768 self._set_shutil_open(_open)
1769
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001770 self.assertRaises(OSError,
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001771 shutil.copyfile, 'srcfile', 'destfile')
1772 self.assertTrue(srcfile._entered)
1773 self.assertTrue(destfile._entered)
1774 self.assertFalse(destfile._raised)
1775 self.assertTrue(srcfile._exited_with[0] is None)
1776 self.assertTrue(srcfile._raised)
1777
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001778 def test_move_dir_caseinsensitive(self):
1779 # Renames a folder to the same name
1780 # but a different case.
1781
1782 self.src_dir = tempfile.mkdtemp()
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001783 self.addCleanup(shutil.rmtree, self.src_dir, True)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001784 dst_dir = os.path.join(
1785 os.path.dirname(self.src_dir),
1786 os.path.basename(self.src_dir).upper())
1787 self.assertNotEqual(self.src_dir, dst_dir)
1788
1789 try:
1790 shutil.move(self.src_dir, dst_dir)
1791 self.assertTrue(os.path.isdir(dst_dir))
1792 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +02001793 os.rmdir(dst_dir)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001794
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001795class TermsizeTests(unittest.TestCase):
1796 def test_does_not_crash(self):
1797 """Check if get_terminal_size() returns a meaningful value.
1798
1799 There's no easy portable way to actually check the size of the
1800 terminal, so let's check if it returns something sensible instead.
1801 """
1802 size = shutil.get_terminal_size()
Antoine Pitroucfade362012-02-08 23:48:59 +01001803 self.assertGreaterEqual(size.columns, 0)
1804 self.assertGreaterEqual(size.lines, 0)
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001805
1806 def test_os_environ_first(self):
1807 "Check if environment variables have precedence"
1808
1809 with support.EnvironmentVarGuard() as env:
1810 env['COLUMNS'] = '777'
1811 size = shutil.get_terminal_size()
1812 self.assertEqual(size.columns, 777)
1813
1814 with support.EnvironmentVarGuard() as env:
1815 env['LINES'] = '888'
1816 size = shutil.get_terminal_size()
1817 self.assertEqual(size.lines, 888)
1818
1819 @unittest.skipUnless(os.isatty(sys.__stdout__.fileno()), "not on tty")
1820 def test_stty_match(self):
1821 """Check if stty returns the same results ignoring env
1822
1823 This test will fail if stdin and stdout are connected to
1824 different terminals with different sizes. Nevertheless, such
1825 situations should be pretty rare.
1826 """
1827 try:
1828 size = subprocess.check_output(['stty', 'size']).decode().split()
1829 except (FileNotFoundError, subprocess.CalledProcessError):
1830 self.skipTest("stty invocation failed")
1831 expected = (int(size[1]), int(size[0])) # reversed order
1832
1833 with support.EnvironmentVarGuard() as env:
1834 del env['LINES']
1835 del env['COLUMNS']
1836 actual = shutil.get_terminal_size()
1837
1838 self.assertEqual(expected, actual)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001839
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001840
Berker Peksag8083cd62014-11-01 11:04:06 +02001841class PublicAPITests(unittest.TestCase):
1842 """Ensures that the correct values are exposed in the public API."""
1843
1844 def test_module_all_attribute(self):
1845 self.assertTrue(hasattr(shutil, '__all__'))
1846 target_api = ['copyfileobj', 'copyfile', 'copymode', 'copystat',
1847 'copy', 'copy2', 'copytree', 'move', 'rmtree', 'Error',
1848 'SpecialFileError', 'ExecError', 'make_archive',
1849 'get_archive_formats', 'register_archive_format',
1850 'unregister_archive_format', 'get_unpack_formats',
1851 'register_unpack_format', 'unregister_unpack_format',
1852 'unpack_archive', 'ignore_patterns', 'chown', 'which',
1853 'get_terminal_size', 'SameFileError']
1854 if hasattr(os, 'statvfs') or os.name == 'nt':
1855 target_api.append('disk_usage')
1856 self.assertEqual(set(shutil.__all__), set(target_api))
1857
1858
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001859if __name__ == '__main__':
Brett Cannon3e9a9ae2013-06-12 21:25:59 -04001860 unittest.main()