blob: cbca767a4c30afb6cce9a6aca7f7a03d5acbb186 [file] [log] [blame]
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001# Copyright (C) 2003 Python Software Foundation
2
3import unittest
4import shutil
5import tempfile
Johannes Gijsbers8e6f2de2004-11-23 09:27:27 +00006import sys
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +00007import stat
Brett Cannon1c3fa182004-06-19 21:11:35 +00008import os
9import os.path
Antoine Pitrouc041ab62012-01-02 19:18:02 +010010import errno
Nick Coghlan8ed3cf32011-03-16 14:05:35 -040011import functools
Antoine Pitroubcf2b592012-02-08 23:28:36 +010012import subprocess
Benjamin Petersonee8712c2008-05-20 21:35:26 +000013from test import support
14from test.support import TESTFN
Tarek Ziadé396fad72010-02-23 05:30:31 +000015from os.path import splitdrive
16from distutils.spawn import find_executable, spawn
17from shutil import (_make_tarball, _make_zipfile, make_archive,
18 register_archive_format, unregister_archive_format,
Tarek Ziadé6ac91722010-04-28 17:51:36 +000019 get_archive_formats, Error, unpack_archive,
20 register_unpack_format, RegistryError,
Hynek Schlawack48653762012-10-07 12:49:58 +020021 unregister_unpack_format, get_unpack_formats,
22 SameFileError)
Tarek Ziadé396fad72010-02-23 05:30:31 +000023import tarfile
24import warnings
25
26from test import support
Ezio Melotti975077a2011-05-19 22:03:22 +030027from test.support import TESTFN, check_warnings, captured_stdout, requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +000028
Tarek Ziadéffa155a2010-04-29 13:34:35 +000029try:
30 import bz2
31 BZ2_SUPPORTED = True
32except ImportError:
33 BZ2_SUPPORTED = False
34
Antoine Pitrou7fff0962009-05-01 21:09:44 +000035TESTFN2 = TESTFN + "2"
Barry Warsaw7fc2cca2003-01-24 17:34:13 +000036
Tarek Ziadé396fad72010-02-23 05:30:31 +000037try:
38 import grp
39 import pwd
40 UID_GID_SUPPORT = True
41except ImportError:
42 UID_GID_SUPPORT = False
43
44try:
Tarek Ziadé396fad72010-02-23 05:30:31 +000045 import zipfile
46 ZIP_SUPPORT = True
47except ImportError:
48 ZIP_SUPPORT = find_executable('zip')
49
Nick Coghlan8ed3cf32011-03-16 14:05:35 -040050def _fake_rename(*args, **kwargs):
51 # Pretend the destination path is on a different filesystem.
Antoine Pitrouc041ab62012-01-02 19:18:02 +010052 raise OSError(getattr(errno, 'EXDEV', 18), "Invalid cross-device link")
Nick Coghlan8ed3cf32011-03-16 14:05:35 -040053
54def mock_rename(func):
55 @functools.wraps(func)
56 def wrap(*args, **kwargs):
57 try:
58 builtin_rename = os.rename
59 os.rename = _fake_rename
60 return func(*args, **kwargs)
61 finally:
62 os.rename = builtin_rename
63 return wrap
64
Éric Araujoa7e33a12011-08-12 19:51:35 +020065def write_file(path, content, binary=False):
66 """Write *content* to a file located at *path*.
67
68 If *path* is a tuple instead of a string, os.path.join will be used to
69 make a path. If *binary* is true, the file will be opened in binary
70 mode.
71 """
72 if isinstance(path, tuple):
73 path = os.path.join(*path)
74 with open(path, 'wb' if binary else 'w') as fp:
75 fp.write(content)
76
77def read_file(path, binary=False):
78 """Return contents from a file located at *path*.
79
80 If *path* is a tuple instead of a string, os.path.join will be used to
81 make a path. If *binary* is true, the file will be opened in binary
82 mode.
83 """
84 if isinstance(path, tuple):
85 path = os.path.join(*path)
86 with open(path, 'rb' if binary else 'r') as fp:
87 return fp.read()
88
89
Barry Warsaw7fc2cca2003-01-24 17:34:13 +000090class TestShutil(unittest.TestCase):
Tarek Ziadé396fad72010-02-23 05:30:31 +000091
92 def setUp(self):
93 super(TestShutil, self).setUp()
94 self.tempdirs = []
95
96 def tearDown(self):
97 super(TestShutil, self).tearDown()
98 while self.tempdirs:
99 d = self.tempdirs.pop()
100 shutil.rmtree(d, os.name in ('nt', 'cygwin'))
101
Tarek Ziadé396fad72010-02-23 05:30:31 +0000102
103 def mkdtemp(self):
104 """Create a temporary directory that will be cleaned up.
105
106 Returns the path of the directory.
107 """
108 d = tempfile.mkdtemp()
109 self.tempdirs.append(d)
110 return d
Tarek Ziadé5340db32010-04-19 22:30:51 +0000111
Hynek Schlawack3b527782012-06-25 13:27:31 +0200112 def test_rmtree_works_on_bytes(self):
113 tmp = self.mkdtemp()
114 victim = os.path.join(tmp, 'killme')
115 os.mkdir(victim)
116 write_file(os.path.join(victim, 'somefile'), 'foo')
117 victim = os.fsencode(victim)
118 self.assertIsInstance(victim, bytes)
119 shutil.rmtree(victim)
120
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200121 @support.skip_unless_symlink
122 def test_rmtree_fails_on_symlink(self):
123 tmp = self.mkdtemp()
124 dir_ = os.path.join(tmp, 'dir')
125 os.mkdir(dir_)
126 link = os.path.join(tmp, 'link')
127 os.symlink(dir_, link)
128 self.assertRaises(OSError, shutil.rmtree, link)
129 self.assertTrue(os.path.exists(dir_))
130
131 @support.skip_unless_symlink
132 def test_rmtree_works_on_symlinks(self):
133 tmp = self.mkdtemp()
134 dir1 = os.path.join(tmp, 'dir1')
135 dir2 = os.path.join(dir1, 'dir2')
136 dir3 = os.path.join(tmp, 'dir3')
137 for d in dir1, dir2, dir3:
138 os.mkdir(d)
139 file1 = os.path.join(tmp, 'file1')
140 write_file(file1, 'foo')
141 link1 = os.path.join(dir1, 'link1')
142 os.symlink(dir2, link1)
143 link2 = os.path.join(dir1, 'link2')
144 os.symlink(dir3, link2)
145 link3 = os.path.join(dir1, 'link3')
146 os.symlink(file1, link3)
147 # make sure symlinks are removed but not followed
148 shutil.rmtree(dir1)
149 self.assertFalse(os.path.exists(dir1))
150 self.assertTrue(os.path.exists(dir3))
151 self.assertTrue(os.path.exists(file1))
152
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000153 def test_rmtree_errors(self):
154 # filename is guaranteed not to exist
155 filename = tempfile.mktemp()
156 self.assertRaises(OSError, shutil.rmtree, filename)
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000157
Johannes Gijsbersb8b09d02004-12-06 20:50:15 +0000158 # See bug #1071513 for why we don't run this on cygwin
159 # and bug #1076467 for why we don't run this as root.
160 if (hasattr(os, 'chmod') and sys.platform[:6] != 'cygwin'
Johannes Gijsbers6b220b02004-12-12 15:52:57 +0000161 and not (hasattr(os, 'geteuid') and os.geteuid() == 0)):
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000162 def test_on_error(self):
163 self.errorState = 0
164 os.mkdir(TESTFN)
Antoine Pitrou2f8a75c2012-06-23 21:28:15 +0200165 self.addCleanup(shutil.rmtree, TESTFN)
166
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200167 self.child_file_path = os.path.join(TESTFN, 'a')
168 self.child_dir_path = os.path.join(TESTFN, 'b')
169 support.create_empty_file(self.child_file_path)
170 os.mkdir(self.child_dir_path)
Tim Peters4590c002004-11-01 02:40:52 +0000171 old_dir_mode = os.stat(TESTFN).st_mode
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200172 old_child_file_mode = os.stat(self.child_file_path).st_mode
173 old_child_dir_mode = os.stat(self.child_dir_path).st_mode
Tim Peters4590c002004-11-01 02:40:52 +0000174 # Make unwritable.
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200175 new_mode = stat.S_IREAD|stat.S_IEXEC
176 os.chmod(self.child_file_path, new_mode)
177 os.chmod(self.child_dir_path, new_mode)
178 os.chmod(TESTFN, new_mode)
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000179
Antoine Pitrou2f8a75c2012-06-23 21:28:15 +0200180 self.addCleanup(os.chmod, TESTFN, old_dir_mode)
181 self.addCleanup(os.chmod, self.child_file_path, old_child_file_mode)
182 self.addCleanup(os.chmod, self.child_dir_path, old_child_dir_mode)
183
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000184 shutil.rmtree(TESTFN, onerror=self.check_args_to_onerror)
Johannes Gijsbers8e6f2de2004-11-23 09:27:27 +0000185 # Test whether onerror has actually been called.
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200186 self.assertEqual(self.errorState, 3,
187 "Expected call to onerror function did not "
188 "happen.")
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000189
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000190 def check_args_to_onerror(self, func, arg, exc):
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000191 # test_rmtree_errors deliberately runs rmtree
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200192 # on a directory that is chmod 500, which will fail.
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000193 # This function is run when shutil.rmtree fails.
194 # 99.9% of the time it initially fails to remove
195 # a file in the directory, so the first time through
196 # func is os.remove.
197 # However, some Linux machines running ZFS on
198 # FUSE experienced a failure earlier in the process
199 # at os.listdir. The first failure may legally
200 # be either.
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200201 if self.errorState < 2:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200202 if func is os.unlink:
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200203 self.assertEqual(arg, self.child_file_path)
204 elif func is os.rmdir:
205 self.assertEqual(arg, self.child_dir_path)
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000206 else:
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200207 self.assertIs(func, os.listdir)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200208 self.assertIn(arg, [TESTFN, self.child_dir_path])
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000209 self.assertTrue(issubclass(exc[0], OSError))
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200210 self.errorState += 1
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000211 else:
212 self.assertEqual(func, os.rmdir)
213 self.assertEqual(arg, TESTFN)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000214 self.assertTrue(issubclass(exc[0], OSError))
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200215 self.errorState = 3
216
217 def test_rmtree_does_not_choke_on_failing_lstat(self):
218 try:
219 orig_lstat = os.lstat
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200220 def raiser(fn, *args, **kwargs):
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200221 if fn != TESTFN:
222 raise OSError()
223 else:
224 return orig_lstat(fn)
225 os.lstat = raiser
226
227 os.mkdir(TESTFN)
228 write_file((TESTFN, 'foo'), 'foo')
229 shutil.rmtree(TESTFN)
230 finally:
231 os.lstat = orig_lstat
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000232
Antoine Pitrou78091e62011-12-29 18:54:15 +0100233 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
234 @support.skip_unless_symlink
235 def test_copymode_follow_symlinks(self):
236 tmp_dir = self.mkdtemp()
237 src = os.path.join(tmp_dir, 'foo')
238 dst = os.path.join(tmp_dir, 'bar')
239 src_link = os.path.join(tmp_dir, 'baz')
240 dst_link = os.path.join(tmp_dir, 'quux')
241 write_file(src, 'foo')
242 write_file(dst, 'foo')
243 os.symlink(src, src_link)
244 os.symlink(dst, dst_link)
245 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
246 # file to file
247 os.chmod(dst, stat.S_IRWXO)
248 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
249 shutil.copymode(src, dst)
250 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
251 # follow src link
252 os.chmod(dst, stat.S_IRWXO)
253 shutil.copymode(src_link, dst)
254 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
255 # follow dst link
256 os.chmod(dst, stat.S_IRWXO)
257 shutil.copymode(src, dst_link)
258 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
259 # follow both links
260 os.chmod(dst, stat.S_IRWXO)
261 shutil.copymode(src_link, dst)
262 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
263
264 @unittest.skipUnless(hasattr(os, 'lchmod'), 'requires os.lchmod')
265 @support.skip_unless_symlink
266 def test_copymode_symlink_to_symlink(self):
267 tmp_dir = self.mkdtemp()
268 src = os.path.join(tmp_dir, 'foo')
269 dst = os.path.join(tmp_dir, 'bar')
270 src_link = os.path.join(tmp_dir, 'baz')
271 dst_link = os.path.join(tmp_dir, 'quux')
272 write_file(src, 'foo')
273 write_file(dst, 'foo')
274 os.symlink(src, src_link)
275 os.symlink(dst, dst_link)
276 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
277 os.chmod(dst, stat.S_IRWXU)
278 os.lchmod(src_link, stat.S_IRWXO|stat.S_IRWXG)
279 # link to link
280 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700281 shutil.copymode(src_link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100282 self.assertEqual(os.lstat(src_link).st_mode,
283 os.lstat(dst_link).st_mode)
284 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
285 # src link - use chmod
286 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700287 shutil.copymode(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100288 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
289 # dst link - use chmod
290 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700291 shutil.copymode(src, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100292 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
293
294 @unittest.skipIf(hasattr(os, 'lchmod'), 'requires os.lchmod to be missing')
295 @support.skip_unless_symlink
296 def test_copymode_symlink_to_symlink_wo_lchmod(self):
297 tmp_dir = self.mkdtemp()
298 src = os.path.join(tmp_dir, 'foo')
299 dst = os.path.join(tmp_dir, 'bar')
300 src_link = os.path.join(tmp_dir, 'baz')
301 dst_link = os.path.join(tmp_dir, 'quux')
302 write_file(src, 'foo')
303 write_file(dst, 'foo')
304 os.symlink(src, src_link)
305 os.symlink(dst, dst_link)
Larry Hastingsb4038062012-07-15 10:57:38 -0700306 shutil.copymode(src_link, dst_link, follow_symlinks=False) # silent fail
Antoine Pitrou78091e62011-12-29 18:54:15 +0100307
308 @support.skip_unless_symlink
309 def test_copystat_symlinks(self):
310 tmp_dir = self.mkdtemp()
311 src = os.path.join(tmp_dir, 'foo')
312 dst = os.path.join(tmp_dir, 'bar')
313 src_link = os.path.join(tmp_dir, 'baz')
314 dst_link = os.path.join(tmp_dir, 'qux')
315 write_file(src, 'foo')
316 src_stat = os.stat(src)
317 os.utime(src, (src_stat.st_atime,
318 src_stat.st_mtime - 42.0)) # ensure different mtimes
319 write_file(dst, 'bar')
320 self.assertNotEqual(os.stat(src).st_mtime, os.stat(dst).st_mtime)
321 os.symlink(src, src_link)
322 os.symlink(dst, dst_link)
323 if hasattr(os, 'lchmod'):
324 os.lchmod(src_link, stat.S_IRWXO)
325 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
326 os.lchflags(src_link, stat.UF_NODUMP)
327 src_link_stat = os.lstat(src_link)
328 # follow
329 if hasattr(os, 'lchmod'):
Larry Hastingsb4038062012-07-15 10:57:38 -0700330 shutil.copystat(src_link, dst_link, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100331 self.assertNotEqual(src_link_stat.st_mode, os.stat(dst).st_mode)
332 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700333 shutil.copystat(src_link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100334 dst_link_stat = os.lstat(dst_link)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700335 if os.utime in os.supports_follow_symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100336 for attr in 'st_atime', 'st_mtime':
337 # The modification times may be truncated in the new file.
338 self.assertLessEqual(getattr(src_link_stat, attr),
339 getattr(dst_link_stat, attr) + 1)
340 if hasattr(os, 'lchmod'):
341 self.assertEqual(src_link_stat.st_mode, dst_link_stat.st_mode)
342 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
343 self.assertEqual(src_link_stat.st_flags, dst_link_stat.st_flags)
344 # tell to follow but dst is not a link
Larry Hastingsb4038062012-07-15 10:57:38 -0700345 shutil.copystat(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100346 self.assertTrue(abs(os.stat(src).st_mtime - os.stat(dst).st_mtime) <
347 00000.1)
348
Ned Deilybaf75712012-05-10 17:05:19 -0700349 @unittest.skipUnless(hasattr(os, 'chflags') and
350 hasattr(errno, 'EOPNOTSUPP') and
351 hasattr(errno, 'ENOTSUP'),
352 "requires os.chflags, EOPNOTSUPP & ENOTSUP")
353 def test_copystat_handles_harmless_chflags_errors(self):
354 tmpdir = self.mkdtemp()
355 file1 = os.path.join(tmpdir, 'file1')
356 file2 = os.path.join(tmpdir, 'file2')
357 write_file(file1, 'xxx')
358 write_file(file2, 'xxx')
359
360 def make_chflags_raiser(err):
361 ex = OSError()
362
Larry Hastings90867a52012-06-22 17:01:41 -0700363 def _chflags_raiser(path, flags, *, follow_symlinks=True):
Ned Deilybaf75712012-05-10 17:05:19 -0700364 ex.errno = err
365 raise ex
366 return _chflags_raiser
367 old_chflags = os.chflags
368 try:
369 for err in errno.EOPNOTSUPP, errno.ENOTSUP:
370 os.chflags = make_chflags_raiser(err)
371 shutil.copystat(file1, file2)
372 # assert others errors break it
373 os.chflags = make_chflags_raiser(errno.EOPNOTSUPP + errno.ENOTSUP)
374 self.assertRaises(OSError, shutil.copystat, file1, file2)
375 finally:
376 os.chflags = old_chflags
377
Antoine Pitrou424246f2012-05-12 19:02:01 +0200378 @support.skip_unless_xattr
379 def test_copyxattr(self):
380 tmp_dir = self.mkdtemp()
381 src = os.path.join(tmp_dir, 'foo')
382 write_file(src, 'foo')
383 dst = os.path.join(tmp_dir, 'bar')
384 write_file(dst, 'bar')
385
386 # no xattr == no problem
387 shutil._copyxattr(src, dst)
388 # common case
389 os.setxattr(src, 'user.foo', b'42')
390 os.setxattr(src, 'user.bar', b'43')
391 shutil._copyxattr(src, dst)
392 self.assertEqual(os.listxattr(src), os.listxattr(dst))
393 self.assertEqual(
394 os.getxattr(src, 'user.foo'),
395 os.getxattr(dst, 'user.foo'))
396 # check errors don't affect other attrs
397 os.remove(dst)
398 write_file(dst, 'bar')
399 os_error = OSError(errno.EPERM, 'EPERM')
400
Larry Hastings9cf065c2012-06-22 16:30:09 -0700401 def _raise_on_user_foo(fname, attr, val, **kwargs):
Antoine Pitrou424246f2012-05-12 19:02:01 +0200402 if attr == 'user.foo':
403 raise os_error
404 else:
Larry Hastings9cf065c2012-06-22 16:30:09 -0700405 orig_setxattr(fname, attr, val, **kwargs)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200406 try:
407 orig_setxattr = os.setxattr
408 os.setxattr = _raise_on_user_foo
409 shutil._copyxattr(src, dst)
Antoine Pitrou61597d32012-05-12 23:37:35 +0200410 self.assertIn('user.bar', os.listxattr(dst))
Antoine Pitrou424246f2012-05-12 19:02:01 +0200411 finally:
412 os.setxattr = orig_setxattr
413
Larry Hastingsad5ae042012-07-14 17:55:11 -0700414 # test that shutil.copystat copies xattrs
415 src = os.path.join(tmp_dir, 'the_original')
416 write_file(src, src)
417 os.setxattr(src, 'user.the_value', b'fiddly')
418 dst = os.path.join(tmp_dir, 'the_copy')
419 write_file(dst, dst)
420 shutil.copystat(src, dst)
Hynek Schlawackc2d481f2012-07-16 17:11:10 +0200421 self.assertEqual(os.getxattr(dst, 'user.the_value'), b'fiddly')
Larry Hastingsad5ae042012-07-14 17:55:11 -0700422
Antoine Pitrou424246f2012-05-12 19:02:01 +0200423 @support.skip_unless_symlink
424 @support.skip_unless_xattr
425 @unittest.skipUnless(hasattr(os, 'geteuid') and os.geteuid() == 0,
426 'root privileges required')
427 def test_copyxattr_symlinks(self):
428 # On Linux, it's only possible to access non-user xattr for symlinks;
429 # which in turn require root privileges. This test should be expanded
430 # as soon as other platforms gain support for extended attributes.
431 tmp_dir = self.mkdtemp()
432 src = os.path.join(tmp_dir, 'foo')
433 src_link = os.path.join(tmp_dir, 'baz')
434 write_file(src, 'foo')
435 os.symlink(src, src_link)
436 os.setxattr(src, 'trusted.foo', b'42')
Larry Hastings9cf065c2012-06-22 16:30:09 -0700437 os.setxattr(src_link, 'trusted.foo', b'43', follow_symlinks=False)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200438 dst = os.path.join(tmp_dir, 'bar')
439 dst_link = os.path.join(tmp_dir, 'qux')
440 write_file(dst, 'bar')
441 os.symlink(dst, dst_link)
Larry Hastingsb4038062012-07-15 10:57:38 -0700442 shutil._copyxattr(src_link, dst_link, follow_symlinks=False)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700443 self.assertEqual(os.getxattr(dst_link, 'trusted.foo', follow_symlinks=False), b'43')
Antoine Pitrou424246f2012-05-12 19:02:01 +0200444 self.assertRaises(OSError, os.getxattr, dst, 'trusted.foo')
Larry Hastingsb4038062012-07-15 10:57:38 -0700445 shutil._copyxattr(src_link, dst, follow_symlinks=False)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200446 self.assertEqual(os.getxattr(dst, 'trusted.foo'), b'43')
447
Antoine Pitrou78091e62011-12-29 18:54:15 +0100448 @support.skip_unless_symlink
449 def test_copy_symlinks(self):
450 tmp_dir = self.mkdtemp()
451 src = os.path.join(tmp_dir, 'foo')
452 dst = os.path.join(tmp_dir, 'bar')
453 src_link = os.path.join(tmp_dir, 'baz')
454 write_file(src, 'foo')
455 os.symlink(src, src_link)
456 if hasattr(os, 'lchmod'):
457 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
458 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700459 shutil.copy(src_link, dst, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100460 self.assertFalse(os.path.islink(dst))
461 self.assertEqual(read_file(src), read_file(dst))
462 os.remove(dst)
463 # follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700464 shutil.copy(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100465 self.assertTrue(os.path.islink(dst))
466 self.assertEqual(os.readlink(dst), os.readlink(src_link))
467 if hasattr(os, 'lchmod'):
468 self.assertEqual(os.lstat(src_link).st_mode,
469 os.lstat(dst).st_mode)
470
471 @support.skip_unless_symlink
472 def test_copy2_symlinks(self):
473 tmp_dir = self.mkdtemp()
474 src = os.path.join(tmp_dir, 'foo')
475 dst = os.path.join(tmp_dir, 'bar')
476 src_link = os.path.join(tmp_dir, 'baz')
477 write_file(src, 'foo')
478 os.symlink(src, src_link)
479 if hasattr(os, 'lchmod'):
480 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
481 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
482 os.lchflags(src_link, stat.UF_NODUMP)
483 src_stat = os.stat(src)
484 src_link_stat = os.lstat(src_link)
485 # follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700486 shutil.copy2(src_link, dst, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100487 self.assertFalse(os.path.islink(dst))
488 self.assertEqual(read_file(src), read_file(dst))
489 os.remove(dst)
490 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700491 shutil.copy2(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100492 self.assertTrue(os.path.islink(dst))
493 self.assertEqual(os.readlink(dst), os.readlink(src_link))
494 dst_stat = os.lstat(dst)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700495 if os.utime in os.supports_follow_symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100496 for attr in 'st_atime', 'st_mtime':
497 # The modification times may be truncated in the new file.
498 self.assertLessEqual(getattr(src_link_stat, attr),
499 getattr(dst_stat, attr) + 1)
500 if hasattr(os, 'lchmod'):
501 self.assertEqual(src_link_stat.st_mode, dst_stat.st_mode)
502 self.assertNotEqual(src_stat.st_mode, dst_stat.st_mode)
503 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
504 self.assertEqual(src_link_stat.st_flags, dst_stat.st_flags)
505
Antoine Pitrou424246f2012-05-12 19:02:01 +0200506 @support.skip_unless_xattr
507 def test_copy2_xattr(self):
508 tmp_dir = self.mkdtemp()
509 src = os.path.join(tmp_dir, 'foo')
510 dst = os.path.join(tmp_dir, 'bar')
511 write_file(src, 'foo')
512 os.setxattr(src, 'user.foo', b'42')
513 shutil.copy2(src, dst)
514 self.assertEqual(
515 os.getxattr(src, 'user.foo'),
516 os.getxattr(dst, 'user.foo'))
517 os.remove(dst)
518
Antoine Pitrou78091e62011-12-29 18:54:15 +0100519 @support.skip_unless_symlink
520 def test_copyfile_symlinks(self):
521 tmp_dir = self.mkdtemp()
522 src = os.path.join(tmp_dir, 'src')
523 dst = os.path.join(tmp_dir, 'dst')
524 dst_link = os.path.join(tmp_dir, 'dst_link')
525 link = os.path.join(tmp_dir, 'link')
526 write_file(src, 'foo')
527 os.symlink(src, link)
528 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700529 shutil.copyfile(link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100530 self.assertTrue(os.path.islink(dst_link))
531 self.assertEqual(os.readlink(link), os.readlink(dst_link))
532 # follow
533 shutil.copyfile(link, dst)
534 self.assertFalse(os.path.islink(dst))
535
Hynek Schlawack2100b422012-06-23 20:28:32 +0200536 def test_rmtree_uses_safe_fd_version_if_available(self):
Hynek Schlawackd0f6e0a2012-06-29 08:28:20 +0200537 _use_fd_functions = ({os.open, os.stat, os.unlink, os.rmdir} <=
538 os.supports_dir_fd and
539 os.listdir in os.supports_fd and
540 os.stat in os.supports_follow_symlinks)
541 if _use_fd_functions:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200542 self.assertTrue(shutil._use_fd_functions)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000543 self.assertTrue(shutil.rmtree.avoids_symlink_attacks)
Hynek Schlawack2100b422012-06-23 20:28:32 +0200544 tmp_dir = self.mkdtemp()
545 d = os.path.join(tmp_dir, 'a')
546 os.mkdir(d)
547 try:
548 real_rmtree = shutil._rmtree_safe_fd
549 class Called(Exception): pass
550 def _raiser(*args, **kwargs):
551 raise Called
552 shutil._rmtree_safe_fd = _raiser
553 self.assertRaises(Called, shutil.rmtree, d)
554 finally:
555 shutil._rmtree_safe_fd = real_rmtree
556 else:
557 self.assertFalse(shutil._use_fd_functions)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000558 self.assertFalse(shutil.rmtree.avoids_symlink_attacks)
Hynek Schlawack2100b422012-06-23 20:28:32 +0200559
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000560 def test_rmtree_dont_delete_file(self):
561 # When called on a file instead of a directory, don't delete it.
562 handle, path = tempfile.mkstemp()
Victor Stinnerbf816222011-06-30 23:25:47 +0200563 os.close(handle)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200564 self.assertRaises(NotADirectoryError, shutil.rmtree, path)
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000565 os.remove(path)
566
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000567 def test_copytree_simple(self):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000568 src_dir = tempfile.mkdtemp()
569 dst_dir = os.path.join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200570 self.addCleanup(shutil.rmtree, src_dir)
571 self.addCleanup(shutil.rmtree, os.path.dirname(dst_dir))
572 write_file((src_dir, 'test.txt'), '123')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000573 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200574 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000575
Éric Araujoa7e33a12011-08-12 19:51:35 +0200576 shutil.copytree(src_dir, dst_dir)
577 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test.txt')))
578 self.assertTrue(os.path.isdir(os.path.join(dst_dir, 'test_dir')))
579 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test_dir',
580 'test.txt')))
581 actual = read_file((dst_dir, 'test.txt'))
582 self.assertEqual(actual, '123')
583 actual = read_file((dst_dir, 'test_dir', 'test.txt'))
584 self.assertEqual(actual, '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000585
Antoine Pitrou78091e62011-12-29 18:54:15 +0100586 @support.skip_unless_symlink
587 def test_copytree_symlinks(self):
588 tmp_dir = self.mkdtemp()
589 src_dir = os.path.join(tmp_dir, 'src')
590 dst_dir = os.path.join(tmp_dir, 'dst')
591 sub_dir = os.path.join(src_dir, 'sub')
592 os.mkdir(src_dir)
593 os.mkdir(sub_dir)
594 write_file((src_dir, 'file.txt'), 'foo')
595 src_link = os.path.join(sub_dir, 'link')
596 dst_link = os.path.join(dst_dir, 'sub/link')
597 os.symlink(os.path.join(src_dir, 'file.txt'),
598 src_link)
599 if hasattr(os, 'lchmod'):
600 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
601 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
602 os.lchflags(src_link, stat.UF_NODUMP)
603 src_stat = os.lstat(src_link)
604 shutil.copytree(src_dir, dst_dir, symlinks=True)
605 self.assertTrue(os.path.islink(os.path.join(dst_dir, 'sub', 'link')))
606 self.assertEqual(os.readlink(os.path.join(dst_dir, 'sub', 'link')),
607 os.path.join(src_dir, 'file.txt'))
608 dst_stat = os.lstat(dst_link)
609 if hasattr(os, 'lchmod'):
610 self.assertEqual(dst_stat.st_mode, src_stat.st_mode)
611 if hasattr(os, 'lchflags'):
612 self.assertEqual(dst_stat.st_flags, src_stat.st_flags)
613
Georg Brandl2ee470f2008-07-16 12:55:28 +0000614 def test_copytree_with_exclude(self):
Georg Brandl2ee470f2008-07-16 12:55:28 +0000615 # creating data
616 join = os.path.join
617 exists = os.path.exists
618 src_dir = tempfile.mkdtemp()
Georg Brandl2ee470f2008-07-16 12:55:28 +0000619 try:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000620 dst_dir = join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200621 write_file((src_dir, 'test.txt'), '123')
622 write_file((src_dir, 'test.tmp'), '123')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000623 os.mkdir(join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200624 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000625 os.mkdir(join(src_dir, 'test_dir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200626 write_file((src_dir, 'test_dir2', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000627 os.mkdir(join(src_dir, 'test_dir2', 'subdir'))
628 os.mkdir(join(src_dir, 'test_dir2', 'subdir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200629 write_file((src_dir, 'test_dir2', 'subdir', 'test.txt'), '456')
630 write_file((src_dir, 'test_dir2', 'subdir2', 'test.py'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000631
632 # testing glob-like patterns
633 try:
634 patterns = shutil.ignore_patterns('*.tmp', 'test_dir2')
635 shutil.copytree(src_dir, dst_dir, ignore=patterns)
636 # checking the result: some elements should not be copied
637 self.assertTrue(exists(join(dst_dir, 'test.txt')))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200638 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
639 self.assertFalse(exists(join(dst_dir, 'test_dir2')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000640 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200641 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000642 try:
643 patterns = shutil.ignore_patterns('*.tmp', 'subdir*')
644 shutil.copytree(src_dir, dst_dir, ignore=patterns)
645 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200646 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
647 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2')))
648 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000649 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200650 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000651
652 # testing callable-style
653 try:
654 def _filter(src, names):
655 res = []
656 for name in names:
657 path = os.path.join(src, name)
658
659 if (os.path.isdir(path) and
660 path.split()[-1] == 'subdir'):
661 res.append(name)
662 elif os.path.splitext(path)[-1] in ('.py'):
663 res.append(name)
664 return res
665
666 shutil.copytree(src_dir, dst_dir, ignore=_filter)
667
668 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200669 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2',
670 'test.py')))
671 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000672
673 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200674 shutil.rmtree(dst_dir)
Georg Brandl2ee470f2008-07-16 12:55:28 +0000675 finally:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000676 shutil.rmtree(src_dir)
677 shutil.rmtree(os.path.dirname(dst_dir))
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000678
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000679 @unittest.skipUnless(hasattr(os, 'link'), 'requires os.link')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000680 def test_dont_copy_file_onto_link_to_itself(self):
Georg Brandl724d0892010-12-05 07:51:39 +0000681 # Temporarily disable test on Windows.
682 if os.name == 'nt':
683 return
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000684 # bug 851123.
685 os.mkdir(TESTFN)
686 src = os.path.join(TESTFN, 'cheese')
687 dst = os.path.join(TESTFN, 'shop')
688 try:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000689 with open(src, 'w') as f:
690 f.write('cheddar')
691 os.link(src, dst)
Hynek Schlawack48653762012-10-07 12:49:58 +0200692 self.assertRaises(shutil.SameFileError, shutil.copyfile, src, dst)
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000693 with open(src, 'r') as f:
694 self.assertEqual(f.read(), 'cheddar')
695 os.remove(dst)
696 finally:
697 shutil.rmtree(TESTFN, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000698
Brian Curtin3b4499c2010-12-28 14:31:47 +0000699 @support.skip_unless_symlink
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000700 def test_dont_copy_file_onto_symlink_to_itself(self):
701 # bug 851123.
702 os.mkdir(TESTFN)
703 src = os.path.join(TESTFN, 'cheese')
704 dst = os.path.join(TESTFN, 'shop')
705 try:
706 with open(src, 'w') as f:
707 f.write('cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000708 # Using `src` here would mean we end up with a symlink pointing
709 # to TESTFN/TESTFN/cheese, while it should point at
710 # TESTFN/cheese.
711 os.symlink('cheese', dst)
Hynek Schlawack48653762012-10-07 12:49:58 +0200712 self.assertRaises(shutil.SameFileError, shutil.copyfile, src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +0000713 with open(src, 'r') as f:
714 self.assertEqual(f.read(), 'cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000715 os.remove(dst)
716 finally:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000717 shutil.rmtree(TESTFN, ignore_errors=True)
Johannes Gijsbers68128712004-08-14 13:57:08 +0000718
Brian Curtin3b4499c2010-12-28 14:31:47 +0000719 @support.skip_unless_symlink
Brian Curtind40e6f72010-07-08 21:39:08 +0000720 def test_rmtree_on_symlink(self):
721 # bug 1669.
722 os.mkdir(TESTFN)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000723 try:
Brian Curtind40e6f72010-07-08 21:39:08 +0000724 src = os.path.join(TESTFN, 'cheese')
725 dst = os.path.join(TESTFN, 'shop')
726 os.mkdir(src)
727 os.symlink(src, dst)
728 self.assertRaises(OSError, shutil.rmtree, dst)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200729 shutil.rmtree(dst, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000730 finally:
Brian Curtind40e6f72010-07-08 21:39:08 +0000731 shutil.rmtree(TESTFN, ignore_errors=True)
732
733 if hasattr(os, "mkfifo"):
734 # Issue #3002: copyfile and copytree block indefinitely on named pipes
735 def test_copyfile_named_pipe(self):
736 os.mkfifo(TESTFN)
737 try:
738 self.assertRaises(shutil.SpecialFileError,
739 shutil.copyfile, TESTFN, TESTFN2)
740 self.assertRaises(shutil.SpecialFileError,
741 shutil.copyfile, __file__, TESTFN)
742 finally:
743 os.remove(TESTFN)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000744
Brian Curtin3b4499c2010-12-28 14:31:47 +0000745 @support.skip_unless_symlink
Brian Curtin52173d42010-12-02 18:29:18 +0000746 def test_copytree_named_pipe(self):
747 os.mkdir(TESTFN)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000748 try:
Brian Curtin52173d42010-12-02 18:29:18 +0000749 subdir = os.path.join(TESTFN, "subdir")
750 os.mkdir(subdir)
751 pipe = os.path.join(subdir, "mypipe")
752 os.mkfifo(pipe)
753 try:
754 shutil.copytree(TESTFN, TESTFN2)
755 except shutil.Error as e:
756 errors = e.args[0]
757 self.assertEqual(len(errors), 1)
758 src, dst, error_msg = errors[0]
759 self.assertEqual("`%s` is a named pipe" % pipe, error_msg)
760 else:
761 self.fail("shutil.Error should have been raised")
762 finally:
763 shutil.rmtree(TESTFN, ignore_errors=True)
764 shutil.rmtree(TESTFN2, ignore_errors=True)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000765
Tarek Ziadé5340db32010-04-19 22:30:51 +0000766 def test_copytree_special_func(self):
767
768 src_dir = self.mkdtemp()
769 dst_dir = os.path.join(self.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200770 write_file((src_dir, 'test.txt'), '123')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000771 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200772 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000773
774 copied = []
775 def _copy(src, dst):
776 copied.append((src, dst))
777
778 shutil.copytree(src_dir, dst_dir, copy_function=_copy)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000779 self.assertEqual(len(copied), 2)
Tarek Ziadé5340db32010-04-19 22:30:51 +0000780
Brian Curtin3b4499c2010-12-28 14:31:47 +0000781 @support.skip_unless_symlink
Tarek Ziadéfb437512010-04-20 08:57:33 +0000782 def test_copytree_dangling_symlinks(self):
783
784 # a dangling symlink raises an error at the end
785 src_dir = self.mkdtemp()
786 dst_dir = os.path.join(self.mkdtemp(), 'destination')
787 os.symlink('IDONTEXIST', os.path.join(src_dir, 'test.txt'))
788 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200789 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadéfb437512010-04-20 08:57:33 +0000790 self.assertRaises(Error, shutil.copytree, src_dir, dst_dir)
791
792 # a dangling symlink is ignored with the proper flag
793 dst_dir = os.path.join(self.mkdtemp(), 'destination2')
794 shutil.copytree(src_dir, dst_dir, ignore_dangling_symlinks=True)
795 self.assertNotIn('test.txt', os.listdir(dst_dir))
796
797 # a dangling symlink is copied if symlinks=True
798 dst_dir = os.path.join(self.mkdtemp(), 'destination3')
799 shutil.copytree(src_dir, dst_dir, symlinks=True)
800 self.assertIn('test.txt', os.listdir(dst_dir))
801
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400802 def _copy_file(self, method):
803 fname = 'test.txt'
804 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200805 write_file((tmpdir, fname), 'xxx')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400806 file1 = os.path.join(tmpdir, fname)
807 tmpdir2 = self.mkdtemp()
808 method(file1, tmpdir2)
809 file2 = os.path.join(tmpdir2, fname)
810 return (file1, file2)
811
812 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
813 def test_copy(self):
814 # Ensure that the copied file exists and has the same mode bits.
815 file1, file2 = self._copy_file(shutil.copy)
816 self.assertTrue(os.path.exists(file2))
817 self.assertEqual(os.stat(file1).st_mode, os.stat(file2).st_mode)
818
819 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
Senthil Kumaran0c2dba52011-07-03 18:21:38 -0700820 @unittest.skipUnless(hasattr(os, 'utime'), 'requires os.utime')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400821 def test_copy2(self):
822 # Ensure that the copied file exists and has the same mode and
823 # modification time bits.
824 file1, file2 = self._copy_file(shutil.copy2)
825 self.assertTrue(os.path.exists(file2))
826 file1_stat = os.stat(file1)
827 file2_stat = os.stat(file2)
828 self.assertEqual(file1_stat.st_mode, file2_stat.st_mode)
829 for attr in 'st_atime', 'st_mtime':
830 # The modification times may be truncated in the new file.
831 self.assertLessEqual(getattr(file1_stat, attr),
832 getattr(file2_stat, attr) + 1)
833 if hasattr(os, 'chflags') and hasattr(file1_stat, 'st_flags'):
834 self.assertEqual(getattr(file1_stat, 'st_flags'),
835 getattr(file2_stat, 'st_flags'))
836
Ezio Melotti975077a2011-05-19 22:03:22 +0300837 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000838 def test_make_tarball(self):
839 # creating something to tar
840 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200841 write_file((tmpdir, 'file1'), 'xxx')
842 write_file((tmpdir, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000843 os.mkdir(os.path.join(tmpdir, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200844 write_file((tmpdir, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000845
846 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400847 # force shutil to create the directory
848 os.rmdir(tmpdir2)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000849 unittest.skipUnless(splitdrive(tmpdir)[0] == splitdrive(tmpdir2)[0],
850 "source and target should be on same drive")
851
852 base_name = os.path.join(tmpdir2, 'archive')
853
854 # working with relative paths to avoid tar warnings
855 old_dir = os.getcwd()
856 os.chdir(tmpdir)
857 try:
858 _make_tarball(splitdrive(base_name)[1], '.')
859 finally:
860 os.chdir(old_dir)
861
862 # check if the compressed tarball was created
863 tarball = base_name + '.tar.gz'
864 self.assertTrue(os.path.exists(tarball))
865
866 # trying an uncompressed one
867 base_name = os.path.join(tmpdir2, 'archive')
868 old_dir = os.getcwd()
869 os.chdir(tmpdir)
870 try:
871 _make_tarball(splitdrive(base_name)[1], '.', compress=None)
872 finally:
873 os.chdir(old_dir)
874 tarball = base_name + '.tar'
875 self.assertTrue(os.path.exists(tarball))
876
877 def _tarinfo(self, path):
878 tar = tarfile.open(path)
879 try:
880 names = tar.getnames()
881 names.sort()
882 return tuple(names)
883 finally:
884 tar.close()
885
886 def _create_files(self):
887 # creating something to tar
888 tmpdir = self.mkdtemp()
889 dist = os.path.join(tmpdir, 'dist')
890 os.mkdir(dist)
Éric Araujoa7e33a12011-08-12 19:51:35 +0200891 write_file((dist, 'file1'), 'xxx')
892 write_file((dist, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000893 os.mkdir(os.path.join(dist, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200894 write_file((dist, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000895 os.mkdir(os.path.join(dist, 'sub2'))
896 tmpdir2 = self.mkdtemp()
897 base_name = os.path.join(tmpdir2, 'archive')
898 return tmpdir, tmpdir2, base_name
899
Ezio Melotti975077a2011-05-19 22:03:22 +0300900 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000901 @unittest.skipUnless(find_executable('tar') and find_executable('gzip'),
902 'Need the tar command to run')
903 def test_tarfile_vs_tar(self):
904 tmpdir, tmpdir2, base_name = self._create_files()
905 old_dir = os.getcwd()
906 os.chdir(tmpdir)
907 try:
908 _make_tarball(base_name, 'dist')
909 finally:
910 os.chdir(old_dir)
911
912 # check if the compressed tarball was created
913 tarball = base_name + '.tar.gz'
914 self.assertTrue(os.path.exists(tarball))
915
916 # now create another tarball using `tar`
917 tarball2 = os.path.join(tmpdir, 'archive2.tar.gz')
918 tar_cmd = ['tar', '-cf', 'archive2.tar', 'dist']
919 gzip_cmd = ['gzip', '-f9', 'archive2.tar']
920 old_dir = os.getcwd()
921 os.chdir(tmpdir)
922 try:
923 with captured_stdout() as s:
924 spawn(tar_cmd)
925 spawn(gzip_cmd)
926 finally:
927 os.chdir(old_dir)
928
929 self.assertTrue(os.path.exists(tarball2))
930 # let's compare both tarballs
Ezio Melottib3aedd42010-11-20 19:04:17 +0000931 self.assertEqual(self._tarinfo(tarball), self._tarinfo(tarball2))
Tarek Ziadé396fad72010-02-23 05:30:31 +0000932
933 # trying an uncompressed one
934 base_name = os.path.join(tmpdir2, 'archive')
935 old_dir = os.getcwd()
936 os.chdir(tmpdir)
937 try:
938 _make_tarball(base_name, 'dist', compress=None)
939 finally:
940 os.chdir(old_dir)
941 tarball = base_name + '.tar'
942 self.assertTrue(os.path.exists(tarball))
943
944 # now for a dry_run
945 base_name = os.path.join(tmpdir2, 'archive')
946 old_dir = os.getcwd()
947 os.chdir(tmpdir)
948 try:
949 _make_tarball(base_name, 'dist', compress=None, dry_run=True)
950 finally:
951 os.chdir(old_dir)
952 tarball = base_name + '.tar'
953 self.assertTrue(os.path.exists(tarball))
954
Ezio Melotti975077a2011-05-19 22:03:22 +0300955 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000956 @unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run')
957 def test_make_zipfile(self):
958 # creating something to tar
959 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200960 write_file((tmpdir, 'file1'), 'xxx')
961 write_file((tmpdir, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000962
963 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400964 # force shutil to create the directory
965 os.rmdir(tmpdir2)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000966 base_name = os.path.join(tmpdir2, 'archive')
967 _make_zipfile(base_name, tmpdir)
968
969 # check if the compressed tarball was created
970 tarball = base_name + '.zip'
Éric Araujo1c505492010-11-06 02:12:51 +0000971 self.assertTrue(os.path.exists(tarball))
Tarek Ziadé396fad72010-02-23 05:30:31 +0000972
973
974 def test_make_archive(self):
975 tmpdir = self.mkdtemp()
976 base_name = os.path.join(tmpdir, 'archive')
977 self.assertRaises(ValueError, make_archive, base_name, 'xxx')
978
Ezio Melotti975077a2011-05-19 22:03:22 +0300979 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000980 def test_make_archive_owner_group(self):
981 # testing make_archive with owner and group, with various combinations
982 # this works even if there's not gid/uid support
983 if UID_GID_SUPPORT:
984 group = grp.getgrgid(0)[0]
985 owner = pwd.getpwuid(0)[0]
986 else:
987 group = owner = 'root'
988
989 base_dir, root_dir, base_name = self._create_files()
990 base_name = os.path.join(self.mkdtemp() , 'archive')
991 res = make_archive(base_name, 'zip', root_dir, base_dir, owner=owner,
992 group=group)
993 self.assertTrue(os.path.exists(res))
994
995 res = make_archive(base_name, 'zip', root_dir, base_dir)
996 self.assertTrue(os.path.exists(res))
997
998 res = make_archive(base_name, 'tar', root_dir, base_dir,
999 owner=owner, group=group)
1000 self.assertTrue(os.path.exists(res))
1001
1002 res = make_archive(base_name, 'tar', root_dir, base_dir,
1003 owner='kjhkjhkjg', group='oihohoh')
1004 self.assertTrue(os.path.exists(res))
1005
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001006
Ezio Melotti975077a2011-05-19 22:03:22 +03001007 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001008 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1009 def test_tarfile_root_owner(self):
1010 tmpdir, tmpdir2, base_name = self._create_files()
1011 old_dir = os.getcwd()
1012 os.chdir(tmpdir)
1013 group = grp.getgrgid(0)[0]
1014 owner = pwd.getpwuid(0)[0]
1015 try:
1016 archive_name = _make_tarball(base_name, 'dist', compress=None,
1017 owner=owner, group=group)
1018 finally:
1019 os.chdir(old_dir)
1020
1021 # check if the compressed tarball was created
1022 self.assertTrue(os.path.exists(archive_name))
1023
1024 # now checks the rights
1025 archive = tarfile.open(archive_name)
1026 try:
1027 for member in archive.getmembers():
Ezio Melottib3aedd42010-11-20 19:04:17 +00001028 self.assertEqual(member.uid, 0)
1029 self.assertEqual(member.gid, 0)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001030 finally:
1031 archive.close()
1032
1033 def test_make_archive_cwd(self):
1034 current_dir = os.getcwd()
1035 def _breaks(*args, **kw):
1036 raise RuntimeError()
1037
1038 register_archive_format('xxx', _breaks, [], 'xxx file')
1039 try:
1040 try:
1041 make_archive('xxx', 'xxx', root_dir=self.mkdtemp())
1042 except Exception:
1043 pass
Ezio Melottib3aedd42010-11-20 19:04:17 +00001044 self.assertEqual(os.getcwd(), current_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001045 finally:
1046 unregister_archive_format('xxx')
1047
1048 def test_register_archive_format(self):
1049
1050 self.assertRaises(TypeError, register_archive_format, 'xxx', 1)
1051 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1052 1)
1053 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1054 [(1, 2), (1, 2, 3)])
1055
1056 register_archive_format('xxx', lambda: x, [(1, 2)], 'xxx file')
1057 formats = [name for name, params in get_archive_formats()]
1058 self.assertIn('xxx', formats)
1059
1060 unregister_archive_format('xxx')
1061 formats = [name for name, params in get_archive_formats()]
1062 self.assertNotIn('xxx', formats)
1063
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001064 def _compare_dirs(self, dir1, dir2):
1065 # check that dir1 and dir2 are equivalent,
1066 # return the diff
1067 diff = []
1068 for root, dirs, files in os.walk(dir1):
1069 for file_ in files:
1070 path = os.path.join(root, file_)
1071 target_path = os.path.join(dir2, os.path.split(path)[-1])
1072 if not os.path.exists(target_path):
1073 diff.append(file_)
1074 return diff
1075
Ezio Melotti975077a2011-05-19 22:03:22 +03001076 @requires_zlib
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001077 def test_unpack_archive(self):
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001078 formats = ['tar', 'gztar', 'zip']
1079 if BZ2_SUPPORTED:
1080 formats.append('bztar')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001081
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001082 for format in formats:
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001083 tmpdir = self.mkdtemp()
1084 base_dir, root_dir, base_name = self._create_files()
1085 tmpdir2 = self.mkdtemp()
1086 filename = make_archive(base_name, format, root_dir, base_dir)
1087
1088 # let's try to unpack it now
1089 unpack_archive(filename, tmpdir2)
1090 diff = self._compare_dirs(tmpdir, tmpdir2)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001091 self.assertEqual(diff, [])
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001092
Nick Coghlanabf202d2011-03-16 13:52:20 -04001093 # and again, this time with the format specified
1094 tmpdir3 = self.mkdtemp()
1095 unpack_archive(filename, tmpdir3, format=format)
1096 diff = self._compare_dirs(tmpdir, tmpdir3)
1097 self.assertEqual(diff, [])
1098 self.assertRaises(shutil.ReadError, unpack_archive, TESTFN)
1099 self.assertRaises(ValueError, unpack_archive, TESTFN, format='xxx')
1100
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001101 def test_unpack_registery(self):
1102
1103 formats = get_unpack_formats()
1104
1105 def _boo(filename, extract_dir, extra):
Ezio Melottib3aedd42010-11-20 19:04:17 +00001106 self.assertEqual(extra, 1)
1107 self.assertEqual(filename, 'stuff.boo')
1108 self.assertEqual(extract_dir, 'xx')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001109
1110 register_unpack_format('Boo', ['.boo', '.b2'], _boo, [('extra', 1)])
1111 unpack_archive('stuff.boo', 'xx')
1112
1113 # trying to register a .boo unpacker again
1114 self.assertRaises(RegistryError, register_unpack_format, 'Boo2',
1115 ['.boo'], _boo)
1116
1117 # should work now
1118 unregister_unpack_format('Boo')
1119 register_unpack_format('Boo2', ['.boo'], _boo)
1120 self.assertIn(('Boo2', ['.boo'], ''), get_unpack_formats())
1121 self.assertNotIn(('Boo', ['.boo'], ''), get_unpack_formats())
1122
1123 # let's leave a clean state
1124 unregister_unpack_format('Boo2')
Ezio Melottib3aedd42010-11-20 19:04:17 +00001125 self.assertEqual(get_unpack_formats(), formats)
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001126
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001127 @unittest.skipUnless(hasattr(shutil, 'disk_usage'),
1128 "disk_usage not available on this platform")
1129 def test_disk_usage(self):
1130 usage = shutil.disk_usage(os.getcwd())
Éric Araujo2ee61882011-07-02 16:45:45 +02001131 self.assertGreater(usage.total, 0)
1132 self.assertGreater(usage.used, 0)
1133 self.assertGreaterEqual(usage.free, 0)
1134 self.assertGreaterEqual(usage.total, usage.used)
1135 self.assertGreater(usage.total, usage.free)
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001136
Sandro Tosid902a142011-08-22 23:28:27 +02001137 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1138 @unittest.skipUnless(hasattr(os, 'chown'), 'requires os.chown')
1139 def test_chown(self):
1140
1141 # cleaned-up automatically by TestShutil.tearDown method
1142 dirname = self.mkdtemp()
1143 filename = tempfile.mktemp(dir=dirname)
1144 write_file(filename, 'testing chown function')
1145
1146 with self.assertRaises(ValueError):
1147 shutil.chown(filename)
1148
1149 with self.assertRaises(LookupError):
1150 shutil.chown(filename, user='non-exising username')
1151
1152 with self.assertRaises(LookupError):
1153 shutil.chown(filename, group='non-exising groupname')
1154
1155 with self.assertRaises(TypeError):
1156 shutil.chown(filename, b'spam')
1157
1158 with self.assertRaises(TypeError):
1159 shutil.chown(filename, 3.14)
1160
1161 uid = os.getuid()
1162 gid = os.getgid()
1163
1164 def check_chown(path, uid=None, gid=None):
1165 s = os.stat(filename)
1166 if uid is not None:
1167 self.assertEqual(uid, s.st_uid)
1168 if gid is not None:
1169 self.assertEqual(gid, s.st_gid)
1170
1171 shutil.chown(filename, uid, gid)
1172 check_chown(filename, uid, gid)
1173 shutil.chown(filename, uid)
1174 check_chown(filename, uid)
1175 shutil.chown(filename, user=uid)
1176 check_chown(filename, uid)
1177 shutil.chown(filename, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001178 check_chown(filename, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001179
1180 shutil.chown(dirname, uid, gid)
1181 check_chown(dirname, uid, gid)
1182 shutil.chown(dirname, uid)
1183 check_chown(dirname, uid)
1184 shutil.chown(dirname, user=uid)
1185 check_chown(dirname, uid)
1186 shutil.chown(dirname, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001187 check_chown(dirname, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001188
1189 user = pwd.getpwuid(uid)[0]
1190 group = grp.getgrgid(gid)[0]
1191 shutil.chown(filename, user, group)
1192 check_chown(filename, uid, gid)
1193 shutil.chown(dirname, user, group)
1194 check_chown(dirname, uid, gid)
1195
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001196 def test_copy_return_value(self):
1197 # copy and copy2 both return their destination path.
1198 for fn in (shutil.copy, shutil.copy2):
1199 src_dir = self.mkdtemp()
1200 dst_dir = self.mkdtemp()
1201 src = os.path.join(src_dir, 'foo')
1202 write_file(src, 'foo')
1203 rv = fn(src, dst_dir)
1204 self.assertEqual(rv, os.path.join(dst_dir, 'foo'))
1205 rv = fn(src, os.path.join(dst_dir, 'bar'))
1206 self.assertEqual(rv, os.path.join(dst_dir, 'bar'))
1207
1208 def test_copyfile_return_value(self):
1209 # copytree returns its destination path.
1210 src_dir = self.mkdtemp()
1211 dst_dir = self.mkdtemp()
1212 dst_file = os.path.join(dst_dir, 'bar')
1213 src_file = os.path.join(src_dir, 'foo')
1214 write_file(src_file, 'foo')
1215 rv = shutil.copyfile(src_file, dst_file)
1216 self.assertTrue(os.path.exists(rv))
1217 self.assertEqual(read_file(src_file), read_file(dst_file))
1218
Hynek Schlawack48653762012-10-07 12:49:58 +02001219 def test_copyfile_same_file(self):
1220 # copyfile() should raise SameFileError if the source and destination
1221 # are the same.
1222 src_dir = self.mkdtemp()
1223 src_file = os.path.join(src_dir, 'foo')
1224 write_file(src_file, 'foo')
1225 self.assertRaises(SameFileError, shutil.copyfile, src_file, src_file)
1226
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001227 def test_copytree_return_value(self):
1228 # copytree returns its destination path.
1229 src_dir = self.mkdtemp()
1230 dst_dir = src_dir + "dest"
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001231 self.addCleanup(shutil.rmtree, dst_dir, True)
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001232 src = os.path.join(src_dir, 'foo')
1233 write_file(src, 'foo')
1234 rv = shutil.copytree(src_dir, dst_dir)
1235 self.assertEqual(['foo'], os.listdir(rv))
1236
Christian Heimes9bd667a2008-01-20 15:14:11 +00001237
Brian Curtinc57a3452012-06-22 16:00:30 -05001238class TestWhich(unittest.TestCase):
1239
1240 def setUp(self):
1241 self.temp_dir = tempfile.mkdtemp()
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001242 self.addCleanup(shutil.rmtree, self.temp_dir, True)
Brian Curtinc57a3452012-06-22 16:00:30 -05001243 # Give the temp_file an ".exe" suffix for all.
1244 # It's needed on Windows and not harmful on other platforms.
1245 self.temp_file = tempfile.NamedTemporaryFile(dir=self.temp_dir,
1246 suffix=".exe")
1247 os.chmod(self.temp_file.name, stat.S_IXUSR)
1248 self.addCleanup(self.temp_file.close)
1249 self.dir, self.file = os.path.split(self.temp_file.name)
1250
1251 def test_basic(self):
1252 # Given an EXE in a directory, it should be returned.
1253 rv = shutil.which(self.file, path=self.dir)
1254 self.assertEqual(rv, self.temp_file.name)
1255
1256 def test_full_path_short_circuit(self):
1257 # When given the fully qualified path to an executable that exists,
1258 # it should be returned.
1259 rv = shutil.which(self.temp_file.name, path=self.temp_dir)
1260 self.assertEqual(self.temp_file.name, rv)
1261
1262 def test_non_matching_mode(self):
1263 # Set the file read-only and ask for writeable files.
1264 os.chmod(self.temp_file.name, stat.S_IREAD)
1265 rv = shutil.which(self.file, path=self.dir, mode=os.W_OK)
1266 self.assertIsNone(rv)
1267
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001268 def test_relative(self):
1269 old_cwd = os.getcwd()
1270 base_dir, tail_dir = os.path.split(self.dir)
1271 os.chdir(base_dir)
1272 try:
1273 rv = shutil.which(self.file, path=tail_dir)
1274 self.assertEqual(rv, os.path.join(tail_dir, self.file))
1275 finally:
1276 os.chdir(old_cwd)
1277
Brian Curtinc57a3452012-06-22 16:00:30 -05001278 def test_nonexistent_file(self):
1279 # Return None when no matching executable file is found on the path.
1280 rv = shutil.which("foo.exe", path=self.dir)
1281 self.assertIsNone(rv)
1282
1283 @unittest.skipUnless(sys.platform == "win32",
1284 "pathext check is Windows-only")
1285 def test_pathext_checking(self):
1286 # Ask for the file without the ".exe" extension, then ensure that
1287 # it gets found properly with the extension.
1288 rv = shutil.which(self.temp_file.name[:-4], path=self.dir)
1289 self.assertEqual(self.temp_file.name, rv)
1290
1291
Christian Heimesada8c3b2008-03-18 18:26:33 +00001292class TestMove(unittest.TestCase):
1293
1294 def setUp(self):
1295 filename = "foo"
1296 self.src_dir = tempfile.mkdtemp()
1297 self.dst_dir = tempfile.mkdtemp()
1298 self.src_file = os.path.join(self.src_dir, filename)
1299 self.dst_file = os.path.join(self.dst_dir, filename)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001300 with open(self.src_file, "wb") as f:
1301 f.write(b"spam")
1302
1303 def tearDown(self):
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001304 for d in (self.src_dir, self.dst_dir):
Christian Heimesada8c3b2008-03-18 18:26:33 +00001305 try:
1306 if d:
1307 shutil.rmtree(d)
1308 except:
1309 pass
1310
1311 def _check_move_file(self, src, dst, real_dst):
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001312 with open(src, "rb") as f:
1313 contents = f.read()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001314 shutil.move(src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001315 with open(real_dst, "rb") as f:
1316 self.assertEqual(contents, f.read())
Christian Heimesada8c3b2008-03-18 18:26:33 +00001317 self.assertFalse(os.path.exists(src))
1318
1319 def _check_move_dir(self, src, dst, real_dst):
1320 contents = sorted(os.listdir(src))
1321 shutil.move(src, dst)
1322 self.assertEqual(contents, sorted(os.listdir(real_dst)))
1323 self.assertFalse(os.path.exists(src))
1324
1325 def test_move_file(self):
1326 # Move a file to another location on the same filesystem.
1327 self._check_move_file(self.src_file, self.dst_file, self.dst_file)
1328
1329 def test_move_file_to_dir(self):
1330 # Move a file inside an existing dir on the same filesystem.
1331 self._check_move_file(self.src_file, self.dst_dir, self.dst_file)
1332
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001333 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001334 def test_move_file_other_fs(self):
1335 # Move a file to an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001336 self.test_move_file()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001337
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001338 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001339 def test_move_file_to_dir_other_fs(self):
1340 # Move a file to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001341 self.test_move_file_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001342
1343 def test_move_dir(self):
1344 # Move a dir to another location on the same filesystem.
1345 dst_dir = tempfile.mktemp()
1346 try:
1347 self._check_move_dir(self.src_dir, dst_dir, dst_dir)
1348 finally:
1349 try:
1350 shutil.rmtree(dst_dir)
1351 except:
1352 pass
1353
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001354 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001355 def test_move_dir_other_fs(self):
1356 # Move a dir to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001357 self.test_move_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001358
1359 def test_move_dir_to_dir(self):
1360 # Move a dir inside an existing dir on the same filesystem.
1361 self._check_move_dir(self.src_dir, self.dst_dir,
1362 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1363
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001364 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001365 def test_move_dir_to_dir_other_fs(self):
1366 # Move a dir inside an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001367 self.test_move_dir_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001368
1369 def test_existing_file_inside_dest_dir(self):
1370 # A file with the same name inside the destination dir already exists.
1371 with open(self.dst_file, "wb"):
1372 pass
1373 self.assertRaises(shutil.Error, shutil.move, self.src_file, self.dst_dir)
1374
1375 def test_dont_move_dir_in_itself(self):
1376 # Moving a dir inside itself raises an Error.
1377 dst = os.path.join(self.src_dir, "bar")
1378 self.assertRaises(shutil.Error, shutil.move, self.src_dir, dst)
1379
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001380 def test_destinsrc_false_negative(self):
1381 os.mkdir(TESTFN)
1382 try:
1383 for src, dst in [('srcdir', 'srcdir/dest')]:
1384 src = os.path.join(TESTFN, src)
1385 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001386 self.assertTrue(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001387 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001388 'dst (%s) is not in src (%s)' % (dst, src))
1389 finally:
1390 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001391
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001392 def test_destinsrc_false_positive(self):
1393 os.mkdir(TESTFN)
1394 try:
1395 for src, dst in [('srcdir', 'src/dest'), ('srcdir', 'srcdir.new')]:
1396 src = os.path.join(TESTFN, src)
1397 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001398 self.assertFalse(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001399 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001400 'dst (%s) is in src (%s)' % (dst, src))
1401 finally:
1402 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimes9bd667a2008-01-20 15:14:11 +00001403
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +01001404 @support.skip_unless_symlink
1405 @mock_rename
1406 def test_move_file_symlink(self):
1407 dst = os.path.join(self.src_dir, 'bar')
1408 os.symlink(self.src_file, dst)
1409 shutil.move(dst, self.dst_file)
1410 self.assertTrue(os.path.islink(self.dst_file))
1411 self.assertTrue(os.path.samefile(self.src_file, self.dst_file))
1412
1413 @support.skip_unless_symlink
1414 @mock_rename
1415 def test_move_file_symlink_to_dir(self):
1416 filename = "bar"
1417 dst = os.path.join(self.src_dir, filename)
1418 os.symlink(self.src_file, dst)
1419 shutil.move(dst, self.dst_dir)
1420 final_link = os.path.join(self.dst_dir, filename)
1421 self.assertTrue(os.path.islink(final_link))
1422 self.assertTrue(os.path.samefile(self.src_file, final_link))
1423
1424 @support.skip_unless_symlink
1425 @mock_rename
1426 def test_move_dangling_symlink(self):
1427 src = os.path.join(self.src_dir, 'baz')
1428 dst = os.path.join(self.src_dir, 'bar')
1429 os.symlink(src, dst)
1430 dst_link = os.path.join(self.dst_dir, 'quux')
1431 shutil.move(dst, dst_link)
1432 self.assertTrue(os.path.islink(dst_link))
1433 self.assertEqual(os.path.realpath(src), os.path.realpath(dst_link))
1434
1435 @support.skip_unless_symlink
1436 @mock_rename
1437 def test_move_dir_symlink(self):
1438 src = os.path.join(self.src_dir, 'baz')
1439 dst = os.path.join(self.src_dir, 'bar')
1440 os.mkdir(src)
1441 os.symlink(src, dst)
1442 dst_link = os.path.join(self.dst_dir, 'quux')
1443 shutil.move(dst, dst_link)
1444 self.assertTrue(os.path.islink(dst_link))
1445 self.assertTrue(os.path.samefile(src, dst_link))
1446
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001447 def test_move_return_value(self):
1448 rv = shutil.move(self.src_file, self.dst_dir)
1449 self.assertEqual(rv,
1450 os.path.join(self.dst_dir, os.path.basename(self.src_file)))
1451
1452 def test_move_as_rename_return_value(self):
1453 rv = shutil.move(self.src_file, os.path.join(self.dst_dir, 'bar'))
1454 self.assertEqual(rv, os.path.join(self.dst_dir, 'bar'))
1455
Tarek Ziadé5340db32010-04-19 22:30:51 +00001456
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001457class TestCopyFile(unittest.TestCase):
1458
1459 _delete = False
1460
1461 class Faux(object):
1462 _entered = False
1463 _exited_with = None
1464 _raised = False
1465 def __init__(self, raise_in_exit=False, suppress_at_exit=True):
1466 self._raise_in_exit = raise_in_exit
1467 self._suppress_at_exit = suppress_at_exit
1468 def read(self, *args):
1469 return ''
1470 def __enter__(self):
1471 self._entered = True
1472 def __exit__(self, exc_type, exc_val, exc_tb):
1473 self._exited_with = exc_type, exc_val, exc_tb
1474 if self._raise_in_exit:
1475 self._raised = True
1476 raise IOError("Cannot close")
1477 return self._suppress_at_exit
1478
1479 def tearDown(self):
1480 if self._delete:
1481 del shutil.open
1482
1483 def _set_shutil_open(self, func):
1484 shutil.open = func
1485 self._delete = True
1486
1487 def test_w_source_open_fails(self):
1488 def _open(filename, mode='r'):
1489 if filename == 'srcfile':
1490 raise IOError('Cannot open "srcfile"')
1491 assert 0 # shouldn't reach here.
1492
1493 self._set_shutil_open(_open)
1494
1495 self.assertRaises(IOError, shutil.copyfile, 'srcfile', 'destfile')
1496
1497 def test_w_dest_open_fails(self):
1498
1499 srcfile = self.Faux()
1500
1501 def _open(filename, mode='r'):
1502 if filename == 'srcfile':
1503 return srcfile
1504 if filename == 'destfile':
1505 raise IOError('Cannot open "destfile"')
1506 assert 0 # shouldn't reach here.
1507
1508 self._set_shutil_open(_open)
1509
1510 shutil.copyfile('srcfile', 'destfile')
1511 self.assertTrue(srcfile._entered)
1512 self.assertTrue(srcfile._exited_with[0] is IOError)
1513 self.assertEqual(srcfile._exited_with[1].args,
1514 ('Cannot open "destfile"',))
1515
1516 def test_w_dest_close_fails(self):
1517
1518 srcfile = self.Faux()
1519 destfile = self.Faux(True)
1520
1521 def _open(filename, mode='r'):
1522 if filename == 'srcfile':
1523 return srcfile
1524 if filename == 'destfile':
1525 return destfile
1526 assert 0 # shouldn't reach here.
1527
1528 self._set_shutil_open(_open)
1529
1530 shutil.copyfile('srcfile', 'destfile')
1531 self.assertTrue(srcfile._entered)
1532 self.assertTrue(destfile._entered)
1533 self.assertTrue(destfile._raised)
1534 self.assertTrue(srcfile._exited_with[0] is IOError)
1535 self.assertEqual(srcfile._exited_with[1].args,
1536 ('Cannot close',))
1537
1538 def test_w_source_close_fails(self):
1539
1540 srcfile = self.Faux(True)
1541 destfile = self.Faux()
1542
1543 def _open(filename, mode='r'):
1544 if filename == 'srcfile':
1545 return srcfile
1546 if filename == 'destfile':
1547 return destfile
1548 assert 0 # shouldn't reach here.
1549
1550 self._set_shutil_open(_open)
1551
1552 self.assertRaises(IOError,
1553 shutil.copyfile, 'srcfile', 'destfile')
1554 self.assertTrue(srcfile._entered)
1555 self.assertTrue(destfile._entered)
1556 self.assertFalse(destfile._raised)
1557 self.assertTrue(srcfile._exited_with[0] is None)
1558 self.assertTrue(srcfile._raised)
1559
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001560 def test_move_dir_caseinsensitive(self):
1561 # Renames a folder to the same name
1562 # but a different case.
1563
1564 self.src_dir = tempfile.mkdtemp()
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001565 self.addCleanup(shutil.rmtree, self.src_dir, True)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001566 dst_dir = os.path.join(
1567 os.path.dirname(self.src_dir),
1568 os.path.basename(self.src_dir).upper())
1569 self.assertNotEqual(self.src_dir, dst_dir)
1570
1571 try:
1572 shutil.move(self.src_dir, dst_dir)
1573 self.assertTrue(os.path.isdir(dst_dir))
1574 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +02001575 os.rmdir(dst_dir)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001576
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001577class TermsizeTests(unittest.TestCase):
1578 def test_does_not_crash(self):
1579 """Check if get_terminal_size() returns a meaningful value.
1580
1581 There's no easy portable way to actually check the size of the
1582 terminal, so let's check if it returns something sensible instead.
1583 """
1584 size = shutil.get_terminal_size()
Antoine Pitroucfade362012-02-08 23:48:59 +01001585 self.assertGreaterEqual(size.columns, 0)
1586 self.assertGreaterEqual(size.lines, 0)
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001587
1588 def test_os_environ_first(self):
1589 "Check if environment variables have precedence"
1590
1591 with support.EnvironmentVarGuard() as env:
1592 env['COLUMNS'] = '777'
1593 size = shutil.get_terminal_size()
1594 self.assertEqual(size.columns, 777)
1595
1596 with support.EnvironmentVarGuard() as env:
1597 env['LINES'] = '888'
1598 size = shutil.get_terminal_size()
1599 self.assertEqual(size.lines, 888)
1600
1601 @unittest.skipUnless(os.isatty(sys.__stdout__.fileno()), "not on tty")
1602 def test_stty_match(self):
1603 """Check if stty returns the same results ignoring env
1604
1605 This test will fail if stdin and stdout are connected to
1606 different terminals with different sizes. Nevertheless, such
1607 situations should be pretty rare.
1608 """
1609 try:
1610 size = subprocess.check_output(['stty', 'size']).decode().split()
1611 except (FileNotFoundError, subprocess.CalledProcessError):
1612 self.skipTest("stty invocation failed")
1613 expected = (int(size[1]), int(size[0])) # reversed order
1614
1615 with support.EnvironmentVarGuard() as env:
1616 del env['LINES']
1617 del env['COLUMNS']
1618 actual = shutil.get_terminal_size()
1619
1620 self.assertEqual(expected, actual)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001621
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001622
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001623def test_main():
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001624 support.run_unittest(TestShutil, TestMove, TestCopyFile,
Brian Curtinc57a3452012-06-22 16:00:30 -05001625 TermsizeTests, TestWhich)
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001626
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001627if __name__ == '__main__':
Walter Dörwald21d3a322003-05-01 17:45:56 +00001628 test_main()