blob: cb712b3e61695198aa8cba2b68f5b1e27fb42e69 [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)
280 shutil.copymode(src_link, dst_link, symlinks=True)
281 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)
286 shutil.copymode(src_link, dst, symlinks=True)
287 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)
290 shutil.copymode(src, dst_link, symlinks=True)
291 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)
305 shutil.copymode(src_link, dst_link, symlinks=True) # silent fail
306
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'):
329 shutil.copystat(src_link, dst_link, symlinks=False)
330 self.assertNotEqual(src_link_stat.st_mode, os.stat(dst).st_mode)
331 # don't follow
332 shutil.copystat(src_link, dst_link, symlinks=True)
333 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
344 shutil.copystat(src_link, dst, symlinks=True)
345 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
413 @support.skip_unless_symlink
414 @support.skip_unless_xattr
415 @unittest.skipUnless(hasattr(os, 'geteuid') and os.geteuid() == 0,
416 'root privileges required')
417 def test_copyxattr_symlinks(self):
418 # On Linux, it's only possible to access non-user xattr for symlinks;
419 # which in turn require root privileges. This test should be expanded
420 # as soon as other platforms gain support for extended attributes.
421 tmp_dir = self.mkdtemp()
422 src = os.path.join(tmp_dir, 'foo')
423 src_link = os.path.join(tmp_dir, 'baz')
424 write_file(src, 'foo')
425 os.symlink(src, src_link)
426 os.setxattr(src, 'trusted.foo', b'42')
Larry Hastings9cf065c2012-06-22 16:30:09 -0700427 os.setxattr(src_link, 'trusted.foo', b'43', follow_symlinks=False)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200428 dst = os.path.join(tmp_dir, 'bar')
429 dst_link = os.path.join(tmp_dir, 'qux')
430 write_file(dst, 'bar')
431 os.symlink(dst, dst_link)
432 shutil._copyxattr(src_link, dst_link, symlinks=True)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700433 self.assertEqual(os.getxattr(dst_link, 'trusted.foo', follow_symlinks=False), b'43')
Antoine Pitrou424246f2012-05-12 19:02:01 +0200434 self.assertRaises(OSError, os.getxattr, dst, 'trusted.foo')
435 shutil._copyxattr(src_link, dst, symlinks=True)
436 self.assertEqual(os.getxattr(dst, 'trusted.foo'), b'43')
437
Antoine Pitrou78091e62011-12-29 18:54:15 +0100438 @support.skip_unless_symlink
439 def test_copy_symlinks(self):
440 tmp_dir = self.mkdtemp()
441 src = os.path.join(tmp_dir, 'foo')
442 dst = os.path.join(tmp_dir, 'bar')
443 src_link = os.path.join(tmp_dir, 'baz')
444 write_file(src, 'foo')
445 os.symlink(src, src_link)
446 if hasattr(os, 'lchmod'):
447 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
448 # don't follow
449 shutil.copy(src_link, dst, symlinks=False)
450 self.assertFalse(os.path.islink(dst))
451 self.assertEqual(read_file(src), read_file(dst))
452 os.remove(dst)
453 # follow
454 shutil.copy(src_link, dst, symlinks=True)
455 self.assertTrue(os.path.islink(dst))
456 self.assertEqual(os.readlink(dst), os.readlink(src_link))
457 if hasattr(os, 'lchmod'):
458 self.assertEqual(os.lstat(src_link).st_mode,
459 os.lstat(dst).st_mode)
460
461 @support.skip_unless_symlink
462 def test_copy2_symlinks(self):
463 tmp_dir = self.mkdtemp()
464 src = os.path.join(tmp_dir, 'foo')
465 dst = os.path.join(tmp_dir, 'bar')
466 src_link = os.path.join(tmp_dir, 'baz')
467 write_file(src, 'foo')
468 os.symlink(src, src_link)
469 if hasattr(os, 'lchmod'):
470 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
471 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
472 os.lchflags(src_link, stat.UF_NODUMP)
473 src_stat = os.stat(src)
474 src_link_stat = os.lstat(src_link)
475 # follow
476 shutil.copy2(src_link, dst, symlinks=False)
477 self.assertFalse(os.path.islink(dst))
478 self.assertEqual(read_file(src), read_file(dst))
479 os.remove(dst)
480 # don't follow
481 shutil.copy2(src_link, dst, symlinks=True)
482 self.assertTrue(os.path.islink(dst))
483 self.assertEqual(os.readlink(dst), os.readlink(src_link))
484 dst_stat = os.lstat(dst)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700485 if os.utime in os.supports_follow_symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100486 for attr in 'st_atime', 'st_mtime':
487 # The modification times may be truncated in the new file.
488 self.assertLessEqual(getattr(src_link_stat, attr),
489 getattr(dst_stat, attr) + 1)
490 if hasattr(os, 'lchmod'):
491 self.assertEqual(src_link_stat.st_mode, dst_stat.st_mode)
492 self.assertNotEqual(src_stat.st_mode, dst_stat.st_mode)
493 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
494 self.assertEqual(src_link_stat.st_flags, dst_stat.st_flags)
495
Antoine Pitrou424246f2012-05-12 19:02:01 +0200496 @support.skip_unless_xattr
497 def test_copy2_xattr(self):
498 tmp_dir = self.mkdtemp()
499 src = os.path.join(tmp_dir, 'foo')
500 dst = os.path.join(tmp_dir, 'bar')
501 write_file(src, 'foo')
502 os.setxattr(src, 'user.foo', b'42')
503 shutil.copy2(src, dst)
504 self.assertEqual(
505 os.getxattr(src, 'user.foo'),
506 os.getxattr(dst, 'user.foo'))
507 os.remove(dst)
508
Antoine Pitrou78091e62011-12-29 18:54:15 +0100509 @support.skip_unless_symlink
510 def test_copyfile_symlinks(self):
511 tmp_dir = self.mkdtemp()
512 src = os.path.join(tmp_dir, 'src')
513 dst = os.path.join(tmp_dir, 'dst')
514 dst_link = os.path.join(tmp_dir, 'dst_link')
515 link = os.path.join(tmp_dir, 'link')
516 write_file(src, 'foo')
517 os.symlink(src, link)
518 # don't follow
519 shutil.copyfile(link, dst_link, symlinks=True)
520 self.assertTrue(os.path.islink(dst_link))
521 self.assertEqual(os.readlink(link), os.readlink(dst_link))
522 # follow
523 shutil.copyfile(link, dst)
524 self.assertFalse(os.path.islink(dst))
525
Hynek Schlawack2100b422012-06-23 20:28:32 +0200526 def test_rmtree_uses_safe_fd_version_if_available(self):
527 if os.unlink in os.supports_dir_fd and os.open in os.supports_dir_fd:
528 self.assertTrue(shutil._use_fd_functions)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000529 self.assertTrue(shutil.rmtree.avoids_symlink_attacks)
Hynek Schlawack2100b422012-06-23 20:28:32 +0200530 tmp_dir = self.mkdtemp()
531 d = os.path.join(tmp_dir, 'a')
532 os.mkdir(d)
533 try:
534 real_rmtree = shutil._rmtree_safe_fd
535 class Called(Exception): pass
536 def _raiser(*args, **kwargs):
537 raise Called
538 shutil._rmtree_safe_fd = _raiser
539 self.assertRaises(Called, shutil.rmtree, d)
540 finally:
541 shutil._rmtree_safe_fd = real_rmtree
542 else:
543 self.assertFalse(shutil._use_fd_functions)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000544 self.assertFalse(shutil.rmtree.avoids_symlink_attacks)
Hynek Schlawack2100b422012-06-23 20:28:32 +0200545
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000546 def test_rmtree_dont_delete_file(self):
547 # When called on a file instead of a directory, don't delete it.
548 handle, path = tempfile.mkstemp()
Victor Stinnerbf816222011-06-30 23:25:47 +0200549 os.close(handle)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200550 self.assertRaises(NotADirectoryError, shutil.rmtree, path)
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000551 os.remove(path)
552
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000553 def test_copytree_simple(self):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000554 src_dir = tempfile.mkdtemp()
555 dst_dir = os.path.join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200556 self.addCleanup(shutil.rmtree, src_dir)
557 self.addCleanup(shutil.rmtree, os.path.dirname(dst_dir))
558 write_file((src_dir, 'test.txt'), '123')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000559 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200560 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000561
Éric Araujoa7e33a12011-08-12 19:51:35 +0200562 shutil.copytree(src_dir, dst_dir)
563 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test.txt')))
564 self.assertTrue(os.path.isdir(os.path.join(dst_dir, 'test_dir')))
565 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test_dir',
566 'test.txt')))
567 actual = read_file((dst_dir, 'test.txt'))
568 self.assertEqual(actual, '123')
569 actual = read_file((dst_dir, 'test_dir', 'test.txt'))
570 self.assertEqual(actual, '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000571
Antoine Pitrou78091e62011-12-29 18:54:15 +0100572 @support.skip_unless_symlink
573 def test_copytree_symlinks(self):
574 tmp_dir = self.mkdtemp()
575 src_dir = os.path.join(tmp_dir, 'src')
576 dst_dir = os.path.join(tmp_dir, 'dst')
577 sub_dir = os.path.join(src_dir, 'sub')
578 os.mkdir(src_dir)
579 os.mkdir(sub_dir)
580 write_file((src_dir, 'file.txt'), 'foo')
581 src_link = os.path.join(sub_dir, 'link')
582 dst_link = os.path.join(dst_dir, 'sub/link')
583 os.symlink(os.path.join(src_dir, 'file.txt'),
584 src_link)
585 if hasattr(os, 'lchmod'):
586 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
587 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
588 os.lchflags(src_link, stat.UF_NODUMP)
589 src_stat = os.lstat(src_link)
590 shutil.copytree(src_dir, dst_dir, symlinks=True)
591 self.assertTrue(os.path.islink(os.path.join(dst_dir, 'sub', 'link')))
592 self.assertEqual(os.readlink(os.path.join(dst_dir, 'sub', 'link')),
593 os.path.join(src_dir, 'file.txt'))
594 dst_stat = os.lstat(dst_link)
595 if hasattr(os, 'lchmod'):
596 self.assertEqual(dst_stat.st_mode, src_stat.st_mode)
597 if hasattr(os, 'lchflags'):
598 self.assertEqual(dst_stat.st_flags, src_stat.st_flags)
599
Georg Brandl2ee470f2008-07-16 12:55:28 +0000600 def test_copytree_with_exclude(self):
Georg Brandl2ee470f2008-07-16 12:55:28 +0000601 # creating data
602 join = os.path.join
603 exists = os.path.exists
604 src_dir = tempfile.mkdtemp()
Georg Brandl2ee470f2008-07-16 12:55:28 +0000605 try:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000606 dst_dir = join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200607 write_file((src_dir, 'test.txt'), '123')
608 write_file((src_dir, 'test.tmp'), '123')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000609 os.mkdir(join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200610 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000611 os.mkdir(join(src_dir, 'test_dir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200612 write_file((src_dir, 'test_dir2', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000613 os.mkdir(join(src_dir, 'test_dir2', 'subdir'))
614 os.mkdir(join(src_dir, 'test_dir2', 'subdir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200615 write_file((src_dir, 'test_dir2', 'subdir', 'test.txt'), '456')
616 write_file((src_dir, 'test_dir2', 'subdir2', 'test.py'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000617
618 # testing glob-like patterns
619 try:
620 patterns = shutil.ignore_patterns('*.tmp', 'test_dir2')
621 shutil.copytree(src_dir, dst_dir, ignore=patterns)
622 # checking the result: some elements should not be copied
623 self.assertTrue(exists(join(dst_dir, 'test.txt')))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200624 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
625 self.assertFalse(exists(join(dst_dir, 'test_dir2')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000626 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200627 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000628 try:
629 patterns = shutil.ignore_patterns('*.tmp', 'subdir*')
630 shutil.copytree(src_dir, dst_dir, ignore=patterns)
631 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200632 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
633 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2')))
634 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000635 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200636 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000637
638 # testing callable-style
639 try:
640 def _filter(src, names):
641 res = []
642 for name in names:
643 path = os.path.join(src, name)
644
645 if (os.path.isdir(path) and
646 path.split()[-1] == 'subdir'):
647 res.append(name)
648 elif os.path.splitext(path)[-1] in ('.py'):
649 res.append(name)
650 return res
651
652 shutil.copytree(src_dir, dst_dir, ignore=_filter)
653
654 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200655 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2',
656 'test.py')))
657 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000658
659 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200660 shutil.rmtree(dst_dir)
Georg Brandl2ee470f2008-07-16 12:55:28 +0000661 finally:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000662 shutil.rmtree(src_dir)
663 shutil.rmtree(os.path.dirname(dst_dir))
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000664
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000665 @unittest.skipUnless(hasattr(os, 'link'), 'requires os.link')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000666 def test_dont_copy_file_onto_link_to_itself(self):
Georg Brandl724d0892010-12-05 07:51:39 +0000667 # Temporarily disable test on Windows.
668 if os.name == 'nt':
669 return
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000670 # bug 851123.
671 os.mkdir(TESTFN)
672 src = os.path.join(TESTFN, 'cheese')
673 dst = os.path.join(TESTFN, 'shop')
674 try:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000675 with open(src, 'w') as f:
676 f.write('cheddar')
677 os.link(src, dst)
678 self.assertRaises(shutil.Error, shutil.copyfile, src, dst)
679 with open(src, 'r') as f:
680 self.assertEqual(f.read(), 'cheddar')
681 os.remove(dst)
682 finally:
683 shutil.rmtree(TESTFN, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000684
Brian Curtin3b4499c2010-12-28 14:31:47 +0000685 @support.skip_unless_symlink
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000686 def test_dont_copy_file_onto_symlink_to_itself(self):
687 # bug 851123.
688 os.mkdir(TESTFN)
689 src = os.path.join(TESTFN, 'cheese')
690 dst = os.path.join(TESTFN, 'shop')
691 try:
692 with open(src, 'w') as f:
693 f.write('cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000694 # Using `src` here would mean we end up with a symlink pointing
695 # to TESTFN/TESTFN/cheese, while it should point at
696 # TESTFN/cheese.
697 os.symlink('cheese', dst)
698 self.assertRaises(shutil.Error, shutil.copyfile, src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +0000699 with open(src, 'r') as f:
700 self.assertEqual(f.read(), 'cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000701 os.remove(dst)
702 finally:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000703 shutil.rmtree(TESTFN, ignore_errors=True)
Johannes Gijsbers68128712004-08-14 13:57:08 +0000704
Brian Curtin3b4499c2010-12-28 14:31:47 +0000705 @support.skip_unless_symlink
Brian Curtind40e6f72010-07-08 21:39:08 +0000706 def test_rmtree_on_symlink(self):
707 # bug 1669.
708 os.mkdir(TESTFN)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000709 try:
Brian Curtind40e6f72010-07-08 21:39:08 +0000710 src = os.path.join(TESTFN, 'cheese')
711 dst = os.path.join(TESTFN, 'shop')
712 os.mkdir(src)
713 os.symlink(src, dst)
714 self.assertRaises(OSError, shutil.rmtree, dst)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200715 shutil.rmtree(dst, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000716 finally:
Brian Curtind40e6f72010-07-08 21:39:08 +0000717 shutil.rmtree(TESTFN, ignore_errors=True)
718
719 if hasattr(os, "mkfifo"):
720 # Issue #3002: copyfile and copytree block indefinitely on named pipes
721 def test_copyfile_named_pipe(self):
722 os.mkfifo(TESTFN)
723 try:
724 self.assertRaises(shutil.SpecialFileError,
725 shutil.copyfile, TESTFN, TESTFN2)
726 self.assertRaises(shutil.SpecialFileError,
727 shutil.copyfile, __file__, TESTFN)
728 finally:
729 os.remove(TESTFN)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000730
Brian Curtin3b4499c2010-12-28 14:31:47 +0000731 @support.skip_unless_symlink
Brian Curtin52173d42010-12-02 18:29:18 +0000732 def test_copytree_named_pipe(self):
733 os.mkdir(TESTFN)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000734 try:
Brian Curtin52173d42010-12-02 18:29:18 +0000735 subdir = os.path.join(TESTFN, "subdir")
736 os.mkdir(subdir)
737 pipe = os.path.join(subdir, "mypipe")
738 os.mkfifo(pipe)
739 try:
740 shutil.copytree(TESTFN, TESTFN2)
741 except shutil.Error as e:
742 errors = e.args[0]
743 self.assertEqual(len(errors), 1)
744 src, dst, error_msg = errors[0]
745 self.assertEqual("`%s` is a named pipe" % pipe, error_msg)
746 else:
747 self.fail("shutil.Error should have been raised")
748 finally:
749 shutil.rmtree(TESTFN, ignore_errors=True)
750 shutil.rmtree(TESTFN2, ignore_errors=True)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000751
Tarek Ziadé5340db32010-04-19 22:30:51 +0000752 def test_copytree_special_func(self):
753
754 src_dir = self.mkdtemp()
755 dst_dir = os.path.join(self.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200756 write_file((src_dir, 'test.txt'), '123')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000757 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200758 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000759
760 copied = []
761 def _copy(src, dst):
762 copied.append((src, dst))
763
764 shutil.copytree(src_dir, dst_dir, copy_function=_copy)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000765 self.assertEqual(len(copied), 2)
Tarek Ziadé5340db32010-04-19 22:30:51 +0000766
Brian Curtin3b4499c2010-12-28 14:31:47 +0000767 @support.skip_unless_symlink
Tarek Ziadéfb437512010-04-20 08:57:33 +0000768 def test_copytree_dangling_symlinks(self):
769
770 # a dangling symlink raises an error at the end
771 src_dir = self.mkdtemp()
772 dst_dir = os.path.join(self.mkdtemp(), 'destination')
773 os.symlink('IDONTEXIST', os.path.join(src_dir, 'test.txt'))
774 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200775 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadéfb437512010-04-20 08:57:33 +0000776 self.assertRaises(Error, shutil.copytree, src_dir, dst_dir)
777
778 # a dangling symlink is ignored with the proper flag
779 dst_dir = os.path.join(self.mkdtemp(), 'destination2')
780 shutil.copytree(src_dir, dst_dir, ignore_dangling_symlinks=True)
781 self.assertNotIn('test.txt', os.listdir(dst_dir))
782
783 # a dangling symlink is copied if symlinks=True
784 dst_dir = os.path.join(self.mkdtemp(), 'destination3')
785 shutil.copytree(src_dir, dst_dir, symlinks=True)
786 self.assertIn('test.txt', os.listdir(dst_dir))
787
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400788 def _copy_file(self, method):
789 fname = 'test.txt'
790 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200791 write_file((tmpdir, fname), 'xxx')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400792 file1 = os.path.join(tmpdir, fname)
793 tmpdir2 = self.mkdtemp()
794 method(file1, tmpdir2)
795 file2 = os.path.join(tmpdir2, fname)
796 return (file1, file2)
797
798 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
799 def test_copy(self):
800 # Ensure that the copied file exists and has the same mode bits.
801 file1, file2 = self._copy_file(shutil.copy)
802 self.assertTrue(os.path.exists(file2))
803 self.assertEqual(os.stat(file1).st_mode, os.stat(file2).st_mode)
804
805 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
Senthil Kumaran0c2dba52011-07-03 18:21:38 -0700806 @unittest.skipUnless(hasattr(os, 'utime'), 'requires os.utime')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400807 def test_copy2(self):
808 # Ensure that the copied file exists and has the same mode and
809 # modification time bits.
810 file1, file2 = self._copy_file(shutil.copy2)
811 self.assertTrue(os.path.exists(file2))
812 file1_stat = os.stat(file1)
813 file2_stat = os.stat(file2)
814 self.assertEqual(file1_stat.st_mode, file2_stat.st_mode)
815 for attr in 'st_atime', 'st_mtime':
816 # The modification times may be truncated in the new file.
817 self.assertLessEqual(getattr(file1_stat, attr),
818 getattr(file2_stat, attr) + 1)
819 if hasattr(os, 'chflags') and hasattr(file1_stat, 'st_flags'):
820 self.assertEqual(getattr(file1_stat, 'st_flags'),
821 getattr(file2_stat, 'st_flags'))
822
Ezio Melotti975077a2011-05-19 22:03:22 +0300823 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000824 def test_make_tarball(self):
825 # creating something to tar
826 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200827 write_file((tmpdir, 'file1'), 'xxx')
828 write_file((tmpdir, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000829 os.mkdir(os.path.join(tmpdir, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200830 write_file((tmpdir, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000831
832 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400833 # force shutil to create the directory
834 os.rmdir(tmpdir2)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000835 unittest.skipUnless(splitdrive(tmpdir)[0] == splitdrive(tmpdir2)[0],
836 "source and target should be on same drive")
837
838 base_name = os.path.join(tmpdir2, 'archive')
839
840 # working with relative paths to avoid tar warnings
841 old_dir = os.getcwd()
842 os.chdir(tmpdir)
843 try:
844 _make_tarball(splitdrive(base_name)[1], '.')
845 finally:
846 os.chdir(old_dir)
847
848 # check if the compressed tarball was created
849 tarball = base_name + '.tar.gz'
850 self.assertTrue(os.path.exists(tarball))
851
852 # trying an uncompressed one
853 base_name = os.path.join(tmpdir2, 'archive')
854 old_dir = os.getcwd()
855 os.chdir(tmpdir)
856 try:
857 _make_tarball(splitdrive(base_name)[1], '.', compress=None)
858 finally:
859 os.chdir(old_dir)
860 tarball = base_name + '.tar'
861 self.assertTrue(os.path.exists(tarball))
862
863 def _tarinfo(self, path):
864 tar = tarfile.open(path)
865 try:
866 names = tar.getnames()
867 names.sort()
868 return tuple(names)
869 finally:
870 tar.close()
871
872 def _create_files(self):
873 # creating something to tar
874 tmpdir = self.mkdtemp()
875 dist = os.path.join(tmpdir, 'dist')
876 os.mkdir(dist)
Éric Araujoa7e33a12011-08-12 19:51:35 +0200877 write_file((dist, 'file1'), 'xxx')
878 write_file((dist, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000879 os.mkdir(os.path.join(dist, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200880 write_file((dist, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000881 os.mkdir(os.path.join(dist, 'sub2'))
882 tmpdir2 = self.mkdtemp()
883 base_name = os.path.join(tmpdir2, 'archive')
884 return tmpdir, tmpdir2, base_name
885
Ezio Melotti975077a2011-05-19 22:03:22 +0300886 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000887 @unittest.skipUnless(find_executable('tar') and find_executable('gzip'),
888 'Need the tar command to run')
889 def test_tarfile_vs_tar(self):
890 tmpdir, tmpdir2, base_name = self._create_files()
891 old_dir = os.getcwd()
892 os.chdir(tmpdir)
893 try:
894 _make_tarball(base_name, 'dist')
895 finally:
896 os.chdir(old_dir)
897
898 # check if the compressed tarball was created
899 tarball = base_name + '.tar.gz'
900 self.assertTrue(os.path.exists(tarball))
901
902 # now create another tarball using `tar`
903 tarball2 = os.path.join(tmpdir, 'archive2.tar.gz')
904 tar_cmd = ['tar', '-cf', 'archive2.tar', 'dist']
905 gzip_cmd = ['gzip', '-f9', 'archive2.tar']
906 old_dir = os.getcwd()
907 os.chdir(tmpdir)
908 try:
909 with captured_stdout() as s:
910 spawn(tar_cmd)
911 spawn(gzip_cmd)
912 finally:
913 os.chdir(old_dir)
914
915 self.assertTrue(os.path.exists(tarball2))
916 # let's compare both tarballs
Ezio Melottib3aedd42010-11-20 19:04:17 +0000917 self.assertEqual(self._tarinfo(tarball), self._tarinfo(tarball2))
Tarek Ziadé396fad72010-02-23 05:30:31 +0000918
919 # trying an uncompressed one
920 base_name = os.path.join(tmpdir2, 'archive')
921 old_dir = os.getcwd()
922 os.chdir(tmpdir)
923 try:
924 _make_tarball(base_name, 'dist', compress=None)
925 finally:
926 os.chdir(old_dir)
927 tarball = base_name + '.tar'
928 self.assertTrue(os.path.exists(tarball))
929
930 # now for a dry_run
931 base_name = os.path.join(tmpdir2, 'archive')
932 old_dir = os.getcwd()
933 os.chdir(tmpdir)
934 try:
935 _make_tarball(base_name, 'dist', compress=None, dry_run=True)
936 finally:
937 os.chdir(old_dir)
938 tarball = base_name + '.tar'
939 self.assertTrue(os.path.exists(tarball))
940
Ezio Melotti975077a2011-05-19 22:03:22 +0300941 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000942 @unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run')
943 def test_make_zipfile(self):
944 # creating something to tar
945 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200946 write_file((tmpdir, 'file1'), 'xxx')
947 write_file((tmpdir, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000948
949 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400950 # force shutil to create the directory
951 os.rmdir(tmpdir2)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000952 base_name = os.path.join(tmpdir2, 'archive')
953 _make_zipfile(base_name, tmpdir)
954
955 # check if the compressed tarball was created
956 tarball = base_name + '.zip'
Éric Araujo1c505492010-11-06 02:12:51 +0000957 self.assertTrue(os.path.exists(tarball))
Tarek Ziadé396fad72010-02-23 05:30:31 +0000958
959
960 def test_make_archive(self):
961 tmpdir = self.mkdtemp()
962 base_name = os.path.join(tmpdir, 'archive')
963 self.assertRaises(ValueError, make_archive, base_name, 'xxx')
964
Ezio Melotti975077a2011-05-19 22:03:22 +0300965 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000966 def test_make_archive_owner_group(self):
967 # testing make_archive with owner and group, with various combinations
968 # this works even if there's not gid/uid support
969 if UID_GID_SUPPORT:
970 group = grp.getgrgid(0)[0]
971 owner = pwd.getpwuid(0)[0]
972 else:
973 group = owner = 'root'
974
975 base_dir, root_dir, base_name = self._create_files()
976 base_name = os.path.join(self.mkdtemp() , 'archive')
977 res = make_archive(base_name, 'zip', root_dir, base_dir, owner=owner,
978 group=group)
979 self.assertTrue(os.path.exists(res))
980
981 res = make_archive(base_name, 'zip', root_dir, base_dir)
982 self.assertTrue(os.path.exists(res))
983
984 res = make_archive(base_name, 'tar', root_dir, base_dir,
985 owner=owner, group=group)
986 self.assertTrue(os.path.exists(res))
987
988 res = make_archive(base_name, 'tar', root_dir, base_dir,
989 owner='kjhkjhkjg', group='oihohoh')
990 self.assertTrue(os.path.exists(res))
991
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000992
Ezio Melotti975077a2011-05-19 22:03:22 +0300993 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000994 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
995 def test_tarfile_root_owner(self):
996 tmpdir, tmpdir2, base_name = self._create_files()
997 old_dir = os.getcwd()
998 os.chdir(tmpdir)
999 group = grp.getgrgid(0)[0]
1000 owner = pwd.getpwuid(0)[0]
1001 try:
1002 archive_name = _make_tarball(base_name, 'dist', compress=None,
1003 owner=owner, group=group)
1004 finally:
1005 os.chdir(old_dir)
1006
1007 # check if the compressed tarball was created
1008 self.assertTrue(os.path.exists(archive_name))
1009
1010 # now checks the rights
1011 archive = tarfile.open(archive_name)
1012 try:
1013 for member in archive.getmembers():
Ezio Melottib3aedd42010-11-20 19:04:17 +00001014 self.assertEqual(member.uid, 0)
1015 self.assertEqual(member.gid, 0)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001016 finally:
1017 archive.close()
1018
1019 def test_make_archive_cwd(self):
1020 current_dir = os.getcwd()
1021 def _breaks(*args, **kw):
1022 raise RuntimeError()
1023
1024 register_archive_format('xxx', _breaks, [], 'xxx file')
1025 try:
1026 try:
1027 make_archive('xxx', 'xxx', root_dir=self.mkdtemp())
1028 except Exception:
1029 pass
Ezio Melottib3aedd42010-11-20 19:04:17 +00001030 self.assertEqual(os.getcwd(), current_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001031 finally:
1032 unregister_archive_format('xxx')
1033
1034 def test_register_archive_format(self):
1035
1036 self.assertRaises(TypeError, register_archive_format, 'xxx', 1)
1037 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1038 1)
1039 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1040 [(1, 2), (1, 2, 3)])
1041
1042 register_archive_format('xxx', lambda: x, [(1, 2)], 'xxx file')
1043 formats = [name for name, params in get_archive_formats()]
1044 self.assertIn('xxx', formats)
1045
1046 unregister_archive_format('xxx')
1047 formats = [name for name, params in get_archive_formats()]
1048 self.assertNotIn('xxx', formats)
1049
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001050 def _compare_dirs(self, dir1, dir2):
1051 # check that dir1 and dir2 are equivalent,
1052 # return the diff
1053 diff = []
1054 for root, dirs, files in os.walk(dir1):
1055 for file_ in files:
1056 path = os.path.join(root, file_)
1057 target_path = os.path.join(dir2, os.path.split(path)[-1])
1058 if not os.path.exists(target_path):
1059 diff.append(file_)
1060 return diff
1061
Ezio Melotti975077a2011-05-19 22:03:22 +03001062 @requires_zlib
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001063 def test_unpack_archive(self):
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001064 formats = ['tar', 'gztar', 'zip']
1065 if BZ2_SUPPORTED:
1066 formats.append('bztar')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001067
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001068 for format in formats:
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001069 tmpdir = self.mkdtemp()
1070 base_dir, root_dir, base_name = self._create_files()
1071 tmpdir2 = self.mkdtemp()
1072 filename = make_archive(base_name, format, root_dir, base_dir)
1073
1074 # let's try to unpack it now
1075 unpack_archive(filename, tmpdir2)
1076 diff = self._compare_dirs(tmpdir, tmpdir2)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001077 self.assertEqual(diff, [])
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001078
Nick Coghlanabf202d2011-03-16 13:52:20 -04001079 # and again, this time with the format specified
1080 tmpdir3 = self.mkdtemp()
1081 unpack_archive(filename, tmpdir3, format=format)
1082 diff = self._compare_dirs(tmpdir, tmpdir3)
1083 self.assertEqual(diff, [])
1084 self.assertRaises(shutil.ReadError, unpack_archive, TESTFN)
1085 self.assertRaises(ValueError, unpack_archive, TESTFN, format='xxx')
1086
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001087 def test_unpack_registery(self):
1088
1089 formats = get_unpack_formats()
1090
1091 def _boo(filename, extract_dir, extra):
Ezio Melottib3aedd42010-11-20 19:04:17 +00001092 self.assertEqual(extra, 1)
1093 self.assertEqual(filename, 'stuff.boo')
1094 self.assertEqual(extract_dir, 'xx')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001095
1096 register_unpack_format('Boo', ['.boo', '.b2'], _boo, [('extra', 1)])
1097 unpack_archive('stuff.boo', 'xx')
1098
1099 # trying to register a .boo unpacker again
1100 self.assertRaises(RegistryError, register_unpack_format, 'Boo2',
1101 ['.boo'], _boo)
1102
1103 # should work now
1104 unregister_unpack_format('Boo')
1105 register_unpack_format('Boo2', ['.boo'], _boo)
1106 self.assertIn(('Boo2', ['.boo'], ''), get_unpack_formats())
1107 self.assertNotIn(('Boo', ['.boo'], ''), get_unpack_formats())
1108
1109 # let's leave a clean state
1110 unregister_unpack_format('Boo2')
Ezio Melottib3aedd42010-11-20 19:04:17 +00001111 self.assertEqual(get_unpack_formats(), formats)
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001112
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001113 @unittest.skipUnless(hasattr(shutil, 'disk_usage'),
1114 "disk_usage not available on this platform")
1115 def test_disk_usage(self):
1116 usage = shutil.disk_usage(os.getcwd())
Éric Araujo2ee61882011-07-02 16:45:45 +02001117 self.assertGreater(usage.total, 0)
1118 self.assertGreater(usage.used, 0)
1119 self.assertGreaterEqual(usage.free, 0)
1120 self.assertGreaterEqual(usage.total, usage.used)
1121 self.assertGreater(usage.total, usage.free)
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001122
Sandro Tosid902a142011-08-22 23:28:27 +02001123 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1124 @unittest.skipUnless(hasattr(os, 'chown'), 'requires os.chown')
1125 def test_chown(self):
1126
1127 # cleaned-up automatically by TestShutil.tearDown method
1128 dirname = self.mkdtemp()
1129 filename = tempfile.mktemp(dir=dirname)
1130 write_file(filename, 'testing chown function')
1131
1132 with self.assertRaises(ValueError):
1133 shutil.chown(filename)
1134
1135 with self.assertRaises(LookupError):
1136 shutil.chown(filename, user='non-exising username')
1137
1138 with self.assertRaises(LookupError):
1139 shutil.chown(filename, group='non-exising groupname')
1140
1141 with self.assertRaises(TypeError):
1142 shutil.chown(filename, b'spam')
1143
1144 with self.assertRaises(TypeError):
1145 shutil.chown(filename, 3.14)
1146
1147 uid = os.getuid()
1148 gid = os.getgid()
1149
1150 def check_chown(path, uid=None, gid=None):
1151 s = os.stat(filename)
1152 if uid is not None:
1153 self.assertEqual(uid, s.st_uid)
1154 if gid is not None:
1155 self.assertEqual(gid, s.st_gid)
1156
1157 shutil.chown(filename, uid, gid)
1158 check_chown(filename, uid, gid)
1159 shutil.chown(filename, uid)
1160 check_chown(filename, uid)
1161 shutil.chown(filename, user=uid)
1162 check_chown(filename, uid)
1163 shutil.chown(filename, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001164 check_chown(filename, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001165
1166 shutil.chown(dirname, uid, gid)
1167 check_chown(dirname, uid, gid)
1168 shutil.chown(dirname, uid)
1169 check_chown(dirname, uid)
1170 shutil.chown(dirname, user=uid)
1171 check_chown(dirname, uid)
1172 shutil.chown(dirname, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001173 check_chown(dirname, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001174
1175 user = pwd.getpwuid(uid)[0]
1176 group = grp.getgrgid(gid)[0]
1177 shutil.chown(filename, user, group)
1178 check_chown(filename, uid, gid)
1179 shutil.chown(dirname, user, group)
1180 check_chown(dirname, uid, gid)
1181
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001182 def test_copy_return_value(self):
1183 # copy and copy2 both return their destination path.
1184 for fn in (shutil.copy, shutil.copy2):
1185 src_dir = self.mkdtemp()
1186 dst_dir = self.mkdtemp()
1187 src = os.path.join(src_dir, 'foo')
1188 write_file(src, 'foo')
1189 rv = fn(src, dst_dir)
1190 self.assertEqual(rv, os.path.join(dst_dir, 'foo'))
1191 rv = fn(src, os.path.join(dst_dir, 'bar'))
1192 self.assertEqual(rv, os.path.join(dst_dir, 'bar'))
1193
1194 def test_copyfile_return_value(self):
1195 # copytree returns its destination path.
1196 src_dir = self.mkdtemp()
1197 dst_dir = self.mkdtemp()
1198 dst_file = os.path.join(dst_dir, 'bar')
1199 src_file = os.path.join(src_dir, 'foo')
1200 write_file(src_file, 'foo')
1201 rv = shutil.copyfile(src_file, dst_file)
1202 self.assertTrue(os.path.exists(rv))
1203 self.assertEqual(read_file(src_file), read_file(dst_file))
1204
1205 def test_copytree_return_value(self):
1206 # copytree returns its destination path.
1207 src_dir = self.mkdtemp()
1208 dst_dir = src_dir + "dest"
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001209 self.addCleanup(shutil.rmtree, dst_dir, True)
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001210 src = os.path.join(src_dir, 'foo')
1211 write_file(src, 'foo')
1212 rv = shutil.copytree(src_dir, dst_dir)
1213 self.assertEqual(['foo'], os.listdir(rv))
1214
Christian Heimes9bd667a2008-01-20 15:14:11 +00001215
Brian Curtinc57a3452012-06-22 16:00:30 -05001216class TestWhich(unittest.TestCase):
1217
1218 def setUp(self):
1219 self.temp_dir = tempfile.mkdtemp()
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001220 self.addCleanup(shutil.rmtree, self.temp_dir, True)
Brian Curtinc57a3452012-06-22 16:00:30 -05001221 # Give the temp_file an ".exe" suffix for all.
1222 # It's needed on Windows and not harmful on other platforms.
1223 self.temp_file = tempfile.NamedTemporaryFile(dir=self.temp_dir,
1224 suffix=".exe")
1225 os.chmod(self.temp_file.name, stat.S_IXUSR)
1226 self.addCleanup(self.temp_file.close)
1227 self.dir, self.file = os.path.split(self.temp_file.name)
1228
1229 def test_basic(self):
1230 # Given an EXE in a directory, it should be returned.
1231 rv = shutil.which(self.file, path=self.dir)
1232 self.assertEqual(rv, self.temp_file.name)
1233
1234 def test_full_path_short_circuit(self):
1235 # When given the fully qualified path to an executable that exists,
1236 # it should be returned.
1237 rv = shutil.which(self.temp_file.name, path=self.temp_dir)
1238 self.assertEqual(self.temp_file.name, rv)
1239
1240 def test_non_matching_mode(self):
1241 # Set the file read-only and ask for writeable files.
1242 os.chmod(self.temp_file.name, stat.S_IREAD)
1243 rv = shutil.which(self.file, path=self.dir, mode=os.W_OK)
1244 self.assertIsNone(rv)
1245
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001246 def test_relative(self):
1247 old_cwd = os.getcwd()
1248 base_dir, tail_dir = os.path.split(self.dir)
1249 os.chdir(base_dir)
1250 try:
1251 rv = shutil.which(self.file, path=tail_dir)
1252 self.assertEqual(rv, os.path.join(tail_dir, self.file))
1253 finally:
1254 os.chdir(old_cwd)
1255
Brian Curtinc57a3452012-06-22 16:00:30 -05001256 def test_nonexistent_file(self):
1257 # Return None when no matching executable file is found on the path.
1258 rv = shutil.which("foo.exe", path=self.dir)
1259 self.assertIsNone(rv)
1260
1261 @unittest.skipUnless(sys.platform == "win32",
1262 "pathext check is Windows-only")
1263 def test_pathext_checking(self):
1264 # Ask for the file without the ".exe" extension, then ensure that
1265 # it gets found properly with the extension.
1266 rv = shutil.which(self.temp_file.name[:-4], path=self.dir)
1267 self.assertEqual(self.temp_file.name, rv)
1268
1269
Christian Heimesada8c3b2008-03-18 18:26:33 +00001270class TestMove(unittest.TestCase):
1271
1272 def setUp(self):
1273 filename = "foo"
1274 self.src_dir = tempfile.mkdtemp()
1275 self.dst_dir = tempfile.mkdtemp()
1276 self.src_file = os.path.join(self.src_dir, filename)
1277 self.dst_file = os.path.join(self.dst_dir, filename)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001278 with open(self.src_file, "wb") as f:
1279 f.write(b"spam")
1280
1281 def tearDown(self):
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001282 for d in (self.src_dir, self.dst_dir):
Christian Heimesada8c3b2008-03-18 18:26:33 +00001283 try:
1284 if d:
1285 shutil.rmtree(d)
1286 except:
1287 pass
1288
1289 def _check_move_file(self, src, dst, real_dst):
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001290 with open(src, "rb") as f:
1291 contents = f.read()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001292 shutil.move(src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001293 with open(real_dst, "rb") as f:
1294 self.assertEqual(contents, f.read())
Christian Heimesada8c3b2008-03-18 18:26:33 +00001295 self.assertFalse(os.path.exists(src))
1296
1297 def _check_move_dir(self, src, dst, real_dst):
1298 contents = sorted(os.listdir(src))
1299 shutil.move(src, dst)
1300 self.assertEqual(contents, sorted(os.listdir(real_dst)))
1301 self.assertFalse(os.path.exists(src))
1302
1303 def test_move_file(self):
1304 # Move a file to another location on the same filesystem.
1305 self._check_move_file(self.src_file, self.dst_file, self.dst_file)
1306
1307 def test_move_file_to_dir(self):
1308 # Move a file inside an existing dir on the same filesystem.
1309 self._check_move_file(self.src_file, self.dst_dir, self.dst_file)
1310
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001311 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001312 def test_move_file_other_fs(self):
1313 # Move a file to an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001314 self.test_move_file()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001315
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001316 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001317 def test_move_file_to_dir_other_fs(self):
1318 # Move a file to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001319 self.test_move_file_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001320
1321 def test_move_dir(self):
1322 # Move a dir to another location on the same filesystem.
1323 dst_dir = tempfile.mktemp()
1324 try:
1325 self._check_move_dir(self.src_dir, dst_dir, dst_dir)
1326 finally:
1327 try:
1328 shutil.rmtree(dst_dir)
1329 except:
1330 pass
1331
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001332 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001333 def test_move_dir_other_fs(self):
1334 # Move a dir to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001335 self.test_move_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001336
1337 def test_move_dir_to_dir(self):
1338 # Move a dir inside an existing dir on the same filesystem.
1339 self._check_move_dir(self.src_dir, self.dst_dir,
1340 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1341
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001342 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001343 def test_move_dir_to_dir_other_fs(self):
1344 # Move a dir inside an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001345 self.test_move_dir_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001346
1347 def test_existing_file_inside_dest_dir(self):
1348 # A file with the same name inside the destination dir already exists.
1349 with open(self.dst_file, "wb"):
1350 pass
1351 self.assertRaises(shutil.Error, shutil.move, self.src_file, self.dst_dir)
1352
1353 def test_dont_move_dir_in_itself(self):
1354 # Moving a dir inside itself raises an Error.
1355 dst = os.path.join(self.src_dir, "bar")
1356 self.assertRaises(shutil.Error, shutil.move, self.src_dir, dst)
1357
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001358 def test_destinsrc_false_negative(self):
1359 os.mkdir(TESTFN)
1360 try:
1361 for src, dst in [('srcdir', 'srcdir/dest')]:
1362 src = os.path.join(TESTFN, src)
1363 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001364 self.assertTrue(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001365 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001366 'dst (%s) is not in src (%s)' % (dst, src))
1367 finally:
1368 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001369
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001370 def test_destinsrc_false_positive(self):
1371 os.mkdir(TESTFN)
1372 try:
1373 for src, dst in [('srcdir', 'src/dest'), ('srcdir', 'srcdir.new')]:
1374 src = os.path.join(TESTFN, src)
1375 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001376 self.assertFalse(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001377 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001378 'dst (%s) is in src (%s)' % (dst, src))
1379 finally:
1380 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimes9bd667a2008-01-20 15:14:11 +00001381
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +01001382 @support.skip_unless_symlink
1383 @mock_rename
1384 def test_move_file_symlink(self):
1385 dst = os.path.join(self.src_dir, 'bar')
1386 os.symlink(self.src_file, dst)
1387 shutil.move(dst, self.dst_file)
1388 self.assertTrue(os.path.islink(self.dst_file))
1389 self.assertTrue(os.path.samefile(self.src_file, self.dst_file))
1390
1391 @support.skip_unless_symlink
1392 @mock_rename
1393 def test_move_file_symlink_to_dir(self):
1394 filename = "bar"
1395 dst = os.path.join(self.src_dir, filename)
1396 os.symlink(self.src_file, dst)
1397 shutil.move(dst, self.dst_dir)
1398 final_link = os.path.join(self.dst_dir, filename)
1399 self.assertTrue(os.path.islink(final_link))
1400 self.assertTrue(os.path.samefile(self.src_file, final_link))
1401
1402 @support.skip_unless_symlink
1403 @mock_rename
1404 def test_move_dangling_symlink(self):
1405 src = os.path.join(self.src_dir, 'baz')
1406 dst = os.path.join(self.src_dir, 'bar')
1407 os.symlink(src, dst)
1408 dst_link = os.path.join(self.dst_dir, 'quux')
1409 shutil.move(dst, dst_link)
1410 self.assertTrue(os.path.islink(dst_link))
1411 self.assertEqual(os.path.realpath(src), os.path.realpath(dst_link))
1412
1413 @support.skip_unless_symlink
1414 @mock_rename
1415 def test_move_dir_symlink(self):
1416 src = os.path.join(self.src_dir, 'baz')
1417 dst = os.path.join(self.src_dir, 'bar')
1418 os.mkdir(src)
1419 os.symlink(src, dst)
1420 dst_link = os.path.join(self.dst_dir, 'quux')
1421 shutil.move(dst, dst_link)
1422 self.assertTrue(os.path.islink(dst_link))
1423 self.assertTrue(os.path.samefile(src, dst_link))
1424
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001425 def test_move_return_value(self):
1426 rv = shutil.move(self.src_file, self.dst_dir)
1427 self.assertEqual(rv,
1428 os.path.join(self.dst_dir, os.path.basename(self.src_file)))
1429
1430 def test_move_as_rename_return_value(self):
1431 rv = shutil.move(self.src_file, os.path.join(self.dst_dir, 'bar'))
1432 self.assertEqual(rv, os.path.join(self.dst_dir, 'bar'))
1433
Tarek Ziadé5340db32010-04-19 22:30:51 +00001434
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001435class TestCopyFile(unittest.TestCase):
1436
1437 _delete = False
1438
1439 class Faux(object):
1440 _entered = False
1441 _exited_with = None
1442 _raised = False
1443 def __init__(self, raise_in_exit=False, suppress_at_exit=True):
1444 self._raise_in_exit = raise_in_exit
1445 self._suppress_at_exit = suppress_at_exit
1446 def read(self, *args):
1447 return ''
1448 def __enter__(self):
1449 self._entered = True
1450 def __exit__(self, exc_type, exc_val, exc_tb):
1451 self._exited_with = exc_type, exc_val, exc_tb
1452 if self._raise_in_exit:
1453 self._raised = True
1454 raise IOError("Cannot close")
1455 return self._suppress_at_exit
1456
1457 def tearDown(self):
1458 if self._delete:
1459 del shutil.open
1460
1461 def _set_shutil_open(self, func):
1462 shutil.open = func
1463 self._delete = True
1464
1465 def test_w_source_open_fails(self):
1466 def _open(filename, mode='r'):
1467 if filename == 'srcfile':
1468 raise IOError('Cannot open "srcfile"')
1469 assert 0 # shouldn't reach here.
1470
1471 self._set_shutil_open(_open)
1472
1473 self.assertRaises(IOError, shutil.copyfile, 'srcfile', 'destfile')
1474
1475 def test_w_dest_open_fails(self):
1476
1477 srcfile = self.Faux()
1478
1479 def _open(filename, mode='r'):
1480 if filename == 'srcfile':
1481 return srcfile
1482 if filename == 'destfile':
1483 raise IOError('Cannot open "destfile"')
1484 assert 0 # shouldn't reach here.
1485
1486 self._set_shutil_open(_open)
1487
1488 shutil.copyfile('srcfile', 'destfile')
1489 self.assertTrue(srcfile._entered)
1490 self.assertTrue(srcfile._exited_with[0] is IOError)
1491 self.assertEqual(srcfile._exited_with[1].args,
1492 ('Cannot open "destfile"',))
1493
1494 def test_w_dest_close_fails(self):
1495
1496 srcfile = self.Faux()
1497 destfile = self.Faux(True)
1498
1499 def _open(filename, mode='r'):
1500 if filename == 'srcfile':
1501 return srcfile
1502 if filename == 'destfile':
1503 return destfile
1504 assert 0 # shouldn't reach here.
1505
1506 self._set_shutil_open(_open)
1507
1508 shutil.copyfile('srcfile', 'destfile')
1509 self.assertTrue(srcfile._entered)
1510 self.assertTrue(destfile._entered)
1511 self.assertTrue(destfile._raised)
1512 self.assertTrue(srcfile._exited_with[0] is IOError)
1513 self.assertEqual(srcfile._exited_with[1].args,
1514 ('Cannot close',))
1515
1516 def test_w_source_close_fails(self):
1517
1518 srcfile = self.Faux(True)
1519 destfile = self.Faux()
1520
1521 def _open(filename, mode='r'):
1522 if filename == 'srcfile':
1523 return srcfile
1524 if filename == 'destfile':
1525 return destfile
1526 assert 0 # shouldn't reach here.
1527
1528 self._set_shutil_open(_open)
1529
1530 self.assertRaises(IOError,
1531 shutil.copyfile, 'srcfile', 'destfile')
1532 self.assertTrue(srcfile._entered)
1533 self.assertTrue(destfile._entered)
1534 self.assertFalse(destfile._raised)
1535 self.assertTrue(srcfile._exited_with[0] is None)
1536 self.assertTrue(srcfile._raised)
1537
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001538 def test_move_dir_caseinsensitive(self):
1539 # Renames a folder to the same name
1540 # but a different case.
1541
1542 self.src_dir = tempfile.mkdtemp()
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001543 self.addCleanup(shutil.rmtree, self.src_dir, True)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001544 dst_dir = os.path.join(
1545 os.path.dirname(self.src_dir),
1546 os.path.basename(self.src_dir).upper())
1547 self.assertNotEqual(self.src_dir, dst_dir)
1548
1549 try:
1550 shutil.move(self.src_dir, dst_dir)
1551 self.assertTrue(os.path.isdir(dst_dir))
1552 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +02001553 os.rmdir(dst_dir)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001554
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001555class TermsizeTests(unittest.TestCase):
1556 def test_does_not_crash(self):
1557 """Check if get_terminal_size() returns a meaningful value.
1558
1559 There's no easy portable way to actually check the size of the
1560 terminal, so let's check if it returns something sensible instead.
1561 """
1562 size = shutil.get_terminal_size()
Antoine Pitroucfade362012-02-08 23:48:59 +01001563 self.assertGreaterEqual(size.columns, 0)
1564 self.assertGreaterEqual(size.lines, 0)
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001565
1566 def test_os_environ_first(self):
1567 "Check if environment variables have precedence"
1568
1569 with support.EnvironmentVarGuard() as env:
1570 env['COLUMNS'] = '777'
1571 size = shutil.get_terminal_size()
1572 self.assertEqual(size.columns, 777)
1573
1574 with support.EnvironmentVarGuard() as env:
1575 env['LINES'] = '888'
1576 size = shutil.get_terminal_size()
1577 self.assertEqual(size.lines, 888)
1578
1579 @unittest.skipUnless(os.isatty(sys.__stdout__.fileno()), "not on tty")
1580 def test_stty_match(self):
1581 """Check if stty returns the same results ignoring env
1582
1583 This test will fail if stdin and stdout are connected to
1584 different terminals with different sizes. Nevertheless, such
1585 situations should be pretty rare.
1586 """
1587 try:
1588 size = subprocess.check_output(['stty', 'size']).decode().split()
1589 except (FileNotFoundError, subprocess.CalledProcessError):
1590 self.skipTest("stty invocation failed")
1591 expected = (int(size[1]), int(size[0])) # reversed order
1592
1593 with support.EnvironmentVarGuard() as env:
1594 del env['LINES']
1595 del env['COLUMNS']
1596 actual = shutil.get_terminal_size()
1597
1598 self.assertEqual(expected, actual)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001599
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001600
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001601def test_main():
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001602 support.run_unittest(TestShutil, TestMove, TestCopyFile,
Brian Curtinc57a3452012-06-22 16:00:30 -05001603 TermsizeTests, TestWhich)
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001604
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001605if __name__ == '__main__':
Walter Dörwald21d3a322003-05-01 17:45:56 +00001606 test_main()