blob: 9af7da71cbd82e8426c5197589d86c51c1878621 [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,
Hynek Schlawack26fe37d2012-07-19 21:41:02 +020021 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
Hynek Schlawack3b527782012-06-25 13:27:31 +0200111 def test_rmtree_works_on_bytes(self):
112 tmp = self.mkdtemp()
113 victim = os.path.join(tmp, 'killme')
114 os.mkdir(victim)
115 write_file(os.path.join(victim, 'somefile'), 'foo')
116 victim = os.fsencode(victim)
117 self.assertIsInstance(victim, bytes)
118 shutil.rmtree(victim)
119
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200120 @support.skip_unless_symlink
121 def test_rmtree_fails_on_symlink(self):
122 tmp = self.mkdtemp()
123 dir_ = os.path.join(tmp, 'dir')
124 os.mkdir(dir_)
125 link = os.path.join(tmp, 'link')
126 os.symlink(dir_, link)
127 self.assertRaises(OSError, shutil.rmtree, link)
128 self.assertTrue(os.path.exists(dir_))
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100129 self.assertTrue(os.path.lexists(link))
130 errors = []
131 def onerror(*args):
132 errors.append(args)
133 shutil.rmtree(link, onerror=onerror)
134 self.assertEqual(len(errors), 1)
135 self.assertIs(errors[0][0], os.path.islink)
136 self.assertEqual(errors[0][1], link)
137 self.assertIsInstance(errors[0][2][1], OSError)
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200138
139 @support.skip_unless_symlink
140 def test_rmtree_works_on_symlinks(self):
141 tmp = self.mkdtemp()
142 dir1 = os.path.join(tmp, 'dir1')
143 dir2 = os.path.join(dir1, 'dir2')
144 dir3 = os.path.join(tmp, 'dir3')
145 for d in dir1, dir2, dir3:
146 os.mkdir(d)
147 file1 = os.path.join(tmp, 'file1')
148 write_file(file1, 'foo')
149 link1 = os.path.join(dir1, 'link1')
150 os.symlink(dir2, link1)
151 link2 = os.path.join(dir1, 'link2')
152 os.symlink(dir3, link2)
153 link3 = os.path.join(dir1, 'link3')
154 os.symlink(file1, link3)
155 # make sure symlinks are removed but not followed
156 shutil.rmtree(dir1)
157 self.assertFalse(os.path.exists(dir1))
158 self.assertTrue(os.path.exists(dir3))
159 self.assertTrue(os.path.exists(file1))
160
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000161 def test_rmtree_errors(self):
162 # filename is guaranteed not to exist
163 filename = tempfile.mktemp()
Hynek Schlawackb5501102012-12-10 09:11:25 +0100164 self.assertRaises(FileNotFoundError, shutil.rmtree, filename)
165 # test that ignore_errors option is honored
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100166 shutil.rmtree(filename, ignore_errors=True)
167
168 # existing file
169 tmpdir = self.mkdtemp()
Hynek Schlawackb5501102012-12-10 09:11:25 +0100170 write_file((tmpdir, "tstfile"), "")
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100171 filename = os.path.join(tmpdir, "tstfile")
Hynek Schlawackb5501102012-12-10 09:11:25 +0100172 with self.assertRaises(NotADirectoryError) as cm:
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100173 shutil.rmtree(filename)
Hynek Schlawack87f9b462012-12-10 16:29:57 +0100174 # The reason for this rather odd construct is that Windows sprinkles
175 # a \*.* at the end of file names. But only sometimes on some buildbots
176 possible_args = [filename, os.path.join(filename, '*.*')]
177 self.assertIn(cm.exception.filename, possible_args)
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100178 self.assertTrue(os.path.exists(filename))
Hynek Schlawackb5501102012-12-10 09:11:25 +0100179 # test that ignore_errors option is honored
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100180 shutil.rmtree(filename, ignore_errors=True)
181 self.assertTrue(os.path.exists(filename))
182 errors = []
183 def onerror(*args):
184 errors.append(args)
185 shutil.rmtree(filename, onerror=onerror)
186 self.assertEqual(len(errors), 2)
187 self.assertIs(errors[0][0], os.listdir)
188 self.assertEqual(errors[0][1], filename)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100189 self.assertIsInstance(errors[0][2][1], NotADirectoryError)
Hynek Schlawack87f9b462012-12-10 16:29:57 +0100190 self.assertIn(errors[0][2][1].filename, possible_args)
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100191 self.assertIs(errors[1][0], os.rmdir)
192 self.assertEqual(errors[1][1], filename)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100193 self.assertIsInstance(errors[1][2][1], NotADirectoryError)
Hynek Schlawack87f9b462012-12-10 16:29:57 +0100194 self.assertIn(errors[1][2][1].filename, possible_args)
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000195
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000196
Johannes Gijsbersb8b09d02004-12-06 20:50:15 +0000197 # See bug #1071513 for why we don't run this on cygwin
198 # and bug #1076467 for why we don't run this as root.
199 if (hasattr(os, 'chmod') and sys.platform[:6] != 'cygwin'
Johannes Gijsbers6b220b02004-12-12 15:52:57 +0000200 and not (hasattr(os, 'geteuid') and os.geteuid() == 0)):
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000201 def test_on_error(self):
202 self.errorState = 0
203 os.mkdir(TESTFN)
Antoine Pitrou2f8a75c2012-06-23 21:28:15 +0200204 self.addCleanup(shutil.rmtree, TESTFN)
205
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200206 self.child_file_path = os.path.join(TESTFN, 'a')
207 self.child_dir_path = os.path.join(TESTFN, 'b')
208 support.create_empty_file(self.child_file_path)
209 os.mkdir(self.child_dir_path)
Tim Peters4590c002004-11-01 02:40:52 +0000210 old_dir_mode = os.stat(TESTFN).st_mode
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200211 old_child_file_mode = os.stat(self.child_file_path).st_mode
212 old_child_dir_mode = os.stat(self.child_dir_path).st_mode
Tim Peters4590c002004-11-01 02:40:52 +0000213 # Make unwritable.
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200214 new_mode = stat.S_IREAD|stat.S_IEXEC
215 os.chmod(self.child_file_path, new_mode)
216 os.chmod(self.child_dir_path, new_mode)
217 os.chmod(TESTFN, new_mode)
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000218
Antoine Pitrou2f8a75c2012-06-23 21:28:15 +0200219 self.addCleanup(os.chmod, TESTFN, old_dir_mode)
220 self.addCleanup(os.chmod, self.child_file_path, old_child_file_mode)
221 self.addCleanup(os.chmod, self.child_dir_path, old_child_dir_mode)
222
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000223 shutil.rmtree(TESTFN, onerror=self.check_args_to_onerror)
Johannes Gijsbers8e6f2de2004-11-23 09:27:27 +0000224 # Test whether onerror has actually been called.
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200225 self.assertEqual(self.errorState, 3,
226 "Expected call to onerror function did not "
227 "happen.")
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000228
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000229 def check_args_to_onerror(self, func, arg, exc):
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000230 # test_rmtree_errors deliberately runs rmtree
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200231 # on a directory that is chmod 500, which will fail.
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000232 # This function is run when shutil.rmtree fails.
233 # 99.9% of the time it initially fails to remove
234 # a file in the directory, so the first time through
235 # func is os.remove.
236 # However, some Linux machines running ZFS on
237 # FUSE experienced a failure earlier in the process
238 # at os.listdir. The first failure may legally
239 # be either.
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200240 if self.errorState < 2:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200241 if func is os.unlink:
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200242 self.assertEqual(arg, self.child_file_path)
243 elif func is os.rmdir:
244 self.assertEqual(arg, self.child_dir_path)
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000245 else:
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200246 self.assertIs(func, os.listdir)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200247 self.assertIn(arg, [TESTFN, self.child_dir_path])
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000248 self.assertTrue(issubclass(exc[0], OSError))
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200249 self.errorState += 1
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000250 else:
251 self.assertEqual(func, os.rmdir)
252 self.assertEqual(arg, TESTFN)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000253 self.assertTrue(issubclass(exc[0], OSError))
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200254 self.errorState = 3
255
256 def test_rmtree_does_not_choke_on_failing_lstat(self):
257 try:
258 orig_lstat = os.lstat
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200259 def raiser(fn, *args, **kwargs):
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200260 if fn != TESTFN:
261 raise OSError()
262 else:
263 return orig_lstat(fn)
264 os.lstat = raiser
265
266 os.mkdir(TESTFN)
267 write_file((TESTFN, 'foo'), 'foo')
268 shutil.rmtree(TESTFN)
269 finally:
270 os.lstat = orig_lstat
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000271
Antoine Pitrou78091e62011-12-29 18:54:15 +0100272 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
273 @support.skip_unless_symlink
274 def test_copymode_follow_symlinks(self):
275 tmp_dir = self.mkdtemp()
276 src = os.path.join(tmp_dir, 'foo')
277 dst = os.path.join(tmp_dir, 'bar')
278 src_link = os.path.join(tmp_dir, 'baz')
279 dst_link = os.path.join(tmp_dir, 'quux')
280 write_file(src, 'foo')
281 write_file(dst, 'foo')
282 os.symlink(src, src_link)
283 os.symlink(dst, dst_link)
284 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
285 # file to file
286 os.chmod(dst, stat.S_IRWXO)
287 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
288 shutil.copymode(src, dst)
289 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
290 # follow src link
291 os.chmod(dst, stat.S_IRWXO)
292 shutil.copymode(src_link, dst)
293 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
294 # follow dst link
295 os.chmod(dst, stat.S_IRWXO)
296 shutil.copymode(src, dst_link)
297 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
298 # follow both links
299 os.chmod(dst, stat.S_IRWXO)
300 shutil.copymode(src_link, dst)
301 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
302
303 @unittest.skipUnless(hasattr(os, 'lchmod'), 'requires os.lchmod')
304 @support.skip_unless_symlink
305 def test_copymode_symlink_to_symlink(self):
306 tmp_dir = self.mkdtemp()
307 src = os.path.join(tmp_dir, 'foo')
308 dst = os.path.join(tmp_dir, 'bar')
309 src_link = os.path.join(tmp_dir, 'baz')
310 dst_link = os.path.join(tmp_dir, 'quux')
311 write_file(src, 'foo')
312 write_file(dst, 'foo')
313 os.symlink(src, src_link)
314 os.symlink(dst, dst_link)
315 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
316 os.chmod(dst, stat.S_IRWXU)
317 os.lchmod(src_link, stat.S_IRWXO|stat.S_IRWXG)
318 # link to link
319 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700320 shutil.copymode(src_link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100321 self.assertEqual(os.lstat(src_link).st_mode,
322 os.lstat(dst_link).st_mode)
323 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
324 # src link - use chmod
325 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700326 shutil.copymode(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100327 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
328 # dst link - use chmod
329 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700330 shutil.copymode(src, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100331 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
332
333 @unittest.skipIf(hasattr(os, 'lchmod'), 'requires os.lchmod to be missing')
334 @support.skip_unless_symlink
335 def test_copymode_symlink_to_symlink_wo_lchmod(self):
336 tmp_dir = self.mkdtemp()
337 src = os.path.join(tmp_dir, 'foo')
338 dst = os.path.join(tmp_dir, 'bar')
339 src_link = os.path.join(tmp_dir, 'baz')
340 dst_link = os.path.join(tmp_dir, 'quux')
341 write_file(src, 'foo')
342 write_file(dst, 'foo')
343 os.symlink(src, src_link)
344 os.symlink(dst, dst_link)
Larry Hastingsb4038062012-07-15 10:57:38 -0700345 shutil.copymode(src_link, dst_link, follow_symlinks=False) # silent fail
Antoine Pitrou78091e62011-12-29 18:54:15 +0100346
347 @support.skip_unless_symlink
348 def test_copystat_symlinks(self):
349 tmp_dir = self.mkdtemp()
350 src = os.path.join(tmp_dir, 'foo')
351 dst = os.path.join(tmp_dir, 'bar')
352 src_link = os.path.join(tmp_dir, 'baz')
353 dst_link = os.path.join(tmp_dir, 'qux')
354 write_file(src, 'foo')
355 src_stat = os.stat(src)
356 os.utime(src, (src_stat.st_atime,
357 src_stat.st_mtime - 42.0)) # ensure different mtimes
358 write_file(dst, 'bar')
359 self.assertNotEqual(os.stat(src).st_mtime, os.stat(dst).st_mtime)
360 os.symlink(src, src_link)
361 os.symlink(dst, dst_link)
362 if hasattr(os, 'lchmod'):
363 os.lchmod(src_link, stat.S_IRWXO)
364 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
365 os.lchflags(src_link, stat.UF_NODUMP)
366 src_link_stat = os.lstat(src_link)
367 # follow
368 if hasattr(os, 'lchmod'):
Larry Hastingsb4038062012-07-15 10:57:38 -0700369 shutil.copystat(src_link, dst_link, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100370 self.assertNotEqual(src_link_stat.st_mode, os.stat(dst).st_mode)
371 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700372 shutil.copystat(src_link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100373 dst_link_stat = os.lstat(dst_link)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700374 if os.utime in os.supports_follow_symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100375 for attr in 'st_atime', 'st_mtime':
376 # The modification times may be truncated in the new file.
377 self.assertLessEqual(getattr(src_link_stat, attr),
378 getattr(dst_link_stat, attr) + 1)
379 if hasattr(os, 'lchmod'):
380 self.assertEqual(src_link_stat.st_mode, dst_link_stat.st_mode)
381 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
382 self.assertEqual(src_link_stat.st_flags, dst_link_stat.st_flags)
383 # tell to follow but dst is not a link
Larry Hastingsb4038062012-07-15 10:57:38 -0700384 shutil.copystat(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100385 self.assertTrue(abs(os.stat(src).st_mtime - os.stat(dst).st_mtime) <
386 00000.1)
387
Ned Deilybaf75712012-05-10 17:05:19 -0700388 @unittest.skipUnless(hasattr(os, 'chflags') and
389 hasattr(errno, 'EOPNOTSUPP') and
390 hasattr(errno, 'ENOTSUP'),
391 "requires os.chflags, EOPNOTSUPP & ENOTSUP")
392 def test_copystat_handles_harmless_chflags_errors(self):
393 tmpdir = self.mkdtemp()
394 file1 = os.path.join(tmpdir, 'file1')
395 file2 = os.path.join(tmpdir, 'file2')
396 write_file(file1, 'xxx')
397 write_file(file2, 'xxx')
398
399 def make_chflags_raiser(err):
400 ex = OSError()
401
Larry Hastings90867a52012-06-22 17:01:41 -0700402 def _chflags_raiser(path, flags, *, follow_symlinks=True):
Ned Deilybaf75712012-05-10 17:05:19 -0700403 ex.errno = err
404 raise ex
405 return _chflags_raiser
406 old_chflags = os.chflags
407 try:
408 for err in errno.EOPNOTSUPP, errno.ENOTSUP:
409 os.chflags = make_chflags_raiser(err)
410 shutil.copystat(file1, file2)
411 # assert others errors break it
412 os.chflags = make_chflags_raiser(errno.EOPNOTSUPP + errno.ENOTSUP)
413 self.assertRaises(OSError, shutil.copystat, file1, file2)
414 finally:
415 os.chflags = old_chflags
416
Antoine Pitrou424246f2012-05-12 19:02:01 +0200417 @support.skip_unless_xattr
418 def test_copyxattr(self):
419 tmp_dir = self.mkdtemp()
420 src = os.path.join(tmp_dir, 'foo')
421 write_file(src, 'foo')
422 dst = os.path.join(tmp_dir, 'bar')
423 write_file(dst, 'bar')
424
425 # no xattr == no problem
426 shutil._copyxattr(src, dst)
427 # common case
428 os.setxattr(src, 'user.foo', b'42')
429 os.setxattr(src, 'user.bar', b'43')
430 shutil._copyxattr(src, dst)
431 self.assertEqual(os.listxattr(src), os.listxattr(dst))
432 self.assertEqual(
433 os.getxattr(src, 'user.foo'),
434 os.getxattr(dst, 'user.foo'))
435 # check errors don't affect other attrs
436 os.remove(dst)
437 write_file(dst, 'bar')
438 os_error = OSError(errno.EPERM, 'EPERM')
439
Larry Hastings9cf065c2012-06-22 16:30:09 -0700440 def _raise_on_user_foo(fname, attr, val, **kwargs):
Antoine Pitrou424246f2012-05-12 19:02:01 +0200441 if attr == 'user.foo':
442 raise os_error
443 else:
Larry Hastings9cf065c2012-06-22 16:30:09 -0700444 orig_setxattr(fname, attr, val, **kwargs)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200445 try:
446 orig_setxattr = os.setxattr
447 os.setxattr = _raise_on_user_foo
448 shutil._copyxattr(src, dst)
Antoine Pitrou61597d32012-05-12 23:37:35 +0200449 self.assertIn('user.bar', os.listxattr(dst))
Antoine Pitrou424246f2012-05-12 19:02:01 +0200450 finally:
451 os.setxattr = orig_setxattr
Hynek Schlawack0beab052013-02-05 08:22:44 +0100452 # the source filesystem not supporting xattrs should be ok, too.
453 def _raise_on_src(fname, *, follow_symlinks=True):
454 if fname == src:
455 raise OSError(errno.ENOTSUP, 'Operation not supported')
456 return orig_listxattr(fname, follow_symlinks=follow_symlinks)
457 try:
458 orig_listxattr = os.listxattr
459 os.listxattr = _raise_on_src
460 shutil._copyxattr(src, dst)
461 finally:
462 os.listxattr = orig_listxattr
Antoine Pitrou424246f2012-05-12 19:02:01 +0200463
Larry Hastingsad5ae042012-07-14 17:55:11 -0700464 # test that shutil.copystat copies xattrs
465 src = os.path.join(tmp_dir, 'the_original')
466 write_file(src, src)
467 os.setxattr(src, 'user.the_value', b'fiddly')
468 dst = os.path.join(tmp_dir, 'the_copy')
469 write_file(dst, dst)
470 shutil.copystat(src, dst)
Hynek Schlawackc2d481f2012-07-16 17:11:10 +0200471 self.assertEqual(os.getxattr(dst, 'user.the_value'), b'fiddly')
Larry Hastingsad5ae042012-07-14 17:55:11 -0700472
Antoine Pitrou424246f2012-05-12 19:02:01 +0200473 @support.skip_unless_symlink
474 @support.skip_unless_xattr
475 @unittest.skipUnless(hasattr(os, 'geteuid') and os.geteuid() == 0,
476 'root privileges required')
477 def test_copyxattr_symlinks(self):
478 # On Linux, it's only possible to access non-user xattr for symlinks;
479 # which in turn require root privileges. This test should be expanded
480 # as soon as other platforms gain support for extended attributes.
481 tmp_dir = self.mkdtemp()
482 src = os.path.join(tmp_dir, 'foo')
483 src_link = os.path.join(tmp_dir, 'baz')
484 write_file(src, 'foo')
485 os.symlink(src, src_link)
486 os.setxattr(src, 'trusted.foo', b'42')
Larry Hastings9cf065c2012-06-22 16:30:09 -0700487 os.setxattr(src_link, 'trusted.foo', b'43', follow_symlinks=False)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200488 dst = os.path.join(tmp_dir, 'bar')
489 dst_link = os.path.join(tmp_dir, 'qux')
490 write_file(dst, 'bar')
491 os.symlink(dst, dst_link)
Larry Hastingsb4038062012-07-15 10:57:38 -0700492 shutil._copyxattr(src_link, dst_link, follow_symlinks=False)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700493 self.assertEqual(os.getxattr(dst_link, 'trusted.foo', follow_symlinks=False), b'43')
Antoine Pitrou424246f2012-05-12 19:02:01 +0200494 self.assertRaises(OSError, os.getxattr, dst, 'trusted.foo')
Larry Hastingsb4038062012-07-15 10:57:38 -0700495 shutil._copyxattr(src_link, dst, follow_symlinks=False)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200496 self.assertEqual(os.getxattr(dst, 'trusted.foo'), b'43')
497
Antoine Pitrou78091e62011-12-29 18:54:15 +0100498 @support.skip_unless_symlink
499 def test_copy_symlinks(self):
500 tmp_dir = self.mkdtemp()
501 src = os.path.join(tmp_dir, 'foo')
502 dst = os.path.join(tmp_dir, 'bar')
503 src_link = os.path.join(tmp_dir, 'baz')
504 write_file(src, 'foo')
505 os.symlink(src, src_link)
506 if hasattr(os, 'lchmod'):
507 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
508 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700509 shutil.copy(src_link, dst, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100510 self.assertFalse(os.path.islink(dst))
511 self.assertEqual(read_file(src), read_file(dst))
512 os.remove(dst)
513 # follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700514 shutil.copy(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100515 self.assertTrue(os.path.islink(dst))
516 self.assertEqual(os.readlink(dst), os.readlink(src_link))
517 if hasattr(os, 'lchmod'):
518 self.assertEqual(os.lstat(src_link).st_mode,
519 os.lstat(dst).st_mode)
520
521 @support.skip_unless_symlink
522 def test_copy2_symlinks(self):
523 tmp_dir = self.mkdtemp()
524 src = os.path.join(tmp_dir, 'foo')
525 dst = os.path.join(tmp_dir, 'bar')
526 src_link = os.path.join(tmp_dir, 'baz')
527 write_file(src, 'foo')
528 os.symlink(src, src_link)
529 if hasattr(os, 'lchmod'):
530 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
531 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
532 os.lchflags(src_link, stat.UF_NODUMP)
533 src_stat = os.stat(src)
534 src_link_stat = os.lstat(src_link)
535 # follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700536 shutil.copy2(src_link, dst, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100537 self.assertFalse(os.path.islink(dst))
538 self.assertEqual(read_file(src), read_file(dst))
539 os.remove(dst)
540 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700541 shutil.copy2(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100542 self.assertTrue(os.path.islink(dst))
543 self.assertEqual(os.readlink(dst), os.readlink(src_link))
544 dst_stat = os.lstat(dst)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700545 if os.utime in os.supports_follow_symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100546 for attr in 'st_atime', 'st_mtime':
547 # The modification times may be truncated in the new file.
548 self.assertLessEqual(getattr(src_link_stat, attr),
549 getattr(dst_stat, attr) + 1)
550 if hasattr(os, 'lchmod'):
551 self.assertEqual(src_link_stat.st_mode, dst_stat.st_mode)
552 self.assertNotEqual(src_stat.st_mode, dst_stat.st_mode)
553 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
554 self.assertEqual(src_link_stat.st_flags, dst_stat.st_flags)
555
Antoine Pitrou424246f2012-05-12 19:02:01 +0200556 @support.skip_unless_xattr
557 def test_copy2_xattr(self):
558 tmp_dir = self.mkdtemp()
559 src = os.path.join(tmp_dir, 'foo')
560 dst = os.path.join(tmp_dir, 'bar')
561 write_file(src, 'foo')
562 os.setxattr(src, 'user.foo', b'42')
563 shutil.copy2(src, dst)
564 self.assertEqual(
565 os.getxattr(src, 'user.foo'),
566 os.getxattr(dst, 'user.foo'))
567 os.remove(dst)
568
Antoine Pitrou78091e62011-12-29 18:54:15 +0100569 @support.skip_unless_symlink
570 def test_copyfile_symlinks(self):
571 tmp_dir = self.mkdtemp()
572 src = os.path.join(tmp_dir, 'src')
573 dst = os.path.join(tmp_dir, 'dst')
574 dst_link = os.path.join(tmp_dir, 'dst_link')
575 link = os.path.join(tmp_dir, 'link')
576 write_file(src, 'foo')
577 os.symlink(src, link)
578 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700579 shutil.copyfile(link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100580 self.assertTrue(os.path.islink(dst_link))
581 self.assertEqual(os.readlink(link), os.readlink(dst_link))
582 # follow
583 shutil.copyfile(link, dst)
584 self.assertFalse(os.path.islink(dst))
585
Hynek Schlawack2100b422012-06-23 20:28:32 +0200586 def test_rmtree_uses_safe_fd_version_if_available(self):
Hynek Schlawackd0f6e0a2012-06-29 08:28:20 +0200587 _use_fd_functions = ({os.open, os.stat, os.unlink, os.rmdir} <=
588 os.supports_dir_fd and
589 os.listdir in os.supports_fd and
590 os.stat in os.supports_follow_symlinks)
591 if _use_fd_functions:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200592 self.assertTrue(shutil._use_fd_functions)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000593 self.assertTrue(shutil.rmtree.avoids_symlink_attacks)
Hynek Schlawack2100b422012-06-23 20:28:32 +0200594 tmp_dir = self.mkdtemp()
595 d = os.path.join(tmp_dir, 'a')
596 os.mkdir(d)
597 try:
598 real_rmtree = shutil._rmtree_safe_fd
599 class Called(Exception): pass
600 def _raiser(*args, **kwargs):
601 raise Called
602 shutil._rmtree_safe_fd = _raiser
603 self.assertRaises(Called, shutil.rmtree, d)
604 finally:
605 shutil._rmtree_safe_fd = real_rmtree
606 else:
607 self.assertFalse(shutil._use_fd_functions)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000608 self.assertFalse(shutil.rmtree.avoids_symlink_attacks)
Hynek Schlawack2100b422012-06-23 20:28:32 +0200609
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000610 def test_rmtree_dont_delete_file(self):
611 # When called on a file instead of a directory, don't delete it.
612 handle, path = tempfile.mkstemp()
Victor Stinnerbf816222011-06-30 23:25:47 +0200613 os.close(handle)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200614 self.assertRaises(NotADirectoryError, shutil.rmtree, path)
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000615 os.remove(path)
616
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000617 def test_copytree_simple(self):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000618 src_dir = tempfile.mkdtemp()
619 dst_dir = os.path.join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200620 self.addCleanup(shutil.rmtree, src_dir)
621 self.addCleanup(shutil.rmtree, os.path.dirname(dst_dir))
622 write_file((src_dir, 'test.txt'), '123')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000623 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200624 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000625
Éric Araujoa7e33a12011-08-12 19:51:35 +0200626 shutil.copytree(src_dir, dst_dir)
627 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test.txt')))
628 self.assertTrue(os.path.isdir(os.path.join(dst_dir, 'test_dir')))
629 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test_dir',
630 'test.txt')))
631 actual = read_file((dst_dir, 'test.txt'))
632 self.assertEqual(actual, '123')
633 actual = read_file((dst_dir, 'test_dir', 'test.txt'))
634 self.assertEqual(actual, '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000635
Antoine Pitrou78091e62011-12-29 18:54:15 +0100636 @support.skip_unless_symlink
637 def test_copytree_symlinks(self):
638 tmp_dir = self.mkdtemp()
639 src_dir = os.path.join(tmp_dir, 'src')
640 dst_dir = os.path.join(tmp_dir, 'dst')
641 sub_dir = os.path.join(src_dir, 'sub')
642 os.mkdir(src_dir)
643 os.mkdir(sub_dir)
644 write_file((src_dir, 'file.txt'), 'foo')
645 src_link = os.path.join(sub_dir, 'link')
646 dst_link = os.path.join(dst_dir, 'sub/link')
647 os.symlink(os.path.join(src_dir, 'file.txt'),
648 src_link)
649 if hasattr(os, 'lchmod'):
650 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
651 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
652 os.lchflags(src_link, stat.UF_NODUMP)
653 src_stat = os.lstat(src_link)
654 shutil.copytree(src_dir, dst_dir, symlinks=True)
655 self.assertTrue(os.path.islink(os.path.join(dst_dir, 'sub', 'link')))
656 self.assertEqual(os.readlink(os.path.join(dst_dir, 'sub', 'link')),
657 os.path.join(src_dir, 'file.txt'))
658 dst_stat = os.lstat(dst_link)
659 if hasattr(os, 'lchmod'):
660 self.assertEqual(dst_stat.st_mode, src_stat.st_mode)
661 if hasattr(os, 'lchflags'):
662 self.assertEqual(dst_stat.st_flags, src_stat.st_flags)
663
Georg Brandl2ee470f2008-07-16 12:55:28 +0000664 def test_copytree_with_exclude(self):
Georg Brandl2ee470f2008-07-16 12:55:28 +0000665 # creating data
666 join = os.path.join
667 exists = os.path.exists
668 src_dir = tempfile.mkdtemp()
Georg Brandl2ee470f2008-07-16 12:55:28 +0000669 try:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000670 dst_dir = join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200671 write_file((src_dir, 'test.txt'), '123')
672 write_file((src_dir, 'test.tmp'), '123')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000673 os.mkdir(join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200674 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000675 os.mkdir(join(src_dir, 'test_dir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200676 write_file((src_dir, 'test_dir2', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000677 os.mkdir(join(src_dir, 'test_dir2', 'subdir'))
678 os.mkdir(join(src_dir, 'test_dir2', 'subdir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200679 write_file((src_dir, 'test_dir2', 'subdir', 'test.txt'), '456')
680 write_file((src_dir, 'test_dir2', 'subdir2', 'test.py'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000681
682 # testing glob-like patterns
683 try:
684 patterns = shutil.ignore_patterns('*.tmp', 'test_dir2')
685 shutil.copytree(src_dir, dst_dir, ignore=patterns)
686 # checking the result: some elements should not be copied
687 self.assertTrue(exists(join(dst_dir, 'test.txt')))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200688 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
689 self.assertFalse(exists(join(dst_dir, 'test_dir2')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000690 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200691 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000692 try:
693 patterns = shutil.ignore_patterns('*.tmp', 'subdir*')
694 shutil.copytree(src_dir, dst_dir, ignore=patterns)
695 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200696 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
697 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2')))
698 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000699 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200700 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000701
702 # testing callable-style
703 try:
704 def _filter(src, names):
705 res = []
706 for name in names:
707 path = os.path.join(src, name)
708
709 if (os.path.isdir(path) and
710 path.split()[-1] == 'subdir'):
711 res.append(name)
712 elif os.path.splitext(path)[-1] in ('.py'):
713 res.append(name)
714 return res
715
716 shutil.copytree(src_dir, dst_dir, ignore=_filter)
717
718 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200719 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2',
720 'test.py')))
721 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000722
723 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200724 shutil.rmtree(dst_dir)
Georg Brandl2ee470f2008-07-16 12:55:28 +0000725 finally:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000726 shutil.rmtree(src_dir)
727 shutil.rmtree(os.path.dirname(dst_dir))
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000728
Antoine Pitrouac601602013-08-16 19:35:02 +0200729 def test_copytree_retains_permissions(self):
730 tmp_dir = tempfile.mkdtemp()
731 src_dir = os.path.join(tmp_dir, 'source')
732 os.mkdir(src_dir)
733 dst_dir = os.path.join(tmp_dir, 'destination')
734 self.addCleanup(shutil.rmtree, tmp_dir)
735
736 os.chmod(src_dir, 0o777)
737 write_file((src_dir, 'permissive.txt'), '123')
738 os.chmod(os.path.join(src_dir, 'permissive.txt'), 0o777)
739 write_file((src_dir, 'restrictive.txt'), '456')
740 os.chmod(os.path.join(src_dir, 'restrictive.txt'), 0o600)
741 restrictive_subdir = tempfile.mkdtemp(dir=src_dir)
742 os.chmod(restrictive_subdir, 0o600)
743
744 shutil.copytree(src_dir, dst_dir)
745 self.assertEquals(os.stat(src_dir).st_mode, os.stat(dst_dir).st_mode)
746 self.assertEquals(os.stat(os.path.join(src_dir, 'permissive.txt')).st_mode,
747 os.stat(os.path.join(dst_dir, 'permissive.txt')).st_mode)
748 self.assertEquals(os.stat(os.path.join(src_dir, 'restrictive.txt')).st_mode,
749 os.stat(os.path.join(dst_dir, 'restrictive.txt')).st_mode)
750 restrictive_subdir_dst = os.path.join(dst_dir,
751 os.path.split(restrictive_subdir)[1])
752 self.assertEquals(os.stat(restrictive_subdir).st_mode,
753 os.stat(restrictive_subdir_dst).st_mode)
754
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000755 @unittest.skipUnless(hasattr(os, 'link'), 'requires os.link')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000756 def test_dont_copy_file_onto_link_to_itself(self):
Georg Brandl724d0892010-12-05 07:51:39 +0000757 # Temporarily disable test on Windows.
758 if os.name == 'nt':
759 return
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000760 # bug 851123.
761 os.mkdir(TESTFN)
762 src = os.path.join(TESTFN, 'cheese')
763 dst = os.path.join(TESTFN, 'shop')
764 try:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000765 with open(src, 'w') as f:
766 f.write('cheddar')
767 os.link(src, dst)
Hynek Schlawack26fe37d2012-07-19 21:41:02 +0200768 self.assertRaises(shutil.Error, shutil.copyfile, src, dst)
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000769 with open(src, 'r') as f:
770 self.assertEqual(f.read(), 'cheddar')
771 os.remove(dst)
772 finally:
773 shutil.rmtree(TESTFN, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000774
Brian Curtin3b4499c2010-12-28 14:31:47 +0000775 @support.skip_unless_symlink
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000776 def test_dont_copy_file_onto_symlink_to_itself(self):
777 # bug 851123.
778 os.mkdir(TESTFN)
779 src = os.path.join(TESTFN, 'cheese')
780 dst = os.path.join(TESTFN, 'shop')
781 try:
782 with open(src, 'w') as f:
783 f.write('cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000784 # Using `src` here would mean we end up with a symlink pointing
785 # to TESTFN/TESTFN/cheese, while it should point at
786 # TESTFN/cheese.
787 os.symlink('cheese', dst)
Hynek Schlawack26fe37d2012-07-19 21:41:02 +0200788 self.assertRaises(shutil.Error, shutil.copyfile, src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +0000789 with open(src, 'r') as f:
790 self.assertEqual(f.read(), 'cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000791 os.remove(dst)
792 finally:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000793 shutil.rmtree(TESTFN, ignore_errors=True)
Johannes Gijsbers68128712004-08-14 13:57:08 +0000794
Brian Curtin3b4499c2010-12-28 14:31:47 +0000795 @support.skip_unless_symlink
Brian Curtind40e6f72010-07-08 21:39:08 +0000796 def test_rmtree_on_symlink(self):
797 # bug 1669.
798 os.mkdir(TESTFN)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000799 try:
Brian Curtind40e6f72010-07-08 21:39:08 +0000800 src = os.path.join(TESTFN, 'cheese')
801 dst = os.path.join(TESTFN, 'shop')
802 os.mkdir(src)
803 os.symlink(src, dst)
804 self.assertRaises(OSError, shutil.rmtree, dst)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200805 shutil.rmtree(dst, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000806 finally:
Brian Curtind40e6f72010-07-08 21:39:08 +0000807 shutil.rmtree(TESTFN, ignore_errors=True)
808
809 if hasattr(os, "mkfifo"):
810 # Issue #3002: copyfile and copytree block indefinitely on named pipes
811 def test_copyfile_named_pipe(self):
812 os.mkfifo(TESTFN)
813 try:
814 self.assertRaises(shutil.SpecialFileError,
815 shutil.copyfile, TESTFN, TESTFN2)
816 self.assertRaises(shutil.SpecialFileError,
817 shutil.copyfile, __file__, TESTFN)
818 finally:
819 os.remove(TESTFN)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000820
Brian Curtin3b4499c2010-12-28 14:31:47 +0000821 @support.skip_unless_symlink
Brian Curtin52173d42010-12-02 18:29:18 +0000822 def test_copytree_named_pipe(self):
823 os.mkdir(TESTFN)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000824 try:
Brian Curtin52173d42010-12-02 18:29:18 +0000825 subdir = os.path.join(TESTFN, "subdir")
826 os.mkdir(subdir)
827 pipe = os.path.join(subdir, "mypipe")
828 os.mkfifo(pipe)
829 try:
830 shutil.copytree(TESTFN, TESTFN2)
831 except shutil.Error as e:
832 errors = e.args[0]
833 self.assertEqual(len(errors), 1)
834 src, dst, error_msg = errors[0]
835 self.assertEqual("`%s` is a named pipe" % pipe, error_msg)
836 else:
837 self.fail("shutil.Error should have been raised")
838 finally:
839 shutil.rmtree(TESTFN, ignore_errors=True)
840 shutil.rmtree(TESTFN2, ignore_errors=True)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000841
Tarek Ziadé5340db32010-04-19 22:30:51 +0000842 def test_copytree_special_func(self):
843
844 src_dir = self.mkdtemp()
845 dst_dir = os.path.join(self.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200846 write_file((src_dir, 'test.txt'), '123')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000847 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200848 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000849
850 copied = []
851 def _copy(src, dst):
852 copied.append((src, dst))
853
854 shutil.copytree(src_dir, dst_dir, copy_function=_copy)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000855 self.assertEqual(len(copied), 2)
Tarek Ziadé5340db32010-04-19 22:30:51 +0000856
Brian Curtin3b4499c2010-12-28 14:31:47 +0000857 @support.skip_unless_symlink
Tarek Ziadéfb437512010-04-20 08:57:33 +0000858 def test_copytree_dangling_symlinks(self):
859
860 # a dangling symlink raises an error at the end
861 src_dir = self.mkdtemp()
862 dst_dir = os.path.join(self.mkdtemp(), 'destination')
863 os.symlink('IDONTEXIST', os.path.join(src_dir, 'test.txt'))
864 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200865 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadéfb437512010-04-20 08:57:33 +0000866 self.assertRaises(Error, shutil.copytree, src_dir, dst_dir)
867
868 # a dangling symlink is ignored with the proper flag
869 dst_dir = os.path.join(self.mkdtemp(), 'destination2')
870 shutil.copytree(src_dir, dst_dir, ignore_dangling_symlinks=True)
871 self.assertNotIn('test.txt', os.listdir(dst_dir))
872
873 # a dangling symlink is copied if symlinks=True
874 dst_dir = os.path.join(self.mkdtemp(), 'destination3')
875 shutil.copytree(src_dir, dst_dir, symlinks=True)
876 self.assertIn('test.txt', os.listdir(dst_dir))
877
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400878 def _copy_file(self, method):
879 fname = 'test.txt'
880 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200881 write_file((tmpdir, fname), 'xxx')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400882 file1 = os.path.join(tmpdir, fname)
883 tmpdir2 = self.mkdtemp()
884 method(file1, tmpdir2)
885 file2 = os.path.join(tmpdir2, fname)
886 return (file1, file2)
887
888 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
889 def test_copy(self):
890 # Ensure that the copied file exists and has the same mode bits.
891 file1, file2 = self._copy_file(shutil.copy)
892 self.assertTrue(os.path.exists(file2))
893 self.assertEqual(os.stat(file1).st_mode, os.stat(file2).st_mode)
894
895 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
Senthil Kumaran0c2dba52011-07-03 18:21:38 -0700896 @unittest.skipUnless(hasattr(os, 'utime'), 'requires os.utime')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400897 def test_copy2(self):
898 # Ensure that the copied file exists and has the same mode and
899 # modification time bits.
900 file1, file2 = self._copy_file(shutil.copy2)
901 self.assertTrue(os.path.exists(file2))
902 file1_stat = os.stat(file1)
903 file2_stat = os.stat(file2)
904 self.assertEqual(file1_stat.st_mode, file2_stat.st_mode)
905 for attr in 'st_atime', 'st_mtime':
906 # The modification times may be truncated in the new file.
907 self.assertLessEqual(getattr(file1_stat, attr),
908 getattr(file2_stat, attr) + 1)
909 if hasattr(os, 'chflags') and hasattr(file1_stat, 'st_flags'):
910 self.assertEqual(getattr(file1_stat, 'st_flags'),
911 getattr(file2_stat, 'st_flags'))
912
Ezio Melotti975077a2011-05-19 22:03:22 +0300913 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000914 def test_make_tarball(self):
915 # creating something to tar
916 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200917 write_file((tmpdir, 'file1'), 'xxx')
918 write_file((tmpdir, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000919 os.mkdir(os.path.join(tmpdir, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200920 write_file((tmpdir, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000921
922 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400923 # force shutil to create the directory
924 os.rmdir(tmpdir2)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000925 unittest.skipUnless(splitdrive(tmpdir)[0] == splitdrive(tmpdir2)[0],
926 "source and target should be on same drive")
927
928 base_name = os.path.join(tmpdir2, 'archive')
929
930 # working with relative paths to avoid tar warnings
931 old_dir = os.getcwd()
932 os.chdir(tmpdir)
933 try:
934 _make_tarball(splitdrive(base_name)[1], '.')
935 finally:
936 os.chdir(old_dir)
937
938 # check if the compressed tarball was created
939 tarball = base_name + '.tar.gz'
940 self.assertTrue(os.path.exists(tarball))
941
942 # trying an uncompressed one
943 base_name = os.path.join(tmpdir2, 'archive')
944 old_dir = os.getcwd()
945 os.chdir(tmpdir)
946 try:
947 _make_tarball(splitdrive(base_name)[1], '.', compress=None)
948 finally:
949 os.chdir(old_dir)
950 tarball = base_name + '.tar'
951 self.assertTrue(os.path.exists(tarball))
952
953 def _tarinfo(self, path):
954 tar = tarfile.open(path)
955 try:
956 names = tar.getnames()
957 names.sort()
958 return tuple(names)
959 finally:
960 tar.close()
961
962 def _create_files(self):
963 # creating something to tar
964 tmpdir = self.mkdtemp()
965 dist = os.path.join(tmpdir, 'dist')
966 os.mkdir(dist)
Éric Araujoa7e33a12011-08-12 19:51:35 +0200967 write_file((dist, 'file1'), 'xxx')
968 write_file((dist, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000969 os.mkdir(os.path.join(dist, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200970 write_file((dist, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000971 os.mkdir(os.path.join(dist, 'sub2'))
972 tmpdir2 = self.mkdtemp()
973 base_name = os.path.join(tmpdir2, 'archive')
974 return tmpdir, tmpdir2, base_name
975
Ezio Melotti975077a2011-05-19 22:03:22 +0300976 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000977 @unittest.skipUnless(find_executable('tar') and find_executable('gzip'),
978 'Need the tar command to run')
979 def test_tarfile_vs_tar(self):
980 tmpdir, tmpdir2, base_name = self._create_files()
981 old_dir = os.getcwd()
982 os.chdir(tmpdir)
983 try:
984 _make_tarball(base_name, 'dist')
985 finally:
986 os.chdir(old_dir)
987
988 # check if the compressed tarball was created
989 tarball = base_name + '.tar.gz'
990 self.assertTrue(os.path.exists(tarball))
991
992 # now create another tarball using `tar`
993 tarball2 = os.path.join(tmpdir, 'archive2.tar.gz')
994 tar_cmd = ['tar', '-cf', 'archive2.tar', 'dist']
995 gzip_cmd = ['gzip', '-f9', 'archive2.tar']
996 old_dir = os.getcwd()
997 os.chdir(tmpdir)
998 try:
999 with captured_stdout() as s:
1000 spawn(tar_cmd)
1001 spawn(gzip_cmd)
1002 finally:
1003 os.chdir(old_dir)
1004
1005 self.assertTrue(os.path.exists(tarball2))
1006 # let's compare both tarballs
Ezio Melottib3aedd42010-11-20 19:04:17 +00001007 self.assertEqual(self._tarinfo(tarball), self._tarinfo(tarball2))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001008
1009 # trying an uncompressed one
1010 base_name = os.path.join(tmpdir2, 'archive')
1011 old_dir = os.getcwd()
1012 os.chdir(tmpdir)
1013 try:
1014 _make_tarball(base_name, 'dist', compress=None)
1015 finally:
1016 os.chdir(old_dir)
1017 tarball = base_name + '.tar'
1018 self.assertTrue(os.path.exists(tarball))
1019
1020 # now for a dry_run
1021 base_name = os.path.join(tmpdir2, 'archive')
1022 old_dir = os.getcwd()
1023 os.chdir(tmpdir)
1024 try:
1025 _make_tarball(base_name, 'dist', compress=None, dry_run=True)
1026 finally:
1027 os.chdir(old_dir)
1028 tarball = base_name + '.tar'
1029 self.assertTrue(os.path.exists(tarball))
1030
Ezio Melotti975077a2011-05-19 22:03:22 +03001031 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001032 @unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run')
1033 def test_make_zipfile(self):
1034 # creating something to tar
1035 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +02001036 write_file((tmpdir, 'file1'), 'xxx')
1037 write_file((tmpdir, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +00001038
1039 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001040 # force shutil to create the directory
1041 os.rmdir(tmpdir2)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001042 base_name = os.path.join(tmpdir2, 'archive')
1043 _make_zipfile(base_name, tmpdir)
1044
1045 # check if the compressed tarball was created
1046 tarball = base_name + '.zip'
Éric Araujo1c505492010-11-06 02:12:51 +00001047 self.assertTrue(os.path.exists(tarball))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001048
1049
1050 def test_make_archive(self):
1051 tmpdir = self.mkdtemp()
1052 base_name = os.path.join(tmpdir, 'archive')
1053 self.assertRaises(ValueError, make_archive, base_name, 'xxx')
1054
Ezio Melotti975077a2011-05-19 22:03:22 +03001055 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001056 def test_make_archive_owner_group(self):
1057 # testing make_archive with owner and group, with various combinations
1058 # this works even if there's not gid/uid support
1059 if UID_GID_SUPPORT:
1060 group = grp.getgrgid(0)[0]
1061 owner = pwd.getpwuid(0)[0]
1062 else:
1063 group = owner = 'root'
1064
1065 base_dir, root_dir, base_name = self._create_files()
1066 base_name = os.path.join(self.mkdtemp() , 'archive')
1067 res = make_archive(base_name, 'zip', root_dir, base_dir, owner=owner,
1068 group=group)
1069 self.assertTrue(os.path.exists(res))
1070
1071 res = make_archive(base_name, 'zip', root_dir, base_dir)
1072 self.assertTrue(os.path.exists(res))
1073
1074 res = make_archive(base_name, 'tar', root_dir, base_dir,
1075 owner=owner, group=group)
1076 self.assertTrue(os.path.exists(res))
1077
1078 res = make_archive(base_name, 'tar', root_dir, base_dir,
1079 owner='kjhkjhkjg', group='oihohoh')
1080 self.assertTrue(os.path.exists(res))
1081
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001082
Ezio Melotti975077a2011-05-19 22:03:22 +03001083 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001084 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1085 def test_tarfile_root_owner(self):
1086 tmpdir, tmpdir2, base_name = self._create_files()
1087 old_dir = os.getcwd()
1088 os.chdir(tmpdir)
1089 group = grp.getgrgid(0)[0]
1090 owner = pwd.getpwuid(0)[0]
1091 try:
1092 archive_name = _make_tarball(base_name, 'dist', compress=None,
1093 owner=owner, group=group)
1094 finally:
1095 os.chdir(old_dir)
1096
1097 # check if the compressed tarball was created
1098 self.assertTrue(os.path.exists(archive_name))
1099
1100 # now checks the rights
1101 archive = tarfile.open(archive_name)
1102 try:
1103 for member in archive.getmembers():
Ezio Melottib3aedd42010-11-20 19:04:17 +00001104 self.assertEqual(member.uid, 0)
1105 self.assertEqual(member.gid, 0)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001106 finally:
1107 archive.close()
1108
1109 def test_make_archive_cwd(self):
1110 current_dir = os.getcwd()
1111 def _breaks(*args, **kw):
1112 raise RuntimeError()
1113
1114 register_archive_format('xxx', _breaks, [], 'xxx file')
1115 try:
1116 try:
1117 make_archive('xxx', 'xxx', root_dir=self.mkdtemp())
1118 except Exception:
1119 pass
Ezio Melottib3aedd42010-11-20 19:04:17 +00001120 self.assertEqual(os.getcwd(), current_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001121 finally:
1122 unregister_archive_format('xxx')
1123
1124 def test_register_archive_format(self):
1125
1126 self.assertRaises(TypeError, register_archive_format, 'xxx', 1)
1127 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1128 1)
1129 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1130 [(1, 2), (1, 2, 3)])
1131
1132 register_archive_format('xxx', lambda: x, [(1, 2)], 'xxx file')
1133 formats = [name for name, params in get_archive_formats()]
1134 self.assertIn('xxx', formats)
1135
1136 unregister_archive_format('xxx')
1137 formats = [name for name, params in get_archive_formats()]
1138 self.assertNotIn('xxx', formats)
1139
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001140 def _compare_dirs(self, dir1, dir2):
1141 # check that dir1 and dir2 are equivalent,
1142 # return the diff
1143 diff = []
1144 for root, dirs, files in os.walk(dir1):
1145 for file_ in files:
1146 path = os.path.join(root, file_)
1147 target_path = os.path.join(dir2, os.path.split(path)[-1])
1148 if not os.path.exists(target_path):
1149 diff.append(file_)
1150 return diff
1151
Ezio Melotti975077a2011-05-19 22:03:22 +03001152 @requires_zlib
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001153 def test_unpack_archive(self):
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001154 formats = ['tar', 'gztar', 'zip']
1155 if BZ2_SUPPORTED:
1156 formats.append('bztar')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001157
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001158 for format in formats:
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001159 tmpdir = self.mkdtemp()
1160 base_dir, root_dir, base_name = self._create_files()
1161 tmpdir2 = self.mkdtemp()
1162 filename = make_archive(base_name, format, root_dir, base_dir)
1163
1164 # let's try to unpack it now
1165 unpack_archive(filename, tmpdir2)
1166 diff = self._compare_dirs(tmpdir, tmpdir2)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001167 self.assertEqual(diff, [])
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001168
Nick Coghlanabf202d2011-03-16 13:52:20 -04001169 # and again, this time with the format specified
1170 tmpdir3 = self.mkdtemp()
1171 unpack_archive(filename, tmpdir3, format=format)
1172 diff = self._compare_dirs(tmpdir, tmpdir3)
1173 self.assertEqual(diff, [])
1174 self.assertRaises(shutil.ReadError, unpack_archive, TESTFN)
1175 self.assertRaises(ValueError, unpack_archive, TESTFN, format='xxx')
1176
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001177 def test_unpack_registery(self):
1178
1179 formats = get_unpack_formats()
1180
1181 def _boo(filename, extract_dir, extra):
Ezio Melottib3aedd42010-11-20 19:04:17 +00001182 self.assertEqual(extra, 1)
1183 self.assertEqual(filename, 'stuff.boo')
1184 self.assertEqual(extract_dir, 'xx')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001185
1186 register_unpack_format('Boo', ['.boo', '.b2'], _boo, [('extra', 1)])
1187 unpack_archive('stuff.boo', 'xx')
1188
1189 # trying to register a .boo unpacker again
1190 self.assertRaises(RegistryError, register_unpack_format, 'Boo2',
1191 ['.boo'], _boo)
1192
1193 # should work now
1194 unregister_unpack_format('Boo')
1195 register_unpack_format('Boo2', ['.boo'], _boo)
1196 self.assertIn(('Boo2', ['.boo'], ''), get_unpack_formats())
1197 self.assertNotIn(('Boo', ['.boo'], ''), get_unpack_formats())
1198
1199 # let's leave a clean state
1200 unregister_unpack_format('Boo2')
Ezio Melottib3aedd42010-11-20 19:04:17 +00001201 self.assertEqual(get_unpack_formats(), formats)
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001202
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001203 @unittest.skipUnless(hasattr(shutil, 'disk_usage'),
1204 "disk_usage not available on this platform")
1205 def test_disk_usage(self):
1206 usage = shutil.disk_usage(os.getcwd())
Éric Araujo2ee61882011-07-02 16:45:45 +02001207 self.assertGreater(usage.total, 0)
1208 self.assertGreater(usage.used, 0)
1209 self.assertGreaterEqual(usage.free, 0)
1210 self.assertGreaterEqual(usage.total, usage.used)
1211 self.assertGreater(usage.total, usage.free)
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001212
Sandro Tosid902a142011-08-22 23:28:27 +02001213 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1214 @unittest.skipUnless(hasattr(os, 'chown'), 'requires os.chown')
1215 def test_chown(self):
1216
1217 # cleaned-up automatically by TestShutil.tearDown method
1218 dirname = self.mkdtemp()
1219 filename = tempfile.mktemp(dir=dirname)
1220 write_file(filename, 'testing chown function')
1221
1222 with self.assertRaises(ValueError):
1223 shutil.chown(filename)
1224
1225 with self.assertRaises(LookupError):
1226 shutil.chown(filename, user='non-exising username')
1227
1228 with self.assertRaises(LookupError):
1229 shutil.chown(filename, group='non-exising groupname')
1230
1231 with self.assertRaises(TypeError):
1232 shutil.chown(filename, b'spam')
1233
1234 with self.assertRaises(TypeError):
1235 shutil.chown(filename, 3.14)
1236
1237 uid = os.getuid()
1238 gid = os.getgid()
1239
1240 def check_chown(path, uid=None, gid=None):
1241 s = os.stat(filename)
1242 if uid is not None:
1243 self.assertEqual(uid, s.st_uid)
1244 if gid is not None:
1245 self.assertEqual(gid, s.st_gid)
1246
1247 shutil.chown(filename, uid, gid)
1248 check_chown(filename, uid, gid)
1249 shutil.chown(filename, uid)
1250 check_chown(filename, uid)
1251 shutil.chown(filename, user=uid)
1252 check_chown(filename, uid)
1253 shutil.chown(filename, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001254 check_chown(filename, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001255
1256 shutil.chown(dirname, uid, gid)
1257 check_chown(dirname, uid, gid)
1258 shutil.chown(dirname, uid)
1259 check_chown(dirname, uid)
1260 shutil.chown(dirname, user=uid)
1261 check_chown(dirname, uid)
1262 shutil.chown(dirname, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001263 check_chown(dirname, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001264
1265 user = pwd.getpwuid(uid)[0]
1266 group = grp.getgrgid(gid)[0]
1267 shutil.chown(filename, user, group)
1268 check_chown(filename, uid, gid)
1269 shutil.chown(dirname, user, group)
1270 check_chown(dirname, uid, gid)
1271
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001272 def test_copy_return_value(self):
1273 # copy and copy2 both return their destination path.
1274 for fn in (shutil.copy, shutil.copy2):
1275 src_dir = self.mkdtemp()
1276 dst_dir = self.mkdtemp()
1277 src = os.path.join(src_dir, 'foo')
1278 write_file(src, 'foo')
1279 rv = fn(src, dst_dir)
1280 self.assertEqual(rv, os.path.join(dst_dir, 'foo'))
1281 rv = fn(src, os.path.join(dst_dir, 'bar'))
1282 self.assertEqual(rv, os.path.join(dst_dir, 'bar'))
1283
1284 def test_copyfile_return_value(self):
1285 # copytree returns its destination path.
1286 src_dir = self.mkdtemp()
1287 dst_dir = self.mkdtemp()
1288 dst_file = os.path.join(dst_dir, 'bar')
1289 src_file = os.path.join(src_dir, 'foo')
1290 write_file(src_file, 'foo')
1291 rv = shutil.copyfile(src_file, dst_file)
1292 self.assertTrue(os.path.exists(rv))
1293 self.assertEqual(read_file(src_file), read_file(dst_file))
1294
1295 def test_copytree_return_value(self):
1296 # copytree returns its destination path.
1297 src_dir = self.mkdtemp()
1298 dst_dir = src_dir + "dest"
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001299 self.addCleanup(shutil.rmtree, dst_dir, True)
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001300 src = os.path.join(src_dir, 'foo')
1301 write_file(src, 'foo')
1302 rv = shutil.copytree(src_dir, dst_dir)
1303 self.assertEqual(['foo'], os.listdir(rv))
1304
Christian Heimes9bd667a2008-01-20 15:14:11 +00001305
Brian Curtinc57a3452012-06-22 16:00:30 -05001306class TestWhich(unittest.TestCase):
1307
1308 def setUp(self):
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001309 self.temp_dir = tempfile.mkdtemp(prefix="Tmp")
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001310 self.addCleanup(shutil.rmtree, self.temp_dir, True)
Brian Curtinc57a3452012-06-22 16:00:30 -05001311 # Give the temp_file an ".exe" suffix for all.
1312 # It's needed on Windows and not harmful on other platforms.
1313 self.temp_file = tempfile.NamedTemporaryFile(dir=self.temp_dir,
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001314 prefix="Tmp",
1315 suffix=".Exe")
Brian Curtinc57a3452012-06-22 16:00:30 -05001316 os.chmod(self.temp_file.name, stat.S_IXUSR)
1317 self.addCleanup(self.temp_file.close)
1318 self.dir, self.file = os.path.split(self.temp_file.name)
1319
1320 def test_basic(self):
1321 # Given an EXE in a directory, it should be returned.
1322 rv = shutil.which(self.file, path=self.dir)
1323 self.assertEqual(rv, self.temp_file.name)
1324
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001325 def test_absolute_cmd(self):
Brian Curtinc57a3452012-06-22 16:00:30 -05001326 # When given the fully qualified path to an executable that exists,
1327 # it should be returned.
1328 rv = shutil.which(self.temp_file.name, path=self.temp_dir)
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001329 self.assertEqual(rv, self.temp_file.name)
1330
1331 def test_relative_cmd(self):
1332 # When given the relative path with a directory part to an executable
1333 # that exists, it should be returned.
1334 base_dir, tail_dir = os.path.split(self.dir)
1335 relpath = os.path.join(tail_dir, self.file)
Nick Coghlan55175962013-07-28 22:11:50 +10001336 with support.change_cwd(path=base_dir):
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001337 rv = shutil.which(relpath, path=self.temp_dir)
1338 self.assertEqual(rv, relpath)
1339 # But it shouldn't be searched in PATH directories (issue #16957).
Nick Coghlan55175962013-07-28 22:11:50 +10001340 with support.change_cwd(path=self.dir):
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001341 rv = shutil.which(relpath, path=base_dir)
1342 self.assertIsNone(rv)
1343
1344 def test_cwd(self):
1345 # Issue #16957
1346 base_dir = os.path.dirname(self.dir)
Nick Coghlan55175962013-07-28 22:11:50 +10001347 with support.change_cwd(path=self.dir):
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001348 rv = shutil.which(self.file, path=base_dir)
1349 if sys.platform == "win32":
1350 # Windows: current directory implicitly on PATH
1351 self.assertEqual(rv, os.path.join(os.curdir, self.file))
1352 else:
1353 # Other platforms: shouldn't match in the current directory.
1354 self.assertIsNone(rv)
Brian Curtinc57a3452012-06-22 16:00:30 -05001355
Serhiy Storchaka12516e22013-05-28 15:50:15 +03001356 @unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0,
1357 'non-root user required')
Brian Curtinc57a3452012-06-22 16:00:30 -05001358 def test_non_matching_mode(self):
1359 # Set the file read-only and ask for writeable files.
1360 os.chmod(self.temp_file.name, stat.S_IREAD)
Serhiy Storchaka12516e22013-05-28 15:50:15 +03001361 if os.access(self.temp_file.name, os.W_OK):
1362 self.skipTest("can't set the file read-only")
Brian Curtinc57a3452012-06-22 16:00:30 -05001363 rv = shutil.which(self.file, path=self.dir, mode=os.W_OK)
1364 self.assertIsNone(rv)
1365
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001366 def test_relative_path(self):
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001367 base_dir, tail_dir = os.path.split(self.dir)
Nick Coghlan55175962013-07-28 22:11:50 +10001368 with support.change_cwd(path=base_dir):
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001369 rv = shutil.which(self.file, path=tail_dir)
1370 self.assertEqual(rv, os.path.join(tail_dir, self.file))
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001371
Brian Curtinc57a3452012-06-22 16:00:30 -05001372 def test_nonexistent_file(self):
1373 # Return None when no matching executable file is found on the path.
1374 rv = shutil.which("foo.exe", path=self.dir)
1375 self.assertIsNone(rv)
1376
1377 @unittest.skipUnless(sys.platform == "win32",
1378 "pathext check is Windows-only")
1379 def test_pathext_checking(self):
1380 # Ask for the file without the ".exe" extension, then ensure that
1381 # it gets found properly with the extension.
Serhiy Storchakad70127a2013-01-24 20:03:49 +02001382 rv = shutil.which(self.file[:-4], path=self.dir)
Serhiy Storchaka80c88f42013-01-22 10:31:36 +02001383 self.assertEqual(rv, self.temp_file.name[:-4] + ".EXE")
Brian Curtinc57a3452012-06-22 16:00:30 -05001384
Barry Warsaw618738b2013-04-16 11:05:03 -04001385 def test_environ_path(self):
1386 with support.EnvironmentVarGuard() as env:
1387 env['PATH'] = self.dir
1388 rv = shutil.which(self.file)
1389 self.assertEqual(rv, self.temp_file.name)
1390
1391 def test_empty_path(self):
1392 base_dir = os.path.dirname(self.dir)
Nick Coghlan55175962013-07-28 22:11:50 +10001393 with support.change_cwd(path=self.dir), \
Barry Warsaw618738b2013-04-16 11:05:03 -04001394 support.EnvironmentVarGuard() as env:
1395 env['PATH'] = self.dir
1396 rv = shutil.which(self.file, path='')
1397 self.assertIsNone(rv)
1398
1399 def test_empty_path_no_PATH(self):
1400 with support.EnvironmentVarGuard() as env:
1401 env.pop('PATH', None)
1402 rv = shutil.which(self.file)
1403 self.assertIsNone(rv)
1404
Brian Curtinc57a3452012-06-22 16:00:30 -05001405
Christian Heimesada8c3b2008-03-18 18:26:33 +00001406class TestMove(unittest.TestCase):
1407
1408 def setUp(self):
1409 filename = "foo"
1410 self.src_dir = tempfile.mkdtemp()
1411 self.dst_dir = tempfile.mkdtemp()
1412 self.src_file = os.path.join(self.src_dir, filename)
1413 self.dst_file = os.path.join(self.dst_dir, filename)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001414 with open(self.src_file, "wb") as f:
1415 f.write(b"spam")
1416
1417 def tearDown(self):
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001418 for d in (self.src_dir, self.dst_dir):
Christian Heimesada8c3b2008-03-18 18:26:33 +00001419 try:
1420 if d:
1421 shutil.rmtree(d)
1422 except:
1423 pass
1424
1425 def _check_move_file(self, src, dst, real_dst):
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001426 with open(src, "rb") as f:
1427 contents = f.read()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001428 shutil.move(src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001429 with open(real_dst, "rb") as f:
1430 self.assertEqual(contents, f.read())
Christian Heimesada8c3b2008-03-18 18:26:33 +00001431 self.assertFalse(os.path.exists(src))
1432
1433 def _check_move_dir(self, src, dst, real_dst):
1434 contents = sorted(os.listdir(src))
1435 shutil.move(src, dst)
1436 self.assertEqual(contents, sorted(os.listdir(real_dst)))
1437 self.assertFalse(os.path.exists(src))
1438
1439 def test_move_file(self):
1440 # Move a file to another location on the same filesystem.
1441 self._check_move_file(self.src_file, self.dst_file, self.dst_file)
1442
1443 def test_move_file_to_dir(self):
1444 # Move a file inside an existing dir on the same filesystem.
1445 self._check_move_file(self.src_file, self.dst_dir, self.dst_file)
1446
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001447 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001448 def test_move_file_other_fs(self):
1449 # Move a file to an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001450 self.test_move_file()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001451
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001452 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001453 def test_move_file_to_dir_other_fs(self):
1454 # Move a file to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001455 self.test_move_file_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001456
1457 def test_move_dir(self):
1458 # Move a dir to another location on the same filesystem.
1459 dst_dir = tempfile.mktemp()
1460 try:
1461 self._check_move_dir(self.src_dir, dst_dir, dst_dir)
1462 finally:
1463 try:
1464 shutil.rmtree(dst_dir)
1465 except:
1466 pass
1467
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001468 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001469 def test_move_dir_other_fs(self):
1470 # Move a dir to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001471 self.test_move_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001472
1473 def test_move_dir_to_dir(self):
1474 # Move a dir inside an existing dir on the same filesystem.
1475 self._check_move_dir(self.src_dir, self.dst_dir,
1476 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1477
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001478 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001479 def test_move_dir_to_dir_other_fs(self):
1480 # Move a dir inside an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001481 self.test_move_dir_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001482
1483 def test_existing_file_inside_dest_dir(self):
1484 # A file with the same name inside the destination dir already exists.
1485 with open(self.dst_file, "wb"):
1486 pass
1487 self.assertRaises(shutil.Error, shutil.move, self.src_file, self.dst_dir)
1488
1489 def test_dont_move_dir_in_itself(self):
1490 # Moving a dir inside itself raises an Error.
1491 dst = os.path.join(self.src_dir, "bar")
1492 self.assertRaises(shutil.Error, shutil.move, self.src_dir, dst)
1493
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001494 def test_destinsrc_false_negative(self):
1495 os.mkdir(TESTFN)
1496 try:
1497 for src, dst in [('srcdir', 'srcdir/dest')]:
1498 src = os.path.join(TESTFN, src)
1499 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001500 self.assertTrue(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001501 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001502 'dst (%s) is not in src (%s)' % (dst, src))
1503 finally:
1504 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001505
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001506 def test_destinsrc_false_positive(self):
1507 os.mkdir(TESTFN)
1508 try:
1509 for src, dst in [('srcdir', 'src/dest'), ('srcdir', 'srcdir.new')]:
1510 src = os.path.join(TESTFN, src)
1511 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001512 self.assertFalse(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001513 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001514 'dst (%s) is in src (%s)' % (dst, src))
1515 finally:
1516 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimes9bd667a2008-01-20 15:14:11 +00001517
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +01001518 @support.skip_unless_symlink
1519 @mock_rename
1520 def test_move_file_symlink(self):
1521 dst = os.path.join(self.src_dir, 'bar')
1522 os.symlink(self.src_file, dst)
1523 shutil.move(dst, self.dst_file)
1524 self.assertTrue(os.path.islink(self.dst_file))
1525 self.assertTrue(os.path.samefile(self.src_file, self.dst_file))
1526
1527 @support.skip_unless_symlink
1528 @mock_rename
1529 def test_move_file_symlink_to_dir(self):
1530 filename = "bar"
1531 dst = os.path.join(self.src_dir, filename)
1532 os.symlink(self.src_file, dst)
1533 shutil.move(dst, self.dst_dir)
1534 final_link = os.path.join(self.dst_dir, filename)
1535 self.assertTrue(os.path.islink(final_link))
1536 self.assertTrue(os.path.samefile(self.src_file, final_link))
1537
1538 @support.skip_unless_symlink
1539 @mock_rename
1540 def test_move_dangling_symlink(self):
1541 src = os.path.join(self.src_dir, 'baz')
1542 dst = os.path.join(self.src_dir, 'bar')
1543 os.symlink(src, dst)
1544 dst_link = os.path.join(self.dst_dir, 'quux')
1545 shutil.move(dst, dst_link)
1546 self.assertTrue(os.path.islink(dst_link))
1547 self.assertEqual(os.path.realpath(src), os.path.realpath(dst_link))
1548
1549 @support.skip_unless_symlink
1550 @mock_rename
1551 def test_move_dir_symlink(self):
1552 src = os.path.join(self.src_dir, 'baz')
1553 dst = os.path.join(self.src_dir, 'bar')
1554 os.mkdir(src)
1555 os.symlink(src, dst)
1556 dst_link = os.path.join(self.dst_dir, 'quux')
1557 shutil.move(dst, dst_link)
1558 self.assertTrue(os.path.islink(dst_link))
1559 self.assertTrue(os.path.samefile(src, dst_link))
1560
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001561 def test_move_return_value(self):
1562 rv = shutil.move(self.src_file, self.dst_dir)
1563 self.assertEqual(rv,
1564 os.path.join(self.dst_dir, os.path.basename(self.src_file)))
1565
1566 def test_move_as_rename_return_value(self):
1567 rv = shutil.move(self.src_file, os.path.join(self.dst_dir, 'bar'))
1568 self.assertEqual(rv, os.path.join(self.dst_dir, 'bar'))
1569
Tarek Ziadé5340db32010-04-19 22:30:51 +00001570
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001571class TestCopyFile(unittest.TestCase):
1572
1573 _delete = False
1574
1575 class Faux(object):
1576 _entered = False
1577 _exited_with = None
1578 _raised = False
1579 def __init__(self, raise_in_exit=False, suppress_at_exit=True):
1580 self._raise_in_exit = raise_in_exit
1581 self._suppress_at_exit = suppress_at_exit
1582 def read(self, *args):
1583 return ''
1584 def __enter__(self):
1585 self._entered = True
1586 def __exit__(self, exc_type, exc_val, exc_tb):
1587 self._exited_with = exc_type, exc_val, exc_tb
1588 if self._raise_in_exit:
1589 self._raised = True
1590 raise IOError("Cannot close")
1591 return self._suppress_at_exit
1592
1593 def tearDown(self):
1594 if self._delete:
1595 del shutil.open
1596
1597 def _set_shutil_open(self, func):
1598 shutil.open = func
1599 self._delete = True
1600
1601 def test_w_source_open_fails(self):
1602 def _open(filename, mode='r'):
1603 if filename == 'srcfile':
1604 raise IOError('Cannot open "srcfile"')
1605 assert 0 # shouldn't reach here.
1606
1607 self._set_shutil_open(_open)
1608
1609 self.assertRaises(IOError, shutil.copyfile, 'srcfile', 'destfile')
1610
1611 def test_w_dest_open_fails(self):
1612
1613 srcfile = self.Faux()
1614
1615 def _open(filename, mode='r'):
1616 if filename == 'srcfile':
1617 return srcfile
1618 if filename == 'destfile':
1619 raise IOError('Cannot open "destfile"')
1620 assert 0 # shouldn't reach here.
1621
1622 self._set_shutil_open(_open)
1623
1624 shutil.copyfile('srcfile', 'destfile')
1625 self.assertTrue(srcfile._entered)
1626 self.assertTrue(srcfile._exited_with[0] is IOError)
1627 self.assertEqual(srcfile._exited_with[1].args,
1628 ('Cannot open "destfile"',))
1629
1630 def test_w_dest_close_fails(self):
1631
1632 srcfile = self.Faux()
1633 destfile = self.Faux(True)
1634
1635 def _open(filename, mode='r'):
1636 if filename == 'srcfile':
1637 return srcfile
1638 if filename == 'destfile':
1639 return destfile
1640 assert 0 # shouldn't reach here.
1641
1642 self._set_shutil_open(_open)
1643
1644 shutil.copyfile('srcfile', 'destfile')
1645 self.assertTrue(srcfile._entered)
1646 self.assertTrue(destfile._entered)
1647 self.assertTrue(destfile._raised)
1648 self.assertTrue(srcfile._exited_with[0] is IOError)
1649 self.assertEqual(srcfile._exited_with[1].args,
1650 ('Cannot close',))
1651
1652 def test_w_source_close_fails(self):
1653
1654 srcfile = self.Faux(True)
1655 destfile = self.Faux()
1656
1657 def _open(filename, mode='r'):
1658 if filename == 'srcfile':
1659 return srcfile
1660 if filename == 'destfile':
1661 return destfile
1662 assert 0 # shouldn't reach here.
1663
1664 self._set_shutil_open(_open)
1665
1666 self.assertRaises(IOError,
1667 shutil.copyfile, 'srcfile', 'destfile')
1668 self.assertTrue(srcfile._entered)
1669 self.assertTrue(destfile._entered)
1670 self.assertFalse(destfile._raised)
1671 self.assertTrue(srcfile._exited_with[0] is None)
1672 self.assertTrue(srcfile._raised)
1673
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001674 def test_move_dir_caseinsensitive(self):
1675 # Renames a folder to the same name
1676 # but a different case.
1677
1678 self.src_dir = tempfile.mkdtemp()
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001679 self.addCleanup(shutil.rmtree, self.src_dir, True)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001680 dst_dir = os.path.join(
1681 os.path.dirname(self.src_dir),
1682 os.path.basename(self.src_dir).upper())
1683 self.assertNotEqual(self.src_dir, dst_dir)
1684
1685 try:
1686 shutil.move(self.src_dir, dst_dir)
1687 self.assertTrue(os.path.isdir(dst_dir))
1688 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +02001689 os.rmdir(dst_dir)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001690
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001691class TermsizeTests(unittest.TestCase):
1692 def test_does_not_crash(self):
1693 """Check if get_terminal_size() returns a meaningful value.
1694
1695 There's no easy portable way to actually check the size of the
1696 terminal, so let's check if it returns something sensible instead.
1697 """
1698 size = shutil.get_terminal_size()
Antoine Pitroucfade362012-02-08 23:48:59 +01001699 self.assertGreaterEqual(size.columns, 0)
1700 self.assertGreaterEqual(size.lines, 0)
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001701
1702 def test_os_environ_first(self):
1703 "Check if environment variables have precedence"
1704
1705 with support.EnvironmentVarGuard() as env:
1706 env['COLUMNS'] = '777'
1707 size = shutil.get_terminal_size()
1708 self.assertEqual(size.columns, 777)
1709
1710 with support.EnvironmentVarGuard() as env:
1711 env['LINES'] = '888'
1712 size = shutil.get_terminal_size()
1713 self.assertEqual(size.lines, 888)
1714
1715 @unittest.skipUnless(os.isatty(sys.__stdout__.fileno()), "not on tty")
1716 def test_stty_match(self):
1717 """Check if stty returns the same results ignoring env
1718
1719 This test will fail if stdin and stdout are connected to
1720 different terminals with different sizes. Nevertheless, such
1721 situations should be pretty rare.
1722 """
1723 try:
1724 size = subprocess.check_output(['stty', 'size']).decode().split()
1725 except (FileNotFoundError, subprocess.CalledProcessError):
1726 self.skipTest("stty invocation failed")
1727 expected = (int(size[1]), int(size[0])) # reversed order
1728
1729 with support.EnvironmentVarGuard() as env:
1730 del env['LINES']
1731 del env['COLUMNS']
1732 actual = shutil.get_terminal_size()
1733
1734 self.assertEqual(expected, actual)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001735
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001736
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001737def test_main():
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001738 support.run_unittest(TestShutil, TestMove, TestCopyFile,
Brian Curtinc57a3452012-06-22 16:00:30 -05001739 TermsizeTests, TestWhich)
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001740
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001741if __name__ == '__main__':
Walter Dörwald21d3a322003-05-01 17:45:56 +00001742 test_main()