blob: c72bac26cefbd9d7419e804ec4f6070e3c3bd592 [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
Benjamin Petersonee8712c2008-05-20 21:35:26 +000012from test import support
13from test.support import TESTFN
Tarek Ziadé396fad72010-02-23 05:30:31 +000014from os.path import splitdrive
15from distutils.spawn import find_executable, spawn
16from shutil import (_make_tarball, _make_zipfile, make_archive,
17 register_archive_format, unregister_archive_format,
Tarek Ziadé6ac91722010-04-28 17:51:36 +000018 get_archive_formats, Error, unpack_archive,
19 register_unpack_format, RegistryError,
20 unregister_unpack_format, get_unpack_formats)
Tarek Ziadé396fad72010-02-23 05:30:31 +000021import tarfile
22import warnings
23
24from test import support
Ezio Melotti975077a2011-05-19 22:03:22 +030025from test.support import TESTFN, check_warnings, captured_stdout, requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +000026
Tarek Ziadéffa155a2010-04-29 13:34:35 +000027try:
28 import bz2
29 BZ2_SUPPORTED = True
30except ImportError:
31 BZ2_SUPPORTED = False
32
Antoine Pitrou7fff0962009-05-01 21:09:44 +000033TESTFN2 = TESTFN + "2"
Barry Warsaw7fc2cca2003-01-24 17:34:13 +000034
Tarek Ziadé396fad72010-02-23 05:30:31 +000035try:
36 import grp
37 import pwd
38 UID_GID_SUPPORT = True
39except ImportError:
40 UID_GID_SUPPORT = False
41
42try:
Tarek Ziadé396fad72010-02-23 05:30:31 +000043 import zipfile
44 ZIP_SUPPORT = True
45except ImportError:
46 ZIP_SUPPORT = find_executable('zip')
47
Nick Coghlan8ed3cf32011-03-16 14:05:35 -040048def _fake_rename(*args, **kwargs):
49 # Pretend the destination path is on a different filesystem.
Antoine Pitrouc041ab62012-01-02 19:18:02 +010050 raise OSError(getattr(errno, 'EXDEV', 18), "Invalid cross-device link")
Nick Coghlan8ed3cf32011-03-16 14:05:35 -040051
52def mock_rename(func):
53 @functools.wraps(func)
54 def wrap(*args, **kwargs):
55 try:
56 builtin_rename = os.rename
57 os.rename = _fake_rename
58 return func(*args, **kwargs)
59 finally:
60 os.rename = builtin_rename
61 return wrap
62
Éric Araujoa7e33a12011-08-12 19:51:35 +020063def write_file(path, content, binary=False):
64 """Write *content* to a file located at *path*.
65
66 If *path* is a tuple instead of a string, os.path.join will be used to
67 make a path. If *binary* is true, the file will be opened in binary
68 mode.
69 """
70 if isinstance(path, tuple):
71 path = os.path.join(*path)
72 with open(path, 'wb' if binary else 'w') as fp:
73 fp.write(content)
74
75def read_file(path, binary=False):
76 """Return contents from a file located at *path*.
77
78 If *path* is a tuple instead of a string, os.path.join will be used to
79 make a path. If *binary* is true, the file will be opened in binary
80 mode.
81 """
82 if isinstance(path, tuple):
83 path = os.path.join(*path)
84 with open(path, 'rb' if binary else 'r') as fp:
85 return fp.read()
86
87
Barry Warsaw7fc2cca2003-01-24 17:34:13 +000088class TestShutil(unittest.TestCase):
Tarek Ziadé396fad72010-02-23 05:30:31 +000089
90 def setUp(self):
91 super(TestShutil, self).setUp()
92 self.tempdirs = []
93
94 def tearDown(self):
95 super(TestShutil, self).tearDown()
96 while self.tempdirs:
97 d = self.tempdirs.pop()
98 shutil.rmtree(d, os.name in ('nt', 'cygwin'))
99
Tarek Ziadé396fad72010-02-23 05:30:31 +0000100
101 def mkdtemp(self):
102 """Create a temporary directory that will be cleaned up.
103
104 Returns the path of the directory.
105 """
106 d = tempfile.mkdtemp()
107 self.tempdirs.append(d)
108 return d
Tarek Ziadé5340db32010-04-19 22:30:51 +0000109
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000110 def test_rmtree_errors(self):
111 # filename is guaranteed not to exist
112 filename = tempfile.mktemp()
113 self.assertRaises(OSError, shutil.rmtree, filename)
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000114
Johannes Gijsbersb8b09d02004-12-06 20:50:15 +0000115 # See bug #1071513 for why we don't run this on cygwin
116 # and bug #1076467 for why we don't run this as root.
117 if (hasattr(os, 'chmod') and sys.platform[:6] != 'cygwin'
Johannes Gijsbers6b220b02004-12-12 15:52:57 +0000118 and not (hasattr(os, 'geteuid') and os.geteuid() == 0)):
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000119 def test_on_error(self):
120 self.errorState = 0
121 os.mkdir(TESTFN)
Tim Peters4590c002004-11-01 02:40:52 +0000122 self.childpath = os.path.join(TESTFN, 'a')
Victor Stinnerbf816222011-06-30 23:25:47 +0200123 support.create_empty_file(self.childpath)
Tim Peters4590c002004-11-01 02:40:52 +0000124 old_dir_mode = os.stat(TESTFN).st_mode
125 old_child_mode = os.stat(self.childpath).st_mode
126 # Make unwritable.
127 os.chmod(self.childpath, stat.S_IREAD)
128 os.chmod(TESTFN, stat.S_IREAD)
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000129
130 shutil.rmtree(TESTFN, onerror=self.check_args_to_onerror)
Johannes Gijsbers8e6f2de2004-11-23 09:27:27 +0000131 # Test whether onerror has actually been called.
Johannes Gijsbersb8b09d02004-12-06 20:50:15 +0000132 self.assertEqual(self.errorState, 2,
133 "Expected call to onerror function did not happen.")
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000134
Tim Peters4590c002004-11-01 02:40:52 +0000135 # Make writable again.
136 os.chmod(TESTFN, old_dir_mode)
137 os.chmod(self.childpath, old_child_mode)
138
139 # Clean up.
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000140 shutil.rmtree(TESTFN)
141
142 def check_args_to_onerror(self, func, arg, exc):
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000143 # test_rmtree_errors deliberately runs rmtree
144 # on a directory that is chmod 400, which will fail.
145 # This function is run when shutil.rmtree fails.
146 # 99.9% of the time it initially fails to remove
147 # a file in the directory, so the first time through
148 # func is os.remove.
149 # However, some Linux machines running ZFS on
150 # FUSE experienced a failure earlier in the process
151 # at os.listdir. The first failure may legally
152 # be either.
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000153 if self.errorState == 0:
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000154 if func is os.remove:
155 self.assertEqual(arg, self.childpath)
156 else:
157 self.assertIs(func, os.listdir,
158 "func must be either os.remove or os.listdir")
159 self.assertEqual(arg, TESTFN)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000160 self.assertTrue(issubclass(exc[0], OSError))
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000161 self.errorState = 1
162 else:
163 self.assertEqual(func, os.rmdir)
164 self.assertEqual(arg, TESTFN)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000165 self.assertTrue(issubclass(exc[0], OSError))
Johannes Gijsbers8e6f2de2004-11-23 09:27:27 +0000166 self.errorState = 2
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000167
Antoine Pitrou78091e62011-12-29 18:54:15 +0100168 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
169 @support.skip_unless_symlink
170 def test_copymode_follow_symlinks(self):
171 tmp_dir = self.mkdtemp()
172 src = os.path.join(tmp_dir, 'foo')
173 dst = os.path.join(tmp_dir, 'bar')
174 src_link = os.path.join(tmp_dir, 'baz')
175 dst_link = os.path.join(tmp_dir, 'quux')
176 write_file(src, 'foo')
177 write_file(dst, 'foo')
178 os.symlink(src, src_link)
179 os.symlink(dst, dst_link)
180 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
181 # file to file
182 os.chmod(dst, stat.S_IRWXO)
183 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
184 shutil.copymode(src, dst)
185 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
186 # follow src link
187 os.chmod(dst, stat.S_IRWXO)
188 shutil.copymode(src_link, dst)
189 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
190 # follow dst link
191 os.chmod(dst, stat.S_IRWXO)
192 shutil.copymode(src, dst_link)
193 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
194 # follow both links
195 os.chmod(dst, stat.S_IRWXO)
196 shutil.copymode(src_link, dst)
197 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
198
199 @unittest.skipUnless(hasattr(os, 'lchmod'), 'requires os.lchmod')
200 @support.skip_unless_symlink
201 def test_copymode_symlink_to_symlink(self):
202 tmp_dir = self.mkdtemp()
203 src = os.path.join(tmp_dir, 'foo')
204 dst = os.path.join(tmp_dir, 'bar')
205 src_link = os.path.join(tmp_dir, 'baz')
206 dst_link = os.path.join(tmp_dir, 'quux')
207 write_file(src, 'foo')
208 write_file(dst, 'foo')
209 os.symlink(src, src_link)
210 os.symlink(dst, dst_link)
211 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
212 os.chmod(dst, stat.S_IRWXU)
213 os.lchmod(src_link, stat.S_IRWXO|stat.S_IRWXG)
214 # link to link
215 os.lchmod(dst_link, stat.S_IRWXO)
216 shutil.copymode(src_link, dst_link, symlinks=True)
217 self.assertEqual(os.lstat(src_link).st_mode,
218 os.lstat(dst_link).st_mode)
219 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
220 # src link - use chmod
221 os.lchmod(dst_link, stat.S_IRWXO)
222 shutil.copymode(src_link, dst, symlinks=True)
223 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
224 # dst link - use chmod
225 os.lchmod(dst_link, stat.S_IRWXO)
226 shutil.copymode(src, dst_link, symlinks=True)
227 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
228
229 @unittest.skipIf(hasattr(os, 'lchmod'), 'requires os.lchmod to be missing')
230 @support.skip_unless_symlink
231 def test_copymode_symlink_to_symlink_wo_lchmod(self):
232 tmp_dir = self.mkdtemp()
233 src = os.path.join(tmp_dir, 'foo')
234 dst = os.path.join(tmp_dir, 'bar')
235 src_link = os.path.join(tmp_dir, 'baz')
236 dst_link = os.path.join(tmp_dir, 'quux')
237 write_file(src, 'foo')
238 write_file(dst, 'foo')
239 os.symlink(src, src_link)
240 os.symlink(dst, dst_link)
241 shutil.copymode(src_link, dst_link, symlinks=True) # silent fail
242
243 @support.skip_unless_symlink
244 def test_copystat_symlinks(self):
245 tmp_dir = self.mkdtemp()
246 src = os.path.join(tmp_dir, 'foo')
247 dst = os.path.join(tmp_dir, 'bar')
248 src_link = os.path.join(tmp_dir, 'baz')
249 dst_link = os.path.join(tmp_dir, 'qux')
250 write_file(src, 'foo')
251 src_stat = os.stat(src)
252 os.utime(src, (src_stat.st_atime,
253 src_stat.st_mtime - 42.0)) # ensure different mtimes
254 write_file(dst, 'bar')
255 self.assertNotEqual(os.stat(src).st_mtime, os.stat(dst).st_mtime)
256 os.symlink(src, src_link)
257 os.symlink(dst, dst_link)
258 if hasattr(os, 'lchmod'):
259 os.lchmod(src_link, stat.S_IRWXO)
260 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
261 os.lchflags(src_link, stat.UF_NODUMP)
262 src_link_stat = os.lstat(src_link)
263 # follow
264 if hasattr(os, 'lchmod'):
265 shutil.copystat(src_link, dst_link, symlinks=False)
266 self.assertNotEqual(src_link_stat.st_mode, os.stat(dst).st_mode)
267 # don't follow
268 shutil.copystat(src_link, dst_link, symlinks=True)
269 dst_link_stat = os.lstat(dst_link)
270 if hasattr(os, 'lutimes'):
271 for attr in 'st_atime', 'st_mtime':
272 # The modification times may be truncated in the new file.
273 self.assertLessEqual(getattr(src_link_stat, attr),
274 getattr(dst_link_stat, attr) + 1)
275 if hasattr(os, 'lchmod'):
276 self.assertEqual(src_link_stat.st_mode, dst_link_stat.st_mode)
277 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
278 self.assertEqual(src_link_stat.st_flags, dst_link_stat.st_flags)
279 # tell to follow but dst is not a link
280 shutil.copystat(src_link, dst, symlinks=True)
281 self.assertTrue(abs(os.stat(src).st_mtime - os.stat(dst).st_mtime) <
282 00000.1)
283
284 @support.skip_unless_symlink
285 def test_copy_symlinks(self):
286 tmp_dir = self.mkdtemp()
287 src = os.path.join(tmp_dir, 'foo')
288 dst = os.path.join(tmp_dir, 'bar')
289 src_link = os.path.join(tmp_dir, 'baz')
290 write_file(src, 'foo')
291 os.symlink(src, src_link)
292 if hasattr(os, 'lchmod'):
293 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
294 # don't follow
295 shutil.copy(src_link, dst, symlinks=False)
296 self.assertFalse(os.path.islink(dst))
297 self.assertEqual(read_file(src), read_file(dst))
298 os.remove(dst)
299 # follow
300 shutil.copy(src_link, dst, symlinks=True)
301 self.assertTrue(os.path.islink(dst))
302 self.assertEqual(os.readlink(dst), os.readlink(src_link))
303 if hasattr(os, 'lchmod'):
304 self.assertEqual(os.lstat(src_link).st_mode,
305 os.lstat(dst).st_mode)
306
307 @support.skip_unless_symlink
308 def test_copy2_symlinks(self):
309 tmp_dir = self.mkdtemp()
310 src = os.path.join(tmp_dir, 'foo')
311 dst = os.path.join(tmp_dir, 'bar')
312 src_link = os.path.join(tmp_dir, 'baz')
313 write_file(src, 'foo')
314 os.symlink(src, src_link)
315 if hasattr(os, 'lchmod'):
316 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
317 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
318 os.lchflags(src_link, stat.UF_NODUMP)
319 src_stat = os.stat(src)
320 src_link_stat = os.lstat(src_link)
321 # follow
322 shutil.copy2(src_link, dst, symlinks=False)
323 self.assertFalse(os.path.islink(dst))
324 self.assertEqual(read_file(src), read_file(dst))
325 os.remove(dst)
326 # don't follow
327 shutil.copy2(src_link, dst, symlinks=True)
328 self.assertTrue(os.path.islink(dst))
329 self.assertEqual(os.readlink(dst), os.readlink(src_link))
330 dst_stat = os.lstat(dst)
331 if hasattr(os, 'lutimes'):
332 for attr in 'st_atime', 'st_mtime':
333 # The modification times may be truncated in the new file.
334 self.assertLessEqual(getattr(src_link_stat, attr),
335 getattr(dst_stat, attr) + 1)
336 if hasattr(os, 'lchmod'):
337 self.assertEqual(src_link_stat.st_mode, dst_stat.st_mode)
338 self.assertNotEqual(src_stat.st_mode, dst_stat.st_mode)
339 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
340 self.assertEqual(src_link_stat.st_flags, dst_stat.st_flags)
341
342 @support.skip_unless_symlink
343 def test_copyfile_symlinks(self):
344 tmp_dir = self.mkdtemp()
345 src = os.path.join(tmp_dir, 'src')
346 dst = os.path.join(tmp_dir, 'dst')
347 dst_link = os.path.join(tmp_dir, 'dst_link')
348 link = os.path.join(tmp_dir, 'link')
349 write_file(src, 'foo')
350 os.symlink(src, link)
351 # don't follow
352 shutil.copyfile(link, dst_link, symlinks=True)
353 self.assertTrue(os.path.islink(dst_link))
354 self.assertEqual(os.readlink(link), os.readlink(dst_link))
355 # follow
356 shutil.copyfile(link, dst)
357 self.assertFalse(os.path.islink(dst))
358
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000359 def test_rmtree_dont_delete_file(self):
360 # When called on a file instead of a directory, don't delete it.
361 handle, path = tempfile.mkstemp()
Victor Stinnerbf816222011-06-30 23:25:47 +0200362 os.close(handle)
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000363 self.assertRaises(OSError, shutil.rmtree, path)
364 os.remove(path)
365
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000366 def test_copytree_simple(self):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000367 src_dir = tempfile.mkdtemp()
368 dst_dir = os.path.join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200369 self.addCleanup(shutil.rmtree, src_dir)
370 self.addCleanup(shutil.rmtree, os.path.dirname(dst_dir))
371 write_file((src_dir, 'test.txt'), '123')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000372 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200373 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000374
Éric Araujoa7e33a12011-08-12 19:51:35 +0200375 shutil.copytree(src_dir, dst_dir)
376 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test.txt')))
377 self.assertTrue(os.path.isdir(os.path.join(dst_dir, 'test_dir')))
378 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test_dir',
379 'test.txt')))
380 actual = read_file((dst_dir, 'test.txt'))
381 self.assertEqual(actual, '123')
382 actual = read_file((dst_dir, 'test_dir', 'test.txt'))
383 self.assertEqual(actual, '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000384
Antoine Pitrou78091e62011-12-29 18:54:15 +0100385 @support.skip_unless_symlink
386 def test_copytree_symlinks(self):
387 tmp_dir = self.mkdtemp()
388 src_dir = os.path.join(tmp_dir, 'src')
389 dst_dir = os.path.join(tmp_dir, 'dst')
390 sub_dir = os.path.join(src_dir, 'sub')
391 os.mkdir(src_dir)
392 os.mkdir(sub_dir)
393 write_file((src_dir, 'file.txt'), 'foo')
394 src_link = os.path.join(sub_dir, 'link')
395 dst_link = os.path.join(dst_dir, 'sub/link')
396 os.symlink(os.path.join(src_dir, 'file.txt'),
397 src_link)
398 if hasattr(os, 'lchmod'):
399 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
400 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
401 os.lchflags(src_link, stat.UF_NODUMP)
402 src_stat = os.lstat(src_link)
403 shutil.copytree(src_dir, dst_dir, symlinks=True)
404 self.assertTrue(os.path.islink(os.path.join(dst_dir, 'sub', 'link')))
405 self.assertEqual(os.readlink(os.path.join(dst_dir, 'sub', 'link')),
406 os.path.join(src_dir, 'file.txt'))
407 dst_stat = os.lstat(dst_link)
408 if hasattr(os, 'lchmod'):
409 self.assertEqual(dst_stat.st_mode, src_stat.st_mode)
410 if hasattr(os, 'lchflags'):
411 self.assertEqual(dst_stat.st_flags, src_stat.st_flags)
412
Georg Brandl2ee470f2008-07-16 12:55:28 +0000413 def test_copytree_with_exclude(self):
Georg Brandl2ee470f2008-07-16 12:55:28 +0000414 # creating data
415 join = os.path.join
416 exists = os.path.exists
417 src_dir = tempfile.mkdtemp()
Georg Brandl2ee470f2008-07-16 12:55:28 +0000418 try:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000419 dst_dir = join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200420 write_file((src_dir, 'test.txt'), '123')
421 write_file((src_dir, 'test.tmp'), '123')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000422 os.mkdir(join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200423 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000424 os.mkdir(join(src_dir, 'test_dir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200425 write_file((src_dir, 'test_dir2', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000426 os.mkdir(join(src_dir, 'test_dir2', 'subdir'))
427 os.mkdir(join(src_dir, 'test_dir2', 'subdir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200428 write_file((src_dir, 'test_dir2', 'subdir', 'test.txt'), '456')
429 write_file((src_dir, 'test_dir2', 'subdir2', 'test.py'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000430
431 # testing glob-like patterns
432 try:
433 patterns = shutil.ignore_patterns('*.tmp', 'test_dir2')
434 shutil.copytree(src_dir, dst_dir, ignore=patterns)
435 # checking the result: some elements should not be copied
436 self.assertTrue(exists(join(dst_dir, 'test.txt')))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200437 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
438 self.assertFalse(exists(join(dst_dir, 'test_dir2')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000439 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200440 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000441 try:
442 patterns = shutil.ignore_patterns('*.tmp', 'subdir*')
443 shutil.copytree(src_dir, dst_dir, ignore=patterns)
444 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200445 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
446 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2')))
447 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000448 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200449 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000450
451 # testing callable-style
452 try:
453 def _filter(src, names):
454 res = []
455 for name in names:
456 path = os.path.join(src, name)
457
458 if (os.path.isdir(path) and
459 path.split()[-1] == 'subdir'):
460 res.append(name)
461 elif os.path.splitext(path)[-1] in ('.py'):
462 res.append(name)
463 return res
464
465 shutil.copytree(src_dir, dst_dir, ignore=_filter)
466
467 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200468 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2',
469 'test.py')))
470 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000471
472 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200473 shutil.rmtree(dst_dir)
Georg Brandl2ee470f2008-07-16 12:55:28 +0000474 finally:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000475 shutil.rmtree(src_dir)
476 shutil.rmtree(os.path.dirname(dst_dir))
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000477
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000478 @unittest.skipUnless(hasattr(os, 'link'), 'requires os.link')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000479 def test_dont_copy_file_onto_link_to_itself(self):
Georg Brandl724d0892010-12-05 07:51:39 +0000480 # Temporarily disable test on Windows.
481 if os.name == 'nt':
482 return
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000483 # bug 851123.
484 os.mkdir(TESTFN)
485 src = os.path.join(TESTFN, 'cheese')
486 dst = os.path.join(TESTFN, 'shop')
487 try:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000488 with open(src, 'w') as f:
489 f.write('cheddar')
490 os.link(src, dst)
491 self.assertRaises(shutil.Error, shutil.copyfile, src, dst)
492 with open(src, 'r') as f:
493 self.assertEqual(f.read(), 'cheddar')
494 os.remove(dst)
495 finally:
496 shutil.rmtree(TESTFN, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000497
Brian Curtin3b4499c2010-12-28 14:31:47 +0000498 @support.skip_unless_symlink
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000499 def test_dont_copy_file_onto_symlink_to_itself(self):
500 # bug 851123.
501 os.mkdir(TESTFN)
502 src = os.path.join(TESTFN, 'cheese')
503 dst = os.path.join(TESTFN, 'shop')
504 try:
505 with open(src, 'w') as f:
506 f.write('cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000507 # Using `src` here would mean we end up with a symlink pointing
508 # to TESTFN/TESTFN/cheese, while it should point at
509 # TESTFN/cheese.
510 os.symlink('cheese', dst)
511 self.assertRaises(shutil.Error, shutil.copyfile, src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +0000512 with open(src, 'r') as f:
513 self.assertEqual(f.read(), 'cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000514 os.remove(dst)
515 finally:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000516 shutil.rmtree(TESTFN, ignore_errors=True)
Johannes Gijsbers68128712004-08-14 13:57:08 +0000517
Brian Curtin3b4499c2010-12-28 14:31:47 +0000518 @support.skip_unless_symlink
Brian Curtind40e6f72010-07-08 21:39:08 +0000519 def test_rmtree_on_symlink(self):
520 # bug 1669.
521 os.mkdir(TESTFN)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000522 try:
Brian Curtind40e6f72010-07-08 21:39:08 +0000523 src = os.path.join(TESTFN, 'cheese')
524 dst = os.path.join(TESTFN, 'shop')
525 os.mkdir(src)
526 os.symlink(src, dst)
527 self.assertRaises(OSError, shutil.rmtree, dst)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000528 finally:
Brian Curtind40e6f72010-07-08 21:39:08 +0000529 shutil.rmtree(TESTFN, ignore_errors=True)
530
531 if hasattr(os, "mkfifo"):
532 # Issue #3002: copyfile and copytree block indefinitely on named pipes
533 def test_copyfile_named_pipe(self):
534 os.mkfifo(TESTFN)
535 try:
536 self.assertRaises(shutil.SpecialFileError,
537 shutil.copyfile, TESTFN, TESTFN2)
538 self.assertRaises(shutil.SpecialFileError,
539 shutil.copyfile, __file__, TESTFN)
540 finally:
541 os.remove(TESTFN)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000542
Brian Curtin3b4499c2010-12-28 14:31:47 +0000543 @support.skip_unless_symlink
Brian Curtin52173d42010-12-02 18:29:18 +0000544 def test_copytree_named_pipe(self):
545 os.mkdir(TESTFN)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000546 try:
Brian Curtin52173d42010-12-02 18:29:18 +0000547 subdir = os.path.join(TESTFN, "subdir")
548 os.mkdir(subdir)
549 pipe = os.path.join(subdir, "mypipe")
550 os.mkfifo(pipe)
551 try:
552 shutil.copytree(TESTFN, TESTFN2)
553 except shutil.Error as e:
554 errors = e.args[0]
555 self.assertEqual(len(errors), 1)
556 src, dst, error_msg = errors[0]
557 self.assertEqual("`%s` is a named pipe" % pipe, error_msg)
558 else:
559 self.fail("shutil.Error should have been raised")
560 finally:
561 shutil.rmtree(TESTFN, ignore_errors=True)
562 shutil.rmtree(TESTFN2, ignore_errors=True)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000563
Tarek Ziadé5340db32010-04-19 22:30:51 +0000564 def test_copytree_special_func(self):
565
566 src_dir = self.mkdtemp()
567 dst_dir = os.path.join(self.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200568 write_file((src_dir, 'test.txt'), '123')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000569 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200570 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000571
572 copied = []
573 def _copy(src, dst):
574 copied.append((src, dst))
575
576 shutil.copytree(src_dir, dst_dir, copy_function=_copy)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000577 self.assertEqual(len(copied), 2)
Tarek Ziadé5340db32010-04-19 22:30:51 +0000578
Brian Curtin3b4499c2010-12-28 14:31:47 +0000579 @support.skip_unless_symlink
Tarek Ziadéfb437512010-04-20 08:57:33 +0000580 def test_copytree_dangling_symlinks(self):
581
582 # a dangling symlink raises an error at the end
583 src_dir = self.mkdtemp()
584 dst_dir = os.path.join(self.mkdtemp(), 'destination')
585 os.symlink('IDONTEXIST', os.path.join(src_dir, 'test.txt'))
586 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200587 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadéfb437512010-04-20 08:57:33 +0000588 self.assertRaises(Error, shutil.copytree, src_dir, dst_dir)
589
590 # a dangling symlink is ignored with the proper flag
591 dst_dir = os.path.join(self.mkdtemp(), 'destination2')
592 shutil.copytree(src_dir, dst_dir, ignore_dangling_symlinks=True)
593 self.assertNotIn('test.txt', os.listdir(dst_dir))
594
595 # a dangling symlink is copied if symlinks=True
596 dst_dir = os.path.join(self.mkdtemp(), 'destination3')
597 shutil.copytree(src_dir, dst_dir, symlinks=True)
598 self.assertIn('test.txt', os.listdir(dst_dir))
599
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400600 def _copy_file(self, method):
601 fname = 'test.txt'
602 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200603 write_file((tmpdir, fname), 'xxx')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400604 file1 = os.path.join(tmpdir, fname)
605 tmpdir2 = self.mkdtemp()
606 method(file1, tmpdir2)
607 file2 = os.path.join(tmpdir2, fname)
608 return (file1, file2)
609
610 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
611 def test_copy(self):
612 # Ensure that the copied file exists and has the same mode bits.
613 file1, file2 = self._copy_file(shutil.copy)
614 self.assertTrue(os.path.exists(file2))
615 self.assertEqual(os.stat(file1).st_mode, os.stat(file2).st_mode)
616
617 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
Senthil Kumaran0c2dba52011-07-03 18:21:38 -0700618 @unittest.skipUnless(hasattr(os, 'utime'), 'requires os.utime')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400619 def test_copy2(self):
620 # Ensure that the copied file exists and has the same mode and
621 # modification time bits.
622 file1, file2 = self._copy_file(shutil.copy2)
623 self.assertTrue(os.path.exists(file2))
624 file1_stat = os.stat(file1)
625 file2_stat = os.stat(file2)
626 self.assertEqual(file1_stat.st_mode, file2_stat.st_mode)
627 for attr in 'st_atime', 'st_mtime':
628 # The modification times may be truncated in the new file.
629 self.assertLessEqual(getattr(file1_stat, attr),
630 getattr(file2_stat, attr) + 1)
631 if hasattr(os, 'chflags') and hasattr(file1_stat, 'st_flags'):
632 self.assertEqual(getattr(file1_stat, 'st_flags'),
633 getattr(file2_stat, 'st_flags'))
634
Ezio Melotti975077a2011-05-19 22:03:22 +0300635 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000636 def test_make_tarball(self):
637 # creating something to tar
638 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200639 write_file((tmpdir, 'file1'), 'xxx')
640 write_file((tmpdir, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000641 os.mkdir(os.path.join(tmpdir, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200642 write_file((tmpdir, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000643
644 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400645 # force shutil to create the directory
646 os.rmdir(tmpdir2)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000647 unittest.skipUnless(splitdrive(tmpdir)[0] == splitdrive(tmpdir2)[0],
648 "source and target should be on same drive")
649
650 base_name = os.path.join(tmpdir2, 'archive')
651
652 # working with relative paths to avoid tar warnings
653 old_dir = os.getcwd()
654 os.chdir(tmpdir)
655 try:
656 _make_tarball(splitdrive(base_name)[1], '.')
657 finally:
658 os.chdir(old_dir)
659
660 # check if the compressed tarball was created
661 tarball = base_name + '.tar.gz'
662 self.assertTrue(os.path.exists(tarball))
663
664 # trying an uncompressed one
665 base_name = os.path.join(tmpdir2, 'archive')
666 old_dir = os.getcwd()
667 os.chdir(tmpdir)
668 try:
669 _make_tarball(splitdrive(base_name)[1], '.', compress=None)
670 finally:
671 os.chdir(old_dir)
672 tarball = base_name + '.tar'
673 self.assertTrue(os.path.exists(tarball))
674
675 def _tarinfo(self, path):
676 tar = tarfile.open(path)
677 try:
678 names = tar.getnames()
679 names.sort()
680 return tuple(names)
681 finally:
682 tar.close()
683
684 def _create_files(self):
685 # creating something to tar
686 tmpdir = self.mkdtemp()
687 dist = os.path.join(tmpdir, 'dist')
688 os.mkdir(dist)
Éric Araujoa7e33a12011-08-12 19:51:35 +0200689 write_file((dist, 'file1'), 'xxx')
690 write_file((dist, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000691 os.mkdir(os.path.join(dist, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200692 write_file((dist, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000693 os.mkdir(os.path.join(dist, 'sub2'))
694 tmpdir2 = self.mkdtemp()
695 base_name = os.path.join(tmpdir2, 'archive')
696 return tmpdir, tmpdir2, base_name
697
Ezio Melotti975077a2011-05-19 22:03:22 +0300698 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000699 @unittest.skipUnless(find_executable('tar') and find_executable('gzip'),
700 'Need the tar command to run')
701 def test_tarfile_vs_tar(self):
702 tmpdir, tmpdir2, base_name = self._create_files()
703 old_dir = os.getcwd()
704 os.chdir(tmpdir)
705 try:
706 _make_tarball(base_name, 'dist')
707 finally:
708 os.chdir(old_dir)
709
710 # check if the compressed tarball was created
711 tarball = base_name + '.tar.gz'
712 self.assertTrue(os.path.exists(tarball))
713
714 # now create another tarball using `tar`
715 tarball2 = os.path.join(tmpdir, 'archive2.tar.gz')
716 tar_cmd = ['tar', '-cf', 'archive2.tar', 'dist']
717 gzip_cmd = ['gzip', '-f9', 'archive2.tar']
718 old_dir = os.getcwd()
719 os.chdir(tmpdir)
720 try:
721 with captured_stdout() as s:
722 spawn(tar_cmd)
723 spawn(gzip_cmd)
724 finally:
725 os.chdir(old_dir)
726
727 self.assertTrue(os.path.exists(tarball2))
728 # let's compare both tarballs
Ezio Melottib3aedd42010-11-20 19:04:17 +0000729 self.assertEqual(self._tarinfo(tarball), self._tarinfo(tarball2))
Tarek Ziadé396fad72010-02-23 05:30:31 +0000730
731 # trying an uncompressed one
732 base_name = os.path.join(tmpdir2, 'archive')
733 old_dir = os.getcwd()
734 os.chdir(tmpdir)
735 try:
736 _make_tarball(base_name, 'dist', compress=None)
737 finally:
738 os.chdir(old_dir)
739 tarball = base_name + '.tar'
740 self.assertTrue(os.path.exists(tarball))
741
742 # now for a dry_run
743 base_name = os.path.join(tmpdir2, 'archive')
744 old_dir = os.getcwd()
745 os.chdir(tmpdir)
746 try:
747 _make_tarball(base_name, 'dist', compress=None, dry_run=True)
748 finally:
749 os.chdir(old_dir)
750 tarball = base_name + '.tar'
751 self.assertTrue(os.path.exists(tarball))
752
Ezio Melotti975077a2011-05-19 22:03:22 +0300753 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000754 @unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run')
755 def test_make_zipfile(self):
756 # creating something to tar
757 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200758 write_file((tmpdir, 'file1'), 'xxx')
759 write_file((tmpdir, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000760
761 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400762 # force shutil to create the directory
763 os.rmdir(tmpdir2)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000764 base_name = os.path.join(tmpdir2, 'archive')
765 _make_zipfile(base_name, tmpdir)
766
767 # check if the compressed tarball was created
768 tarball = base_name + '.zip'
Éric Araujo1c505492010-11-06 02:12:51 +0000769 self.assertTrue(os.path.exists(tarball))
Tarek Ziadé396fad72010-02-23 05:30:31 +0000770
771
772 def test_make_archive(self):
773 tmpdir = self.mkdtemp()
774 base_name = os.path.join(tmpdir, 'archive')
775 self.assertRaises(ValueError, make_archive, base_name, 'xxx')
776
Ezio Melotti975077a2011-05-19 22:03:22 +0300777 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000778 def test_make_archive_owner_group(self):
779 # testing make_archive with owner and group, with various combinations
780 # this works even if there's not gid/uid support
781 if UID_GID_SUPPORT:
782 group = grp.getgrgid(0)[0]
783 owner = pwd.getpwuid(0)[0]
784 else:
785 group = owner = 'root'
786
787 base_dir, root_dir, base_name = self._create_files()
788 base_name = os.path.join(self.mkdtemp() , 'archive')
789 res = make_archive(base_name, 'zip', root_dir, base_dir, owner=owner,
790 group=group)
791 self.assertTrue(os.path.exists(res))
792
793 res = make_archive(base_name, 'zip', root_dir, base_dir)
794 self.assertTrue(os.path.exists(res))
795
796 res = make_archive(base_name, 'tar', root_dir, base_dir,
797 owner=owner, group=group)
798 self.assertTrue(os.path.exists(res))
799
800 res = make_archive(base_name, 'tar', root_dir, base_dir,
801 owner='kjhkjhkjg', group='oihohoh')
802 self.assertTrue(os.path.exists(res))
803
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000804
Ezio Melotti975077a2011-05-19 22:03:22 +0300805 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000806 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
807 def test_tarfile_root_owner(self):
808 tmpdir, tmpdir2, base_name = self._create_files()
809 old_dir = os.getcwd()
810 os.chdir(tmpdir)
811 group = grp.getgrgid(0)[0]
812 owner = pwd.getpwuid(0)[0]
813 try:
814 archive_name = _make_tarball(base_name, 'dist', compress=None,
815 owner=owner, group=group)
816 finally:
817 os.chdir(old_dir)
818
819 # check if the compressed tarball was created
820 self.assertTrue(os.path.exists(archive_name))
821
822 # now checks the rights
823 archive = tarfile.open(archive_name)
824 try:
825 for member in archive.getmembers():
Ezio Melottib3aedd42010-11-20 19:04:17 +0000826 self.assertEqual(member.uid, 0)
827 self.assertEqual(member.gid, 0)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000828 finally:
829 archive.close()
830
831 def test_make_archive_cwd(self):
832 current_dir = os.getcwd()
833 def _breaks(*args, **kw):
834 raise RuntimeError()
835
836 register_archive_format('xxx', _breaks, [], 'xxx file')
837 try:
838 try:
839 make_archive('xxx', 'xxx', root_dir=self.mkdtemp())
840 except Exception:
841 pass
Ezio Melottib3aedd42010-11-20 19:04:17 +0000842 self.assertEqual(os.getcwd(), current_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000843 finally:
844 unregister_archive_format('xxx')
845
846 def test_register_archive_format(self):
847
848 self.assertRaises(TypeError, register_archive_format, 'xxx', 1)
849 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
850 1)
851 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
852 [(1, 2), (1, 2, 3)])
853
854 register_archive_format('xxx', lambda: x, [(1, 2)], 'xxx file')
855 formats = [name for name, params in get_archive_formats()]
856 self.assertIn('xxx', formats)
857
858 unregister_archive_format('xxx')
859 formats = [name for name, params in get_archive_formats()]
860 self.assertNotIn('xxx', formats)
861
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000862 def _compare_dirs(self, dir1, dir2):
863 # check that dir1 and dir2 are equivalent,
864 # return the diff
865 diff = []
866 for root, dirs, files in os.walk(dir1):
867 for file_ in files:
868 path = os.path.join(root, file_)
869 target_path = os.path.join(dir2, os.path.split(path)[-1])
870 if not os.path.exists(target_path):
871 diff.append(file_)
872 return diff
873
Ezio Melotti975077a2011-05-19 22:03:22 +0300874 @requires_zlib
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000875 def test_unpack_archive(self):
Tarek Ziadéffa155a2010-04-29 13:34:35 +0000876 formats = ['tar', 'gztar', 'zip']
877 if BZ2_SUPPORTED:
878 formats.append('bztar')
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000879
Tarek Ziadéffa155a2010-04-29 13:34:35 +0000880 for format in formats:
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000881 tmpdir = self.mkdtemp()
882 base_dir, root_dir, base_name = self._create_files()
883 tmpdir2 = self.mkdtemp()
884 filename = make_archive(base_name, format, root_dir, base_dir)
885
886 # let's try to unpack it now
887 unpack_archive(filename, tmpdir2)
888 diff = self._compare_dirs(tmpdir, tmpdir2)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000889 self.assertEqual(diff, [])
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000890
Nick Coghlanabf202d2011-03-16 13:52:20 -0400891 # and again, this time with the format specified
892 tmpdir3 = self.mkdtemp()
893 unpack_archive(filename, tmpdir3, format=format)
894 diff = self._compare_dirs(tmpdir, tmpdir3)
895 self.assertEqual(diff, [])
896 self.assertRaises(shutil.ReadError, unpack_archive, TESTFN)
897 self.assertRaises(ValueError, unpack_archive, TESTFN, format='xxx')
898
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000899 def test_unpack_registery(self):
900
901 formats = get_unpack_formats()
902
903 def _boo(filename, extract_dir, extra):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000904 self.assertEqual(extra, 1)
905 self.assertEqual(filename, 'stuff.boo')
906 self.assertEqual(extract_dir, 'xx')
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000907
908 register_unpack_format('Boo', ['.boo', '.b2'], _boo, [('extra', 1)])
909 unpack_archive('stuff.boo', 'xx')
910
911 # trying to register a .boo unpacker again
912 self.assertRaises(RegistryError, register_unpack_format, 'Boo2',
913 ['.boo'], _boo)
914
915 # should work now
916 unregister_unpack_format('Boo')
917 register_unpack_format('Boo2', ['.boo'], _boo)
918 self.assertIn(('Boo2', ['.boo'], ''), get_unpack_formats())
919 self.assertNotIn(('Boo', ['.boo'], ''), get_unpack_formats())
920
921 # let's leave a clean state
922 unregister_unpack_format('Boo2')
Ezio Melottib3aedd42010-11-20 19:04:17 +0000923 self.assertEqual(get_unpack_formats(), formats)
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000924
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +0200925 @unittest.skipUnless(hasattr(shutil, 'disk_usage'),
926 "disk_usage not available on this platform")
927 def test_disk_usage(self):
928 usage = shutil.disk_usage(os.getcwd())
Éric Araujo2ee61882011-07-02 16:45:45 +0200929 self.assertGreater(usage.total, 0)
930 self.assertGreater(usage.used, 0)
931 self.assertGreaterEqual(usage.free, 0)
932 self.assertGreaterEqual(usage.total, usage.used)
933 self.assertGreater(usage.total, usage.free)
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +0200934
Sandro Tosid902a142011-08-22 23:28:27 +0200935 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
936 @unittest.skipUnless(hasattr(os, 'chown'), 'requires os.chown')
937 def test_chown(self):
938
939 # cleaned-up automatically by TestShutil.tearDown method
940 dirname = self.mkdtemp()
941 filename = tempfile.mktemp(dir=dirname)
942 write_file(filename, 'testing chown function')
943
944 with self.assertRaises(ValueError):
945 shutil.chown(filename)
946
947 with self.assertRaises(LookupError):
948 shutil.chown(filename, user='non-exising username')
949
950 with self.assertRaises(LookupError):
951 shutil.chown(filename, group='non-exising groupname')
952
953 with self.assertRaises(TypeError):
954 shutil.chown(filename, b'spam')
955
956 with self.assertRaises(TypeError):
957 shutil.chown(filename, 3.14)
958
959 uid = os.getuid()
960 gid = os.getgid()
961
962 def check_chown(path, uid=None, gid=None):
963 s = os.stat(filename)
964 if uid is not None:
965 self.assertEqual(uid, s.st_uid)
966 if gid is not None:
967 self.assertEqual(gid, s.st_gid)
968
969 shutil.chown(filename, uid, gid)
970 check_chown(filename, uid, gid)
971 shutil.chown(filename, uid)
972 check_chown(filename, uid)
973 shutil.chown(filename, user=uid)
974 check_chown(filename, uid)
975 shutil.chown(filename, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +0200976 check_chown(filename, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +0200977
978 shutil.chown(dirname, uid, gid)
979 check_chown(dirname, uid, gid)
980 shutil.chown(dirname, uid)
981 check_chown(dirname, uid)
982 shutil.chown(dirname, user=uid)
983 check_chown(dirname, uid)
984 shutil.chown(dirname, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +0200985 check_chown(dirname, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +0200986
987 user = pwd.getpwuid(uid)[0]
988 group = grp.getgrgid(gid)[0]
989 shutil.chown(filename, user, group)
990 check_chown(filename, uid, gid)
991 shutil.chown(dirname, user, group)
992 check_chown(dirname, uid, gid)
993
Christian Heimes9bd667a2008-01-20 15:14:11 +0000994
Christian Heimesada8c3b2008-03-18 18:26:33 +0000995class TestMove(unittest.TestCase):
996
997 def setUp(self):
998 filename = "foo"
999 self.src_dir = tempfile.mkdtemp()
1000 self.dst_dir = tempfile.mkdtemp()
1001 self.src_file = os.path.join(self.src_dir, filename)
1002 self.dst_file = os.path.join(self.dst_dir, filename)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001003 with open(self.src_file, "wb") as f:
1004 f.write(b"spam")
1005
1006 def tearDown(self):
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001007 for d in (self.src_dir, self.dst_dir):
Christian Heimesada8c3b2008-03-18 18:26:33 +00001008 try:
1009 if d:
1010 shutil.rmtree(d)
1011 except:
1012 pass
1013
1014 def _check_move_file(self, src, dst, real_dst):
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001015 with open(src, "rb") as f:
1016 contents = f.read()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001017 shutil.move(src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001018 with open(real_dst, "rb") as f:
1019 self.assertEqual(contents, f.read())
Christian Heimesada8c3b2008-03-18 18:26:33 +00001020 self.assertFalse(os.path.exists(src))
1021
1022 def _check_move_dir(self, src, dst, real_dst):
1023 contents = sorted(os.listdir(src))
1024 shutil.move(src, dst)
1025 self.assertEqual(contents, sorted(os.listdir(real_dst)))
1026 self.assertFalse(os.path.exists(src))
1027
1028 def test_move_file(self):
1029 # Move a file to another location on the same filesystem.
1030 self._check_move_file(self.src_file, self.dst_file, self.dst_file)
1031
1032 def test_move_file_to_dir(self):
1033 # Move a file inside an existing dir on the same filesystem.
1034 self._check_move_file(self.src_file, self.dst_dir, self.dst_file)
1035
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001036 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001037 def test_move_file_other_fs(self):
1038 # Move a file to an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001039 self.test_move_file()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001040
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001041 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001042 def test_move_file_to_dir_other_fs(self):
1043 # Move a file to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001044 self.test_move_file_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001045
1046 def test_move_dir(self):
1047 # Move a dir to another location on the same filesystem.
1048 dst_dir = tempfile.mktemp()
1049 try:
1050 self._check_move_dir(self.src_dir, dst_dir, dst_dir)
1051 finally:
1052 try:
1053 shutil.rmtree(dst_dir)
1054 except:
1055 pass
1056
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001057 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001058 def test_move_dir_other_fs(self):
1059 # Move a dir to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001060 self.test_move_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001061
1062 def test_move_dir_to_dir(self):
1063 # Move a dir inside an existing dir on the same filesystem.
1064 self._check_move_dir(self.src_dir, self.dst_dir,
1065 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1066
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001067 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001068 def test_move_dir_to_dir_other_fs(self):
1069 # Move a dir inside an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001070 self.test_move_dir_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001071
1072 def test_existing_file_inside_dest_dir(self):
1073 # A file with the same name inside the destination dir already exists.
1074 with open(self.dst_file, "wb"):
1075 pass
1076 self.assertRaises(shutil.Error, shutil.move, self.src_file, self.dst_dir)
1077
1078 def test_dont_move_dir_in_itself(self):
1079 # Moving a dir inside itself raises an Error.
1080 dst = os.path.join(self.src_dir, "bar")
1081 self.assertRaises(shutil.Error, shutil.move, self.src_dir, dst)
1082
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001083 def test_destinsrc_false_negative(self):
1084 os.mkdir(TESTFN)
1085 try:
1086 for src, dst in [('srcdir', 'srcdir/dest')]:
1087 src = os.path.join(TESTFN, src)
1088 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001089 self.assertTrue(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001090 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001091 'dst (%s) is not in src (%s)' % (dst, src))
1092 finally:
1093 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001094
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001095 def test_destinsrc_false_positive(self):
1096 os.mkdir(TESTFN)
1097 try:
1098 for src, dst in [('srcdir', 'src/dest'), ('srcdir', 'srcdir.new')]:
1099 src = os.path.join(TESTFN, src)
1100 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001101 self.assertFalse(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001102 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001103 'dst (%s) is in src (%s)' % (dst, src))
1104 finally:
1105 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimes9bd667a2008-01-20 15:14:11 +00001106
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +01001107 @support.skip_unless_symlink
1108 @mock_rename
1109 def test_move_file_symlink(self):
1110 dst = os.path.join(self.src_dir, 'bar')
1111 os.symlink(self.src_file, dst)
1112 shutil.move(dst, self.dst_file)
1113 self.assertTrue(os.path.islink(self.dst_file))
1114 self.assertTrue(os.path.samefile(self.src_file, self.dst_file))
1115
1116 @support.skip_unless_symlink
1117 @mock_rename
1118 def test_move_file_symlink_to_dir(self):
1119 filename = "bar"
1120 dst = os.path.join(self.src_dir, filename)
1121 os.symlink(self.src_file, dst)
1122 shutil.move(dst, self.dst_dir)
1123 final_link = os.path.join(self.dst_dir, filename)
1124 self.assertTrue(os.path.islink(final_link))
1125 self.assertTrue(os.path.samefile(self.src_file, final_link))
1126
1127 @support.skip_unless_symlink
1128 @mock_rename
1129 def test_move_dangling_symlink(self):
1130 src = os.path.join(self.src_dir, 'baz')
1131 dst = os.path.join(self.src_dir, 'bar')
1132 os.symlink(src, dst)
1133 dst_link = os.path.join(self.dst_dir, 'quux')
1134 shutil.move(dst, dst_link)
1135 self.assertTrue(os.path.islink(dst_link))
1136 self.assertEqual(os.path.realpath(src), os.path.realpath(dst_link))
1137
1138 @support.skip_unless_symlink
1139 @mock_rename
1140 def test_move_dir_symlink(self):
1141 src = os.path.join(self.src_dir, 'baz')
1142 dst = os.path.join(self.src_dir, 'bar')
1143 os.mkdir(src)
1144 os.symlink(src, dst)
1145 dst_link = os.path.join(self.dst_dir, 'quux')
1146 shutil.move(dst, dst_link)
1147 self.assertTrue(os.path.islink(dst_link))
1148 self.assertTrue(os.path.samefile(src, dst_link))
1149
Tarek Ziadé5340db32010-04-19 22:30:51 +00001150
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001151class TestCopyFile(unittest.TestCase):
1152
1153 _delete = False
1154
1155 class Faux(object):
1156 _entered = False
1157 _exited_with = None
1158 _raised = False
1159 def __init__(self, raise_in_exit=False, suppress_at_exit=True):
1160 self._raise_in_exit = raise_in_exit
1161 self._suppress_at_exit = suppress_at_exit
1162 def read(self, *args):
1163 return ''
1164 def __enter__(self):
1165 self._entered = True
1166 def __exit__(self, exc_type, exc_val, exc_tb):
1167 self._exited_with = exc_type, exc_val, exc_tb
1168 if self._raise_in_exit:
1169 self._raised = True
1170 raise IOError("Cannot close")
1171 return self._suppress_at_exit
1172
1173 def tearDown(self):
1174 if self._delete:
1175 del shutil.open
1176
1177 def _set_shutil_open(self, func):
1178 shutil.open = func
1179 self._delete = True
1180
1181 def test_w_source_open_fails(self):
1182 def _open(filename, mode='r'):
1183 if filename == 'srcfile':
1184 raise IOError('Cannot open "srcfile"')
1185 assert 0 # shouldn't reach here.
1186
1187 self._set_shutil_open(_open)
1188
1189 self.assertRaises(IOError, shutil.copyfile, 'srcfile', 'destfile')
1190
1191 def test_w_dest_open_fails(self):
1192
1193 srcfile = self.Faux()
1194
1195 def _open(filename, mode='r'):
1196 if filename == 'srcfile':
1197 return srcfile
1198 if filename == 'destfile':
1199 raise IOError('Cannot open "destfile"')
1200 assert 0 # shouldn't reach here.
1201
1202 self._set_shutil_open(_open)
1203
1204 shutil.copyfile('srcfile', 'destfile')
1205 self.assertTrue(srcfile._entered)
1206 self.assertTrue(srcfile._exited_with[0] is IOError)
1207 self.assertEqual(srcfile._exited_with[1].args,
1208 ('Cannot open "destfile"',))
1209
1210 def test_w_dest_close_fails(self):
1211
1212 srcfile = self.Faux()
1213 destfile = self.Faux(True)
1214
1215 def _open(filename, mode='r'):
1216 if filename == 'srcfile':
1217 return srcfile
1218 if filename == 'destfile':
1219 return destfile
1220 assert 0 # shouldn't reach here.
1221
1222 self._set_shutil_open(_open)
1223
1224 shutil.copyfile('srcfile', 'destfile')
1225 self.assertTrue(srcfile._entered)
1226 self.assertTrue(destfile._entered)
1227 self.assertTrue(destfile._raised)
1228 self.assertTrue(srcfile._exited_with[0] is IOError)
1229 self.assertEqual(srcfile._exited_with[1].args,
1230 ('Cannot close',))
1231
1232 def test_w_source_close_fails(self):
1233
1234 srcfile = self.Faux(True)
1235 destfile = self.Faux()
1236
1237 def _open(filename, mode='r'):
1238 if filename == 'srcfile':
1239 return srcfile
1240 if filename == 'destfile':
1241 return destfile
1242 assert 0 # shouldn't reach here.
1243
1244 self._set_shutil_open(_open)
1245
1246 self.assertRaises(IOError,
1247 shutil.copyfile, 'srcfile', 'destfile')
1248 self.assertTrue(srcfile._entered)
1249 self.assertTrue(destfile._entered)
1250 self.assertFalse(destfile._raised)
1251 self.assertTrue(srcfile._exited_with[0] is None)
1252 self.assertTrue(srcfile._raised)
1253
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001254 def test_move_dir_caseinsensitive(self):
1255 # Renames a folder to the same name
1256 # but a different case.
1257
1258 self.src_dir = tempfile.mkdtemp()
1259 dst_dir = os.path.join(
1260 os.path.dirname(self.src_dir),
1261 os.path.basename(self.src_dir).upper())
1262 self.assertNotEqual(self.src_dir, dst_dir)
1263
1264 try:
1265 shutil.move(self.src_dir, dst_dir)
1266 self.assertTrue(os.path.isdir(dst_dir))
1267 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +02001268 os.rmdir(dst_dir)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001269
1270
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001271
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001272def test_main():
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001273 support.run_unittest(TestShutil, TestMove, TestCopyFile)
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001274
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001275if __name__ == '__main__':
Walter Dörwald21d3a322003-05-01 17:45:56 +00001276 test_main()