blob: 4700a49b0030dd435601ba7eab183b7848cb4467 [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)
Tim Peters4590c002004-11-01 02:40:52 +0000123 self.childpath = os.path.join(TESTFN, 'a')
Victor Stinnerbf816222011-06-30 23:25:47 +0200124 support.create_empty_file(self.childpath)
Tim Peters4590c002004-11-01 02:40:52 +0000125 old_dir_mode = os.stat(TESTFN).st_mode
126 old_child_mode = os.stat(self.childpath).st_mode
127 # Make unwritable.
128 os.chmod(self.childpath, stat.S_IREAD)
129 os.chmod(TESTFN, stat.S_IREAD)
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000130
131 shutil.rmtree(TESTFN, onerror=self.check_args_to_onerror)
Johannes Gijsbers8e6f2de2004-11-23 09:27:27 +0000132 # Test whether onerror has actually been called.
Johannes Gijsbersb8b09d02004-12-06 20:50:15 +0000133 self.assertEqual(self.errorState, 2,
134 "Expected call to onerror function did not happen.")
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000135
Tim Peters4590c002004-11-01 02:40:52 +0000136 # Make writable again.
137 os.chmod(TESTFN, old_dir_mode)
138 os.chmod(self.childpath, old_child_mode)
139
140 # Clean up.
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000141 shutil.rmtree(TESTFN)
142
143 def check_args_to_onerror(self, func, arg, exc):
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000144 # test_rmtree_errors deliberately runs rmtree
145 # on a directory that is chmod 400, which will fail.
146 # This function is run when shutil.rmtree fails.
147 # 99.9% of the time it initially fails to remove
148 # a file in the directory, so the first time through
149 # func is os.remove.
150 # However, some Linux machines running ZFS on
151 # FUSE experienced a failure earlier in the process
152 # at os.listdir. The first failure may legally
153 # be either.
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000154 if self.errorState == 0:
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000155 if func is os.remove:
156 self.assertEqual(arg, self.childpath)
157 else:
158 self.assertIs(func, os.listdir,
159 "func must be either os.remove or os.listdir")
160 self.assertEqual(arg, TESTFN)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000161 self.assertTrue(issubclass(exc[0], OSError))
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000162 self.errorState = 1
163 else:
164 self.assertEqual(func, os.rmdir)
165 self.assertEqual(arg, TESTFN)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000166 self.assertTrue(issubclass(exc[0], OSError))
Johannes Gijsbers8e6f2de2004-11-23 09:27:27 +0000167 self.errorState = 2
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000168
Antoine Pitrou78091e62011-12-29 18:54:15 +0100169 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
170 @support.skip_unless_symlink
171 def test_copymode_follow_symlinks(self):
172 tmp_dir = self.mkdtemp()
173 src = os.path.join(tmp_dir, 'foo')
174 dst = os.path.join(tmp_dir, 'bar')
175 src_link = os.path.join(tmp_dir, 'baz')
176 dst_link = os.path.join(tmp_dir, 'quux')
177 write_file(src, 'foo')
178 write_file(dst, 'foo')
179 os.symlink(src, src_link)
180 os.symlink(dst, dst_link)
181 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
182 # file to file
183 os.chmod(dst, stat.S_IRWXO)
184 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
185 shutil.copymode(src, dst)
186 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
187 # follow src link
188 os.chmod(dst, stat.S_IRWXO)
189 shutil.copymode(src_link, dst)
190 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
191 # follow dst link
192 os.chmod(dst, stat.S_IRWXO)
193 shutil.copymode(src, dst_link)
194 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
195 # follow both links
196 os.chmod(dst, stat.S_IRWXO)
197 shutil.copymode(src_link, dst)
198 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
199
200 @unittest.skipUnless(hasattr(os, 'lchmod'), 'requires os.lchmod')
201 @support.skip_unless_symlink
202 def test_copymode_symlink_to_symlink(self):
203 tmp_dir = self.mkdtemp()
204 src = os.path.join(tmp_dir, 'foo')
205 dst = os.path.join(tmp_dir, 'bar')
206 src_link = os.path.join(tmp_dir, 'baz')
207 dst_link = os.path.join(tmp_dir, 'quux')
208 write_file(src, 'foo')
209 write_file(dst, 'foo')
210 os.symlink(src, src_link)
211 os.symlink(dst, dst_link)
212 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
213 os.chmod(dst, stat.S_IRWXU)
214 os.lchmod(src_link, stat.S_IRWXO|stat.S_IRWXG)
215 # link to link
216 os.lchmod(dst_link, stat.S_IRWXO)
217 shutil.copymode(src_link, dst_link, symlinks=True)
218 self.assertEqual(os.lstat(src_link).st_mode,
219 os.lstat(dst_link).st_mode)
220 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
221 # src link - use chmod
222 os.lchmod(dst_link, stat.S_IRWXO)
223 shutil.copymode(src_link, dst, symlinks=True)
224 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
225 # dst link - use chmod
226 os.lchmod(dst_link, stat.S_IRWXO)
227 shutil.copymode(src, dst_link, symlinks=True)
228 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
229
230 @unittest.skipIf(hasattr(os, 'lchmod'), 'requires os.lchmod to be missing')
231 @support.skip_unless_symlink
232 def test_copymode_symlink_to_symlink_wo_lchmod(self):
233 tmp_dir = self.mkdtemp()
234 src = os.path.join(tmp_dir, 'foo')
235 dst = os.path.join(tmp_dir, 'bar')
236 src_link = os.path.join(tmp_dir, 'baz')
237 dst_link = os.path.join(tmp_dir, 'quux')
238 write_file(src, 'foo')
239 write_file(dst, 'foo')
240 os.symlink(src, src_link)
241 os.symlink(dst, dst_link)
242 shutil.copymode(src_link, dst_link, symlinks=True) # silent fail
243
244 @support.skip_unless_symlink
245 def test_copystat_symlinks(self):
246 tmp_dir = self.mkdtemp()
247 src = os.path.join(tmp_dir, 'foo')
248 dst = os.path.join(tmp_dir, 'bar')
249 src_link = os.path.join(tmp_dir, 'baz')
250 dst_link = os.path.join(tmp_dir, 'qux')
251 write_file(src, 'foo')
252 src_stat = os.stat(src)
253 os.utime(src, (src_stat.st_atime,
254 src_stat.st_mtime - 42.0)) # ensure different mtimes
255 write_file(dst, 'bar')
256 self.assertNotEqual(os.stat(src).st_mtime, os.stat(dst).st_mtime)
257 os.symlink(src, src_link)
258 os.symlink(dst, dst_link)
259 if hasattr(os, 'lchmod'):
260 os.lchmod(src_link, stat.S_IRWXO)
261 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
262 os.lchflags(src_link, stat.UF_NODUMP)
263 src_link_stat = os.lstat(src_link)
264 # follow
265 if hasattr(os, 'lchmod'):
266 shutil.copystat(src_link, dst_link, symlinks=False)
267 self.assertNotEqual(src_link_stat.st_mode, os.stat(dst).st_mode)
268 # don't follow
269 shutil.copystat(src_link, dst_link, symlinks=True)
270 dst_link_stat = os.lstat(dst_link)
271 if hasattr(os, 'lutimes'):
272 for attr in 'st_atime', 'st_mtime':
273 # The modification times may be truncated in the new file.
274 self.assertLessEqual(getattr(src_link_stat, attr),
275 getattr(dst_link_stat, attr) + 1)
276 if hasattr(os, 'lchmod'):
277 self.assertEqual(src_link_stat.st_mode, dst_link_stat.st_mode)
278 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
279 self.assertEqual(src_link_stat.st_flags, dst_link_stat.st_flags)
280 # tell to follow but dst is not a link
281 shutil.copystat(src_link, dst, symlinks=True)
282 self.assertTrue(abs(os.stat(src).st_mtime - os.stat(dst).st_mtime) <
283 00000.1)
284
Ned Deilybaf75712012-05-10 17:05:19 -0700285 @unittest.skipUnless(hasattr(os, 'chflags') and
286 hasattr(errno, 'EOPNOTSUPP') and
287 hasattr(errno, 'ENOTSUP'),
288 "requires os.chflags, EOPNOTSUPP & ENOTSUP")
289 def test_copystat_handles_harmless_chflags_errors(self):
290 tmpdir = self.mkdtemp()
291 file1 = os.path.join(tmpdir, 'file1')
292 file2 = os.path.join(tmpdir, 'file2')
293 write_file(file1, 'xxx')
294 write_file(file2, 'xxx')
295
296 def make_chflags_raiser(err):
297 ex = OSError()
298
299 def _chflags_raiser(path, flags):
300 ex.errno = err
301 raise ex
302 return _chflags_raiser
303 old_chflags = os.chflags
304 try:
305 for err in errno.EOPNOTSUPP, errno.ENOTSUP:
306 os.chflags = make_chflags_raiser(err)
307 shutil.copystat(file1, file2)
308 # assert others errors break it
309 os.chflags = make_chflags_raiser(errno.EOPNOTSUPP + errno.ENOTSUP)
310 self.assertRaises(OSError, shutil.copystat, file1, file2)
311 finally:
312 os.chflags = old_chflags
313
Antoine Pitrou78091e62011-12-29 18:54:15 +0100314 @support.skip_unless_symlink
315 def test_copy_symlinks(self):
316 tmp_dir = self.mkdtemp()
317 src = os.path.join(tmp_dir, 'foo')
318 dst = os.path.join(tmp_dir, 'bar')
319 src_link = os.path.join(tmp_dir, 'baz')
320 write_file(src, 'foo')
321 os.symlink(src, src_link)
322 if hasattr(os, 'lchmod'):
323 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
324 # don't follow
325 shutil.copy(src_link, dst, symlinks=False)
326 self.assertFalse(os.path.islink(dst))
327 self.assertEqual(read_file(src), read_file(dst))
328 os.remove(dst)
329 # follow
330 shutil.copy(src_link, dst, symlinks=True)
331 self.assertTrue(os.path.islink(dst))
332 self.assertEqual(os.readlink(dst), os.readlink(src_link))
333 if hasattr(os, 'lchmod'):
334 self.assertEqual(os.lstat(src_link).st_mode,
335 os.lstat(dst).st_mode)
336
337 @support.skip_unless_symlink
338 def test_copy2_symlinks(self):
339 tmp_dir = self.mkdtemp()
340 src = os.path.join(tmp_dir, 'foo')
341 dst = os.path.join(tmp_dir, 'bar')
342 src_link = os.path.join(tmp_dir, 'baz')
343 write_file(src, 'foo')
344 os.symlink(src, src_link)
345 if hasattr(os, 'lchmod'):
346 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
347 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
348 os.lchflags(src_link, stat.UF_NODUMP)
349 src_stat = os.stat(src)
350 src_link_stat = os.lstat(src_link)
351 # follow
352 shutil.copy2(src_link, dst, symlinks=False)
353 self.assertFalse(os.path.islink(dst))
354 self.assertEqual(read_file(src), read_file(dst))
355 os.remove(dst)
356 # don't follow
357 shutil.copy2(src_link, dst, symlinks=True)
358 self.assertTrue(os.path.islink(dst))
359 self.assertEqual(os.readlink(dst), os.readlink(src_link))
360 dst_stat = os.lstat(dst)
361 if hasattr(os, 'lutimes'):
362 for attr in 'st_atime', 'st_mtime':
363 # The modification times may be truncated in the new file.
364 self.assertLessEqual(getattr(src_link_stat, attr),
365 getattr(dst_stat, attr) + 1)
366 if hasattr(os, 'lchmod'):
367 self.assertEqual(src_link_stat.st_mode, dst_stat.st_mode)
368 self.assertNotEqual(src_stat.st_mode, dst_stat.st_mode)
369 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
370 self.assertEqual(src_link_stat.st_flags, dst_stat.st_flags)
371
372 @support.skip_unless_symlink
373 def test_copyfile_symlinks(self):
374 tmp_dir = self.mkdtemp()
375 src = os.path.join(tmp_dir, 'src')
376 dst = os.path.join(tmp_dir, 'dst')
377 dst_link = os.path.join(tmp_dir, 'dst_link')
378 link = os.path.join(tmp_dir, 'link')
379 write_file(src, 'foo')
380 os.symlink(src, link)
381 # don't follow
382 shutil.copyfile(link, dst_link, symlinks=True)
383 self.assertTrue(os.path.islink(dst_link))
384 self.assertEqual(os.readlink(link), os.readlink(dst_link))
385 # follow
386 shutil.copyfile(link, dst)
387 self.assertFalse(os.path.islink(dst))
388
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000389 def test_rmtree_dont_delete_file(self):
390 # When called on a file instead of a directory, don't delete it.
391 handle, path = tempfile.mkstemp()
Victor Stinnerbf816222011-06-30 23:25:47 +0200392 os.close(handle)
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000393 self.assertRaises(OSError, shutil.rmtree, path)
394 os.remove(path)
395
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000396 def test_copytree_simple(self):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000397 src_dir = tempfile.mkdtemp()
398 dst_dir = os.path.join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200399 self.addCleanup(shutil.rmtree, src_dir)
400 self.addCleanup(shutil.rmtree, os.path.dirname(dst_dir))
401 write_file((src_dir, 'test.txt'), '123')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000402 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200403 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000404
Éric Araujoa7e33a12011-08-12 19:51:35 +0200405 shutil.copytree(src_dir, dst_dir)
406 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test.txt')))
407 self.assertTrue(os.path.isdir(os.path.join(dst_dir, 'test_dir')))
408 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test_dir',
409 'test.txt')))
410 actual = read_file((dst_dir, 'test.txt'))
411 self.assertEqual(actual, '123')
412 actual = read_file((dst_dir, 'test_dir', 'test.txt'))
413 self.assertEqual(actual, '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000414
Antoine Pitrou78091e62011-12-29 18:54:15 +0100415 @support.skip_unless_symlink
416 def test_copytree_symlinks(self):
417 tmp_dir = self.mkdtemp()
418 src_dir = os.path.join(tmp_dir, 'src')
419 dst_dir = os.path.join(tmp_dir, 'dst')
420 sub_dir = os.path.join(src_dir, 'sub')
421 os.mkdir(src_dir)
422 os.mkdir(sub_dir)
423 write_file((src_dir, 'file.txt'), 'foo')
424 src_link = os.path.join(sub_dir, 'link')
425 dst_link = os.path.join(dst_dir, 'sub/link')
426 os.symlink(os.path.join(src_dir, 'file.txt'),
427 src_link)
428 if hasattr(os, 'lchmod'):
429 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
430 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
431 os.lchflags(src_link, stat.UF_NODUMP)
432 src_stat = os.lstat(src_link)
433 shutil.copytree(src_dir, dst_dir, symlinks=True)
434 self.assertTrue(os.path.islink(os.path.join(dst_dir, 'sub', 'link')))
435 self.assertEqual(os.readlink(os.path.join(dst_dir, 'sub', 'link')),
436 os.path.join(src_dir, 'file.txt'))
437 dst_stat = os.lstat(dst_link)
438 if hasattr(os, 'lchmod'):
439 self.assertEqual(dst_stat.st_mode, src_stat.st_mode)
440 if hasattr(os, 'lchflags'):
441 self.assertEqual(dst_stat.st_flags, src_stat.st_flags)
442
Georg Brandl2ee470f2008-07-16 12:55:28 +0000443 def test_copytree_with_exclude(self):
Georg Brandl2ee470f2008-07-16 12:55:28 +0000444 # creating data
445 join = os.path.join
446 exists = os.path.exists
447 src_dir = tempfile.mkdtemp()
Georg Brandl2ee470f2008-07-16 12:55:28 +0000448 try:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000449 dst_dir = join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200450 write_file((src_dir, 'test.txt'), '123')
451 write_file((src_dir, 'test.tmp'), '123')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000452 os.mkdir(join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200453 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000454 os.mkdir(join(src_dir, 'test_dir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200455 write_file((src_dir, 'test_dir2', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000456 os.mkdir(join(src_dir, 'test_dir2', 'subdir'))
457 os.mkdir(join(src_dir, 'test_dir2', 'subdir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200458 write_file((src_dir, 'test_dir2', 'subdir', 'test.txt'), '456')
459 write_file((src_dir, 'test_dir2', 'subdir2', 'test.py'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000460
461 # testing glob-like patterns
462 try:
463 patterns = shutil.ignore_patterns('*.tmp', 'test_dir2')
464 shutil.copytree(src_dir, dst_dir, ignore=patterns)
465 # checking the result: some elements should not be copied
466 self.assertTrue(exists(join(dst_dir, 'test.txt')))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200467 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
468 self.assertFalse(exists(join(dst_dir, 'test_dir2')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000469 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200470 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000471 try:
472 patterns = shutil.ignore_patterns('*.tmp', 'subdir*')
473 shutil.copytree(src_dir, dst_dir, ignore=patterns)
474 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200475 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
476 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2')))
477 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000478 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200479 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000480
481 # testing callable-style
482 try:
483 def _filter(src, names):
484 res = []
485 for name in names:
486 path = os.path.join(src, name)
487
488 if (os.path.isdir(path) and
489 path.split()[-1] == 'subdir'):
490 res.append(name)
491 elif os.path.splitext(path)[-1] in ('.py'):
492 res.append(name)
493 return res
494
495 shutil.copytree(src_dir, dst_dir, ignore=_filter)
496
497 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200498 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2',
499 'test.py')))
500 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000501
502 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200503 shutil.rmtree(dst_dir)
Georg Brandl2ee470f2008-07-16 12:55:28 +0000504 finally:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000505 shutil.rmtree(src_dir)
506 shutil.rmtree(os.path.dirname(dst_dir))
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000507
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000508 @unittest.skipUnless(hasattr(os, 'link'), 'requires os.link')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000509 def test_dont_copy_file_onto_link_to_itself(self):
Georg Brandl724d0892010-12-05 07:51:39 +0000510 # Temporarily disable test on Windows.
511 if os.name == 'nt':
512 return
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000513 # bug 851123.
514 os.mkdir(TESTFN)
515 src = os.path.join(TESTFN, 'cheese')
516 dst = os.path.join(TESTFN, 'shop')
517 try:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000518 with open(src, 'w') as f:
519 f.write('cheddar')
520 os.link(src, dst)
521 self.assertRaises(shutil.Error, shutil.copyfile, src, dst)
522 with open(src, 'r') as f:
523 self.assertEqual(f.read(), 'cheddar')
524 os.remove(dst)
525 finally:
526 shutil.rmtree(TESTFN, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000527
Brian Curtin3b4499c2010-12-28 14:31:47 +0000528 @support.skip_unless_symlink
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000529 def test_dont_copy_file_onto_symlink_to_itself(self):
530 # bug 851123.
531 os.mkdir(TESTFN)
532 src = os.path.join(TESTFN, 'cheese')
533 dst = os.path.join(TESTFN, 'shop')
534 try:
535 with open(src, 'w') as f:
536 f.write('cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000537 # Using `src` here would mean we end up with a symlink pointing
538 # to TESTFN/TESTFN/cheese, while it should point at
539 # TESTFN/cheese.
540 os.symlink('cheese', dst)
541 self.assertRaises(shutil.Error, shutil.copyfile, src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +0000542 with open(src, 'r') as f:
543 self.assertEqual(f.read(), 'cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000544 os.remove(dst)
545 finally:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000546 shutil.rmtree(TESTFN, ignore_errors=True)
Johannes Gijsbers68128712004-08-14 13:57:08 +0000547
Brian Curtin3b4499c2010-12-28 14:31:47 +0000548 @support.skip_unless_symlink
Brian Curtind40e6f72010-07-08 21:39:08 +0000549 def test_rmtree_on_symlink(self):
550 # bug 1669.
551 os.mkdir(TESTFN)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000552 try:
Brian Curtind40e6f72010-07-08 21:39:08 +0000553 src = os.path.join(TESTFN, 'cheese')
554 dst = os.path.join(TESTFN, 'shop')
555 os.mkdir(src)
556 os.symlink(src, dst)
557 self.assertRaises(OSError, shutil.rmtree, dst)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000558 finally:
Brian Curtind40e6f72010-07-08 21:39:08 +0000559 shutil.rmtree(TESTFN, ignore_errors=True)
560
561 if hasattr(os, "mkfifo"):
562 # Issue #3002: copyfile and copytree block indefinitely on named pipes
563 def test_copyfile_named_pipe(self):
564 os.mkfifo(TESTFN)
565 try:
566 self.assertRaises(shutil.SpecialFileError,
567 shutil.copyfile, TESTFN, TESTFN2)
568 self.assertRaises(shutil.SpecialFileError,
569 shutil.copyfile, __file__, TESTFN)
570 finally:
571 os.remove(TESTFN)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000572
Brian Curtin3b4499c2010-12-28 14:31:47 +0000573 @support.skip_unless_symlink
Brian Curtin52173d42010-12-02 18:29:18 +0000574 def test_copytree_named_pipe(self):
575 os.mkdir(TESTFN)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000576 try:
Brian Curtin52173d42010-12-02 18:29:18 +0000577 subdir = os.path.join(TESTFN, "subdir")
578 os.mkdir(subdir)
579 pipe = os.path.join(subdir, "mypipe")
580 os.mkfifo(pipe)
581 try:
582 shutil.copytree(TESTFN, TESTFN2)
583 except shutil.Error as e:
584 errors = e.args[0]
585 self.assertEqual(len(errors), 1)
586 src, dst, error_msg = errors[0]
587 self.assertEqual("`%s` is a named pipe" % pipe, error_msg)
588 else:
589 self.fail("shutil.Error should have been raised")
590 finally:
591 shutil.rmtree(TESTFN, ignore_errors=True)
592 shutil.rmtree(TESTFN2, ignore_errors=True)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000593
Tarek Ziadé5340db32010-04-19 22:30:51 +0000594 def test_copytree_special_func(self):
595
596 src_dir = self.mkdtemp()
597 dst_dir = os.path.join(self.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200598 write_file((src_dir, 'test.txt'), '123')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000599 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200600 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000601
602 copied = []
603 def _copy(src, dst):
604 copied.append((src, dst))
605
606 shutil.copytree(src_dir, dst_dir, copy_function=_copy)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000607 self.assertEqual(len(copied), 2)
Tarek Ziadé5340db32010-04-19 22:30:51 +0000608
Brian Curtin3b4499c2010-12-28 14:31:47 +0000609 @support.skip_unless_symlink
Tarek Ziadéfb437512010-04-20 08:57:33 +0000610 def test_copytree_dangling_symlinks(self):
611
612 # a dangling symlink raises an error at the end
613 src_dir = self.mkdtemp()
614 dst_dir = os.path.join(self.mkdtemp(), 'destination')
615 os.symlink('IDONTEXIST', os.path.join(src_dir, 'test.txt'))
616 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200617 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadéfb437512010-04-20 08:57:33 +0000618 self.assertRaises(Error, shutil.copytree, src_dir, dst_dir)
619
620 # a dangling symlink is ignored with the proper flag
621 dst_dir = os.path.join(self.mkdtemp(), 'destination2')
622 shutil.copytree(src_dir, dst_dir, ignore_dangling_symlinks=True)
623 self.assertNotIn('test.txt', os.listdir(dst_dir))
624
625 # a dangling symlink is copied if symlinks=True
626 dst_dir = os.path.join(self.mkdtemp(), 'destination3')
627 shutil.copytree(src_dir, dst_dir, symlinks=True)
628 self.assertIn('test.txt', os.listdir(dst_dir))
629
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400630 def _copy_file(self, method):
631 fname = 'test.txt'
632 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200633 write_file((tmpdir, fname), 'xxx')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400634 file1 = os.path.join(tmpdir, fname)
635 tmpdir2 = self.mkdtemp()
636 method(file1, tmpdir2)
637 file2 = os.path.join(tmpdir2, fname)
638 return (file1, file2)
639
640 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
641 def test_copy(self):
642 # Ensure that the copied file exists and has the same mode bits.
643 file1, file2 = self._copy_file(shutil.copy)
644 self.assertTrue(os.path.exists(file2))
645 self.assertEqual(os.stat(file1).st_mode, os.stat(file2).st_mode)
646
647 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
Senthil Kumaran0c2dba52011-07-03 18:21:38 -0700648 @unittest.skipUnless(hasattr(os, 'utime'), 'requires os.utime')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400649 def test_copy2(self):
650 # Ensure that the copied file exists and has the same mode and
651 # modification time bits.
652 file1, file2 = self._copy_file(shutil.copy2)
653 self.assertTrue(os.path.exists(file2))
654 file1_stat = os.stat(file1)
655 file2_stat = os.stat(file2)
656 self.assertEqual(file1_stat.st_mode, file2_stat.st_mode)
657 for attr in 'st_atime', 'st_mtime':
658 # The modification times may be truncated in the new file.
659 self.assertLessEqual(getattr(file1_stat, attr),
660 getattr(file2_stat, attr) + 1)
661 if hasattr(os, 'chflags') and hasattr(file1_stat, 'st_flags'):
662 self.assertEqual(getattr(file1_stat, 'st_flags'),
663 getattr(file2_stat, 'st_flags'))
664
Ezio Melotti975077a2011-05-19 22:03:22 +0300665 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000666 def test_make_tarball(self):
667 # creating something to tar
668 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200669 write_file((tmpdir, 'file1'), 'xxx')
670 write_file((tmpdir, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000671 os.mkdir(os.path.join(tmpdir, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200672 write_file((tmpdir, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000673
674 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400675 # force shutil to create the directory
676 os.rmdir(tmpdir2)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000677 unittest.skipUnless(splitdrive(tmpdir)[0] == splitdrive(tmpdir2)[0],
678 "source and target should be on same drive")
679
680 base_name = os.path.join(tmpdir2, 'archive')
681
682 # working with relative paths to avoid tar warnings
683 old_dir = os.getcwd()
684 os.chdir(tmpdir)
685 try:
686 _make_tarball(splitdrive(base_name)[1], '.')
687 finally:
688 os.chdir(old_dir)
689
690 # check if the compressed tarball was created
691 tarball = base_name + '.tar.gz'
692 self.assertTrue(os.path.exists(tarball))
693
694 # trying an uncompressed one
695 base_name = os.path.join(tmpdir2, 'archive')
696 old_dir = os.getcwd()
697 os.chdir(tmpdir)
698 try:
699 _make_tarball(splitdrive(base_name)[1], '.', compress=None)
700 finally:
701 os.chdir(old_dir)
702 tarball = base_name + '.tar'
703 self.assertTrue(os.path.exists(tarball))
704
705 def _tarinfo(self, path):
706 tar = tarfile.open(path)
707 try:
708 names = tar.getnames()
709 names.sort()
710 return tuple(names)
711 finally:
712 tar.close()
713
714 def _create_files(self):
715 # creating something to tar
716 tmpdir = self.mkdtemp()
717 dist = os.path.join(tmpdir, 'dist')
718 os.mkdir(dist)
Éric Araujoa7e33a12011-08-12 19:51:35 +0200719 write_file((dist, 'file1'), 'xxx')
720 write_file((dist, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000721 os.mkdir(os.path.join(dist, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200722 write_file((dist, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000723 os.mkdir(os.path.join(dist, 'sub2'))
724 tmpdir2 = self.mkdtemp()
725 base_name = os.path.join(tmpdir2, 'archive')
726 return tmpdir, tmpdir2, base_name
727
Ezio Melotti975077a2011-05-19 22:03:22 +0300728 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000729 @unittest.skipUnless(find_executable('tar') and find_executable('gzip'),
730 'Need the tar command to run')
731 def test_tarfile_vs_tar(self):
732 tmpdir, tmpdir2, base_name = self._create_files()
733 old_dir = os.getcwd()
734 os.chdir(tmpdir)
735 try:
736 _make_tarball(base_name, 'dist')
737 finally:
738 os.chdir(old_dir)
739
740 # check if the compressed tarball was created
741 tarball = base_name + '.tar.gz'
742 self.assertTrue(os.path.exists(tarball))
743
744 # now create another tarball using `tar`
745 tarball2 = os.path.join(tmpdir, 'archive2.tar.gz')
746 tar_cmd = ['tar', '-cf', 'archive2.tar', 'dist']
747 gzip_cmd = ['gzip', '-f9', 'archive2.tar']
748 old_dir = os.getcwd()
749 os.chdir(tmpdir)
750 try:
751 with captured_stdout() as s:
752 spawn(tar_cmd)
753 spawn(gzip_cmd)
754 finally:
755 os.chdir(old_dir)
756
757 self.assertTrue(os.path.exists(tarball2))
758 # let's compare both tarballs
Ezio Melottib3aedd42010-11-20 19:04:17 +0000759 self.assertEqual(self._tarinfo(tarball), self._tarinfo(tarball2))
Tarek Ziadé396fad72010-02-23 05:30:31 +0000760
761 # trying an uncompressed one
762 base_name = os.path.join(tmpdir2, 'archive')
763 old_dir = os.getcwd()
764 os.chdir(tmpdir)
765 try:
766 _make_tarball(base_name, 'dist', compress=None)
767 finally:
768 os.chdir(old_dir)
769 tarball = base_name + '.tar'
770 self.assertTrue(os.path.exists(tarball))
771
772 # now for a dry_run
773 base_name = os.path.join(tmpdir2, 'archive')
774 old_dir = os.getcwd()
775 os.chdir(tmpdir)
776 try:
777 _make_tarball(base_name, 'dist', compress=None, dry_run=True)
778 finally:
779 os.chdir(old_dir)
780 tarball = base_name + '.tar'
781 self.assertTrue(os.path.exists(tarball))
782
Ezio Melotti975077a2011-05-19 22:03:22 +0300783 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000784 @unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run')
785 def test_make_zipfile(self):
786 # creating something to tar
787 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200788 write_file((tmpdir, 'file1'), 'xxx')
789 write_file((tmpdir, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000790
791 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400792 # force shutil to create the directory
793 os.rmdir(tmpdir2)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000794 base_name = os.path.join(tmpdir2, 'archive')
795 _make_zipfile(base_name, tmpdir)
796
797 # check if the compressed tarball was created
798 tarball = base_name + '.zip'
Éric Araujo1c505492010-11-06 02:12:51 +0000799 self.assertTrue(os.path.exists(tarball))
Tarek Ziadé396fad72010-02-23 05:30:31 +0000800
801
802 def test_make_archive(self):
803 tmpdir = self.mkdtemp()
804 base_name = os.path.join(tmpdir, 'archive')
805 self.assertRaises(ValueError, make_archive, base_name, 'xxx')
806
Ezio Melotti975077a2011-05-19 22:03:22 +0300807 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000808 def test_make_archive_owner_group(self):
809 # testing make_archive with owner and group, with various combinations
810 # this works even if there's not gid/uid support
811 if UID_GID_SUPPORT:
812 group = grp.getgrgid(0)[0]
813 owner = pwd.getpwuid(0)[0]
814 else:
815 group = owner = 'root'
816
817 base_dir, root_dir, base_name = self._create_files()
818 base_name = os.path.join(self.mkdtemp() , 'archive')
819 res = make_archive(base_name, 'zip', root_dir, base_dir, owner=owner,
820 group=group)
821 self.assertTrue(os.path.exists(res))
822
823 res = make_archive(base_name, 'zip', root_dir, base_dir)
824 self.assertTrue(os.path.exists(res))
825
826 res = make_archive(base_name, 'tar', root_dir, base_dir,
827 owner=owner, group=group)
828 self.assertTrue(os.path.exists(res))
829
830 res = make_archive(base_name, 'tar', root_dir, base_dir,
831 owner='kjhkjhkjg', group='oihohoh')
832 self.assertTrue(os.path.exists(res))
833
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000834
Ezio Melotti975077a2011-05-19 22:03:22 +0300835 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000836 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
837 def test_tarfile_root_owner(self):
838 tmpdir, tmpdir2, base_name = self._create_files()
839 old_dir = os.getcwd()
840 os.chdir(tmpdir)
841 group = grp.getgrgid(0)[0]
842 owner = pwd.getpwuid(0)[0]
843 try:
844 archive_name = _make_tarball(base_name, 'dist', compress=None,
845 owner=owner, group=group)
846 finally:
847 os.chdir(old_dir)
848
849 # check if the compressed tarball was created
850 self.assertTrue(os.path.exists(archive_name))
851
852 # now checks the rights
853 archive = tarfile.open(archive_name)
854 try:
855 for member in archive.getmembers():
Ezio Melottib3aedd42010-11-20 19:04:17 +0000856 self.assertEqual(member.uid, 0)
857 self.assertEqual(member.gid, 0)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000858 finally:
859 archive.close()
860
861 def test_make_archive_cwd(self):
862 current_dir = os.getcwd()
863 def _breaks(*args, **kw):
864 raise RuntimeError()
865
866 register_archive_format('xxx', _breaks, [], 'xxx file')
867 try:
868 try:
869 make_archive('xxx', 'xxx', root_dir=self.mkdtemp())
870 except Exception:
871 pass
Ezio Melottib3aedd42010-11-20 19:04:17 +0000872 self.assertEqual(os.getcwd(), current_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000873 finally:
874 unregister_archive_format('xxx')
875
876 def test_register_archive_format(self):
877
878 self.assertRaises(TypeError, register_archive_format, 'xxx', 1)
879 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
880 1)
881 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
882 [(1, 2), (1, 2, 3)])
883
884 register_archive_format('xxx', lambda: x, [(1, 2)], 'xxx file')
885 formats = [name for name, params in get_archive_formats()]
886 self.assertIn('xxx', formats)
887
888 unregister_archive_format('xxx')
889 formats = [name for name, params in get_archive_formats()]
890 self.assertNotIn('xxx', formats)
891
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000892 def _compare_dirs(self, dir1, dir2):
893 # check that dir1 and dir2 are equivalent,
894 # return the diff
895 diff = []
896 for root, dirs, files in os.walk(dir1):
897 for file_ in files:
898 path = os.path.join(root, file_)
899 target_path = os.path.join(dir2, os.path.split(path)[-1])
900 if not os.path.exists(target_path):
901 diff.append(file_)
902 return diff
903
Ezio Melotti975077a2011-05-19 22:03:22 +0300904 @requires_zlib
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000905 def test_unpack_archive(self):
Tarek Ziadéffa155a2010-04-29 13:34:35 +0000906 formats = ['tar', 'gztar', 'zip']
907 if BZ2_SUPPORTED:
908 formats.append('bztar')
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000909
Tarek Ziadéffa155a2010-04-29 13:34:35 +0000910 for format in formats:
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000911 tmpdir = self.mkdtemp()
912 base_dir, root_dir, base_name = self._create_files()
913 tmpdir2 = self.mkdtemp()
914 filename = make_archive(base_name, format, root_dir, base_dir)
915
916 # let's try to unpack it now
917 unpack_archive(filename, tmpdir2)
918 diff = self._compare_dirs(tmpdir, tmpdir2)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000919 self.assertEqual(diff, [])
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000920
Nick Coghlanabf202d2011-03-16 13:52:20 -0400921 # and again, this time with the format specified
922 tmpdir3 = self.mkdtemp()
923 unpack_archive(filename, tmpdir3, format=format)
924 diff = self._compare_dirs(tmpdir, tmpdir3)
925 self.assertEqual(diff, [])
926 self.assertRaises(shutil.ReadError, unpack_archive, TESTFN)
927 self.assertRaises(ValueError, unpack_archive, TESTFN, format='xxx')
928
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000929 def test_unpack_registery(self):
930
931 formats = get_unpack_formats()
932
933 def _boo(filename, extract_dir, extra):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000934 self.assertEqual(extra, 1)
935 self.assertEqual(filename, 'stuff.boo')
936 self.assertEqual(extract_dir, 'xx')
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000937
938 register_unpack_format('Boo', ['.boo', '.b2'], _boo, [('extra', 1)])
939 unpack_archive('stuff.boo', 'xx')
940
941 # trying to register a .boo unpacker again
942 self.assertRaises(RegistryError, register_unpack_format, 'Boo2',
943 ['.boo'], _boo)
944
945 # should work now
946 unregister_unpack_format('Boo')
947 register_unpack_format('Boo2', ['.boo'], _boo)
948 self.assertIn(('Boo2', ['.boo'], ''), get_unpack_formats())
949 self.assertNotIn(('Boo', ['.boo'], ''), get_unpack_formats())
950
951 # let's leave a clean state
952 unregister_unpack_format('Boo2')
Ezio Melottib3aedd42010-11-20 19:04:17 +0000953 self.assertEqual(get_unpack_formats(), formats)
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000954
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +0200955 @unittest.skipUnless(hasattr(shutil, 'disk_usage'),
956 "disk_usage not available on this platform")
957 def test_disk_usage(self):
958 usage = shutil.disk_usage(os.getcwd())
Éric Araujo2ee61882011-07-02 16:45:45 +0200959 self.assertGreater(usage.total, 0)
960 self.assertGreater(usage.used, 0)
961 self.assertGreaterEqual(usage.free, 0)
962 self.assertGreaterEqual(usage.total, usage.used)
963 self.assertGreater(usage.total, usage.free)
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +0200964
Sandro Tosid902a142011-08-22 23:28:27 +0200965 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
966 @unittest.skipUnless(hasattr(os, 'chown'), 'requires os.chown')
967 def test_chown(self):
968
969 # cleaned-up automatically by TestShutil.tearDown method
970 dirname = self.mkdtemp()
971 filename = tempfile.mktemp(dir=dirname)
972 write_file(filename, 'testing chown function')
973
974 with self.assertRaises(ValueError):
975 shutil.chown(filename)
976
977 with self.assertRaises(LookupError):
978 shutil.chown(filename, user='non-exising username')
979
980 with self.assertRaises(LookupError):
981 shutil.chown(filename, group='non-exising groupname')
982
983 with self.assertRaises(TypeError):
984 shutil.chown(filename, b'spam')
985
986 with self.assertRaises(TypeError):
987 shutil.chown(filename, 3.14)
988
989 uid = os.getuid()
990 gid = os.getgid()
991
992 def check_chown(path, uid=None, gid=None):
993 s = os.stat(filename)
994 if uid is not None:
995 self.assertEqual(uid, s.st_uid)
996 if gid is not None:
997 self.assertEqual(gid, s.st_gid)
998
999 shutil.chown(filename, uid, gid)
1000 check_chown(filename, uid, gid)
1001 shutil.chown(filename, uid)
1002 check_chown(filename, uid)
1003 shutil.chown(filename, user=uid)
1004 check_chown(filename, uid)
1005 shutil.chown(filename, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001006 check_chown(filename, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001007
1008 shutil.chown(dirname, uid, gid)
1009 check_chown(dirname, uid, gid)
1010 shutil.chown(dirname, uid)
1011 check_chown(dirname, uid)
1012 shutil.chown(dirname, user=uid)
1013 check_chown(dirname, uid)
1014 shutil.chown(dirname, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001015 check_chown(dirname, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001016
1017 user = pwd.getpwuid(uid)[0]
1018 group = grp.getgrgid(gid)[0]
1019 shutil.chown(filename, user, group)
1020 check_chown(filename, uid, gid)
1021 shutil.chown(dirname, user, group)
1022 check_chown(dirname, uid, gid)
1023
Christian Heimes9bd667a2008-01-20 15:14:11 +00001024
Christian Heimesada8c3b2008-03-18 18:26:33 +00001025class TestMove(unittest.TestCase):
1026
1027 def setUp(self):
1028 filename = "foo"
1029 self.src_dir = tempfile.mkdtemp()
1030 self.dst_dir = tempfile.mkdtemp()
1031 self.src_file = os.path.join(self.src_dir, filename)
1032 self.dst_file = os.path.join(self.dst_dir, filename)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001033 with open(self.src_file, "wb") as f:
1034 f.write(b"spam")
1035
1036 def tearDown(self):
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001037 for d in (self.src_dir, self.dst_dir):
Christian Heimesada8c3b2008-03-18 18:26:33 +00001038 try:
1039 if d:
1040 shutil.rmtree(d)
1041 except:
1042 pass
1043
1044 def _check_move_file(self, src, dst, real_dst):
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001045 with open(src, "rb") as f:
1046 contents = f.read()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001047 shutil.move(src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001048 with open(real_dst, "rb") as f:
1049 self.assertEqual(contents, f.read())
Christian Heimesada8c3b2008-03-18 18:26:33 +00001050 self.assertFalse(os.path.exists(src))
1051
1052 def _check_move_dir(self, src, dst, real_dst):
1053 contents = sorted(os.listdir(src))
1054 shutil.move(src, dst)
1055 self.assertEqual(contents, sorted(os.listdir(real_dst)))
1056 self.assertFalse(os.path.exists(src))
1057
1058 def test_move_file(self):
1059 # Move a file to another location on the same filesystem.
1060 self._check_move_file(self.src_file, self.dst_file, self.dst_file)
1061
1062 def test_move_file_to_dir(self):
1063 # Move a file inside an existing dir on the same filesystem.
1064 self._check_move_file(self.src_file, self.dst_dir, self.dst_file)
1065
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001066 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001067 def test_move_file_other_fs(self):
1068 # Move a file to an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001069 self.test_move_file()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001070
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001071 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001072 def test_move_file_to_dir_other_fs(self):
1073 # Move a file to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001074 self.test_move_file_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001075
1076 def test_move_dir(self):
1077 # Move a dir to another location on the same filesystem.
1078 dst_dir = tempfile.mktemp()
1079 try:
1080 self._check_move_dir(self.src_dir, dst_dir, dst_dir)
1081 finally:
1082 try:
1083 shutil.rmtree(dst_dir)
1084 except:
1085 pass
1086
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001087 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001088 def test_move_dir_other_fs(self):
1089 # Move a dir to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001090 self.test_move_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001091
1092 def test_move_dir_to_dir(self):
1093 # Move a dir inside an existing dir on the same filesystem.
1094 self._check_move_dir(self.src_dir, self.dst_dir,
1095 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1096
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001097 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001098 def test_move_dir_to_dir_other_fs(self):
1099 # Move a dir inside an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001100 self.test_move_dir_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001101
1102 def test_existing_file_inside_dest_dir(self):
1103 # A file with the same name inside the destination dir already exists.
1104 with open(self.dst_file, "wb"):
1105 pass
1106 self.assertRaises(shutil.Error, shutil.move, self.src_file, self.dst_dir)
1107
1108 def test_dont_move_dir_in_itself(self):
1109 # Moving a dir inside itself raises an Error.
1110 dst = os.path.join(self.src_dir, "bar")
1111 self.assertRaises(shutil.Error, shutil.move, self.src_dir, dst)
1112
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001113 def test_destinsrc_false_negative(self):
1114 os.mkdir(TESTFN)
1115 try:
1116 for src, dst in [('srcdir', 'srcdir/dest')]:
1117 src = os.path.join(TESTFN, src)
1118 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001119 self.assertTrue(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001120 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001121 'dst (%s) is not in src (%s)' % (dst, src))
1122 finally:
1123 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001124
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001125 def test_destinsrc_false_positive(self):
1126 os.mkdir(TESTFN)
1127 try:
1128 for src, dst in [('srcdir', 'src/dest'), ('srcdir', 'srcdir.new')]:
1129 src = os.path.join(TESTFN, src)
1130 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001131 self.assertFalse(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001132 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001133 'dst (%s) is in src (%s)' % (dst, src))
1134 finally:
1135 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimes9bd667a2008-01-20 15:14:11 +00001136
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +01001137 @support.skip_unless_symlink
1138 @mock_rename
1139 def test_move_file_symlink(self):
1140 dst = os.path.join(self.src_dir, 'bar')
1141 os.symlink(self.src_file, dst)
1142 shutil.move(dst, self.dst_file)
1143 self.assertTrue(os.path.islink(self.dst_file))
1144 self.assertTrue(os.path.samefile(self.src_file, self.dst_file))
1145
1146 @support.skip_unless_symlink
1147 @mock_rename
1148 def test_move_file_symlink_to_dir(self):
1149 filename = "bar"
1150 dst = os.path.join(self.src_dir, filename)
1151 os.symlink(self.src_file, dst)
1152 shutil.move(dst, self.dst_dir)
1153 final_link = os.path.join(self.dst_dir, filename)
1154 self.assertTrue(os.path.islink(final_link))
1155 self.assertTrue(os.path.samefile(self.src_file, final_link))
1156
1157 @support.skip_unless_symlink
1158 @mock_rename
1159 def test_move_dangling_symlink(self):
1160 src = os.path.join(self.src_dir, 'baz')
1161 dst = os.path.join(self.src_dir, 'bar')
1162 os.symlink(src, dst)
1163 dst_link = os.path.join(self.dst_dir, 'quux')
1164 shutil.move(dst, dst_link)
1165 self.assertTrue(os.path.islink(dst_link))
1166 self.assertEqual(os.path.realpath(src), os.path.realpath(dst_link))
1167
1168 @support.skip_unless_symlink
1169 @mock_rename
1170 def test_move_dir_symlink(self):
1171 src = os.path.join(self.src_dir, 'baz')
1172 dst = os.path.join(self.src_dir, 'bar')
1173 os.mkdir(src)
1174 os.symlink(src, dst)
1175 dst_link = os.path.join(self.dst_dir, 'quux')
1176 shutil.move(dst, dst_link)
1177 self.assertTrue(os.path.islink(dst_link))
1178 self.assertTrue(os.path.samefile(src, dst_link))
1179
Tarek Ziadé5340db32010-04-19 22:30:51 +00001180
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001181class TestCopyFile(unittest.TestCase):
1182
1183 _delete = False
1184
1185 class Faux(object):
1186 _entered = False
1187 _exited_with = None
1188 _raised = False
1189 def __init__(self, raise_in_exit=False, suppress_at_exit=True):
1190 self._raise_in_exit = raise_in_exit
1191 self._suppress_at_exit = suppress_at_exit
1192 def read(self, *args):
1193 return ''
1194 def __enter__(self):
1195 self._entered = True
1196 def __exit__(self, exc_type, exc_val, exc_tb):
1197 self._exited_with = exc_type, exc_val, exc_tb
1198 if self._raise_in_exit:
1199 self._raised = True
1200 raise IOError("Cannot close")
1201 return self._suppress_at_exit
1202
1203 def tearDown(self):
1204 if self._delete:
1205 del shutil.open
1206
1207 def _set_shutil_open(self, func):
1208 shutil.open = func
1209 self._delete = True
1210
1211 def test_w_source_open_fails(self):
1212 def _open(filename, mode='r'):
1213 if filename == 'srcfile':
1214 raise IOError('Cannot open "srcfile"')
1215 assert 0 # shouldn't reach here.
1216
1217 self._set_shutil_open(_open)
1218
1219 self.assertRaises(IOError, shutil.copyfile, 'srcfile', 'destfile')
1220
1221 def test_w_dest_open_fails(self):
1222
1223 srcfile = self.Faux()
1224
1225 def _open(filename, mode='r'):
1226 if filename == 'srcfile':
1227 return srcfile
1228 if filename == 'destfile':
1229 raise IOError('Cannot open "destfile"')
1230 assert 0 # shouldn't reach here.
1231
1232 self._set_shutil_open(_open)
1233
1234 shutil.copyfile('srcfile', 'destfile')
1235 self.assertTrue(srcfile._entered)
1236 self.assertTrue(srcfile._exited_with[0] is IOError)
1237 self.assertEqual(srcfile._exited_with[1].args,
1238 ('Cannot open "destfile"',))
1239
1240 def test_w_dest_close_fails(self):
1241
1242 srcfile = self.Faux()
1243 destfile = self.Faux(True)
1244
1245 def _open(filename, mode='r'):
1246 if filename == 'srcfile':
1247 return srcfile
1248 if filename == 'destfile':
1249 return destfile
1250 assert 0 # shouldn't reach here.
1251
1252 self._set_shutil_open(_open)
1253
1254 shutil.copyfile('srcfile', 'destfile')
1255 self.assertTrue(srcfile._entered)
1256 self.assertTrue(destfile._entered)
1257 self.assertTrue(destfile._raised)
1258 self.assertTrue(srcfile._exited_with[0] is IOError)
1259 self.assertEqual(srcfile._exited_with[1].args,
1260 ('Cannot close',))
1261
1262 def test_w_source_close_fails(self):
1263
1264 srcfile = self.Faux(True)
1265 destfile = self.Faux()
1266
1267 def _open(filename, mode='r'):
1268 if filename == 'srcfile':
1269 return srcfile
1270 if filename == 'destfile':
1271 return destfile
1272 assert 0 # shouldn't reach here.
1273
1274 self._set_shutil_open(_open)
1275
1276 self.assertRaises(IOError,
1277 shutil.copyfile, 'srcfile', 'destfile')
1278 self.assertTrue(srcfile._entered)
1279 self.assertTrue(destfile._entered)
1280 self.assertFalse(destfile._raised)
1281 self.assertTrue(srcfile._exited_with[0] is None)
1282 self.assertTrue(srcfile._raised)
1283
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001284 def test_move_dir_caseinsensitive(self):
1285 # Renames a folder to the same name
1286 # but a different case.
1287
1288 self.src_dir = tempfile.mkdtemp()
1289 dst_dir = os.path.join(
1290 os.path.dirname(self.src_dir),
1291 os.path.basename(self.src_dir).upper())
1292 self.assertNotEqual(self.src_dir, dst_dir)
1293
1294 try:
1295 shutil.move(self.src_dir, dst_dir)
1296 self.assertTrue(os.path.isdir(dst_dir))
1297 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +02001298 os.rmdir(dst_dir)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001299
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001300class TermsizeTests(unittest.TestCase):
1301 def test_does_not_crash(self):
1302 """Check if get_terminal_size() returns a meaningful value.
1303
1304 There's no easy portable way to actually check the size of the
1305 terminal, so let's check if it returns something sensible instead.
1306 """
1307 size = shutil.get_terminal_size()
Antoine Pitroucfade362012-02-08 23:48:59 +01001308 self.assertGreaterEqual(size.columns, 0)
1309 self.assertGreaterEqual(size.lines, 0)
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001310
1311 def test_os_environ_first(self):
1312 "Check if environment variables have precedence"
1313
1314 with support.EnvironmentVarGuard() as env:
1315 env['COLUMNS'] = '777'
1316 size = shutil.get_terminal_size()
1317 self.assertEqual(size.columns, 777)
1318
1319 with support.EnvironmentVarGuard() as env:
1320 env['LINES'] = '888'
1321 size = shutil.get_terminal_size()
1322 self.assertEqual(size.lines, 888)
1323
1324 @unittest.skipUnless(os.isatty(sys.__stdout__.fileno()), "not on tty")
1325 def test_stty_match(self):
1326 """Check if stty returns the same results ignoring env
1327
1328 This test will fail if stdin and stdout are connected to
1329 different terminals with different sizes. Nevertheless, such
1330 situations should be pretty rare.
1331 """
1332 try:
1333 size = subprocess.check_output(['stty', 'size']).decode().split()
1334 except (FileNotFoundError, subprocess.CalledProcessError):
1335 self.skipTest("stty invocation failed")
1336 expected = (int(size[1]), int(size[0])) # reversed order
1337
1338 with support.EnvironmentVarGuard() as env:
1339 del env['LINES']
1340 del env['COLUMNS']
1341 actual = shutil.get_terminal_size()
1342
1343 self.assertEqual(expected, actual)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001344
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001345
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001346def test_main():
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001347 support.run_unittest(TestShutil, TestMove, TestCopyFile,
1348 TermsizeTests)
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001349
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001350if __name__ == '__main__':
Walter Dörwald21d3a322003-05-01 17:45:56 +00001351 test_main()