blob: a830935a009a54499cd9aceb8c37a851af6c7f49 [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)
Antoine Pitrou2f8a75c2012-06-23 21:28:15 +0200123 self.addCleanup(shutil.rmtree, TESTFN)
124
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200125 self.child_file_path = os.path.join(TESTFN, 'a')
126 self.child_dir_path = os.path.join(TESTFN, 'b')
127 support.create_empty_file(self.child_file_path)
128 os.mkdir(self.child_dir_path)
Tim Peters4590c002004-11-01 02:40:52 +0000129 old_dir_mode = os.stat(TESTFN).st_mode
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200130 old_child_file_mode = os.stat(self.child_file_path).st_mode
131 old_child_dir_mode = os.stat(self.child_dir_path).st_mode
Tim Peters4590c002004-11-01 02:40:52 +0000132 # Make unwritable.
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200133 new_mode = stat.S_IREAD|stat.S_IEXEC
134 os.chmod(self.child_file_path, new_mode)
135 os.chmod(self.child_dir_path, new_mode)
136 os.chmod(TESTFN, new_mode)
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000137
Antoine Pitrou2f8a75c2012-06-23 21:28:15 +0200138 self.addCleanup(os.chmod, TESTFN, old_dir_mode)
139 self.addCleanup(os.chmod, self.child_file_path, old_child_file_mode)
140 self.addCleanup(os.chmod, self.child_dir_path, old_child_dir_mode)
141
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000142 shutil.rmtree(TESTFN, onerror=self.check_args_to_onerror)
Johannes Gijsbers8e6f2de2004-11-23 09:27:27 +0000143 # Test whether onerror has actually been called.
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200144 self.assertEqual(self.errorState, 3,
145 "Expected call to onerror function did not "
146 "happen.")
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000147
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000148 def check_args_to_onerror(self, func, arg, exc):
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000149 # test_rmtree_errors deliberately runs rmtree
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200150 # on a directory that is chmod 500, which will fail.
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000151 # This function is run when shutil.rmtree fails.
152 # 99.9% of the time it initially fails to remove
153 # a file in the directory, so the first time through
154 # func is os.remove.
155 # However, some Linux machines running ZFS on
156 # FUSE experienced a failure earlier in the process
157 # at os.listdir. The first failure may legally
158 # be either.
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200159 if 0 <= self.errorState < 2:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200160 if func is os.unlink:
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200161 self.assertIn(arg, [self.child_file_path, self.child_dir_path])
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000162 else:
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200163 if self.errorState == 1:
164 self.assertEqual(func, os.rmdir)
165 else:
166 self.assertIs(func, os.listdir, "func must be os.listdir")
167 self.assertIn(arg, [TESTFN, self.child_dir_path])
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000168 self.assertTrue(issubclass(exc[0], OSError))
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200169 self.errorState += 1
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000170 else:
171 self.assertEqual(func, os.rmdir)
172 self.assertEqual(arg, TESTFN)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000173 self.assertTrue(issubclass(exc[0], OSError))
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200174 self.errorState = 3
175
176 def test_rmtree_does_not_choke_on_failing_lstat(self):
177 try:
178 orig_lstat = os.lstat
179 def raiser(fn):
180 if fn != TESTFN:
181 raise OSError()
182 else:
183 return orig_lstat(fn)
184 os.lstat = raiser
185
186 os.mkdir(TESTFN)
187 write_file((TESTFN, 'foo'), 'foo')
188 shutil.rmtree(TESTFN)
189 finally:
190 os.lstat = orig_lstat
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000191
Antoine Pitrou78091e62011-12-29 18:54:15 +0100192 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
193 @support.skip_unless_symlink
194 def test_copymode_follow_symlinks(self):
195 tmp_dir = self.mkdtemp()
196 src = os.path.join(tmp_dir, 'foo')
197 dst = os.path.join(tmp_dir, 'bar')
198 src_link = os.path.join(tmp_dir, 'baz')
199 dst_link = os.path.join(tmp_dir, 'quux')
200 write_file(src, 'foo')
201 write_file(dst, 'foo')
202 os.symlink(src, src_link)
203 os.symlink(dst, dst_link)
204 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
205 # file to file
206 os.chmod(dst, stat.S_IRWXO)
207 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
208 shutil.copymode(src, dst)
209 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
210 # follow src link
211 os.chmod(dst, stat.S_IRWXO)
212 shutil.copymode(src_link, dst)
213 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
214 # follow dst link
215 os.chmod(dst, stat.S_IRWXO)
216 shutil.copymode(src, dst_link)
217 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
218 # follow both links
219 os.chmod(dst, stat.S_IRWXO)
220 shutil.copymode(src_link, dst)
221 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
222
223 @unittest.skipUnless(hasattr(os, 'lchmod'), 'requires os.lchmod')
224 @support.skip_unless_symlink
225 def test_copymode_symlink_to_symlink(self):
226 tmp_dir = self.mkdtemp()
227 src = os.path.join(tmp_dir, 'foo')
228 dst = os.path.join(tmp_dir, 'bar')
229 src_link = os.path.join(tmp_dir, 'baz')
230 dst_link = os.path.join(tmp_dir, 'quux')
231 write_file(src, 'foo')
232 write_file(dst, 'foo')
233 os.symlink(src, src_link)
234 os.symlink(dst, dst_link)
235 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
236 os.chmod(dst, stat.S_IRWXU)
237 os.lchmod(src_link, stat.S_IRWXO|stat.S_IRWXG)
238 # link to link
239 os.lchmod(dst_link, stat.S_IRWXO)
240 shutil.copymode(src_link, dst_link, symlinks=True)
241 self.assertEqual(os.lstat(src_link).st_mode,
242 os.lstat(dst_link).st_mode)
243 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
244 # src link - use chmod
245 os.lchmod(dst_link, stat.S_IRWXO)
246 shutil.copymode(src_link, dst, symlinks=True)
247 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
248 # dst link - use chmod
249 os.lchmod(dst_link, stat.S_IRWXO)
250 shutil.copymode(src, dst_link, symlinks=True)
251 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
252
253 @unittest.skipIf(hasattr(os, 'lchmod'), 'requires os.lchmod to be missing')
254 @support.skip_unless_symlink
255 def test_copymode_symlink_to_symlink_wo_lchmod(self):
256 tmp_dir = self.mkdtemp()
257 src = os.path.join(tmp_dir, 'foo')
258 dst = os.path.join(tmp_dir, 'bar')
259 src_link = os.path.join(tmp_dir, 'baz')
260 dst_link = os.path.join(tmp_dir, 'quux')
261 write_file(src, 'foo')
262 write_file(dst, 'foo')
263 os.symlink(src, src_link)
264 os.symlink(dst, dst_link)
265 shutil.copymode(src_link, dst_link, symlinks=True) # silent fail
266
267 @support.skip_unless_symlink
268 def test_copystat_symlinks(self):
269 tmp_dir = self.mkdtemp()
270 src = os.path.join(tmp_dir, 'foo')
271 dst = os.path.join(tmp_dir, 'bar')
272 src_link = os.path.join(tmp_dir, 'baz')
273 dst_link = os.path.join(tmp_dir, 'qux')
274 write_file(src, 'foo')
275 src_stat = os.stat(src)
276 os.utime(src, (src_stat.st_atime,
277 src_stat.st_mtime - 42.0)) # ensure different mtimes
278 write_file(dst, 'bar')
279 self.assertNotEqual(os.stat(src).st_mtime, os.stat(dst).st_mtime)
280 os.symlink(src, src_link)
281 os.symlink(dst, dst_link)
282 if hasattr(os, 'lchmod'):
283 os.lchmod(src_link, stat.S_IRWXO)
284 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
285 os.lchflags(src_link, stat.UF_NODUMP)
286 src_link_stat = os.lstat(src_link)
287 # follow
288 if hasattr(os, 'lchmod'):
289 shutil.copystat(src_link, dst_link, symlinks=False)
290 self.assertNotEqual(src_link_stat.st_mode, os.stat(dst).st_mode)
291 # don't follow
292 shutil.copystat(src_link, dst_link, symlinks=True)
293 dst_link_stat = os.lstat(dst_link)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700294 if os.utime in os.supports_follow_symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100295 for attr in 'st_atime', 'st_mtime':
296 # The modification times may be truncated in the new file.
297 self.assertLessEqual(getattr(src_link_stat, attr),
298 getattr(dst_link_stat, attr) + 1)
299 if hasattr(os, 'lchmod'):
300 self.assertEqual(src_link_stat.st_mode, dst_link_stat.st_mode)
301 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
302 self.assertEqual(src_link_stat.st_flags, dst_link_stat.st_flags)
303 # tell to follow but dst is not a link
304 shutil.copystat(src_link, dst, symlinks=True)
305 self.assertTrue(abs(os.stat(src).st_mtime - os.stat(dst).st_mtime) <
306 00000.1)
307
Ned Deilybaf75712012-05-10 17:05:19 -0700308 @unittest.skipUnless(hasattr(os, 'chflags') and
309 hasattr(errno, 'EOPNOTSUPP') and
310 hasattr(errno, 'ENOTSUP'),
311 "requires os.chflags, EOPNOTSUPP & ENOTSUP")
312 def test_copystat_handles_harmless_chflags_errors(self):
313 tmpdir = self.mkdtemp()
314 file1 = os.path.join(tmpdir, 'file1')
315 file2 = os.path.join(tmpdir, 'file2')
316 write_file(file1, 'xxx')
317 write_file(file2, 'xxx')
318
319 def make_chflags_raiser(err):
320 ex = OSError()
321
Larry Hastings90867a52012-06-22 17:01:41 -0700322 def _chflags_raiser(path, flags, *, follow_symlinks=True):
Ned Deilybaf75712012-05-10 17:05:19 -0700323 ex.errno = err
324 raise ex
325 return _chflags_raiser
326 old_chflags = os.chflags
327 try:
328 for err in errno.EOPNOTSUPP, errno.ENOTSUP:
329 os.chflags = make_chflags_raiser(err)
330 shutil.copystat(file1, file2)
331 # assert others errors break it
332 os.chflags = make_chflags_raiser(errno.EOPNOTSUPP + errno.ENOTSUP)
333 self.assertRaises(OSError, shutil.copystat, file1, file2)
334 finally:
335 os.chflags = old_chflags
336
Antoine Pitrou424246f2012-05-12 19:02:01 +0200337 @support.skip_unless_xattr
338 def test_copyxattr(self):
339 tmp_dir = self.mkdtemp()
340 src = os.path.join(tmp_dir, 'foo')
341 write_file(src, 'foo')
342 dst = os.path.join(tmp_dir, 'bar')
343 write_file(dst, 'bar')
344
345 # no xattr == no problem
346 shutil._copyxattr(src, dst)
347 # common case
348 os.setxattr(src, 'user.foo', b'42')
349 os.setxattr(src, 'user.bar', b'43')
350 shutil._copyxattr(src, dst)
351 self.assertEqual(os.listxattr(src), os.listxattr(dst))
352 self.assertEqual(
353 os.getxattr(src, 'user.foo'),
354 os.getxattr(dst, 'user.foo'))
355 # check errors don't affect other attrs
356 os.remove(dst)
357 write_file(dst, 'bar')
358 os_error = OSError(errno.EPERM, 'EPERM')
359
Larry Hastings9cf065c2012-06-22 16:30:09 -0700360 def _raise_on_user_foo(fname, attr, val, **kwargs):
Antoine Pitrou424246f2012-05-12 19:02:01 +0200361 if attr == 'user.foo':
362 raise os_error
363 else:
Larry Hastings9cf065c2012-06-22 16:30:09 -0700364 orig_setxattr(fname, attr, val, **kwargs)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200365 try:
366 orig_setxattr = os.setxattr
367 os.setxattr = _raise_on_user_foo
368 shutil._copyxattr(src, dst)
Antoine Pitrou61597d32012-05-12 23:37:35 +0200369 self.assertIn('user.bar', os.listxattr(dst))
Antoine Pitrou424246f2012-05-12 19:02:01 +0200370 finally:
371 os.setxattr = orig_setxattr
372
373 @support.skip_unless_symlink
374 @support.skip_unless_xattr
375 @unittest.skipUnless(hasattr(os, 'geteuid') and os.geteuid() == 0,
376 'root privileges required')
377 def test_copyxattr_symlinks(self):
378 # On Linux, it's only possible to access non-user xattr for symlinks;
379 # which in turn require root privileges. This test should be expanded
380 # as soon as other platforms gain support for extended attributes.
381 tmp_dir = self.mkdtemp()
382 src = os.path.join(tmp_dir, 'foo')
383 src_link = os.path.join(tmp_dir, 'baz')
384 write_file(src, 'foo')
385 os.symlink(src, src_link)
386 os.setxattr(src, 'trusted.foo', b'42')
Larry Hastings9cf065c2012-06-22 16:30:09 -0700387 os.setxattr(src_link, 'trusted.foo', b'43', follow_symlinks=False)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200388 dst = os.path.join(tmp_dir, 'bar')
389 dst_link = os.path.join(tmp_dir, 'qux')
390 write_file(dst, 'bar')
391 os.symlink(dst, dst_link)
392 shutil._copyxattr(src_link, dst_link, symlinks=True)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700393 self.assertEqual(os.getxattr(dst_link, 'trusted.foo', follow_symlinks=False), b'43')
Antoine Pitrou424246f2012-05-12 19:02:01 +0200394 self.assertRaises(OSError, os.getxattr, dst, 'trusted.foo')
395 shutil._copyxattr(src_link, dst, symlinks=True)
396 self.assertEqual(os.getxattr(dst, 'trusted.foo'), b'43')
397
Antoine Pitrou78091e62011-12-29 18:54:15 +0100398 @support.skip_unless_symlink
399 def test_copy_symlinks(self):
400 tmp_dir = self.mkdtemp()
401 src = os.path.join(tmp_dir, 'foo')
402 dst = os.path.join(tmp_dir, 'bar')
403 src_link = os.path.join(tmp_dir, 'baz')
404 write_file(src, 'foo')
405 os.symlink(src, src_link)
406 if hasattr(os, 'lchmod'):
407 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
408 # don't follow
409 shutil.copy(src_link, dst, symlinks=False)
410 self.assertFalse(os.path.islink(dst))
411 self.assertEqual(read_file(src), read_file(dst))
412 os.remove(dst)
413 # follow
414 shutil.copy(src_link, dst, symlinks=True)
415 self.assertTrue(os.path.islink(dst))
416 self.assertEqual(os.readlink(dst), os.readlink(src_link))
417 if hasattr(os, 'lchmod'):
418 self.assertEqual(os.lstat(src_link).st_mode,
419 os.lstat(dst).st_mode)
420
421 @support.skip_unless_symlink
422 def test_copy2_symlinks(self):
423 tmp_dir = self.mkdtemp()
424 src = os.path.join(tmp_dir, 'foo')
425 dst = os.path.join(tmp_dir, 'bar')
426 src_link = os.path.join(tmp_dir, 'baz')
427 write_file(src, 'foo')
428 os.symlink(src, src_link)
429 if hasattr(os, 'lchmod'):
430 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
431 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
432 os.lchflags(src_link, stat.UF_NODUMP)
433 src_stat = os.stat(src)
434 src_link_stat = os.lstat(src_link)
435 # follow
436 shutil.copy2(src_link, dst, symlinks=False)
437 self.assertFalse(os.path.islink(dst))
438 self.assertEqual(read_file(src), read_file(dst))
439 os.remove(dst)
440 # don't follow
441 shutil.copy2(src_link, dst, symlinks=True)
442 self.assertTrue(os.path.islink(dst))
443 self.assertEqual(os.readlink(dst), os.readlink(src_link))
444 dst_stat = os.lstat(dst)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700445 if os.utime in os.supports_follow_symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100446 for attr in 'st_atime', 'st_mtime':
447 # The modification times may be truncated in the new file.
448 self.assertLessEqual(getattr(src_link_stat, attr),
449 getattr(dst_stat, attr) + 1)
450 if hasattr(os, 'lchmod'):
451 self.assertEqual(src_link_stat.st_mode, dst_stat.st_mode)
452 self.assertNotEqual(src_stat.st_mode, dst_stat.st_mode)
453 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
454 self.assertEqual(src_link_stat.st_flags, dst_stat.st_flags)
455
Antoine Pitrou424246f2012-05-12 19:02:01 +0200456 @support.skip_unless_xattr
457 def test_copy2_xattr(self):
458 tmp_dir = self.mkdtemp()
459 src = os.path.join(tmp_dir, 'foo')
460 dst = os.path.join(tmp_dir, 'bar')
461 write_file(src, 'foo')
462 os.setxattr(src, 'user.foo', b'42')
463 shutil.copy2(src, dst)
464 self.assertEqual(
465 os.getxattr(src, 'user.foo'),
466 os.getxattr(dst, 'user.foo'))
467 os.remove(dst)
468
Antoine Pitrou78091e62011-12-29 18:54:15 +0100469 @support.skip_unless_symlink
470 def test_copyfile_symlinks(self):
471 tmp_dir = self.mkdtemp()
472 src = os.path.join(tmp_dir, 'src')
473 dst = os.path.join(tmp_dir, 'dst')
474 dst_link = os.path.join(tmp_dir, 'dst_link')
475 link = os.path.join(tmp_dir, 'link')
476 write_file(src, 'foo')
477 os.symlink(src, link)
478 # don't follow
479 shutil.copyfile(link, dst_link, symlinks=True)
480 self.assertTrue(os.path.islink(dst_link))
481 self.assertEqual(os.readlink(link), os.readlink(dst_link))
482 # follow
483 shutil.copyfile(link, dst)
484 self.assertFalse(os.path.islink(dst))
485
Hynek Schlawack2100b422012-06-23 20:28:32 +0200486 def test_rmtree_uses_safe_fd_version_if_available(self):
487 if os.unlink in os.supports_dir_fd and os.open in os.supports_dir_fd:
488 self.assertTrue(shutil._use_fd_functions)
489 self.assertTrue(shutil.rmtree_is_safe)
490 tmp_dir = self.mkdtemp()
491 d = os.path.join(tmp_dir, 'a')
492 os.mkdir(d)
493 try:
494 real_rmtree = shutil._rmtree_safe_fd
495 class Called(Exception): pass
496 def _raiser(*args, **kwargs):
497 raise Called
498 shutil._rmtree_safe_fd = _raiser
499 self.assertRaises(Called, shutil.rmtree, d)
500 finally:
501 shutil._rmtree_safe_fd = real_rmtree
502 else:
503 self.assertFalse(shutil._use_fd_functions)
504 self.assertFalse(shutil.rmtree_is_safe)
505
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000506 def test_rmtree_dont_delete_file(self):
507 # When called on a file instead of a directory, don't delete it.
508 handle, path = tempfile.mkstemp()
Victor Stinnerbf816222011-06-30 23:25:47 +0200509 os.close(handle)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200510 self.assertRaises(NotADirectoryError, shutil.rmtree, path)
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000511 os.remove(path)
512
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000513 def test_copytree_simple(self):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000514 src_dir = tempfile.mkdtemp()
515 dst_dir = os.path.join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200516 self.addCleanup(shutil.rmtree, src_dir)
517 self.addCleanup(shutil.rmtree, os.path.dirname(dst_dir))
518 write_file((src_dir, 'test.txt'), '123')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000519 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200520 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000521
Éric Araujoa7e33a12011-08-12 19:51:35 +0200522 shutil.copytree(src_dir, dst_dir)
523 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test.txt')))
524 self.assertTrue(os.path.isdir(os.path.join(dst_dir, 'test_dir')))
525 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test_dir',
526 'test.txt')))
527 actual = read_file((dst_dir, 'test.txt'))
528 self.assertEqual(actual, '123')
529 actual = read_file((dst_dir, 'test_dir', 'test.txt'))
530 self.assertEqual(actual, '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000531
Antoine Pitrou78091e62011-12-29 18:54:15 +0100532 @support.skip_unless_symlink
533 def test_copytree_symlinks(self):
534 tmp_dir = self.mkdtemp()
535 src_dir = os.path.join(tmp_dir, 'src')
536 dst_dir = os.path.join(tmp_dir, 'dst')
537 sub_dir = os.path.join(src_dir, 'sub')
538 os.mkdir(src_dir)
539 os.mkdir(sub_dir)
540 write_file((src_dir, 'file.txt'), 'foo')
541 src_link = os.path.join(sub_dir, 'link')
542 dst_link = os.path.join(dst_dir, 'sub/link')
543 os.symlink(os.path.join(src_dir, 'file.txt'),
544 src_link)
545 if hasattr(os, 'lchmod'):
546 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
547 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
548 os.lchflags(src_link, stat.UF_NODUMP)
549 src_stat = os.lstat(src_link)
550 shutil.copytree(src_dir, dst_dir, symlinks=True)
551 self.assertTrue(os.path.islink(os.path.join(dst_dir, 'sub', 'link')))
552 self.assertEqual(os.readlink(os.path.join(dst_dir, 'sub', 'link')),
553 os.path.join(src_dir, 'file.txt'))
554 dst_stat = os.lstat(dst_link)
555 if hasattr(os, 'lchmod'):
556 self.assertEqual(dst_stat.st_mode, src_stat.st_mode)
557 if hasattr(os, 'lchflags'):
558 self.assertEqual(dst_stat.st_flags, src_stat.st_flags)
559
Georg Brandl2ee470f2008-07-16 12:55:28 +0000560 def test_copytree_with_exclude(self):
Georg Brandl2ee470f2008-07-16 12:55:28 +0000561 # creating data
562 join = os.path.join
563 exists = os.path.exists
564 src_dir = tempfile.mkdtemp()
Georg Brandl2ee470f2008-07-16 12:55:28 +0000565 try:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000566 dst_dir = join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200567 write_file((src_dir, 'test.txt'), '123')
568 write_file((src_dir, 'test.tmp'), '123')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000569 os.mkdir(join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200570 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000571 os.mkdir(join(src_dir, 'test_dir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200572 write_file((src_dir, 'test_dir2', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000573 os.mkdir(join(src_dir, 'test_dir2', 'subdir'))
574 os.mkdir(join(src_dir, 'test_dir2', 'subdir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200575 write_file((src_dir, 'test_dir2', 'subdir', 'test.txt'), '456')
576 write_file((src_dir, 'test_dir2', 'subdir2', 'test.py'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000577
578 # testing glob-like patterns
579 try:
580 patterns = shutil.ignore_patterns('*.tmp', 'test_dir2')
581 shutil.copytree(src_dir, dst_dir, ignore=patterns)
582 # checking the result: some elements should not be copied
583 self.assertTrue(exists(join(dst_dir, 'test.txt')))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200584 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
585 self.assertFalse(exists(join(dst_dir, 'test_dir2')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000586 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200587 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000588 try:
589 patterns = shutil.ignore_patterns('*.tmp', 'subdir*')
590 shutil.copytree(src_dir, dst_dir, ignore=patterns)
591 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200592 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
593 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2')))
594 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000595 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200596 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000597
598 # testing callable-style
599 try:
600 def _filter(src, names):
601 res = []
602 for name in names:
603 path = os.path.join(src, name)
604
605 if (os.path.isdir(path) and
606 path.split()[-1] == 'subdir'):
607 res.append(name)
608 elif os.path.splitext(path)[-1] in ('.py'):
609 res.append(name)
610 return res
611
612 shutil.copytree(src_dir, dst_dir, ignore=_filter)
613
614 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200615 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2',
616 'test.py')))
617 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000618
619 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200620 shutil.rmtree(dst_dir)
Georg Brandl2ee470f2008-07-16 12:55:28 +0000621 finally:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000622 shutil.rmtree(src_dir)
623 shutil.rmtree(os.path.dirname(dst_dir))
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000624
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000625 @unittest.skipUnless(hasattr(os, 'link'), 'requires os.link')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000626 def test_dont_copy_file_onto_link_to_itself(self):
Georg Brandl724d0892010-12-05 07:51:39 +0000627 # Temporarily disable test on Windows.
628 if os.name == 'nt':
629 return
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000630 # bug 851123.
631 os.mkdir(TESTFN)
632 src = os.path.join(TESTFN, 'cheese')
633 dst = os.path.join(TESTFN, 'shop')
634 try:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000635 with open(src, 'w') as f:
636 f.write('cheddar')
637 os.link(src, dst)
638 self.assertRaises(shutil.Error, shutil.copyfile, src, dst)
639 with open(src, 'r') as f:
640 self.assertEqual(f.read(), 'cheddar')
641 os.remove(dst)
642 finally:
643 shutil.rmtree(TESTFN, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000644
Brian Curtin3b4499c2010-12-28 14:31:47 +0000645 @support.skip_unless_symlink
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000646 def test_dont_copy_file_onto_symlink_to_itself(self):
647 # bug 851123.
648 os.mkdir(TESTFN)
649 src = os.path.join(TESTFN, 'cheese')
650 dst = os.path.join(TESTFN, 'shop')
651 try:
652 with open(src, 'w') as f:
653 f.write('cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000654 # Using `src` here would mean we end up with a symlink pointing
655 # to TESTFN/TESTFN/cheese, while it should point at
656 # TESTFN/cheese.
657 os.symlink('cheese', dst)
658 self.assertRaises(shutil.Error, shutil.copyfile, src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +0000659 with open(src, 'r') as f:
660 self.assertEqual(f.read(), 'cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000661 os.remove(dst)
662 finally:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000663 shutil.rmtree(TESTFN, ignore_errors=True)
Johannes Gijsbers68128712004-08-14 13:57:08 +0000664
Brian Curtin3b4499c2010-12-28 14:31:47 +0000665 @support.skip_unless_symlink
Brian Curtind40e6f72010-07-08 21:39:08 +0000666 def test_rmtree_on_symlink(self):
667 # bug 1669.
668 os.mkdir(TESTFN)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000669 try:
Brian Curtind40e6f72010-07-08 21:39:08 +0000670 src = os.path.join(TESTFN, 'cheese')
671 dst = os.path.join(TESTFN, 'shop')
672 os.mkdir(src)
673 os.symlink(src, dst)
674 self.assertRaises(OSError, shutil.rmtree, dst)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200675 shutil.rmtree(dst, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000676 finally:
Brian Curtind40e6f72010-07-08 21:39:08 +0000677 shutil.rmtree(TESTFN, ignore_errors=True)
678
679 if hasattr(os, "mkfifo"):
680 # Issue #3002: copyfile and copytree block indefinitely on named pipes
681 def test_copyfile_named_pipe(self):
682 os.mkfifo(TESTFN)
683 try:
684 self.assertRaises(shutil.SpecialFileError,
685 shutil.copyfile, TESTFN, TESTFN2)
686 self.assertRaises(shutil.SpecialFileError,
687 shutil.copyfile, __file__, TESTFN)
688 finally:
689 os.remove(TESTFN)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000690
Brian Curtin3b4499c2010-12-28 14:31:47 +0000691 @support.skip_unless_symlink
Brian Curtin52173d42010-12-02 18:29:18 +0000692 def test_copytree_named_pipe(self):
693 os.mkdir(TESTFN)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000694 try:
Brian Curtin52173d42010-12-02 18:29:18 +0000695 subdir = os.path.join(TESTFN, "subdir")
696 os.mkdir(subdir)
697 pipe = os.path.join(subdir, "mypipe")
698 os.mkfifo(pipe)
699 try:
700 shutil.copytree(TESTFN, TESTFN2)
701 except shutil.Error as e:
702 errors = e.args[0]
703 self.assertEqual(len(errors), 1)
704 src, dst, error_msg = errors[0]
705 self.assertEqual("`%s` is a named pipe" % pipe, error_msg)
706 else:
707 self.fail("shutil.Error should have been raised")
708 finally:
709 shutil.rmtree(TESTFN, ignore_errors=True)
710 shutil.rmtree(TESTFN2, ignore_errors=True)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000711
Tarek Ziadé5340db32010-04-19 22:30:51 +0000712 def test_copytree_special_func(self):
713
714 src_dir = self.mkdtemp()
715 dst_dir = os.path.join(self.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200716 write_file((src_dir, 'test.txt'), '123')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000717 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é5340db32010-04-19 22:30:51 +0000719
720 copied = []
721 def _copy(src, dst):
722 copied.append((src, dst))
723
724 shutil.copytree(src_dir, dst_dir, copy_function=_copy)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000725 self.assertEqual(len(copied), 2)
Tarek Ziadé5340db32010-04-19 22:30:51 +0000726
Brian Curtin3b4499c2010-12-28 14:31:47 +0000727 @support.skip_unless_symlink
Tarek Ziadéfb437512010-04-20 08:57:33 +0000728 def test_copytree_dangling_symlinks(self):
729
730 # a dangling symlink raises an error at the end
731 src_dir = self.mkdtemp()
732 dst_dir = os.path.join(self.mkdtemp(), 'destination')
733 os.symlink('IDONTEXIST', os.path.join(src_dir, 'test.txt'))
734 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200735 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadéfb437512010-04-20 08:57:33 +0000736 self.assertRaises(Error, shutil.copytree, src_dir, dst_dir)
737
738 # a dangling symlink is ignored with the proper flag
739 dst_dir = os.path.join(self.mkdtemp(), 'destination2')
740 shutil.copytree(src_dir, dst_dir, ignore_dangling_symlinks=True)
741 self.assertNotIn('test.txt', os.listdir(dst_dir))
742
743 # a dangling symlink is copied if symlinks=True
744 dst_dir = os.path.join(self.mkdtemp(), 'destination3')
745 shutil.copytree(src_dir, dst_dir, symlinks=True)
746 self.assertIn('test.txt', os.listdir(dst_dir))
747
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400748 def _copy_file(self, method):
749 fname = 'test.txt'
750 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200751 write_file((tmpdir, fname), 'xxx')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400752 file1 = os.path.join(tmpdir, fname)
753 tmpdir2 = self.mkdtemp()
754 method(file1, tmpdir2)
755 file2 = os.path.join(tmpdir2, fname)
756 return (file1, file2)
757
758 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
759 def test_copy(self):
760 # Ensure that the copied file exists and has the same mode bits.
761 file1, file2 = self._copy_file(shutil.copy)
762 self.assertTrue(os.path.exists(file2))
763 self.assertEqual(os.stat(file1).st_mode, os.stat(file2).st_mode)
764
765 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
Senthil Kumaran0c2dba52011-07-03 18:21:38 -0700766 @unittest.skipUnless(hasattr(os, 'utime'), 'requires os.utime')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400767 def test_copy2(self):
768 # Ensure that the copied file exists and has the same mode and
769 # modification time bits.
770 file1, file2 = self._copy_file(shutil.copy2)
771 self.assertTrue(os.path.exists(file2))
772 file1_stat = os.stat(file1)
773 file2_stat = os.stat(file2)
774 self.assertEqual(file1_stat.st_mode, file2_stat.st_mode)
775 for attr in 'st_atime', 'st_mtime':
776 # The modification times may be truncated in the new file.
777 self.assertLessEqual(getattr(file1_stat, attr),
778 getattr(file2_stat, attr) + 1)
779 if hasattr(os, 'chflags') and hasattr(file1_stat, 'st_flags'):
780 self.assertEqual(getattr(file1_stat, 'st_flags'),
781 getattr(file2_stat, 'st_flags'))
782
Ezio Melotti975077a2011-05-19 22:03:22 +0300783 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000784 def test_make_tarball(self):
785 # creating something to tar
786 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200787 write_file((tmpdir, 'file1'), 'xxx')
788 write_file((tmpdir, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000789 os.mkdir(os.path.join(tmpdir, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200790 write_file((tmpdir, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000791
792 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400793 # force shutil to create the directory
794 os.rmdir(tmpdir2)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000795 unittest.skipUnless(splitdrive(tmpdir)[0] == splitdrive(tmpdir2)[0],
796 "source and target should be on same drive")
797
798 base_name = os.path.join(tmpdir2, 'archive')
799
800 # working with relative paths to avoid tar warnings
801 old_dir = os.getcwd()
802 os.chdir(tmpdir)
803 try:
804 _make_tarball(splitdrive(base_name)[1], '.')
805 finally:
806 os.chdir(old_dir)
807
808 # check if the compressed tarball was created
809 tarball = base_name + '.tar.gz'
810 self.assertTrue(os.path.exists(tarball))
811
812 # trying an uncompressed one
813 base_name = os.path.join(tmpdir2, 'archive')
814 old_dir = os.getcwd()
815 os.chdir(tmpdir)
816 try:
817 _make_tarball(splitdrive(base_name)[1], '.', compress=None)
818 finally:
819 os.chdir(old_dir)
820 tarball = base_name + '.tar'
821 self.assertTrue(os.path.exists(tarball))
822
823 def _tarinfo(self, path):
824 tar = tarfile.open(path)
825 try:
826 names = tar.getnames()
827 names.sort()
828 return tuple(names)
829 finally:
830 tar.close()
831
832 def _create_files(self):
833 # creating something to tar
834 tmpdir = self.mkdtemp()
835 dist = os.path.join(tmpdir, 'dist')
836 os.mkdir(dist)
Éric Araujoa7e33a12011-08-12 19:51:35 +0200837 write_file((dist, 'file1'), 'xxx')
838 write_file((dist, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000839 os.mkdir(os.path.join(dist, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200840 write_file((dist, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000841 os.mkdir(os.path.join(dist, 'sub2'))
842 tmpdir2 = self.mkdtemp()
843 base_name = os.path.join(tmpdir2, 'archive')
844 return tmpdir, tmpdir2, base_name
845
Ezio Melotti975077a2011-05-19 22:03:22 +0300846 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000847 @unittest.skipUnless(find_executable('tar') and find_executable('gzip'),
848 'Need the tar command to run')
849 def test_tarfile_vs_tar(self):
850 tmpdir, tmpdir2, base_name = self._create_files()
851 old_dir = os.getcwd()
852 os.chdir(tmpdir)
853 try:
854 _make_tarball(base_name, 'dist')
855 finally:
856 os.chdir(old_dir)
857
858 # check if the compressed tarball was created
859 tarball = base_name + '.tar.gz'
860 self.assertTrue(os.path.exists(tarball))
861
862 # now create another tarball using `tar`
863 tarball2 = os.path.join(tmpdir, 'archive2.tar.gz')
864 tar_cmd = ['tar', '-cf', 'archive2.tar', 'dist']
865 gzip_cmd = ['gzip', '-f9', 'archive2.tar']
866 old_dir = os.getcwd()
867 os.chdir(tmpdir)
868 try:
869 with captured_stdout() as s:
870 spawn(tar_cmd)
871 spawn(gzip_cmd)
872 finally:
873 os.chdir(old_dir)
874
875 self.assertTrue(os.path.exists(tarball2))
876 # let's compare both tarballs
Ezio Melottib3aedd42010-11-20 19:04:17 +0000877 self.assertEqual(self._tarinfo(tarball), self._tarinfo(tarball2))
Tarek Ziadé396fad72010-02-23 05:30:31 +0000878
879 # trying an uncompressed one
880 base_name = os.path.join(tmpdir2, 'archive')
881 old_dir = os.getcwd()
882 os.chdir(tmpdir)
883 try:
884 _make_tarball(base_name, 'dist', compress=None)
885 finally:
886 os.chdir(old_dir)
887 tarball = base_name + '.tar'
888 self.assertTrue(os.path.exists(tarball))
889
890 # now for a dry_run
891 base_name = os.path.join(tmpdir2, 'archive')
892 old_dir = os.getcwd()
893 os.chdir(tmpdir)
894 try:
895 _make_tarball(base_name, 'dist', compress=None, dry_run=True)
896 finally:
897 os.chdir(old_dir)
898 tarball = base_name + '.tar'
899 self.assertTrue(os.path.exists(tarball))
900
Ezio Melotti975077a2011-05-19 22:03:22 +0300901 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000902 @unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run')
903 def test_make_zipfile(self):
904 # creating something to tar
905 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200906 write_file((tmpdir, 'file1'), 'xxx')
907 write_file((tmpdir, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000908
909 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400910 # force shutil to create the directory
911 os.rmdir(tmpdir2)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000912 base_name = os.path.join(tmpdir2, 'archive')
913 _make_zipfile(base_name, tmpdir)
914
915 # check if the compressed tarball was created
916 tarball = base_name + '.zip'
Éric Araujo1c505492010-11-06 02:12:51 +0000917 self.assertTrue(os.path.exists(tarball))
Tarek Ziadé396fad72010-02-23 05:30:31 +0000918
919
920 def test_make_archive(self):
921 tmpdir = self.mkdtemp()
922 base_name = os.path.join(tmpdir, 'archive')
923 self.assertRaises(ValueError, make_archive, base_name, 'xxx')
924
Ezio Melotti975077a2011-05-19 22:03:22 +0300925 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000926 def test_make_archive_owner_group(self):
927 # testing make_archive with owner and group, with various combinations
928 # this works even if there's not gid/uid support
929 if UID_GID_SUPPORT:
930 group = grp.getgrgid(0)[0]
931 owner = pwd.getpwuid(0)[0]
932 else:
933 group = owner = 'root'
934
935 base_dir, root_dir, base_name = self._create_files()
936 base_name = os.path.join(self.mkdtemp() , 'archive')
937 res = make_archive(base_name, 'zip', root_dir, base_dir, owner=owner,
938 group=group)
939 self.assertTrue(os.path.exists(res))
940
941 res = make_archive(base_name, 'zip', root_dir, base_dir)
942 self.assertTrue(os.path.exists(res))
943
944 res = make_archive(base_name, 'tar', root_dir, base_dir,
945 owner=owner, group=group)
946 self.assertTrue(os.path.exists(res))
947
948 res = make_archive(base_name, 'tar', root_dir, base_dir,
949 owner='kjhkjhkjg', group='oihohoh')
950 self.assertTrue(os.path.exists(res))
951
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000952
Ezio Melotti975077a2011-05-19 22:03:22 +0300953 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000954 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
955 def test_tarfile_root_owner(self):
956 tmpdir, tmpdir2, base_name = self._create_files()
957 old_dir = os.getcwd()
958 os.chdir(tmpdir)
959 group = grp.getgrgid(0)[0]
960 owner = pwd.getpwuid(0)[0]
961 try:
962 archive_name = _make_tarball(base_name, 'dist', compress=None,
963 owner=owner, group=group)
964 finally:
965 os.chdir(old_dir)
966
967 # check if the compressed tarball was created
968 self.assertTrue(os.path.exists(archive_name))
969
970 # now checks the rights
971 archive = tarfile.open(archive_name)
972 try:
973 for member in archive.getmembers():
Ezio Melottib3aedd42010-11-20 19:04:17 +0000974 self.assertEqual(member.uid, 0)
975 self.assertEqual(member.gid, 0)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000976 finally:
977 archive.close()
978
979 def test_make_archive_cwd(self):
980 current_dir = os.getcwd()
981 def _breaks(*args, **kw):
982 raise RuntimeError()
983
984 register_archive_format('xxx', _breaks, [], 'xxx file')
985 try:
986 try:
987 make_archive('xxx', 'xxx', root_dir=self.mkdtemp())
988 except Exception:
989 pass
Ezio Melottib3aedd42010-11-20 19:04:17 +0000990 self.assertEqual(os.getcwd(), current_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000991 finally:
992 unregister_archive_format('xxx')
993
994 def test_register_archive_format(self):
995
996 self.assertRaises(TypeError, register_archive_format, 'xxx', 1)
997 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
998 1)
999 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1000 [(1, 2), (1, 2, 3)])
1001
1002 register_archive_format('xxx', lambda: x, [(1, 2)], 'xxx file')
1003 formats = [name for name, params in get_archive_formats()]
1004 self.assertIn('xxx', formats)
1005
1006 unregister_archive_format('xxx')
1007 formats = [name for name, params in get_archive_formats()]
1008 self.assertNotIn('xxx', formats)
1009
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001010 def _compare_dirs(self, dir1, dir2):
1011 # check that dir1 and dir2 are equivalent,
1012 # return the diff
1013 diff = []
1014 for root, dirs, files in os.walk(dir1):
1015 for file_ in files:
1016 path = os.path.join(root, file_)
1017 target_path = os.path.join(dir2, os.path.split(path)[-1])
1018 if not os.path.exists(target_path):
1019 diff.append(file_)
1020 return diff
1021
Ezio Melotti975077a2011-05-19 22:03:22 +03001022 @requires_zlib
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001023 def test_unpack_archive(self):
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001024 formats = ['tar', 'gztar', 'zip']
1025 if BZ2_SUPPORTED:
1026 formats.append('bztar')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001027
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001028 for format in formats:
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001029 tmpdir = self.mkdtemp()
1030 base_dir, root_dir, base_name = self._create_files()
1031 tmpdir2 = self.mkdtemp()
1032 filename = make_archive(base_name, format, root_dir, base_dir)
1033
1034 # let's try to unpack it now
1035 unpack_archive(filename, tmpdir2)
1036 diff = self._compare_dirs(tmpdir, tmpdir2)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001037 self.assertEqual(diff, [])
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001038
Nick Coghlanabf202d2011-03-16 13:52:20 -04001039 # and again, this time with the format specified
1040 tmpdir3 = self.mkdtemp()
1041 unpack_archive(filename, tmpdir3, format=format)
1042 diff = self._compare_dirs(tmpdir, tmpdir3)
1043 self.assertEqual(diff, [])
1044 self.assertRaises(shutil.ReadError, unpack_archive, TESTFN)
1045 self.assertRaises(ValueError, unpack_archive, TESTFN, format='xxx')
1046
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001047 def test_unpack_registery(self):
1048
1049 formats = get_unpack_formats()
1050
1051 def _boo(filename, extract_dir, extra):
Ezio Melottib3aedd42010-11-20 19:04:17 +00001052 self.assertEqual(extra, 1)
1053 self.assertEqual(filename, 'stuff.boo')
1054 self.assertEqual(extract_dir, 'xx')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001055
1056 register_unpack_format('Boo', ['.boo', '.b2'], _boo, [('extra', 1)])
1057 unpack_archive('stuff.boo', 'xx')
1058
1059 # trying to register a .boo unpacker again
1060 self.assertRaises(RegistryError, register_unpack_format, 'Boo2',
1061 ['.boo'], _boo)
1062
1063 # should work now
1064 unregister_unpack_format('Boo')
1065 register_unpack_format('Boo2', ['.boo'], _boo)
1066 self.assertIn(('Boo2', ['.boo'], ''), get_unpack_formats())
1067 self.assertNotIn(('Boo', ['.boo'], ''), get_unpack_formats())
1068
1069 # let's leave a clean state
1070 unregister_unpack_format('Boo2')
Ezio Melottib3aedd42010-11-20 19:04:17 +00001071 self.assertEqual(get_unpack_formats(), formats)
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001072
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001073 @unittest.skipUnless(hasattr(shutil, 'disk_usage'),
1074 "disk_usage not available on this platform")
1075 def test_disk_usage(self):
1076 usage = shutil.disk_usage(os.getcwd())
Éric Araujo2ee61882011-07-02 16:45:45 +02001077 self.assertGreater(usage.total, 0)
1078 self.assertGreater(usage.used, 0)
1079 self.assertGreaterEqual(usage.free, 0)
1080 self.assertGreaterEqual(usage.total, usage.used)
1081 self.assertGreater(usage.total, usage.free)
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001082
Sandro Tosid902a142011-08-22 23:28:27 +02001083 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1084 @unittest.skipUnless(hasattr(os, 'chown'), 'requires os.chown')
1085 def test_chown(self):
1086
1087 # cleaned-up automatically by TestShutil.tearDown method
1088 dirname = self.mkdtemp()
1089 filename = tempfile.mktemp(dir=dirname)
1090 write_file(filename, 'testing chown function')
1091
1092 with self.assertRaises(ValueError):
1093 shutil.chown(filename)
1094
1095 with self.assertRaises(LookupError):
1096 shutil.chown(filename, user='non-exising username')
1097
1098 with self.assertRaises(LookupError):
1099 shutil.chown(filename, group='non-exising groupname')
1100
1101 with self.assertRaises(TypeError):
1102 shutil.chown(filename, b'spam')
1103
1104 with self.assertRaises(TypeError):
1105 shutil.chown(filename, 3.14)
1106
1107 uid = os.getuid()
1108 gid = os.getgid()
1109
1110 def check_chown(path, uid=None, gid=None):
1111 s = os.stat(filename)
1112 if uid is not None:
1113 self.assertEqual(uid, s.st_uid)
1114 if gid is not None:
1115 self.assertEqual(gid, s.st_gid)
1116
1117 shutil.chown(filename, uid, gid)
1118 check_chown(filename, uid, gid)
1119 shutil.chown(filename, uid)
1120 check_chown(filename, uid)
1121 shutil.chown(filename, user=uid)
1122 check_chown(filename, uid)
1123 shutil.chown(filename, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001124 check_chown(filename, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001125
1126 shutil.chown(dirname, uid, gid)
1127 check_chown(dirname, uid, gid)
1128 shutil.chown(dirname, uid)
1129 check_chown(dirname, uid)
1130 shutil.chown(dirname, user=uid)
1131 check_chown(dirname, uid)
1132 shutil.chown(dirname, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001133 check_chown(dirname, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001134
1135 user = pwd.getpwuid(uid)[0]
1136 group = grp.getgrgid(gid)[0]
1137 shutil.chown(filename, user, group)
1138 check_chown(filename, uid, gid)
1139 shutil.chown(dirname, user, group)
1140 check_chown(dirname, uid, gid)
1141
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001142 def test_copy_return_value(self):
1143 # copy and copy2 both return their destination path.
1144 for fn in (shutil.copy, shutil.copy2):
1145 src_dir = self.mkdtemp()
1146 dst_dir = self.mkdtemp()
1147 src = os.path.join(src_dir, 'foo')
1148 write_file(src, 'foo')
1149 rv = fn(src, dst_dir)
1150 self.assertEqual(rv, os.path.join(dst_dir, 'foo'))
1151 rv = fn(src, os.path.join(dst_dir, 'bar'))
1152 self.assertEqual(rv, os.path.join(dst_dir, 'bar'))
1153
1154 def test_copyfile_return_value(self):
1155 # copytree returns its destination path.
1156 src_dir = self.mkdtemp()
1157 dst_dir = self.mkdtemp()
1158 dst_file = os.path.join(dst_dir, 'bar')
1159 src_file = os.path.join(src_dir, 'foo')
1160 write_file(src_file, 'foo')
1161 rv = shutil.copyfile(src_file, dst_file)
1162 self.assertTrue(os.path.exists(rv))
1163 self.assertEqual(read_file(src_file), read_file(dst_file))
1164
1165 def test_copytree_return_value(self):
1166 # copytree returns its destination path.
1167 src_dir = self.mkdtemp()
1168 dst_dir = src_dir + "dest"
1169 src = os.path.join(src_dir, 'foo')
1170 write_file(src, 'foo')
1171 rv = shutil.copytree(src_dir, dst_dir)
1172 self.assertEqual(['foo'], os.listdir(rv))
1173
Christian Heimes9bd667a2008-01-20 15:14:11 +00001174
Brian Curtinc57a3452012-06-22 16:00:30 -05001175class TestWhich(unittest.TestCase):
1176
1177 def setUp(self):
1178 self.temp_dir = tempfile.mkdtemp()
1179 # Give the temp_file an ".exe" suffix for all.
1180 # It's needed on Windows and not harmful on other platforms.
1181 self.temp_file = tempfile.NamedTemporaryFile(dir=self.temp_dir,
1182 suffix=".exe")
1183 os.chmod(self.temp_file.name, stat.S_IXUSR)
1184 self.addCleanup(self.temp_file.close)
1185 self.dir, self.file = os.path.split(self.temp_file.name)
1186
1187 def test_basic(self):
1188 # Given an EXE in a directory, it should be returned.
1189 rv = shutil.which(self.file, path=self.dir)
1190 self.assertEqual(rv, self.temp_file.name)
1191
1192 def test_full_path_short_circuit(self):
1193 # When given the fully qualified path to an executable that exists,
1194 # it should be returned.
1195 rv = shutil.which(self.temp_file.name, path=self.temp_dir)
1196 self.assertEqual(self.temp_file.name, rv)
1197
1198 def test_non_matching_mode(self):
1199 # Set the file read-only and ask for writeable files.
1200 os.chmod(self.temp_file.name, stat.S_IREAD)
1201 rv = shutil.which(self.file, path=self.dir, mode=os.W_OK)
1202 self.assertIsNone(rv)
1203
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001204 def test_relative(self):
1205 old_cwd = os.getcwd()
1206 base_dir, tail_dir = os.path.split(self.dir)
1207 os.chdir(base_dir)
1208 try:
1209 rv = shutil.which(self.file, path=tail_dir)
1210 self.assertEqual(rv, os.path.join(tail_dir, self.file))
1211 finally:
1212 os.chdir(old_cwd)
1213
Brian Curtinc57a3452012-06-22 16:00:30 -05001214 def test_nonexistent_file(self):
1215 # Return None when no matching executable file is found on the path.
1216 rv = shutil.which("foo.exe", path=self.dir)
1217 self.assertIsNone(rv)
1218
1219 @unittest.skipUnless(sys.platform == "win32",
1220 "pathext check is Windows-only")
1221 def test_pathext_checking(self):
1222 # Ask for the file without the ".exe" extension, then ensure that
1223 # it gets found properly with the extension.
1224 rv = shutil.which(self.temp_file.name[:-4], path=self.dir)
1225 self.assertEqual(self.temp_file.name, rv)
1226
1227
Christian Heimesada8c3b2008-03-18 18:26:33 +00001228class TestMove(unittest.TestCase):
1229
1230 def setUp(self):
1231 filename = "foo"
1232 self.src_dir = tempfile.mkdtemp()
1233 self.dst_dir = tempfile.mkdtemp()
1234 self.src_file = os.path.join(self.src_dir, filename)
1235 self.dst_file = os.path.join(self.dst_dir, filename)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001236 with open(self.src_file, "wb") as f:
1237 f.write(b"spam")
1238
1239 def tearDown(self):
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001240 for d in (self.src_dir, self.dst_dir):
Christian Heimesada8c3b2008-03-18 18:26:33 +00001241 try:
1242 if d:
1243 shutil.rmtree(d)
1244 except:
1245 pass
1246
1247 def _check_move_file(self, src, dst, real_dst):
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001248 with open(src, "rb") as f:
1249 contents = f.read()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001250 shutil.move(src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001251 with open(real_dst, "rb") as f:
1252 self.assertEqual(contents, f.read())
Christian Heimesada8c3b2008-03-18 18:26:33 +00001253 self.assertFalse(os.path.exists(src))
1254
1255 def _check_move_dir(self, src, dst, real_dst):
1256 contents = sorted(os.listdir(src))
1257 shutil.move(src, dst)
1258 self.assertEqual(contents, sorted(os.listdir(real_dst)))
1259 self.assertFalse(os.path.exists(src))
1260
1261 def test_move_file(self):
1262 # Move a file to another location on the same filesystem.
1263 self._check_move_file(self.src_file, self.dst_file, self.dst_file)
1264
1265 def test_move_file_to_dir(self):
1266 # Move a file inside an existing dir on the same filesystem.
1267 self._check_move_file(self.src_file, self.dst_dir, self.dst_file)
1268
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001269 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001270 def test_move_file_other_fs(self):
1271 # Move a file to an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001272 self.test_move_file()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001273
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001274 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001275 def test_move_file_to_dir_other_fs(self):
1276 # Move a file to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001277 self.test_move_file_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001278
1279 def test_move_dir(self):
1280 # Move a dir to another location on the same filesystem.
1281 dst_dir = tempfile.mktemp()
1282 try:
1283 self._check_move_dir(self.src_dir, dst_dir, dst_dir)
1284 finally:
1285 try:
1286 shutil.rmtree(dst_dir)
1287 except:
1288 pass
1289
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001290 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001291 def test_move_dir_other_fs(self):
1292 # Move a dir to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001293 self.test_move_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001294
1295 def test_move_dir_to_dir(self):
1296 # Move a dir inside an existing dir on the same filesystem.
1297 self._check_move_dir(self.src_dir, self.dst_dir,
1298 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1299
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001300 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001301 def test_move_dir_to_dir_other_fs(self):
1302 # Move a dir inside an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001303 self.test_move_dir_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001304
1305 def test_existing_file_inside_dest_dir(self):
1306 # A file with the same name inside the destination dir already exists.
1307 with open(self.dst_file, "wb"):
1308 pass
1309 self.assertRaises(shutil.Error, shutil.move, self.src_file, self.dst_dir)
1310
1311 def test_dont_move_dir_in_itself(self):
1312 # Moving a dir inside itself raises an Error.
1313 dst = os.path.join(self.src_dir, "bar")
1314 self.assertRaises(shutil.Error, shutil.move, self.src_dir, dst)
1315
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001316 def test_destinsrc_false_negative(self):
1317 os.mkdir(TESTFN)
1318 try:
1319 for src, dst in [('srcdir', 'srcdir/dest')]:
1320 src = os.path.join(TESTFN, src)
1321 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001322 self.assertTrue(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001323 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001324 'dst (%s) is not in src (%s)' % (dst, src))
1325 finally:
1326 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001327
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001328 def test_destinsrc_false_positive(self):
1329 os.mkdir(TESTFN)
1330 try:
1331 for src, dst in [('srcdir', 'src/dest'), ('srcdir', 'srcdir.new')]:
1332 src = os.path.join(TESTFN, src)
1333 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001334 self.assertFalse(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001335 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001336 'dst (%s) is in src (%s)' % (dst, src))
1337 finally:
1338 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimes9bd667a2008-01-20 15:14:11 +00001339
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +01001340 @support.skip_unless_symlink
1341 @mock_rename
1342 def test_move_file_symlink(self):
1343 dst = os.path.join(self.src_dir, 'bar')
1344 os.symlink(self.src_file, dst)
1345 shutil.move(dst, self.dst_file)
1346 self.assertTrue(os.path.islink(self.dst_file))
1347 self.assertTrue(os.path.samefile(self.src_file, self.dst_file))
1348
1349 @support.skip_unless_symlink
1350 @mock_rename
1351 def test_move_file_symlink_to_dir(self):
1352 filename = "bar"
1353 dst = os.path.join(self.src_dir, filename)
1354 os.symlink(self.src_file, dst)
1355 shutil.move(dst, self.dst_dir)
1356 final_link = os.path.join(self.dst_dir, filename)
1357 self.assertTrue(os.path.islink(final_link))
1358 self.assertTrue(os.path.samefile(self.src_file, final_link))
1359
1360 @support.skip_unless_symlink
1361 @mock_rename
1362 def test_move_dangling_symlink(self):
1363 src = os.path.join(self.src_dir, 'baz')
1364 dst = os.path.join(self.src_dir, 'bar')
1365 os.symlink(src, dst)
1366 dst_link = os.path.join(self.dst_dir, 'quux')
1367 shutil.move(dst, dst_link)
1368 self.assertTrue(os.path.islink(dst_link))
1369 self.assertEqual(os.path.realpath(src), os.path.realpath(dst_link))
1370
1371 @support.skip_unless_symlink
1372 @mock_rename
1373 def test_move_dir_symlink(self):
1374 src = os.path.join(self.src_dir, 'baz')
1375 dst = os.path.join(self.src_dir, 'bar')
1376 os.mkdir(src)
1377 os.symlink(src, dst)
1378 dst_link = os.path.join(self.dst_dir, 'quux')
1379 shutil.move(dst, dst_link)
1380 self.assertTrue(os.path.islink(dst_link))
1381 self.assertTrue(os.path.samefile(src, dst_link))
1382
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001383 def test_move_return_value(self):
1384 rv = shutil.move(self.src_file, self.dst_dir)
1385 self.assertEqual(rv,
1386 os.path.join(self.dst_dir, os.path.basename(self.src_file)))
1387
1388 def test_move_as_rename_return_value(self):
1389 rv = shutil.move(self.src_file, os.path.join(self.dst_dir, 'bar'))
1390 self.assertEqual(rv, os.path.join(self.dst_dir, 'bar'))
1391
Tarek Ziadé5340db32010-04-19 22:30:51 +00001392
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001393class TestCopyFile(unittest.TestCase):
1394
1395 _delete = False
1396
1397 class Faux(object):
1398 _entered = False
1399 _exited_with = None
1400 _raised = False
1401 def __init__(self, raise_in_exit=False, suppress_at_exit=True):
1402 self._raise_in_exit = raise_in_exit
1403 self._suppress_at_exit = suppress_at_exit
1404 def read(self, *args):
1405 return ''
1406 def __enter__(self):
1407 self._entered = True
1408 def __exit__(self, exc_type, exc_val, exc_tb):
1409 self._exited_with = exc_type, exc_val, exc_tb
1410 if self._raise_in_exit:
1411 self._raised = True
1412 raise IOError("Cannot close")
1413 return self._suppress_at_exit
1414
1415 def tearDown(self):
1416 if self._delete:
1417 del shutil.open
1418
1419 def _set_shutil_open(self, func):
1420 shutil.open = func
1421 self._delete = True
1422
1423 def test_w_source_open_fails(self):
1424 def _open(filename, mode='r'):
1425 if filename == 'srcfile':
1426 raise IOError('Cannot open "srcfile"')
1427 assert 0 # shouldn't reach here.
1428
1429 self._set_shutil_open(_open)
1430
1431 self.assertRaises(IOError, shutil.copyfile, 'srcfile', 'destfile')
1432
1433 def test_w_dest_open_fails(self):
1434
1435 srcfile = self.Faux()
1436
1437 def _open(filename, mode='r'):
1438 if filename == 'srcfile':
1439 return srcfile
1440 if filename == 'destfile':
1441 raise IOError('Cannot open "destfile"')
1442 assert 0 # shouldn't reach here.
1443
1444 self._set_shutil_open(_open)
1445
1446 shutil.copyfile('srcfile', 'destfile')
1447 self.assertTrue(srcfile._entered)
1448 self.assertTrue(srcfile._exited_with[0] is IOError)
1449 self.assertEqual(srcfile._exited_with[1].args,
1450 ('Cannot open "destfile"',))
1451
1452 def test_w_dest_close_fails(self):
1453
1454 srcfile = self.Faux()
1455 destfile = self.Faux(True)
1456
1457 def _open(filename, mode='r'):
1458 if filename == 'srcfile':
1459 return srcfile
1460 if filename == 'destfile':
1461 return destfile
1462 assert 0 # shouldn't reach here.
1463
1464 self._set_shutil_open(_open)
1465
1466 shutil.copyfile('srcfile', 'destfile')
1467 self.assertTrue(srcfile._entered)
1468 self.assertTrue(destfile._entered)
1469 self.assertTrue(destfile._raised)
1470 self.assertTrue(srcfile._exited_with[0] is IOError)
1471 self.assertEqual(srcfile._exited_with[1].args,
1472 ('Cannot close',))
1473
1474 def test_w_source_close_fails(self):
1475
1476 srcfile = self.Faux(True)
1477 destfile = self.Faux()
1478
1479 def _open(filename, mode='r'):
1480 if filename == 'srcfile':
1481 return srcfile
1482 if filename == 'destfile':
1483 return destfile
1484 assert 0 # shouldn't reach here.
1485
1486 self._set_shutil_open(_open)
1487
1488 self.assertRaises(IOError,
1489 shutil.copyfile, 'srcfile', 'destfile')
1490 self.assertTrue(srcfile._entered)
1491 self.assertTrue(destfile._entered)
1492 self.assertFalse(destfile._raised)
1493 self.assertTrue(srcfile._exited_with[0] is None)
1494 self.assertTrue(srcfile._raised)
1495
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001496 def test_move_dir_caseinsensitive(self):
1497 # Renames a folder to the same name
1498 # but a different case.
1499
1500 self.src_dir = tempfile.mkdtemp()
1501 dst_dir = os.path.join(
1502 os.path.dirname(self.src_dir),
1503 os.path.basename(self.src_dir).upper())
1504 self.assertNotEqual(self.src_dir, dst_dir)
1505
1506 try:
1507 shutil.move(self.src_dir, dst_dir)
1508 self.assertTrue(os.path.isdir(dst_dir))
1509 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +02001510 os.rmdir(dst_dir)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001511
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001512class TermsizeTests(unittest.TestCase):
1513 def test_does_not_crash(self):
1514 """Check if get_terminal_size() returns a meaningful value.
1515
1516 There's no easy portable way to actually check the size of the
1517 terminal, so let's check if it returns something sensible instead.
1518 """
1519 size = shutil.get_terminal_size()
Antoine Pitroucfade362012-02-08 23:48:59 +01001520 self.assertGreaterEqual(size.columns, 0)
1521 self.assertGreaterEqual(size.lines, 0)
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001522
1523 def test_os_environ_first(self):
1524 "Check if environment variables have precedence"
1525
1526 with support.EnvironmentVarGuard() as env:
1527 env['COLUMNS'] = '777'
1528 size = shutil.get_terminal_size()
1529 self.assertEqual(size.columns, 777)
1530
1531 with support.EnvironmentVarGuard() as env:
1532 env['LINES'] = '888'
1533 size = shutil.get_terminal_size()
1534 self.assertEqual(size.lines, 888)
1535
1536 @unittest.skipUnless(os.isatty(sys.__stdout__.fileno()), "not on tty")
1537 def test_stty_match(self):
1538 """Check if stty returns the same results ignoring env
1539
1540 This test will fail if stdin and stdout are connected to
1541 different terminals with different sizes. Nevertheless, such
1542 situations should be pretty rare.
1543 """
1544 try:
1545 size = subprocess.check_output(['stty', 'size']).decode().split()
1546 except (FileNotFoundError, subprocess.CalledProcessError):
1547 self.skipTest("stty invocation failed")
1548 expected = (int(size[1]), int(size[0])) # reversed order
1549
1550 with support.EnvironmentVarGuard() as env:
1551 del env['LINES']
1552 del env['COLUMNS']
1553 actual = shutil.get_terminal_size()
1554
1555 self.assertEqual(expected, actual)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001556
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001557
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001558def test_main():
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001559 support.run_unittest(TestShutil, TestMove, TestCopyFile,
Brian Curtinc57a3452012-06-22 16:00:30 -05001560 TermsizeTests, TestWhich)
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001561
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001562if __name__ == '__main__':
Walter Dörwald21d3a322003-05-01 17:45:56 +00001563 test_main()