blob: 59d83e8999103f38a1e5c4072fb4806ad205b611 [file] [log] [blame]
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001# Copyright (C) 2003 Python Software Foundation
2
3import unittest
4import shutil
5import tempfile
Johannes Gijsbers8e6f2de2004-11-23 09:27:27 +00006import sys
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +00007import stat
Brett Cannon1c3fa182004-06-19 21:11:35 +00008import os
9import os.path
Antoine Pitrouc041ab62012-01-02 19:18:02 +010010import errno
Nick Coghlan8ed3cf32011-03-16 14:05:35 -040011import functools
Antoine Pitroubcf2b592012-02-08 23:28:36 +010012import subprocess
Benjamin Petersonee8712c2008-05-20 21:35:26 +000013from test import support
14from test.support import TESTFN
Tarek Ziadé396fad72010-02-23 05:30:31 +000015from os.path import splitdrive
16from distutils.spawn import find_executable, spawn
17from shutil import (_make_tarball, _make_zipfile, make_archive,
18 register_archive_format, unregister_archive_format,
Tarek Ziadé6ac91722010-04-28 17:51:36 +000019 get_archive_formats, Error, unpack_archive,
20 register_unpack_format, RegistryError,
21 unregister_unpack_format, get_unpack_formats)
Tarek Ziadé396fad72010-02-23 05:30:31 +000022import tarfile
23import warnings
24
25from test import support
Ezio Melotti975077a2011-05-19 22:03:22 +030026from test.support import TESTFN, check_warnings, captured_stdout, requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +000027
Tarek Ziadéffa155a2010-04-29 13:34:35 +000028try:
29 import bz2
30 BZ2_SUPPORTED = True
31except ImportError:
32 BZ2_SUPPORTED = False
33
Antoine Pitrou7fff0962009-05-01 21:09:44 +000034TESTFN2 = TESTFN + "2"
Barry Warsaw7fc2cca2003-01-24 17:34:13 +000035
Tarek Ziadé396fad72010-02-23 05:30:31 +000036try:
37 import grp
38 import pwd
39 UID_GID_SUPPORT = True
40except ImportError:
41 UID_GID_SUPPORT = False
42
43try:
Tarek Ziadé396fad72010-02-23 05:30:31 +000044 import zipfile
45 ZIP_SUPPORT = True
46except ImportError:
47 ZIP_SUPPORT = find_executable('zip')
48
Nick Coghlan8ed3cf32011-03-16 14:05:35 -040049def _fake_rename(*args, **kwargs):
50 # Pretend the destination path is on a different filesystem.
Antoine Pitrouc041ab62012-01-02 19:18:02 +010051 raise OSError(getattr(errno, 'EXDEV', 18), "Invalid cross-device link")
Nick Coghlan8ed3cf32011-03-16 14:05:35 -040052
53def mock_rename(func):
54 @functools.wraps(func)
55 def wrap(*args, **kwargs):
56 try:
57 builtin_rename = os.rename
58 os.rename = _fake_rename
59 return func(*args, **kwargs)
60 finally:
61 os.rename = builtin_rename
62 return wrap
63
Éric Araujoa7e33a12011-08-12 19:51:35 +020064def write_file(path, content, binary=False):
65 """Write *content* to a file located at *path*.
66
67 If *path* is a tuple instead of a string, os.path.join will be used to
68 make a path. If *binary* is true, the file will be opened in binary
69 mode.
70 """
71 if isinstance(path, tuple):
72 path = os.path.join(*path)
73 with open(path, 'wb' if binary else 'w') as fp:
74 fp.write(content)
75
76def read_file(path, binary=False):
77 """Return contents from a file located at *path*.
78
79 If *path* is a tuple instead of a string, os.path.join will be used to
80 make a path. If *binary* is true, the file will be opened in binary
81 mode.
82 """
83 if isinstance(path, tuple):
84 path = os.path.join(*path)
85 with open(path, 'rb' if binary else 'r') as fp:
86 return fp.read()
87
88
Barry Warsaw7fc2cca2003-01-24 17:34:13 +000089class TestShutil(unittest.TestCase):
Tarek Ziadé396fad72010-02-23 05:30:31 +000090
91 def setUp(self):
92 super(TestShutil, self).setUp()
93 self.tempdirs = []
94
95 def tearDown(self):
96 super(TestShutil, self).tearDown()
97 while self.tempdirs:
98 d = self.tempdirs.pop()
99 shutil.rmtree(d, os.name in ('nt', 'cygwin'))
100
Tarek Ziadé396fad72010-02-23 05:30:31 +0000101
102 def mkdtemp(self):
103 """Create a temporary directory that will be cleaned up.
104
105 Returns the path of the directory.
106 """
107 d = tempfile.mkdtemp()
108 self.tempdirs.append(d)
109 return d
Tarek Ziadé5340db32010-04-19 22:30:51 +0000110
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000111 def test_rmtree_errors(self):
112 # filename is guaranteed not to exist
113 filename = tempfile.mktemp()
114 self.assertRaises(OSError, shutil.rmtree, filename)
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000115
Johannes Gijsbersb8b09d02004-12-06 20:50:15 +0000116 # See bug #1071513 for why we don't run this on cygwin
117 # and bug #1076467 for why we don't run this as root.
118 if (hasattr(os, 'chmod') and sys.platform[:6] != 'cygwin'
Johannes Gijsbers6b220b02004-12-12 15:52:57 +0000119 and not (hasattr(os, 'geteuid') and os.geteuid() == 0)):
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000120 def test_on_error(self):
121 self.errorState = 0
122 os.mkdir(TESTFN)
Tim Peters4590c002004-11-01 02:40:52 +0000123 self.childpath = os.path.join(TESTFN, 'a')
Victor Stinnerbf816222011-06-30 23:25:47 +0200124 support.create_empty_file(self.childpath)
Tim Peters4590c002004-11-01 02:40:52 +0000125 old_dir_mode = os.stat(TESTFN).st_mode
126 old_child_mode = os.stat(self.childpath).st_mode
127 # Make unwritable.
128 os.chmod(self.childpath, stat.S_IREAD)
129 os.chmod(TESTFN, stat.S_IREAD)
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000130
131 shutil.rmtree(TESTFN, onerror=self.check_args_to_onerror)
Johannes Gijsbers8e6f2de2004-11-23 09:27:27 +0000132 # Test whether onerror has actually been called.
Johannes Gijsbersb8b09d02004-12-06 20:50:15 +0000133 self.assertEqual(self.errorState, 2,
134 "Expected call to onerror function did not happen.")
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000135
Tim Peters4590c002004-11-01 02:40:52 +0000136 # Make writable again.
137 os.chmod(TESTFN, old_dir_mode)
138 os.chmod(self.childpath, old_child_mode)
139
140 # Clean up.
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000141 shutil.rmtree(TESTFN)
142
143 def check_args_to_onerror(self, func, arg, exc):
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000144 # test_rmtree_errors deliberately runs rmtree
145 # on a directory that is chmod 400, which will fail.
146 # This function is run when shutil.rmtree fails.
147 # 99.9% of the time it initially fails to remove
148 # a file in the directory, so the first time through
149 # func is os.remove.
150 # However, some Linux machines running ZFS on
151 # FUSE experienced a failure earlier in the process
152 # at os.listdir. The first failure may legally
153 # be either.
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000154 if self.errorState == 0:
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000155 if func is os.remove:
156 self.assertEqual(arg, self.childpath)
157 else:
158 self.assertIs(func, os.listdir,
159 "func must be either os.remove or os.listdir")
160 self.assertEqual(arg, TESTFN)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000161 self.assertTrue(issubclass(exc[0], OSError))
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000162 self.errorState = 1
163 else:
164 self.assertEqual(func, os.rmdir)
165 self.assertEqual(arg, TESTFN)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000166 self.assertTrue(issubclass(exc[0], OSError))
Johannes Gijsbers8e6f2de2004-11-23 09:27:27 +0000167 self.errorState = 2
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000168
Antoine Pitrou78091e62011-12-29 18:54:15 +0100169 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
170 @support.skip_unless_symlink
171 def test_copymode_follow_symlinks(self):
172 tmp_dir = self.mkdtemp()
173 src = os.path.join(tmp_dir, 'foo')
174 dst = os.path.join(tmp_dir, 'bar')
175 src_link = os.path.join(tmp_dir, 'baz')
176 dst_link = os.path.join(tmp_dir, 'quux')
177 write_file(src, 'foo')
178 write_file(dst, 'foo')
179 os.symlink(src, src_link)
180 os.symlink(dst, dst_link)
181 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
182 # file to file
183 os.chmod(dst, stat.S_IRWXO)
184 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
185 shutil.copymode(src, dst)
186 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
187 # follow src link
188 os.chmod(dst, stat.S_IRWXO)
189 shutil.copymode(src_link, dst)
190 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
191 # follow dst link
192 os.chmod(dst, stat.S_IRWXO)
193 shutil.copymode(src, dst_link)
194 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
195 # follow both links
196 os.chmod(dst, stat.S_IRWXO)
197 shutil.copymode(src_link, dst)
198 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
199
200 @unittest.skipUnless(hasattr(os, 'lchmod'), 'requires os.lchmod')
201 @support.skip_unless_symlink
202 def test_copymode_symlink_to_symlink(self):
203 tmp_dir = self.mkdtemp()
204 src = os.path.join(tmp_dir, 'foo')
205 dst = os.path.join(tmp_dir, 'bar')
206 src_link = os.path.join(tmp_dir, 'baz')
207 dst_link = os.path.join(tmp_dir, 'quux')
208 write_file(src, 'foo')
209 write_file(dst, 'foo')
210 os.symlink(src, src_link)
211 os.symlink(dst, dst_link)
212 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
213 os.chmod(dst, stat.S_IRWXU)
214 os.lchmod(src_link, stat.S_IRWXO|stat.S_IRWXG)
215 # link to link
216 os.lchmod(dst_link, stat.S_IRWXO)
217 shutil.copymode(src_link, dst_link, symlinks=True)
218 self.assertEqual(os.lstat(src_link).st_mode,
219 os.lstat(dst_link).st_mode)
220 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
221 # src link - use chmod
222 os.lchmod(dst_link, stat.S_IRWXO)
223 shutil.copymode(src_link, dst, symlinks=True)
224 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
225 # dst link - use chmod
226 os.lchmod(dst_link, stat.S_IRWXO)
227 shutil.copymode(src, dst_link, symlinks=True)
228 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
229
230 @unittest.skipIf(hasattr(os, 'lchmod'), 'requires os.lchmod to be missing')
231 @support.skip_unless_symlink
232 def test_copymode_symlink_to_symlink_wo_lchmod(self):
233 tmp_dir = self.mkdtemp()
234 src = os.path.join(tmp_dir, 'foo')
235 dst = os.path.join(tmp_dir, 'bar')
236 src_link = os.path.join(tmp_dir, 'baz')
237 dst_link = os.path.join(tmp_dir, 'quux')
238 write_file(src, 'foo')
239 write_file(dst, 'foo')
240 os.symlink(src, src_link)
241 os.symlink(dst, dst_link)
242 shutil.copymode(src_link, dst_link, symlinks=True) # silent fail
243
244 @support.skip_unless_symlink
245 def test_copystat_symlinks(self):
246 tmp_dir = self.mkdtemp()
247 src = os.path.join(tmp_dir, 'foo')
248 dst = os.path.join(tmp_dir, 'bar')
249 src_link = os.path.join(tmp_dir, 'baz')
250 dst_link = os.path.join(tmp_dir, 'qux')
251 write_file(src, 'foo')
252 src_stat = os.stat(src)
253 os.utime(src, (src_stat.st_atime,
254 src_stat.st_mtime - 42.0)) # ensure different mtimes
255 write_file(dst, 'bar')
256 self.assertNotEqual(os.stat(src).st_mtime, os.stat(dst).st_mtime)
257 os.symlink(src, src_link)
258 os.symlink(dst, dst_link)
259 if hasattr(os, 'lchmod'):
260 os.lchmod(src_link, stat.S_IRWXO)
261 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
262 os.lchflags(src_link, stat.UF_NODUMP)
263 src_link_stat = os.lstat(src_link)
264 # follow
265 if hasattr(os, 'lchmod'):
266 shutil.copystat(src_link, dst_link, symlinks=False)
267 self.assertNotEqual(src_link_stat.st_mode, os.stat(dst).st_mode)
268 # don't follow
269 shutil.copystat(src_link, dst_link, symlinks=True)
270 dst_link_stat = os.lstat(dst_link)
271 if hasattr(os, 'lutimes'):
272 for attr in 'st_atime', 'st_mtime':
273 # The modification times may be truncated in the new file.
274 self.assertLessEqual(getattr(src_link_stat, attr),
275 getattr(dst_link_stat, attr) + 1)
276 if hasattr(os, 'lchmod'):
277 self.assertEqual(src_link_stat.st_mode, dst_link_stat.st_mode)
278 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
279 self.assertEqual(src_link_stat.st_flags, dst_link_stat.st_flags)
280 # tell to follow but dst is not a link
281 shutil.copystat(src_link, dst, symlinks=True)
282 self.assertTrue(abs(os.stat(src).st_mtime - os.stat(dst).st_mtime) <
283 00000.1)
284
Ned Deilybaf75712012-05-10 17:05:19 -0700285 @unittest.skipUnless(hasattr(os, 'chflags') and
286 hasattr(errno, 'EOPNOTSUPP') and
287 hasattr(errno, 'ENOTSUP'),
288 "requires os.chflags, EOPNOTSUPP & ENOTSUP")
289 def test_copystat_handles_harmless_chflags_errors(self):
290 tmpdir = self.mkdtemp()
291 file1 = os.path.join(tmpdir, 'file1')
292 file2 = os.path.join(tmpdir, 'file2')
293 write_file(file1, 'xxx')
294 write_file(file2, 'xxx')
295
296 def make_chflags_raiser(err):
297 ex = OSError()
298
299 def _chflags_raiser(path, flags):
300 ex.errno = err
301 raise ex
302 return _chflags_raiser
303 old_chflags = os.chflags
304 try:
305 for err in errno.EOPNOTSUPP, errno.ENOTSUP:
306 os.chflags = make_chflags_raiser(err)
307 shutil.copystat(file1, file2)
308 # assert others errors break it
309 os.chflags = make_chflags_raiser(errno.EOPNOTSUPP + errno.ENOTSUP)
310 self.assertRaises(OSError, shutil.copystat, file1, file2)
311 finally:
312 os.chflags = old_chflags
313
Antoine Pitrou424246f2012-05-12 19:02:01 +0200314 @support.skip_unless_xattr
315 def test_copyxattr(self):
316 tmp_dir = self.mkdtemp()
317 src = os.path.join(tmp_dir, 'foo')
318 write_file(src, 'foo')
319 dst = os.path.join(tmp_dir, 'bar')
320 write_file(dst, 'bar')
321
322 # no xattr == no problem
323 shutil._copyxattr(src, dst)
324 # common case
325 os.setxattr(src, 'user.foo', b'42')
326 os.setxattr(src, 'user.bar', b'43')
327 shutil._copyxattr(src, dst)
328 self.assertEqual(os.listxattr(src), os.listxattr(dst))
329 self.assertEqual(
330 os.getxattr(src, 'user.foo'),
331 os.getxattr(dst, 'user.foo'))
332 # check errors don't affect other attrs
333 os.remove(dst)
334 write_file(dst, 'bar')
335 os_error = OSError(errno.EPERM, 'EPERM')
336
337 def _raise_on_user_foo(fname, attr, val):
338 if attr == 'user.foo':
339 raise os_error
340 else:
341 orig_setxattr(fname, attr, val)
342 try:
343 orig_setxattr = os.setxattr
344 os.setxattr = _raise_on_user_foo
345 shutil._copyxattr(src, dst)
346 self.assertEqual(['user.bar'], os.listxattr(dst))
347 finally:
348 os.setxattr = orig_setxattr
349
350 @support.skip_unless_symlink
351 @support.skip_unless_xattr
352 @unittest.skipUnless(hasattr(os, 'geteuid') and os.geteuid() == 0,
353 'root privileges required')
354 def test_copyxattr_symlinks(self):
355 # On Linux, it's only possible to access non-user xattr for symlinks;
356 # which in turn require root privileges. This test should be expanded
357 # as soon as other platforms gain support for extended attributes.
358 tmp_dir = self.mkdtemp()
359 src = os.path.join(tmp_dir, 'foo')
360 src_link = os.path.join(tmp_dir, 'baz')
361 write_file(src, 'foo')
362 os.symlink(src, src_link)
363 os.setxattr(src, 'trusted.foo', b'42')
364 os.lsetxattr(src_link, 'trusted.foo', b'43')
365 dst = os.path.join(tmp_dir, 'bar')
366 dst_link = os.path.join(tmp_dir, 'qux')
367 write_file(dst, 'bar')
368 os.symlink(dst, dst_link)
369 shutil._copyxattr(src_link, dst_link, symlinks=True)
370 self.assertEqual(os.lgetxattr(dst_link, 'trusted.foo'), b'43')
371 self.assertRaises(OSError, os.getxattr, dst, 'trusted.foo')
372 shutil._copyxattr(src_link, dst, symlinks=True)
373 self.assertEqual(os.getxattr(dst, 'trusted.foo'), b'43')
374
Antoine Pitrou78091e62011-12-29 18:54:15 +0100375 @support.skip_unless_symlink
376 def test_copy_symlinks(self):
377 tmp_dir = self.mkdtemp()
378 src = os.path.join(tmp_dir, 'foo')
379 dst = os.path.join(tmp_dir, 'bar')
380 src_link = os.path.join(tmp_dir, 'baz')
381 write_file(src, 'foo')
382 os.symlink(src, src_link)
383 if hasattr(os, 'lchmod'):
384 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
385 # don't follow
386 shutil.copy(src_link, dst, symlinks=False)
387 self.assertFalse(os.path.islink(dst))
388 self.assertEqual(read_file(src), read_file(dst))
389 os.remove(dst)
390 # follow
391 shutil.copy(src_link, dst, symlinks=True)
392 self.assertTrue(os.path.islink(dst))
393 self.assertEqual(os.readlink(dst), os.readlink(src_link))
394 if hasattr(os, 'lchmod'):
395 self.assertEqual(os.lstat(src_link).st_mode,
396 os.lstat(dst).st_mode)
397
398 @support.skip_unless_symlink
399 def test_copy2_symlinks(self):
400 tmp_dir = self.mkdtemp()
401 src = os.path.join(tmp_dir, 'foo')
402 dst = os.path.join(tmp_dir, 'bar')
403 src_link = os.path.join(tmp_dir, 'baz')
404 write_file(src, 'foo')
405 os.symlink(src, src_link)
406 if hasattr(os, 'lchmod'):
407 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
408 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
409 os.lchflags(src_link, stat.UF_NODUMP)
410 src_stat = os.stat(src)
411 src_link_stat = os.lstat(src_link)
412 # follow
413 shutil.copy2(src_link, dst, symlinks=False)
414 self.assertFalse(os.path.islink(dst))
415 self.assertEqual(read_file(src), read_file(dst))
416 os.remove(dst)
417 # don't follow
418 shutil.copy2(src_link, dst, symlinks=True)
419 self.assertTrue(os.path.islink(dst))
420 self.assertEqual(os.readlink(dst), os.readlink(src_link))
421 dst_stat = os.lstat(dst)
422 if hasattr(os, 'lutimes'):
423 for attr in 'st_atime', 'st_mtime':
424 # The modification times may be truncated in the new file.
425 self.assertLessEqual(getattr(src_link_stat, attr),
426 getattr(dst_stat, attr) + 1)
427 if hasattr(os, 'lchmod'):
428 self.assertEqual(src_link_stat.st_mode, dst_stat.st_mode)
429 self.assertNotEqual(src_stat.st_mode, dst_stat.st_mode)
430 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
431 self.assertEqual(src_link_stat.st_flags, dst_stat.st_flags)
432
Antoine Pitrou424246f2012-05-12 19:02:01 +0200433 @support.skip_unless_xattr
434 def test_copy2_xattr(self):
435 tmp_dir = self.mkdtemp()
436 src = os.path.join(tmp_dir, 'foo')
437 dst = os.path.join(tmp_dir, 'bar')
438 write_file(src, 'foo')
439 os.setxattr(src, 'user.foo', b'42')
440 shutil.copy2(src, dst)
441 self.assertEqual(
442 os.getxattr(src, 'user.foo'),
443 os.getxattr(dst, 'user.foo'))
444 os.remove(dst)
445
Antoine Pitrou78091e62011-12-29 18:54:15 +0100446 @support.skip_unless_symlink
447 def test_copyfile_symlinks(self):
448 tmp_dir = self.mkdtemp()
449 src = os.path.join(tmp_dir, 'src')
450 dst = os.path.join(tmp_dir, 'dst')
451 dst_link = os.path.join(tmp_dir, 'dst_link')
452 link = os.path.join(tmp_dir, 'link')
453 write_file(src, 'foo')
454 os.symlink(src, link)
455 # don't follow
456 shutil.copyfile(link, dst_link, symlinks=True)
457 self.assertTrue(os.path.islink(dst_link))
458 self.assertEqual(os.readlink(link), os.readlink(dst_link))
459 # follow
460 shutil.copyfile(link, dst)
461 self.assertFalse(os.path.islink(dst))
462
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000463 def test_rmtree_dont_delete_file(self):
464 # When called on a file instead of a directory, don't delete it.
465 handle, path = tempfile.mkstemp()
Victor Stinnerbf816222011-06-30 23:25:47 +0200466 os.close(handle)
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000467 self.assertRaises(OSError, shutil.rmtree, path)
468 os.remove(path)
469
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000470 def test_copytree_simple(self):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000471 src_dir = tempfile.mkdtemp()
472 dst_dir = os.path.join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200473 self.addCleanup(shutil.rmtree, src_dir)
474 self.addCleanup(shutil.rmtree, os.path.dirname(dst_dir))
475 write_file((src_dir, 'test.txt'), '123')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000476 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200477 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000478
Éric Araujoa7e33a12011-08-12 19:51:35 +0200479 shutil.copytree(src_dir, dst_dir)
480 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test.txt')))
481 self.assertTrue(os.path.isdir(os.path.join(dst_dir, 'test_dir')))
482 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test_dir',
483 'test.txt')))
484 actual = read_file((dst_dir, 'test.txt'))
485 self.assertEqual(actual, '123')
486 actual = read_file((dst_dir, 'test_dir', 'test.txt'))
487 self.assertEqual(actual, '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000488
Antoine Pitrou78091e62011-12-29 18:54:15 +0100489 @support.skip_unless_symlink
490 def test_copytree_symlinks(self):
491 tmp_dir = self.mkdtemp()
492 src_dir = os.path.join(tmp_dir, 'src')
493 dst_dir = os.path.join(tmp_dir, 'dst')
494 sub_dir = os.path.join(src_dir, 'sub')
495 os.mkdir(src_dir)
496 os.mkdir(sub_dir)
497 write_file((src_dir, 'file.txt'), 'foo')
498 src_link = os.path.join(sub_dir, 'link')
499 dst_link = os.path.join(dst_dir, 'sub/link')
500 os.symlink(os.path.join(src_dir, 'file.txt'),
501 src_link)
502 if hasattr(os, 'lchmod'):
503 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
504 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
505 os.lchflags(src_link, stat.UF_NODUMP)
506 src_stat = os.lstat(src_link)
507 shutil.copytree(src_dir, dst_dir, symlinks=True)
508 self.assertTrue(os.path.islink(os.path.join(dst_dir, 'sub', 'link')))
509 self.assertEqual(os.readlink(os.path.join(dst_dir, 'sub', 'link')),
510 os.path.join(src_dir, 'file.txt'))
511 dst_stat = os.lstat(dst_link)
512 if hasattr(os, 'lchmod'):
513 self.assertEqual(dst_stat.st_mode, src_stat.st_mode)
514 if hasattr(os, 'lchflags'):
515 self.assertEqual(dst_stat.st_flags, src_stat.st_flags)
516
Georg Brandl2ee470f2008-07-16 12:55:28 +0000517 def test_copytree_with_exclude(self):
Georg Brandl2ee470f2008-07-16 12:55:28 +0000518 # creating data
519 join = os.path.join
520 exists = os.path.exists
521 src_dir = tempfile.mkdtemp()
Georg Brandl2ee470f2008-07-16 12:55:28 +0000522 try:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000523 dst_dir = join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200524 write_file((src_dir, 'test.txt'), '123')
525 write_file((src_dir, 'test.tmp'), '123')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000526 os.mkdir(join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200527 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000528 os.mkdir(join(src_dir, 'test_dir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200529 write_file((src_dir, 'test_dir2', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000530 os.mkdir(join(src_dir, 'test_dir2', 'subdir'))
531 os.mkdir(join(src_dir, 'test_dir2', 'subdir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200532 write_file((src_dir, 'test_dir2', 'subdir', 'test.txt'), '456')
533 write_file((src_dir, 'test_dir2', 'subdir2', 'test.py'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000534
535 # testing glob-like patterns
536 try:
537 patterns = shutil.ignore_patterns('*.tmp', 'test_dir2')
538 shutil.copytree(src_dir, dst_dir, ignore=patterns)
539 # checking the result: some elements should not be copied
540 self.assertTrue(exists(join(dst_dir, 'test.txt')))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200541 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
542 self.assertFalse(exists(join(dst_dir, 'test_dir2')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000543 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200544 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000545 try:
546 patterns = shutil.ignore_patterns('*.tmp', 'subdir*')
547 shutil.copytree(src_dir, dst_dir, ignore=patterns)
548 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200549 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
550 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2')))
551 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000552 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200553 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000554
555 # testing callable-style
556 try:
557 def _filter(src, names):
558 res = []
559 for name in names:
560 path = os.path.join(src, name)
561
562 if (os.path.isdir(path) and
563 path.split()[-1] == 'subdir'):
564 res.append(name)
565 elif os.path.splitext(path)[-1] in ('.py'):
566 res.append(name)
567 return res
568
569 shutil.copytree(src_dir, dst_dir, ignore=_filter)
570
571 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200572 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2',
573 'test.py')))
574 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000575
576 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200577 shutil.rmtree(dst_dir)
Georg Brandl2ee470f2008-07-16 12:55:28 +0000578 finally:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000579 shutil.rmtree(src_dir)
580 shutil.rmtree(os.path.dirname(dst_dir))
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000581
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000582 @unittest.skipUnless(hasattr(os, 'link'), 'requires os.link')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000583 def test_dont_copy_file_onto_link_to_itself(self):
Georg Brandl724d0892010-12-05 07:51:39 +0000584 # Temporarily disable test on Windows.
585 if os.name == 'nt':
586 return
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000587 # bug 851123.
588 os.mkdir(TESTFN)
589 src = os.path.join(TESTFN, 'cheese')
590 dst = os.path.join(TESTFN, 'shop')
591 try:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000592 with open(src, 'w') as f:
593 f.write('cheddar')
594 os.link(src, dst)
595 self.assertRaises(shutil.Error, shutil.copyfile, src, dst)
596 with open(src, 'r') as f:
597 self.assertEqual(f.read(), 'cheddar')
598 os.remove(dst)
599 finally:
600 shutil.rmtree(TESTFN, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000601
Brian Curtin3b4499c2010-12-28 14:31:47 +0000602 @support.skip_unless_symlink
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000603 def test_dont_copy_file_onto_symlink_to_itself(self):
604 # bug 851123.
605 os.mkdir(TESTFN)
606 src = os.path.join(TESTFN, 'cheese')
607 dst = os.path.join(TESTFN, 'shop')
608 try:
609 with open(src, 'w') as f:
610 f.write('cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000611 # Using `src` here would mean we end up with a symlink pointing
612 # to TESTFN/TESTFN/cheese, while it should point at
613 # TESTFN/cheese.
614 os.symlink('cheese', dst)
615 self.assertRaises(shutil.Error, shutil.copyfile, src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +0000616 with open(src, 'r') as f:
617 self.assertEqual(f.read(), 'cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000618 os.remove(dst)
619 finally:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000620 shutil.rmtree(TESTFN, ignore_errors=True)
Johannes Gijsbers68128712004-08-14 13:57:08 +0000621
Brian Curtin3b4499c2010-12-28 14:31:47 +0000622 @support.skip_unless_symlink
Brian Curtind40e6f72010-07-08 21:39:08 +0000623 def test_rmtree_on_symlink(self):
624 # bug 1669.
625 os.mkdir(TESTFN)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000626 try:
Brian Curtind40e6f72010-07-08 21:39:08 +0000627 src = os.path.join(TESTFN, 'cheese')
628 dst = os.path.join(TESTFN, 'shop')
629 os.mkdir(src)
630 os.symlink(src, dst)
631 self.assertRaises(OSError, shutil.rmtree, dst)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000632 finally:
Brian Curtind40e6f72010-07-08 21:39:08 +0000633 shutil.rmtree(TESTFN, ignore_errors=True)
634
635 if hasattr(os, "mkfifo"):
636 # Issue #3002: copyfile and copytree block indefinitely on named pipes
637 def test_copyfile_named_pipe(self):
638 os.mkfifo(TESTFN)
639 try:
640 self.assertRaises(shutil.SpecialFileError,
641 shutil.copyfile, TESTFN, TESTFN2)
642 self.assertRaises(shutil.SpecialFileError,
643 shutil.copyfile, __file__, TESTFN)
644 finally:
645 os.remove(TESTFN)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000646
Brian Curtin3b4499c2010-12-28 14:31:47 +0000647 @support.skip_unless_symlink
Brian Curtin52173d42010-12-02 18:29:18 +0000648 def test_copytree_named_pipe(self):
649 os.mkdir(TESTFN)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000650 try:
Brian Curtin52173d42010-12-02 18:29:18 +0000651 subdir = os.path.join(TESTFN, "subdir")
652 os.mkdir(subdir)
653 pipe = os.path.join(subdir, "mypipe")
654 os.mkfifo(pipe)
655 try:
656 shutil.copytree(TESTFN, TESTFN2)
657 except shutil.Error as e:
658 errors = e.args[0]
659 self.assertEqual(len(errors), 1)
660 src, dst, error_msg = errors[0]
661 self.assertEqual("`%s` is a named pipe" % pipe, error_msg)
662 else:
663 self.fail("shutil.Error should have been raised")
664 finally:
665 shutil.rmtree(TESTFN, ignore_errors=True)
666 shutil.rmtree(TESTFN2, ignore_errors=True)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000667
Tarek Ziadé5340db32010-04-19 22:30:51 +0000668 def test_copytree_special_func(self):
669
670 src_dir = self.mkdtemp()
671 dst_dir = os.path.join(self.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200672 write_file((src_dir, 'test.txt'), '123')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000673 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200674 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000675
676 copied = []
677 def _copy(src, dst):
678 copied.append((src, dst))
679
680 shutil.copytree(src_dir, dst_dir, copy_function=_copy)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000681 self.assertEqual(len(copied), 2)
Tarek Ziadé5340db32010-04-19 22:30:51 +0000682
Brian Curtin3b4499c2010-12-28 14:31:47 +0000683 @support.skip_unless_symlink
Tarek Ziadéfb437512010-04-20 08:57:33 +0000684 def test_copytree_dangling_symlinks(self):
685
686 # a dangling symlink raises an error at the end
687 src_dir = self.mkdtemp()
688 dst_dir = os.path.join(self.mkdtemp(), 'destination')
689 os.symlink('IDONTEXIST', os.path.join(src_dir, 'test.txt'))
690 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200691 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadéfb437512010-04-20 08:57:33 +0000692 self.assertRaises(Error, shutil.copytree, src_dir, dst_dir)
693
694 # a dangling symlink is ignored with the proper flag
695 dst_dir = os.path.join(self.mkdtemp(), 'destination2')
696 shutil.copytree(src_dir, dst_dir, ignore_dangling_symlinks=True)
697 self.assertNotIn('test.txt', os.listdir(dst_dir))
698
699 # a dangling symlink is copied if symlinks=True
700 dst_dir = os.path.join(self.mkdtemp(), 'destination3')
701 shutil.copytree(src_dir, dst_dir, symlinks=True)
702 self.assertIn('test.txt', os.listdir(dst_dir))
703
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400704 def _copy_file(self, method):
705 fname = 'test.txt'
706 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200707 write_file((tmpdir, fname), 'xxx')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400708 file1 = os.path.join(tmpdir, fname)
709 tmpdir2 = self.mkdtemp()
710 method(file1, tmpdir2)
711 file2 = os.path.join(tmpdir2, fname)
712 return (file1, file2)
713
714 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
715 def test_copy(self):
716 # Ensure that the copied file exists and has the same mode bits.
717 file1, file2 = self._copy_file(shutil.copy)
718 self.assertTrue(os.path.exists(file2))
719 self.assertEqual(os.stat(file1).st_mode, os.stat(file2).st_mode)
720
721 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
Senthil Kumaran0c2dba52011-07-03 18:21:38 -0700722 @unittest.skipUnless(hasattr(os, 'utime'), 'requires os.utime')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400723 def test_copy2(self):
724 # Ensure that the copied file exists and has the same mode and
725 # modification time bits.
726 file1, file2 = self._copy_file(shutil.copy2)
727 self.assertTrue(os.path.exists(file2))
728 file1_stat = os.stat(file1)
729 file2_stat = os.stat(file2)
730 self.assertEqual(file1_stat.st_mode, file2_stat.st_mode)
731 for attr in 'st_atime', 'st_mtime':
732 # The modification times may be truncated in the new file.
733 self.assertLessEqual(getattr(file1_stat, attr),
734 getattr(file2_stat, attr) + 1)
735 if hasattr(os, 'chflags') and hasattr(file1_stat, 'st_flags'):
736 self.assertEqual(getattr(file1_stat, 'st_flags'),
737 getattr(file2_stat, 'st_flags'))
738
Ezio Melotti975077a2011-05-19 22:03:22 +0300739 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000740 def test_make_tarball(self):
741 # creating something to tar
742 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200743 write_file((tmpdir, 'file1'), 'xxx')
744 write_file((tmpdir, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000745 os.mkdir(os.path.join(tmpdir, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200746 write_file((tmpdir, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000747
748 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400749 # force shutil to create the directory
750 os.rmdir(tmpdir2)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000751 unittest.skipUnless(splitdrive(tmpdir)[0] == splitdrive(tmpdir2)[0],
752 "source and target should be on same drive")
753
754 base_name = os.path.join(tmpdir2, 'archive')
755
756 # working with relative paths to avoid tar warnings
757 old_dir = os.getcwd()
758 os.chdir(tmpdir)
759 try:
760 _make_tarball(splitdrive(base_name)[1], '.')
761 finally:
762 os.chdir(old_dir)
763
764 # check if the compressed tarball was created
765 tarball = base_name + '.tar.gz'
766 self.assertTrue(os.path.exists(tarball))
767
768 # trying an uncompressed one
769 base_name = os.path.join(tmpdir2, 'archive')
770 old_dir = os.getcwd()
771 os.chdir(tmpdir)
772 try:
773 _make_tarball(splitdrive(base_name)[1], '.', compress=None)
774 finally:
775 os.chdir(old_dir)
776 tarball = base_name + '.tar'
777 self.assertTrue(os.path.exists(tarball))
778
779 def _tarinfo(self, path):
780 tar = tarfile.open(path)
781 try:
782 names = tar.getnames()
783 names.sort()
784 return tuple(names)
785 finally:
786 tar.close()
787
788 def _create_files(self):
789 # creating something to tar
790 tmpdir = self.mkdtemp()
791 dist = os.path.join(tmpdir, 'dist')
792 os.mkdir(dist)
Éric Araujoa7e33a12011-08-12 19:51:35 +0200793 write_file((dist, 'file1'), 'xxx')
794 write_file((dist, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000795 os.mkdir(os.path.join(dist, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200796 write_file((dist, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000797 os.mkdir(os.path.join(dist, 'sub2'))
798 tmpdir2 = self.mkdtemp()
799 base_name = os.path.join(tmpdir2, 'archive')
800 return tmpdir, tmpdir2, base_name
801
Ezio Melotti975077a2011-05-19 22:03:22 +0300802 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000803 @unittest.skipUnless(find_executable('tar') and find_executable('gzip'),
804 'Need the tar command to run')
805 def test_tarfile_vs_tar(self):
806 tmpdir, tmpdir2, base_name = self._create_files()
807 old_dir = os.getcwd()
808 os.chdir(tmpdir)
809 try:
810 _make_tarball(base_name, 'dist')
811 finally:
812 os.chdir(old_dir)
813
814 # check if the compressed tarball was created
815 tarball = base_name + '.tar.gz'
816 self.assertTrue(os.path.exists(tarball))
817
818 # now create another tarball using `tar`
819 tarball2 = os.path.join(tmpdir, 'archive2.tar.gz')
820 tar_cmd = ['tar', '-cf', 'archive2.tar', 'dist']
821 gzip_cmd = ['gzip', '-f9', 'archive2.tar']
822 old_dir = os.getcwd()
823 os.chdir(tmpdir)
824 try:
825 with captured_stdout() as s:
826 spawn(tar_cmd)
827 spawn(gzip_cmd)
828 finally:
829 os.chdir(old_dir)
830
831 self.assertTrue(os.path.exists(tarball2))
832 # let's compare both tarballs
Ezio Melottib3aedd42010-11-20 19:04:17 +0000833 self.assertEqual(self._tarinfo(tarball), self._tarinfo(tarball2))
Tarek Ziadé396fad72010-02-23 05:30:31 +0000834
835 # trying an uncompressed one
836 base_name = os.path.join(tmpdir2, 'archive')
837 old_dir = os.getcwd()
838 os.chdir(tmpdir)
839 try:
840 _make_tarball(base_name, 'dist', compress=None)
841 finally:
842 os.chdir(old_dir)
843 tarball = base_name + '.tar'
844 self.assertTrue(os.path.exists(tarball))
845
846 # now for a dry_run
847 base_name = os.path.join(tmpdir2, 'archive')
848 old_dir = os.getcwd()
849 os.chdir(tmpdir)
850 try:
851 _make_tarball(base_name, 'dist', compress=None, dry_run=True)
852 finally:
853 os.chdir(old_dir)
854 tarball = base_name + '.tar'
855 self.assertTrue(os.path.exists(tarball))
856
Ezio Melotti975077a2011-05-19 22:03:22 +0300857 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000858 @unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run')
859 def test_make_zipfile(self):
860 # creating something to tar
861 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200862 write_file((tmpdir, 'file1'), 'xxx')
863 write_file((tmpdir, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000864
865 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400866 # force shutil to create the directory
867 os.rmdir(tmpdir2)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000868 base_name = os.path.join(tmpdir2, 'archive')
869 _make_zipfile(base_name, tmpdir)
870
871 # check if the compressed tarball was created
872 tarball = base_name + '.zip'
Éric Araujo1c505492010-11-06 02:12:51 +0000873 self.assertTrue(os.path.exists(tarball))
Tarek Ziadé396fad72010-02-23 05:30:31 +0000874
875
876 def test_make_archive(self):
877 tmpdir = self.mkdtemp()
878 base_name = os.path.join(tmpdir, 'archive')
879 self.assertRaises(ValueError, make_archive, base_name, 'xxx')
880
Ezio Melotti975077a2011-05-19 22:03:22 +0300881 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000882 def test_make_archive_owner_group(self):
883 # testing make_archive with owner and group, with various combinations
884 # this works even if there's not gid/uid support
885 if UID_GID_SUPPORT:
886 group = grp.getgrgid(0)[0]
887 owner = pwd.getpwuid(0)[0]
888 else:
889 group = owner = 'root'
890
891 base_dir, root_dir, base_name = self._create_files()
892 base_name = os.path.join(self.mkdtemp() , 'archive')
893 res = make_archive(base_name, 'zip', root_dir, base_dir, owner=owner,
894 group=group)
895 self.assertTrue(os.path.exists(res))
896
897 res = make_archive(base_name, 'zip', root_dir, base_dir)
898 self.assertTrue(os.path.exists(res))
899
900 res = make_archive(base_name, 'tar', root_dir, base_dir,
901 owner=owner, group=group)
902 self.assertTrue(os.path.exists(res))
903
904 res = make_archive(base_name, 'tar', root_dir, base_dir,
905 owner='kjhkjhkjg', group='oihohoh')
906 self.assertTrue(os.path.exists(res))
907
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000908
Ezio Melotti975077a2011-05-19 22:03:22 +0300909 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000910 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
911 def test_tarfile_root_owner(self):
912 tmpdir, tmpdir2, base_name = self._create_files()
913 old_dir = os.getcwd()
914 os.chdir(tmpdir)
915 group = grp.getgrgid(0)[0]
916 owner = pwd.getpwuid(0)[0]
917 try:
918 archive_name = _make_tarball(base_name, 'dist', compress=None,
919 owner=owner, group=group)
920 finally:
921 os.chdir(old_dir)
922
923 # check if the compressed tarball was created
924 self.assertTrue(os.path.exists(archive_name))
925
926 # now checks the rights
927 archive = tarfile.open(archive_name)
928 try:
929 for member in archive.getmembers():
Ezio Melottib3aedd42010-11-20 19:04:17 +0000930 self.assertEqual(member.uid, 0)
931 self.assertEqual(member.gid, 0)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000932 finally:
933 archive.close()
934
935 def test_make_archive_cwd(self):
936 current_dir = os.getcwd()
937 def _breaks(*args, **kw):
938 raise RuntimeError()
939
940 register_archive_format('xxx', _breaks, [], 'xxx file')
941 try:
942 try:
943 make_archive('xxx', 'xxx', root_dir=self.mkdtemp())
944 except Exception:
945 pass
Ezio Melottib3aedd42010-11-20 19:04:17 +0000946 self.assertEqual(os.getcwd(), current_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000947 finally:
948 unregister_archive_format('xxx')
949
950 def test_register_archive_format(self):
951
952 self.assertRaises(TypeError, register_archive_format, 'xxx', 1)
953 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
954 1)
955 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
956 [(1, 2), (1, 2, 3)])
957
958 register_archive_format('xxx', lambda: x, [(1, 2)], 'xxx file')
959 formats = [name for name, params in get_archive_formats()]
960 self.assertIn('xxx', formats)
961
962 unregister_archive_format('xxx')
963 formats = [name for name, params in get_archive_formats()]
964 self.assertNotIn('xxx', formats)
965
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000966 def _compare_dirs(self, dir1, dir2):
967 # check that dir1 and dir2 are equivalent,
968 # return the diff
969 diff = []
970 for root, dirs, files in os.walk(dir1):
971 for file_ in files:
972 path = os.path.join(root, file_)
973 target_path = os.path.join(dir2, os.path.split(path)[-1])
974 if not os.path.exists(target_path):
975 diff.append(file_)
976 return diff
977
Ezio Melotti975077a2011-05-19 22:03:22 +0300978 @requires_zlib
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000979 def test_unpack_archive(self):
Tarek Ziadéffa155a2010-04-29 13:34:35 +0000980 formats = ['tar', 'gztar', 'zip']
981 if BZ2_SUPPORTED:
982 formats.append('bztar')
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000983
Tarek Ziadéffa155a2010-04-29 13:34:35 +0000984 for format in formats:
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000985 tmpdir = self.mkdtemp()
986 base_dir, root_dir, base_name = self._create_files()
987 tmpdir2 = self.mkdtemp()
988 filename = make_archive(base_name, format, root_dir, base_dir)
989
990 # let's try to unpack it now
991 unpack_archive(filename, tmpdir2)
992 diff = self._compare_dirs(tmpdir, tmpdir2)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000993 self.assertEqual(diff, [])
Tarek Ziadé6ac91722010-04-28 17:51:36 +0000994
Nick Coghlanabf202d2011-03-16 13:52:20 -0400995 # and again, this time with the format specified
996 tmpdir3 = self.mkdtemp()
997 unpack_archive(filename, tmpdir3, format=format)
998 diff = self._compare_dirs(tmpdir, tmpdir3)
999 self.assertEqual(diff, [])
1000 self.assertRaises(shutil.ReadError, unpack_archive, TESTFN)
1001 self.assertRaises(ValueError, unpack_archive, TESTFN, format='xxx')
1002
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001003 def test_unpack_registery(self):
1004
1005 formats = get_unpack_formats()
1006
1007 def _boo(filename, extract_dir, extra):
Ezio Melottib3aedd42010-11-20 19:04:17 +00001008 self.assertEqual(extra, 1)
1009 self.assertEqual(filename, 'stuff.boo')
1010 self.assertEqual(extract_dir, 'xx')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001011
1012 register_unpack_format('Boo', ['.boo', '.b2'], _boo, [('extra', 1)])
1013 unpack_archive('stuff.boo', 'xx')
1014
1015 # trying to register a .boo unpacker again
1016 self.assertRaises(RegistryError, register_unpack_format, 'Boo2',
1017 ['.boo'], _boo)
1018
1019 # should work now
1020 unregister_unpack_format('Boo')
1021 register_unpack_format('Boo2', ['.boo'], _boo)
1022 self.assertIn(('Boo2', ['.boo'], ''), get_unpack_formats())
1023 self.assertNotIn(('Boo', ['.boo'], ''), get_unpack_formats())
1024
1025 # let's leave a clean state
1026 unregister_unpack_format('Boo2')
Ezio Melottib3aedd42010-11-20 19:04:17 +00001027 self.assertEqual(get_unpack_formats(), formats)
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001028
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001029 @unittest.skipUnless(hasattr(shutil, 'disk_usage'),
1030 "disk_usage not available on this platform")
1031 def test_disk_usage(self):
1032 usage = shutil.disk_usage(os.getcwd())
Éric Araujo2ee61882011-07-02 16:45:45 +02001033 self.assertGreater(usage.total, 0)
1034 self.assertGreater(usage.used, 0)
1035 self.assertGreaterEqual(usage.free, 0)
1036 self.assertGreaterEqual(usage.total, usage.used)
1037 self.assertGreater(usage.total, usage.free)
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001038
Sandro Tosid902a142011-08-22 23:28:27 +02001039 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1040 @unittest.skipUnless(hasattr(os, 'chown'), 'requires os.chown')
1041 def test_chown(self):
1042
1043 # cleaned-up automatically by TestShutil.tearDown method
1044 dirname = self.mkdtemp()
1045 filename = tempfile.mktemp(dir=dirname)
1046 write_file(filename, 'testing chown function')
1047
1048 with self.assertRaises(ValueError):
1049 shutil.chown(filename)
1050
1051 with self.assertRaises(LookupError):
1052 shutil.chown(filename, user='non-exising username')
1053
1054 with self.assertRaises(LookupError):
1055 shutil.chown(filename, group='non-exising groupname')
1056
1057 with self.assertRaises(TypeError):
1058 shutil.chown(filename, b'spam')
1059
1060 with self.assertRaises(TypeError):
1061 shutil.chown(filename, 3.14)
1062
1063 uid = os.getuid()
1064 gid = os.getgid()
1065
1066 def check_chown(path, uid=None, gid=None):
1067 s = os.stat(filename)
1068 if uid is not None:
1069 self.assertEqual(uid, s.st_uid)
1070 if gid is not None:
1071 self.assertEqual(gid, s.st_gid)
1072
1073 shutil.chown(filename, uid, gid)
1074 check_chown(filename, uid, gid)
1075 shutil.chown(filename, uid)
1076 check_chown(filename, uid)
1077 shutil.chown(filename, user=uid)
1078 check_chown(filename, uid)
1079 shutil.chown(filename, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001080 check_chown(filename, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001081
1082 shutil.chown(dirname, uid, gid)
1083 check_chown(dirname, uid, gid)
1084 shutil.chown(dirname, uid)
1085 check_chown(dirname, uid)
1086 shutil.chown(dirname, user=uid)
1087 check_chown(dirname, uid)
1088 shutil.chown(dirname, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001089 check_chown(dirname, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001090
1091 user = pwd.getpwuid(uid)[0]
1092 group = grp.getgrgid(gid)[0]
1093 shutil.chown(filename, user, group)
1094 check_chown(filename, uid, gid)
1095 shutil.chown(dirname, user, group)
1096 check_chown(dirname, uid, gid)
1097
Christian Heimes9bd667a2008-01-20 15:14:11 +00001098
Christian Heimesada8c3b2008-03-18 18:26:33 +00001099class TestMove(unittest.TestCase):
1100
1101 def setUp(self):
1102 filename = "foo"
1103 self.src_dir = tempfile.mkdtemp()
1104 self.dst_dir = tempfile.mkdtemp()
1105 self.src_file = os.path.join(self.src_dir, filename)
1106 self.dst_file = os.path.join(self.dst_dir, filename)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001107 with open(self.src_file, "wb") as f:
1108 f.write(b"spam")
1109
1110 def tearDown(self):
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001111 for d in (self.src_dir, self.dst_dir):
Christian Heimesada8c3b2008-03-18 18:26:33 +00001112 try:
1113 if d:
1114 shutil.rmtree(d)
1115 except:
1116 pass
1117
1118 def _check_move_file(self, src, dst, real_dst):
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001119 with open(src, "rb") as f:
1120 contents = f.read()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001121 shutil.move(src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001122 with open(real_dst, "rb") as f:
1123 self.assertEqual(contents, f.read())
Christian Heimesada8c3b2008-03-18 18:26:33 +00001124 self.assertFalse(os.path.exists(src))
1125
1126 def _check_move_dir(self, src, dst, real_dst):
1127 contents = sorted(os.listdir(src))
1128 shutil.move(src, dst)
1129 self.assertEqual(contents, sorted(os.listdir(real_dst)))
1130 self.assertFalse(os.path.exists(src))
1131
1132 def test_move_file(self):
1133 # Move a file to another location on the same filesystem.
1134 self._check_move_file(self.src_file, self.dst_file, self.dst_file)
1135
1136 def test_move_file_to_dir(self):
1137 # Move a file inside an existing dir on the same filesystem.
1138 self._check_move_file(self.src_file, self.dst_dir, self.dst_file)
1139
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001140 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001141 def test_move_file_other_fs(self):
1142 # Move a file to an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001143 self.test_move_file()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001144
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001145 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001146 def test_move_file_to_dir_other_fs(self):
1147 # Move a file to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001148 self.test_move_file_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001149
1150 def test_move_dir(self):
1151 # Move a dir to another location on the same filesystem.
1152 dst_dir = tempfile.mktemp()
1153 try:
1154 self._check_move_dir(self.src_dir, dst_dir, dst_dir)
1155 finally:
1156 try:
1157 shutil.rmtree(dst_dir)
1158 except:
1159 pass
1160
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001161 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001162 def test_move_dir_other_fs(self):
1163 # Move a dir to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001164 self.test_move_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001165
1166 def test_move_dir_to_dir(self):
1167 # Move a dir inside an existing dir on the same filesystem.
1168 self._check_move_dir(self.src_dir, self.dst_dir,
1169 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1170
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001171 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001172 def test_move_dir_to_dir_other_fs(self):
1173 # Move a dir inside an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001174 self.test_move_dir_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001175
1176 def test_existing_file_inside_dest_dir(self):
1177 # A file with the same name inside the destination dir already exists.
1178 with open(self.dst_file, "wb"):
1179 pass
1180 self.assertRaises(shutil.Error, shutil.move, self.src_file, self.dst_dir)
1181
1182 def test_dont_move_dir_in_itself(self):
1183 # Moving a dir inside itself raises an Error.
1184 dst = os.path.join(self.src_dir, "bar")
1185 self.assertRaises(shutil.Error, shutil.move, self.src_dir, dst)
1186
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001187 def test_destinsrc_false_negative(self):
1188 os.mkdir(TESTFN)
1189 try:
1190 for src, dst in [('srcdir', 'srcdir/dest')]:
1191 src = os.path.join(TESTFN, src)
1192 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001193 self.assertTrue(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001194 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001195 'dst (%s) is not in src (%s)' % (dst, src))
1196 finally:
1197 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001198
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001199 def test_destinsrc_false_positive(self):
1200 os.mkdir(TESTFN)
1201 try:
1202 for src, dst in [('srcdir', 'src/dest'), ('srcdir', 'srcdir.new')]:
1203 src = os.path.join(TESTFN, src)
1204 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001205 self.assertFalse(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001206 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001207 'dst (%s) is in src (%s)' % (dst, src))
1208 finally:
1209 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimes9bd667a2008-01-20 15:14:11 +00001210
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +01001211 @support.skip_unless_symlink
1212 @mock_rename
1213 def test_move_file_symlink(self):
1214 dst = os.path.join(self.src_dir, 'bar')
1215 os.symlink(self.src_file, dst)
1216 shutil.move(dst, self.dst_file)
1217 self.assertTrue(os.path.islink(self.dst_file))
1218 self.assertTrue(os.path.samefile(self.src_file, self.dst_file))
1219
1220 @support.skip_unless_symlink
1221 @mock_rename
1222 def test_move_file_symlink_to_dir(self):
1223 filename = "bar"
1224 dst = os.path.join(self.src_dir, filename)
1225 os.symlink(self.src_file, dst)
1226 shutil.move(dst, self.dst_dir)
1227 final_link = os.path.join(self.dst_dir, filename)
1228 self.assertTrue(os.path.islink(final_link))
1229 self.assertTrue(os.path.samefile(self.src_file, final_link))
1230
1231 @support.skip_unless_symlink
1232 @mock_rename
1233 def test_move_dangling_symlink(self):
1234 src = os.path.join(self.src_dir, 'baz')
1235 dst = os.path.join(self.src_dir, 'bar')
1236 os.symlink(src, dst)
1237 dst_link = os.path.join(self.dst_dir, 'quux')
1238 shutil.move(dst, dst_link)
1239 self.assertTrue(os.path.islink(dst_link))
1240 self.assertEqual(os.path.realpath(src), os.path.realpath(dst_link))
1241
1242 @support.skip_unless_symlink
1243 @mock_rename
1244 def test_move_dir_symlink(self):
1245 src = os.path.join(self.src_dir, 'baz')
1246 dst = os.path.join(self.src_dir, 'bar')
1247 os.mkdir(src)
1248 os.symlink(src, dst)
1249 dst_link = os.path.join(self.dst_dir, 'quux')
1250 shutil.move(dst, dst_link)
1251 self.assertTrue(os.path.islink(dst_link))
1252 self.assertTrue(os.path.samefile(src, dst_link))
1253
Tarek Ziadé5340db32010-04-19 22:30:51 +00001254
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001255class TestCopyFile(unittest.TestCase):
1256
1257 _delete = False
1258
1259 class Faux(object):
1260 _entered = False
1261 _exited_with = None
1262 _raised = False
1263 def __init__(self, raise_in_exit=False, suppress_at_exit=True):
1264 self._raise_in_exit = raise_in_exit
1265 self._suppress_at_exit = suppress_at_exit
1266 def read(self, *args):
1267 return ''
1268 def __enter__(self):
1269 self._entered = True
1270 def __exit__(self, exc_type, exc_val, exc_tb):
1271 self._exited_with = exc_type, exc_val, exc_tb
1272 if self._raise_in_exit:
1273 self._raised = True
1274 raise IOError("Cannot close")
1275 return self._suppress_at_exit
1276
1277 def tearDown(self):
1278 if self._delete:
1279 del shutil.open
1280
1281 def _set_shutil_open(self, func):
1282 shutil.open = func
1283 self._delete = True
1284
1285 def test_w_source_open_fails(self):
1286 def _open(filename, mode='r'):
1287 if filename == 'srcfile':
1288 raise IOError('Cannot open "srcfile"')
1289 assert 0 # shouldn't reach here.
1290
1291 self._set_shutil_open(_open)
1292
1293 self.assertRaises(IOError, shutil.copyfile, 'srcfile', 'destfile')
1294
1295 def test_w_dest_open_fails(self):
1296
1297 srcfile = self.Faux()
1298
1299 def _open(filename, mode='r'):
1300 if filename == 'srcfile':
1301 return srcfile
1302 if filename == 'destfile':
1303 raise IOError('Cannot open "destfile"')
1304 assert 0 # shouldn't reach here.
1305
1306 self._set_shutil_open(_open)
1307
1308 shutil.copyfile('srcfile', 'destfile')
1309 self.assertTrue(srcfile._entered)
1310 self.assertTrue(srcfile._exited_with[0] is IOError)
1311 self.assertEqual(srcfile._exited_with[1].args,
1312 ('Cannot open "destfile"',))
1313
1314 def test_w_dest_close_fails(self):
1315
1316 srcfile = self.Faux()
1317 destfile = self.Faux(True)
1318
1319 def _open(filename, mode='r'):
1320 if filename == 'srcfile':
1321 return srcfile
1322 if filename == 'destfile':
1323 return destfile
1324 assert 0 # shouldn't reach here.
1325
1326 self._set_shutil_open(_open)
1327
1328 shutil.copyfile('srcfile', 'destfile')
1329 self.assertTrue(srcfile._entered)
1330 self.assertTrue(destfile._entered)
1331 self.assertTrue(destfile._raised)
1332 self.assertTrue(srcfile._exited_with[0] is IOError)
1333 self.assertEqual(srcfile._exited_with[1].args,
1334 ('Cannot close',))
1335
1336 def test_w_source_close_fails(self):
1337
1338 srcfile = self.Faux(True)
1339 destfile = self.Faux()
1340
1341 def _open(filename, mode='r'):
1342 if filename == 'srcfile':
1343 return srcfile
1344 if filename == 'destfile':
1345 return destfile
1346 assert 0 # shouldn't reach here.
1347
1348 self._set_shutil_open(_open)
1349
1350 self.assertRaises(IOError,
1351 shutil.copyfile, 'srcfile', 'destfile')
1352 self.assertTrue(srcfile._entered)
1353 self.assertTrue(destfile._entered)
1354 self.assertFalse(destfile._raised)
1355 self.assertTrue(srcfile._exited_with[0] is None)
1356 self.assertTrue(srcfile._raised)
1357
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001358 def test_move_dir_caseinsensitive(self):
1359 # Renames a folder to the same name
1360 # but a different case.
1361
1362 self.src_dir = tempfile.mkdtemp()
1363 dst_dir = os.path.join(
1364 os.path.dirname(self.src_dir),
1365 os.path.basename(self.src_dir).upper())
1366 self.assertNotEqual(self.src_dir, dst_dir)
1367
1368 try:
1369 shutil.move(self.src_dir, dst_dir)
1370 self.assertTrue(os.path.isdir(dst_dir))
1371 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +02001372 os.rmdir(dst_dir)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001373
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001374class TermsizeTests(unittest.TestCase):
1375 def test_does_not_crash(self):
1376 """Check if get_terminal_size() returns a meaningful value.
1377
1378 There's no easy portable way to actually check the size of the
1379 terminal, so let's check if it returns something sensible instead.
1380 """
1381 size = shutil.get_terminal_size()
Antoine Pitroucfade362012-02-08 23:48:59 +01001382 self.assertGreaterEqual(size.columns, 0)
1383 self.assertGreaterEqual(size.lines, 0)
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001384
1385 def test_os_environ_first(self):
1386 "Check if environment variables have precedence"
1387
1388 with support.EnvironmentVarGuard() as env:
1389 env['COLUMNS'] = '777'
1390 size = shutil.get_terminal_size()
1391 self.assertEqual(size.columns, 777)
1392
1393 with support.EnvironmentVarGuard() as env:
1394 env['LINES'] = '888'
1395 size = shutil.get_terminal_size()
1396 self.assertEqual(size.lines, 888)
1397
1398 @unittest.skipUnless(os.isatty(sys.__stdout__.fileno()), "not on tty")
1399 def test_stty_match(self):
1400 """Check if stty returns the same results ignoring env
1401
1402 This test will fail if stdin and stdout are connected to
1403 different terminals with different sizes. Nevertheless, such
1404 situations should be pretty rare.
1405 """
1406 try:
1407 size = subprocess.check_output(['stty', 'size']).decode().split()
1408 except (FileNotFoundError, subprocess.CalledProcessError):
1409 self.skipTest("stty invocation failed")
1410 expected = (int(size[1]), int(size[0])) # reversed order
1411
1412 with support.EnvironmentVarGuard() as env:
1413 del env['LINES']
1414 del env['COLUMNS']
1415 actual = shutil.get_terminal_size()
1416
1417 self.assertEqual(expected, actual)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001418
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001419
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001420def test_main():
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001421 support.run_unittest(TestShutil, TestMove, TestCopyFile,
1422 TermsizeTests)
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001423
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001424if __name__ == '__main__':
Walter Dörwald21d3a322003-05-01 17:45:56 +00001425 test_main()