blob: 9c0c52cce8164ed16bb0ee2da3b4cceaf39252bd [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:
162 if (func is os.remove or
163 hasattr(os, 'unlinkat') and func is os.unlinkat):
164 self.assertIn(arg, [self.child_file_path, self.child_dir_path])
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000165 else:
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200166 if self.errorState == 1:
167 self.assertEqual(func, os.rmdir)
168 else:
169 self.assertIs(func, os.listdir, "func must be os.listdir")
170 self.assertIn(arg, [TESTFN, self.child_dir_path])
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000171 self.assertTrue(issubclass(exc[0], OSError))
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200172 self.errorState += 1
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000173 else:
174 self.assertEqual(func, os.rmdir)
175 self.assertEqual(arg, TESTFN)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000176 self.assertTrue(issubclass(exc[0], OSError))
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200177 self.errorState = 3
178
179 def test_rmtree_does_not_choke_on_failing_lstat(self):
180 try:
181 orig_lstat = os.lstat
182 def raiser(fn):
183 if fn != TESTFN:
184 raise OSError()
185 else:
186 return orig_lstat(fn)
187 os.lstat = raiser
188
189 os.mkdir(TESTFN)
190 write_file((TESTFN, 'foo'), 'foo')
191 shutil.rmtree(TESTFN)
192 finally:
193 os.lstat = orig_lstat
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000194
Antoine Pitrou78091e62011-12-29 18:54:15 +0100195 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
196 @support.skip_unless_symlink
197 def test_copymode_follow_symlinks(self):
198 tmp_dir = self.mkdtemp()
199 src = os.path.join(tmp_dir, 'foo')
200 dst = os.path.join(tmp_dir, 'bar')
201 src_link = os.path.join(tmp_dir, 'baz')
202 dst_link = os.path.join(tmp_dir, 'quux')
203 write_file(src, 'foo')
204 write_file(dst, 'foo')
205 os.symlink(src, src_link)
206 os.symlink(dst, dst_link)
207 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
208 # file to file
209 os.chmod(dst, stat.S_IRWXO)
210 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
211 shutil.copymode(src, dst)
212 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
213 # follow src link
214 os.chmod(dst, stat.S_IRWXO)
215 shutil.copymode(src_link, dst)
216 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
217 # follow dst link
218 os.chmod(dst, stat.S_IRWXO)
219 shutil.copymode(src, dst_link)
220 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
221 # follow both links
222 os.chmod(dst, stat.S_IRWXO)
223 shutil.copymode(src_link, dst)
224 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
225
226 @unittest.skipUnless(hasattr(os, 'lchmod'), 'requires os.lchmod')
227 @support.skip_unless_symlink
228 def test_copymode_symlink_to_symlink(self):
229 tmp_dir = self.mkdtemp()
230 src = os.path.join(tmp_dir, 'foo')
231 dst = os.path.join(tmp_dir, 'bar')
232 src_link = os.path.join(tmp_dir, 'baz')
233 dst_link = os.path.join(tmp_dir, 'quux')
234 write_file(src, 'foo')
235 write_file(dst, 'foo')
236 os.symlink(src, src_link)
237 os.symlink(dst, dst_link)
238 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
239 os.chmod(dst, stat.S_IRWXU)
240 os.lchmod(src_link, stat.S_IRWXO|stat.S_IRWXG)
241 # link to link
242 os.lchmod(dst_link, stat.S_IRWXO)
243 shutil.copymode(src_link, dst_link, symlinks=True)
244 self.assertEqual(os.lstat(src_link).st_mode,
245 os.lstat(dst_link).st_mode)
246 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
247 # src link - use chmod
248 os.lchmod(dst_link, stat.S_IRWXO)
249 shutil.copymode(src_link, dst, symlinks=True)
250 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
251 # dst link - use chmod
252 os.lchmod(dst_link, stat.S_IRWXO)
253 shutil.copymode(src, dst_link, symlinks=True)
254 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
255
256 @unittest.skipIf(hasattr(os, 'lchmod'), 'requires os.lchmod to be missing')
257 @support.skip_unless_symlink
258 def test_copymode_symlink_to_symlink_wo_lchmod(self):
259 tmp_dir = self.mkdtemp()
260 src = os.path.join(tmp_dir, 'foo')
261 dst = os.path.join(tmp_dir, 'bar')
262 src_link = os.path.join(tmp_dir, 'baz')
263 dst_link = os.path.join(tmp_dir, 'quux')
264 write_file(src, 'foo')
265 write_file(dst, 'foo')
266 os.symlink(src, src_link)
267 os.symlink(dst, dst_link)
268 shutil.copymode(src_link, dst_link, symlinks=True) # silent fail
269
270 @support.skip_unless_symlink
271 def test_copystat_symlinks(self):
272 tmp_dir = self.mkdtemp()
273 src = os.path.join(tmp_dir, 'foo')
274 dst = os.path.join(tmp_dir, 'bar')
275 src_link = os.path.join(tmp_dir, 'baz')
276 dst_link = os.path.join(tmp_dir, 'qux')
277 write_file(src, 'foo')
278 src_stat = os.stat(src)
279 os.utime(src, (src_stat.st_atime,
280 src_stat.st_mtime - 42.0)) # ensure different mtimes
281 write_file(dst, 'bar')
282 self.assertNotEqual(os.stat(src).st_mtime, os.stat(dst).st_mtime)
283 os.symlink(src, src_link)
284 os.symlink(dst, dst_link)
285 if hasattr(os, 'lchmod'):
286 os.lchmod(src_link, stat.S_IRWXO)
287 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
288 os.lchflags(src_link, stat.UF_NODUMP)
289 src_link_stat = os.lstat(src_link)
290 # follow
291 if hasattr(os, 'lchmod'):
292 shutil.copystat(src_link, dst_link, symlinks=False)
293 self.assertNotEqual(src_link_stat.st_mode, os.stat(dst).st_mode)
294 # don't follow
295 shutil.copystat(src_link, dst_link, symlinks=True)
296 dst_link_stat = os.lstat(dst_link)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700297 if os.utime in os.supports_follow_symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100298 for attr in 'st_atime', 'st_mtime':
299 # The modification times may be truncated in the new file.
300 self.assertLessEqual(getattr(src_link_stat, attr),
301 getattr(dst_link_stat, attr) + 1)
302 if hasattr(os, 'lchmod'):
303 self.assertEqual(src_link_stat.st_mode, dst_link_stat.st_mode)
304 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
305 self.assertEqual(src_link_stat.st_flags, dst_link_stat.st_flags)
306 # tell to follow but dst is not a link
307 shutil.copystat(src_link, dst, symlinks=True)
308 self.assertTrue(abs(os.stat(src).st_mtime - os.stat(dst).st_mtime) <
309 00000.1)
310
Ned Deilybaf75712012-05-10 17:05:19 -0700311 @unittest.skipUnless(hasattr(os, 'chflags') and
312 hasattr(errno, 'EOPNOTSUPP') and
313 hasattr(errno, 'ENOTSUP'),
314 "requires os.chflags, EOPNOTSUPP & ENOTSUP")
315 def test_copystat_handles_harmless_chflags_errors(self):
316 tmpdir = self.mkdtemp()
317 file1 = os.path.join(tmpdir, 'file1')
318 file2 = os.path.join(tmpdir, 'file2')
319 write_file(file1, 'xxx')
320 write_file(file2, 'xxx')
321
322 def make_chflags_raiser(err):
323 ex = OSError()
324
Larry Hastings90867a52012-06-22 17:01:41 -0700325 def _chflags_raiser(path, flags, *, follow_symlinks=True):
Ned Deilybaf75712012-05-10 17:05:19 -0700326 ex.errno = err
327 raise ex
328 return _chflags_raiser
329 old_chflags = os.chflags
330 try:
331 for err in errno.EOPNOTSUPP, errno.ENOTSUP:
332 os.chflags = make_chflags_raiser(err)
333 shutil.copystat(file1, file2)
334 # assert others errors break it
335 os.chflags = make_chflags_raiser(errno.EOPNOTSUPP + errno.ENOTSUP)
336 self.assertRaises(OSError, shutil.copystat, file1, file2)
337 finally:
338 os.chflags = old_chflags
339
Antoine Pitrou424246f2012-05-12 19:02:01 +0200340 @support.skip_unless_xattr
341 def test_copyxattr(self):
342 tmp_dir = self.mkdtemp()
343 src = os.path.join(tmp_dir, 'foo')
344 write_file(src, 'foo')
345 dst = os.path.join(tmp_dir, 'bar')
346 write_file(dst, 'bar')
347
348 # no xattr == no problem
349 shutil._copyxattr(src, dst)
350 # common case
351 os.setxattr(src, 'user.foo', b'42')
352 os.setxattr(src, 'user.bar', b'43')
353 shutil._copyxattr(src, dst)
354 self.assertEqual(os.listxattr(src), os.listxattr(dst))
355 self.assertEqual(
356 os.getxattr(src, 'user.foo'),
357 os.getxattr(dst, 'user.foo'))
358 # check errors don't affect other attrs
359 os.remove(dst)
360 write_file(dst, 'bar')
361 os_error = OSError(errno.EPERM, 'EPERM')
362
Larry Hastings9cf065c2012-06-22 16:30:09 -0700363 def _raise_on_user_foo(fname, attr, val, **kwargs):
Antoine Pitrou424246f2012-05-12 19:02:01 +0200364 if attr == 'user.foo':
365 raise os_error
366 else:
Larry Hastings9cf065c2012-06-22 16:30:09 -0700367 orig_setxattr(fname, attr, val, **kwargs)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200368 try:
369 orig_setxattr = os.setxattr
370 os.setxattr = _raise_on_user_foo
371 shutil._copyxattr(src, dst)
Antoine Pitrou61597d32012-05-12 23:37:35 +0200372 self.assertIn('user.bar', os.listxattr(dst))
Antoine Pitrou424246f2012-05-12 19:02:01 +0200373 finally:
374 os.setxattr = orig_setxattr
375
376 @support.skip_unless_symlink
377 @support.skip_unless_xattr
378 @unittest.skipUnless(hasattr(os, 'geteuid') and os.geteuid() == 0,
379 'root privileges required')
380 def test_copyxattr_symlinks(self):
381 # On Linux, it's only possible to access non-user xattr for symlinks;
382 # which in turn require root privileges. This test should be expanded
383 # as soon as other platforms gain support for extended attributes.
384 tmp_dir = self.mkdtemp()
385 src = os.path.join(tmp_dir, 'foo')
386 src_link = os.path.join(tmp_dir, 'baz')
387 write_file(src, 'foo')
388 os.symlink(src, src_link)
389 os.setxattr(src, 'trusted.foo', b'42')
Larry Hastings9cf065c2012-06-22 16:30:09 -0700390 os.setxattr(src_link, 'trusted.foo', b'43', follow_symlinks=False)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200391 dst = os.path.join(tmp_dir, 'bar')
392 dst_link = os.path.join(tmp_dir, 'qux')
393 write_file(dst, 'bar')
394 os.symlink(dst, dst_link)
395 shutil._copyxattr(src_link, dst_link, symlinks=True)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700396 self.assertEqual(os.getxattr(dst_link, 'trusted.foo', follow_symlinks=False), b'43')
Antoine Pitrou424246f2012-05-12 19:02:01 +0200397 self.assertRaises(OSError, os.getxattr, dst, 'trusted.foo')
398 shutil._copyxattr(src_link, dst, symlinks=True)
399 self.assertEqual(os.getxattr(dst, 'trusted.foo'), b'43')
400
Antoine Pitrou78091e62011-12-29 18:54:15 +0100401 @support.skip_unless_symlink
402 def test_copy_symlinks(self):
403 tmp_dir = self.mkdtemp()
404 src = os.path.join(tmp_dir, 'foo')
405 dst = os.path.join(tmp_dir, 'bar')
406 src_link = os.path.join(tmp_dir, 'baz')
407 write_file(src, 'foo')
408 os.symlink(src, src_link)
409 if hasattr(os, 'lchmod'):
410 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
411 # don't follow
412 shutil.copy(src_link, dst, symlinks=False)
413 self.assertFalse(os.path.islink(dst))
414 self.assertEqual(read_file(src), read_file(dst))
415 os.remove(dst)
416 # follow
417 shutil.copy(src_link, dst, symlinks=True)
418 self.assertTrue(os.path.islink(dst))
419 self.assertEqual(os.readlink(dst), os.readlink(src_link))
420 if hasattr(os, 'lchmod'):
421 self.assertEqual(os.lstat(src_link).st_mode,
422 os.lstat(dst).st_mode)
423
424 @support.skip_unless_symlink
425 def test_copy2_symlinks(self):
426 tmp_dir = self.mkdtemp()
427 src = os.path.join(tmp_dir, 'foo')
428 dst = os.path.join(tmp_dir, 'bar')
429 src_link = os.path.join(tmp_dir, 'baz')
430 write_file(src, 'foo')
431 os.symlink(src, src_link)
432 if hasattr(os, 'lchmod'):
433 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
434 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
435 os.lchflags(src_link, stat.UF_NODUMP)
436 src_stat = os.stat(src)
437 src_link_stat = os.lstat(src_link)
438 # follow
439 shutil.copy2(src_link, dst, symlinks=False)
440 self.assertFalse(os.path.islink(dst))
441 self.assertEqual(read_file(src), read_file(dst))
442 os.remove(dst)
443 # don't follow
444 shutil.copy2(src_link, dst, symlinks=True)
445 self.assertTrue(os.path.islink(dst))
446 self.assertEqual(os.readlink(dst), os.readlink(src_link))
447 dst_stat = os.lstat(dst)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700448 if os.utime in os.supports_follow_symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100449 for attr in 'st_atime', 'st_mtime':
450 # The modification times may be truncated in the new file.
451 self.assertLessEqual(getattr(src_link_stat, attr),
452 getattr(dst_stat, attr) + 1)
453 if hasattr(os, 'lchmod'):
454 self.assertEqual(src_link_stat.st_mode, dst_stat.st_mode)
455 self.assertNotEqual(src_stat.st_mode, dst_stat.st_mode)
456 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
457 self.assertEqual(src_link_stat.st_flags, dst_stat.st_flags)
458
Antoine Pitrou424246f2012-05-12 19:02:01 +0200459 @support.skip_unless_xattr
460 def test_copy2_xattr(self):
461 tmp_dir = self.mkdtemp()
462 src = os.path.join(tmp_dir, 'foo')
463 dst = os.path.join(tmp_dir, 'bar')
464 write_file(src, 'foo')
465 os.setxattr(src, 'user.foo', b'42')
466 shutil.copy2(src, dst)
467 self.assertEqual(
468 os.getxattr(src, 'user.foo'),
469 os.getxattr(dst, 'user.foo'))
470 os.remove(dst)
471
Antoine Pitrou78091e62011-12-29 18:54:15 +0100472 @support.skip_unless_symlink
473 def test_copyfile_symlinks(self):
474 tmp_dir = self.mkdtemp()
475 src = os.path.join(tmp_dir, 'src')
476 dst = os.path.join(tmp_dir, 'dst')
477 dst_link = os.path.join(tmp_dir, 'dst_link')
478 link = os.path.join(tmp_dir, 'link')
479 write_file(src, 'foo')
480 os.symlink(src, link)
481 # don't follow
482 shutil.copyfile(link, dst_link, symlinks=True)
483 self.assertTrue(os.path.islink(dst_link))
484 self.assertEqual(os.readlink(link), os.readlink(dst_link))
485 # follow
486 shutil.copyfile(link, dst)
487 self.assertFalse(os.path.islink(dst))
488
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000489 def test_rmtree_dont_delete_file(self):
490 # When called on a file instead of a directory, don't delete it.
491 handle, path = tempfile.mkstemp()
Victor Stinnerbf816222011-06-30 23:25:47 +0200492 os.close(handle)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200493 self.assertRaises(NotADirectoryError, shutil.rmtree, path)
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000494 os.remove(path)
495
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000496 def test_copytree_simple(self):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000497 src_dir = tempfile.mkdtemp()
498 dst_dir = os.path.join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200499 self.addCleanup(shutil.rmtree, src_dir)
500 self.addCleanup(shutil.rmtree, os.path.dirname(dst_dir))
501 write_file((src_dir, 'test.txt'), '123')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000502 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200503 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000504
Éric Araujoa7e33a12011-08-12 19:51:35 +0200505 shutil.copytree(src_dir, dst_dir)
506 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test.txt')))
507 self.assertTrue(os.path.isdir(os.path.join(dst_dir, 'test_dir')))
508 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test_dir',
509 'test.txt')))
510 actual = read_file((dst_dir, 'test.txt'))
511 self.assertEqual(actual, '123')
512 actual = read_file((dst_dir, 'test_dir', 'test.txt'))
513 self.assertEqual(actual, '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000514
Antoine Pitrou78091e62011-12-29 18:54:15 +0100515 @support.skip_unless_symlink
516 def test_copytree_symlinks(self):
517 tmp_dir = self.mkdtemp()
518 src_dir = os.path.join(tmp_dir, 'src')
519 dst_dir = os.path.join(tmp_dir, 'dst')
520 sub_dir = os.path.join(src_dir, 'sub')
521 os.mkdir(src_dir)
522 os.mkdir(sub_dir)
523 write_file((src_dir, 'file.txt'), 'foo')
524 src_link = os.path.join(sub_dir, 'link')
525 dst_link = os.path.join(dst_dir, 'sub/link')
526 os.symlink(os.path.join(src_dir, 'file.txt'),
527 src_link)
528 if hasattr(os, 'lchmod'):
529 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
530 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
531 os.lchflags(src_link, stat.UF_NODUMP)
532 src_stat = os.lstat(src_link)
533 shutil.copytree(src_dir, dst_dir, symlinks=True)
534 self.assertTrue(os.path.islink(os.path.join(dst_dir, 'sub', 'link')))
535 self.assertEqual(os.readlink(os.path.join(dst_dir, 'sub', 'link')),
536 os.path.join(src_dir, 'file.txt'))
537 dst_stat = os.lstat(dst_link)
538 if hasattr(os, 'lchmod'):
539 self.assertEqual(dst_stat.st_mode, src_stat.st_mode)
540 if hasattr(os, 'lchflags'):
541 self.assertEqual(dst_stat.st_flags, src_stat.st_flags)
542
Georg Brandl2ee470f2008-07-16 12:55:28 +0000543 def test_copytree_with_exclude(self):
Georg Brandl2ee470f2008-07-16 12:55:28 +0000544 # creating data
545 join = os.path.join
546 exists = os.path.exists
547 src_dir = tempfile.mkdtemp()
Georg Brandl2ee470f2008-07-16 12:55:28 +0000548 try:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000549 dst_dir = join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200550 write_file((src_dir, 'test.txt'), '123')
551 write_file((src_dir, 'test.tmp'), '123')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000552 os.mkdir(join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200553 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000554 os.mkdir(join(src_dir, 'test_dir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200555 write_file((src_dir, 'test_dir2', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000556 os.mkdir(join(src_dir, 'test_dir2', 'subdir'))
557 os.mkdir(join(src_dir, 'test_dir2', 'subdir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200558 write_file((src_dir, 'test_dir2', 'subdir', 'test.txt'), '456')
559 write_file((src_dir, 'test_dir2', 'subdir2', 'test.py'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000560
561 # testing glob-like patterns
562 try:
563 patterns = shutil.ignore_patterns('*.tmp', 'test_dir2')
564 shutil.copytree(src_dir, dst_dir, ignore=patterns)
565 # checking the result: some elements should not be copied
566 self.assertTrue(exists(join(dst_dir, 'test.txt')))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200567 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
568 self.assertFalse(exists(join(dst_dir, 'test_dir2')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000569 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200570 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000571 try:
572 patterns = shutil.ignore_patterns('*.tmp', 'subdir*')
573 shutil.copytree(src_dir, dst_dir, ignore=patterns)
574 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200575 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
576 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2')))
577 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000578 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200579 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000580
581 # testing callable-style
582 try:
583 def _filter(src, names):
584 res = []
585 for name in names:
586 path = os.path.join(src, name)
587
588 if (os.path.isdir(path) and
589 path.split()[-1] == 'subdir'):
590 res.append(name)
591 elif os.path.splitext(path)[-1] in ('.py'):
592 res.append(name)
593 return res
594
595 shutil.copytree(src_dir, dst_dir, ignore=_filter)
596
597 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200598 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2',
599 'test.py')))
600 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000601
602 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200603 shutil.rmtree(dst_dir)
Georg Brandl2ee470f2008-07-16 12:55:28 +0000604 finally:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000605 shutil.rmtree(src_dir)
606 shutil.rmtree(os.path.dirname(dst_dir))
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000607
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000608 @unittest.skipUnless(hasattr(os, 'link'), 'requires os.link')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000609 def test_dont_copy_file_onto_link_to_itself(self):
Georg Brandl724d0892010-12-05 07:51:39 +0000610 # Temporarily disable test on Windows.
611 if os.name == 'nt':
612 return
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000613 # bug 851123.
614 os.mkdir(TESTFN)
615 src = os.path.join(TESTFN, 'cheese')
616 dst = os.path.join(TESTFN, 'shop')
617 try:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000618 with open(src, 'w') as f:
619 f.write('cheddar')
620 os.link(src, dst)
621 self.assertRaises(shutil.Error, shutil.copyfile, src, dst)
622 with open(src, 'r') as f:
623 self.assertEqual(f.read(), 'cheddar')
624 os.remove(dst)
625 finally:
626 shutil.rmtree(TESTFN, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000627
Brian Curtin3b4499c2010-12-28 14:31:47 +0000628 @support.skip_unless_symlink
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000629 def test_dont_copy_file_onto_symlink_to_itself(self):
630 # bug 851123.
631 os.mkdir(TESTFN)
632 src = os.path.join(TESTFN, 'cheese')
633 dst = os.path.join(TESTFN, 'shop')
634 try:
635 with open(src, 'w') as f:
636 f.write('cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000637 # Using `src` here would mean we end up with a symlink pointing
638 # to TESTFN/TESTFN/cheese, while it should point at
639 # TESTFN/cheese.
640 os.symlink('cheese', dst)
641 self.assertRaises(shutil.Error, shutil.copyfile, src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +0000642 with open(src, 'r') as f:
643 self.assertEqual(f.read(), 'cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000644 os.remove(dst)
645 finally:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000646 shutil.rmtree(TESTFN, ignore_errors=True)
Johannes Gijsbers68128712004-08-14 13:57:08 +0000647
Brian Curtin3b4499c2010-12-28 14:31:47 +0000648 @support.skip_unless_symlink
Brian Curtind40e6f72010-07-08 21:39:08 +0000649 def test_rmtree_on_symlink(self):
650 # bug 1669.
651 os.mkdir(TESTFN)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000652 try:
Brian Curtind40e6f72010-07-08 21:39:08 +0000653 src = os.path.join(TESTFN, 'cheese')
654 dst = os.path.join(TESTFN, 'shop')
655 os.mkdir(src)
656 os.symlink(src, dst)
657 self.assertRaises(OSError, shutil.rmtree, dst)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200658 shutil.rmtree(dst, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000659 finally:
Brian Curtind40e6f72010-07-08 21:39:08 +0000660 shutil.rmtree(TESTFN, ignore_errors=True)
661
662 if hasattr(os, "mkfifo"):
663 # Issue #3002: copyfile and copytree block indefinitely on named pipes
664 def test_copyfile_named_pipe(self):
665 os.mkfifo(TESTFN)
666 try:
667 self.assertRaises(shutil.SpecialFileError,
668 shutil.copyfile, TESTFN, TESTFN2)
669 self.assertRaises(shutil.SpecialFileError,
670 shutil.copyfile, __file__, TESTFN)
671 finally:
672 os.remove(TESTFN)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000673
Brian Curtin3b4499c2010-12-28 14:31:47 +0000674 @support.skip_unless_symlink
Brian Curtin52173d42010-12-02 18:29:18 +0000675 def test_copytree_named_pipe(self):
676 os.mkdir(TESTFN)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000677 try:
Brian Curtin52173d42010-12-02 18:29:18 +0000678 subdir = os.path.join(TESTFN, "subdir")
679 os.mkdir(subdir)
680 pipe = os.path.join(subdir, "mypipe")
681 os.mkfifo(pipe)
682 try:
683 shutil.copytree(TESTFN, TESTFN2)
684 except shutil.Error as e:
685 errors = e.args[0]
686 self.assertEqual(len(errors), 1)
687 src, dst, error_msg = errors[0]
688 self.assertEqual("`%s` is a named pipe" % pipe, error_msg)
689 else:
690 self.fail("shutil.Error should have been raised")
691 finally:
692 shutil.rmtree(TESTFN, ignore_errors=True)
693 shutil.rmtree(TESTFN2, ignore_errors=True)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000694
Tarek Ziadé5340db32010-04-19 22:30:51 +0000695 def test_copytree_special_func(self):
696
697 src_dir = self.mkdtemp()
698 dst_dir = os.path.join(self.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200699 write_file((src_dir, 'test.txt'), '123')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000700 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200701 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000702
703 copied = []
704 def _copy(src, dst):
705 copied.append((src, dst))
706
707 shutil.copytree(src_dir, dst_dir, copy_function=_copy)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000708 self.assertEqual(len(copied), 2)
Tarek Ziadé5340db32010-04-19 22:30:51 +0000709
Brian Curtin3b4499c2010-12-28 14:31:47 +0000710 @support.skip_unless_symlink
Tarek Ziadéfb437512010-04-20 08:57:33 +0000711 def test_copytree_dangling_symlinks(self):
712
713 # a dangling symlink raises an error at the end
714 src_dir = self.mkdtemp()
715 dst_dir = os.path.join(self.mkdtemp(), 'destination')
716 os.symlink('IDONTEXIST', os.path.join(src_dir, 'test.txt'))
717 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200718 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadéfb437512010-04-20 08:57:33 +0000719 self.assertRaises(Error, shutil.copytree, src_dir, dst_dir)
720
721 # a dangling symlink is ignored with the proper flag
722 dst_dir = os.path.join(self.mkdtemp(), 'destination2')
723 shutil.copytree(src_dir, dst_dir, ignore_dangling_symlinks=True)
724 self.assertNotIn('test.txt', os.listdir(dst_dir))
725
726 # a dangling symlink is copied if symlinks=True
727 dst_dir = os.path.join(self.mkdtemp(), 'destination3')
728 shutil.copytree(src_dir, dst_dir, symlinks=True)
729 self.assertIn('test.txt', os.listdir(dst_dir))
730
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400731 def _copy_file(self, method):
732 fname = 'test.txt'
733 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200734 write_file((tmpdir, fname), 'xxx')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400735 file1 = os.path.join(tmpdir, fname)
736 tmpdir2 = self.mkdtemp()
737 method(file1, tmpdir2)
738 file2 = os.path.join(tmpdir2, fname)
739 return (file1, file2)
740
741 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
742 def test_copy(self):
743 # Ensure that the copied file exists and has the same mode bits.
744 file1, file2 = self._copy_file(shutil.copy)
745 self.assertTrue(os.path.exists(file2))
746 self.assertEqual(os.stat(file1).st_mode, os.stat(file2).st_mode)
747
748 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
Senthil Kumaran0c2dba52011-07-03 18:21:38 -0700749 @unittest.skipUnless(hasattr(os, 'utime'), 'requires os.utime')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400750 def test_copy2(self):
751 # Ensure that the copied file exists and has the same mode and
752 # modification time bits.
753 file1, file2 = self._copy_file(shutil.copy2)
754 self.assertTrue(os.path.exists(file2))
755 file1_stat = os.stat(file1)
756 file2_stat = os.stat(file2)
757 self.assertEqual(file1_stat.st_mode, file2_stat.st_mode)
758 for attr in 'st_atime', 'st_mtime':
759 # The modification times may be truncated in the new file.
760 self.assertLessEqual(getattr(file1_stat, attr),
761 getattr(file2_stat, attr) + 1)
762 if hasattr(os, 'chflags') and hasattr(file1_stat, 'st_flags'):
763 self.assertEqual(getattr(file1_stat, 'st_flags'),
764 getattr(file2_stat, 'st_flags'))
765
Ezio Melotti975077a2011-05-19 22:03:22 +0300766 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000767 def test_make_tarball(self):
768 # creating something to tar
769 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200770 write_file((tmpdir, 'file1'), 'xxx')
771 write_file((tmpdir, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000772 os.mkdir(os.path.join(tmpdir, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200773 write_file((tmpdir, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000774
775 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400776 # force shutil to create the directory
777 os.rmdir(tmpdir2)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000778 unittest.skipUnless(splitdrive(tmpdir)[0] == splitdrive(tmpdir2)[0],
779 "source and target should be on same drive")
780
781 base_name = os.path.join(tmpdir2, 'archive')
782
783 # working with relative paths to avoid tar warnings
784 old_dir = os.getcwd()
785 os.chdir(tmpdir)
786 try:
787 _make_tarball(splitdrive(base_name)[1], '.')
788 finally:
789 os.chdir(old_dir)
790
791 # check if the compressed tarball was created
792 tarball = base_name + '.tar.gz'
793 self.assertTrue(os.path.exists(tarball))
794
795 # trying an uncompressed one
796 base_name = os.path.join(tmpdir2, 'archive')
797 old_dir = os.getcwd()
798 os.chdir(tmpdir)
799 try:
800 _make_tarball(splitdrive(base_name)[1], '.', compress=None)
801 finally:
802 os.chdir(old_dir)
803 tarball = base_name + '.tar'
804 self.assertTrue(os.path.exists(tarball))
805
806 def _tarinfo(self, path):
807 tar = tarfile.open(path)
808 try:
809 names = tar.getnames()
810 names.sort()
811 return tuple(names)
812 finally:
813 tar.close()
814
815 def _create_files(self):
816 # creating something to tar
817 tmpdir = self.mkdtemp()
818 dist = os.path.join(tmpdir, 'dist')
819 os.mkdir(dist)
Éric Araujoa7e33a12011-08-12 19:51:35 +0200820 write_file((dist, 'file1'), 'xxx')
821 write_file((dist, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000822 os.mkdir(os.path.join(dist, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200823 write_file((dist, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000824 os.mkdir(os.path.join(dist, 'sub2'))
825 tmpdir2 = self.mkdtemp()
826 base_name = os.path.join(tmpdir2, 'archive')
827 return tmpdir, tmpdir2, base_name
828
Ezio Melotti975077a2011-05-19 22:03:22 +0300829 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000830 @unittest.skipUnless(find_executable('tar') and find_executable('gzip'),
831 'Need the tar command to run')
832 def test_tarfile_vs_tar(self):
833 tmpdir, tmpdir2, base_name = self._create_files()
834 old_dir = os.getcwd()
835 os.chdir(tmpdir)
836 try:
837 _make_tarball(base_name, 'dist')
838 finally:
839 os.chdir(old_dir)
840
841 # check if the compressed tarball was created
842 tarball = base_name + '.tar.gz'
843 self.assertTrue(os.path.exists(tarball))
844
845 # now create another tarball using `tar`
846 tarball2 = os.path.join(tmpdir, 'archive2.tar.gz')
847 tar_cmd = ['tar', '-cf', 'archive2.tar', 'dist']
848 gzip_cmd = ['gzip', '-f9', 'archive2.tar']
849 old_dir = os.getcwd()
850 os.chdir(tmpdir)
851 try:
852 with captured_stdout() as s:
853 spawn(tar_cmd)
854 spawn(gzip_cmd)
855 finally:
856 os.chdir(old_dir)
857
858 self.assertTrue(os.path.exists(tarball2))
859 # let's compare both tarballs
Ezio Melottib3aedd42010-11-20 19:04:17 +0000860 self.assertEqual(self._tarinfo(tarball), self._tarinfo(tarball2))
Tarek Ziadé396fad72010-02-23 05:30:31 +0000861
862 # trying an uncompressed one
863 base_name = os.path.join(tmpdir2, 'archive')
864 old_dir = os.getcwd()
865 os.chdir(tmpdir)
866 try:
867 _make_tarball(base_name, 'dist', compress=None)
868 finally:
869 os.chdir(old_dir)
870 tarball = base_name + '.tar'
871 self.assertTrue(os.path.exists(tarball))
872
873 # now for a dry_run
874 base_name = os.path.join(tmpdir2, 'archive')
875 old_dir = os.getcwd()
876 os.chdir(tmpdir)
877 try:
878 _make_tarball(base_name, 'dist', compress=None, dry_run=True)
879 finally:
880 os.chdir(old_dir)
881 tarball = base_name + '.tar'
882 self.assertTrue(os.path.exists(tarball))
883
Ezio Melotti975077a2011-05-19 22:03:22 +0300884 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000885 @unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run')
886 def test_make_zipfile(self):
887 # creating something to tar
888 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200889 write_file((tmpdir, 'file1'), 'xxx')
890 write_file((tmpdir, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000891
892 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400893 # force shutil to create the directory
894 os.rmdir(tmpdir2)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000895 base_name = os.path.join(tmpdir2, 'archive')
896 _make_zipfile(base_name, tmpdir)
897
898 # check if the compressed tarball was created
899 tarball = base_name + '.zip'
Éric Araujo1c505492010-11-06 02:12:51 +0000900 self.assertTrue(os.path.exists(tarball))
Tarek Ziadé396fad72010-02-23 05:30:31 +0000901
902
903 def test_make_archive(self):
904 tmpdir = self.mkdtemp()
905 base_name = os.path.join(tmpdir, 'archive')
906 self.assertRaises(ValueError, make_archive, base_name, 'xxx')
907
Ezio Melotti975077a2011-05-19 22:03:22 +0300908 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000909 def test_make_archive_owner_group(self):
910 # testing make_archive with owner and group, with various combinations
911 # this works even if there's not gid/uid support
912 if UID_GID_SUPPORT:
913 group = grp.getgrgid(0)[0]
914 owner = pwd.getpwuid(0)[0]
915 else:
916 group = owner = 'root'
917
918 base_dir, root_dir, base_name = self._create_files()
919 base_name = os.path.join(self.mkdtemp() , 'archive')
920 res = make_archive(base_name, 'zip', root_dir, base_dir, owner=owner,
921 group=group)
922 self.assertTrue(os.path.exists(res))
923
924 res = make_archive(base_name, 'zip', root_dir, base_dir)
925 self.assertTrue(os.path.exists(res))
926
927 res = make_archive(base_name, 'tar', root_dir, base_dir,
928 owner=owner, group=group)
929 self.assertTrue(os.path.exists(res))
930
931 res = make_archive(base_name, 'tar', root_dir, base_dir,
932 owner='kjhkjhkjg', group='oihohoh')
933 self.assertTrue(os.path.exists(res))
934
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000935
Ezio Melotti975077a2011-05-19 22:03:22 +0300936 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000937 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
938 def test_tarfile_root_owner(self):
939 tmpdir, tmpdir2, base_name = self._create_files()
940 old_dir = os.getcwd()
941 os.chdir(tmpdir)
942 group = grp.getgrgid(0)[0]
943 owner = pwd.getpwuid(0)[0]
944 try:
945 archive_name = _make_tarball(base_name, 'dist', compress=None,
946 owner=owner, group=group)
947 finally:
948 os.chdir(old_dir)
949
950 # check if the compressed tarball was created
951 self.assertTrue(os.path.exists(archive_name))
952
953 # now checks the rights
954 archive = tarfile.open(archive_name)
955 try:
956 for member in archive.getmembers():
Ezio Melottib3aedd42010-11-20 19:04:17 +0000957 self.assertEqual(member.uid, 0)
958 self.assertEqual(member.gid, 0)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000959 finally:
960 archive.close()
961
962 def test_make_archive_cwd(self):
963 current_dir = os.getcwd()
964 def _breaks(*args, **kw):
965 raise RuntimeError()
966
967 register_archive_format('xxx', _breaks, [], 'xxx file')
968 try:
969 try:
970 make_archive('xxx', 'xxx', root_dir=self.mkdtemp())
971 except Exception:
972 pass
Ezio Melottib3aedd42010-11-20 19:04:17 +0000973 self.assertEqual(os.getcwd(), current_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000974 finally:
975 unregister_archive_format('xxx')
976
977 def test_register_archive_format(self):
978
979 self.assertRaises(TypeError, register_archive_format, 'xxx', 1)
980 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
981 1)
982 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
983 [(1, 2), (1, 2, 3)])
984
985 register_archive_format('xxx', lambda: x, [(1, 2)], 'xxx file')
986 formats = [name for name, params in get_archive_formats()]
987 self.assertIn('xxx', formats)
988
989 unregister_archive_format('xxx')
990 formats = [name for name, params in get_archive_formats()]
991 self.assertNotIn('xxx', formats)
992
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000993 def _compare_dirs(self, dir1, dir2):
994 # check that dir1 and dir2 are equivalent,
995 # return the diff
996 diff = []
997 for root, dirs, files in os.walk(dir1):
998 for file_ in files:
999 path = os.path.join(root, file_)
1000 target_path = os.path.join(dir2, os.path.split(path)[-1])
1001 if not os.path.exists(target_path):
1002 diff.append(file_)
1003 return diff
1004
Ezio Melotti975077a2011-05-19 22:03:22 +03001005 @requires_zlib
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001006 def test_unpack_archive(self):
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001007 formats = ['tar', 'gztar', 'zip']
1008 if BZ2_SUPPORTED:
1009 formats.append('bztar')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001010
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001011 for format in formats:
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001012 tmpdir = self.mkdtemp()
1013 base_dir, root_dir, base_name = self._create_files()
1014 tmpdir2 = self.mkdtemp()
1015 filename = make_archive(base_name, format, root_dir, base_dir)
1016
1017 # let's try to unpack it now
1018 unpack_archive(filename, tmpdir2)
1019 diff = self._compare_dirs(tmpdir, tmpdir2)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001020 self.assertEqual(diff, [])
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001021
Nick Coghlanabf202d2011-03-16 13:52:20 -04001022 # and again, this time with the format specified
1023 tmpdir3 = self.mkdtemp()
1024 unpack_archive(filename, tmpdir3, format=format)
1025 diff = self._compare_dirs(tmpdir, tmpdir3)
1026 self.assertEqual(diff, [])
1027 self.assertRaises(shutil.ReadError, unpack_archive, TESTFN)
1028 self.assertRaises(ValueError, unpack_archive, TESTFN, format='xxx')
1029
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001030 def test_unpack_registery(self):
1031
1032 formats = get_unpack_formats()
1033
1034 def _boo(filename, extract_dir, extra):
Ezio Melottib3aedd42010-11-20 19:04:17 +00001035 self.assertEqual(extra, 1)
1036 self.assertEqual(filename, 'stuff.boo')
1037 self.assertEqual(extract_dir, 'xx')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001038
1039 register_unpack_format('Boo', ['.boo', '.b2'], _boo, [('extra', 1)])
1040 unpack_archive('stuff.boo', 'xx')
1041
1042 # trying to register a .boo unpacker again
1043 self.assertRaises(RegistryError, register_unpack_format, 'Boo2',
1044 ['.boo'], _boo)
1045
1046 # should work now
1047 unregister_unpack_format('Boo')
1048 register_unpack_format('Boo2', ['.boo'], _boo)
1049 self.assertIn(('Boo2', ['.boo'], ''), get_unpack_formats())
1050 self.assertNotIn(('Boo', ['.boo'], ''), get_unpack_formats())
1051
1052 # let's leave a clean state
1053 unregister_unpack_format('Boo2')
Ezio Melottib3aedd42010-11-20 19:04:17 +00001054 self.assertEqual(get_unpack_formats(), formats)
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001055
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001056 @unittest.skipUnless(hasattr(shutil, 'disk_usage'),
1057 "disk_usage not available on this platform")
1058 def test_disk_usage(self):
1059 usage = shutil.disk_usage(os.getcwd())
Éric Araujo2ee61882011-07-02 16:45:45 +02001060 self.assertGreater(usage.total, 0)
1061 self.assertGreater(usage.used, 0)
1062 self.assertGreaterEqual(usage.free, 0)
1063 self.assertGreaterEqual(usage.total, usage.used)
1064 self.assertGreater(usage.total, usage.free)
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001065
Sandro Tosid902a142011-08-22 23:28:27 +02001066 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1067 @unittest.skipUnless(hasattr(os, 'chown'), 'requires os.chown')
1068 def test_chown(self):
1069
1070 # cleaned-up automatically by TestShutil.tearDown method
1071 dirname = self.mkdtemp()
1072 filename = tempfile.mktemp(dir=dirname)
1073 write_file(filename, 'testing chown function')
1074
1075 with self.assertRaises(ValueError):
1076 shutil.chown(filename)
1077
1078 with self.assertRaises(LookupError):
1079 shutil.chown(filename, user='non-exising username')
1080
1081 with self.assertRaises(LookupError):
1082 shutil.chown(filename, group='non-exising groupname')
1083
1084 with self.assertRaises(TypeError):
1085 shutil.chown(filename, b'spam')
1086
1087 with self.assertRaises(TypeError):
1088 shutil.chown(filename, 3.14)
1089
1090 uid = os.getuid()
1091 gid = os.getgid()
1092
1093 def check_chown(path, uid=None, gid=None):
1094 s = os.stat(filename)
1095 if uid is not None:
1096 self.assertEqual(uid, s.st_uid)
1097 if gid is not None:
1098 self.assertEqual(gid, s.st_gid)
1099
1100 shutil.chown(filename, uid, gid)
1101 check_chown(filename, uid, gid)
1102 shutil.chown(filename, uid)
1103 check_chown(filename, uid)
1104 shutil.chown(filename, user=uid)
1105 check_chown(filename, uid)
1106 shutil.chown(filename, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001107 check_chown(filename, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001108
1109 shutil.chown(dirname, uid, gid)
1110 check_chown(dirname, uid, gid)
1111 shutil.chown(dirname, uid)
1112 check_chown(dirname, uid)
1113 shutil.chown(dirname, user=uid)
1114 check_chown(dirname, uid)
1115 shutil.chown(dirname, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001116 check_chown(dirname, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001117
1118 user = pwd.getpwuid(uid)[0]
1119 group = grp.getgrgid(gid)[0]
1120 shutil.chown(filename, user, group)
1121 check_chown(filename, uid, gid)
1122 shutil.chown(dirname, user, group)
1123 check_chown(dirname, uid, gid)
1124
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001125 def test_copy_return_value(self):
1126 # copy and copy2 both return their destination path.
1127 for fn in (shutil.copy, shutil.copy2):
1128 src_dir = self.mkdtemp()
1129 dst_dir = self.mkdtemp()
1130 src = os.path.join(src_dir, 'foo')
1131 write_file(src, 'foo')
1132 rv = fn(src, dst_dir)
1133 self.assertEqual(rv, os.path.join(dst_dir, 'foo'))
1134 rv = fn(src, os.path.join(dst_dir, 'bar'))
1135 self.assertEqual(rv, os.path.join(dst_dir, 'bar'))
1136
1137 def test_copyfile_return_value(self):
1138 # copytree returns its destination path.
1139 src_dir = self.mkdtemp()
1140 dst_dir = self.mkdtemp()
1141 dst_file = os.path.join(dst_dir, 'bar')
1142 src_file = os.path.join(src_dir, 'foo')
1143 write_file(src_file, 'foo')
1144 rv = shutil.copyfile(src_file, dst_file)
1145 self.assertTrue(os.path.exists(rv))
1146 self.assertEqual(read_file(src_file), read_file(dst_file))
1147
1148 def test_copytree_return_value(self):
1149 # copytree returns its destination path.
1150 src_dir = self.mkdtemp()
1151 dst_dir = src_dir + "dest"
1152 src = os.path.join(src_dir, 'foo')
1153 write_file(src, 'foo')
1154 rv = shutil.copytree(src_dir, dst_dir)
1155 self.assertEqual(['foo'], os.listdir(rv))
1156
Christian Heimes9bd667a2008-01-20 15:14:11 +00001157
Brian Curtinc57a3452012-06-22 16:00:30 -05001158class TestWhich(unittest.TestCase):
1159
1160 def setUp(self):
1161 self.temp_dir = tempfile.mkdtemp()
1162 # Give the temp_file an ".exe" suffix for all.
1163 # It's needed on Windows and not harmful on other platforms.
1164 self.temp_file = tempfile.NamedTemporaryFile(dir=self.temp_dir,
1165 suffix=".exe")
1166 os.chmod(self.temp_file.name, stat.S_IXUSR)
1167 self.addCleanup(self.temp_file.close)
1168 self.dir, self.file = os.path.split(self.temp_file.name)
1169
1170 def test_basic(self):
1171 # Given an EXE in a directory, it should be returned.
1172 rv = shutil.which(self.file, path=self.dir)
1173 self.assertEqual(rv, self.temp_file.name)
1174
1175 def test_full_path_short_circuit(self):
1176 # When given the fully qualified path to an executable that exists,
1177 # it should be returned.
1178 rv = shutil.which(self.temp_file.name, path=self.temp_dir)
1179 self.assertEqual(self.temp_file.name, rv)
1180
1181 def test_non_matching_mode(self):
1182 # Set the file read-only and ask for writeable files.
1183 os.chmod(self.temp_file.name, stat.S_IREAD)
1184 rv = shutil.which(self.file, path=self.dir, mode=os.W_OK)
1185 self.assertIsNone(rv)
1186
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001187 def test_relative(self):
1188 old_cwd = os.getcwd()
1189 base_dir, tail_dir = os.path.split(self.dir)
1190 os.chdir(base_dir)
1191 try:
1192 rv = shutil.which(self.file, path=tail_dir)
1193 self.assertEqual(rv, os.path.join(tail_dir, self.file))
1194 finally:
1195 os.chdir(old_cwd)
1196
Brian Curtinc57a3452012-06-22 16:00:30 -05001197 def test_nonexistent_file(self):
1198 # Return None when no matching executable file is found on the path.
1199 rv = shutil.which("foo.exe", path=self.dir)
1200 self.assertIsNone(rv)
1201
1202 @unittest.skipUnless(sys.platform == "win32",
1203 "pathext check is Windows-only")
1204 def test_pathext_checking(self):
1205 # Ask for the file without the ".exe" extension, then ensure that
1206 # it gets found properly with the extension.
1207 rv = shutil.which(self.temp_file.name[:-4], path=self.dir)
1208 self.assertEqual(self.temp_file.name, rv)
1209
1210
Christian Heimesada8c3b2008-03-18 18:26:33 +00001211class TestMove(unittest.TestCase):
1212
1213 def setUp(self):
1214 filename = "foo"
1215 self.src_dir = tempfile.mkdtemp()
1216 self.dst_dir = tempfile.mkdtemp()
1217 self.src_file = os.path.join(self.src_dir, filename)
1218 self.dst_file = os.path.join(self.dst_dir, filename)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001219 with open(self.src_file, "wb") as f:
1220 f.write(b"spam")
1221
1222 def tearDown(self):
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001223 for d in (self.src_dir, self.dst_dir):
Christian Heimesada8c3b2008-03-18 18:26:33 +00001224 try:
1225 if d:
1226 shutil.rmtree(d)
1227 except:
1228 pass
1229
1230 def _check_move_file(self, src, dst, real_dst):
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001231 with open(src, "rb") as f:
1232 contents = f.read()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001233 shutil.move(src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001234 with open(real_dst, "rb") as f:
1235 self.assertEqual(contents, f.read())
Christian Heimesada8c3b2008-03-18 18:26:33 +00001236 self.assertFalse(os.path.exists(src))
1237
1238 def _check_move_dir(self, src, dst, real_dst):
1239 contents = sorted(os.listdir(src))
1240 shutil.move(src, dst)
1241 self.assertEqual(contents, sorted(os.listdir(real_dst)))
1242 self.assertFalse(os.path.exists(src))
1243
1244 def test_move_file(self):
1245 # Move a file to another location on the same filesystem.
1246 self._check_move_file(self.src_file, self.dst_file, self.dst_file)
1247
1248 def test_move_file_to_dir(self):
1249 # Move a file inside an existing dir on the same filesystem.
1250 self._check_move_file(self.src_file, self.dst_dir, self.dst_file)
1251
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001252 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001253 def test_move_file_other_fs(self):
1254 # Move a file to an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001255 self.test_move_file()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001256
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001257 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001258 def test_move_file_to_dir_other_fs(self):
1259 # Move a file to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001260 self.test_move_file_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001261
1262 def test_move_dir(self):
1263 # Move a dir to another location on the same filesystem.
1264 dst_dir = tempfile.mktemp()
1265 try:
1266 self._check_move_dir(self.src_dir, dst_dir, dst_dir)
1267 finally:
1268 try:
1269 shutil.rmtree(dst_dir)
1270 except:
1271 pass
1272
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001273 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001274 def test_move_dir_other_fs(self):
1275 # Move a dir to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001276 self.test_move_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001277
1278 def test_move_dir_to_dir(self):
1279 # Move a dir inside an existing dir on the same filesystem.
1280 self._check_move_dir(self.src_dir, self.dst_dir,
1281 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1282
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001283 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001284 def test_move_dir_to_dir_other_fs(self):
1285 # Move a dir inside an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001286 self.test_move_dir_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001287
1288 def test_existing_file_inside_dest_dir(self):
1289 # A file with the same name inside the destination dir already exists.
1290 with open(self.dst_file, "wb"):
1291 pass
1292 self.assertRaises(shutil.Error, shutil.move, self.src_file, self.dst_dir)
1293
1294 def test_dont_move_dir_in_itself(self):
1295 # Moving a dir inside itself raises an Error.
1296 dst = os.path.join(self.src_dir, "bar")
1297 self.assertRaises(shutil.Error, shutil.move, self.src_dir, dst)
1298
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001299 def test_destinsrc_false_negative(self):
1300 os.mkdir(TESTFN)
1301 try:
1302 for src, dst in [('srcdir', 'srcdir/dest')]:
1303 src = os.path.join(TESTFN, src)
1304 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001305 self.assertTrue(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001306 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001307 'dst (%s) is not in src (%s)' % (dst, src))
1308 finally:
1309 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001310
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001311 def test_destinsrc_false_positive(self):
1312 os.mkdir(TESTFN)
1313 try:
1314 for src, dst in [('srcdir', 'src/dest'), ('srcdir', 'srcdir.new')]:
1315 src = os.path.join(TESTFN, src)
1316 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001317 self.assertFalse(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001318 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001319 'dst (%s) is in src (%s)' % (dst, src))
1320 finally:
1321 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimes9bd667a2008-01-20 15:14:11 +00001322
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +01001323 @support.skip_unless_symlink
1324 @mock_rename
1325 def test_move_file_symlink(self):
1326 dst = os.path.join(self.src_dir, 'bar')
1327 os.symlink(self.src_file, dst)
1328 shutil.move(dst, self.dst_file)
1329 self.assertTrue(os.path.islink(self.dst_file))
1330 self.assertTrue(os.path.samefile(self.src_file, self.dst_file))
1331
1332 @support.skip_unless_symlink
1333 @mock_rename
1334 def test_move_file_symlink_to_dir(self):
1335 filename = "bar"
1336 dst = os.path.join(self.src_dir, filename)
1337 os.symlink(self.src_file, dst)
1338 shutil.move(dst, self.dst_dir)
1339 final_link = os.path.join(self.dst_dir, filename)
1340 self.assertTrue(os.path.islink(final_link))
1341 self.assertTrue(os.path.samefile(self.src_file, final_link))
1342
1343 @support.skip_unless_symlink
1344 @mock_rename
1345 def test_move_dangling_symlink(self):
1346 src = os.path.join(self.src_dir, 'baz')
1347 dst = os.path.join(self.src_dir, 'bar')
1348 os.symlink(src, dst)
1349 dst_link = os.path.join(self.dst_dir, 'quux')
1350 shutil.move(dst, dst_link)
1351 self.assertTrue(os.path.islink(dst_link))
1352 self.assertEqual(os.path.realpath(src), os.path.realpath(dst_link))
1353
1354 @support.skip_unless_symlink
1355 @mock_rename
1356 def test_move_dir_symlink(self):
1357 src = os.path.join(self.src_dir, 'baz')
1358 dst = os.path.join(self.src_dir, 'bar')
1359 os.mkdir(src)
1360 os.symlink(src, dst)
1361 dst_link = os.path.join(self.dst_dir, 'quux')
1362 shutil.move(dst, dst_link)
1363 self.assertTrue(os.path.islink(dst_link))
1364 self.assertTrue(os.path.samefile(src, dst_link))
1365
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001366 def test_move_return_value(self):
1367 rv = shutil.move(self.src_file, self.dst_dir)
1368 self.assertEqual(rv,
1369 os.path.join(self.dst_dir, os.path.basename(self.src_file)))
1370
1371 def test_move_as_rename_return_value(self):
1372 rv = shutil.move(self.src_file, os.path.join(self.dst_dir, 'bar'))
1373 self.assertEqual(rv, os.path.join(self.dst_dir, 'bar'))
1374
Tarek Ziadé5340db32010-04-19 22:30:51 +00001375
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001376class TestCopyFile(unittest.TestCase):
1377
1378 _delete = False
1379
1380 class Faux(object):
1381 _entered = False
1382 _exited_with = None
1383 _raised = False
1384 def __init__(self, raise_in_exit=False, suppress_at_exit=True):
1385 self._raise_in_exit = raise_in_exit
1386 self._suppress_at_exit = suppress_at_exit
1387 def read(self, *args):
1388 return ''
1389 def __enter__(self):
1390 self._entered = True
1391 def __exit__(self, exc_type, exc_val, exc_tb):
1392 self._exited_with = exc_type, exc_val, exc_tb
1393 if self._raise_in_exit:
1394 self._raised = True
1395 raise IOError("Cannot close")
1396 return self._suppress_at_exit
1397
1398 def tearDown(self):
1399 if self._delete:
1400 del shutil.open
1401
1402 def _set_shutil_open(self, func):
1403 shutil.open = func
1404 self._delete = True
1405
1406 def test_w_source_open_fails(self):
1407 def _open(filename, mode='r'):
1408 if filename == 'srcfile':
1409 raise IOError('Cannot open "srcfile"')
1410 assert 0 # shouldn't reach here.
1411
1412 self._set_shutil_open(_open)
1413
1414 self.assertRaises(IOError, shutil.copyfile, 'srcfile', 'destfile')
1415
1416 def test_w_dest_open_fails(self):
1417
1418 srcfile = self.Faux()
1419
1420 def _open(filename, mode='r'):
1421 if filename == 'srcfile':
1422 return srcfile
1423 if filename == 'destfile':
1424 raise IOError('Cannot open "destfile"')
1425 assert 0 # shouldn't reach here.
1426
1427 self._set_shutil_open(_open)
1428
1429 shutil.copyfile('srcfile', 'destfile')
1430 self.assertTrue(srcfile._entered)
1431 self.assertTrue(srcfile._exited_with[0] is IOError)
1432 self.assertEqual(srcfile._exited_with[1].args,
1433 ('Cannot open "destfile"',))
1434
1435 def test_w_dest_close_fails(self):
1436
1437 srcfile = self.Faux()
1438 destfile = self.Faux(True)
1439
1440 def _open(filename, mode='r'):
1441 if filename == 'srcfile':
1442 return srcfile
1443 if filename == 'destfile':
1444 return destfile
1445 assert 0 # shouldn't reach here.
1446
1447 self._set_shutil_open(_open)
1448
1449 shutil.copyfile('srcfile', 'destfile')
1450 self.assertTrue(srcfile._entered)
1451 self.assertTrue(destfile._entered)
1452 self.assertTrue(destfile._raised)
1453 self.assertTrue(srcfile._exited_with[0] is IOError)
1454 self.assertEqual(srcfile._exited_with[1].args,
1455 ('Cannot close',))
1456
1457 def test_w_source_close_fails(self):
1458
1459 srcfile = self.Faux(True)
1460 destfile = self.Faux()
1461
1462 def _open(filename, mode='r'):
1463 if filename == 'srcfile':
1464 return srcfile
1465 if filename == 'destfile':
1466 return destfile
1467 assert 0 # shouldn't reach here.
1468
1469 self._set_shutil_open(_open)
1470
1471 self.assertRaises(IOError,
1472 shutil.copyfile, 'srcfile', 'destfile')
1473 self.assertTrue(srcfile._entered)
1474 self.assertTrue(destfile._entered)
1475 self.assertFalse(destfile._raised)
1476 self.assertTrue(srcfile._exited_with[0] is None)
1477 self.assertTrue(srcfile._raised)
1478
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001479 def test_move_dir_caseinsensitive(self):
1480 # Renames a folder to the same name
1481 # but a different case.
1482
1483 self.src_dir = tempfile.mkdtemp()
1484 dst_dir = os.path.join(
1485 os.path.dirname(self.src_dir),
1486 os.path.basename(self.src_dir).upper())
1487 self.assertNotEqual(self.src_dir, dst_dir)
1488
1489 try:
1490 shutil.move(self.src_dir, dst_dir)
1491 self.assertTrue(os.path.isdir(dst_dir))
1492 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +02001493 os.rmdir(dst_dir)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001494
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001495class TermsizeTests(unittest.TestCase):
1496 def test_does_not_crash(self):
1497 """Check if get_terminal_size() returns a meaningful value.
1498
1499 There's no easy portable way to actually check the size of the
1500 terminal, so let's check if it returns something sensible instead.
1501 """
1502 size = shutil.get_terminal_size()
Antoine Pitroucfade362012-02-08 23:48:59 +01001503 self.assertGreaterEqual(size.columns, 0)
1504 self.assertGreaterEqual(size.lines, 0)
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001505
1506 def test_os_environ_first(self):
1507 "Check if environment variables have precedence"
1508
1509 with support.EnvironmentVarGuard() as env:
1510 env['COLUMNS'] = '777'
1511 size = shutil.get_terminal_size()
1512 self.assertEqual(size.columns, 777)
1513
1514 with support.EnvironmentVarGuard() as env:
1515 env['LINES'] = '888'
1516 size = shutil.get_terminal_size()
1517 self.assertEqual(size.lines, 888)
1518
1519 @unittest.skipUnless(os.isatty(sys.__stdout__.fileno()), "not on tty")
1520 def test_stty_match(self):
1521 """Check if stty returns the same results ignoring env
1522
1523 This test will fail if stdin and stdout are connected to
1524 different terminals with different sizes. Nevertheless, such
1525 situations should be pretty rare.
1526 """
1527 try:
1528 size = subprocess.check_output(['stty', 'size']).decode().split()
1529 except (FileNotFoundError, subprocess.CalledProcessError):
1530 self.skipTest("stty invocation failed")
1531 expected = (int(size[1]), int(size[0])) # reversed order
1532
1533 with support.EnvironmentVarGuard() as env:
1534 del env['LINES']
1535 del env['COLUMNS']
1536 actual = shutil.get_terminal_size()
1537
1538 self.assertEqual(expected, actual)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001539
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001540
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001541def test_main():
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001542 support.run_unittest(TestShutil, TestMove, TestCopyFile,
Brian Curtinc57a3452012-06-22 16:00:30 -05001543 TermsizeTests, TestWhich)
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001544
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001545if __name__ == '__main__':
Walter Dörwald21d3a322003-05-01 17:45:56 +00001546 test_main()