blob: e5c38eb9c89bfb28fde002c05bf6f2fe5cb273bd [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,
21 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)
420 self.assertEqual(os.listxattr(src), ['user.the_value'])
421 self.assertEqual(os.getxattr(src, 'user.the_value'), b'fiddly')
422
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)
692 self.assertRaises(shutil.Error, shutil.copyfile, src, dst)
693 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)
712 self.assertRaises(shutil.Error, 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
1219 def test_copytree_return_value(self):
1220 # copytree returns its destination path.
1221 src_dir = self.mkdtemp()
1222 dst_dir = src_dir + "dest"
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001223 self.addCleanup(shutil.rmtree, dst_dir, True)
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001224 src = os.path.join(src_dir, 'foo')
1225 write_file(src, 'foo')
1226 rv = shutil.copytree(src_dir, dst_dir)
1227 self.assertEqual(['foo'], os.listdir(rv))
1228
Christian Heimes9bd667a2008-01-20 15:14:11 +00001229
Brian Curtinc57a3452012-06-22 16:00:30 -05001230class TestWhich(unittest.TestCase):
1231
1232 def setUp(self):
1233 self.temp_dir = tempfile.mkdtemp()
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001234 self.addCleanup(shutil.rmtree, self.temp_dir, True)
Brian Curtinc57a3452012-06-22 16:00:30 -05001235 # Give the temp_file an ".exe" suffix for all.
1236 # It's needed on Windows and not harmful on other platforms.
1237 self.temp_file = tempfile.NamedTemporaryFile(dir=self.temp_dir,
1238 suffix=".exe")
1239 os.chmod(self.temp_file.name, stat.S_IXUSR)
1240 self.addCleanup(self.temp_file.close)
1241 self.dir, self.file = os.path.split(self.temp_file.name)
1242
1243 def test_basic(self):
1244 # Given an EXE in a directory, it should be returned.
1245 rv = shutil.which(self.file, path=self.dir)
1246 self.assertEqual(rv, self.temp_file.name)
1247
1248 def test_full_path_short_circuit(self):
1249 # When given the fully qualified path to an executable that exists,
1250 # it should be returned.
1251 rv = shutil.which(self.temp_file.name, path=self.temp_dir)
1252 self.assertEqual(self.temp_file.name, rv)
1253
1254 def test_non_matching_mode(self):
1255 # Set the file read-only and ask for writeable files.
1256 os.chmod(self.temp_file.name, stat.S_IREAD)
1257 rv = shutil.which(self.file, path=self.dir, mode=os.W_OK)
1258 self.assertIsNone(rv)
1259
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001260 def test_relative(self):
1261 old_cwd = os.getcwd()
1262 base_dir, tail_dir = os.path.split(self.dir)
1263 os.chdir(base_dir)
1264 try:
1265 rv = shutil.which(self.file, path=tail_dir)
1266 self.assertEqual(rv, os.path.join(tail_dir, self.file))
1267 finally:
1268 os.chdir(old_cwd)
1269
Brian Curtinc57a3452012-06-22 16:00:30 -05001270 def test_nonexistent_file(self):
1271 # Return None when no matching executable file is found on the path.
1272 rv = shutil.which("foo.exe", path=self.dir)
1273 self.assertIsNone(rv)
1274
1275 @unittest.skipUnless(sys.platform == "win32",
1276 "pathext check is Windows-only")
1277 def test_pathext_checking(self):
1278 # Ask for the file without the ".exe" extension, then ensure that
1279 # it gets found properly with the extension.
1280 rv = shutil.which(self.temp_file.name[:-4], path=self.dir)
1281 self.assertEqual(self.temp_file.name, rv)
1282
1283
Christian Heimesada8c3b2008-03-18 18:26:33 +00001284class TestMove(unittest.TestCase):
1285
1286 def setUp(self):
1287 filename = "foo"
1288 self.src_dir = tempfile.mkdtemp()
1289 self.dst_dir = tempfile.mkdtemp()
1290 self.src_file = os.path.join(self.src_dir, filename)
1291 self.dst_file = os.path.join(self.dst_dir, filename)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001292 with open(self.src_file, "wb") as f:
1293 f.write(b"spam")
1294
1295 def tearDown(self):
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001296 for d in (self.src_dir, self.dst_dir):
Christian Heimesada8c3b2008-03-18 18:26:33 +00001297 try:
1298 if d:
1299 shutil.rmtree(d)
1300 except:
1301 pass
1302
1303 def _check_move_file(self, src, dst, real_dst):
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001304 with open(src, "rb") as f:
1305 contents = f.read()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001306 shutil.move(src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001307 with open(real_dst, "rb") as f:
1308 self.assertEqual(contents, f.read())
Christian Heimesada8c3b2008-03-18 18:26:33 +00001309 self.assertFalse(os.path.exists(src))
1310
1311 def _check_move_dir(self, src, dst, real_dst):
1312 contents = sorted(os.listdir(src))
1313 shutil.move(src, dst)
1314 self.assertEqual(contents, sorted(os.listdir(real_dst)))
1315 self.assertFalse(os.path.exists(src))
1316
1317 def test_move_file(self):
1318 # Move a file to another location on the same filesystem.
1319 self._check_move_file(self.src_file, self.dst_file, self.dst_file)
1320
1321 def test_move_file_to_dir(self):
1322 # Move a file inside an existing dir on the same filesystem.
1323 self._check_move_file(self.src_file, self.dst_dir, self.dst_file)
1324
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001325 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001326 def test_move_file_other_fs(self):
1327 # Move a file to an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001328 self.test_move_file()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001329
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001330 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001331 def test_move_file_to_dir_other_fs(self):
1332 # Move a file to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001333 self.test_move_file_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001334
1335 def test_move_dir(self):
1336 # Move a dir to another location on the same filesystem.
1337 dst_dir = tempfile.mktemp()
1338 try:
1339 self._check_move_dir(self.src_dir, dst_dir, dst_dir)
1340 finally:
1341 try:
1342 shutil.rmtree(dst_dir)
1343 except:
1344 pass
1345
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001346 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001347 def test_move_dir_other_fs(self):
1348 # Move a dir to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001349 self.test_move_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001350
1351 def test_move_dir_to_dir(self):
1352 # Move a dir inside an existing dir on the same filesystem.
1353 self._check_move_dir(self.src_dir, self.dst_dir,
1354 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1355
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001356 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001357 def test_move_dir_to_dir_other_fs(self):
1358 # Move a dir inside an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001359 self.test_move_dir_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001360
1361 def test_existing_file_inside_dest_dir(self):
1362 # A file with the same name inside the destination dir already exists.
1363 with open(self.dst_file, "wb"):
1364 pass
1365 self.assertRaises(shutil.Error, shutil.move, self.src_file, self.dst_dir)
1366
1367 def test_dont_move_dir_in_itself(self):
1368 # Moving a dir inside itself raises an Error.
1369 dst = os.path.join(self.src_dir, "bar")
1370 self.assertRaises(shutil.Error, shutil.move, self.src_dir, dst)
1371
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001372 def test_destinsrc_false_negative(self):
1373 os.mkdir(TESTFN)
1374 try:
1375 for src, dst in [('srcdir', 'srcdir/dest')]:
1376 src = os.path.join(TESTFN, src)
1377 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001378 self.assertTrue(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001379 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001380 'dst (%s) is not in src (%s)' % (dst, src))
1381 finally:
1382 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001383
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001384 def test_destinsrc_false_positive(self):
1385 os.mkdir(TESTFN)
1386 try:
1387 for src, dst in [('srcdir', 'src/dest'), ('srcdir', 'srcdir.new')]:
1388 src = os.path.join(TESTFN, src)
1389 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001390 self.assertFalse(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001391 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001392 'dst (%s) is in src (%s)' % (dst, src))
1393 finally:
1394 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimes9bd667a2008-01-20 15:14:11 +00001395
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +01001396 @support.skip_unless_symlink
1397 @mock_rename
1398 def test_move_file_symlink(self):
1399 dst = os.path.join(self.src_dir, 'bar')
1400 os.symlink(self.src_file, dst)
1401 shutil.move(dst, self.dst_file)
1402 self.assertTrue(os.path.islink(self.dst_file))
1403 self.assertTrue(os.path.samefile(self.src_file, self.dst_file))
1404
1405 @support.skip_unless_symlink
1406 @mock_rename
1407 def test_move_file_symlink_to_dir(self):
1408 filename = "bar"
1409 dst = os.path.join(self.src_dir, filename)
1410 os.symlink(self.src_file, dst)
1411 shutil.move(dst, self.dst_dir)
1412 final_link = os.path.join(self.dst_dir, filename)
1413 self.assertTrue(os.path.islink(final_link))
1414 self.assertTrue(os.path.samefile(self.src_file, final_link))
1415
1416 @support.skip_unless_symlink
1417 @mock_rename
1418 def test_move_dangling_symlink(self):
1419 src = os.path.join(self.src_dir, 'baz')
1420 dst = os.path.join(self.src_dir, 'bar')
1421 os.symlink(src, dst)
1422 dst_link = os.path.join(self.dst_dir, 'quux')
1423 shutil.move(dst, dst_link)
1424 self.assertTrue(os.path.islink(dst_link))
1425 self.assertEqual(os.path.realpath(src), os.path.realpath(dst_link))
1426
1427 @support.skip_unless_symlink
1428 @mock_rename
1429 def test_move_dir_symlink(self):
1430 src = os.path.join(self.src_dir, 'baz')
1431 dst = os.path.join(self.src_dir, 'bar')
1432 os.mkdir(src)
1433 os.symlink(src, dst)
1434 dst_link = os.path.join(self.dst_dir, 'quux')
1435 shutil.move(dst, dst_link)
1436 self.assertTrue(os.path.islink(dst_link))
1437 self.assertTrue(os.path.samefile(src, dst_link))
1438
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001439 def test_move_return_value(self):
1440 rv = shutil.move(self.src_file, self.dst_dir)
1441 self.assertEqual(rv,
1442 os.path.join(self.dst_dir, os.path.basename(self.src_file)))
1443
1444 def test_move_as_rename_return_value(self):
1445 rv = shutil.move(self.src_file, os.path.join(self.dst_dir, 'bar'))
1446 self.assertEqual(rv, os.path.join(self.dst_dir, 'bar'))
1447
Tarek Ziadé5340db32010-04-19 22:30:51 +00001448
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001449class TestCopyFile(unittest.TestCase):
1450
1451 _delete = False
1452
1453 class Faux(object):
1454 _entered = False
1455 _exited_with = None
1456 _raised = False
1457 def __init__(self, raise_in_exit=False, suppress_at_exit=True):
1458 self._raise_in_exit = raise_in_exit
1459 self._suppress_at_exit = suppress_at_exit
1460 def read(self, *args):
1461 return ''
1462 def __enter__(self):
1463 self._entered = True
1464 def __exit__(self, exc_type, exc_val, exc_tb):
1465 self._exited_with = exc_type, exc_val, exc_tb
1466 if self._raise_in_exit:
1467 self._raised = True
1468 raise IOError("Cannot close")
1469 return self._suppress_at_exit
1470
1471 def tearDown(self):
1472 if self._delete:
1473 del shutil.open
1474
1475 def _set_shutil_open(self, func):
1476 shutil.open = func
1477 self._delete = True
1478
1479 def test_w_source_open_fails(self):
1480 def _open(filename, mode='r'):
1481 if filename == 'srcfile':
1482 raise IOError('Cannot open "srcfile"')
1483 assert 0 # shouldn't reach here.
1484
1485 self._set_shutil_open(_open)
1486
1487 self.assertRaises(IOError, shutil.copyfile, 'srcfile', 'destfile')
1488
1489 def test_w_dest_open_fails(self):
1490
1491 srcfile = self.Faux()
1492
1493 def _open(filename, mode='r'):
1494 if filename == 'srcfile':
1495 return srcfile
1496 if filename == 'destfile':
1497 raise IOError('Cannot open "destfile"')
1498 assert 0 # shouldn't reach here.
1499
1500 self._set_shutil_open(_open)
1501
1502 shutil.copyfile('srcfile', 'destfile')
1503 self.assertTrue(srcfile._entered)
1504 self.assertTrue(srcfile._exited_with[0] is IOError)
1505 self.assertEqual(srcfile._exited_with[1].args,
1506 ('Cannot open "destfile"',))
1507
1508 def test_w_dest_close_fails(self):
1509
1510 srcfile = self.Faux()
1511 destfile = self.Faux(True)
1512
1513 def _open(filename, mode='r'):
1514 if filename == 'srcfile':
1515 return srcfile
1516 if filename == 'destfile':
1517 return destfile
1518 assert 0 # shouldn't reach here.
1519
1520 self._set_shutil_open(_open)
1521
1522 shutil.copyfile('srcfile', 'destfile')
1523 self.assertTrue(srcfile._entered)
1524 self.assertTrue(destfile._entered)
1525 self.assertTrue(destfile._raised)
1526 self.assertTrue(srcfile._exited_with[0] is IOError)
1527 self.assertEqual(srcfile._exited_with[1].args,
1528 ('Cannot close',))
1529
1530 def test_w_source_close_fails(self):
1531
1532 srcfile = self.Faux(True)
1533 destfile = self.Faux()
1534
1535 def _open(filename, mode='r'):
1536 if filename == 'srcfile':
1537 return srcfile
1538 if filename == 'destfile':
1539 return destfile
1540 assert 0 # shouldn't reach here.
1541
1542 self._set_shutil_open(_open)
1543
1544 self.assertRaises(IOError,
1545 shutil.copyfile, 'srcfile', 'destfile')
1546 self.assertTrue(srcfile._entered)
1547 self.assertTrue(destfile._entered)
1548 self.assertFalse(destfile._raised)
1549 self.assertTrue(srcfile._exited_with[0] is None)
1550 self.assertTrue(srcfile._raised)
1551
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001552 def test_move_dir_caseinsensitive(self):
1553 # Renames a folder to the same name
1554 # but a different case.
1555
1556 self.src_dir = tempfile.mkdtemp()
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001557 self.addCleanup(shutil.rmtree, self.src_dir, True)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001558 dst_dir = os.path.join(
1559 os.path.dirname(self.src_dir),
1560 os.path.basename(self.src_dir).upper())
1561 self.assertNotEqual(self.src_dir, dst_dir)
1562
1563 try:
1564 shutil.move(self.src_dir, dst_dir)
1565 self.assertTrue(os.path.isdir(dst_dir))
1566 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +02001567 os.rmdir(dst_dir)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001568
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001569class TermsizeTests(unittest.TestCase):
1570 def test_does_not_crash(self):
1571 """Check if get_terminal_size() returns a meaningful value.
1572
1573 There's no easy portable way to actually check the size of the
1574 terminal, so let's check if it returns something sensible instead.
1575 """
1576 size = shutil.get_terminal_size()
Antoine Pitroucfade362012-02-08 23:48:59 +01001577 self.assertGreaterEqual(size.columns, 0)
1578 self.assertGreaterEqual(size.lines, 0)
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001579
1580 def test_os_environ_first(self):
1581 "Check if environment variables have precedence"
1582
1583 with support.EnvironmentVarGuard() as env:
1584 env['COLUMNS'] = '777'
1585 size = shutil.get_terminal_size()
1586 self.assertEqual(size.columns, 777)
1587
1588 with support.EnvironmentVarGuard() as env:
1589 env['LINES'] = '888'
1590 size = shutil.get_terminal_size()
1591 self.assertEqual(size.lines, 888)
1592
1593 @unittest.skipUnless(os.isatty(sys.__stdout__.fileno()), "not on tty")
1594 def test_stty_match(self):
1595 """Check if stty returns the same results ignoring env
1596
1597 This test will fail if stdin and stdout are connected to
1598 different terminals with different sizes. Nevertheless, such
1599 situations should be pretty rare.
1600 """
1601 try:
1602 size = subprocess.check_output(['stty', 'size']).decode().split()
1603 except (FileNotFoundError, subprocess.CalledProcessError):
1604 self.skipTest("stty invocation failed")
1605 expected = (int(size[1]), int(size[0])) # reversed order
1606
1607 with support.EnvironmentVarGuard() as env:
1608 del env['LINES']
1609 del env['COLUMNS']
1610 actual = shutil.get_terminal_size()
1611
1612 self.assertEqual(expected, actual)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001613
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001614
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001615def test_main():
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001616 support.run_unittest(TestShutil, TestMove, TestCopyFile,
Brian Curtinc57a3452012-06-22 16:00:30 -05001617 TermsizeTests, TestWhich)
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001618
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001619if __name__ == '__main__':
Walter Dörwald21d3a322003-05-01 17:45:56 +00001620 test_main()