blob: eb0e9a4ee7a8fd8c19d0f61d702049381f5c8475 [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 Schlawack26fe37d2012-07-19 21:41:02 +020021 unregister_unpack_format, get_unpack_formats)
Tarek Ziadé396fad72010-02-23 05:30:31 +000022import tarfile
23import warnings
24
25from test import support
Ezio Melotti975077a2011-05-19 22:03:22 +030026from test.support import TESTFN, check_warnings, captured_stdout, requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +000027
Tarek Ziadéffa155a2010-04-29 13:34:35 +000028try:
29 import bz2
30 BZ2_SUPPORTED = True
31except ImportError:
32 BZ2_SUPPORTED = False
33
Antoine Pitrou7fff0962009-05-01 21:09:44 +000034TESTFN2 = TESTFN + "2"
Barry Warsaw7fc2cca2003-01-24 17:34:13 +000035
Tarek Ziadé396fad72010-02-23 05:30:31 +000036try:
37 import grp
38 import pwd
39 UID_GID_SUPPORT = True
40except ImportError:
41 UID_GID_SUPPORT = False
42
43try:
Tarek Ziadé396fad72010-02-23 05:30:31 +000044 import zipfile
45 ZIP_SUPPORT = True
46except ImportError:
47 ZIP_SUPPORT = find_executable('zip')
48
Nick Coghlan8ed3cf32011-03-16 14:05:35 -040049def _fake_rename(*args, **kwargs):
50 # Pretend the destination path is on a different filesystem.
Antoine Pitrouc041ab62012-01-02 19:18:02 +010051 raise OSError(getattr(errno, 'EXDEV', 18), "Invalid cross-device link")
Nick Coghlan8ed3cf32011-03-16 14:05:35 -040052
53def mock_rename(func):
54 @functools.wraps(func)
55 def wrap(*args, **kwargs):
56 try:
57 builtin_rename = os.rename
58 os.rename = _fake_rename
59 return func(*args, **kwargs)
60 finally:
61 os.rename = builtin_rename
62 return wrap
63
Éric Araujoa7e33a12011-08-12 19:51:35 +020064def write_file(path, content, binary=False):
65 """Write *content* to a file located at *path*.
66
67 If *path* is a tuple instead of a string, os.path.join will be used to
68 make a path. If *binary* is true, the file will be opened in binary
69 mode.
70 """
71 if isinstance(path, tuple):
72 path = os.path.join(*path)
73 with open(path, 'wb' if binary else 'w') as fp:
74 fp.write(content)
75
76def read_file(path, binary=False):
77 """Return contents from a file located at *path*.
78
79 If *path* is a tuple instead of a string, os.path.join will be used to
80 make a path. If *binary* is true, the file will be opened in binary
81 mode.
82 """
83 if isinstance(path, tuple):
84 path = os.path.join(*path)
85 with open(path, 'rb' if binary else 'r') as fp:
86 return fp.read()
87
88
Barry Warsaw7fc2cca2003-01-24 17:34:13 +000089class TestShutil(unittest.TestCase):
Tarek Ziadé396fad72010-02-23 05:30:31 +000090
91 def setUp(self):
92 super(TestShutil, self).setUp()
93 self.tempdirs = []
94
95 def tearDown(self):
96 super(TestShutil, self).tearDown()
97 while self.tempdirs:
98 d = self.tempdirs.pop()
99 shutil.rmtree(d, os.name in ('nt', 'cygwin'))
100
Tarek Ziadé396fad72010-02-23 05:30:31 +0000101
102 def mkdtemp(self):
103 """Create a temporary directory that will be cleaned up.
104
105 Returns the path of the directory.
106 """
107 d = tempfile.mkdtemp()
108 self.tempdirs.append(d)
109 return d
Tarek Ziadé5340db32010-04-19 22:30:51 +0000110
Hynek Schlawack3b527782012-06-25 13:27:31 +0200111 def test_rmtree_works_on_bytes(self):
112 tmp = self.mkdtemp()
113 victim = os.path.join(tmp, 'killme')
114 os.mkdir(victim)
115 write_file(os.path.join(victim, 'somefile'), 'foo')
116 victim = os.fsencode(victim)
117 self.assertIsInstance(victim, bytes)
118 shutil.rmtree(victim)
119
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200120 @support.skip_unless_symlink
121 def test_rmtree_fails_on_symlink(self):
122 tmp = self.mkdtemp()
123 dir_ = os.path.join(tmp, 'dir')
124 os.mkdir(dir_)
125 link = os.path.join(tmp, 'link')
126 os.symlink(dir_, link)
127 self.assertRaises(OSError, shutil.rmtree, link)
128 self.assertTrue(os.path.exists(dir_))
129
130 @support.skip_unless_symlink
131 def test_rmtree_works_on_symlinks(self):
132 tmp = self.mkdtemp()
133 dir1 = os.path.join(tmp, 'dir1')
134 dir2 = os.path.join(dir1, 'dir2')
135 dir3 = os.path.join(tmp, 'dir3')
136 for d in dir1, dir2, dir3:
137 os.mkdir(d)
138 file1 = os.path.join(tmp, 'file1')
139 write_file(file1, 'foo')
140 link1 = os.path.join(dir1, 'link1')
141 os.symlink(dir2, link1)
142 link2 = os.path.join(dir1, 'link2')
143 os.symlink(dir3, link2)
144 link3 = os.path.join(dir1, 'link3')
145 os.symlink(file1, link3)
146 # make sure symlinks are removed but not followed
147 shutil.rmtree(dir1)
148 self.assertFalse(os.path.exists(dir1))
149 self.assertTrue(os.path.exists(dir3))
150 self.assertTrue(os.path.exists(file1))
151
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000152 def test_rmtree_errors(self):
153 # filename is guaranteed not to exist
154 filename = tempfile.mktemp()
155 self.assertRaises(OSError, shutil.rmtree, filename)
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000156
Johannes Gijsbersb8b09d02004-12-06 20:50:15 +0000157 # See bug #1071513 for why we don't run this on cygwin
158 # and bug #1076467 for why we don't run this as root.
159 if (hasattr(os, 'chmod') and sys.platform[:6] != 'cygwin'
Johannes Gijsbers6b220b02004-12-12 15:52:57 +0000160 and not (hasattr(os, 'geteuid') and os.geteuid() == 0)):
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000161 def test_on_error(self):
162 self.errorState = 0
163 os.mkdir(TESTFN)
Antoine Pitrou2f8a75c2012-06-23 21:28:15 +0200164 self.addCleanup(shutil.rmtree, TESTFN)
165
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200166 self.child_file_path = os.path.join(TESTFN, 'a')
167 self.child_dir_path = os.path.join(TESTFN, 'b')
168 support.create_empty_file(self.child_file_path)
169 os.mkdir(self.child_dir_path)
Tim Peters4590c002004-11-01 02:40:52 +0000170 old_dir_mode = os.stat(TESTFN).st_mode
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200171 old_child_file_mode = os.stat(self.child_file_path).st_mode
172 old_child_dir_mode = os.stat(self.child_dir_path).st_mode
Tim Peters4590c002004-11-01 02:40:52 +0000173 # Make unwritable.
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200174 new_mode = stat.S_IREAD|stat.S_IEXEC
175 os.chmod(self.child_file_path, new_mode)
176 os.chmod(self.child_dir_path, new_mode)
177 os.chmod(TESTFN, new_mode)
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000178
Antoine Pitrou2f8a75c2012-06-23 21:28:15 +0200179 self.addCleanup(os.chmod, TESTFN, old_dir_mode)
180 self.addCleanup(os.chmod, self.child_file_path, old_child_file_mode)
181 self.addCleanup(os.chmod, self.child_dir_path, old_child_dir_mode)
182
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000183 shutil.rmtree(TESTFN, onerror=self.check_args_to_onerror)
Johannes Gijsbers8e6f2de2004-11-23 09:27:27 +0000184 # Test whether onerror has actually been called.
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200185 self.assertEqual(self.errorState, 3,
186 "Expected call to onerror function did not "
187 "happen.")
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000188
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000189 def check_args_to_onerror(self, func, arg, exc):
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000190 # test_rmtree_errors deliberately runs rmtree
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200191 # on a directory that is chmod 500, which will fail.
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000192 # This function is run when shutil.rmtree fails.
193 # 99.9% of the time it initially fails to remove
194 # a file in the directory, so the first time through
195 # func is os.remove.
196 # However, some Linux machines running ZFS on
197 # FUSE experienced a failure earlier in the process
198 # at os.listdir. The first failure may legally
199 # be either.
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200200 if self.errorState < 2:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200201 if func is os.unlink:
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200202 self.assertEqual(arg, self.child_file_path)
203 elif func is os.rmdir:
204 self.assertEqual(arg, self.child_dir_path)
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000205 else:
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200206 self.assertIs(func, os.listdir)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200207 self.assertIn(arg, [TESTFN, self.child_dir_path])
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000208 self.assertTrue(issubclass(exc[0], OSError))
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200209 self.errorState += 1
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000210 else:
211 self.assertEqual(func, os.rmdir)
212 self.assertEqual(arg, TESTFN)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000213 self.assertTrue(issubclass(exc[0], OSError))
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200214 self.errorState = 3
215
216 def test_rmtree_does_not_choke_on_failing_lstat(self):
217 try:
218 orig_lstat = os.lstat
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200219 def raiser(fn, *args, **kwargs):
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200220 if fn != TESTFN:
221 raise OSError()
222 else:
223 return orig_lstat(fn)
224 os.lstat = raiser
225
226 os.mkdir(TESTFN)
227 write_file((TESTFN, 'foo'), 'foo')
228 shutil.rmtree(TESTFN)
229 finally:
230 os.lstat = orig_lstat
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000231
Antoine Pitrou78091e62011-12-29 18:54:15 +0100232 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
233 @support.skip_unless_symlink
234 def test_copymode_follow_symlinks(self):
235 tmp_dir = self.mkdtemp()
236 src = os.path.join(tmp_dir, 'foo')
237 dst = os.path.join(tmp_dir, 'bar')
238 src_link = os.path.join(tmp_dir, 'baz')
239 dst_link = os.path.join(tmp_dir, 'quux')
240 write_file(src, 'foo')
241 write_file(dst, 'foo')
242 os.symlink(src, src_link)
243 os.symlink(dst, dst_link)
244 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
245 # file to file
246 os.chmod(dst, stat.S_IRWXO)
247 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
248 shutil.copymode(src, dst)
249 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
250 # follow src link
251 os.chmod(dst, stat.S_IRWXO)
252 shutil.copymode(src_link, dst)
253 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
254 # follow dst link
255 os.chmod(dst, stat.S_IRWXO)
256 shutil.copymode(src, dst_link)
257 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
258 # follow both links
259 os.chmod(dst, stat.S_IRWXO)
260 shutil.copymode(src_link, dst)
261 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
262
263 @unittest.skipUnless(hasattr(os, 'lchmod'), 'requires os.lchmod')
264 @support.skip_unless_symlink
265 def test_copymode_symlink_to_symlink(self):
266 tmp_dir = self.mkdtemp()
267 src = os.path.join(tmp_dir, 'foo')
268 dst = os.path.join(tmp_dir, 'bar')
269 src_link = os.path.join(tmp_dir, 'baz')
270 dst_link = os.path.join(tmp_dir, 'quux')
271 write_file(src, 'foo')
272 write_file(dst, 'foo')
273 os.symlink(src, src_link)
274 os.symlink(dst, dst_link)
275 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
276 os.chmod(dst, stat.S_IRWXU)
277 os.lchmod(src_link, stat.S_IRWXO|stat.S_IRWXG)
278 # link to link
279 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700280 shutil.copymode(src_link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100281 self.assertEqual(os.lstat(src_link).st_mode,
282 os.lstat(dst_link).st_mode)
283 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
284 # src link - use chmod
285 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700286 shutil.copymode(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100287 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
288 # dst link - use chmod
289 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700290 shutil.copymode(src, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100291 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
292
293 @unittest.skipIf(hasattr(os, 'lchmod'), 'requires os.lchmod to be missing')
294 @support.skip_unless_symlink
295 def test_copymode_symlink_to_symlink_wo_lchmod(self):
296 tmp_dir = self.mkdtemp()
297 src = os.path.join(tmp_dir, 'foo')
298 dst = os.path.join(tmp_dir, 'bar')
299 src_link = os.path.join(tmp_dir, 'baz')
300 dst_link = os.path.join(tmp_dir, 'quux')
301 write_file(src, 'foo')
302 write_file(dst, 'foo')
303 os.symlink(src, src_link)
304 os.symlink(dst, dst_link)
Larry Hastingsb4038062012-07-15 10:57:38 -0700305 shutil.copymode(src_link, dst_link, follow_symlinks=False) # silent fail
Antoine Pitrou78091e62011-12-29 18:54:15 +0100306
307 @support.skip_unless_symlink
308 def test_copystat_symlinks(self):
309 tmp_dir = self.mkdtemp()
310 src = os.path.join(tmp_dir, 'foo')
311 dst = os.path.join(tmp_dir, 'bar')
312 src_link = os.path.join(tmp_dir, 'baz')
313 dst_link = os.path.join(tmp_dir, 'qux')
314 write_file(src, 'foo')
315 src_stat = os.stat(src)
316 os.utime(src, (src_stat.st_atime,
317 src_stat.st_mtime - 42.0)) # ensure different mtimes
318 write_file(dst, 'bar')
319 self.assertNotEqual(os.stat(src).st_mtime, os.stat(dst).st_mtime)
320 os.symlink(src, src_link)
321 os.symlink(dst, dst_link)
322 if hasattr(os, 'lchmod'):
323 os.lchmod(src_link, stat.S_IRWXO)
324 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
325 os.lchflags(src_link, stat.UF_NODUMP)
326 src_link_stat = os.lstat(src_link)
327 # follow
328 if hasattr(os, 'lchmod'):
Larry Hastingsb4038062012-07-15 10:57:38 -0700329 shutil.copystat(src_link, dst_link, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100330 self.assertNotEqual(src_link_stat.st_mode, os.stat(dst).st_mode)
331 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700332 shutil.copystat(src_link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100333 dst_link_stat = os.lstat(dst_link)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700334 if os.utime in os.supports_follow_symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100335 for attr in 'st_atime', 'st_mtime':
336 # The modification times may be truncated in the new file.
337 self.assertLessEqual(getattr(src_link_stat, attr),
338 getattr(dst_link_stat, attr) + 1)
339 if hasattr(os, 'lchmod'):
340 self.assertEqual(src_link_stat.st_mode, dst_link_stat.st_mode)
341 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
342 self.assertEqual(src_link_stat.st_flags, dst_link_stat.st_flags)
343 # tell to follow but dst is not a link
Larry Hastingsb4038062012-07-15 10:57:38 -0700344 shutil.copystat(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100345 self.assertTrue(abs(os.stat(src).st_mtime - os.stat(dst).st_mtime) <
346 00000.1)
347
Ned Deilybaf75712012-05-10 17:05:19 -0700348 @unittest.skipUnless(hasattr(os, 'chflags') and
349 hasattr(errno, 'EOPNOTSUPP') and
350 hasattr(errno, 'ENOTSUP'),
351 "requires os.chflags, EOPNOTSUPP & ENOTSUP")
352 def test_copystat_handles_harmless_chflags_errors(self):
353 tmpdir = self.mkdtemp()
354 file1 = os.path.join(tmpdir, 'file1')
355 file2 = os.path.join(tmpdir, 'file2')
356 write_file(file1, 'xxx')
357 write_file(file2, 'xxx')
358
359 def make_chflags_raiser(err):
360 ex = OSError()
361
Larry Hastings90867a52012-06-22 17:01:41 -0700362 def _chflags_raiser(path, flags, *, follow_symlinks=True):
Ned Deilybaf75712012-05-10 17:05:19 -0700363 ex.errno = err
364 raise ex
365 return _chflags_raiser
366 old_chflags = os.chflags
367 try:
368 for err in errno.EOPNOTSUPP, errno.ENOTSUP:
369 os.chflags = make_chflags_raiser(err)
370 shutil.copystat(file1, file2)
371 # assert others errors break it
372 os.chflags = make_chflags_raiser(errno.EOPNOTSUPP + errno.ENOTSUP)
373 self.assertRaises(OSError, shutil.copystat, file1, file2)
374 finally:
375 os.chflags = old_chflags
376
Antoine Pitrou424246f2012-05-12 19:02:01 +0200377 @support.skip_unless_xattr
378 def test_copyxattr(self):
379 tmp_dir = self.mkdtemp()
380 src = os.path.join(tmp_dir, 'foo')
381 write_file(src, 'foo')
382 dst = os.path.join(tmp_dir, 'bar')
383 write_file(dst, 'bar')
384
385 # no xattr == no problem
386 shutil._copyxattr(src, dst)
387 # common case
388 os.setxattr(src, 'user.foo', b'42')
389 os.setxattr(src, 'user.bar', b'43')
390 shutil._copyxattr(src, dst)
391 self.assertEqual(os.listxattr(src), os.listxattr(dst))
392 self.assertEqual(
393 os.getxattr(src, 'user.foo'),
394 os.getxattr(dst, 'user.foo'))
395 # check errors don't affect other attrs
396 os.remove(dst)
397 write_file(dst, 'bar')
398 os_error = OSError(errno.EPERM, 'EPERM')
399
Larry Hastings9cf065c2012-06-22 16:30:09 -0700400 def _raise_on_user_foo(fname, attr, val, **kwargs):
Antoine Pitrou424246f2012-05-12 19:02:01 +0200401 if attr == 'user.foo':
402 raise os_error
403 else:
Larry Hastings9cf065c2012-06-22 16:30:09 -0700404 orig_setxattr(fname, attr, val, **kwargs)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200405 try:
406 orig_setxattr = os.setxattr
407 os.setxattr = _raise_on_user_foo
408 shutil._copyxattr(src, dst)
Antoine Pitrou61597d32012-05-12 23:37:35 +0200409 self.assertIn('user.bar', os.listxattr(dst))
Antoine Pitrou424246f2012-05-12 19:02:01 +0200410 finally:
411 os.setxattr = orig_setxattr
412
Larry Hastingsad5ae042012-07-14 17:55:11 -0700413 # test that shutil.copystat copies xattrs
414 src = os.path.join(tmp_dir, 'the_original')
415 write_file(src, src)
416 os.setxattr(src, 'user.the_value', b'fiddly')
417 dst = os.path.join(tmp_dir, 'the_copy')
418 write_file(dst, dst)
419 shutil.copystat(src, dst)
Hynek Schlawackc2d481f2012-07-16 17:11:10 +0200420 self.assertEqual(os.getxattr(dst, 'user.the_value'), b'fiddly')
Larry Hastingsad5ae042012-07-14 17:55:11 -0700421
Antoine Pitrou424246f2012-05-12 19:02:01 +0200422 @support.skip_unless_symlink
423 @support.skip_unless_xattr
424 @unittest.skipUnless(hasattr(os, 'geteuid') and os.geteuid() == 0,
425 'root privileges required')
426 def test_copyxattr_symlinks(self):
427 # On Linux, it's only possible to access non-user xattr for symlinks;
428 # which in turn require root privileges. This test should be expanded
429 # as soon as other platforms gain support for extended attributes.
430 tmp_dir = self.mkdtemp()
431 src = os.path.join(tmp_dir, 'foo')
432 src_link = os.path.join(tmp_dir, 'baz')
433 write_file(src, 'foo')
434 os.symlink(src, src_link)
435 os.setxattr(src, 'trusted.foo', b'42')
Larry Hastings9cf065c2012-06-22 16:30:09 -0700436 os.setxattr(src_link, 'trusted.foo', b'43', follow_symlinks=False)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200437 dst = os.path.join(tmp_dir, 'bar')
438 dst_link = os.path.join(tmp_dir, 'qux')
439 write_file(dst, 'bar')
440 os.symlink(dst, dst_link)
Larry Hastingsb4038062012-07-15 10:57:38 -0700441 shutil._copyxattr(src_link, dst_link, follow_symlinks=False)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700442 self.assertEqual(os.getxattr(dst_link, 'trusted.foo', follow_symlinks=False), b'43')
Antoine Pitrou424246f2012-05-12 19:02:01 +0200443 self.assertRaises(OSError, os.getxattr, dst, 'trusted.foo')
Larry Hastingsb4038062012-07-15 10:57:38 -0700444 shutil._copyxattr(src_link, dst, follow_symlinks=False)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200445 self.assertEqual(os.getxattr(dst, 'trusted.foo'), b'43')
446
Antoine Pitrou78091e62011-12-29 18:54:15 +0100447 @support.skip_unless_symlink
448 def test_copy_symlinks(self):
449 tmp_dir = self.mkdtemp()
450 src = os.path.join(tmp_dir, 'foo')
451 dst = os.path.join(tmp_dir, 'bar')
452 src_link = os.path.join(tmp_dir, 'baz')
453 write_file(src, 'foo')
454 os.symlink(src, src_link)
455 if hasattr(os, 'lchmod'):
456 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
457 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700458 shutil.copy(src_link, dst, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100459 self.assertFalse(os.path.islink(dst))
460 self.assertEqual(read_file(src), read_file(dst))
461 os.remove(dst)
462 # follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700463 shutil.copy(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100464 self.assertTrue(os.path.islink(dst))
465 self.assertEqual(os.readlink(dst), os.readlink(src_link))
466 if hasattr(os, 'lchmod'):
467 self.assertEqual(os.lstat(src_link).st_mode,
468 os.lstat(dst).st_mode)
469
470 @support.skip_unless_symlink
471 def test_copy2_symlinks(self):
472 tmp_dir = self.mkdtemp()
473 src = os.path.join(tmp_dir, 'foo')
474 dst = os.path.join(tmp_dir, 'bar')
475 src_link = os.path.join(tmp_dir, 'baz')
476 write_file(src, 'foo')
477 os.symlink(src, src_link)
478 if hasattr(os, 'lchmod'):
479 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
480 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
481 os.lchflags(src_link, stat.UF_NODUMP)
482 src_stat = os.stat(src)
483 src_link_stat = os.lstat(src_link)
484 # follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700485 shutil.copy2(src_link, dst, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100486 self.assertFalse(os.path.islink(dst))
487 self.assertEqual(read_file(src), read_file(dst))
488 os.remove(dst)
489 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700490 shutil.copy2(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100491 self.assertTrue(os.path.islink(dst))
492 self.assertEqual(os.readlink(dst), os.readlink(src_link))
493 dst_stat = os.lstat(dst)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700494 if os.utime in os.supports_follow_symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100495 for attr in 'st_atime', 'st_mtime':
496 # The modification times may be truncated in the new file.
497 self.assertLessEqual(getattr(src_link_stat, attr),
498 getattr(dst_stat, attr) + 1)
499 if hasattr(os, 'lchmod'):
500 self.assertEqual(src_link_stat.st_mode, dst_stat.st_mode)
501 self.assertNotEqual(src_stat.st_mode, dst_stat.st_mode)
502 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
503 self.assertEqual(src_link_stat.st_flags, dst_stat.st_flags)
504
Antoine Pitrou424246f2012-05-12 19:02:01 +0200505 @support.skip_unless_xattr
506 def test_copy2_xattr(self):
507 tmp_dir = self.mkdtemp()
508 src = os.path.join(tmp_dir, 'foo')
509 dst = os.path.join(tmp_dir, 'bar')
510 write_file(src, 'foo')
511 os.setxattr(src, 'user.foo', b'42')
512 shutil.copy2(src, dst)
513 self.assertEqual(
514 os.getxattr(src, 'user.foo'),
515 os.getxattr(dst, 'user.foo'))
516 os.remove(dst)
517
Antoine Pitrou78091e62011-12-29 18:54:15 +0100518 @support.skip_unless_symlink
519 def test_copyfile_symlinks(self):
520 tmp_dir = self.mkdtemp()
521 src = os.path.join(tmp_dir, 'src')
522 dst = os.path.join(tmp_dir, 'dst')
523 dst_link = os.path.join(tmp_dir, 'dst_link')
524 link = os.path.join(tmp_dir, 'link')
525 write_file(src, 'foo')
526 os.symlink(src, link)
527 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700528 shutil.copyfile(link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100529 self.assertTrue(os.path.islink(dst_link))
530 self.assertEqual(os.readlink(link), os.readlink(dst_link))
531 # follow
532 shutil.copyfile(link, dst)
533 self.assertFalse(os.path.islink(dst))
534
Hynek Schlawack2100b422012-06-23 20:28:32 +0200535 def test_rmtree_uses_safe_fd_version_if_available(self):
Hynek Schlawackd0f6e0a2012-06-29 08:28:20 +0200536 _use_fd_functions = ({os.open, os.stat, os.unlink, os.rmdir} <=
537 os.supports_dir_fd and
538 os.listdir in os.supports_fd and
539 os.stat in os.supports_follow_symlinks)
540 if _use_fd_functions:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200541 self.assertTrue(shutil._use_fd_functions)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000542 self.assertTrue(shutil.rmtree.avoids_symlink_attacks)
Hynek Schlawack2100b422012-06-23 20:28:32 +0200543 tmp_dir = self.mkdtemp()
544 d = os.path.join(tmp_dir, 'a')
545 os.mkdir(d)
546 try:
547 real_rmtree = shutil._rmtree_safe_fd
548 class Called(Exception): pass
549 def _raiser(*args, **kwargs):
550 raise Called
551 shutil._rmtree_safe_fd = _raiser
552 self.assertRaises(Called, shutil.rmtree, d)
553 finally:
554 shutil._rmtree_safe_fd = real_rmtree
555 else:
556 self.assertFalse(shutil._use_fd_functions)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000557 self.assertFalse(shutil.rmtree.avoids_symlink_attacks)
Hynek Schlawack2100b422012-06-23 20:28:32 +0200558
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000559 def test_rmtree_dont_delete_file(self):
560 # When called on a file instead of a directory, don't delete it.
561 handle, path = tempfile.mkstemp()
Victor Stinnerbf816222011-06-30 23:25:47 +0200562 os.close(handle)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200563 self.assertRaises(NotADirectoryError, shutil.rmtree, path)
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000564 os.remove(path)
565
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000566 def test_copytree_simple(self):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000567 src_dir = tempfile.mkdtemp()
568 dst_dir = os.path.join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200569 self.addCleanup(shutil.rmtree, src_dir)
570 self.addCleanup(shutil.rmtree, os.path.dirname(dst_dir))
571 write_file((src_dir, 'test.txt'), '123')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000572 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200573 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000574
Éric Araujoa7e33a12011-08-12 19:51:35 +0200575 shutil.copytree(src_dir, dst_dir)
576 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test.txt')))
577 self.assertTrue(os.path.isdir(os.path.join(dst_dir, 'test_dir')))
578 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test_dir',
579 'test.txt')))
580 actual = read_file((dst_dir, 'test.txt'))
581 self.assertEqual(actual, '123')
582 actual = read_file((dst_dir, 'test_dir', 'test.txt'))
583 self.assertEqual(actual, '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000584
Antoine Pitrou78091e62011-12-29 18:54:15 +0100585 @support.skip_unless_symlink
586 def test_copytree_symlinks(self):
587 tmp_dir = self.mkdtemp()
588 src_dir = os.path.join(tmp_dir, 'src')
589 dst_dir = os.path.join(tmp_dir, 'dst')
590 sub_dir = os.path.join(src_dir, 'sub')
591 os.mkdir(src_dir)
592 os.mkdir(sub_dir)
593 write_file((src_dir, 'file.txt'), 'foo')
594 src_link = os.path.join(sub_dir, 'link')
595 dst_link = os.path.join(dst_dir, 'sub/link')
596 os.symlink(os.path.join(src_dir, 'file.txt'),
597 src_link)
598 if hasattr(os, 'lchmod'):
599 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
600 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
601 os.lchflags(src_link, stat.UF_NODUMP)
602 src_stat = os.lstat(src_link)
603 shutil.copytree(src_dir, dst_dir, symlinks=True)
604 self.assertTrue(os.path.islink(os.path.join(dst_dir, 'sub', 'link')))
605 self.assertEqual(os.readlink(os.path.join(dst_dir, 'sub', 'link')),
606 os.path.join(src_dir, 'file.txt'))
607 dst_stat = os.lstat(dst_link)
608 if hasattr(os, 'lchmod'):
609 self.assertEqual(dst_stat.st_mode, src_stat.st_mode)
610 if hasattr(os, 'lchflags'):
611 self.assertEqual(dst_stat.st_flags, src_stat.st_flags)
612
Georg Brandl2ee470f2008-07-16 12:55:28 +0000613 def test_copytree_with_exclude(self):
Georg Brandl2ee470f2008-07-16 12:55:28 +0000614 # creating data
615 join = os.path.join
616 exists = os.path.exists
617 src_dir = tempfile.mkdtemp()
Georg Brandl2ee470f2008-07-16 12:55:28 +0000618 try:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000619 dst_dir = join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200620 write_file((src_dir, 'test.txt'), '123')
621 write_file((src_dir, 'test.tmp'), '123')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000622 os.mkdir(join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200623 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000624 os.mkdir(join(src_dir, 'test_dir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200625 write_file((src_dir, 'test_dir2', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000626 os.mkdir(join(src_dir, 'test_dir2', 'subdir'))
627 os.mkdir(join(src_dir, 'test_dir2', 'subdir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200628 write_file((src_dir, 'test_dir2', 'subdir', 'test.txt'), '456')
629 write_file((src_dir, 'test_dir2', 'subdir2', 'test.py'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000630
631 # testing glob-like patterns
632 try:
633 patterns = shutil.ignore_patterns('*.tmp', 'test_dir2')
634 shutil.copytree(src_dir, dst_dir, ignore=patterns)
635 # checking the result: some elements should not be copied
636 self.assertTrue(exists(join(dst_dir, 'test.txt')))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200637 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
638 self.assertFalse(exists(join(dst_dir, 'test_dir2')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000639 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200640 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000641 try:
642 patterns = shutil.ignore_patterns('*.tmp', 'subdir*')
643 shutil.copytree(src_dir, dst_dir, ignore=patterns)
644 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200645 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
646 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2')))
647 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000648 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200649 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000650
651 # testing callable-style
652 try:
653 def _filter(src, names):
654 res = []
655 for name in names:
656 path = os.path.join(src, name)
657
658 if (os.path.isdir(path) and
659 path.split()[-1] == 'subdir'):
660 res.append(name)
661 elif os.path.splitext(path)[-1] in ('.py'):
662 res.append(name)
663 return res
664
665 shutil.copytree(src_dir, dst_dir, ignore=_filter)
666
667 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200668 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2',
669 'test.py')))
670 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000671
672 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200673 shutil.rmtree(dst_dir)
Georg Brandl2ee470f2008-07-16 12:55:28 +0000674 finally:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000675 shutil.rmtree(src_dir)
676 shutil.rmtree(os.path.dirname(dst_dir))
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000677
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000678 @unittest.skipUnless(hasattr(os, 'link'), 'requires os.link')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000679 def test_dont_copy_file_onto_link_to_itself(self):
Georg Brandl724d0892010-12-05 07:51:39 +0000680 # Temporarily disable test on Windows.
681 if os.name == 'nt':
682 return
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000683 # bug 851123.
684 os.mkdir(TESTFN)
685 src = os.path.join(TESTFN, 'cheese')
686 dst = os.path.join(TESTFN, 'shop')
687 try:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000688 with open(src, 'w') as f:
689 f.write('cheddar')
690 os.link(src, dst)
Hynek Schlawack26fe37d2012-07-19 21:41:02 +0200691 self.assertRaises(shutil.Error, shutil.copyfile, src, dst)
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000692 with open(src, 'r') as f:
693 self.assertEqual(f.read(), 'cheddar')
694 os.remove(dst)
695 finally:
696 shutil.rmtree(TESTFN, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000697
Brian Curtin3b4499c2010-12-28 14:31:47 +0000698 @support.skip_unless_symlink
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000699 def test_dont_copy_file_onto_symlink_to_itself(self):
700 # bug 851123.
701 os.mkdir(TESTFN)
702 src = os.path.join(TESTFN, 'cheese')
703 dst = os.path.join(TESTFN, 'shop')
704 try:
705 with open(src, 'w') as f:
706 f.write('cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000707 # Using `src` here would mean we end up with a symlink pointing
708 # to TESTFN/TESTFN/cheese, while it should point at
709 # TESTFN/cheese.
710 os.symlink('cheese', dst)
Hynek Schlawack26fe37d2012-07-19 21:41:02 +0200711 self.assertRaises(shutil.Error, shutil.copyfile, src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +0000712 with open(src, 'r') as f:
713 self.assertEqual(f.read(), 'cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000714 os.remove(dst)
715 finally:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000716 shutil.rmtree(TESTFN, ignore_errors=True)
Johannes Gijsbers68128712004-08-14 13:57:08 +0000717
Brian Curtin3b4499c2010-12-28 14:31:47 +0000718 @support.skip_unless_symlink
Brian Curtind40e6f72010-07-08 21:39:08 +0000719 def test_rmtree_on_symlink(self):
720 # bug 1669.
721 os.mkdir(TESTFN)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000722 try:
Brian Curtind40e6f72010-07-08 21:39:08 +0000723 src = os.path.join(TESTFN, 'cheese')
724 dst = os.path.join(TESTFN, 'shop')
725 os.mkdir(src)
726 os.symlink(src, dst)
727 self.assertRaises(OSError, shutil.rmtree, dst)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200728 shutil.rmtree(dst, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000729 finally:
Brian Curtind40e6f72010-07-08 21:39:08 +0000730 shutil.rmtree(TESTFN, ignore_errors=True)
731
732 if hasattr(os, "mkfifo"):
733 # Issue #3002: copyfile and copytree block indefinitely on named pipes
734 def test_copyfile_named_pipe(self):
735 os.mkfifo(TESTFN)
736 try:
737 self.assertRaises(shutil.SpecialFileError,
738 shutil.copyfile, TESTFN, TESTFN2)
739 self.assertRaises(shutil.SpecialFileError,
740 shutil.copyfile, __file__, TESTFN)
741 finally:
742 os.remove(TESTFN)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000743
Brian Curtin3b4499c2010-12-28 14:31:47 +0000744 @support.skip_unless_symlink
Brian Curtin52173d42010-12-02 18:29:18 +0000745 def test_copytree_named_pipe(self):
746 os.mkdir(TESTFN)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000747 try:
Brian Curtin52173d42010-12-02 18:29:18 +0000748 subdir = os.path.join(TESTFN, "subdir")
749 os.mkdir(subdir)
750 pipe = os.path.join(subdir, "mypipe")
751 os.mkfifo(pipe)
752 try:
753 shutil.copytree(TESTFN, TESTFN2)
754 except shutil.Error as e:
755 errors = e.args[0]
756 self.assertEqual(len(errors), 1)
757 src, dst, error_msg = errors[0]
758 self.assertEqual("`%s` is a named pipe" % pipe, error_msg)
759 else:
760 self.fail("shutil.Error should have been raised")
761 finally:
762 shutil.rmtree(TESTFN, ignore_errors=True)
763 shutil.rmtree(TESTFN2, ignore_errors=True)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000764
Tarek Ziadé5340db32010-04-19 22:30:51 +0000765 def test_copytree_special_func(self):
766
767 src_dir = self.mkdtemp()
768 dst_dir = os.path.join(self.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200769 write_file((src_dir, 'test.txt'), '123')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000770 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200771 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000772
773 copied = []
774 def _copy(src, dst):
775 copied.append((src, dst))
776
777 shutil.copytree(src_dir, dst_dir, copy_function=_copy)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000778 self.assertEqual(len(copied), 2)
Tarek Ziadé5340db32010-04-19 22:30:51 +0000779
Brian Curtin3b4499c2010-12-28 14:31:47 +0000780 @support.skip_unless_symlink
Tarek Ziadéfb437512010-04-20 08:57:33 +0000781 def test_copytree_dangling_symlinks(self):
782
783 # a dangling symlink raises an error at the end
784 src_dir = self.mkdtemp()
785 dst_dir = os.path.join(self.mkdtemp(), 'destination')
786 os.symlink('IDONTEXIST', os.path.join(src_dir, 'test.txt'))
787 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200788 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadéfb437512010-04-20 08:57:33 +0000789 self.assertRaises(Error, shutil.copytree, src_dir, dst_dir)
790
791 # a dangling symlink is ignored with the proper flag
792 dst_dir = os.path.join(self.mkdtemp(), 'destination2')
793 shutil.copytree(src_dir, dst_dir, ignore_dangling_symlinks=True)
794 self.assertNotIn('test.txt', os.listdir(dst_dir))
795
796 # a dangling symlink is copied if symlinks=True
797 dst_dir = os.path.join(self.mkdtemp(), 'destination3')
798 shutil.copytree(src_dir, dst_dir, symlinks=True)
799 self.assertIn('test.txt', os.listdir(dst_dir))
800
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400801 def _copy_file(self, method):
802 fname = 'test.txt'
803 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200804 write_file((tmpdir, fname), 'xxx')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400805 file1 = os.path.join(tmpdir, fname)
806 tmpdir2 = self.mkdtemp()
807 method(file1, tmpdir2)
808 file2 = os.path.join(tmpdir2, fname)
809 return (file1, file2)
810
811 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
812 def test_copy(self):
813 # Ensure that the copied file exists and has the same mode bits.
814 file1, file2 = self._copy_file(shutil.copy)
815 self.assertTrue(os.path.exists(file2))
816 self.assertEqual(os.stat(file1).st_mode, os.stat(file2).st_mode)
817
818 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
Senthil Kumaran0c2dba52011-07-03 18:21:38 -0700819 @unittest.skipUnless(hasattr(os, 'utime'), 'requires os.utime')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400820 def test_copy2(self):
821 # Ensure that the copied file exists and has the same mode and
822 # modification time bits.
823 file1, file2 = self._copy_file(shutil.copy2)
824 self.assertTrue(os.path.exists(file2))
825 file1_stat = os.stat(file1)
826 file2_stat = os.stat(file2)
827 self.assertEqual(file1_stat.st_mode, file2_stat.st_mode)
828 for attr in 'st_atime', 'st_mtime':
829 # The modification times may be truncated in the new file.
830 self.assertLessEqual(getattr(file1_stat, attr),
831 getattr(file2_stat, attr) + 1)
832 if hasattr(os, 'chflags') and hasattr(file1_stat, 'st_flags'):
833 self.assertEqual(getattr(file1_stat, 'st_flags'),
834 getattr(file2_stat, 'st_flags'))
835
Ezio Melotti975077a2011-05-19 22:03:22 +0300836 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000837 def test_make_tarball(self):
838 # creating something to tar
839 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200840 write_file((tmpdir, 'file1'), 'xxx')
841 write_file((tmpdir, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000842 os.mkdir(os.path.join(tmpdir, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200843 write_file((tmpdir, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000844
845 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400846 # force shutil to create the directory
847 os.rmdir(tmpdir2)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000848 unittest.skipUnless(splitdrive(tmpdir)[0] == splitdrive(tmpdir2)[0],
849 "source and target should be on same drive")
850
851 base_name = os.path.join(tmpdir2, 'archive')
852
853 # working with relative paths to avoid tar warnings
854 old_dir = os.getcwd()
855 os.chdir(tmpdir)
856 try:
857 _make_tarball(splitdrive(base_name)[1], '.')
858 finally:
859 os.chdir(old_dir)
860
861 # check if the compressed tarball was created
862 tarball = base_name + '.tar.gz'
863 self.assertTrue(os.path.exists(tarball))
864
865 # trying an uncompressed one
866 base_name = os.path.join(tmpdir2, 'archive')
867 old_dir = os.getcwd()
868 os.chdir(tmpdir)
869 try:
870 _make_tarball(splitdrive(base_name)[1], '.', compress=None)
871 finally:
872 os.chdir(old_dir)
873 tarball = base_name + '.tar'
874 self.assertTrue(os.path.exists(tarball))
875
876 def _tarinfo(self, path):
877 tar = tarfile.open(path)
878 try:
879 names = tar.getnames()
880 names.sort()
881 return tuple(names)
882 finally:
883 tar.close()
884
885 def _create_files(self):
886 # creating something to tar
887 tmpdir = self.mkdtemp()
888 dist = os.path.join(tmpdir, 'dist')
889 os.mkdir(dist)
Éric Araujoa7e33a12011-08-12 19:51:35 +0200890 write_file((dist, 'file1'), 'xxx')
891 write_file((dist, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000892 os.mkdir(os.path.join(dist, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200893 write_file((dist, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000894 os.mkdir(os.path.join(dist, 'sub2'))
895 tmpdir2 = self.mkdtemp()
896 base_name = os.path.join(tmpdir2, 'archive')
897 return tmpdir, tmpdir2, base_name
898
Ezio Melotti975077a2011-05-19 22:03:22 +0300899 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000900 @unittest.skipUnless(find_executable('tar') and find_executable('gzip'),
901 'Need the tar command to run')
902 def test_tarfile_vs_tar(self):
903 tmpdir, tmpdir2, base_name = self._create_files()
904 old_dir = os.getcwd()
905 os.chdir(tmpdir)
906 try:
907 _make_tarball(base_name, 'dist')
908 finally:
909 os.chdir(old_dir)
910
911 # check if the compressed tarball was created
912 tarball = base_name + '.tar.gz'
913 self.assertTrue(os.path.exists(tarball))
914
915 # now create another tarball using `tar`
916 tarball2 = os.path.join(tmpdir, 'archive2.tar.gz')
917 tar_cmd = ['tar', '-cf', 'archive2.tar', 'dist']
918 gzip_cmd = ['gzip', '-f9', 'archive2.tar']
919 old_dir = os.getcwd()
920 os.chdir(tmpdir)
921 try:
922 with captured_stdout() as s:
923 spawn(tar_cmd)
924 spawn(gzip_cmd)
925 finally:
926 os.chdir(old_dir)
927
928 self.assertTrue(os.path.exists(tarball2))
929 # let's compare both tarballs
Ezio Melottib3aedd42010-11-20 19:04:17 +0000930 self.assertEqual(self._tarinfo(tarball), self._tarinfo(tarball2))
Tarek Ziadé396fad72010-02-23 05:30:31 +0000931
932 # trying an uncompressed one
933 base_name = os.path.join(tmpdir2, 'archive')
934 old_dir = os.getcwd()
935 os.chdir(tmpdir)
936 try:
937 _make_tarball(base_name, 'dist', compress=None)
938 finally:
939 os.chdir(old_dir)
940 tarball = base_name + '.tar'
941 self.assertTrue(os.path.exists(tarball))
942
943 # now for a dry_run
944 base_name = os.path.join(tmpdir2, 'archive')
945 old_dir = os.getcwd()
946 os.chdir(tmpdir)
947 try:
948 _make_tarball(base_name, 'dist', compress=None, dry_run=True)
949 finally:
950 os.chdir(old_dir)
951 tarball = base_name + '.tar'
952 self.assertTrue(os.path.exists(tarball))
953
Ezio Melotti975077a2011-05-19 22:03:22 +0300954 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000955 @unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run')
956 def test_make_zipfile(self):
957 # creating something to tar
958 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200959 write_file((tmpdir, 'file1'), 'xxx')
960 write_file((tmpdir, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000961
962 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400963 # force shutil to create the directory
964 os.rmdir(tmpdir2)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000965 base_name = os.path.join(tmpdir2, 'archive')
966 _make_zipfile(base_name, tmpdir)
967
968 # check if the compressed tarball was created
969 tarball = base_name + '.zip'
Éric Araujo1c505492010-11-06 02:12:51 +0000970 self.assertTrue(os.path.exists(tarball))
Tarek Ziadé396fad72010-02-23 05:30:31 +0000971
972
973 def test_make_archive(self):
974 tmpdir = self.mkdtemp()
975 base_name = os.path.join(tmpdir, 'archive')
976 self.assertRaises(ValueError, make_archive, base_name, 'xxx')
977
Ezio Melotti975077a2011-05-19 22:03:22 +0300978 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000979 def test_make_archive_owner_group(self):
980 # testing make_archive with owner and group, with various combinations
981 # this works even if there's not gid/uid support
982 if UID_GID_SUPPORT:
983 group = grp.getgrgid(0)[0]
984 owner = pwd.getpwuid(0)[0]
985 else:
986 group = owner = 'root'
987
988 base_dir, root_dir, base_name = self._create_files()
989 base_name = os.path.join(self.mkdtemp() , 'archive')
990 res = make_archive(base_name, 'zip', root_dir, base_dir, owner=owner,
991 group=group)
992 self.assertTrue(os.path.exists(res))
993
994 res = make_archive(base_name, 'zip', root_dir, base_dir)
995 self.assertTrue(os.path.exists(res))
996
997 res = make_archive(base_name, 'tar', root_dir, base_dir,
998 owner=owner, group=group)
999 self.assertTrue(os.path.exists(res))
1000
1001 res = make_archive(base_name, 'tar', root_dir, base_dir,
1002 owner='kjhkjhkjg', group='oihohoh')
1003 self.assertTrue(os.path.exists(res))
1004
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001005
Ezio Melotti975077a2011-05-19 22:03:22 +03001006 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001007 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1008 def test_tarfile_root_owner(self):
1009 tmpdir, tmpdir2, base_name = self._create_files()
1010 old_dir = os.getcwd()
1011 os.chdir(tmpdir)
1012 group = grp.getgrgid(0)[0]
1013 owner = pwd.getpwuid(0)[0]
1014 try:
1015 archive_name = _make_tarball(base_name, 'dist', compress=None,
1016 owner=owner, group=group)
1017 finally:
1018 os.chdir(old_dir)
1019
1020 # check if the compressed tarball was created
1021 self.assertTrue(os.path.exists(archive_name))
1022
1023 # now checks the rights
1024 archive = tarfile.open(archive_name)
1025 try:
1026 for member in archive.getmembers():
Ezio Melottib3aedd42010-11-20 19:04:17 +00001027 self.assertEqual(member.uid, 0)
1028 self.assertEqual(member.gid, 0)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001029 finally:
1030 archive.close()
1031
1032 def test_make_archive_cwd(self):
1033 current_dir = os.getcwd()
1034 def _breaks(*args, **kw):
1035 raise RuntimeError()
1036
1037 register_archive_format('xxx', _breaks, [], 'xxx file')
1038 try:
1039 try:
1040 make_archive('xxx', 'xxx', root_dir=self.mkdtemp())
1041 except Exception:
1042 pass
Ezio Melottib3aedd42010-11-20 19:04:17 +00001043 self.assertEqual(os.getcwd(), current_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001044 finally:
1045 unregister_archive_format('xxx')
1046
1047 def test_register_archive_format(self):
1048
1049 self.assertRaises(TypeError, register_archive_format, 'xxx', 1)
1050 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1051 1)
1052 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1053 [(1, 2), (1, 2, 3)])
1054
1055 register_archive_format('xxx', lambda: x, [(1, 2)], 'xxx file')
1056 formats = [name for name, params in get_archive_formats()]
1057 self.assertIn('xxx', formats)
1058
1059 unregister_archive_format('xxx')
1060 formats = [name for name, params in get_archive_formats()]
1061 self.assertNotIn('xxx', formats)
1062
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001063 def _compare_dirs(self, dir1, dir2):
1064 # check that dir1 and dir2 are equivalent,
1065 # return the diff
1066 diff = []
1067 for root, dirs, files in os.walk(dir1):
1068 for file_ in files:
1069 path = os.path.join(root, file_)
1070 target_path = os.path.join(dir2, os.path.split(path)[-1])
1071 if not os.path.exists(target_path):
1072 diff.append(file_)
1073 return diff
1074
Ezio Melotti975077a2011-05-19 22:03:22 +03001075 @requires_zlib
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001076 def test_unpack_archive(self):
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001077 formats = ['tar', 'gztar', 'zip']
1078 if BZ2_SUPPORTED:
1079 formats.append('bztar')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001080
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001081 for format in formats:
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001082 tmpdir = self.mkdtemp()
1083 base_dir, root_dir, base_name = self._create_files()
1084 tmpdir2 = self.mkdtemp()
1085 filename = make_archive(base_name, format, root_dir, base_dir)
1086
1087 # let's try to unpack it now
1088 unpack_archive(filename, tmpdir2)
1089 diff = self._compare_dirs(tmpdir, tmpdir2)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001090 self.assertEqual(diff, [])
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001091
Nick Coghlanabf202d2011-03-16 13:52:20 -04001092 # and again, this time with the format specified
1093 tmpdir3 = self.mkdtemp()
1094 unpack_archive(filename, tmpdir3, format=format)
1095 diff = self._compare_dirs(tmpdir, tmpdir3)
1096 self.assertEqual(diff, [])
1097 self.assertRaises(shutil.ReadError, unpack_archive, TESTFN)
1098 self.assertRaises(ValueError, unpack_archive, TESTFN, format='xxx')
1099
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001100 def test_unpack_registery(self):
1101
1102 formats = get_unpack_formats()
1103
1104 def _boo(filename, extract_dir, extra):
Ezio Melottib3aedd42010-11-20 19:04:17 +00001105 self.assertEqual(extra, 1)
1106 self.assertEqual(filename, 'stuff.boo')
1107 self.assertEqual(extract_dir, 'xx')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001108
1109 register_unpack_format('Boo', ['.boo', '.b2'], _boo, [('extra', 1)])
1110 unpack_archive('stuff.boo', 'xx')
1111
1112 # trying to register a .boo unpacker again
1113 self.assertRaises(RegistryError, register_unpack_format, 'Boo2',
1114 ['.boo'], _boo)
1115
1116 # should work now
1117 unregister_unpack_format('Boo')
1118 register_unpack_format('Boo2', ['.boo'], _boo)
1119 self.assertIn(('Boo2', ['.boo'], ''), get_unpack_formats())
1120 self.assertNotIn(('Boo', ['.boo'], ''), get_unpack_formats())
1121
1122 # let's leave a clean state
1123 unregister_unpack_format('Boo2')
Ezio Melottib3aedd42010-11-20 19:04:17 +00001124 self.assertEqual(get_unpack_formats(), formats)
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001125
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001126 @unittest.skipUnless(hasattr(shutil, 'disk_usage'),
1127 "disk_usage not available on this platform")
1128 def test_disk_usage(self):
1129 usage = shutil.disk_usage(os.getcwd())
Éric Araujo2ee61882011-07-02 16:45:45 +02001130 self.assertGreater(usage.total, 0)
1131 self.assertGreater(usage.used, 0)
1132 self.assertGreaterEqual(usage.free, 0)
1133 self.assertGreaterEqual(usage.total, usage.used)
1134 self.assertGreater(usage.total, usage.free)
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001135
Sandro Tosid902a142011-08-22 23:28:27 +02001136 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1137 @unittest.skipUnless(hasattr(os, 'chown'), 'requires os.chown')
1138 def test_chown(self):
1139
1140 # cleaned-up automatically by TestShutil.tearDown method
1141 dirname = self.mkdtemp()
1142 filename = tempfile.mktemp(dir=dirname)
1143 write_file(filename, 'testing chown function')
1144
1145 with self.assertRaises(ValueError):
1146 shutil.chown(filename)
1147
1148 with self.assertRaises(LookupError):
1149 shutil.chown(filename, user='non-exising username')
1150
1151 with self.assertRaises(LookupError):
1152 shutil.chown(filename, group='non-exising groupname')
1153
1154 with self.assertRaises(TypeError):
1155 shutil.chown(filename, b'spam')
1156
1157 with self.assertRaises(TypeError):
1158 shutil.chown(filename, 3.14)
1159
1160 uid = os.getuid()
1161 gid = os.getgid()
1162
1163 def check_chown(path, uid=None, gid=None):
1164 s = os.stat(filename)
1165 if uid is not None:
1166 self.assertEqual(uid, s.st_uid)
1167 if gid is not None:
1168 self.assertEqual(gid, s.st_gid)
1169
1170 shutil.chown(filename, uid, gid)
1171 check_chown(filename, uid, gid)
1172 shutil.chown(filename, uid)
1173 check_chown(filename, uid)
1174 shutil.chown(filename, user=uid)
1175 check_chown(filename, uid)
1176 shutil.chown(filename, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001177 check_chown(filename, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001178
1179 shutil.chown(dirname, uid, gid)
1180 check_chown(dirname, uid, gid)
1181 shutil.chown(dirname, uid)
1182 check_chown(dirname, uid)
1183 shutil.chown(dirname, user=uid)
1184 check_chown(dirname, uid)
1185 shutil.chown(dirname, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001186 check_chown(dirname, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001187
1188 user = pwd.getpwuid(uid)[0]
1189 group = grp.getgrgid(gid)[0]
1190 shutil.chown(filename, user, group)
1191 check_chown(filename, uid, gid)
1192 shutil.chown(dirname, user, group)
1193 check_chown(dirname, uid, gid)
1194
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001195 def test_copy_return_value(self):
1196 # copy and copy2 both return their destination path.
1197 for fn in (shutil.copy, shutil.copy2):
1198 src_dir = self.mkdtemp()
1199 dst_dir = self.mkdtemp()
1200 src = os.path.join(src_dir, 'foo')
1201 write_file(src, 'foo')
1202 rv = fn(src, dst_dir)
1203 self.assertEqual(rv, os.path.join(dst_dir, 'foo'))
1204 rv = fn(src, os.path.join(dst_dir, 'bar'))
1205 self.assertEqual(rv, os.path.join(dst_dir, 'bar'))
1206
1207 def test_copyfile_return_value(self):
1208 # copytree returns its destination path.
1209 src_dir = self.mkdtemp()
1210 dst_dir = self.mkdtemp()
1211 dst_file = os.path.join(dst_dir, 'bar')
1212 src_file = os.path.join(src_dir, 'foo')
1213 write_file(src_file, 'foo')
1214 rv = shutil.copyfile(src_file, dst_file)
1215 self.assertTrue(os.path.exists(rv))
1216 self.assertEqual(read_file(src_file), read_file(dst_file))
1217
1218 def test_copytree_return_value(self):
1219 # copytree returns its destination path.
1220 src_dir = self.mkdtemp()
1221 dst_dir = src_dir + "dest"
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001222 self.addCleanup(shutil.rmtree, dst_dir, True)
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001223 src = os.path.join(src_dir, 'foo')
1224 write_file(src, 'foo')
1225 rv = shutil.copytree(src_dir, dst_dir)
1226 self.assertEqual(['foo'], os.listdir(rv))
1227
Christian Heimes9bd667a2008-01-20 15:14:11 +00001228
Brian Curtinc57a3452012-06-22 16:00:30 -05001229class TestWhich(unittest.TestCase):
1230
1231 def setUp(self):
1232 self.temp_dir = tempfile.mkdtemp()
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001233 self.addCleanup(shutil.rmtree, self.temp_dir, True)
Brian Curtinc57a3452012-06-22 16:00:30 -05001234 # Give the temp_file an ".exe" suffix for all.
1235 # It's needed on Windows and not harmful on other platforms.
1236 self.temp_file = tempfile.NamedTemporaryFile(dir=self.temp_dir,
1237 suffix=".exe")
1238 os.chmod(self.temp_file.name, stat.S_IXUSR)
1239 self.addCleanup(self.temp_file.close)
1240 self.dir, self.file = os.path.split(self.temp_file.name)
1241
1242 def test_basic(self):
1243 # Given an EXE in a directory, it should be returned.
1244 rv = shutil.which(self.file, path=self.dir)
1245 self.assertEqual(rv, self.temp_file.name)
1246
1247 def test_full_path_short_circuit(self):
1248 # When given the fully qualified path to an executable that exists,
1249 # it should be returned.
1250 rv = shutil.which(self.temp_file.name, path=self.temp_dir)
1251 self.assertEqual(self.temp_file.name, rv)
1252
1253 def test_non_matching_mode(self):
1254 # Set the file read-only and ask for writeable files.
1255 os.chmod(self.temp_file.name, stat.S_IREAD)
1256 rv = shutil.which(self.file, path=self.dir, mode=os.W_OK)
1257 self.assertIsNone(rv)
1258
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001259 def test_relative(self):
1260 old_cwd = os.getcwd()
1261 base_dir, tail_dir = os.path.split(self.dir)
1262 os.chdir(base_dir)
1263 try:
1264 rv = shutil.which(self.file, path=tail_dir)
1265 self.assertEqual(rv, os.path.join(tail_dir, self.file))
1266 finally:
1267 os.chdir(old_cwd)
1268
Brian Curtinc57a3452012-06-22 16:00:30 -05001269 def test_nonexistent_file(self):
1270 # Return None when no matching executable file is found on the path.
1271 rv = shutil.which("foo.exe", path=self.dir)
1272 self.assertIsNone(rv)
1273
1274 @unittest.skipUnless(sys.platform == "win32",
1275 "pathext check is Windows-only")
1276 def test_pathext_checking(self):
1277 # Ask for the file without the ".exe" extension, then ensure that
1278 # it gets found properly with the extension.
1279 rv = shutil.which(self.temp_file.name[:-4], path=self.dir)
1280 self.assertEqual(self.temp_file.name, rv)
1281
1282
Christian Heimesada8c3b2008-03-18 18:26:33 +00001283class TestMove(unittest.TestCase):
1284
1285 def setUp(self):
1286 filename = "foo"
1287 self.src_dir = tempfile.mkdtemp()
1288 self.dst_dir = tempfile.mkdtemp()
1289 self.src_file = os.path.join(self.src_dir, filename)
1290 self.dst_file = os.path.join(self.dst_dir, filename)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001291 with open(self.src_file, "wb") as f:
1292 f.write(b"spam")
1293
1294 def tearDown(self):
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001295 for d in (self.src_dir, self.dst_dir):
Christian Heimesada8c3b2008-03-18 18:26:33 +00001296 try:
1297 if d:
1298 shutil.rmtree(d)
1299 except:
1300 pass
1301
1302 def _check_move_file(self, src, dst, real_dst):
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001303 with open(src, "rb") as f:
1304 contents = f.read()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001305 shutil.move(src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001306 with open(real_dst, "rb") as f:
1307 self.assertEqual(contents, f.read())
Christian Heimesada8c3b2008-03-18 18:26:33 +00001308 self.assertFalse(os.path.exists(src))
1309
1310 def _check_move_dir(self, src, dst, real_dst):
1311 contents = sorted(os.listdir(src))
1312 shutil.move(src, dst)
1313 self.assertEqual(contents, sorted(os.listdir(real_dst)))
1314 self.assertFalse(os.path.exists(src))
1315
1316 def test_move_file(self):
1317 # Move a file to another location on the same filesystem.
1318 self._check_move_file(self.src_file, self.dst_file, self.dst_file)
1319
1320 def test_move_file_to_dir(self):
1321 # Move a file inside an existing dir on the same filesystem.
1322 self._check_move_file(self.src_file, self.dst_dir, self.dst_file)
1323
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001324 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001325 def test_move_file_other_fs(self):
1326 # Move a file to an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001327 self.test_move_file()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001328
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001329 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001330 def test_move_file_to_dir_other_fs(self):
1331 # Move a file to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001332 self.test_move_file_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001333
1334 def test_move_dir(self):
1335 # Move a dir to another location on the same filesystem.
1336 dst_dir = tempfile.mktemp()
1337 try:
1338 self._check_move_dir(self.src_dir, dst_dir, dst_dir)
1339 finally:
1340 try:
1341 shutil.rmtree(dst_dir)
1342 except:
1343 pass
1344
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001345 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001346 def test_move_dir_other_fs(self):
1347 # Move a dir to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001348 self.test_move_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001349
1350 def test_move_dir_to_dir(self):
1351 # Move a dir inside an existing dir on the same filesystem.
1352 self._check_move_dir(self.src_dir, self.dst_dir,
1353 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1354
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001355 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001356 def test_move_dir_to_dir_other_fs(self):
1357 # Move a dir inside an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001358 self.test_move_dir_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001359
1360 def test_existing_file_inside_dest_dir(self):
1361 # A file with the same name inside the destination dir already exists.
1362 with open(self.dst_file, "wb"):
1363 pass
1364 self.assertRaises(shutil.Error, shutil.move, self.src_file, self.dst_dir)
1365
1366 def test_dont_move_dir_in_itself(self):
1367 # Moving a dir inside itself raises an Error.
1368 dst = os.path.join(self.src_dir, "bar")
1369 self.assertRaises(shutil.Error, shutil.move, self.src_dir, dst)
1370
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001371 def test_destinsrc_false_negative(self):
1372 os.mkdir(TESTFN)
1373 try:
1374 for src, dst in [('srcdir', 'srcdir/dest')]:
1375 src = os.path.join(TESTFN, src)
1376 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001377 self.assertTrue(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001378 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001379 'dst (%s) is not in src (%s)' % (dst, src))
1380 finally:
1381 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001382
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001383 def test_destinsrc_false_positive(self):
1384 os.mkdir(TESTFN)
1385 try:
1386 for src, dst in [('srcdir', 'src/dest'), ('srcdir', 'srcdir.new')]:
1387 src = os.path.join(TESTFN, src)
1388 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001389 self.assertFalse(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001390 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001391 'dst (%s) is in src (%s)' % (dst, src))
1392 finally:
1393 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimes9bd667a2008-01-20 15:14:11 +00001394
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +01001395 @support.skip_unless_symlink
1396 @mock_rename
1397 def test_move_file_symlink(self):
1398 dst = os.path.join(self.src_dir, 'bar')
1399 os.symlink(self.src_file, dst)
1400 shutil.move(dst, self.dst_file)
1401 self.assertTrue(os.path.islink(self.dst_file))
1402 self.assertTrue(os.path.samefile(self.src_file, self.dst_file))
1403
1404 @support.skip_unless_symlink
1405 @mock_rename
1406 def test_move_file_symlink_to_dir(self):
1407 filename = "bar"
1408 dst = os.path.join(self.src_dir, filename)
1409 os.symlink(self.src_file, dst)
1410 shutil.move(dst, self.dst_dir)
1411 final_link = os.path.join(self.dst_dir, filename)
1412 self.assertTrue(os.path.islink(final_link))
1413 self.assertTrue(os.path.samefile(self.src_file, final_link))
1414
1415 @support.skip_unless_symlink
1416 @mock_rename
1417 def test_move_dangling_symlink(self):
1418 src = os.path.join(self.src_dir, 'baz')
1419 dst = os.path.join(self.src_dir, 'bar')
1420 os.symlink(src, dst)
1421 dst_link = os.path.join(self.dst_dir, 'quux')
1422 shutil.move(dst, dst_link)
1423 self.assertTrue(os.path.islink(dst_link))
1424 self.assertEqual(os.path.realpath(src), os.path.realpath(dst_link))
1425
1426 @support.skip_unless_symlink
1427 @mock_rename
1428 def test_move_dir_symlink(self):
1429 src = os.path.join(self.src_dir, 'baz')
1430 dst = os.path.join(self.src_dir, 'bar')
1431 os.mkdir(src)
1432 os.symlink(src, dst)
1433 dst_link = os.path.join(self.dst_dir, 'quux')
1434 shutil.move(dst, dst_link)
1435 self.assertTrue(os.path.islink(dst_link))
1436 self.assertTrue(os.path.samefile(src, dst_link))
1437
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001438 def test_move_return_value(self):
1439 rv = shutil.move(self.src_file, self.dst_dir)
1440 self.assertEqual(rv,
1441 os.path.join(self.dst_dir, os.path.basename(self.src_file)))
1442
1443 def test_move_as_rename_return_value(self):
1444 rv = shutil.move(self.src_file, os.path.join(self.dst_dir, 'bar'))
1445 self.assertEqual(rv, os.path.join(self.dst_dir, 'bar'))
1446
Tarek Ziadé5340db32010-04-19 22:30:51 +00001447
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001448class TestCopyFile(unittest.TestCase):
1449
1450 _delete = False
1451
1452 class Faux(object):
1453 _entered = False
1454 _exited_with = None
1455 _raised = False
1456 def __init__(self, raise_in_exit=False, suppress_at_exit=True):
1457 self._raise_in_exit = raise_in_exit
1458 self._suppress_at_exit = suppress_at_exit
1459 def read(self, *args):
1460 return ''
1461 def __enter__(self):
1462 self._entered = True
1463 def __exit__(self, exc_type, exc_val, exc_tb):
1464 self._exited_with = exc_type, exc_val, exc_tb
1465 if self._raise_in_exit:
1466 self._raised = True
1467 raise IOError("Cannot close")
1468 return self._suppress_at_exit
1469
1470 def tearDown(self):
1471 if self._delete:
1472 del shutil.open
1473
1474 def _set_shutil_open(self, func):
1475 shutil.open = func
1476 self._delete = True
1477
1478 def test_w_source_open_fails(self):
1479 def _open(filename, mode='r'):
1480 if filename == 'srcfile':
1481 raise IOError('Cannot open "srcfile"')
1482 assert 0 # shouldn't reach here.
1483
1484 self._set_shutil_open(_open)
1485
1486 self.assertRaises(IOError, shutil.copyfile, 'srcfile', 'destfile')
1487
1488 def test_w_dest_open_fails(self):
1489
1490 srcfile = self.Faux()
1491
1492 def _open(filename, mode='r'):
1493 if filename == 'srcfile':
1494 return srcfile
1495 if filename == 'destfile':
1496 raise IOError('Cannot open "destfile"')
1497 assert 0 # shouldn't reach here.
1498
1499 self._set_shutil_open(_open)
1500
1501 shutil.copyfile('srcfile', 'destfile')
1502 self.assertTrue(srcfile._entered)
1503 self.assertTrue(srcfile._exited_with[0] is IOError)
1504 self.assertEqual(srcfile._exited_with[1].args,
1505 ('Cannot open "destfile"',))
1506
1507 def test_w_dest_close_fails(self):
1508
1509 srcfile = self.Faux()
1510 destfile = self.Faux(True)
1511
1512 def _open(filename, mode='r'):
1513 if filename == 'srcfile':
1514 return srcfile
1515 if filename == 'destfile':
1516 return destfile
1517 assert 0 # shouldn't reach here.
1518
1519 self._set_shutil_open(_open)
1520
1521 shutil.copyfile('srcfile', 'destfile')
1522 self.assertTrue(srcfile._entered)
1523 self.assertTrue(destfile._entered)
1524 self.assertTrue(destfile._raised)
1525 self.assertTrue(srcfile._exited_with[0] is IOError)
1526 self.assertEqual(srcfile._exited_with[1].args,
1527 ('Cannot close',))
1528
1529 def test_w_source_close_fails(self):
1530
1531 srcfile = self.Faux(True)
1532 destfile = self.Faux()
1533
1534 def _open(filename, mode='r'):
1535 if filename == 'srcfile':
1536 return srcfile
1537 if filename == 'destfile':
1538 return destfile
1539 assert 0 # shouldn't reach here.
1540
1541 self._set_shutil_open(_open)
1542
1543 self.assertRaises(IOError,
1544 shutil.copyfile, 'srcfile', 'destfile')
1545 self.assertTrue(srcfile._entered)
1546 self.assertTrue(destfile._entered)
1547 self.assertFalse(destfile._raised)
1548 self.assertTrue(srcfile._exited_with[0] is None)
1549 self.assertTrue(srcfile._raised)
1550
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001551 def test_move_dir_caseinsensitive(self):
1552 # Renames a folder to the same name
1553 # but a different case.
1554
1555 self.src_dir = tempfile.mkdtemp()
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001556 self.addCleanup(shutil.rmtree, self.src_dir, True)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001557 dst_dir = os.path.join(
1558 os.path.dirname(self.src_dir),
1559 os.path.basename(self.src_dir).upper())
1560 self.assertNotEqual(self.src_dir, dst_dir)
1561
1562 try:
1563 shutil.move(self.src_dir, dst_dir)
1564 self.assertTrue(os.path.isdir(dst_dir))
1565 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +02001566 os.rmdir(dst_dir)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001567
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001568class TermsizeTests(unittest.TestCase):
1569 def test_does_not_crash(self):
1570 """Check if get_terminal_size() returns a meaningful value.
1571
1572 There's no easy portable way to actually check the size of the
1573 terminal, so let's check if it returns something sensible instead.
1574 """
1575 size = shutil.get_terminal_size()
Antoine Pitroucfade362012-02-08 23:48:59 +01001576 self.assertGreaterEqual(size.columns, 0)
1577 self.assertGreaterEqual(size.lines, 0)
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001578
1579 def test_os_environ_first(self):
1580 "Check if environment variables have precedence"
1581
1582 with support.EnvironmentVarGuard() as env:
1583 env['COLUMNS'] = '777'
1584 size = shutil.get_terminal_size()
1585 self.assertEqual(size.columns, 777)
1586
1587 with support.EnvironmentVarGuard() as env:
1588 env['LINES'] = '888'
1589 size = shutil.get_terminal_size()
1590 self.assertEqual(size.lines, 888)
1591
1592 @unittest.skipUnless(os.isatty(sys.__stdout__.fileno()), "not on tty")
1593 def test_stty_match(self):
1594 """Check if stty returns the same results ignoring env
1595
1596 This test will fail if stdin and stdout are connected to
1597 different terminals with different sizes. Nevertheless, such
1598 situations should be pretty rare.
1599 """
1600 try:
1601 size = subprocess.check_output(['stty', 'size']).decode().split()
1602 except (FileNotFoundError, subprocess.CalledProcessError):
1603 self.skipTest("stty invocation failed")
1604 expected = (int(size[1]), int(size[0])) # reversed order
1605
1606 with support.EnvironmentVarGuard() as env:
1607 del env['LINES']
1608 del env['COLUMNS']
1609 actual = shutil.get_terminal_size()
1610
1611 self.assertEqual(expected, actual)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001612
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001613
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001614def test_main():
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001615 support.run_unittest(TestShutil, TestMove, TestCopyFile,
Brian Curtinc57a3452012-06-22 16:00:30 -05001616 TermsizeTests, TestWhich)
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001617
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001618if __name__ == '__main__':
Walter Dörwald21d3a322003-05-01 17:45:56 +00001619 test_main()