blob: a2002369aa2925bb710fb105d0d3fd0c6f2ec899 [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
Nick Coghlan8ed3cf32011-03-16 14:05:35 -040010import functools
Benjamin Petersonee8712c2008-05-20 21:35:26 +000011from test import support
12from test.support import TESTFN
Tarek Ziadé396fad72010-02-23 05:30:31 +000013from os.path import splitdrive
14from distutils.spawn import find_executable, spawn
15from shutil import (_make_tarball, _make_zipfile, make_archive,
16 register_archive_format, unregister_archive_format,
Tarek Ziadé6ac91722010-04-28 17:51:36 +000017 get_archive_formats, Error, unpack_archive,
18 register_unpack_format, RegistryError,
19 unregister_unpack_format, get_unpack_formats)
Tarek Ziadé396fad72010-02-23 05:30:31 +000020import tarfile
21import warnings
22
23from test import support
Ezio Melotti975077a2011-05-19 22:03:22 +030024from test.support import TESTFN, check_warnings, captured_stdout, requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +000025
Tarek Ziadéffa155a2010-04-29 13:34:35 +000026try:
27 import bz2
28 BZ2_SUPPORTED = True
29except ImportError:
30 BZ2_SUPPORTED = False
31
Antoine Pitrou7fff0962009-05-01 21:09:44 +000032TESTFN2 = TESTFN + "2"
Barry Warsaw7fc2cca2003-01-24 17:34:13 +000033
Tarek Ziadé396fad72010-02-23 05:30:31 +000034try:
35 import grp
36 import pwd
37 UID_GID_SUPPORT = True
38except ImportError:
39 UID_GID_SUPPORT = False
40
41try:
Tarek Ziadé396fad72010-02-23 05:30:31 +000042 import zipfile
43 ZIP_SUPPORT = True
44except ImportError:
45 ZIP_SUPPORT = find_executable('zip')
46
Nick Coghlan8ed3cf32011-03-16 14:05:35 -040047def _fake_rename(*args, **kwargs):
48 # Pretend the destination path is on a different filesystem.
49 raise OSError()
50
51def mock_rename(func):
52 @functools.wraps(func)
53 def wrap(*args, **kwargs):
54 try:
55 builtin_rename = os.rename
56 os.rename = _fake_rename
57 return func(*args, **kwargs)
58 finally:
59 os.rename = builtin_rename
60 return wrap
61
Éric Araujoa7e33a12011-08-12 19:51:35 +020062def write_file(path, content, binary=False):
63 """Write *content* to a file located at *path*.
64
65 If *path* is a tuple instead of a string, os.path.join will be used to
66 make a path. If *binary* is true, the file will be opened in binary
67 mode.
68 """
69 if isinstance(path, tuple):
70 path = os.path.join(*path)
71 with open(path, 'wb' if binary else 'w') as fp:
72 fp.write(content)
73
74def read_file(path, binary=False):
75 """Return contents from a file located at *path*.
76
77 If *path* is a tuple instead of a string, os.path.join will be used to
78 make a path. If *binary* is true, the file will be opened in binary
79 mode.
80 """
81 if isinstance(path, tuple):
82 path = os.path.join(*path)
83 with open(path, 'rb' if binary else 'r') as fp:
84 return fp.read()
85
86
Barry Warsaw7fc2cca2003-01-24 17:34:13 +000087class TestShutil(unittest.TestCase):
Tarek Ziadé396fad72010-02-23 05:30:31 +000088
89 def setUp(self):
90 super(TestShutil, self).setUp()
91 self.tempdirs = []
92
93 def tearDown(self):
94 super(TestShutil, self).tearDown()
95 while self.tempdirs:
96 d = self.tempdirs.pop()
97 shutil.rmtree(d, os.name in ('nt', 'cygwin'))
98
Tarek Ziadé396fad72010-02-23 05:30:31 +000099
100 def mkdtemp(self):
101 """Create a temporary directory that will be cleaned up.
102
103 Returns the path of the directory.
104 """
105 d = tempfile.mkdtemp()
106 self.tempdirs.append(d)
107 return d
Tarek Ziadé5340db32010-04-19 22:30:51 +0000108
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000109 def test_rmtree_errors(self):
110 # filename is guaranteed not to exist
111 filename = tempfile.mktemp()
112 self.assertRaises(OSError, shutil.rmtree, filename)
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000113
Johannes Gijsbersb8b09d02004-12-06 20:50:15 +0000114 # See bug #1071513 for why we don't run this on cygwin
115 # and bug #1076467 for why we don't run this as root.
116 if (hasattr(os, 'chmod') and sys.platform[:6] != 'cygwin'
Johannes Gijsbers6b220b02004-12-12 15:52:57 +0000117 and not (hasattr(os, 'geteuid') and os.geteuid() == 0)):
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000118 def test_on_error(self):
119 self.errorState = 0
120 os.mkdir(TESTFN)
Tim Peters4590c002004-11-01 02:40:52 +0000121 self.childpath = os.path.join(TESTFN, 'a')
Victor Stinnerbf816222011-06-30 23:25:47 +0200122 support.create_empty_file(self.childpath)
Tim Peters4590c002004-11-01 02:40:52 +0000123 old_dir_mode = os.stat(TESTFN).st_mode
124 old_child_mode = os.stat(self.childpath).st_mode
125 # Make unwritable.
126 os.chmod(self.childpath, stat.S_IREAD)
127 os.chmod(TESTFN, stat.S_IREAD)
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000128
129 shutil.rmtree(TESTFN, onerror=self.check_args_to_onerror)
Johannes Gijsbers8e6f2de2004-11-23 09:27:27 +0000130 # Test whether onerror has actually been called.
Johannes Gijsbersb8b09d02004-12-06 20:50:15 +0000131 self.assertEqual(self.errorState, 2,
132 "Expected call to onerror function did not happen.")
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000133
Tim Peters4590c002004-11-01 02:40:52 +0000134 # Make writable again.
135 os.chmod(TESTFN, old_dir_mode)
136 os.chmod(self.childpath, old_child_mode)
137
138 # Clean up.
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000139 shutil.rmtree(TESTFN)
140
141 def check_args_to_onerror(self, func, arg, exc):
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000142 # test_rmtree_errors deliberately runs rmtree
143 # on a directory that is chmod 400, which will fail.
144 # This function is run when shutil.rmtree fails.
145 # 99.9% of the time it initially fails to remove
146 # a file in the directory, so the first time through
147 # func is os.remove.
148 # However, some Linux machines running ZFS on
149 # FUSE experienced a failure earlier in the process
150 # at os.listdir. The first failure may legally
151 # be either.
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000152 if self.errorState == 0:
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000153 if func is os.remove:
154 self.assertEqual(arg, self.childpath)
155 else:
156 self.assertIs(func, os.listdir,
157 "func must be either os.remove or os.listdir")
158 self.assertEqual(arg, TESTFN)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000159 self.assertTrue(issubclass(exc[0], OSError))
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000160 self.errorState = 1
161 else:
162 self.assertEqual(func, os.rmdir)
163 self.assertEqual(arg, TESTFN)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000164 self.assertTrue(issubclass(exc[0], OSError))
Johannes Gijsbers8e6f2de2004-11-23 09:27:27 +0000165 self.errorState = 2
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000166
Antoine Pitrou78091e62011-12-29 18:54:15 +0100167 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
168 @support.skip_unless_symlink
169 def test_copymode_follow_symlinks(self):
170 tmp_dir = self.mkdtemp()
171 src = os.path.join(tmp_dir, 'foo')
172 dst = os.path.join(tmp_dir, 'bar')
173 src_link = os.path.join(tmp_dir, 'baz')
174 dst_link = os.path.join(tmp_dir, 'quux')
175 write_file(src, 'foo')
176 write_file(dst, 'foo')
177 os.symlink(src, src_link)
178 os.symlink(dst, dst_link)
179 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
180 # file to file
181 os.chmod(dst, stat.S_IRWXO)
182 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
183 shutil.copymode(src, dst)
184 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
185 # follow src link
186 os.chmod(dst, stat.S_IRWXO)
187 shutil.copymode(src_link, dst)
188 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
189 # follow dst link
190 os.chmod(dst, stat.S_IRWXO)
191 shutil.copymode(src, dst_link)
192 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
193 # follow both links
194 os.chmod(dst, stat.S_IRWXO)
195 shutil.copymode(src_link, dst)
196 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
197
198 @unittest.skipUnless(hasattr(os, 'lchmod'), 'requires os.lchmod')
199 @support.skip_unless_symlink
200 def test_copymode_symlink_to_symlink(self):
201 tmp_dir = self.mkdtemp()
202 src = os.path.join(tmp_dir, 'foo')
203 dst = os.path.join(tmp_dir, 'bar')
204 src_link = os.path.join(tmp_dir, 'baz')
205 dst_link = os.path.join(tmp_dir, 'quux')
206 write_file(src, 'foo')
207 write_file(dst, 'foo')
208 os.symlink(src, src_link)
209 os.symlink(dst, dst_link)
210 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
211 os.chmod(dst, stat.S_IRWXU)
212 os.lchmod(src_link, stat.S_IRWXO|stat.S_IRWXG)
213 # link to link
214 os.lchmod(dst_link, stat.S_IRWXO)
215 shutil.copymode(src_link, dst_link, symlinks=True)
216 self.assertEqual(os.lstat(src_link).st_mode,
217 os.lstat(dst_link).st_mode)
218 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
219 # src link - use chmod
220 os.lchmod(dst_link, stat.S_IRWXO)
221 shutil.copymode(src_link, dst, symlinks=True)
222 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
223 # dst link - use chmod
224 os.lchmod(dst_link, stat.S_IRWXO)
225 shutil.copymode(src, dst_link, symlinks=True)
226 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
227
228 @unittest.skipIf(hasattr(os, 'lchmod'), 'requires os.lchmod to be missing')
229 @support.skip_unless_symlink
230 def test_copymode_symlink_to_symlink_wo_lchmod(self):
231 tmp_dir = self.mkdtemp()
232 src = os.path.join(tmp_dir, 'foo')
233 dst = os.path.join(tmp_dir, 'bar')
234 src_link = os.path.join(tmp_dir, 'baz')
235 dst_link = os.path.join(tmp_dir, 'quux')
236 write_file(src, 'foo')
237 write_file(dst, 'foo')
238 os.symlink(src, src_link)
239 os.symlink(dst, dst_link)
240 shutil.copymode(src_link, dst_link, symlinks=True) # silent fail
241
242 @support.skip_unless_symlink
243 def test_copystat_symlinks(self):
244 tmp_dir = self.mkdtemp()
245 src = os.path.join(tmp_dir, 'foo')
246 dst = os.path.join(tmp_dir, 'bar')
247 src_link = os.path.join(tmp_dir, 'baz')
248 dst_link = os.path.join(tmp_dir, 'qux')
249 write_file(src, 'foo')
250 src_stat = os.stat(src)
251 os.utime(src, (src_stat.st_atime,
252 src_stat.st_mtime - 42.0)) # ensure different mtimes
253 write_file(dst, 'bar')
254 self.assertNotEqual(os.stat(src).st_mtime, os.stat(dst).st_mtime)
255 os.symlink(src, src_link)
256 os.symlink(dst, dst_link)
257 if hasattr(os, 'lchmod'):
258 os.lchmod(src_link, stat.S_IRWXO)
259 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
260 os.lchflags(src_link, stat.UF_NODUMP)
261 src_link_stat = os.lstat(src_link)
262 # follow
263 if hasattr(os, 'lchmod'):
264 shutil.copystat(src_link, dst_link, symlinks=False)
265 self.assertNotEqual(src_link_stat.st_mode, os.stat(dst).st_mode)
266 # don't follow
267 shutil.copystat(src_link, dst_link, symlinks=True)
268 dst_link_stat = os.lstat(dst_link)
269 if hasattr(os, 'lutimes'):
270 for attr in 'st_atime', 'st_mtime':
271 # The modification times may be truncated in the new file.
272 self.assertLessEqual(getattr(src_link_stat, attr),
273 getattr(dst_link_stat, attr) + 1)
274 if hasattr(os, 'lchmod'):
275 self.assertEqual(src_link_stat.st_mode, dst_link_stat.st_mode)
276 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
277 self.assertEqual(src_link_stat.st_flags, dst_link_stat.st_flags)
278 # tell to follow but dst is not a link
279 shutil.copystat(src_link, dst, symlinks=True)
280 self.assertTrue(abs(os.stat(src).st_mtime - os.stat(dst).st_mtime) <
281 00000.1)
282
283 @support.skip_unless_symlink
284 def test_copy_symlinks(self):
285 tmp_dir = self.mkdtemp()
286 src = os.path.join(tmp_dir, 'foo')
287 dst = os.path.join(tmp_dir, 'bar')
288 src_link = os.path.join(tmp_dir, 'baz')
289 write_file(src, 'foo')
290 os.symlink(src, src_link)
291 if hasattr(os, 'lchmod'):
292 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
293 # don't follow
294 shutil.copy(src_link, dst, symlinks=False)
295 self.assertFalse(os.path.islink(dst))
296 self.assertEqual(read_file(src), read_file(dst))
297 os.remove(dst)
298 # follow
299 shutil.copy(src_link, dst, symlinks=True)
300 self.assertTrue(os.path.islink(dst))
301 self.assertEqual(os.readlink(dst), os.readlink(src_link))
302 if hasattr(os, 'lchmod'):
303 self.assertEqual(os.lstat(src_link).st_mode,
304 os.lstat(dst).st_mode)
305
306 @support.skip_unless_symlink
307 def test_copy2_symlinks(self):
308 tmp_dir = self.mkdtemp()
309 src = os.path.join(tmp_dir, 'foo')
310 dst = os.path.join(tmp_dir, 'bar')
311 src_link = os.path.join(tmp_dir, 'baz')
312 write_file(src, 'foo')
313 os.symlink(src, src_link)
314 if hasattr(os, 'lchmod'):
315 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
316 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
317 os.lchflags(src_link, stat.UF_NODUMP)
318 src_stat = os.stat(src)
319 src_link_stat = os.lstat(src_link)
320 # follow
321 shutil.copy2(src_link, dst, symlinks=False)
322 self.assertFalse(os.path.islink(dst))
323 self.assertEqual(read_file(src), read_file(dst))
324 os.remove(dst)
325 # don't follow
326 shutil.copy2(src_link, dst, symlinks=True)
327 self.assertTrue(os.path.islink(dst))
328 self.assertEqual(os.readlink(dst), os.readlink(src_link))
329 dst_stat = os.lstat(dst)
330 if hasattr(os, 'lutimes'):
331 for attr in 'st_atime', 'st_mtime':
332 # The modification times may be truncated in the new file.
333 self.assertLessEqual(getattr(src_link_stat, attr),
334 getattr(dst_stat, attr) + 1)
335 if hasattr(os, 'lchmod'):
336 self.assertEqual(src_link_stat.st_mode, dst_stat.st_mode)
337 self.assertNotEqual(src_stat.st_mode, dst_stat.st_mode)
338 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
339 self.assertEqual(src_link_stat.st_flags, dst_stat.st_flags)
340
341 @support.skip_unless_symlink
342 def test_copyfile_symlinks(self):
343 tmp_dir = self.mkdtemp()
344 src = os.path.join(tmp_dir, 'src')
345 dst = os.path.join(tmp_dir, 'dst')
346 dst_link = os.path.join(tmp_dir, 'dst_link')
347 link = os.path.join(tmp_dir, 'link')
348 write_file(src, 'foo')
349 os.symlink(src, link)
350 # don't follow
351 shutil.copyfile(link, dst_link, symlinks=True)
352 self.assertTrue(os.path.islink(dst_link))
353 self.assertEqual(os.readlink(link), os.readlink(dst_link))
354 # follow
355 shutil.copyfile(link, dst)
356 self.assertFalse(os.path.islink(dst))
357
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000358 def test_rmtree_dont_delete_file(self):
359 # When called on a file instead of a directory, don't delete it.
360 handle, path = tempfile.mkstemp()
Victor Stinnerbf816222011-06-30 23:25:47 +0200361 os.close(handle)
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000362 self.assertRaises(OSError, shutil.rmtree, path)
363 os.remove(path)
364
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000365 def test_copytree_simple(self):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000366 src_dir = tempfile.mkdtemp()
367 dst_dir = os.path.join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200368 self.addCleanup(shutil.rmtree, src_dir)
369 self.addCleanup(shutil.rmtree, os.path.dirname(dst_dir))
370 write_file((src_dir, 'test.txt'), '123')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000371 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200372 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000373
Éric Araujoa7e33a12011-08-12 19:51:35 +0200374 shutil.copytree(src_dir, dst_dir)
375 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test.txt')))
376 self.assertTrue(os.path.isdir(os.path.join(dst_dir, 'test_dir')))
377 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test_dir',
378 'test.txt')))
379 actual = read_file((dst_dir, 'test.txt'))
380 self.assertEqual(actual, '123')
381 actual = read_file((dst_dir, 'test_dir', 'test.txt'))
382 self.assertEqual(actual, '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000383
Antoine Pitrou78091e62011-12-29 18:54:15 +0100384 @support.skip_unless_symlink
385 def test_copytree_symlinks(self):
386 tmp_dir = self.mkdtemp()
387 src_dir = os.path.join(tmp_dir, 'src')
388 dst_dir = os.path.join(tmp_dir, 'dst')
389 sub_dir = os.path.join(src_dir, 'sub')
390 os.mkdir(src_dir)
391 os.mkdir(sub_dir)
392 write_file((src_dir, 'file.txt'), 'foo')
393 src_link = os.path.join(sub_dir, 'link')
394 dst_link = os.path.join(dst_dir, 'sub/link')
395 os.symlink(os.path.join(src_dir, 'file.txt'),
396 src_link)
397 if hasattr(os, 'lchmod'):
398 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
399 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
400 os.lchflags(src_link, stat.UF_NODUMP)
401 src_stat = os.lstat(src_link)
402 shutil.copytree(src_dir, dst_dir, symlinks=True)
403 self.assertTrue(os.path.islink(os.path.join(dst_dir, 'sub', 'link')))
404 self.assertEqual(os.readlink(os.path.join(dst_dir, 'sub', 'link')),
405 os.path.join(src_dir, 'file.txt'))
406 dst_stat = os.lstat(dst_link)
407 if hasattr(os, 'lchmod'):
408 self.assertEqual(dst_stat.st_mode, src_stat.st_mode)
409 if hasattr(os, 'lchflags'):
410 self.assertEqual(dst_stat.st_flags, src_stat.st_flags)
411
Georg Brandl2ee470f2008-07-16 12:55:28 +0000412 def test_copytree_with_exclude(self):
Georg Brandl2ee470f2008-07-16 12:55:28 +0000413 # creating data
414 join = os.path.join
415 exists = os.path.exists
416 src_dir = tempfile.mkdtemp()
Georg Brandl2ee470f2008-07-16 12:55:28 +0000417 try:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000418 dst_dir = join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200419 write_file((src_dir, 'test.txt'), '123')
420 write_file((src_dir, 'test.tmp'), '123')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000421 os.mkdir(join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200422 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000423 os.mkdir(join(src_dir, 'test_dir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200424 write_file((src_dir, 'test_dir2', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000425 os.mkdir(join(src_dir, 'test_dir2', 'subdir'))
426 os.mkdir(join(src_dir, 'test_dir2', 'subdir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200427 write_file((src_dir, 'test_dir2', 'subdir', 'test.txt'), '456')
428 write_file((src_dir, 'test_dir2', 'subdir2', 'test.py'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000429
430 # testing glob-like patterns
431 try:
432 patterns = shutil.ignore_patterns('*.tmp', 'test_dir2')
433 shutil.copytree(src_dir, dst_dir, ignore=patterns)
434 # checking the result: some elements should not be copied
435 self.assertTrue(exists(join(dst_dir, 'test.txt')))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200436 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
437 self.assertFalse(exists(join(dst_dir, 'test_dir2')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000438 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200439 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000440 try:
441 patterns = shutil.ignore_patterns('*.tmp', 'subdir*')
442 shutil.copytree(src_dir, dst_dir, ignore=patterns)
443 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200444 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
445 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2')))
446 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000447 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200448 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000449
450 # testing callable-style
451 try:
452 def _filter(src, names):
453 res = []
454 for name in names:
455 path = os.path.join(src, name)
456
457 if (os.path.isdir(path) and
458 path.split()[-1] == 'subdir'):
459 res.append(name)
460 elif os.path.splitext(path)[-1] in ('.py'):
461 res.append(name)
462 return res
463
464 shutil.copytree(src_dir, dst_dir, ignore=_filter)
465
466 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200467 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2',
468 'test.py')))
469 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000470
471 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200472 shutil.rmtree(dst_dir)
Georg Brandl2ee470f2008-07-16 12:55:28 +0000473 finally:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000474 shutil.rmtree(src_dir)
475 shutil.rmtree(os.path.dirname(dst_dir))
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000476
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000477 @unittest.skipUnless(hasattr(os, 'link'), 'requires os.link')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000478 def test_dont_copy_file_onto_link_to_itself(self):
Georg Brandl724d0892010-12-05 07:51:39 +0000479 # Temporarily disable test on Windows.
480 if os.name == 'nt':
481 return
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000482 # bug 851123.
483 os.mkdir(TESTFN)
484 src = os.path.join(TESTFN, 'cheese')
485 dst = os.path.join(TESTFN, 'shop')
486 try:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000487 with open(src, 'w') as f:
488 f.write('cheddar')
489 os.link(src, dst)
490 self.assertRaises(shutil.Error, shutil.copyfile, src, dst)
491 with open(src, 'r') as f:
492 self.assertEqual(f.read(), 'cheddar')
493 os.remove(dst)
494 finally:
495 shutil.rmtree(TESTFN, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000496
Brian Curtin3b4499c2010-12-28 14:31:47 +0000497 @support.skip_unless_symlink
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000498 def test_dont_copy_file_onto_symlink_to_itself(self):
499 # bug 851123.
500 os.mkdir(TESTFN)
501 src = os.path.join(TESTFN, 'cheese')
502 dst = os.path.join(TESTFN, 'shop')
503 try:
504 with open(src, 'w') as f:
505 f.write('cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000506 # Using `src` here would mean we end up with a symlink pointing
507 # to TESTFN/TESTFN/cheese, while it should point at
508 # TESTFN/cheese.
509 os.symlink('cheese', dst)
510 self.assertRaises(shutil.Error, shutil.copyfile, src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +0000511 with open(src, 'r') as f:
512 self.assertEqual(f.read(), 'cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000513 os.remove(dst)
514 finally:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000515 shutil.rmtree(TESTFN, ignore_errors=True)
Johannes Gijsbers68128712004-08-14 13:57:08 +0000516
Brian Curtin3b4499c2010-12-28 14:31:47 +0000517 @support.skip_unless_symlink
Brian Curtind40e6f72010-07-08 21:39:08 +0000518 def test_rmtree_on_symlink(self):
519 # bug 1669.
520 os.mkdir(TESTFN)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000521 try:
Brian Curtind40e6f72010-07-08 21:39:08 +0000522 src = os.path.join(TESTFN, 'cheese')
523 dst = os.path.join(TESTFN, 'shop')
524 os.mkdir(src)
525 os.symlink(src, dst)
526 self.assertRaises(OSError, shutil.rmtree, dst)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000527 finally:
Brian Curtind40e6f72010-07-08 21:39:08 +0000528 shutil.rmtree(TESTFN, ignore_errors=True)
529
530 if hasattr(os, "mkfifo"):
531 # Issue #3002: copyfile and copytree block indefinitely on named pipes
532 def test_copyfile_named_pipe(self):
533 os.mkfifo(TESTFN)
534 try:
535 self.assertRaises(shutil.SpecialFileError,
536 shutil.copyfile, TESTFN, TESTFN2)
537 self.assertRaises(shutil.SpecialFileError,
538 shutil.copyfile, __file__, TESTFN)
539 finally:
540 os.remove(TESTFN)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000541
Brian Curtin3b4499c2010-12-28 14:31:47 +0000542 @support.skip_unless_symlink
Brian Curtin52173d42010-12-02 18:29:18 +0000543 def test_copytree_named_pipe(self):
544 os.mkdir(TESTFN)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000545 try:
Brian Curtin52173d42010-12-02 18:29:18 +0000546 subdir = os.path.join(TESTFN, "subdir")
547 os.mkdir(subdir)
548 pipe = os.path.join(subdir, "mypipe")
549 os.mkfifo(pipe)
550 try:
551 shutil.copytree(TESTFN, TESTFN2)
552 except shutil.Error as e:
553 errors = e.args[0]
554 self.assertEqual(len(errors), 1)
555 src, dst, error_msg = errors[0]
556 self.assertEqual("`%s` is a named pipe" % pipe, error_msg)
557 else:
558 self.fail("shutil.Error should have been raised")
559 finally:
560 shutil.rmtree(TESTFN, ignore_errors=True)
561 shutil.rmtree(TESTFN2, ignore_errors=True)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000562
Tarek Ziadé5340db32010-04-19 22:30:51 +0000563 def test_copytree_special_func(self):
564
565 src_dir = self.mkdtemp()
566 dst_dir = os.path.join(self.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200567 write_file((src_dir, 'test.txt'), '123')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000568 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200569 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000570
571 copied = []
572 def _copy(src, dst):
573 copied.append((src, dst))
574
575 shutil.copytree(src_dir, dst_dir, copy_function=_copy)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000576 self.assertEqual(len(copied), 2)
Tarek Ziadé5340db32010-04-19 22:30:51 +0000577
Brian Curtin3b4499c2010-12-28 14:31:47 +0000578 @support.skip_unless_symlink
Tarek Ziadéfb437512010-04-20 08:57:33 +0000579 def test_copytree_dangling_symlinks(self):
580
581 # a dangling symlink raises an error at the end
582 src_dir = self.mkdtemp()
583 dst_dir = os.path.join(self.mkdtemp(), 'destination')
584 os.symlink('IDONTEXIST', os.path.join(src_dir, 'test.txt'))
585 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200586 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadéfb437512010-04-20 08:57:33 +0000587 self.assertRaises(Error, shutil.copytree, src_dir, dst_dir)
588
589 # a dangling symlink is ignored with the proper flag
590 dst_dir = os.path.join(self.mkdtemp(), 'destination2')
591 shutil.copytree(src_dir, dst_dir, ignore_dangling_symlinks=True)
592 self.assertNotIn('test.txt', os.listdir(dst_dir))
593
594 # a dangling symlink is copied if symlinks=True
595 dst_dir = os.path.join(self.mkdtemp(), 'destination3')
596 shutil.copytree(src_dir, dst_dir, symlinks=True)
597 self.assertIn('test.txt', os.listdir(dst_dir))
598
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400599 def _copy_file(self, method):
600 fname = 'test.txt'
601 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200602 write_file((tmpdir, fname), 'xxx')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400603 file1 = os.path.join(tmpdir, fname)
604 tmpdir2 = self.mkdtemp()
605 method(file1, tmpdir2)
606 file2 = os.path.join(tmpdir2, fname)
607 return (file1, file2)
608
609 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
610 def test_copy(self):
611 # Ensure that the copied file exists and has the same mode bits.
612 file1, file2 = self._copy_file(shutil.copy)
613 self.assertTrue(os.path.exists(file2))
614 self.assertEqual(os.stat(file1).st_mode, os.stat(file2).st_mode)
615
616 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
Senthil Kumaran0c2dba52011-07-03 18:21:38 -0700617 @unittest.skipUnless(hasattr(os, 'utime'), 'requires os.utime')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400618 def test_copy2(self):
619 # Ensure that the copied file exists and has the same mode and
620 # modification time bits.
621 file1, file2 = self._copy_file(shutil.copy2)
622 self.assertTrue(os.path.exists(file2))
623 file1_stat = os.stat(file1)
624 file2_stat = os.stat(file2)
625 self.assertEqual(file1_stat.st_mode, file2_stat.st_mode)
626 for attr in 'st_atime', 'st_mtime':
627 # The modification times may be truncated in the new file.
628 self.assertLessEqual(getattr(file1_stat, attr),
629 getattr(file2_stat, attr) + 1)
630 if hasattr(os, 'chflags') and hasattr(file1_stat, 'st_flags'):
631 self.assertEqual(getattr(file1_stat, 'st_flags'),
632 getattr(file2_stat, 'st_flags'))
633
Ezio Melotti975077a2011-05-19 22:03:22 +0300634 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000635 def test_make_tarball(self):
636 # creating something to tar
637 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200638 write_file((tmpdir, 'file1'), 'xxx')
639 write_file((tmpdir, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000640 os.mkdir(os.path.join(tmpdir, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200641 write_file((tmpdir, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000642
643 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400644 # force shutil to create the directory
645 os.rmdir(tmpdir2)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000646 unittest.skipUnless(splitdrive(tmpdir)[0] == splitdrive(tmpdir2)[0],
647 "source and target should be on same drive")
648
649 base_name = os.path.join(tmpdir2, 'archive')
650
651 # working with relative paths to avoid tar warnings
652 old_dir = os.getcwd()
653 os.chdir(tmpdir)
654 try:
655 _make_tarball(splitdrive(base_name)[1], '.')
656 finally:
657 os.chdir(old_dir)
658
659 # check if the compressed tarball was created
660 tarball = base_name + '.tar.gz'
661 self.assertTrue(os.path.exists(tarball))
662
663 # trying an uncompressed one
664 base_name = os.path.join(tmpdir2, 'archive')
665 old_dir = os.getcwd()
666 os.chdir(tmpdir)
667 try:
668 _make_tarball(splitdrive(base_name)[1], '.', compress=None)
669 finally:
670 os.chdir(old_dir)
671 tarball = base_name + '.tar'
672 self.assertTrue(os.path.exists(tarball))
673
674 def _tarinfo(self, path):
675 tar = tarfile.open(path)
676 try:
677 names = tar.getnames()
678 names.sort()
679 return tuple(names)
680 finally:
681 tar.close()
682
683 def _create_files(self):
684 # creating something to tar
685 tmpdir = self.mkdtemp()
686 dist = os.path.join(tmpdir, 'dist')
687 os.mkdir(dist)
Éric Araujoa7e33a12011-08-12 19:51:35 +0200688 write_file((dist, 'file1'), 'xxx')
689 write_file((dist, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000690 os.mkdir(os.path.join(dist, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200691 write_file((dist, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000692 os.mkdir(os.path.join(dist, 'sub2'))
693 tmpdir2 = self.mkdtemp()
694 base_name = os.path.join(tmpdir2, 'archive')
695 return tmpdir, tmpdir2, base_name
696
Ezio Melotti975077a2011-05-19 22:03:22 +0300697 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000698 @unittest.skipUnless(find_executable('tar') and find_executable('gzip'),
699 'Need the tar command to run')
700 def test_tarfile_vs_tar(self):
701 tmpdir, tmpdir2, base_name = self._create_files()
702 old_dir = os.getcwd()
703 os.chdir(tmpdir)
704 try:
705 _make_tarball(base_name, 'dist')
706 finally:
707 os.chdir(old_dir)
708
709 # check if the compressed tarball was created
710 tarball = base_name + '.tar.gz'
711 self.assertTrue(os.path.exists(tarball))
712
713 # now create another tarball using `tar`
714 tarball2 = os.path.join(tmpdir, 'archive2.tar.gz')
715 tar_cmd = ['tar', '-cf', 'archive2.tar', 'dist']
716 gzip_cmd = ['gzip', '-f9', 'archive2.tar']
717 old_dir = os.getcwd()
718 os.chdir(tmpdir)
719 try:
720 with captured_stdout() as s:
721 spawn(tar_cmd)
722 spawn(gzip_cmd)
723 finally:
724 os.chdir(old_dir)
725
726 self.assertTrue(os.path.exists(tarball2))
727 # let's compare both tarballs
Ezio Melottib3aedd42010-11-20 19:04:17 +0000728 self.assertEqual(self._tarinfo(tarball), self._tarinfo(tarball2))
Tarek Ziadé396fad72010-02-23 05:30:31 +0000729
730 # trying an uncompressed one
731 base_name = os.path.join(tmpdir2, 'archive')
732 old_dir = os.getcwd()
733 os.chdir(tmpdir)
734 try:
735 _make_tarball(base_name, 'dist', compress=None)
736 finally:
737 os.chdir(old_dir)
738 tarball = base_name + '.tar'
739 self.assertTrue(os.path.exists(tarball))
740
741 # now for a dry_run
742 base_name = os.path.join(tmpdir2, 'archive')
743 old_dir = os.getcwd()
744 os.chdir(tmpdir)
745 try:
746 _make_tarball(base_name, 'dist', compress=None, dry_run=True)
747 finally:
748 os.chdir(old_dir)
749 tarball = base_name + '.tar'
750 self.assertTrue(os.path.exists(tarball))
751
Ezio Melotti975077a2011-05-19 22:03:22 +0300752 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000753 @unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run')
754 def test_make_zipfile(self):
755 # creating something to tar
756 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200757 write_file((tmpdir, 'file1'), 'xxx')
758 write_file((tmpdir, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000759
760 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400761 # force shutil to create the directory
762 os.rmdir(tmpdir2)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000763 base_name = os.path.join(tmpdir2, 'archive')
764 _make_zipfile(base_name, tmpdir)
765
766 # check if the compressed tarball was created
767 tarball = base_name + '.zip'
Éric Araujo1c505492010-11-06 02:12:51 +0000768 self.assertTrue(os.path.exists(tarball))
Tarek Ziadé396fad72010-02-23 05:30:31 +0000769
770
771 def test_make_archive(self):
772 tmpdir = self.mkdtemp()
773 base_name = os.path.join(tmpdir, 'archive')
774 self.assertRaises(ValueError, make_archive, base_name, 'xxx')
775
Ezio Melotti975077a2011-05-19 22:03:22 +0300776 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000777 def test_make_archive_owner_group(self):
778 # testing make_archive with owner and group, with various combinations
779 # this works even if there's not gid/uid support
780 if UID_GID_SUPPORT:
781 group = grp.getgrgid(0)[0]
782 owner = pwd.getpwuid(0)[0]
783 else:
784 group = owner = 'root'
785
786 base_dir, root_dir, base_name = self._create_files()
787 base_name = os.path.join(self.mkdtemp() , 'archive')
788 res = make_archive(base_name, 'zip', root_dir, base_dir, owner=owner,
789 group=group)
790 self.assertTrue(os.path.exists(res))
791
792 res = make_archive(base_name, 'zip', root_dir, base_dir)
793 self.assertTrue(os.path.exists(res))
794
795 res = make_archive(base_name, 'tar', root_dir, base_dir,
796 owner=owner, group=group)
797 self.assertTrue(os.path.exists(res))
798
799 res = make_archive(base_name, 'tar', root_dir, base_dir,
800 owner='kjhkjhkjg', group='oihohoh')
801 self.assertTrue(os.path.exists(res))
802
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000803
Ezio Melotti975077a2011-05-19 22:03:22 +0300804 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000805 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
806 def test_tarfile_root_owner(self):
807 tmpdir, tmpdir2, base_name = self._create_files()
808 old_dir = os.getcwd()
809 os.chdir(tmpdir)
810 group = grp.getgrgid(0)[0]
811 owner = pwd.getpwuid(0)[0]
812 try:
813 archive_name = _make_tarball(base_name, 'dist', compress=None,
814 owner=owner, group=group)
815 finally:
816 os.chdir(old_dir)
817
818 # check if the compressed tarball was created
819 self.assertTrue(os.path.exists(archive_name))
820
821 # now checks the rights
822 archive = tarfile.open(archive_name)
823 try:
824 for member in archive.getmembers():
Ezio Melottib3aedd42010-11-20 19:04:17 +0000825 self.assertEqual(member.uid, 0)
826 self.assertEqual(member.gid, 0)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000827 finally:
828 archive.close()
829
830 def test_make_archive_cwd(self):
831 current_dir = os.getcwd()
832 def _breaks(*args, **kw):
833 raise RuntimeError()
834
835 register_archive_format('xxx', _breaks, [], 'xxx file')
836 try:
837 try:
838 make_archive('xxx', 'xxx', root_dir=self.mkdtemp())
839 except Exception:
840 pass
Ezio Melottib3aedd42010-11-20 19:04:17 +0000841 self.assertEqual(os.getcwd(), current_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000842 finally:
843 unregister_archive_format('xxx')
844
845 def test_register_archive_format(self):
846
847 self.assertRaises(TypeError, register_archive_format, 'xxx', 1)
848 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
849 1)
850 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
851 [(1, 2), (1, 2, 3)])
852
853 register_archive_format('xxx', lambda: x, [(1, 2)], 'xxx file')
854 formats = [name for name, params in get_archive_formats()]
855 self.assertIn('xxx', formats)
856
857 unregister_archive_format('xxx')
858 formats = [name for name, params in get_archive_formats()]
859 self.assertNotIn('xxx', formats)
860
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000861 def _compare_dirs(self, dir1, dir2):
862 # check that dir1 and dir2 are equivalent,
863 # return the diff
864 diff = []
865 for root, dirs, files in os.walk(dir1):
866 for file_ in files:
867 path = os.path.join(root, file_)
868 target_path = os.path.join(dir2, os.path.split(path)[-1])
869 if not os.path.exists(target_path):
870 diff.append(file_)
871 return diff
872
Ezio Melotti975077a2011-05-19 22:03:22 +0300873 @requires_zlib
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000874 def test_unpack_archive(self):
Tarek Ziadéffa155a2010-04-29 13:34:35 +0000875 formats = ['tar', 'gztar', 'zip']
876 if BZ2_SUPPORTED:
877 formats.append('bztar')
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000878
Tarek Ziadéffa155a2010-04-29 13:34:35 +0000879 for format in formats:
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000880 tmpdir = self.mkdtemp()
881 base_dir, root_dir, base_name = self._create_files()
882 tmpdir2 = self.mkdtemp()
883 filename = make_archive(base_name, format, root_dir, base_dir)
884
885 # let's try to unpack it now
886 unpack_archive(filename, tmpdir2)
887 diff = self._compare_dirs(tmpdir, tmpdir2)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000888 self.assertEqual(diff, [])
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000889
Nick Coghlanabf202d2011-03-16 13:52:20 -0400890 # and again, this time with the format specified
891 tmpdir3 = self.mkdtemp()
892 unpack_archive(filename, tmpdir3, format=format)
893 diff = self._compare_dirs(tmpdir, tmpdir3)
894 self.assertEqual(diff, [])
895 self.assertRaises(shutil.ReadError, unpack_archive, TESTFN)
896 self.assertRaises(ValueError, unpack_archive, TESTFN, format='xxx')
897
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000898 def test_unpack_registery(self):
899
900 formats = get_unpack_formats()
901
902 def _boo(filename, extract_dir, extra):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000903 self.assertEqual(extra, 1)
904 self.assertEqual(filename, 'stuff.boo')
905 self.assertEqual(extract_dir, 'xx')
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000906
907 register_unpack_format('Boo', ['.boo', '.b2'], _boo, [('extra', 1)])
908 unpack_archive('stuff.boo', 'xx')
909
910 # trying to register a .boo unpacker again
911 self.assertRaises(RegistryError, register_unpack_format, 'Boo2',
912 ['.boo'], _boo)
913
914 # should work now
915 unregister_unpack_format('Boo')
916 register_unpack_format('Boo2', ['.boo'], _boo)
917 self.assertIn(('Boo2', ['.boo'], ''), get_unpack_formats())
918 self.assertNotIn(('Boo', ['.boo'], ''), get_unpack_formats())
919
920 # let's leave a clean state
921 unregister_unpack_format('Boo2')
Ezio Melottib3aedd42010-11-20 19:04:17 +0000922 self.assertEqual(get_unpack_formats(), formats)
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000923
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +0200924 @unittest.skipUnless(hasattr(shutil, 'disk_usage'),
925 "disk_usage not available on this platform")
926 def test_disk_usage(self):
927 usage = shutil.disk_usage(os.getcwd())
Éric Araujo2ee61882011-07-02 16:45:45 +0200928 self.assertGreater(usage.total, 0)
929 self.assertGreater(usage.used, 0)
930 self.assertGreaterEqual(usage.free, 0)
931 self.assertGreaterEqual(usage.total, usage.used)
932 self.assertGreater(usage.total, usage.free)
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +0200933
Sandro Tosid902a142011-08-22 23:28:27 +0200934 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
935 @unittest.skipUnless(hasattr(os, 'chown'), 'requires os.chown')
936 def test_chown(self):
937
938 # cleaned-up automatically by TestShutil.tearDown method
939 dirname = self.mkdtemp()
940 filename = tempfile.mktemp(dir=dirname)
941 write_file(filename, 'testing chown function')
942
943 with self.assertRaises(ValueError):
944 shutil.chown(filename)
945
946 with self.assertRaises(LookupError):
947 shutil.chown(filename, user='non-exising username')
948
949 with self.assertRaises(LookupError):
950 shutil.chown(filename, group='non-exising groupname')
951
952 with self.assertRaises(TypeError):
953 shutil.chown(filename, b'spam')
954
955 with self.assertRaises(TypeError):
956 shutil.chown(filename, 3.14)
957
958 uid = os.getuid()
959 gid = os.getgid()
960
961 def check_chown(path, uid=None, gid=None):
962 s = os.stat(filename)
963 if uid is not None:
964 self.assertEqual(uid, s.st_uid)
965 if gid is not None:
966 self.assertEqual(gid, s.st_gid)
967
968 shutil.chown(filename, uid, gid)
969 check_chown(filename, uid, gid)
970 shutil.chown(filename, uid)
971 check_chown(filename, uid)
972 shutil.chown(filename, user=uid)
973 check_chown(filename, uid)
974 shutil.chown(filename, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +0200975 check_chown(filename, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +0200976
977 shutil.chown(dirname, uid, gid)
978 check_chown(dirname, uid, gid)
979 shutil.chown(dirname, uid)
980 check_chown(dirname, uid)
981 shutil.chown(dirname, user=uid)
982 check_chown(dirname, uid)
983 shutil.chown(dirname, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +0200984 check_chown(dirname, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +0200985
986 user = pwd.getpwuid(uid)[0]
987 group = grp.getgrgid(gid)[0]
988 shutil.chown(filename, user, group)
989 check_chown(filename, uid, gid)
990 shutil.chown(dirname, user, group)
991 check_chown(dirname, uid, gid)
992
Christian Heimes9bd667a2008-01-20 15:14:11 +0000993
Christian Heimesada8c3b2008-03-18 18:26:33 +0000994class TestMove(unittest.TestCase):
995
996 def setUp(self):
997 filename = "foo"
998 self.src_dir = tempfile.mkdtemp()
999 self.dst_dir = tempfile.mkdtemp()
1000 self.src_file = os.path.join(self.src_dir, filename)
1001 self.dst_file = os.path.join(self.dst_dir, filename)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001002 with open(self.src_file, "wb") as f:
1003 f.write(b"spam")
1004
1005 def tearDown(self):
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001006 for d in (self.src_dir, self.dst_dir):
Christian Heimesada8c3b2008-03-18 18:26:33 +00001007 try:
1008 if d:
1009 shutil.rmtree(d)
1010 except:
1011 pass
1012
1013 def _check_move_file(self, src, dst, real_dst):
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001014 with open(src, "rb") as f:
1015 contents = f.read()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001016 shutil.move(src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001017 with open(real_dst, "rb") as f:
1018 self.assertEqual(contents, f.read())
Christian Heimesada8c3b2008-03-18 18:26:33 +00001019 self.assertFalse(os.path.exists(src))
1020
1021 def _check_move_dir(self, src, dst, real_dst):
1022 contents = sorted(os.listdir(src))
1023 shutil.move(src, dst)
1024 self.assertEqual(contents, sorted(os.listdir(real_dst)))
1025 self.assertFalse(os.path.exists(src))
1026
1027 def test_move_file(self):
1028 # Move a file to another location on the same filesystem.
1029 self._check_move_file(self.src_file, self.dst_file, self.dst_file)
1030
1031 def test_move_file_to_dir(self):
1032 # Move a file inside an existing dir on the same filesystem.
1033 self._check_move_file(self.src_file, self.dst_dir, self.dst_file)
1034
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001035 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001036 def test_move_file_other_fs(self):
1037 # Move a file to an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001038 self.test_move_file()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001039
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001040 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001041 def test_move_file_to_dir_other_fs(self):
1042 # Move a file to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001043 self.test_move_file_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001044
1045 def test_move_dir(self):
1046 # Move a dir to another location on the same filesystem.
1047 dst_dir = tempfile.mktemp()
1048 try:
1049 self._check_move_dir(self.src_dir, dst_dir, dst_dir)
1050 finally:
1051 try:
1052 shutil.rmtree(dst_dir)
1053 except:
1054 pass
1055
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001056 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001057 def test_move_dir_other_fs(self):
1058 # Move a dir to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001059 self.test_move_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001060
1061 def test_move_dir_to_dir(self):
1062 # Move a dir inside an existing dir on the same filesystem.
1063 self._check_move_dir(self.src_dir, self.dst_dir,
1064 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1065
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001066 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001067 def test_move_dir_to_dir_other_fs(self):
1068 # Move a dir inside an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001069 self.test_move_dir_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001070
1071 def test_existing_file_inside_dest_dir(self):
1072 # A file with the same name inside the destination dir already exists.
1073 with open(self.dst_file, "wb"):
1074 pass
1075 self.assertRaises(shutil.Error, shutil.move, self.src_file, self.dst_dir)
1076
1077 def test_dont_move_dir_in_itself(self):
1078 # Moving a dir inside itself raises an Error.
1079 dst = os.path.join(self.src_dir, "bar")
1080 self.assertRaises(shutil.Error, shutil.move, self.src_dir, dst)
1081
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001082 def test_destinsrc_false_negative(self):
1083 os.mkdir(TESTFN)
1084 try:
1085 for src, dst in [('srcdir', 'srcdir/dest')]:
1086 src = os.path.join(TESTFN, src)
1087 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001088 self.assertTrue(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001089 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001090 'dst (%s) is not in src (%s)' % (dst, src))
1091 finally:
1092 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001093
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001094 def test_destinsrc_false_positive(self):
1095 os.mkdir(TESTFN)
1096 try:
1097 for src, dst in [('srcdir', 'src/dest'), ('srcdir', 'srcdir.new')]:
1098 src = os.path.join(TESTFN, src)
1099 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001100 self.assertFalse(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001101 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001102 'dst (%s) is in src (%s)' % (dst, src))
1103 finally:
1104 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimes9bd667a2008-01-20 15:14:11 +00001105
Tarek Ziadé5340db32010-04-19 22:30:51 +00001106
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001107class TestCopyFile(unittest.TestCase):
1108
1109 _delete = False
1110
1111 class Faux(object):
1112 _entered = False
1113 _exited_with = None
1114 _raised = False
1115 def __init__(self, raise_in_exit=False, suppress_at_exit=True):
1116 self._raise_in_exit = raise_in_exit
1117 self._suppress_at_exit = suppress_at_exit
1118 def read(self, *args):
1119 return ''
1120 def __enter__(self):
1121 self._entered = True
1122 def __exit__(self, exc_type, exc_val, exc_tb):
1123 self._exited_with = exc_type, exc_val, exc_tb
1124 if self._raise_in_exit:
1125 self._raised = True
1126 raise IOError("Cannot close")
1127 return self._suppress_at_exit
1128
1129 def tearDown(self):
1130 if self._delete:
1131 del shutil.open
1132
1133 def _set_shutil_open(self, func):
1134 shutil.open = func
1135 self._delete = True
1136
1137 def test_w_source_open_fails(self):
1138 def _open(filename, mode='r'):
1139 if filename == 'srcfile':
1140 raise IOError('Cannot open "srcfile"')
1141 assert 0 # shouldn't reach here.
1142
1143 self._set_shutil_open(_open)
1144
1145 self.assertRaises(IOError, shutil.copyfile, 'srcfile', 'destfile')
1146
1147 def test_w_dest_open_fails(self):
1148
1149 srcfile = self.Faux()
1150
1151 def _open(filename, mode='r'):
1152 if filename == 'srcfile':
1153 return srcfile
1154 if filename == 'destfile':
1155 raise IOError('Cannot open "destfile"')
1156 assert 0 # shouldn't reach here.
1157
1158 self._set_shutil_open(_open)
1159
1160 shutil.copyfile('srcfile', 'destfile')
1161 self.assertTrue(srcfile._entered)
1162 self.assertTrue(srcfile._exited_with[0] is IOError)
1163 self.assertEqual(srcfile._exited_with[1].args,
1164 ('Cannot open "destfile"',))
1165
1166 def test_w_dest_close_fails(self):
1167
1168 srcfile = self.Faux()
1169 destfile = self.Faux(True)
1170
1171 def _open(filename, mode='r'):
1172 if filename == 'srcfile':
1173 return srcfile
1174 if filename == 'destfile':
1175 return destfile
1176 assert 0 # shouldn't reach here.
1177
1178 self._set_shutil_open(_open)
1179
1180 shutil.copyfile('srcfile', 'destfile')
1181 self.assertTrue(srcfile._entered)
1182 self.assertTrue(destfile._entered)
1183 self.assertTrue(destfile._raised)
1184 self.assertTrue(srcfile._exited_with[0] is IOError)
1185 self.assertEqual(srcfile._exited_with[1].args,
1186 ('Cannot close',))
1187
1188 def test_w_source_close_fails(self):
1189
1190 srcfile = self.Faux(True)
1191 destfile = self.Faux()
1192
1193 def _open(filename, mode='r'):
1194 if filename == 'srcfile':
1195 return srcfile
1196 if filename == 'destfile':
1197 return destfile
1198 assert 0 # shouldn't reach here.
1199
1200 self._set_shutil_open(_open)
1201
1202 self.assertRaises(IOError,
1203 shutil.copyfile, 'srcfile', 'destfile')
1204 self.assertTrue(srcfile._entered)
1205 self.assertTrue(destfile._entered)
1206 self.assertFalse(destfile._raised)
1207 self.assertTrue(srcfile._exited_with[0] is None)
1208 self.assertTrue(srcfile._raised)
1209
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001210 def test_move_dir_caseinsensitive(self):
1211 # Renames a folder to the same name
1212 # but a different case.
1213
1214 self.src_dir = tempfile.mkdtemp()
1215 dst_dir = os.path.join(
1216 os.path.dirname(self.src_dir),
1217 os.path.basename(self.src_dir).upper())
1218 self.assertNotEqual(self.src_dir, dst_dir)
1219
1220 try:
1221 shutil.move(self.src_dir, dst_dir)
1222 self.assertTrue(os.path.isdir(dst_dir))
1223 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +02001224 os.rmdir(dst_dir)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001225
1226
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001227
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001228def test_main():
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001229 support.run_unittest(TestShutil, TestMove, TestCopyFile)
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001230
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001231if __name__ == '__main__':
Walter Dörwald21d3a322003-05-01 17:45:56 +00001232 test_main()