blob: 6c9515e409fe31c0a73bb15c70c071981461cb9e [file] [log] [blame]
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001# Copyright (C) 2003 Python Software Foundation
2
3import unittest
4import shutil
5import tempfile
Johannes Gijsbers8e6f2de2004-11-23 09:27:27 +00006import sys
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +00007import stat
Brett Cannon1c3fa182004-06-19 21:11:35 +00008import os
9import os.path
Antoine Pitrouc041ab62012-01-02 19:18:02 +010010import errno
Nick Coghlan8ed3cf32011-03-16 14:05:35 -040011import functools
Antoine Pitroubcf2b592012-02-08 23:28:36 +010012import subprocess
Benjamin Petersonee8712c2008-05-20 21:35:26 +000013from test import support
14from test.support import TESTFN
Tarek Ziadé396fad72010-02-23 05:30:31 +000015from os.path import splitdrive
16from distutils.spawn import find_executable, spawn
17from shutil import (_make_tarball, _make_zipfile, make_archive,
18 register_archive_format, unregister_archive_format,
Tarek Ziadé6ac91722010-04-28 17:51:36 +000019 get_archive_formats, Error, unpack_archive,
20 register_unpack_format, RegistryError,
21 unregister_unpack_format, get_unpack_formats)
Tarek Ziadé396fad72010-02-23 05:30:31 +000022import tarfile
23import warnings
24
25from test import support
Ezio Melotti975077a2011-05-19 22:03:22 +030026from test.support import TESTFN, check_warnings, captured_stdout, requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +000027
Tarek Ziadéffa155a2010-04-29 13:34:35 +000028try:
29 import bz2
30 BZ2_SUPPORTED = True
31except ImportError:
32 BZ2_SUPPORTED = False
33
Antoine Pitrou7fff0962009-05-01 21:09:44 +000034TESTFN2 = TESTFN + "2"
Barry Warsaw7fc2cca2003-01-24 17:34:13 +000035
Tarek Ziadé396fad72010-02-23 05:30:31 +000036try:
37 import grp
38 import pwd
39 UID_GID_SUPPORT = True
40except ImportError:
41 UID_GID_SUPPORT = False
42
43try:
Tarek Ziadé396fad72010-02-23 05:30:31 +000044 import zipfile
45 ZIP_SUPPORT = True
46except ImportError:
47 ZIP_SUPPORT = find_executable('zip')
48
Nick Coghlan8ed3cf32011-03-16 14:05:35 -040049def _fake_rename(*args, **kwargs):
50 # Pretend the destination path is on a different filesystem.
Antoine Pitrouc041ab62012-01-02 19:18:02 +010051 raise OSError(getattr(errno, 'EXDEV', 18), "Invalid cross-device link")
Nick Coghlan8ed3cf32011-03-16 14:05:35 -040052
53def mock_rename(func):
54 @functools.wraps(func)
55 def wrap(*args, **kwargs):
56 try:
57 builtin_rename = os.rename
58 os.rename = _fake_rename
59 return func(*args, **kwargs)
60 finally:
61 os.rename = builtin_rename
62 return wrap
63
Éric Araujoa7e33a12011-08-12 19:51:35 +020064def write_file(path, content, binary=False):
65 """Write *content* to a file located at *path*.
66
67 If *path* is a tuple instead of a string, os.path.join will be used to
68 make a path. If *binary* is true, the file will be opened in binary
69 mode.
70 """
71 if isinstance(path, tuple):
72 path = os.path.join(*path)
73 with open(path, 'wb' if binary else 'w') as fp:
74 fp.write(content)
75
76def read_file(path, binary=False):
77 """Return contents from a file located at *path*.
78
79 If *path* is a tuple instead of a string, os.path.join will be used to
80 make a path. If *binary* is true, the file will be opened in binary
81 mode.
82 """
83 if isinstance(path, tuple):
84 path = os.path.join(*path)
85 with open(path, 'rb' if binary else 'r') as fp:
86 return fp.read()
87
88
Barry Warsaw7fc2cca2003-01-24 17:34:13 +000089class TestShutil(unittest.TestCase):
Tarek Ziadé396fad72010-02-23 05:30:31 +000090
91 def setUp(self):
92 super(TestShutil, self).setUp()
93 self.tempdirs = []
94
95 def tearDown(self):
96 super(TestShutil, self).tearDown()
97 while self.tempdirs:
98 d = self.tempdirs.pop()
99 shutil.rmtree(d, os.name in ('nt', 'cygwin'))
100
Tarek Ziadé396fad72010-02-23 05:30:31 +0000101
102 def mkdtemp(self):
103 """Create a temporary directory that will be cleaned up.
104
105 Returns the path of the directory.
106 """
107 d = tempfile.mkdtemp()
108 self.tempdirs.append(d)
109 return d
Tarek Ziadé5340db32010-04-19 22:30:51 +0000110
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000111 def test_rmtree_errors(self):
112 # filename is guaranteed not to exist
113 filename = tempfile.mktemp()
114 self.assertRaises(OSError, shutil.rmtree, filename)
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000115
Johannes Gijsbersb8b09d02004-12-06 20:50:15 +0000116 # See bug #1071513 for why we don't run this on cygwin
117 # and bug #1076467 for why we don't run this as root.
118 if (hasattr(os, 'chmod') and sys.platform[:6] != 'cygwin'
Johannes Gijsbers6b220b02004-12-12 15:52:57 +0000119 and not (hasattr(os, 'geteuid') and os.geteuid() == 0)):
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000120 def test_on_error(self):
121 self.errorState = 0
122 os.mkdir(TESTFN)
Tim Peters4590c002004-11-01 02:40:52 +0000123 self.childpath = os.path.join(TESTFN, 'a')
Victor Stinnerbf816222011-06-30 23:25:47 +0200124 support.create_empty_file(self.childpath)
Tim Peters4590c002004-11-01 02:40:52 +0000125 old_dir_mode = os.stat(TESTFN).st_mode
126 old_child_mode = os.stat(self.childpath).st_mode
127 # Make unwritable.
128 os.chmod(self.childpath, stat.S_IREAD)
129 os.chmod(TESTFN, stat.S_IREAD)
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000130
131 shutil.rmtree(TESTFN, onerror=self.check_args_to_onerror)
Johannes Gijsbers8e6f2de2004-11-23 09:27:27 +0000132 # Test whether onerror has actually been called.
Johannes Gijsbersb8b09d02004-12-06 20:50:15 +0000133 self.assertEqual(self.errorState, 2,
134 "Expected call to onerror function did not happen.")
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000135
Tim Peters4590c002004-11-01 02:40:52 +0000136 # Make writable again.
137 os.chmod(TESTFN, old_dir_mode)
138 os.chmod(self.childpath, old_child_mode)
139
140 # Clean up.
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000141 shutil.rmtree(TESTFN)
142
143 def check_args_to_onerror(self, func, arg, exc):
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000144 # test_rmtree_errors deliberately runs rmtree
145 # on a directory that is chmod 400, which will fail.
146 # This function is run when shutil.rmtree fails.
147 # 99.9% of the time it initially fails to remove
148 # a file in the directory, so the first time through
149 # func is os.remove.
150 # However, some Linux machines running ZFS on
151 # FUSE experienced a failure earlier in the process
152 # at os.listdir. The first failure may legally
153 # be either.
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000154 if self.errorState == 0:
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000155 if func is os.remove:
156 self.assertEqual(arg, self.childpath)
157 else:
158 self.assertIs(func, os.listdir,
159 "func must be either os.remove or os.listdir")
160 self.assertEqual(arg, TESTFN)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000161 self.assertTrue(issubclass(exc[0], OSError))
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000162 self.errorState = 1
163 else:
164 self.assertEqual(func, os.rmdir)
165 self.assertEqual(arg, TESTFN)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000166 self.assertTrue(issubclass(exc[0], OSError))
Johannes Gijsbers8e6f2de2004-11-23 09:27:27 +0000167 self.errorState = 2
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000168
Antoine Pitrou78091e62011-12-29 18:54:15 +0100169 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
170 @support.skip_unless_symlink
171 def test_copymode_follow_symlinks(self):
172 tmp_dir = self.mkdtemp()
173 src = os.path.join(tmp_dir, 'foo')
174 dst = os.path.join(tmp_dir, 'bar')
175 src_link = os.path.join(tmp_dir, 'baz')
176 dst_link = os.path.join(tmp_dir, 'quux')
177 write_file(src, 'foo')
178 write_file(dst, 'foo')
179 os.symlink(src, src_link)
180 os.symlink(dst, dst_link)
181 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
182 # file to file
183 os.chmod(dst, stat.S_IRWXO)
184 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
185 shutil.copymode(src, dst)
186 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
187 # follow src link
188 os.chmod(dst, stat.S_IRWXO)
189 shutil.copymode(src_link, dst)
190 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
191 # follow dst link
192 os.chmod(dst, stat.S_IRWXO)
193 shutil.copymode(src, dst_link)
194 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
195 # follow both links
196 os.chmod(dst, stat.S_IRWXO)
197 shutil.copymode(src_link, dst)
198 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
199
200 @unittest.skipUnless(hasattr(os, 'lchmod'), 'requires os.lchmod')
201 @support.skip_unless_symlink
202 def test_copymode_symlink_to_symlink(self):
203 tmp_dir = self.mkdtemp()
204 src = os.path.join(tmp_dir, 'foo')
205 dst = os.path.join(tmp_dir, 'bar')
206 src_link = os.path.join(tmp_dir, 'baz')
207 dst_link = os.path.join(tmp_dir, 'quux')
208 write_file(src, 'foo')
209 write_file(dst, 'foo')
210 os.symlink(src, src_link)
211 os.symlink(dst, dst_link)
212 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
213 os.chmod(dst, stat.S_IRWXU)
214 os.lchmod(src_link, stat.S_IRWXO|stat.S_IRWXG)
215 # link to link
216 os.lchmod(dst_link, stat.S_IRWXO)
217 shutil.copymode(src_link, dst_link, symlinks=True)
218 self.assertEqual(os.lstat(src_link).st_mode,
219 os.lstat(dst_link).st_mode)
220 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
221 # src link - use chmod
222 os.lchmod(dst_link, stat.S_IRWXO)
223 shutil.copymode(src_link, dst, symlinks=True)
224 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
225 # dst link - use chmod
226 os.lchmod(dst_link, stat.S_IRWXO)
227 shutil.copymode(src, dst_link, symlinks=True)
228 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
229
230 @unittest.skipIf(hasattr(os, 'lchmod'), 'requires os.lchmod to be missing')
231 @support.skip_unless_symlink
232 def test_copymode_symlink_to_symlink_wo_lchmod(self):
233 tmp_dir = self.mkdtemp()
234 src = os.path.join(tmp_dir, 'foo')
235 dst = os.path.join(tmp_dir, 'bar')
236 src_link = os.path.join(tmp_dir, 'baz')
237 dst_link = os.path.join(tmp_dir, 'quux')
238 write_file(src, 'foo')
239 write_file(dst, 'foo')
240 os.symlink(src, src_link)
241 os.symlink(dst, dst_link)
242 shutil.copymode(src_link, dst_link, symlinks=True) # silent fail
243
244 @support.skip_unless_symlink
245 def test_copystat_symlinks(self):
246 tmp_dir = self.mkdtemp()
247 src = os.path.join(tmp_dir, 'foo')
248 dst = os.path.join(tmp_dir, 'bar')
249 src_link = os.path.join(tmp_dir, 'baz')
250 dst_link = os.path.join(tmp_dir, 'qux')
251 write_file(src, 'foo')
252 src_stat = os.stat(src)
253 os.utime(src, (src_stat.st_atime,
254 src_stat.st_mtime - 42.0)) # ensure different mtimes
255 write_file(dst, 'bar')
256 self.assertNotEqual(os.stat(src).st_mtime, os.stat(dst).st_mtime)
257 os.symlink(src, src_link)
258 os.symlink(dst, dst_link)
259 if hasattr(os, 'lchmod'):
260 os.lchmod(src_link, stat.S_IRWXO)
261 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
262 os.lchflags(src_link, stat.UF_NODUMP)
263 src_link_stat = os.lstat(src_link)
264 # follow
265 if hasattr(os, 'lchmod'):
266 shutil.copystat(src_link, dst_link, symlinks=False)
267 self.assertNotEqual(src_link_stat.st_mode, os.stat(dst).st_mode)
268 # don't follow
269 shutil.copystat(src_link, dst_link, symlinks=True)
270 dst_link_stat = os.lstat(dst_link)
271 if hasattr(os, 'lutimes'):
272 for attr in 'st_atime', 'st_mtime':
273 # The modification times may be truncated in the new file.
274 self.assertLessEqual(getattr(src_link_stat, attr),
275 getattr(dst_link_stat, attr) + 1)
276 if hasattr(os, 'lchmod'):
277 self.assertEqual(src_link_stat.st_mode, dst_link_stat.st_mode)
278 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
279 self.assertEqual(src_link_stat.st_flags, dst_link_stat.st_flags)
280 # tell to follow but dst is not a link
281 shutil.copystat(src_link, dst, symlinks=True)
282 self.assertTrue(abs(os.stat(src).st_mtime - os.stat(dst).st_mtime) <
283 00000.1)
284
285 @support.skip_unless_symlink
286 def test_copy_symlinks(self):
287 tmp_dir = self.mkdtemp()
288 src = os.path.join(tmp_dir, 'foo')
289 dst = os.path.join(tmp_dir, 'bar')
290 src_link = os.path.join(tmp_dir, 'baz')
291 write_file(src, 'foo')
292 os.symlink(src, src_link)
293 if hasattr(os, 'lchmod'):
294 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
295 # don't follow
296 shutil.copy(src_link, dst, symlinks=False)
297 self.assertFalse(os.path.islink(dst))
298 self.assertEqual(read_file(src), read_file(dst))
299 os.remove(dst)
300 # follow
301 shutil.copy(src_link, dst, symlinks=True)
302 self.assertTrue(os.path.islink(dst))
303 self.assertEqual(os.readlink(dst), os.readlink(src_link))
304 if hasattr(os, 'lchmod'):
305 self.assertEqual(os.lstat(src_link).st_mode,
306 os.lstat(dst).st_mode)
307
308 @support.skip_unless_symlink
309 def test_copy2_symlinks(self):
310 tmp_dir = self.mkdtemp()
311 src = os.path.join(tmp_dir, 'foo')
312 dst = os.path.join(tmp_dir, 'bar')
313 src_link = os.path.join(tmp_dir, 'baz')
314 write_file(src, 'foo')
315 os.symlink(src, src_link)
316 if hasattr(os, 'lchmod'):
317 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
318 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
319 os.lchflags(src_link, stat.UF_NODUMP)
320 src_stat = os.stat(src)
321 src_link_stat = os.lstat(src_link)
322 # follow
323 shutil.copy2(src_link, dst, symlinks=False)
324 self.assertFalse(os.path.islink(dst))
325 self.assertEqual(read_file(src), read_file(dst))
326 os.remove(dst)
327 # don't follow
328 shutil.copy2(src_link, dst, symlinks=True)
329 self.assertTrue(os.path.islink(dst))
330 self.assertEqual(os.readlink(dst), os.readlink(src_link))
331 dst_stat = os.lstat(dst)
332 if hasattr(os, 'lutimes'):
333 for attr in 'st_atime', 'st_mtime':
334 # The modification times may be truncated in the new file.
335 self.assertLessEqual(getattr(src_link_stat, attr),
336 getattr(dst_stat, attr) + 1)
337 if hasattr(os, 'lchmod'):
338 self.assertEqual(src_link_stat.st_mode, dst_stat.st_mode)
339 self.assertNotEqual(src_stat.st_mode, dst_stat.st_mode)
340 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
341 self.assertEqual(src_link_stat.st_flags, dst_stat.st_flags)
342
343 @support.skip_unless_symlink
344 def test_copyfile_symlinks(self):
345 tmp_dir = self.mkdtemp()
346 src = os.path.join(tmp_dir, 'src')
347 dst = os.path.join(tmp_dir, 'dst')
348 dst_link = os.path.join(tmp_dir, 'dst_link')
349 link = os.path.join(tmp_dir, 'link')
350 write_file(src, 'foo')
351 os.symlink(src, link)
352 # don't follow
353 shutil.copyfile(link, dst_link, symlinks=True)
354 self.assertTrue(os.path.islink(dst_link))
355 self.assertEqual(os.readlink(link), os.readlink(dst_link))
356 # follow
357 shutil.copyfile(link, dst)
358 self.assertFalse(os.path.islink(dst))
359
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000360 def test_rmtree_dont_delete_file(self):
361 # When called on a file instead of a directory, don't delete it.
362 handle, path = tempfile.mkstemp()
Victor Stinnerbf816222011-06-30 23:25:47 +0200363 os.close(handle)
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000364 self.assertRaises(OSError, shutil.rmtree, path)
365 os.remove(path)
366
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000367 def test_copytree_simple(self):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000368 src_dir = tempfile.mkdtemp()
369 dst_dir = os.path.join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200370 self.addCleanup(shutil.rmtree, src_dir)
371 self.addCleanup(shutil.rmtree, os.path.dirname(dst_dir))
372 write_file((src_dir, 'test.txt'), '123')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000373 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200374 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000375
Éric Araujoa7e33a12011-08-12 19:51:35 +0200376 shutil.copytree(src_dir, dst_dir)
377 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test.txt')))
378 self.assertTrue(os.path.isdir(os.path.join(dst_dir, 'test_dir')))
379 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test_dir',
380 'test.txt')))
381 actual = read_file((dst_dir, 'test.txt'))
382 self.assertEqual(actual, '123')
383 actual = read_file((dst_dir, 'test_dir', 'test.txt'))
384 self.assertEqual(actual, '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000385
Antoine Pitrou78091e62011-12-29 18:54:15 +0100386 @support.skip_unless_symlink
387 def test_copytree_symlinks(self):
388 tmp_dir = self.mkdtemp()
389 src_dir = os.path.join(tmp_dir, 'src')
390 dst_dir = os.path.join(tmp_dir, 'dst')
391 sub_dir = os.path.join(src_dir, 'sub')
392 os.mkdir(src_dir)
393 os.mkdir(sub_dir)
394 write_file((src_dir, 'file.txt'), 'foo')
395 src_link = os.path.join(sub_dir, 'link')
396 dst_link = os.path.join(dst_dir, 'sub/link')
397 os.symlink(os.path.join(src_dir, 'file.txt'),
398 src_link)
399 if hasattr(os, 'lchmod'):
400 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
401 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
402 os.lchflags(src_link, stat.UF_NODUMP)
403 src_stat = os.lstat(src_link)
404 shutil.copytree(src_dir, dst_dir, symlinks=True)
405 self.assertTrue(os.path.islink(os.path.join(dst_dir, 'sub', 'link')))
406 self.assertEqual(os.readlink(os.path.join(dst_dir, 'sub', 'link')),
407 os.path.join(src_dir, 'file.txt'))
408 dst_stat = os.lstat(dst_link)
409 if hasattr(os, 'lchmod'):
410 self.assertEqual(dst_stat.st_mode, src_stat.st_mode)
411 if hasattr(os, 'lchflags'):
412 self.assertEqual(dst_stat.st_flags, src_stat.st_flags)
413
Georg Brandl2ee470f2008-07-16 12:55:28 +0000414 def test_copytree_with_exclude(self):
Georg Brandl2ee470f2008-07-16 12:55:28 +0000415 # creating data
416 join = os.path.join
417 exists = os.path.exists
418 src_dir = tempfile.mkdtemp()
Georg Brandl2ee470f2008-07-16 12:55:28 +0000419 try:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000420 dst_dir = join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200421 write_file((src_dir, 'test.txt'), '123')
422 write_file((src_dir, 'test.tmp'), '123')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000423 os.mkdir(join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200424 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000425 os.mkdir(join(src_dir, 'test_dir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200426 write_file((src_dir, 'test_dir2', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000427 os.mkdir(join(src_dir, 'test_dir2', 'subdir'))
428 os.mkdir(join(src_dir, 'test_dir2', 'subdir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200429 write_file((src_dir, 'test_dir2', 'subdir', 'test.txt'), '456')
430 write_file((src_dir, 'test_dir2', 'subdir2', 'test.py'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000431
432 # testing glob-like patterns
433 try:
434 patterns = shutil.ignore_patterns('*.tmp', 'test_dir2')
435 shutil.copytree(src_dir, dst_dir, ignore=patterns)
436 # checking the result: some elements should not be copied
437 self.assertTrue(exists(join(dst_dir, 'test.txt')))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200438 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
439 self.assertFalse(exists(join(dst_dir, 'test_dir2')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000440 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200441 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000442 try:
443 patterns = shutil.ignore_patterns('*.tmp', 'subdir*')
444 shutil.copytree(src_dir, dst_dir, ignore=patterns)
445 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200446 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
447 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2')))
448 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000449 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200450 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000451
452 # testing callable-style
453 try:
454 def _filter(src, names):
455 res = []
456 for name in names:
457 path = os.path.join(src, name)
458
459 if (os.path.isdir(path) and
460 path.split()[-1] == 'subdir'):
461 res.append(name)
462 elif os.path.splitext(path)[-1] in ('.py'):
463 res.append(name)
464 return res
465
466 shutil.copytree(src_dir, dst_dir, ignore=_filter)
467
468 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200469 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2',
470 'test.py')))
471 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000472
473 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200474 shutil.rmtree(dst_dir)
Georg Brandl2ee470f2008-07-16 12:55:28 +0000475 finally:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000476 shutil.rmtree(src_dir)
477 shutil.rmtree(os.path.dirname(dst_dir))
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000478
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000479 @unittest.skipUnless(hasattr(os, 'link'), 'requires os.link')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000480 def test_dont_copy_file_onto_link_to_itself(self):
Georg Brandl724d0892010-12-05 07:51:39 +0000481 # Temporarily disable test on Windows.
482 if os.name == 'nt':
483 return
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000484 # bug 851123.
485 os.mkdir(TESTFN)
486 src = os.path.join(TESTFN, 'cheese')
487 dst = os.path.join(TESTFN, 'shop')
488 try:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000489 with open(src, 'w') as f:
490 f.write('cheddar')
491 os.link(src, dst)
492 self.assertRaises(shutil.Error, shutil.copyfile, src, dst)
493 with open(src, 'r') as f:
494 self.assertEqual(f.read(), 'cheddar')
495 os.remove(dst)
496 finally:
497 shutil.rmtree(TESTFN, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000498
Brian Curtin3b4499c2010-12-28 14:31:47 +0000499 @support.skip_unless_symlink
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000500 def test_dont_copy_file_onto_symlink_to_itself(self):
501 # bug 851123.
502 os.mkdir(TESTFN)
503 src = os.path.join(TESTFN, 'cheese')
504 dst = os.path.join(TESTFN, 'shop')
505 try:
506 with open(src, 'w') as f:
507 f.write('cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000508 # Using `src` here would mean we end up with a symlink pointing
509 # to TESTFN/TESTFN/cheese, while it should point at
510 # TESTFN/cheese.
511 os.symlink('cheese', dst)
512 self.assertRaises(shutil.Error, shutil.copyfile, src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +0000513 with open(src, 'r') as f:
514 self.assertEqual(f.read(), 'cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000515 os.remove(dst)
516 finally:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000517 shutil.rmtree(TESTFN, ignore_errors=True)
Johannes Gijsbers68128712004-08-14 13:57:08 +0000518
Brian Curtin3b4499c2010-12-28 14:31:47 +0000519 @support.skip_unless_symlink
Brian Curtind40e6f72010-07-08 21:39:08 +0000520 def test_rmtree_on_symlink(self):
521 # bug 1669.
522 os.mkdir(TESTFN)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000523 try:
Brian Curtind40e6f72010-07-08 21:39:08 +0000524 src = os.path.join(TESTFN, 'cheese')
525 dst = os.path.join(TESTFN, 'shop')
526 os.mkdir(src)
527 os.symlink(src, dst)
528 self.assertRaises(OSError, shutil.rmtree, dst)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000529 finally:
Brian Curtind40e6f72010-07-08 21:39:08 +0000530 shutil.rmtree(TESTFN, ignore_errors=True)
531
532 if hasattr(os, "mkfifo"):
533 # Issue #3002: copyfile and copytree block indefinitely on named pipes
534 def test_copyfile_named_pipe(self):
535 os.mkfifo(TESTFN)
536 try:
537 self.assertRaises(shutil.SpecialFileError,
538 shutil.copyfile, TESTFN, TESTFN2)
539 self.assertRaises(shutil.SpecialFileError,
540 shutil.copyfile, __file__, TESTFN)
541 finally:
542 os.remove(TESTFN)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000543
Brian Curtin3b4499c2010-12-28 14:31:47 +0000544 @support.skip_unless_symlink
Brian Curtin52173d42010-12-02 18:29:18 +0000545 def test_copytree_named_pipe(self):
546 os.mkdir(TESTFN)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000547 try:
Brian Curtin52173d42010-12-02 18:29:18 +0000548 subdir = os.path.join(TESTFN, "subdir")
549 os.mkdir(subdir)
550 pipe = os.path.join(subdir, "mypipe")
551 os.mkfifo(pipe)
552 try:
553 shutil.copytree(TESTFN, TESTFN2)
554 except shutil.Error as e:
555 errors = e.args[0]
556 self.assertEqual(len(errors), 1)
557 src, dst, error_msg = errors[0]
558 self.assertEqual("`%s` is a named pipe" % pipe, error_msg)
559 else:
560 self.fail("shutil.Error should have been raised")
561 finally:
562 shutil.rmtree(TESTFN, ignore_errors=True)
563 shutil.rmtree(TESTFN2, ignore_errors=True)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000564
Tarek Ziadé5340db32010-04-19 22:30:51 +0000565 def test_copytree_special_func(self):
566
567 src_dir = self.mkdtemp()
568 dst_dir = os.path.join(self.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200569 write_file((src_dir, 'test.txt'), '123')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000570 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200571 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000572
573 copied = []
574 def _copy(src, dst):
575 copied.append((src, dst))
576
577 shutil.copytree(src_dir, dst_dir, copy_function=_copy)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000578 self.assertEqual(len(copied), 2)
Tarek Ziadé5340db32010-04-19 22:30:51 +0000579
Brian Curtin3b4499c2010-12-28 14:31:47 +0000580 @support.skip_unless_symlink
Tarek Ziadéfb437512010-04-20 08:57:33 +0000581 def test_copytree_dangling_symlinks(self):
582
583 # a dangling symlink raises an error at the end
584 src_dir = self.mkdtemp()
585 dst_dir = os.path.join(self.mkdtemp(), 'destination')
586 os.symlink('IDONTEXIST', os.path.join(src_dir, 'test.txt'))
587 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200588 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadéfb437512010-04-20 08:57:33 +0000589 self.assertRaises(Error, shutil.copytree, src_dir, dst_dir)
590
591 # a dangling symlink is ignored with the proper flag
592 dst_dir = os.path.join(self.mkdtemp(), 'destination2')
593 shutil.copytree(src_dir, dst_dir, ignore_dangling_symlinks=True)
594 self.assertNotIn('test.txt', os.listdir(dst_dir))
595
596 # a dangling symlink is copied if symlinks=True
597 dst_dir = os.path.join(self.mkdtemp(), 'destination3')
598 shutil.copytree(src_dir, dst_dir, symlinks=True)
599 self.assertIn('test.txt', os.listdir(dst_dir))
600
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400601 def _copy_file(self, method):
602 fname = 'test.txt'
603 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200604 write_file((tmpdir, fname), 'xxx')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400605 file1 = os.path.join(tmpdir, fname)
606 tmpdir2 = self.mkdtemp()
607 method(file1, tmpdir2)
608 file2 = os.path.join(tmpdir2, fname)
609 return (file1, file2)
610
611 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
612 def test_copy(self):
613 # Ensure that the copied file exists and has the same mode bits.
614 file1, file2 = self._copy_file(shutil.copy)
615 self.assertTrue(os.path.exists(file2))
616 self.assertEqual(os.stat(file1).st_mode, os.stat(file2).st_mode)
617
618 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
Senthil Kumaran0c2dba52011-07-03 18:21:38 -0700619 @unittest.skipUnless(hasattr(os, 'utime'), 'requires os.utime')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400620 def test_copy2(self):
621 # Ensure that the copied file exists and has the same mode and
622 # modification time bits.
623 file1, file2 = self._copy_file(shutil.copy2)
624 self.assertTrue(os.path.exists(file2))
625 file1_stat = os.stat(file1)
626 file2_stat = os.stat(file2)
627 self.assertEqual(file1_stat.st_mode, file2_stat.st_mode)
628 for attr in 'st_atime', 'st_mtime':
629 # The modification times may be truncated in the new file.
630 self.assertLessEqual(getattr(file1_stat, attr),
631 getattr(file2_stat, attr) + 1)
632 if hasattr(os, 'chflags') and hasattr(file1_stat, 'st_flags'):
633 self.assertEqual(getattr(file1_stat, 'st_flags'),
634 getattr(file2_stat, 'st_flags'))
635
Ezio Melotti975077a2011-05-19 22:03:22 +0300636 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000637 def test_make_tarball(self):
638 # creating something to tar
639 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200640 write_file((tmpdir, 'file1'), 'xxx')
641 write_file((tmpdir, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000642 os.mkdir(os.path.join(tmpdir, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200643 write_file((tmpdir, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000644
645 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400646 # force shutil to create the directory
647 os.rmdir(tmpdir2)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000648 unittest.skipUnless(splitdrive(tmpdir)[0] == splitdrive(tmpdir2)[0],
649 "source and target should be on same drive")
650
651 base_name = os.path.join(tmpdir2, 'archive')
652
653 # working with relative paths to avoid tar warnings
654 old_dir = os.getcwd()
655 os.chdir(tmpdir)
656 try:
657 _make_tarball(splitdrive(base_name)[1], '.')
658 finally:
659 os.chdir(old_dir)
660
661 # check if the compressed tarball was created
662 tarball = base_name + '.tar.gz'
663 self.assertTrue(os.path.exists(tarball))
664
665 # trying an uncompressed one
666 base_name = os.path.join(tmpdir2, 'archive')
667 old_dir = os.getcwd()
668 os.chdir(tmpdir)
669 try:
670 _make_tarball(splitdrive(base_name)[1], '.', compress=None)
671 finally:
672 os.chdir(old_dir)
673 tarball = base_name + '.tar'
674 self.assertTrue(os.path.exists(tarball))
675
676 def _tarinfo(self, path):
677 tar = tarfile.open(path)
678 try:
679 names = tar.getnames()
680 names.sort()
681 return tuple(names)
682 finally:
683 tar.close()
684
685 def _create_files(self):
686 # creating something to tar
687 tmpdir = self.mkdtemp()
688 dist = os.path.join(tmpdir, 'dist')
689 os.mkdir(dist)
Éric Araujoa7e33a12011-08-12 19:51:35 +0200690 write_file((dist, 'file1'), 'xxx')
691 write_file((dist, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000692 os.mkdir(os.path.join(dist, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200693 write_file((dist, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000694 os.mkdir(os.path.join(dist, 'sub2'))
695 tmpdir2 = self.mkdtemp()
696 base_name = os.path.join(tmpdir2, 'archive')
697 return tmpdir, tmpdir2, base_name
698
Ezio Melotti975077a2011-05-19 22:03:22 +0300699 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000700 @unittest.skipUnless(find_executable('tar') and find_executable('gzip'),
701 'Need the tar command to run')
702 def test_tarfile_vs_tar(self):
703 tmpdir, tmpdir2, base_name = self._create_files()
704 old_dir = os.getcwd()
705 os.chdir(tmpdir)
706 try:
707 _make_tarball(base_name, 'dist')
708 finally:
709 os.chdir(old_dir)
710
711 # check if the compressed tarball was created
712 tarball = base_name + '.tar.gz'
713 self.assertTrue(os.path.exists(tarball))
714
715 # now create another tarball using `tar`
716 tarball2 = os.path.join(tmpdir, 'archive2.tar.gz')
717 tar_cmd = ['tar', '-cf', 'archive2.tar', 'dist']
718 gzip_cmd = ['gzip', '-f9', 'archive2.tar']
719 old_dir = os.getcwd()
720 os.chdir(tmpdir)
721 try:
722 with captured_stdout() as s:
723 spawn(tar_cmd)
724 spawn(gzip_cmd)
725 finally:
726 os.chdir(old_dir)
727
728 self.assertTrue(os.path.exists(tarball2))
729 # let's compare both tarballs
Ezio Melottib3aedd42010-11-20 19:04:17 +0000730 self.assertEqual(self._tarinfo(tarball), self._tarinfo(tarball2))
Tarek Ziadé396fad72010-02-23 05:30:31 +0000731
732 # trying an uncompressed one
733 base_name = os.path.join(tmpdir2, 'archive')
734 old_dir = os.getcwd()
735 os.chdir(tmpdir)
736 try:
737 _make_tarball(base_name, 'dist', compress=None)
738 finally:
739 os.chdir(old_dir)
740 tarball = base_name + '.tar'
741 self.assertTrue(os.path.exists(tarball))
742
743 # now for a dry_run
744 base_name = os.path.join(tmpdir2, 'archive')
745 old_dir = os.getcwd()
746 os.chdir(tmpdir)
747 try:
748 _make_tarball(base_name, 'dist', compress=None, dry_run=True)
749 finally:
750 os.chdir(old_dir)
751 tarball = base_name + '.tar'
752 self.assertTrue(os.path.exists(tarball))
753
Ezio Melotti975077a2011-05-19 22:03:22 +0300754 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000755 @unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run')
756 def test_make_zipfile(self):
757 # creating something to tar
758 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200759 write_file((tmpdir, 'file1'), 'xxx')
760 write_file((tmpdir, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000761
762 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400763 # force shutil to create the directory
764 os.rmdir(tmpdir2)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000765 base_name = os.path.join(tmpdir2, 'archive')
766 _make_zipfile(base_name, tmpdir)
767
768 # check if the compressed tarball was created
769 tarball = base_name + '.zip'
Éric Araujo1c505492010-11-06 02:12:51 +0000770 self.assertTrue(os.path.exists(tarball))
Tarek Ziadé396fad72010-02-23 05:30:31 +0000771
772
773 def test_make_archive(self):
774 tmpdir = self.mkdtemp()
775 base_name = os.path.join(tmpdir, 'archive')
776 self.assertRaises(ValueError, make_archive, base_name, 'xxx')
777
Ezio Melotti975077a2011-05-19 22:03:22 +0300778 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000779 def test_make_archive_owner_group(self):
780 # testing make_archive with owner and group, with various combinations
781 # this works even if there's not gid/uid support
782 if UID_GID_SUPPORT:
783 group = grp.getgrgid(0)[0]
784 owner = pwd.getpwuid(0)[0]
785 else:
786 group = owner = 'root'
787
788 base_dir, root_dir, base_name = self._create_files()
789 base_name = os.path.join(self.mkdtemp() , 'archive')
790 res = make_archive(base_name, 'zip', root_dir, base_dir, owner=owner,
791 group=group)
792 self.assertTrue(os.path.exists(res))
793
794 res = make_archive(base_name, 'zip', root_dir, base_dir)
795 self.assertTrue(os.path.exists(res))
796
797 res = make_archive(base_name, 'tar', root_dir, base_dir,
798 owner=owner, group=group)
799 self.assertTrue(os.path.exists(res))
800
801 res = make_archive(base_name, 'tar', root_dir, base_dir,
802 owner='kjhkjhkjg', group='oihohoh')
803 self.assertTrue(os.path.exists(res))
804
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000805
Ezio Melotti975077a2011-05-19 22:03:22 +0300806 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000807 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
808 def test_tarfile_root_owner(self):
809 tmpdir, tmpdir2, base_name = self._create_files()
810 old_dir = os.getcwd()
811 os.chdir(tmpdir)
812 group = grp.getgrgid(0)[0]
813 owner = pwd.getpwuid(0)[0]
814 try:
815 archive_name = _make_tarball(base_name, 'dist', compress=None,
816 owner=owner, group=group)
817 finally:
818 os.chdir(old_dir)
819
820 # check if the compressed tarball was created
821 self.assertTrue(os.path.exists(archive_name))
822
823 # now checks the rights
824 archive = tarfile.open(archive_name)
825 try:
826 for member in archive.getmembers():
Ezio Melottib3aedd42010-11-20 19:04:17 +0000827 self.assertEqual(member.uid, 0)
828 self.assertEqual(member.gid, 0)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000829 finally:
830 archive.close()
831
832 def test_make_archive_cwd(self):
833 current_dir = os.getcwd()
834 def _breaks(*args, **kw):
835 raise RuntimeError()
836
837 register_archive_format('xxx', _breaks, [], 'xxx file')
838 try:
839 try:
840 make_archive('xxx', 'xxx', root_dir=self.mkdtemp())
841 except Exception:
842 pass
Ezio Melottib3aedd42010-11-20 19:04:17 +0000843 self.assertEqual(os.getcwd(), current_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000844 finally:
845 unregister_archive_format('xxx')
846
847 def test_register_archive_format(self):
848
849 self.assertRaises(TypeError, register_archive_format, 'xxx', 1)
850 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
851 1)
852 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
853 [(1, 2), (1, 2, 3)])
854
855 register_archive_format('xxx', lambda: x, [(1, 2)], 'xxx file')
856 formats = [name for name, params in get_archive_formats()]
857 self.assertIn('xxx', formats)
858
859 unregister_archive_format('xxx')
860 formats = [name for name, params in get_archive_formats()]
861 self.assertNotIn('xxx', formats)
862
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000863 def _compare_dirs(self, dir1, dir2):
864 # check that dir1 and dir2 are equivalent,
865 # return the diff
866 diff = []
867 for root, dirs, files in os.walk(dir1):
868 for file_ in files:
869 path = os.path.join(root, file_)
870 target_path = os.path.join(dir2, os.path.split(path)[-1])
871 if not os.path.exists(target_path):
872 diff.append(file_)
873 return diff
874
Ezio Melotti975077a2011-05-19 22:03:22 +0300875 @requires_zlib
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000876 def test_unpack_archive(self):
Tarek Ziadéffa155a2010-04-29 13:34:35 +0000877 formats = ['tar', 'gztar', 'zip']
878 if BZ2_SUPPORTED:
879 formats.append('bztar')
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000880
Tarek Ziadéffa155a2010-04-29 13:34:35 +0000881 for format in formats:
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000882 tmpdir = self.mkdtemp()
883 base_dir, root_dir, base_name = self._create_files()
884 tmpdir2 = self.mkdtemp()
885 filename = make_archive(base_name, format, root_dir, base_dir)
886
887 # let's try to unpack it now
888 unpack_archive(filename, tmpdir2)
889 diff = self._compare_dirs(tmpdir, tmpdir2)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000890 self.assertEqual(diff, [])
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000891
Nick Coghlanabf202d2011-03-16 13:52:20 -0400892 # and again, this time with the format specified
893 tmpdir3 = self.mkdtemp()
894 unpack_archive(filename, tmpdir3, format=format)
895 diff = self._compare_dirs(tmpdir, tmpdir3)
896 self.assertEqual(diff, [])
897 self.assertRaises(shutil.ReadError, unpack_archive, TESTFN)
898 self.assertRaises(ValueError, unpack_archive, TESTFN, format='xxx')
899
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000900 def test_unpack_registery(self):
901
902 formats = get_unpack_formats()
903
904 def _boo(filename, extract_dir, extra):
Ezio Melottib3aedd42010-11-20 19:04:17 +0000905 self.assertEqual(extra, 1)
906 self.assertEqual(filename, 'stuff.boo')
907 self.assertEqual(extract_dir, 'xx')
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000908
909 register_unpack_format('Boo', ['.boo', '.b2'], _boo, [('extra', 1)])
910 unpack_archive('stuff.boo', 'xx')
911
912 # trying to register a .boo unpacker again
913 self.assertRaises(RegistryError, register_unpack_format, 'Boo2',
914 ['.boo'], _boo)
915
916 # should work now
917 unregister_unpack_format('Boo')
918 register_unpack_format('Boo2', ['.boo'], _boo)
919 self.assertIn(('Boo2', ['.boo'], ''), get_unpack_formats())
920 self.assertNotIn(('Boo', ['.boo'], ''), get_unpack_formats())
921
922 # let's leave a clean state
923 unregister_unpack_format('Boo2')
Ezio Melottib3aedd42010-11-20 19:04:17 +0000924 self.assertEqual(get_unpack_formats(), formats)
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000925
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +0200926 @unittest.skipUnless(hasattr(shutil, 'disk_usage'),
927 "disk_usage not available on this platform")
928 def test_disk_usage(self):
929 usage = shutil.disk_usage(os.getcwd())
Éric Araujo2ee61882011-07-02 16:45:45 +0200930 self.assertGreater(usage.total, 0)
931 self.assertGreater(usage.used, 0)
932 self.assertGreaterEqual(usage.free, 0)
933 self.assertGreaterEqual(usage.total, usage.used)
934 self.assertGreater(usage.total, usage.free)
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +0200935
Sandro Tosid902a142011-08-22 23:28:27 +0200936 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
937 @unittest.skipUnless(hasattr(os, 'chown'), 'requires os.chown')
938 def test_chown(self):
939
940 # cleaned-up automatically by TestShutil.tearDown method
941 dirname = self.mkdtemp()
942 filename = tempfile.mktemp(dir=dirname)
943 write_file(filename, 'testing chown function')
944
945 with self.assertRaises(ValueError):
946 shutil.chown(filename)
947
948 with self.assertRaises(LookupError):
949 shutil.chown(filename, user='non-exising username')
950
951 with self.assertRaises(LookupError):
952 shutil.chown(filename, group='non-exising groupname')
953
954 with self.assertRaises(TypeError):
955 shutil.chown(filename, b'spam')
956
957 with self.assertRaises(TypeError):
958 shutil.chown(filename, 3.14)
959
960 uid = os.getuid()
961 gid = os.getgid()
962
963 def check_chown(path, uid=None, gid=None):
964 s = os.stat(filename)
965 if uid is not None:
966 self.assertEqual(uid, s.st_uid)
967 if gid is not None:
968 self.assertEqual(gid, s.st_gid)
969
970 shutil.chown(filename, uid, gid)
971 check_chown(filename, uid, gid)
972 shutil.chown(filename, uid)
973 check_chown(filename, uid)
974 shutil.chown(filename, user=uid)
975 check_chown(filename, uid)
976 shutil.chown(filename, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +0200977 check_chown(filename, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +0200978
979 shutil.chown(dirname, uid, gid)
980 check_chown(dirname, uid, gid)
981 shutil.chown(dirname, uid)
982 check_chown(dirname, uid)
983 shutil.chown(dirname, user=uid)
984 check_chown(dirname, uid)
985 shutil.chown(dirname, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +0200986 check_chown(dirname, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +0200987
988 user = pwd.getpwuid(uid)[0]
989 group = grp.getgrgid(gid)[0]
990 shutil.chown(filename, user, group)
991 check_chown(filename, uid, gid)
992 shutil.chown(dirname, user, group)
993 check_chown(dirname, uid, gid)
994
Christian Heimes9bd667a2008-01-20 15:14:11 +0000995
Christian Heimesada8c3b2008-03-18 18:26:33 +0000996class TestMove(unittest.TestCase):
997
998 def setUp(self):
999 filename = "foo"
1000 self.src_dir = tempfile.mkdtemp()
1001 self.dst_dir = tempfile.mkdtemp()
1002 self.src_file = os.path.join(self.src_dir, filename)
1003 self.dst_file = os.path.join(self.dst_dir, filename)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001004 with open(self.src_file, "wb") as f:
1005 f.write(b"spam")
1006
1007 def tearDown(self):
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001008 for d in (self.src_dir, self.dst_dir):
Christian Heimesada8c3b2008-03-18 18:26:33 +00001009 try:
1010 if d:
1011 shutil.rmtree(d)
1012 except:
1013 pass
1014
1015 def _check_move_file(self, src, dst, real_dst):
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001016 with open(src, "rb") as f:
1017 contents = f.read()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001018 shutil.move(src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001019 with open(real_dst, "rb") as f:
1020 self.assertEqual(contents, f.read())
Christian Heimesada8c3b2008-03-18 18:26:33 +00001021 self.assertFalse(os.path.exists(src))
1022
1023 def _check_move_dir(self, src, dst, real_dst):
1024 contents = sorted(os.listdir(src))
1025 shutil.move(src, dst)
1026 self.assertEqual(contents, sorted(os.listdir(real_dst)))
1027 self.assertFalse(os.path.exists(src))
1028
1029 def test_move_file(self):
1030 # Move a file to another location on the same filesystem.
1031 self._check_move_file(self.src_file, self.dst_file, self.dst_file)
1032
1033 def test_move_file_to_dir(self):
1034 # Move a file inside an existing dir on the same filesystem.
1035 self._check_move_file(self.src_file, self.dst_dir, self.dst_file)
1036
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001037 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001038 def test_move_file_other_fs(self):
1039 # Move a file to an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001040 self.test_move_file()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001041
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001042 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001043 def test_move_file_to_dir_other_fs(self):
1044 # Move a file to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001045 self.test_move_file_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001046
1047 def test_move_dir(self):
1048 # Move a dir to another location on the same filesystem.
1049 dst_dir = tempfile.mktemp()
1050 try:
1051 self._check_move_dir(self.src_dir, dst_dir, dst_dir)
1052 finally:
1053 try:
1054 shutil.rmtree(dst_dir)
1055 except:
1056 pass
1057
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001058 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001059 def test_move_dir_other_fs(self):
1060 # Move a dir to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001061 self.test_move_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001062
1063 def test_move_dir_to_dir(self):
1064 # Move a dir inside an existing dir on the same filesystem.
1065 self._check_move_dir(self.src_dir, self.dst_dir,
1066 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1067
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001068 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001069 def test_move_dir_to_dir_other_fs(self):
1070 # Move a dir inside an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001071 self.test_move_dir_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001072
1073 def test_existing_file_inside_dest_dir(self):
1074 # A file with the same name inside the destination dir already exists.
1075 with open(self.dst_file, "wb"):
1076 pass
1077 self.assertRaises(shutil.Error, shutil.move, self.src_file, self.dst_dir)
1078
1079 def test_dont_move_dir_in_itself(self):
1080 # Moving a dir inside itself raises an Error.
1081 dst = os.path.join(self.src_dir, "bar")
1082 self.assertRaises(shutil.Error, shutil.move, self.src_dir, dst)
1083
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001084 def test_destinsrc_false_negative(self):
1085 os.mkdir(TESTFN)
1086 try:
1087 for src, dst in [('srcdir', 'srcdir/dest')]:
1088 src = os.path.join(TESTFN, src)
1089 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001090 self.assertTrue(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001091 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001092 'dst (%s) is not in src (%s)' % (dst, src))
1093 finally:
1094 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001095
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001096 def test_destinsrc_false_positive(self):
1097 os.mkdir(TESTFN)
1098 try:
1099 for src, dst in [('srcdir', 'src/dest'), ('srcdir', 'srcdir.new')]:
1100 src = os.path.join(TESTFN, src)
1101 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001102 self.assertFalse(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001103 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001104 'dst (%s) is in src (%s)' % (dst, src))
1105 finally:
1106 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimes9bd667a2008-01-20 15:14:11 +00001107
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +01001108 @support.skip_unless_symlink
1109 @mock_rename
1110 def test_move_file_symlink(self):
1111 dst = os.path.join(self.src_dir, 'bar')
1112 os.symlink(self.src_file, dst)
1113 shutil.move(dst, self.dst_file)
1114 self.assertTrue(os.path.islink(self.dst_file))
1115 self.assertTrue(os.path.samefile(self.src_file, self.dst_file))
1116
1117 @support.skip_unless_symlink
1118 @mock_rename
1119 def test_move_file_symlink_to_dir(self):
1120 filename = "bar"
1121 dst = os.path.join(self.src_dir, filename)
1122 os.symlink(self.src_file, dst)
1123 shutil.move(dst, self.dst_dir)
1124 final_link = os.path.join(self.dst_dir, filename)
1125 self.assertTrue(os.path.islink(final_link))
1126 self.assertTrue(os.path.samefile(self.src_file, final_link))
1127
1128 @support.skip_unless_symlink
1129 @mock_rename
1130 def test_move_dangling_symlink(self):
1131 src = os.path.join(self.src_dir, 'baz')
1132 dst = os.path.join(self.src_dir, 'bar')
1133 os.symlink(src, dst)
1134 dst_link = os.path.join(self.dst_dir, 'quux')
1135 shutil.move(dst, dst_link)
1136 self.assertTrue(os.path.islink(dst_link))
1137 self.assertEqual(os.path.realpath(src), os.path.realpath(dst_link))
1138
1139 @support.skip_unless_symlink
1140 @mock_rename
1141 def test_move_dir_symlink(self):
1142 src = os.path.join(self.src_dir, 'baz')
1143 dst = os.path.join(self.src_dir, 'bar')
1144 os.mkdir(src)
1145 os.symlink(src, dst)
1146 dst_link = os.path.join(self.dst_dir, 'quux')
1147 shutil.move(dst, dst_link)
1148 self.assertTrue(os.path.islink(dst_link))
1149 self.assertTrue(os.path.samefile(src, dst_link))
1150
Tarek Ziadé5340db32010-04-19 22:30:51 +00001151
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001152class TestCopyFile(unittest.TestCase):
1153
1154 _delete = False
1155
1156 class Faux(object):
1157 _entered = False
1158 _exited_with = None
1159 _raised = False
1160 def __init__(self, raise_in_exit=False, suppress_at_exit=True):
1161 self._raise_in_exit = raise_in_exit
1162 self._suppress_at_exit = suppress_at_exit
1163 def read(self, *args):
1164 return ''
1165 def __enter__(self):
1166 self._entered = True
1167 def __exit__(self, exc_type, exc_val, exc_tb):
1168 self._exited_with = exc_type, exc_val, exc_tb
1169 if self._raise_in_exit:
1170 self._raised = True
1171 raise IOError("Cannot close")
1172 return self._suppress_at_exit
1173
1174 def tearDown(self):
1175 if self._delete:
1176 del shutil.open
1177
1178 def _set_shutil_open(self, func):
1179 shutil.open = func
1180 self._delete = True
1181
1182 def test_w_source_open_fails(self):
1183 def _open(filename, mode='r'):
1184 if filename == 'srcfile':
1185 raise IOError('Cannot open "srcfile"')
1186 assert 0 # shouldn't reach here.
1187
1188 self._set_shutil_open(_open)
1189
1190 self.assertRaises(IOError, shutil.copyfile, 'srcfile', 'destfile')
1191
1192 def test_w_dest_open_fails(self):
1193
1194 srcfile = self.Faux()
1195
1196 def _open(filename, mode='r'):
1197 if filename == 'srcfile':
1198 return srcfile
1199 if filename == 'destfile':
1200 raise IOError('Cannot open "destfile"')
1201 assert 0 # shouldn't reach here.
1202
1203 self._set_shutil_open(_open)
1204
1205 shutil.copyfile('srcfile', 'destfile')
1206 self.assertTrue(srcfile._entered)
1207 self.assertTrue(srcfile._exited_with[0] is IOError)
1208 self.assertEqual(srcfile._exited_with[1].args,
1209 ('Cannot open "destfile"',))
1210
1211 def test_w_dest_close_fails(self):
1212
1213 srcfile = self.Faux()
1214 destfile = self.Faux(True)
1215
1216 def _open(filename, mode='r'):
1217 if filename == 'srcfile':
1218 return srcfile
1219 if filename == 'destfile':
1220 return destfile
1221 assert 0 # shouldn't reach here.
1222
1223 self._set_shutil_open(_open)
1224
1225 shutil.copyfile('srcfile', 'destfile')
1226 self.assertTrue(srcfile._entered)
1227 self.assertTrue(destfile._entered)
1228 self.assertTrue(destfile._raised)
1229 self.assertTrue(srcfile._exited_with[0] is IOError)
1230 self.assertEqual(srcfile._exited_with[1].args,
1231 ('Cannot close',))
1232
1233 def test_w_source_close_fails(self):
1234
1235 srcfile = self.Faux(True)
1236 destfile = self.Faux()
1237
1238 def _open(filename, mode='r'):
1239 if filename == 'srcfile':
1240 return srcfile
1241 if filename == 'destfile':
1242 return destfile
1243 assert 0 # shouldn't reach here.
1244
1245 self._set_shutil_open(_open)
1246
1247 self.assertRaises(IOError,
1248 shutil.copyfile, 'srcfile', 'destfile')
1249 self.assertTrue(srcfile._entered)
1250 self.assertTrue(destfile._entered)
1251 self.assertFalse(destfile._raised)
1252 self.assertTrue(srcfile._exited_with[0] is None)
1253 self.assertTrue(srcfile._raised)
1254
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001255 def test_move_dir_caseinsensitive(self):
1256 # Renames a folder to the same name
1257 # but a different case.
1258
1259 self.src_dir = tempfile.mkdtemp()
1260 dst_dir = os.path.join(
1261 os.path.dirname(self.src_dir),
1262 os.path.basename(self.src_dir).upper())
1263 self.assertNotEqual(self.src_dir, dst_dir)
1264
1265 try:
1266 shutil.move(self.src_dir, dst_dir)
1267 self.assertTrue(os.path.isdir(dst_dir))
1268 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +02001269 os.rmdir(dst_dir)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001270
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001271class TermsizeTests(unittest.TestCase):
1272 def test_does_not_crash(self):
1273 """Check if get_terminal_size() returns a meaningful value.
1274
1275 There's no easy portable way to actually check the size of the
1276 terminal, so let's check if it returns something sensible instead.
1277 """
1278 size = shutil.get_terminal_size()
Antoine Pitroucfade362012-02-08 23:48:59 +01001279 self.assertGreaterEqual(size.columns, 0)
1280 self.assertGreaterEqual(size.lines, 0)
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001281
1282 def test_os_environ_first(self):
1283 "Check if environment variables have precedence"
1284
1285 with support.EnvironmentVarGuard() as env:
1286 env['COLUMNS'] = '777'
1287 size = shutil.get_terminal_size()
1288 self.assertEqual(size.columns, 777)
1289
1290 with support.EnvironmentVarGuard() as env:
1291 env['LINES'] = '888'
1292 size = shutil.get_terminal_size()
1293 self.assertEqual(size.lines, 888)
1294
1295 @unittest.skipUnless(os.isatty(sys.__stdout__.fileno()), "not on tty")
1296 def test_stty_match(self):
1297 """Check if stty returns the same results ignoring env
1298
1299 This test will fail if stdin and stdout are connected to
1300 different terminals with different sizes. Nevertheless, such
1301 situations should be pretty rare.
1302 """
1303 try:
1304 size = subprocess.check_output(['stty', 'size']).decode().split()
1305 except (FileNotFoundError, subprocess.CalledProcessError):
1306 self.skipTest("stty invocation failed")
1307 expected = (int(size[1]), int(size[0])) # reversed order
1308
1309 with support.EnvironmentVarGuard() as env:
1310 del env['LINES']
1311 del env['COLUMNS']
1312 actual = shutil.get_terminal_size()
1313
1314 self.assertEqual(expected, actual)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001315
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001316
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001317def test_main():
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001318 support.run_unittest(TestShutil, TestMove, TestCopyFile,
1319 TermsizeTests)
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001320
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001321if __name__ == '__main__':
Walter Dörwald21d3a322003-05-01 17:45:56 +00001322 test_main()