blob: a2b6e88afec0ef37bd53cc83134779f4b702a0f2 [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):
Hynek Schlawackd0f6e0a2012-06-29 08:28:20 +0200527 _use_fd_functions = ({os.open, os.stat, os.unlink, os.rmdir} <=
528 os.supports_dir_fd and
529 os.listdir in os.supports_fd and
530 os.stat in os.supports_follow_symlinks)
531 if _use_fd_functions:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200532 self.assertTrue(shutil._use_fd_functions)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000533 self.assertTrue(shutil.rmtree.avoids_symlink_attacks)
Hynek Schlawack2100b422012-06-23 20:28:32 +0200534 tmp_dir = self.mkdtemp()
535 d = os.path.join(tmp_dir, 'a')
536 os.mkdir(d)
537 try:
538 real_rmtree = shutil._rmtree_safe_fd
539 class Called(Exception): pass
540 def _raiser(*args, **kwargs):
541 raise Called
542 shutil._rmtree_safe_fd = _raiser
543 self.assertRaises(Called, shutil.rmtree, d)
544 finally:
545 shutil._rmtree_safe_fd = real_rmtree
546 else:
547 self.assertFalse(shutil._use_fd_functions)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000548 self.assertFalse(shutil.rmtree.avoids_symlink_attacks)
Hynek Schlawack2100b422012-06-23 20:28:32 +0200549
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000550 def test_rmtree_dont_delete_file(self):
551 # When called on a file instead of a directory, don't delete it.
552 handle, path = tempfile.mkstemp()
Victor Stinnerbf816222011-06-30 23:25:47 +0200553 os.close(handle)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200554 self.assertRaises(NotADirectoryError, shutil.rmtree, path)
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000555 os.remove(path)
556
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000557 def test_copytree_simple(self):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000558 src_dir = tempfile.mkdtemp()
559 dst_dir = os.path.join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200560 self.addCleanup(shutil.rmtree, src_dir)
561 self.addCleanup(shutil.rmtree, os.path.dirname(dst_dir))
562 write_file((src_dir, 'test.txt'), '123')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000563 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200564 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000565
Éric Araujoa7e33a12011-08-12 19:51:35 +0200566 shutil.copytree(src_dir, dst_dir)
567 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test.txt')))
568 self.assertTrue(os.path.isdir(os.path.join(dst_dir, 'test_dir')))
569 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test_dir',
570 'test.txt')))
571 actual = read_file((dst_dir, 'test.txt'))
572 self.assertEqual(actual, '123')
573 actual = read_file((dst_dir, 'test_dir', 'test.txt'))
574 self.assertEqual(actual, '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000575
Antoine Pitrou78091e62011-12-29 18:54:15 +0100576 @support.skip_unless_symlink
577 def test_copytree_symlinks(self):
578 tmp_dir = self.mkdtemp()
579 src_dir = os.path.join(tmp_dir, 'src')
580 dst_dir = os.path.join(tmp_dir, 'dst')
581 sub_dir = os.path.join(src_dir, 'sub')
582 os.mkdir(src_dir)
583 os.mkdir(sub_dir)
584 write_file((src_dir, 'file.txt'), 'foo')
585 src_link = os.path.join(sub_dir, 'link')
586 dst_link = os.path.join(dst_dir, 'sub/link')
587 os.symlink(os.path.join(src_dir, 'file.txt'),
588 src_link)
589 if hasattr(os, 'lchmod'):
590 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
591 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
592 os.lchflags(src_link, stat.UF_NODUMP)
593 src_stat = os.lstat(src_link)
594 shutil.copytree(src_dir, dst_dir, symlinks=True)
595 self.assertTrue(os.path.islink(os.path.join(dst_dir, 'sub', 'link')))
596 self.assertEqual(os.readlink(os.path.join(dst_dir, 'sub', 'link')),
597 os.path.join(src_dir, 'file.txt'))
598 dst_stat = os.lstat(dst_link)
599 if hasattr(os, 'lchmod'):
600 self.assertEqual(dst_stat.st_mode, src_stat.st_mode)
601 if hasattr(os, 'lchflags'):
602 self.assertEqual(dst_stat.st_flags, src_stat.st_flags)
603
Georg Brandl2ee470f2008-07-16 12:55:28 +0000604 def test_copytree_with_exclude(self):
Georg Brandl2ee470f2008-07-16 12:55:28 +0000605 # creating data
606 join = os.path.join
607 exists = os.path.exists
608 src_dir = tempfile.mkdtemp()
Georg Brandl2ee470f2008-07-16 12:55:28 +0000609 try:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000610 dst_dir = join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200611 write_file((src_dir, 'test.txt'), '123')
612 write_file((src_dir, 'test.tmp'), '123')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000613 os.mkdir(join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200614 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000615 os.mkdir(join(src_dir, 'test_dir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200616 write_file((src_dir, 'test_dir2', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000617 os.mkdir(join(src_dir, 'test_dir2', 'subdir'))
618 os.mkdir(join(src_dir, 'test_dir2', 'subdir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200619 write_file((src_dir, 'test_dir2', 'subdir', 'test.txt'), '456')
620 write_file((src_dir, 'test_dir2', 'subdir2', 'test.py'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000621
622 # testing glob-like patterns
623 try:
624 patterns = shutil.ignore_patterns('*.tmp', 'test_dir2')
625 shutil.copytree(src_dir, dst_dir, ignore=patterns)
626 # checking the result: some elements should not be copied
627 self.assertTrue(exists(join(dst_dir, 'test.txt')))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200628 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
629 self.assertFalse(exists(join(dst_dir, 'test_dir2')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000630 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200631 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000632 try:
633 patterns = shutil.ignore_patterns('*.tmp', 'subdir*')
634 shutil.copytree(src_dir, dst_dir, ignore=patterns)
635 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200636 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
637 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2')))
638 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000639 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200640 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000641
642 # testing callable-style
643 try:
644 def _filter(src, names):
645 res = []
646 for name in names:
647 path = os.path.join(src, name)
648
649 if (os.path.isdir(path) and
650 path.split()[-1] == 'subdir'):
651 res.append(name)
652 elif os.path.splitext(path)[-1] in ('.py'):
653 res.append(name)
654 return res
655
656 shutil.copytree(src_dir, dst_dir, ignore=_filter)
657
658 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200659 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2',
660 'test.py')))
661 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000662
663 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200664 shutil.rmtree(dst_dir)
Georg Brandl2ee470f2008-07-16 12:55:28 +0000665 finally:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000666 shutil.rmtree(src_dir)
667 shutil.rmtree(os.path.dirname(dst_dir))
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000668
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000669 @unittest.skipUnless(hasattr(os, 'link'), 'requires os.link')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000670 def test_dont_copy_file_onto_link_to_itself(self):
Georg Brandl724d0892010-12-05 07:51:39 +0000671 # Temporarily disable test on Windows.
672 if os.name == 'nt':
673 return
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000674 # bug 851123.
675 os.mkdir(TESTFN)
676 src = os.path.join(TESTFN, 'cheese')
677 dst = os.path.join(TESTFN, 'shop')
678 try:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000679 with open(src, 'w') as f:
680 f.write('cheddar')
681 os.link(src, dst)
682 self.assertRaises(shutil.Error, shutil.copyfile, src, dst)
683 with open(src, 'r') as f:
684 self.assertEqual(f.read(), 'cheddar')
685 os.remove(dst)
686 finally:
687 shutil.rmtree(TESTFN, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000688
Brian Curtin3b4499c2010-12-28 14:31:47 +0000689 @support.skip_unless_symlink
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000690 def test_dont_copy_file_onto_symlink_to_itself(self):
691 # bug 851123.
692 os.mkdir(TESTFN)
693 src = os.path.join(TESTFN, 'cheese')
694 dst = os.path.join(TESTFN, 'shop')
695 try:
696 with open(src, 'w') as f:
697 f.write('cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000698 # Using `src` here would mean we end up with a symlink pointing
699 # to TESTFN/TESTFN/cheese, while it should point at
700 # TESTFN/cheese.
701 os.symlink('cheese', dst)
702 self.assertRaises(shutil.Error, shutil.copyfile, src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +0000703 with open(src, 'r') as f:
704 self.assertEqual(f.read(), 'cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000705 os.remove(dst)
706 finally:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000707 shutil.rmtree(TESTFN, ignore_errors=True)
Johannes Gijsbers68128712004-08-14 13:57:08 +0000708
Brian Curtin3b4499c2010-12-28 14:31:47 +0000709 @support.skip_unless_symlink
Brian Curtind40e6f72010-07-08 21:39:08 +0000710 def test_rmtree_on_symlink(self):
711 # bug 1669.
712 os.mkdir(TESTFN)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000713 try:
Brian Curtind40e6f72010-07-08 21:39:08 +0000714 src = os.path.join(TESTFN, 'cheese')
715 dst = os.path.join(TESTFN, 'shop')
716 os.mkdir(src)
717 os.symlink(src, dst)
718 self.assertRaises(OSError, shutil.rmtree, dst)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200719 shutil.rmtree(dst, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000720 finally:
Brian Curtind40e6f72010-07-08 21:39:08 +0000721 shutil.rmtree(TESTFN, ignore_errors=True)
722
723 if hasattr(os, "mkfifo"):
724 # Issue #3002: copyfile and copytree block indefinitely on named pipes
725 def test_copyfile_named_pipe(self):
726 os.mkfifo(TESTFN)
727 try:
728 self.assertRaises(shutil.SpecialFileError,
729 shutil.copyfile, TESTFN, TESTFN2)
730 self.assertRaises(shutil.SpecialFileError,
731 shutil.copyfile, __file__, TESTFN)
732 finally:
733 os.remove(TESTFN)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000734
Brian Curtin3b4499c2010-12-28 14:31:47 +0000735 @support.skip_unless_symlink
Brian Curtin52173d42010-12-02 18:29:18 +0000736 def test_copytree_named_pipe(self):
737 os.mkdir(TESTFN)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000738 try:
Brian Curtin52173d42010-12-02 18:29:18 +0000739 subdir = os.path.join(TESTFN, "subdir")
740 os.mkdir(subdir)
741 pipe = os.path.join(subdir, "mypipe")
742 os.mkfifo(pipe)
743 try:
744 shutil.copytree(TESTFN, TESTFN2)
745 except shutil.Error as e:
746 errors = e.args[0]
747 self.assertEqual(len(errors), 1)
748 src, dst, error_msg = errors[0]
749 self.assertEqual("`%s` is a named pipe" % pipe, error_msg)
750 else:
751 self.fail("shutil.Error should have been raised")
752 finally:
753 shutil.rmtree(TESTFN, ignore_errors=True)
754 shutil.rmtree(TESTFN2, ignore_errors=True)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000755
Tarek Ziadé5340db32010-04-19 22:30:51 +0000756 def test_copytree_special_func(self):
757
758 src_dir = self.mkdtemp()
759 dst_dir = os.path.join(self.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200760 write_file((src_dir, 'test.txt'), '123')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000761 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200762 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000763
764 copied = []
765 def _copy(src, dst):
766 copied.append((src, dst))
767
768 shutil.copytree(src_dir, dst_dir, copy_function=_copy)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000769 self.assertEqual(len(copied), 2)
Tarek Ziadé5340db32010-04-19 22:30:51 +0000770
Brian Curtin3b4499c2010-12-28 14:31:47 +0000771 @support.skip_unless_symlink
Tarek Ziadéfb437512010-04-20 08:57:33 +0000772 def test_copytree_dangling_symlinks(self):
773
774 # a dangling symlink raises an error at the end
775 src_dir = self.mkdtemp()
776 dst_dir = os.path.join(self.mkdtemp(), 'destination')
777 os.symlink('IDONTEXIST', os.path.join(src_dir, 'test.txt'))
778 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200779 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadéfb437512010-04-20 08:57:33 +0000780 self.assertRaises(Error, shutil.copytree, src_dir, dst_dir)
781
782 # a dangling symlink is ignored with the proper flag
783 dst_dir = os.path.join(self.mkdtemp(), 'destination2')
784 shutil.copytree(src_dir, dst_dir, ignore_dangling_symlinks=True)
785 self.assertNotIn('test.txt', os.listdir(dst_dir))
786
787 # a dangling symlink is copied if symlinks=True
788 dst_dir = os.path.join(self.mkdtemp(), 'destination3')
789 shutil.copytree(src_dir, dst_dir, symlinks=True)
790 self.assertIn('test.txt', os.listdir(dst_dir))
791
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400792 def _copy_file(self, method):
793 fname = 'test.txt'
794 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200795 write_file((tmpdir, fname), 'xxx')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400796 file1 = os.path.join(tmpdir, fname)
797 tmpdir2 = self.mkdtemp()
798 method(file1, tmpdir2)
799 file2 = os.path.join(tmpdir2, fname)
800 return (file1, file2)
801
802 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
803 def test_copy(self):
804 # Ensure that the copied file exists and has the same mode bits.
805 file1, file2 = self._copy_file(shutil.copy)
806 self.assertTrue(os.path.exists(file2))
807 self.assertEqual(os.stat(file1).st_mode, os.stat(file2).st_mode)
808
809 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
Senthil Kumaran0c2dba52011-07-03 18:21:38 -0700810 @unittest.skipUnless(hasattr(os, 'utime'), 'requires os.utime')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400811 def test_copy2(self):
812 # Ensure that the copied file exists and has the same mode and
813 # modification time bits.
814 file1, file2 = self._copy_file(shutil.copy2)
815 self.assertTrue(os.path.exists(file2))
816 file1_stat = os.stat(file1)
817 file2_stat = os.stat(file2)
818 self.assertEqual(file1_stat.st_mode, file2_stat.st_mode)
819 for attr in 'st_atime', 'st_mtime':
820 # The modification times may be truncated in the new file.
821 self.assertLessEqual(getattr(file1_stat, attr),
822 getattr(file2_stat, attr) + 1)
823 if hasattr(os, 'chflags') and hasattr(file1_stat, 'st_flags'):
824 self.assertEqual(getattr(file1_stat, 'st_flags'),
825 getattr(file2_stat, 'st_flags'))
826
Ezio Melotti975077a2011-05-19 22:03:22 +0300827 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000828 def test_make_tarball(self):
829 # creating something to tar
830 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200831 write_file((tmpdir, 'file1'), 'xxx')
832 write_file((tmpdir, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000833 os.mkdir(os.path.join(tmpdir, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200834 write_file((tmpdir, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000835
836 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400837 # force shutil to create the directory
838 os.rmdir(tmpdir2)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000839 unittest.skipUnless(splitdrive(tmpdir)[0] == splitdrive(tmpdir2)[0],
840 "source and target should be on same drive")
841
842 base_name = os.path.join(tmpdir2, 'archive')
843
844 # working with relative paths to avoid tar warnings
845 old_dir = os.getcwd()
846 os.chdir(tmpdir)
847 try:
848 _make_tarball(splitdrive(base_name)[1], '.')
849 finally:
850 os.chdir(old_dir)
851
852 # check if the compressed tarball was created
853 tarball = base_name + '.tar.gz'
854 self.assertTrue(os.path.exists(tarball))
855
856 # trying an uncompressed one
857 base_name = os.path.join(tmpdir2, 'archive')
858 old_dir = os.getcwd()
859 os.chdir(tmpdir)
860 try:
861 _make_tarball(splitdrive(base_name)[1], '.', compress=None)
862 finally:
863 os.chdir(old_dir)
864 tarball = base_name + '.tar'
865 self.assertTrue(os.path.exists(tarball))
866
867 def _tarinfo(self, path):
868 tar = tarfile.open(path)
869 try:
870 names = tar.getnames()
871 names.sort()
872 return tuple(names)
873 finally:
874 tar.close()
875
876 def _create_files(self):
877 # creating something to tar
878 tmpdir = self.mkdtemp()
879 dist = os.path.join(tmpdir, 'dist')
880 os.mkdir(dist)
Éric Araujoa7e33a12011-08-12 19:51:35 +0200881 write_file((dist, 'file1'), 'xxx')
882 write_file((dist, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000883 os.mkdir(os.path.join(dist, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200884 write_file((dist, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000885 os.mkdir(os.path.join(dist, 'sub2'))
886 tmpdir2 = self.mkdtemp()
887 base_name = os.path.join(tmpdir2, 'archive')
888 return tmpdir, tmpdir2, base_name
889
Ezio Melotti975077a2011-05-19 22:03:22 +0300890 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000891 @unittest.skipUnless(find_executable('tar') and find_executable('gzip'),
892 'Need the tar command to run')
893 def test_tarfile_vs_tar(self):
894 tmpdir, tmpdir2, base_name = self._create_files()
895 old_dir = os.getcwd()
896 os.chdir(tmpdir)
897 try:
898 _make_tarball(base_name, 'dist')
899 finally:
900 os.chdir(old_dir)
901
902 # check if the compressed tarball was created
903 tarball = base_name + '.tar.gz'
904 self.assertTrue(os.path.exists(tarball))
905
906 # now create another tarball using `tar`
907 tarball2 = os.path.join(tmpdir, 'archive2.tar.gz')
908 tar_cmd = ['tar', '-cf', 'archive2.tar', 'dist']
909 gzip_cmd = ['gzip', '-f9', 'archive2.tar']
910 old_dir = os.getcwd()
911 os.chdir(tmpdir)
912 try:
913 with captured_stdout() as s:
914 spawn(tar_cmd)
915 spawn(gzip_cmd)
916 finally:
917 os.chdir(old_dir)
918
919 self.assertTrue(os.path.exists(tarball2))
920 # let's compare both tarballs
Ezio Melottib3aedd42010-11-20 19:04:17 +0000921 self.assertEqual(self._tarinfo(tarball), self._tarinfo(tarball2))
Tarek Ziadé396fad72010-02-23 05:30:31 +0000922
923 # trying an uncompressed one
924 base_name = os.path.join(tmpdir2, 'archive')
925 old_dir = os.getcwd()
926 os.chdir(tmpdir)
927 try:
928 _make_tarball(base_name, 'dist', compress=None)
929 finally:
930 os.chdir(old_dir)
931 tarball = base_name + '.tar'
932 self.assertTrue(os.path.exists(tarball))
933
934 # now for a dry_run
935 base_name = os.path.join(tmpdir2, 'archive')
936 old_dir = os.getcwd()
937 os.chdir(tmpdir)
938 try:
939 _make_tarball(base_name, 'dist', compress=None, dry_run=True)
940 finally:
941 os.chdir(old_dir)
942 tarball = base_name + '.tar'
943 self.assertTrue(os.path.exists(tarball))
944
Ezio Melotti975077a2011-05-19 22:03:22 +0300945 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000946 @unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run')
947 def test_make_zipfile(self):
948 # creating something to tar
949 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200950 write_file((tmpdir, 'file1'), 'xxx')
951 write_file((tmpdir, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000952
953 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400954 # force shutil to create the directory
955 os.rmdir(tmpdir2)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000956 base_name = os.path.join(tmpdir2, 'archive')
957 _make_zipfile(base_name, tmpdir)
958
959 # check if the compressed tarball was created
960 tarball = base_name + '.zip'
Éric Araujo1c505492010-11-06 02:12:51 +0000961 self.assertTrue(os.path.exists(tarball))
Tarek Ziadé396fad72010-02-23 05:30:31 +0000962
963
964 def test_make_archive(self):
965 tmpdir = self.mkdtemp()
966 base_name = os.path.join(tmpdir, 'archive')
967 self.assertRaises(ValueError, make_archive, base_name, 'xxx')
968
Ezio Melotti975077a2011-05-19 22:03:22 +0300969 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000970 def test_make_archive_owner_group(self):
971 # testing make_archive with owner and group, with various combinations
972 # this works even if there's not gid/uid support
973 if UID_GID_SUPPORT:
974 group = grp.getgrgid(0)[0]
975 owner = pwd.getpwuid(0)[0]
976 else:
977 group = owner = 'root'
978
979 base_dir, root_dir, base_name = self._create_files()
980 base_name = os.path.join(self.mkdtemp() , 'archive')
981 res = make_archive(base_name, 'zip', root_dir, base_dir, owner=owner,
982 group=group)
983 self.assertTrue(os.path.exists(res))
984
985 res = make_archive(base_name, 'zip', root_dir, base_dir)
986 self.assertTrue(os.path.exists(res))
987
988 res = make_archive(base_name, 'tar', root_dir, base_dir,
989 owner=owner, group=group)
990 self.assertTrue(os.path.exists(res))
991
992 res = make_archive(base_name, 'tar', root_dir, base_dir,
993 owner='kjhkjhkjg', group='oihohoh')
994 self.assertTrue(os.path.exists(res))
995
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000996
Ezio Melotti975077a2011-05-19 22:03:22 +0300997 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000998 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
999 def test_tarfile_root_owner(self):
1000 tmpdir, tmpdir2, base_name = self._create_files()
1001 old_dir = os.getcwd()
1002 os.chdir(tmpdir)
1003 group = grp.getgrgid(0)[0]
1004 owner = pwd.getpwuid(0)[0]
1005 try:
1006 archive_name = _make_tarball(base_name, 'dist', compress=None,
1007 owner=owner, group=group)
1008 finally:
1009 os.chdir(old_dir)
1010
1011 # check if the compressed tarball was created
1012 self.assertTrue(os.path.exists(archive_name))
1013
1014 # now checks the rights
1015 archive = tarfile.open(archive_name)
1016 try:
1017 for member in archive.getmembers():
Ezio Melottib3aedd42010-11-20 19:04:17 +00001018 self.assertEqual(member.uid, 0)
1019 self.assertEqual(member.gid, 0)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001020 finally:
1021 archive.close()
1022
1023 def test_make_archive_cwd(self):
1024 current_dir = os.getcwd()
1025 def _breaks(*args, **kw):
1026 raise RuntimeError()
1027
1028 register_archive_format('xxx', _breaks, [], 'xxx file')
1029 try:
1030 try:
1031 make_archive('xxx', 'xxx', root_dir=self.mkdtemp())
1032 except Exception:
1033 pass
Ezio Melottib3aedd42010-11-20 19:04:17 +00001034 self.assertEqual(os.getcwd(), current_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001035 finally:
1036 unregister_archive_format('xxx')
1037
1038 def test_register_archive_format(self):
1039
1040 self.assertRaises(TypeError, register_archive_format, 'xxx', 1)
1041 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1042 1)
1043 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1044 [(1, 2), (1, 2, 3)])
1045
1046 register_archive_format('xxx', lambda: x, [(1, 2)], 'xxx file')
1047 formats = [name for name, params in get_archive_formats()]
1048 self.assertIn('xxx', formats)
1049
1050 unregister_archive_format('xxx')
1051 formats = [name for name, params in get_archive_formats()]
1052 self.assertNotIn('xxx', formats)
1053
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001054 def _compare_dirs(self, dir1, dir2):
1055 # check that dir1 and dir2 are equivalent,
1056 # return the diff
1057 diff = []
1058 for root, dirs, files in os.walk(dir1):
1059 for file_ in files:
1060 path = os.path.join(root, file_)
1061 target_path = os.path.join(dir2, os.path.split(path)[-1])
1062 if not os.path.exists(target_path):
1063 diff.append(file_)
1064 return diff
1065
Ezio Melotti975077a2011-05-19 22:03:22 +03001066 @requires_zlib
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001067 def test_unpack_archive(self):
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001068 formats = ['tar', 'gztar', 'zip']
1069 if BZ2_SUPPORTED:
1070 formats.append('bztar')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001071
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001072 for format in formats:
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001073 tmpdir = self.mkdtemp()
1074 base_dir, root_dir, base_name = self._create_files()
1075 tmpdir2 = self.mkdtemp()
1076 filename = make_archive(base_name, format, root_dir, base_dir)
1077
1078 # let's try to unpack it now
1079 unpack_archive(filename, tmpdir2)
1080 diff = self._compare_dirs(tmpdir, tmpdir2)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001081 self.assertEqual(diff, [])
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001082
Nick Coghlanabf202d2011-03-16 13:52:20 -04001083 # and again, this time with the format specified
1084 tmpdir3 = self.mkdtemp()
1085 unpack_archive(filename, tmpdir3, format=format)
1086 diff = self._compare_dirs(tmpdir, tmpdir3)
1087 self.assertEqual(diff, [])
1088 self.assertRaises(shutil.ReadError, unpack_archive, TESTFN)
1089 self.assertRaises(ValueError, unpack_archive, TESTFN, format='xxx')
1090
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001091 def test_unpack_registery(self):
1092
1093 formats = get_unpack_formats()
1094
1095 def _boo(filename, extract_dir, extra):
Ezio Melottib3aedd42010-11-20 19:04:17 +00001096 self.assertEqual(extra, 1)
1097 self.assertEqual(filename, 'stuff.boo')
1098 self.assertEqual(extract_dir, 'xx')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001099
1100 register_unpack_format('Boo', ['.boo', '.b2'], _boo, [('extra', 1)])
1101 unpack_archive('stuff.boo', 'xx')
1102
1103 # trying to register a .boo unpacker again
1104 self.assertRaises(RegistryError, register_unpack_format, 'Boo2',
1105 ['.boo'], _boo)
1106
1107 # should work now
1108 unregister_unpack_format('Boo')
1109 register_unpack_format('Boo2', ['.boo'], _boo)
1110 self.assertIn(('Boo2', ['.boo'], ''), get_unpack_formats())
1111 self.assertNotIn(('Boo', ['.boo'], ''), get_unpack_formats())
1112
1113 # let's leave a clean state
1114 unregister_unpack_format('Boo2')
Ezio Melottib3aedd42010-11-20 19:04:17 +00001115 self.assertEqual(get_unpack_formats(), formats)
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001116
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001117 @unittest.skipUnless(hasattr(shutil, 'disk_usage'),
1118 "disk_usage not available on this platform")
1119 def test_disk_usage(self):
1120 usage = shutil.disk_usage(os.getcwd())
Éric Araujo2ee61882011-07-02 16:45:45 +02001121 self.assertGreater(usage.total, 0)
1122 self.assertGreater(usage.used, 0)
1123 self.assertGreaterEqual(usage.free, 0)
1124 self.assertGreaterEqual(usage.total, usage.used)
1125 self.assertGreater(usage.total, usage.free)
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001126
Sandro Tosid902a142011-08-22 23:28:27 +02001127 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1128 @unittest.skipUnless(hasattr(os, 'chown'), 'requires os.chown')
1129 def test_chown(self):
1130
1131 # cleaned-up automatically by TestShutil.tearDown method
1132 dirname = self.mkdtemp()
1133 filename = tempfile.mktemp(dir=dirname)
1134 write_file(filename, 'testing chown function')
1135
1136 with self.assertRaises(ValueError):
1137 shutil.chown(filename)
1138
1139 with self.assertRaises(LookupError):
1140 shutil.chown(filename, user='non-exising username')
1141
1142 with self.assertRaises(LookupError):
1143 shutil.chown(filename, group='non-exising groupname')
1144
1145 with self.assertRaises(TypeError):
1146 shutil.chown(filename, b'spam')
1147
1148 with self.assertRaises(TypeError):
1149 shutil.chown(filename, 3.14)
1150
1151 uid = os.getuid()
1152 gid = os.getgid()
1153
1154 def check_chown(path, uid=None, gid=None):
1155 s = os.stat(filename)
1156 if uid is not None:
1157 self.assertEqual(uid, s.st_uid)
1158 if gid is not None:
1159 self.assertEqual(gid, s.st_gid)
1160
1161 shutil.chown(filename, uid, gid)
1162 check_chown(filename, uid, gid)
1163 shutil.chown(filename, uid)
1164 check_chown(filename, uid)
1165 shutil.chown(filename, user=uid)
1166 check_chown(filename, uid)
1167 shutil.chown(filename, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001168 check_chown(filename, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001169
1170 shutil.chown(dirname, uid, gid)
1171 check_chown(dirname, uid, gid)
1172 shutil.chown(dirname, uid)
1173 check_chown(dirname, uid)
1174 shutil.chown(dirname, user=uid)
1175 check_chown(dirname, uid)
1176 shutil.chown(dirname, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001177 check_chown(dirname, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001178
1179 user = pwd.getpwuid(uid)[0]
1180 group = grp.getgrgid(gid)[0]
1181 shutil.chown(filename, user, group)
1182 check_chown(filename, uid, gid)
1183 shutil.chown(dirname, user, group)
1184 check_chown(dirname, uid, gid)
1185
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001186 def test_copy_return_value(self):
1187 # copy and copy2 both return their destination path.
1188 for fn in (shutil.copy, shutil.copy2):
1189 src_dir = self.mkdtemp()
1190 dst_dir = self.mkdtemp()
1191 src = os.path.join(src_dir, 'foo')
1192 write_file(src, 'foo')
1193 rv = fn(src, dst_dir)
1194 self.assertEqual(rv, os.path.join(dst_dir, 'foo'))
1195 rv = fn(src, os.path.join(dst_dir, 'bar'))
1196 self.assertEqual(rv, os.path.join(dst_dir, 'bar'))
1197
1198 def test_copyfile_return_value(self):
1199 # copytree returns its destination path.
1200 src_dir = self.mkdtemp()
1201 dst_dir = self.mkdtemp()
1202 dst_file = os.path.join(dst_dir, 'bar')
1203 src_file = os.path.join(src_dir, 'foo')
1204 write_file(src_file, 'foo')
1205 rv = shutil.copyfile(src_file, dst_file)
1206 self.assertTrue(os.path.exists(rv))
1207 self.assertEqual(read_file(src_file), read_file(dst_file))
1208
1209 def test_copytree_return_value(self):
1210 # copytree returns its destination path.
1211 src_dir = self.mkdtemp()
1212 dst_dir = src_dir + "dest"
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001213 self.addCleanup(shutil.rmtree, dst_dir, True)
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001214 src = os.path.join(src_dir, 'foo')
1215 write_file(src, 'foo')
1216 rv = shutil.copytree(src_dir, dst_dir)
1217 self.assertEqual(['foo'], os.listdir(rv))
1218
Christian Heimes9bd667a2008-01-20 15:14:11 +00001219
Brian Curtinc57a3452012-06-22 16:00:30 -05001220class TestWhich(unittest.TestCase):
1221
1222 def setUp(self):
1223 self.temp_dir = tempfile.mkdtemp()
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001224 self.addCleanup(shutil.rmtree, self.temp_dir, True)
Brian Curtinc57a3452012-06-22 16:00:30 -05001225 # Give the temp_file an ".exe" suffix for all.
1226 # It's needed on Windows and not harmful on other platforms.
1227 self.temp_file = tempfile.NamedTemporaryFile(dir=self.temp_dir,
1228 suffix=".exe")
1229 os.chmod(self.temp_file.name, stat.S_IXUSR)
1230 self.addCleanup(self.temp_file.close)
1231 self.dir, self.file = os.path.split(self.temp_file.name)
1232
1233 def test_basic(self):
1234 # Given an EXE in a directory, it should be returned.
1235 rv = shutil.which(self.file, path=self.dir)
1236 self.assertEqual(rv, self.temp_file.name)
1237
1238 def test_full_path_short_circuit(self):
1239 # When given the fully qualified path to an executable that exists,
1240 # it should be returned.
1241 rv = shutil.which(self.temp_file.name, path=self.temp_dir)
1242 self.assertEqual(self.temp_file.name, rv)
1243
1244 def test_non_matching_mode(self):
1245 # Set the file read-only and ask for writeable files.
1246 os.chmod(self.temp_file.name, stat.S_IREAD)
1247 rv = shutil.which(self.file, path=self.dir, mode=os.W_OK)
1248 self.assertIsNone(rv)
1249
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001250 def test_relative(self):
1251 old_cwd = os.getcwd()
1252 base_dir, tail_dir = os.path.split(self.dir)
1253 os.chdir(base_dir)
1254 try:
1255 rv = shutil.which(self.file, path=tail_dir)
1256 self.assertEqual(rv, os.path.join(tail_dir, self.file))
1257 finally:
1258 os.chdir(old_cwd)
1259
Brian Curtinc57a3452012-06-22 16:00:30 -05001260 def test_nonexistent_file(self):
1261 # Return None when no matching executable file is found on the path.
1262 rv = shutil.which("foo.exe", path=self.dir)
1263 self.assertIsNone(rv)
1264
1265 @unittest.skipUnless(sys.platform == "win32",
1266 "pathext check is Windows-only")
1267 def test_pathext_checking(self):
1268 # Ask for the file without the ".exe" extension, then ensure that
1269 # it gets found properly with the extension.
1270 rv = shutil.which(self.temp_file.name[:-4], path=self.dir)
1271 self.assertEqual(self.temp_file.name, rv)
1272
1273
Christian Heimesada8c3b2008-03-18 18:26:33 +00001274class TestMove(unittest.TestCase):
1275
1276 def setUp(self):
1277 filename = "foo"
1278 self.src_dir = tempfile.mkdtemp()
1279 self.dst_dir = tempfile.mkdtemp()
1280 self.src_file = os.path.join(self.src_dir, filename)
1281 self.dst_file = os.path.join(self.dst_dir, filename)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001282 with open(self.src_file, "wb") as f:
1283 f.write(b"spam")
1284
1285 def tearDown(self):
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001286 for d in (self.src_dir, self.dst_dir):
Christian Heimesada8c3b2008-03-18 18:26:33 +00001287 try:
1288 if d:
1289 shutil.rmtree(d)
1290 except:
1291 pass
1292
1293 def _check_move_file(self, src, dst, real_dst):
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001294 with open(src, "rb") as f:
1295 contents = f.read()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001296 shutil.move(src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001297 with open(real_dst, "rb") as f:
1298 self.assertEqual(contents, f.read())
Christian Heimesada8c3b2008-03-18 18:26:33 +00001299 self.assertFalse(os.path.exists(src))
1300
1301 def _check_move_dir(self, src, dst, real_dst):
1302 contents = sorted(os.listdir(src))
1303 shutil.move(src, dst)
1304 self.assertEqual(contents, sorted(os.listdir(real_dst)))
1305 self.assertFalse(os.path.exists(src))
1306
1307 def test_move_file(self):
1308 # Move a file to another location on the same filesystem.
1309 self._check_move_file(self.src_file, self.dst_file, self.dst_file)
1310
1311 def test_move_file_to_dir(self):
1312 # Move a file inside an existing dir on the same filesystem.
1313 self._check_move_file(self.src_file, self.dst_dir, self.dst_file)
1314
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001315 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001316 def test_move_file_other_fs(self):
1317 # Move a file to an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001318 self.test_move_file()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001319
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001320 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001321 def test_move_file_to_dir_other_fs(self):
1322 # Move a file to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001323 self.test_move_file_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001324
1325 def test_move_dir(self):
1326 # Move a dir to another location on the same filesystem.
1327 dst_dir = tempfile.mktemp()
1328 try:
1329 self._check_move_dir(self.src_dir, dst_dir, dst_dir)
1330 finally:
1331 try:
1332 shutil.rmtree(dst_dir)
1333 except:
1334 pass
1335
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001336 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001337 def test_move_dir_other_fs(self):
1338 # Move a dir to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001339 self.test_move_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001340
1341 def test_move_dir_to_dir(self):
1342 # Move a dir inside an existing dir on the same filesystem.
1343 self._check_move_dir(self.src_dir, self.dst_dir,
1344 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1345
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001346 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001347 def test_move_dir_to_dir_other_fs(self):
1348 # Move a dir inside an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001349 self.test_move_dir_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001350
1351 def test_existing_file_inside_dest_dir(self):
1352 # A file with the same name inside the destination dir already exists.
1353 with open(self.dst_file, "wb"):
1354 pass
1355 self.assertRaises(shutil.Error, shutil.move, self.src_file, self.dst_dir)
1356
1357 def test_dont_move_dir_in_itself(self):
1358 # Moving a dir inside itself raises an Error.
1359 dst = os.path.join(self.src_dir, "bar")
1360 self.assertRaises(shutil.Error, shutil.move, self.src_dir, dst)
1361
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001362 def test_destinsrc_false_negative(self):
1363 os.mkdir(TESTFN)
1364 try:
1365 for src, dst in [('srcdir', 'srcdir/dest')]:
1366 src = os.path.join(TESTFN, src)
1367 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001368 self.assertTrue(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001369 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001370 'dst (%s) is not in src (%s)' % (dst, src))
1371 finally:
1372 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001373
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001374 def test_destinsrc_false_positive(self):
1375 os.mkdir(TESTFN)
1376 try:
1377 for src, dst in [('srcdir', 'src/dest'), ('srcdir', 'srcdir.new')]:
1378 src = os.path.join(TESTFN, src)
1379 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001380 self.assertFalse(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001381 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001382 'dst (%s) is in src (%s)' % (dst, src))
1383 finally:
1384 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimes9bd667a2008-01-20 15:14:11 +00001385
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +01001386 @support.skip_unless_symlink
1387 @mock_rename
1388 def test_move_file_symlink(self):
1389 dst = os.path.join(self.src_dir, 'bar')
1390 os.symlink(self.src_file, dst)
1391 shutil.move(dst, self.dst_file)
1392 self.assertTrue(os.path.islink(self.dst_file))
1393 self.assertTrue(os.path.samefile(self.src_file, self.dst_file))
1394
1395 @support.skip_unless_symlink
1396 @mock_rename
1397 def test_move_file_symlink_to_dir(self):
1398 filename = "bar"
1399 dst = os.path.join(self.src_dir, filename)
1400 os.symlink(self.src_file, dst)
1401 shutil.move(dst, self.dst_dir)
1402 final_link = os.path.join(self.dst_dir, filename)
1403 self.assertTrue(os.path.islink(final_link))
1404 self.assertTrue(os.path.samefile(self.src_file, final_link))
1405
1406 @support.skip_unless_symlink
1407 @mock_rename
1408 def test_move_dangling_symlink(self):
1409 src = os.path.join(self.src_dir, 'baz')
1410 dst = os.path.join(self.src_dir, 'bar')
1411 os.symlink(src, dst)
1412 dst_link = os.path.join(self.dst_dir, 'quux')
1413 shutil.move(dst, dst_link)
1414 self.assertTrue(os.path.islink(dst_link))
1415 self.assertEqual(os.path.realpath(src), os.path.realpath(dst_link))
1416
1417 @support.skip_unless_symlink
1418 @mock_rename
1419 def test_move_dir_symlink(self):
1420 src = os.path.join(self.src_dir, 'baz')
1421 dst = os.path.join(self.src_dir, 'bar')
1422 os.mkdir(src)
1423 os.symlink(src, dst)
1424 dst_link = os.path.join(self.dst_dir, 'quux')
1425 shutil.move(dst, dst_link)
1426 self.assertTrue(os.path.islink(dst_link))
1427 self.assertTrue(os.path.samefile(src, dst_link))
1428
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001429 def test_move_return_value(self):
1430 rv = shutil.move(self.src_file, self.dst_dir)
1431 self.assertEqual(rv,
1432 os.path.join(self.dst_dir, os.path.basename(self.src_file)))
1433
1434 def test_move_as_rename_return_value(self):
1435 rv = shutil.move(self.src_file, os.path.join(self.dst_dir, 'bar'))
1436 self.assertEqual(rv, os.path.join(self.dst_dir, 'bar'))
1437
Tarek Ziadé5340db32010-04-19 22:30:51 +00001438
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001439class TestCopyFile(unittest.TestCase):
1440
1441 _delete = False
1442
1443 class Faux(object):
1444 _entered = False
1445 _exited_with = None
1446 _raised = False
1447 def __init__(self, raise_in_exit=False, suppress_at_exit=True):
1448 self._raise_in_exit = raise_in_exit
1449 self._suppress_at_exit = suppress_at_exit
1450 def read(self, *args):
1451 return ''
1452 def __enter__(self):
1453 self._entered = True
1454 def __exit__(self, exc_type, exc_val, exc_tb):
1455 self._exited_with = exc_type, exc_val, exc_tb
1456 if self._raise_in_exit:
1457 self._raised = True
1458 raise IOError("Cannot close")
1459 return self._suppress_at_exit
1460
1461 def tearDown(self):
1462 if self._delete:
1463 del shutil.open
1464
1465 def _set_shutil_open(self, func):
1466 shutil.open = func
1467 self._delete = True
1468
1469 def test_w_source_open_fails(self):
1470 def _open(filename, mode='r'):
1471 if filename == 'srcfile':
1472 raise IOError('Cannot open "srcfile"')
1473 assert 0 # shouldn't reach here.
1474
1475 self._set_shutil_open(_open)
1476
1477 self.assertRaises(IOError, shutil.copyfile, 'srcfile', 'destfile')
1478
1479 def test_w_dest_open_fails(self):
1480
1481 srcfile = self.Faux()
1482
1483 def _open(filename, mode='r'):
1484 if filename == 'srcfile':
1485 return srcfile
1486 if filename == 'destfile':
1487 raise IOError('Cannot open "destfile"')
1488 assert 0 # shouldn't reach here.
1489
1490 self._set_shutil_open(_open)
1491
1492 shutil.copyfile('srcfile', 'destfile')
1493 self.assertTrue(srcfile._entered)
1494 self.assertTrue(srcfile._exited_with[0] is IOError)
1495 self.assertEqual(srcfile._exited_with[1].args,
1496 ('Cannot open "destfile"',))
1497
1498 def test_w_dest_close_fails(self):
1499
1500 srcfile = self.Faux()
1501 destfile = self.Faux(True)
1502
1503 def _open(filename, mode='r'):
1504 if filename == 'srcfile':
1505 return srcfile
1506 if filename == 'destfile':
1507 return destfile
1508 assert 0 # shouldn't reach here.
1509
1510 self._set_shutil_open(_open)
1511
1512 shutil.copyfile('srcfile', 'destfile')
1513 self.assertTrue(srcfile._entered)
1514 self.assertTrue(destfile._entered)
1515 self.assertTrue(destfile._raised)
1516 self.assertTrue(srcfile._exited_with[0] is IOError)
1517 self.assertEqual(srcfile._exited_with[1].args,
1518 ('Cannot close',))
1519
1520 def test_w_source_close_fails(self):
1521
1522 srcfile = self.Faux(True)
1523 destfile = self.Faux()
1524
1525 def _open(filename, mode='r'):
1526 if filename == 'srcfile':
1527 return srcfile
1528 if filename == 'destfile':
1529 return destfile
1530 assert 0 # shouldn't reach here.
1531
1532 self._set_shutil_open(_open)
1533
1534 self.assertRaises(IOError,
1535 shutil.copyfile, 'srcfile', 'destfile')
1536 self.assertTrue(srcfile._entered)
1537 self.assertTrue(destfile._entered)
1538 self.assertFalse(destfile._raised)
1539 self.assertTrue(srcfile._exited_with[0] is None)
1540 self.assertTrue(srcfile._raised)
1541
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001542 def test_move_dir_caseinsensitive(self):
1543 # Renames a folder to the same name
1544 # but a different case.
1545
1546 self.src_dir = tempfile.mkdtemp()
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001547 self.addCleanup(shutil.rmtree, self.src_dir, True)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001548 dst_dir = os.path.join(
1549 os.path.dirname(self.src_dir),
1550 os.path.basename(self.src_dir).upper())
1551 self.assertNotEqual(self.src_dir, dst_dir)
1552
1553 try:
1554 shutil.move(self.src_dir, dst_dir)
1555 self.assertTrue(os.path.isdir(dst_dir))
1556 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +02001557 os.rmdir(dst_dir)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001558
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001559class TermsizeTests(unittest.TestCase):
1560 def test_does_not_crash(self):
1561 """Check if get_terminal_size() returns a meaningful value.
1562
1563 There's no easy portable way to actually check the size of the
1564 terminal, so let's check if it returns something sensible instead.
1565 """
1566 size = shutil.get_terminal_size()
Antoine Pitroucfade362012-02-08 23:48:59 +01001567 self.assertGreaterEqual(size.columns, 0)
1568 self.assertGreaterEqual(size.lines, 0)
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001569
1570 def test_os_environ_first(self):
1571 "Check if environment variables have precedence"
1572
1573 with support.EnvironmentVarGuard() as env:
1574 env['COLUMNS'] = '777'
1575 size = shutil.get_terminal_size()
1576 self.assertEqual(size.columns, 777)
1577
1578 with support.EnvironmentVarGuard() as env:
1579 env['LINES'] = '888'
1580 size = shutil.get_terminal_size()
1581 self.assertEqual(size.lines, 888)
1582
1583 @unittest.skipUnless(os.isatty(sys.__stdout__.fileno()), "not on tty")
1584 def test_stty_match(self):
1585 """Check if stty returns the same results ignoring env
1586
1587 This test will fail if stdin and stdout are connected to
1588 different terminals with different sizes. Nevertheless, such
1589 situations should be pretty rare.
1590 """
1591 try:
1592 size = subprocess.check_output(['stty', 'size']).decode().split()
1593 except (FileNotFoundError, subprocess.CalledProcessError):
1594 self.skipTest("stty invocation failed")
1595 expected = (int(size[1]), int(size[0])) # reversed order
1596
1597 with support.EnvironmentVarGuard() as env:
1598 del env['LINES']
1599 del env['COLUMNS']
1600 actual = shutil.get_terminal_size()
1601
1602 self.assertEqual(expected, actual)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001603
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001604
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001605def test_main():
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001606 support.run_unittest(TestShutil, TestMove, TestCopyFile,
Brian Curtinc57a3452012-06-22 16:00:30 -05001607 TermsizeTests, TestWhich)
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001608
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001609if __name__ == '__main__':
Walter Dörwald21d3a322003-05-01 17:45:56 +00001610 test_main()