blob: b12d2597ba1c23a7d925fc326af58bbb155f2fb4 [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
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000111 def test_rmtree_errors(self):
112 # filename is guaranteed not to exist
113 filename = tempfile.mktemp()
114 self.assertRaises(OSError, shutil.rmtree, filename)
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000115
Johannes Gijsbersb8b09d02004-12-06 20:50:15 +0000116 # See bug #1071513 for why we don't run this on cygwin
117 # and bug #1076467 for why we don't run this as root.
118 if (hasattr(os, 'chmod') and sys.platform[:6] != 'cygwin'
Johannes Gijsbers6b220b02004-12-12 15:52:57 +0000119 and not (hasattr(os, 'geteuid') and os.geteuid() == 0)):
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000120 def test_on_error(self):
121 self.errorState = 0
122 os.mkdir(TESTFN)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200123 self.child_file_path = os.path.join(TESTFN, 'a')
124 self.child_dir_path = os.path.join(TESTFN, 'b')
125 support.create_empty_file(self.child_file_path)
126 os.mkdir(self.child_dir_path)
Tim Peters4590c002004-11-01 02:40:52 +0000127 old_dir_mode = os.stat(TESTFN).st_mode
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200128 old_child_file_mode = os.stat(self.child_file_path).st_mode
129 old_child_dir_mode = os.stat(self.child_dir_path).st_mode
Tim Peters4590c002004-11-01 02:40:52 +0000130 # Make unwritable.
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200131 new_mode = stat.S_IREAD|stat.S_IEXEC
132 os.chmod(self.child_file_path, new_mode)
133 os.chmod(self.child_dir_path, new_mode)
134 os.chmod(TESTFN, new_mode)
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000135
136 shutil.rmtree(TESTFN, onerror=self.check_args_to_onerror)
Johannes Gijsbers8e6f2de2004-11-23 09:27:27 +0000137 # Test whether onerror has actually been called.
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200138 self.assertEqual(self.errorState, 3,
139 "Expected call to onerror function did not "
140 "happen.")
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000141
Tim Peters4590c002004-11-01 02:40:52 +0000142 # Make writable again.
143 os.chmod(TESTFN, old_dir_mode)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200144 os.chmod(self.child_file_path, old_child_file_mode)
145 os.chmod(self.child_dir_path, old_child_dir_mode)
Tim Peters4590c002004-11-01 02:40:52 +0000146
147 # Clean up.
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000148 shutil.rmtree(TESTFN)
149
150 def check_args_to_onerror(self, func, arg, exc):
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000151 # test_rmtree_errors deliberately runs rmtree
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200152 # on a directory that is chmod 500, which will fail.
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000153 # This function is run when shutil.rmtree fails.
154 # 99.9% of the time it initially fails to remove
155 # a file in the directory, so the first time through
156 # func is os.remove.
157 # However, some Linux machines running ZFS on
158 # FUSE experienced a failure earlier in the process
159 # at os.listdir. The first failure may legally
160 # be either.
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200161 if 0 <= self.errorState < 2:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200162 if func is os.unlink:
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200163 self.assertIn(arg, [self.child_file_path, self.child_dir_path])
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000164 else:
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200165 if self.errorState == 1:
166 self.assertEqual(func, os.rmdir)
167 else:
168 self.assertIs(func, os.listdir, "func must be os.listdir")
169 self.assertIn(arg, [TESTFN, self.child_dir_path])
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000170 self.assertTrue(issubclass(exc[0], OSError))
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200171 self.errorState += 1
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000172 else:
173 self.assertEqual(func, os.rmdir)
174 self.assertEqual(arg, TESTFN)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000175 self.assertTrue(issubclass(exc[0], OSError))
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200176 self.errorState = 3
177
178 def test_rmtree_does_not_choke_on_failing_lstat(self):
179 try:
180 orig_lstat = os.lstat
181 def raiser(fn):
182 if fn != TESTFN:
183 raise OSError()
184 else:
185 return orig_lstat(fn)
186 os.lstat = raiser
187
188 os.mkdir(TESTFN)
189 write_file((TESTFN, 'foo'), 'foo')
190 shutil.rmtree(TESTFN)
191 finally:
192 os.lstat = orig_lstat
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000193
Antoine Pitrou78091e62011-12-29 18:54:15 +0100194 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
195 @support.skip_unless_symlink
196 def test_copymode_follow_symlinks(self):
197 tmp_dir = self.mkdtemp()
198 src = os.path.join(tmp_dir, 'foo')
199 dst = os.path.join(tmp_dir, 'bar')
200 src_link = os.path.join(tmp_dir, 'baz')
201 dst_link = os.path.join(tmp_dir, 'quux')
202 write_file(src, 'foo')
203 write_file(dst, 'foo')
204 os.symlink(src, src_link)
205 os.symlink(dst, dst_link)
206 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
207 # file to file
208 os.chmod(dst, stat.S_IRWXO)
209 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
210 shutil.copymode(src, dst)
211 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
212 # follow src link
213 os.chmod(dst, stat.S_IRWXO)
214 shutil.copymode(src_link, dst)
215 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
216 # follow dst link
217 os.chmod(dst, stat.S_IRWXO)
218 shutil.copymode(src, dst_link)
219 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
220 # follow both links
221 os.chmod(dst, stat.S_IRWXO)
222 shutil.copymode(src_link, dst)
223 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
224
225 @unittest.skipUnless(hasattr(os, 'lchmod'), 'requires os.lchmod')
226 @support.skip_unless_symlink
227 def test_copymode_symlink_to_symlink(self):
228 tmp_dir = self.mkdtemp()
229 src = os.path.join(tmp_dir, 'foo')
230 dst = os.path.join(tmp_dir, 'bar')
231 src_link = os.path.join(tmp_dir, 'baz')
232 dst_link = os.path.join(tmp_dir, 'quux')
233 write_file(src, 'foo')
234 write_file(dst, 'foo')
235 os.symlink(src, src_link)
236 os.symlink(dst, dst_link)
237 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
238 os.chmod(dst, stat.S_IRWXU)
239 os.lchmod(src_link, stat.S_IRWXO|stat.S_IRWXG)
240 # link to link
241 os.lchmod(dst_link, stat.S_IRWXO)
242 shutil.copymode(src_link, dst_link, symlinks=True)
243 self.assertEqual(os.lstat(src_link).st_mode,
244 os.lstat(dst_link).st_mode)
245 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
246 # src link - use chmod
247 os.lchmod(dst_link, stat.S_IRWXO)
248 shutil.copymode(src_link, dst, symlinks=True)
249 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
250 # dst link - use chmod
251 os.lchmod(dst_link, stat.S_IRWXO)
252 shutil.copymode(src, dst_link, symlinks=True)
253 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
254
255 @unittest.skipIf(hasattr(os, 'lchmod'), 'requires os.lchmod to be missing')
256 @support.skip_unless_symlink
257 def test_copymode_symlink_to_symlink_wo_lchmod(self):
258 tmp_dir = self.mkdtemp()
259 src = os.path.join(tmp_dir, 'foo')
260 dst = os.path.join(tmp_dir, 'bar')
261 src_link = os.path.join(tmp_dir, 'baz')
262 dst_link = os.path.join(tmp_dir, 'quux')
263 write_file(src, 'foo')
264 write_file(dst, 'foo')
265 os.symlink(src, src_link)
266 os.symlink(dst, dst_link)
267 shutil.copymode(src_link, dst_link, symlinks=True) # silent fail
268
269 @support.skip_unless_symlink
270 def test_copystat_symlinks(self):
271 tmp_dir = self.mkdtemp()
272 src = os.path.join(tmp_dir, 'foo')
273 dst = os.path.join(tmp_dir, 'bar')
274 src_link = os.path.join(tmp_dir, 'baz')
275 dst_link = os.path.join(tmp_dir, 'qux')
276 write_file(src, 'foo')
277 src_stat = os.stat(src)
278 os.utime(src, (src_stat.st_atime,
279 src_stat.st_mtime - 42.0)) # ensure different mtimes
280 write_file(dst, 'bar')
281 self.assertNotEqual(os.stat(src).st_mtime, os.stat(dst).st_mtime)
282 os.symlink(src, src_link)
283 os.symlink(dst, dst_link)
284 if hasattr(os, 'lchmod'):
285 os.lchmod(src_link, stat.S_IRWXO)
286 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
287 os.lchflags(src_link, stat.UF_NODUMP)
288 src_link_stat = os.lstat(src_link)
289 # follow
290 if hasattr(os, 'lchmod'):
291 shutil.copystat(src_link, dst_link, symlinks=False)
292 self.assertNotEqual(src_link_stat.st_mode, os.stat(dst).st_mode)
293 # don't follow
294 shutil.copystat(src_link, dst_link, symlinks=True)
295 dst_link_stat = os.lstat(dst_link)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700296 if os.utime in os.supports_follow_symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100297 for attr in 'st_atime', 'st_mtime':
298 # The modification times may be truncated in the new file.
299 self.assertLessEqual(getattr(src_link_stat, attr),
300 getattr(dst_link_stat, attr) + 1)
301 if hasattr(os, 'lchmod'):
302 self.assertEqual(src_link_stat.st_mode, dst_link_stat.st_mode)
303 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
304 self.assertEqual(src_link_stat.st_flags, dst_link_stat.st_flags)
305 # tell to follow but dst is not a link
306 shutil.copystat(src_link, dst, symlinks=True)
307 self.assertTrue(abs(os.stat(src).st_mtime - os.stat(dst).st_mtime) <
308 00000.1)
309
Ned Deilybaf75712012-05-10 17:05:19 -0700310 @unittest.skipUnless(hasattr(os, 'chflags') and
311 hasattr(errno, 'EOPNOTSUPP') and
312 hasattr(errno, 'ENOTSUP'),
313 "requires os.chflags, EOPNOTSUPP & ENOTSUP")
314 def test_copystat_handles_harmless_chflags_errors(self):
315 tmpdir = self.mkdtemp()
316 file1 = os.path.join(tmpdir, 'file1')
317 file2 = os.path.join(tmpdir, 'file2')
318 write_file(file1, 'xxx')
319 write_file(file2, 'xxx')
320
321 def make_chflags_raiser(err):
322 ex = OSError()
323
Larry Hastings90867a52012-06-22 17:01:41 -0700324 def _chflags_raiser(path, flags, *, follow_symlinks=True):
Ned Deilybaf75712012-05-10 17:05:19 -0700325 ex.errno = err
326 raise ex
327 return _chflags_raiser
328 old_chflags = os.chflags
329 try:
330 for err in errno.EOPNOTSUPP, errno.ENOTSUP:
331 os.chflags = make_chflags_raiser(err)
332 shutil.copystat(file1, file2)
333 # assert others errors break it
334 os.chflags = make_chflags_raiser(errno.EOPNOTSUPP + errno.ENOTSUP)
335 self.assertRaises(OSError, shutil.copystat, file1, file2)
336 finally:
337 os.chflags = old_chflags
338
Antoine Pitrou424246f2012-05-12 19:02:01 +0200339 @support.skip_unless_xattr
340 def test_copyxattr(self):
341 tmp_dir = self.mkdtemp()
342 src = os.path.join(tmp_dir, 'foo')
343 write_file(src, 'foo')
344 dst = os.path.join(tmp_dir, 'bar')
345 write_file(dst, 'bar')
346
347 # no xattr == no problem
348 shutil._copyxattr(src, dst)
349 # common case
350 os.setxattr(src, 'user.foo', b'42')
351 os.setxattr(src, 'user.bar', b'43')
352 shutil._copyxattr(src, dst)
353 self.assertEqual(os.listxattr(src), os.listxattr(dst))
354 self.assertEqual(
355 os.getxattr(src, 'user.foo'),
356 os.getxattr(dst, 'user.foo'))
357 # check errors don't affect other attrs
358 os.remove(dst)
359 write_file(dst, 'bar')
360 os_error = OSError(errno.EPERM, 'EPERM')
361
Larry Hastings9cf065c2012-06-22 16:30:09 -0700362 def _raise_on_user_foo(fname, attr, val, **kwargs):
Antoine Pitrou424246f2012-05-12 19:02:01 +0200363 if attr == 'user.foo':
364 raise os_error
365 else:
Larry Hastings9cf065c2012-06-22 16:30:09 -0700366 orig_setxattr(fname, attr, val, **kwargs)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200367 try:
368 orig_setxattr = os.setxattr
369 os.setxattr = _raise_on_user_foo
370 shutil._copyxattr(src, dst)
Antoine Pitrou61597d32012-05-12 23:37:35 +0200371 self.assertIn('user.bar', os.listxattr(dst))
Antoine Pitrou424246f2012-05-12 19:02:01 +0200372 finally:
373 os.setxattr = orig_setxattr
374
375 @support.skip_unless_symlink
376 @support.skip_unless_xattr
377 @unittest.skipUnless(hasattr(os, 'geteuid') and os.geteuid() == 0,
378 'root privileges required')
379 def test_copyxattr_symlinks(self):
380 # On Linux, it's only possible to access non-user xattr for symlinks;
381 # which in turn require root privileges. This test should be expanded
382 # as soon as other platforms gain support for extended attributes.
383 tmp_dir = self.mkdtemp()
384 src = os.path.join(tmp_dir, 'foo')
385 src_link = os.path.join(tmp_dir, 'baz')
386 write_file(src, 'foo')
387 os.symlink(src, src_link)
388 os.setxattr(src, 'trusted.foo', b'42')
Larry Hastings9cf065c2012-06-22 16:30:09 -0700389 os.setxattr(src_link, 'trusted.foo', b'43', follow_symlinks=False)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200390 dst = os.path.join(tmp_dir, 'bar')
391 dst_link = os.path.join(tmp_dir, 'qux')
392 write_file(dst, 'bar')
393 os.symlink(dst, dst_link)
394 shutil._copyxattr(src_link, dst_link, symlinks=True)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700395 self.assertEqual(os.getxattr(dst_link, 'trusted.foo', follow_symlinks=False), b'43')
Antoine Pitrou424246f2012-05-12 19:02:01 +0200396 self.assertRaises(OSError, os.getxattr, dst, 'trusted.foo')
397 shutil._copyxattr(src_link, dst, symlinks=True)
398 self.assertEqual(os.getxattr(dst, 'trusted.foo'), b'43')
399
Antoine Pitrou78091e62011-12-29 18:54:15 +0100400 @support.skip_unless_symlink
401 def test_copy_symlinks(self):
402 tmp_dir = self.mkdtemp()
403 src = os.path.join(tmp_dir, 'foo')
404 dst = os.path.join(tmp_dir, 'bar')
405 src_link = os.path.join(tmp_dir, 'baz')
406 write_file(src, 'foo')
407 os.symlink(src, src_link)
408 if hasattr(os, 'lchmod'):
409 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
410 # don't follow
411 shutil.copy(src_link, dst, symlinks=False)
412 self.assertFalse(os.path.islink(dst))
413 self.assertEqual(read_file(src), read_file(dst))
414 os.remove(dst)
415 # follow
416 shutil.copy(src_link, dst, symlinks=True)
417 self.assertTrue(os.path.islink(dst))
418 self.assertEqual(os.readlink(dst), os.readlink(src_link))
419 if hasattr(os, 'lchmod'):
420 self.assertEqual(os.lstat(src_link).st_mode,
421 os.lstat(dst).st_mode)
422
423 @support.skip_unless_symlink
424 def test_copy2_symlinks(self):
425 tmp_dir = self.mkdtemp()
426 src = os.path.join(tmp_dir, 'foo')
427 dst = os.path.join(tmp_dir, 'bar')
428 src_link = os.path.join(tmp_dir, 'baz')
429 write_file(src, 'foo')
430 os.symlink(src, src_link)
431 if hasattr(os, 'lchmod'):
432 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
433 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
434 os.lchflags(src_link, stat.UF_NODUMP)
435 src_stat = os.stat(src)
436 src_link_stat = os.lstat(src_link)
437 # follow
438 shutil.copy2(src_link, dst, symlinks=False)
439 self.assertFalse(os.path.islink(dst))
440 self.assertEqual(read_file(src), read_file(dst))
441 os.remove(dst)
442 # don't follow
443 shutil.copy2(src_link, dst, symlinks=True)
444 self.assertTrue(os.path.islink(dst))
445 self.assertEqual(os.readlink(dst), os.readlink(src_link))
446 dst_stat = os.lstat(dst)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700447 if os.utime in os.supports_follow_symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100448 for attr in 'st_atime', 'st_mtime':
449 # The modification times may be truncated in the new file.
450 self.assertLessEqual(getattr(src_link_stat, attr),
451 getattr(dst_stat, attr) + 1)
452 if hasattr(os, 'lchmod'):
453 self.assertEqual(src_link_stat.st_mode, dst_stat.st_mode)
454 self.assertNotEqual(src_stat.st_mode, dst_stat.st_mode)
455 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
456 self.assertEqual(src_link_stat.st_flags, dst_stat.st_flags)
457
Antoine Pitrou424246f2012-05-12 19:02:01 +0200458 @support.skip_unless_xattr
459 def test_copy2_xattr(self):
460 tmp_dir = self.mkdtemp()
461 src = os.path.join(tmp_dir, 'foo')
462 dst = os.path.join(tmp_dir, 'bar')
463 write_file(src, 'foo')
464 os.setxattr(src, 'user.foo', b'42')
465 shutil.copy2(src, dst)
466 self.assertEqual(
467 os.getxattr(src, 'user.foo'),
468 os.getxattr(dst, 'user.foo'))
469 os.remove(dst)
470
Antoine Pitrou78091e62011-12-29 18:54:15 +0100471 @support.skip_unless_symlink
472 def test_copyfile_symlinks(self):
473 tmp_dir = self.mkdtemp()
474 src = os.path.join(tmp_dir, 'src')
475 dst = os.path.join(tmp_dir, 'dst')
476 dst_link = os.path.join(tmp_dir, 'dst_link')
477 link = os.path.join(tmp_dir, 'link')
478 write_file(src, 'foo')
479 os.symlink(src, link)
480 # don't follow
481 shutil.copyfile(link, dst_link, symlinks=True)
482 self.assertTrue(os.path.islink(dst_link))
483 self.assertEqual(os.readlink(link), os.readlink(dst_link))
484 # follow
485 shutil.copyfile(link, dst)
486 self.assertFalse(os.path.islink(dst))
487
Hynek Schlawack2100b422012-06-23 20:28:32 +0200488 def test_rmtree_uses_safe_fd_version_if_available(self):
489 if os.unlink in os.supports_dir_fd and os.open in os.supports_dir_fd:
490 self.assertTrue(shutil._use_fd_functions)
491 self.assertTrue(shutil.rmtree_is_safe)
492 tmp_dir = self.mkdtemp()
493 d = os.path.join(tmp_dir, 'a')
494 os.mkdir(d)
495 try:
496 real_rmtree = shutil._rmtree_safe_fd
497 class Called(Exception): pass
498 def _raiser(*args, **kwargs):
499 raise Called
500 shutil._rmtree_safe_fd = _raiser
501 self.assertRaises(Called, shutil.rmtree, d)
502 finally:
503 shutil._rmtree_safe_fd = real_rmtree
504 else:
505 self.assertFalse(shutil._use_fd_functions)
506 self.assertFalse(shutil.rmtree_is_safe)
507
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000508 def test_rmtree_dont_delete_file(self):
509 # When called on a file instead of a directory, don't delete it.
510 handle, path = tempfile.mkstemp()
Victor Stinnerbf816222011-06-30 23:25:47 +0200511 os.close(handle)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200512 self.assertRaises(NotADirectoryError, shutil.rmtree, path)
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000513 os.remove(path)
514
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000515 def test_copytree_simple(self):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000516 src_dir = tempfile.mkdtemp()
517 dst_dir = os.path.join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200518 self.addCleanup(shutil.rmtree, src_dir)
519 self.addCleanup(shutil.rmtree, os.path.dirname(dst_dir))
520 write_file((src_dir, 'test.txt'), '123')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000521 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200522 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000523
Éric Araujoa7e33a12011-08-12 19:51:35 +0200524 shutil.copytree(src_dir, dst_dir)
525 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test.txt')))
526 self.assertTrue(os.path.isdir(os.path.join(dst_dir, 'test_dir')))
527 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test_dir',
528 'test.txt')))
529 actual = read_file((dst_dir, 'test.txt'))
530 self.assertEqual(actual, '123')
531 actual = read_file((dst_dir, 'test_dir', 'test.txt'))
532 self.assertEqual(actual, '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000533
Antoine Pitrou78091e62011-12-29 18:54:15 +0100534 @support.skip_unless_symlink
535 def test_copytree_symlinks(self):
536 tmp_dir = self.mkdtemp()
537 src_dir = os.path.join(tmp_dir, 'src')
538 dst_dir = os.path.join(tmp_dir, 'dst')
539 sub_dir = os.path.join(src_dir, 'sub')
540 os.mkdir(src_dir)
541 os.mkdir(sub_dir)
542 write_file((src_dir, 'file.txt'), 'foo')
543 src_link = os.path.join(sub_dir, 'link')
544 dst_link = os.path.join(dst_dir, 'sub/link')
545 os.symlink(os.path.join(src_dir, 'file.txt'),
546 src_link)
547 if hasattr(os, 'lchmod'):
548 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
549 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
550 os.lchflags(src_link, stat.UF_NODUMP)
551 src_stat = os.lstat(src_link)
552 shutil.copytree(src_dir, dst_dir, symlinks=True)
553 self.assertTrue(os.path.islink(os.path.join(dst_dir, 'sub', 'link')))
554 self.assertEqual(os.readlink(os.path.join(dst_dir, 'sub', 'link')),
555 os.path.join(src_dir, 'file.txt'))
556 dst_stat = os.lstat(dst_link)
557 if hasattr(os, 'lchmod'):
558 self.assertEqual(dst_stat.st_mode, src_stat.st_mode)
559 if hasattr(os, 'lchflags'):
560 self.assertEqual(dst_stat.st_flags, src_stat.st_flags)
561
Georg Brandl2ee470f2008-07-16 12:55:28 +0000562 def test_copytree_with_exclude(self):
Georg Brandl2ee470f2008-07-16 12:55:28 +0000563 # creating data
564 join = os.path.join
565 exists = os.path.exists
566 src_dir = tempfile.mkdtemp()
Georg Brandl2ee470f2008-07-16 12:55:28 +0000567 try:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000568 dst_dir = join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200569 write_file((src_dir, 'test.txt'), '123')
570 write_file((src_dir, 'test.tmp'), '123')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000571 os.mkdir(join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200572 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000573 os.mkdir(join(src_dir, 'test_dir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200574 write_file((src_dir, 'test_dir2', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000575 os.mkdir(join(src_dir, 'test_dir2', 'subdir'))
576 os.mkdir(join(src_dir, 'test_dir2', 'subdir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200577 write_file((src_dir, 'test_dir2', 'subdir', 'test.txt'), '456')
578 write_file((src_dir, 'test_dir2', 'subdir2', 'test.py'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000579
580 # testing glob-like patterns
581 try:
582 patterns = shutil.ignore_patterns('*.tmp', 'test_dir2')
583 shutil.copytree(src_dir, dst_dir, ignore=patterns)
584 # checking the result: some elements should not be copied
585 self.assertTrue(exists(join(dst_dir, 'test.txt')))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200586 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
587 self.assertFalse(exists(join(dst_dir, 'test_dir2')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000588 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200589 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000590 try:
591 patterns = shutil.ignore_patterns('*.tmp', 'subdir*')
592 shutil.copytree(src_dir, dst_dir, ignore=patterns)
593 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200594 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
595 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2')))
596 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000597 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200598 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000599
600 # testing callable-style
601 try:
602 def _filter(src, names):
603 res = []
604 for name in names:
605 path = os.path.join(src, name)
606
607 if (os.path.isdir(path) and
608 path.split()[-1] == 'subdir'):
609 res.append(name)
610 elif os.path.splitext(path)[-1] in ('.py'):
611 res.append(name)
612 return res
613
614 shutil.copytree(src_dir, dst_dir, ignore=_filter)
615
616 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200617 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2',
618 'test.py')))
619 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000620
621 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200622 shutil.rmtree(dst_dir)
Georg Brandl2ee470f2008-07-16 12:55:28 +0000623 finally:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000624 shutil.rmtree(src_dir)
625 shutil.rmtree(os.path.dirname(dst_dir))
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000626
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000627 @unittest.skipUnless(hasattr(os, 'link'), 'requires os.link')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000628 def test_dont_copy_file_onto_link_to_itself(self):
Georg Brandl724d0892010-12-05 07:51:39 +0000629 # Temporarily disable test on Windows.
630 if os.name == 'nt':
631 return
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000632 # bug 851123.
633 os.mkdir(TESTFN)
634 src = os.path.join(TESTFN, 'cheese')
635 dst = os.path.join(TESTFN, 'shop')
636 try:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000637 with open(src, 'w') as f:
638 f.write('cheddar')
639 os.link(src, dst)
640 self.assertRaises(shutil.Error, shutil.copyfile, src, dst)
641 with open(src, 'r') as f:
642 self.assertEqual(f.read(), 'cheddar')
643 os.remove(dst)
644 finally:
645 shutil.rmtree(TESTFN, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000646
Brian Curtin3b4499c2010-12-28 14:31:47 +0000647 @support.skip_unless_symlink
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000648 def test_dont_copy_file_onto_symlink_to_itself(self):
649 # bug 851123.
650 os.mkdir(TESTFN)
651 src = os.path.join(TESTFN, 'cheese')
652 dst = os.path.join(TESTFN, 'shop')
653 try:
654 with open(src, 'w') as f:
655 f.write('cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000656 # Using `src` here would mean we end up with a symlink pointing
657 # to TESTFN/TESTFN/cheese, while it should point at
658 # TESTFN/cheese.
659 os.symlink('cheese', dst)
660 self.assertRaises(shutil.Error, shutil.copyfile, src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +0000661 with open(src, 'r') as f:
662 self.assertEqual(f.read(), 'cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000663 os.remove(dst)
664 finally:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000665 shutil.rmtree(TESTFN, ignore_errors=True)
Johannes Gijsbers68128712004-08-14 13:57:08 +0000666
Brian Curtin3b4499c2010-12-28 14:31:47 +0000667 @support.skip_unless_symlink
Brian Curtind40e6f72010-07-08 21:39:08 +0000668 def test_rmtree_on_symlink(self):
669 # bug 1669.
670 os.mkdir(TESTFN)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000671 try:
Brian Curtind40e6f72010-07-08 21:39:08 +0000672 src = os.path.join(TESTFN, 'cheese')
673 dst = os.path.join(TESTFN, 'shop')
674 os.mkdir(src)
675 os.symlink(src, dst)
676 self.assertRaises(OSError, shutil.rmtree, dst)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200677 shutil.rmtree(dst, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000678 finally:
Brian Curtind40e6f72010-07-08 21:39:08 +0000679 shutil.rmtree(TESTFN, ignore_errors=True)
680
681 if hasattr(os, "mkfifo"):
682 # Issue #3002: copyfile and copytree block indefinitely on named pipes
683 def test_copyfile_named_pipe(self):
684 os.mkfifo(TESTFN)
685 try:
686 self.assertRaises(shutil.SpecialFileError,
687 shutil.copyfile, TESTFN, TESTFN2)
688 self.assertRaises(shutil.SpecialFileError,
689 shutil.copyfile, __file__, TESTFN)
690 finally:
691 os.remove(TESTFN)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000692
Brian Curtin3b4499c2010-12-28 14:31:47 +0000693 @support.skip_unless_symlink
Brian Curtin52173d42010-12-02 18:29:18 +0000694 def test_copytree_named_pipe(self):
695 os.mkdir(TESTFN)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000696 try:
Brian Curtin52173d42010-12-02 18:29:18 +0000697 subdir = os.path.join(TESTFN, "subdir")
698 os.mkdir(subdir)
699 pipe = os.path.join(subdir, "mypipe")
700 os.mkfifo(pipe)
701 try:
702 shutil.copytree(TESTFN, TESTFN2)
703 except shutil.Error as e:
704 errors = e.args[0]
705 self.assertEqual(len(errors), 1)
706 src, dst, error_msg = errors[0]
707 self.assertEqual("`%s` is a named pipe" % pipe, error_msg)
708 else:
709 self.fail("shutil.Error should have been raised")
710 finally:
711 shutil.rmtree(TESTFN, ignore_errors=True)
712 shutil.rmtree(TESTFN2, ignore_errors=True)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000713
Tarek Ziadé5340db32010-04-19 22:30:51 +0000714 def test_copytree_special_func(self):
715
716 src_dir = self.mkdtemp()
717 dst_dir = os.path.join(self.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200718 write_file((src_dir, 'test.txt'), '123')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000719 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200720 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000721
722 copied = []
723 def _copy(src, dst):
724 copied.append((src, dst))
725
726 shutil.copytree(src_dir, dst_dir, copy_function=_copy)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000727 self.assertEqual(len(copied), 2)
Tarek Ziadé5340db32010-04-19 22:30:51 +0000728
Brian Curtin3b4499c2010-12-28 14:31:47 +0000729 @support.skip_unless_symlink
Tarek Ziadéfb437512010-04-20 08:57:33 +0000730 def test_copytree_dangling_symlinks(self):
731
732 # a dangling symlink raises an error at the end
733 src_dir = self.mkdtemp()
734 dst_dir = os.path.join(self.mkdtemp(), 'destination')
735 os.symlink('IDONTEXIST', os.path.join(src_dir, 'test.txt'))
736 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200737 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadéfb437512010-04-20 08:57:33 +0000738 self.assertRaises(Error, shutil.copytree, src_dir, dst_dir)
739
740 # a dangling symlink is ignored with the proper flag
741 dst_dir = os.path.join(self.mkdtemp(), 'destination2')
742 shutil.copytree(src_dir, dst_dir, ignore_dangling_symlinks=True)
743 self.assertNotIn('test.txt', os.listdir(dst_dir))
744
745 # a dangling symlink is copied if symlinks=True
746 dst_dir = os.path.join(self.mkdtemp(), 'destination3')
747 shutil.copytree(src_dir, dst_dir, symlinks=True)
748 self.assertIn('test.txt', os.listdir(dst_dir))
749
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400750 def _copy_file(self, method):
751 fname = 'test.txt'
752 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200753 write_file((tmpdir, fname), 'xxx')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400754 file1 = os.path.join(tmpdir, fname)
755 tmpdir2 = self.mkdtemp()
756 method(file1, tmpdir2)
757 file2 = os.path.join(tmpdir2, fname)
758 return (file1, file2)
759
760 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
761 def test_copy(self):
762 # Ensure that the copied file exists and has the same mode bits.
763 file1, file2 = self._copy_file(shutil.copy)
764 self.assertTrue(os.path.exists(file2))
765 self.assertEqual(os.stat(file1).st_mode, os.stat(file2).st_mode)
766
767 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
Senthil Kumaran0c2dba52011-07-03 18:21:38 -0700768 @unittest.skipUnless(hasattr(os, 'utime'), 'requires os.utime')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400769 def test_copy2(self):
770 # Ensure that the copied file exists and has the same mode and
771 # modification time bits.
772 file1, file2 = self._copy_file(shutil.copy2)
773 self.assertTrue(os.path.exists(file2))
774 file1_stat = os.stat(file1)
775 file2_stat = os.stat(file2)
776 self.assertEqual(file1_stat.st_mode, file2_stat.st_mode)
777 for attr in 'st_atime', 'st_mtime':
778 # The modification times may be truncated in the new file.
779 self.assertLessEqual(getattr(file1_stat, attr),
780 getattr(file2_stat, attr) + 1)
781 if hasattr(os, 'chflags') and hasattr(file1_stat, 'st_flags'):
782 self.assertEqual(getattr(file1_stat, 'st_flags'),
783 getattr(file2_stat, 'st_flags'))
784
Ezio Melotti975077a2011-05-19 22:03:22 +0300785 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000786 def test_make_tarball(self):
787 # creating something to tar
788 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200789 write_file((tmpdir, 'file1'), 'xxx')
790 write_file((tmpdir, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000791 os.mkdir(os.path.join(tmpdir, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200792 write_file((tmpdir, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000793
794 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400795 # force shutil to create the directory
796 os.rmdir(tmpdir2)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000797 unittest.skipUnless(splitdrive(tmpdir)[0] == splitdrive(tmpdir2)[0],
798 "source and target should be on same drive")
799
800 base_name = os.path.join(tmpdir2, 'archive')
801
802 # working with relative paths to avoid tar warnings
803 old_dir = os.getcwd()
804 os.chdir(tmpdir)
805 try:
806 _make_tarball(splitdrive(base_name)[1], '.')
807 finally:
808 os.chdir(old_dir)
809
810 # check if the compressed tarball was created
811 tarball = base_name + '.tar.gz'
812 self.assertTrue(os.path.exists(tarball))
813
814 # trying an uncompressed one
815 base_name = os.path.join(tmpdir2, 'archive')
816 old_dir = os.getcwd()
817 os.chdir(tmpdir)
818 try:
819 _make_tarball(splitdrive(base_name)[1], '.', compress=None)
820 finally:
821 os.chdir(old_dir)
822 tarball = base_name + '.tar'
823 self.assertTrue(os.path.exists(tarball))
824
825 def _tarinfo(self, path):
826 tar = tarfile.open(path)
827 try:
828 names = tar.getnames()
829 names.sort()
830 return tuple(names)
831 finally:
832 tar.close()
833
834 def _create_files(self):
835 # creating something to tar
836 tmpdir = self.mkdtemp()
837 dist = os.path.join(tmpdir, 'dist')
838 os.mkdir(dist)
Éric Araujoa7e33a12011-08-12 19:51:35 +0200839 write_file((dist, 'file1'), 'xxx')
840 write_file((dist, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000841 os.mkdir(os.path.join(dist, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200842 write_file((dist, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000843 os.mkdir(os.path.join(dist, 'sub2'))
844 tmpdir2 = self.mkdtemp()
845 base_name = os.path.join(tmpdir2, 'archive')
846 return tmpdir, tmpdir2, base_name
847
Ezio Melotti975077a2011-05-19 22:03:22 +0300848 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000849 @unittest.skipUnless(find_executable('tar') and find_executable('gzip'),
850 'Need the tar command to run')
851 def test_tarfile_vs_tar(self):
852 tmpdir, tmpdir2, base_name = self._create_files()
853 old_dir = os.getcwd()
854 os.chdir(tmpdir)
855 try:
856 _make_tarball(base_name, 'dist')
857 finally:
858 os.chdir(old_dir)
859
860 # check if the compressed tarball was created
861 tarball = base_name + '.tar.gz'
862 self.assertTrue(os.path.exists(tarball))
863
864 # now create another tarball using `tar`
865 tarball2 = os.path.join(tmpdir, 'archive2.tar.gz')
866 tar_cmd = ['tar', '-cf', 'archive2.tar', 'dist']
867 gzip_cmd = ['gzip', '-f9', 'archive2.tar']
868 old_dir = os.getcwd()
869 os.chdir(tmpdir)
870 try:
871 with captured_stdout() as s:
872 spawn(tar_cmd)
873 spawn(gzip_cmd)
874 finally:
875 os.chdir(old_dir)
876
877 self.assertTrue(os.path.exists(tarball2))
878 # let's compare both tarballs
Ezio Melottib3aedd42010-11-20 19:04:17 +0000879 self.assertEqual(self._tarinfo(tarball), self._tarinfo(tarball2))
Tarek Ziadé396fad72010-02-23 05:30:31 +0000880
881 # trying an uncompressed one
882 base_name = os.path.join(tmpdir2, 'archive')
883 old_dir = os.getcwd()
884 os.chdir(tmpdir)
885 try:
886 _make_tarball(base_name, 'dist', compress=None)
887 finally:
888 os.chdir(old_dir)
889 tarball = base_name + '.tar'
890 self.assertTrue(os.path.exists(tarball))
891
892 # now for a dry_run
893 base_name = os.path.join(tmpdir2, 'archive')
894 old_dir = os.getcwd()
895 os.chdir(tmpdir)
896 try:
897 _make_tarball(base_name, 'dist', compress=None, dry_run=True)
898 finally:
899 os.chdir(old_dir)
900 tarball = base_name + '.tar'
901 self.assertTrue(os.path.exists(tarball))
902
Ezio Melotti975077a2011-05-19 22:03:22 +0300903 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000904 @unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run')
905 def test_make_zipfile(self):
906 # creating something to tar
907 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200908 write_file((tmpdir, 'file1'), 'xxx')
909 write_file((tmpdir, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000910
911 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400912 # force shutil to create the directory
913 os.rmdir(tmpdir2)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000914 base_name = os.path.join(tmpdir2, 'archive')
915 _make_zipfile(base_name, tmpdir)
916
917 # check if the compressed tarball was created
918 tarball = base_name + '.zip'
Éric Araujo1c505492010-11-06 02:12:51 +0000919 self.assertTrue(os.path.exists(tarball))
Tarek Ziadé396fad72010-02-23 05:30:31 +0000920
921
922 def test_make_archive(self):
923 tmpdir = self.mkdtemp()
924 base_name = os.path.join(tmpdir, 'archive')
925 self.assertRaises(ValueError, make_archive, base_name, 'xxx')
926
Ezio Melotti975077a2011-05-19 22:03:22 +0300927 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000928 def test_make_archive_owner_group(self):
929 # testing make_archive with owner and group, with various combinations
930 # this works even if there's not gid/uid support
931 if UID_GID_SUPPORT:
932 group = grp.getgrgid(0)[0]
933 owner = pwd.getpwuid(0)[0]
934 else:
935 group = owner = 'root'
936
937 base_dir, root_dir, base_name = self._create_files()
938 base_name = os.path.join(self.mkdtemp() , 'archive')
939 res = make_archive(base_name, 'zip', root_dir, base_dir, owner=owner,
940 group=group)
941 self.assertTrue(os.path.exists(res))
942
943 res = make_archive(base_name, 'zip', root_dir, base_dir)
944 self.assertTrue(os.path.exists(res))
945
946 res = make_archive(base_name, 'tar', root_dir, base_dir,
947 owner=owner, group=group)
948 self.assertTrue(os.path.exists(res))
949
950 res = make_archive(base_name, 'tar', root_dir, base_dir,
951 owner='kjhkjhkjg', group='oihohoh')
952 self.assertTrue(os.path.exists(res))
953
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000954
Ezio Melotti975077a2011-05-19 22:03:22 +0300955 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000956 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
957 def test_tarfile_root_owner(self):
958 tmpdir, tmpdir2, base_name = self._create_files()
959 old_dir = os.getcwd()
960 os.chdir(tmpdir)
961 group = grp.getgrgid(0)[0]
962 owner = pwd.getpwuid(0)[0]
963 try:
964 archive_name = _make_tarball(base_name, 'dist', compress=None,
965 owner=owner, group=group)
966 finally:
967 os.chdir(old_dir)
968
969 # check if the compressed tarball was created
970 self.assertTrue(os.path.exists(archive_name))
971
972 # now checks the rights
973 archive = tarfile.open(archive_name)
974 try:
975 for member in archive.getmembers():
Ezio Melottib3aedd42010-11-20 19:04:17 +0000976 self.assertEqual(member.uid, 0)
977 self.assertEqual(member.gid, 0)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000978 finally:
979 archive.close()
980
981 def test_make_archive_cwd(self):
982 current_dir = os.getcwd()
983 def _breaks(*args, **kw):
984 raise RuntimeError()
985
986 register_archive_format('xxx', _breaks, [], 'xxx file')
987 try:
988 try:
989 make_archive('xxx', 'xxx', root_dir=self.mkdtemp())
990 except Exception:
991 pass
Ezio Melottib3aedd42010-11-20 19:04:17 +0000992 self.assertEqual(os.getcwd(), current_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000993 finally:
994 unregister_archive_format('xxx')
995
996 def test_register_archive_format(self):
997
998 self.assertRaises(TypeError, register_archive_format, 'xxx', 1)
999 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1000 1)
1001 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1002 [(1, 2), (1, 2, 3)])
1003
1004 register_archive_format('xxx', lambda: x, [(1, 2)], 'xxx file')
1005 formats = [name for name, params in get_archive_formats()]
1006 self.assertIn('xxx', formats)
1007
1008 unregister_archive_format('xxx')
1009 formats = [name for name, params in get_archive_formats()]
1010 self.assertNotIn('xxx', formats)
1011
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001012 def _compare_dirs(self, dir1, dir2):
1013 # check that dir1 and dir2 are equivalent,
1014 # return the diff
1015 diff = []
1016 for root, dirs, files in os.walk(dir1):
1017 for file_ in files:
1018 path = os.path.join(root, file_)
1019 target_path = os.path.join(dir2, os.path.split(path)[-1])
1020 if not os.path.exists(target_path):
1021 diff.append(file_)
1022 return diff
1023
Ezio Melotti975077a2011-05-19 22:03:22 +03001024 @requires_zlib
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001025 def test_unpack_archive(self):
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001026 formats = ['tar', 'gztar', 'zip']
1027 if BZ2_SUPPORTED:
1028 formats.append('bztar')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001029
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001030 for format in formats:
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001031 tmpdir = self.mkdtemp()
1032 base_dir, root_dir, base_name = self._create_files()
1033 tmpdir2 = self.mkdtemp()
1034 filename = make_archive(base_name, format, root_dir, base_dir)
1035
1036 # let's try to unpack it now
1037 unpack_archive(filename, tmpdir2)
1038 diff = self._compare_dirs(tmpdir, tmpdir2)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001039 self.assertEqual(diff, [])
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001040
Nick Coghlanabf202d2011-03-16 13:52:20 -04001041 # and again, this time with the format specified
1042 tmpdir3 = self.mkdtemp()
1043 unpack_archive(filename, tmpdir3, format=format)
1044 diff = self._compare_dirs(tmpdir, tmpdir3)
1045 self.assertEqual(diff, [])
1046 self.assertRaises(shutil.ReadError, unpack_archive, TESTFN)
1047 self.assertRaises(ValueError, unpack_archive, TESTFN, format='xxx')
1048
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001049 def test_unpack_registery(self):
1050
1051 formats = get_unpack_formats()
1052
1053 def _boo(filename, extract_dir, extra):
Ezio Melottib3aedd42010-11-20 19:04:17 +00001054 self.assertEqual(extra, 1)
1055 self.assertEqual(filename, 'stuff.boo')
1056 self.assertEqual(extract_dir, 'xx')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001057
1058 register_unpack_format('Boo', ['.boo', '.b2'], _boo, [('extra', 1)])
1059 unpack_archive('stuff.boo', 'xx')
1060
1061 # trying to register a .boo unpacker again
1062 self.assertRaises(RegistryError, register_unpack_format, 'Boo2',
1063 ['.boo'], _boo)
1064
1065 # should work now
1066 unregister_unpack_format('Boo')
1067 register_unpack_format('Boo2', ['.boo'], _boo)
1068 self.assertIn(('Boo2', ['.boo'], ''), get_unpack_formats())
1069 self.assertNotIn(('Boo', ['.boo'], ''), get_unpack_formats())
1070
1071 # let's leave a clean state
1072 unregister_unpack_format('Boo2')
Ezio Melottib3aedd42010-11-20 19:04:17 +00001073 self.assertEqual(get_unpack_formats(), formats)
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001074
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001075 @unittest.skipUnless(hasattr(shutil, 'disk_usage'),
1076 "disk_usage not available on this platform")
1077 def test_disk_usage(self):
1078 usage = shutil.disk_usage(os.getcwd())
Éric Araujo2ee61882011-07-02 16:45:45 +02001079 self.assertGreater(usage.total, 0)
1080 self.assertGreater(usage.used, 0)
1081 self.assertGreaterEqual(usage.free, 0)
1082 self.assertGreaterEqual(usage.total, usage.used)
1083 self.assertGreater(usage.total, usage.free)
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001084
Sandro Tosid902a142011-08-22 23:28:27 +02001085 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1086 @unittest.skipUnless(hasattr(os, 'chown'), 'requires os.chown')
1087 def test_chown(self):
1088
1089 # cleaned-up automatically by TestShutil.tearDown method
1090 dirname = self.mkdtemp()
1091 filename = tempfile.mktemp(dir=dirname)
1092 write_file(filename, 'testing chown function')
1093
1094 with self.assertRaises(ValueError):
1095 shutil.chown(filename)
1096
1097 with self.assertRaises(LookupError):
1098 shutil.chown(filename, user='non-exising username')
1099
1100 with self.assertRaises(LookupError):
1101 shutil.chown(filename, group='non-exising groupname')
1102
1103 with self.assertRaises(TypeError):
1104 shutil.chown(filename, b'spam')
1105
1106 with self.assertRaises(TypeError):
1107 shutil.chown(filename, 3.14)
1108
1109 uid = os.getuid()
1110 gid = os.getgid()
1111
1112 def check_chown(path, uid=None, gid=None):
1113 s = os.stat(filename)
1114 if uid is not None:
1115 self.assertEqual(uid, s.st_uid)
1116 if gid is not None:
1117 self.assertEqual(gid, s.st_gid)
1118
1119 shutil.chown(filename, uid, gid)
1120 check_chown(filename, uid, gid)
1121 shutil.chown(filename, uid)
1122 check_chown(filename, uid)
1123 shutil.chown(filename, user=uid)
1124 check_chown(filename, uid)
1125 shutil.chown(filename, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001126 check_chown(filename, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001127
1128 shutil.chown(dirname, uid, gid)
1129 check_chown(dirname, uid, gid)
1130 shutil.chown(dirname, uid)
1131 check_chown(dirname, uid)
1132 shutil.chown(dirname, user=uid)
1133 check_chown(dirname, uid)
1134 shutil.chown(dirname, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001135 check_chown(dirname, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001136
1137 user = pwd.getpwuid(uid)[0]
1138 group = grp.getgrgid(gid)[0]
1139 shutil.chown(filename, user, group)
1140 check_chown(filename, uid, gid)
1141 shutil.chown(dirname, user, group)
1142 check_chown(dirname, uid, gid)
1143
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001144 def test_copy_return_value(self):
1145 # copy and copy2 both return their destination path.
1146 for fn in (shutil.copy, shutil.copy2):
1147 src_dir = self.mkdtemp()
1148 dst_dir = self.mkdtemp()
1149 src = os.path.join(src_dir, 'foo')
1150 write_file(src, 'foo')
1151 rv = fn(src, dst_dir)
1152 self.assertEqual(rv, os.path.join(dst_dir, 'foo'))
1153 rv = fn(src, os.path.join(dst_dir, 'bar'))
1154 self.assertEqual(rv, os.path.join(dst_dir, 'bar'))
1155
1156 def test_copyfile_return_value(self):
1157 # copytree returns its destination path.
1158 src_dir = self.mkdtemp()
1159 dst_dir = self.mkdtemp()
1160 dst_file = os.path.join(dst_dir, 'bar')
1161 src_file = os.path.join(src_dir, 'foo')
1162 write_file(src_file, 'foo')
1163 rv = shutil.copyfile(src_file, dst_file)
1164 self.assertTrue(os.path.exists(rv))
1165 self.assertEqual(read_file(src_file), read_file(dst_file))
1166
1167 def test_copytree_return_value(self):
1168 # copytree returns its destination path.
1169 src_dir = self.mkdtemp()
1170 dst_dir = src_dir + "dest"
1171 src = os.path.join(src_dir, 'foo')
1172 write_file(src, 'foo')
1173 rv = shutil.copytree(src_dir, dst_dir)
1174 self.assertEqual(['foo'], os.listdir(rv))
1175
Christian Heimes9bd667a2008-01-20 15:14:11 +00001176
Brian Curtinc57a3452012-06-22 16:00:30 -05001177class TestWhich(unittest.TestCase):
1178
1179 def setUp(self):
1180 self.temp_dir = tempfile.mkdtemp()
1181 # Give the temp_file an ".exe" suffix for all.
1182 # It's needed on Windows and not harmful on other platforms.
1183 self.temp_file = tempfile.NamedTemporaryFile(dir=self.temp_dir,
1184 suffix=".exe")
1185 os.chmod(self.temp_file.name, stat.S_IXUSR)
1186 self.addCleanup(self.temp_file.close)
1187 self.dir, self.file = os.path.split(self.temp_file.name)
1188
1189 def test_basic(self):
1190 # Given an EXE in a directory, it should be returned.
1191 rv = shutil.which(self.file, path=self.dir)
1192 self.assertEqual(rv, self.temp_file.name)
1193
1194 def test_full_path_short_circuit(self):
1195 # When given the fully qualified path to an executable that exists,
1196 # it should be returned.
1197 rv = shutil.which(self.temp_file.name, path=self.temp_dir)
1198 self.assertEqual(self.temp_file.name, rv)
1199
1200 def test_non_matching_mode(self):
1201 # Set the file read-only and ask for writeable files.
1202 os.chmod(self.temp_file.name, stat.S_IREAD)
1203 rv = shutil.which(self.file, path=self.dir, mode=os.W_OK)
1204 self.assertIsNone(rv)
1205
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001206 def test_relative(self):
1207 old_cwd = os.getcwd()
1208 base_dir, tail_dir = os.path.split(self.dir)
1209 os.chdir(base_dir)
1210 try:
1211 rv = shutil.which(self.file, path=tail_dir)
1212 self.assertEqual(rv, os.path.join(tail_dir, self.file))
1213 finally:
1214 os.chdir(old_cwd)
1215
Brian Curtinc57a3452012-06-22 16:00:30 -05001216 def test_nonexistent_file(self):
1217 # Return None when no matching executable file is found on the path.
1218 rv = shutil.which("foo.exe", path=self.dir)
1219 self.assertIsNone(rv)
1220
1221 @unittest.skipUnless(sys.platform == "win32",
1222 "pathext check is Windows-only")
1223 def test_pathext_checking(self):
1224 # Ask for the file without the ".exe" extension, then ensure that
1225 # it gets found properly with the extension.
1226 rv = shutil.which(self.temp_file.name[:-4], path=self.dir)
1227 self.assertEqual(self.temp_file.name, rv)
1228
1229
Christian Heimesada8c3b2008-03-18 18:26:33 +00001230class TestMove(unittest.TestCase):
1231
1232 def setUp(self):
1233 filename = "foo"
1234 self.src_dir = tempfile.mkdtemp()
1235 self.dst_dir = tempfile.mkdtemp()
1236 self.src_file = os.path.join(self.src_dir, filename)
1237 self.dst_file = os.path.join(self.dst_dir, filename)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001238 with open(self.src_file, "wb") as f:
1239 f.write(b"spam")
1240
1241 def tearDown(self):
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001242 for d in (self.src_dir, self.dst_dir):
Christian Heimesada8c3b2008-03-18 18:26:33 +00001243 try:
1244 if d:
1245 shutil.rmtree(d)
1246 except:
1247 pass
1248
1249 def _check_move_file(self, src, dst, real_dst):
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001250 with open(src, "rb") as f:
1251 contents = f.read()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001252 shutil.move(src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001253 with open(real_dst, "rb") as f:
1254 self.assertEqual(contents, f.read())
Christian Heimesada8c3b2008-03-18 18:26:33 +00001255 self.assertFalse(os.path.exists(src))
1256
1257 def _check_move_dir(self, src, dst, real_dst):
1258 contents = sorted(os.listdir(src))
1259 shutil.move(src, dst)
1260 self.assertEqual(contents, sorted(os.listdir(real_dst)))
1261 self.assertFalse(os.path.exists(src))
1262
1263 def test_move_file(self):
1264 # Move a file to another location on the same filesystem.
1265 self._check_move_file(self.src_file, self.dst_file, self.dst_file)
1266
1267 def test_move_file_to_dir(self):
1268 # Move a file inside an existing dir on the same filesystem.
1269 self._check_move_file(self.src_file, self.dst_dir, self.dst_file)
1270
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001271 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001272 def test_move_file_other_fs(self):
1273 # Move a file to an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001274 self.test_move_file()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001275
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001276 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001277 def test_move_file_to_dir_other_fs(self):
1278 # Move a file to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001279 self.test_move_file_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001280
1281 def test_move_dir(self):
1282 # Move a dir to another location on the same filesystem.
1283 dst_dir = tempfile.mktemp()
1284 try:
1285 self._check_move_dir(self.src_dir, dst_dir, dst_dir)
1286 finally:
1287 try:
1288 shutil.rmtree(dst_dir)
1289 except:
1290 pass
1291
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001292 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001293 def test_move_dir_other_fs(self):
1294 # Move a dir to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001295 self.test_move_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001296
1297 def test_move_dir_to_dir(self):
1298 # Move a dir inside an existing dir on the same filesystem.
1299 self._check_move_dir(self.src_dir, self.dst_dir,
1300 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1301
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001302 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001303 def test_move_dir_to_dir_other_fs(self):
1304 # Move a dir inside an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001305 self.test_move_dir_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001306
1307 def test_existing_file_inside_dest_dir(self):
1308 # A file with the same name inside the destination dir already exists.
1309 with open(self.dst_file, "wb"):
1310 pass
1311 self.assertRaises(shutil.Error, shutil.move, self.src_file, self.dst_dir)
1312
1313 def test_dont_move_dir_in_itself(self):
1314 # Moving a dir inside itself raises an Error.
1315 dst = os.path.join(self.src_dir, "bar")
1316 self.assertRaises(shutil.Error, shutil.move, self.src_dir, dst)
1317
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001318 def test_destinsrc_false_negative(self):
1319 os.mkdir(TESTFN)
1320 try:
1321 for src, dst in [('srcdir', 'srcdir/dest')]:
1322 src = os.path.join(TESTFN, src)
1323 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001324 self.assertTrue(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001325 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001326 'dst (%s) is not in src (%s)' % (dst, src))
1327 finally:
1328 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001329
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001330 def test_destinsrc_false_positive(self):
1331 os.mkdir(TESTFN)
1332 try:
1333 for src, dst in [('srcdir', 'src/dest'), ('srcdir', 'srcdir.new')]:
1334 src = os.path.join(TESTFN, src)
1335 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001336 self.assertFalse(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001337 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001338 'dst (%s) is in src (%s)' % (dst, src))
1339 finally:
1340 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimes9bd667a2008-01-20 15:14:11 +00001341
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +01001342 @support.skip_unless_symlink
1343 @mock_rename
1344 def test_move_file_symlink(self):
1345 dst = os.path.join(self.src_dir, 'bar')
1346 os.symlink(self.src_file, dst)
1347 shutil.move(dst, self.dst_file)
1348 self.assertTrue(os.path.islink(self.dst_file))
1349 self.assertTrue(os.path.samefile(self.src_file, self.dst_file))
1350
1351 @support.skip_unless_symlink
1352 @mock_rename
1353 def test_move_file_symlink_to_dir(self):
1354 filename = "bar"
1355 dst = os.path.join(self.src_dir, filename)
1356 os.symlink(self.src_file, dst)
1357 shutil.move(dst, self.dst_dir)
1358 final_link = os.path.join(self.dst_dir, filename)
1359 self.assertTrue(os.path.islink(final_link))
1360 self.assertTrue(os.path.samefile(self.src_file, final_link))
1361
1362 @support.skip_unless_symlink
1363 @mock_rename
1364 def test_move_dangling_symlink(self):
1365 src = os.path.join(self.src_dir, 'baz')
1366 dst = os.path.join(self.src_dir, 'bar')
1367 os.symlink(src, dst)
1368 dst_link = os.path.join(self.dst_dir, 'quux')
1369 shutil.move(dst, dst_link)
1370 self.assertTrue(os.path.islink(dst_link))
1371 self.assertEqual(os.path.realpath(src), os.path.realpath(dst_link))
1372
1373 @support.skip_unless_symlink
1374 @mock_rename
1375 def test_move_dir_symlink(self):
1376 src = os.path.join(self.src_dir, 'baz')
1377 dst = os.path.join(self.src_dir, 'bar')
1378 os.mkdir(src)
1379 os.symlink(src, dst)
1380 dst_link = os.path.join(self.dst_dir, 'quux')
1381 shutil.move(dst, dst_link)
1382 self.assertTrue(os.path.islink(dst_link))
1383 self.assertTrue(os.path.samefile(src, dst_link))
1384
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001385 def test_move_return_value(self):
1386 rv = shutil.move(self.src_file, self.dst_dir)
1387 self.assertEqual(rv,
1388 os.path.join(self.dst_dir, os.path.basename(self.src_file)))
1389
1390 def test_move_as_rename_return_value(self):
1391 rv = shutil.move(self.src_file, os.path.join(self.dst_dir, 'bar'))
1392 self.assertEqual(rv, os.path.join(self.dst_dir, 'bar'))
1393
Tarek Ziadé5340db32010-04-19 22:30:51 +00001394
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001395class TestCopyFile(unittest.TestCase):
1396
1397 _delete = False
1398
1399 class Faux(object):
1400 _entered = False
1401 _exited_with = None
1402 _raised = False
1403 def __init__(self, raise_in_exit=False, suppress_at_exit=True):
1404 self._raise_in_exit = raise_in_exit
1405 self._suppress_at_exit = suppress_at_exit
1406 def read(self, *args):
1407 return ''
1408 def __enter__(self):
1409 self._entered = True
1410 def __exit__(self, exc_type, exc_val, exc_tb):
1411 self._exited_with = exc_type, exc_val, exc_tb
1412 if self._raise_in_exit:
1413 self._raised = True
1414 raise IOError("Cannot close")
1415 return self._suppress_at_exit
1416
1417 def tearDown(self):
1418 if self._delete:
1419 del shutil.open
1420
1421 def _set_shutil_open(self, func):
1422 shutil.open = func
1423 self._delete = True
1424
1425 def test_w_source_open_fails(self):
1426 def _open(filename, mode='r'):
1427 if filename == 'srcfile':
1428 raise IOError('Cannot open "srcfile"')
1429 assert 0 # shouldn't reach here.
1430
1431 self._set_shutil_open(_open)
1432
1433 self.assertRaises(IOError, shutil.copyfile, 'srcfile', 'destfile')
1434
1435 def test_w_dest_open_fails(self):
1436
1437 srcfile = self.Faux()
1438
1439 def _open(filename, mode='r'):
1440 if filename == 'srcfile':
1441 return srcfile
1442 if filename == 'destfile':
1443 raise IOError('Cannot open "destfile"')
1444 assert 0 # shouldn't reach here.
1445
1446 self._set_shutil_open(_open)
1447
1448 shutil.copyfile('srcfile', 'destfile')
1449 self.assertTrue(srcfile._entered)
1450 self.assertTrue(srcfile._exited_with[0] is IOError)
1451 self.assertEqual(srcfile._exited_with[1].args,
1452 ('Cannot open "destfile"',))
1453
1454 def test_w_dest_close_fails(self):
1455
1456 srcfile = self.Faux()
1457 destfile = self.Faux(True)
1458
1459 def _open(filename, mode='r'):
1460 if filename == 'srcfile':
1461 return srcfile
1462 if filename == 'destfile':
1463 return destfile
1464 assert 0 # shouldn't reach here.
1465
1466 self._set_shutil_open(_open)
1467
1468 shutil.copyfile('srcfile', 'destfile')
1469 self.assertTrue(srcfile._entered)
1470 self.assertTrue(destfile._entered)
1471 self.assertTrue(destfile._raised)
1472 self.assertTrue(srcfile._exited_with[0] is IOError)
1473 self.assertEqual(srcfile._exited_with[1].args,
1474 ('Cannot close',))
1475
1476 def test_w_source_close_fails(self):
1477
1478 srcfile = self.Faux(True)
1479 destfile = self.Faux()
1480
1481 def _open(filename, mode='r'):
1482 if filename == 'srcfile':
1483 return srcfile
1484 if filename == 'destfile':
1485 return destfile
1486 assert 0 # shouldn't reach here.
1487
1488 self._set_shutil_open(_open)
1489
1490 self.assertRaises(IOError,
1491 shutil.copyfile, 'srcfile', 'destfile')
1492 self.assertTrue(srcfile._entered)
1493 self.assertTrue(destfile._entered)
1494 self.assertFalse(destfile._raised)
1495 self.assertTrue(srcfile._exited_with[0] is None)
1496 self.assertTrue(srcfile._raised)
1497
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001498 def test_move_dir_caseinsensitive(self):
1499 # Renames a folder to the same name
1500 # but a different case.
1501
1502 self.src_dir = tempfile.mkdtemp()
1503 dst_dir = os.path.join(
1504 os.path.dirname(self.src_dir),
1505 os.path.basename(self.src_dir).upper())
1506 self.assertNotEqual(self.src_dir, dst_dir)
1507
1508 try:
1509 shutil.move(self.src_dir, dst_dir)
1510 self.assertTrue(os.path.isdir(dst_dir))
1511 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +02001512 os.rmdir(dst_dir)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001513
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001514class TermsizeTests(unittest.TestCase):
1515 def test_does_not_crash(self):
1516 """Check if get_terminal_size() returns a meaningful value.
1517
1518 There's no easy portable way to actually check the size of the
1519 terminal, so let's check if it returns something sensible instead.
1520 """
1521 size = shutil.get_terminal_size()
Antoine Pitroucfade362012-02-08 23:48:59 +01001522 self.assertGreaterEqual(size.columns, 0)
1523 self.assertGreaterEqual(size.lines, 0)
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001524
1525 def test_os_environ_first(self):
1526 "Check if environment variables have precedence"
1527
1528 with support.EnvironmentVarGuard() as env:
1529 env['COLUMNS'] = '777'
1530 size = shutil.get_terminal_size()
1531 self.assertEqual(size.columns, 777)
1532
1533 with support.EnvironmentVarGuard() as env:
1534 env['LINES'] = '888'
1535 size = shutil.get_terminal_size()
1536 self.assertEqual(size.lines, 888)
1537
1538 @unittest.skipUnless(os.isatty(sys.__stdout__.fileno()), "not on tty")
1539 def test_stty_match(self):
1540 """Check if stty returns the same results ignoring env
1541
1542 This test will fail if stdin and stdout are connected to
1543 different terminals with different sizes. Nevertheless, such
1544 situations should be pretty rare.
1545 """
1546 try:
1547 size = subprocess.check_output(['stty', 'size']).decode().split()
1548 except (FileNotFoundError, subprocess.CalledProcessError):
1549 self.skipTest("stty invocation failed")
1550 expected = (int(size[1]), int(size[0])) # reversed order
1551
1552 with support.EnvironmentVarGuard() as env:
1553 del env['LINES']
1554 del env['COLUMNS']
1555 actual = shutil.get_terminal_size()
1556
1557 self.assertEqual(expected, actual)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001558
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001559
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001560def test_main():
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001561 support.run_unittest(TestShutil, TestMove, TestCopyFile,
Brian Curtinc57a3452012-06-22 16:00:30 -05001562 TermsizeTests, TestWhich)
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001563
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001564if __name__ == '__main__':
Walter Dörwald21d3a322003-05-01 17:45:56 +00001565 test_main()