blob: 8a8ce868b72038fd8e13e8f53332fa43882d7aae [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
Serhiy Storchaka79080682013-11-03 21:31:18 +0200197 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod()')
198 @unittest.skipIf(sys.platform[:6] == 'cygwin',
199 "This test can't be run on Cygwin (issue #1071513).")
200 @unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0,
201 "This test can't be run reliably as root (issue #1076467).")
202 def test_on_error(self):
203 self.errorState = 0
204 os.mkdir(TESTFN)
205 self.addCleanup(shutil.rmtree, TESTFN)
Antoine Pitrou2f8a75c2012-06-23 21:28:15 +0200206
Serhiy Storchaka79080682013-11-03 21:31:18 +0200207 self.child_file_path = os.path.join(TESTFN, 'a')
208 self.child_dir_path = os.path.join(TESTFN, 'b')
209 support.create_empty_file(self.child_file_path)
210 os.mkdir(self.child_dir_path)
211 old_dir_mode = os.stat(TESTFN).st_mode
212 old_child_file_mode = os.stat(self.child_file_path).st_mode
213 old_child_dir_mode = os.stat(self.child_dir_path).st_mode
214 # Make unwritable.
215 new_mode = stat.S_IREAD|stat.S_IEXEC
216 os.chmod(self.child_file_path, new_mode)
217 os.chmod(self.child_dir_path, new_mode)
218 os.chmod(TESTFN, new_mode)
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000219
Serhiy Storchaka79080682013-11-03 21:31:18 +0200220 self.addCleanup(os.chmod, TESTFN, old_dir_mode)
221 self.addCleanup(os.chmod, self.child_file_path, old_child_file_mode)
222 self.addCleanup(os.chmod, self.child_dir_path, old_child_dir_mode)
Antoine Pitrou2f8a75c2012-06-23 21:28:15 +0200223
Serhiy Storchaka79080682013-11-03 21:31:18 +0200224 shutil.rmtree(TESTFN, onerror=self.check_args_to_onerror)
225 # Test whether onerror has actually been called.
226 self.assertEqual(self.errorState, 3,
227 "Expected call to onerror function did not 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)
Antoine Pitrou3f48ac92014-01-01 02:50:45 +0100290 # On Windows, os.chmod does not follow symlinks (issue #15411)
291 if os.name != 'nt':
292 # follow src link
293 os.chmod(dst, stat.S_IRWXO)
294 shutil.copymode(src_link, dst)
295 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
296 # follow dst link
297 os.chmod(dst, stat.S_IRWXO)
298 shutil.copymode(src, dst_link)
299 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
300 # follow both links
301 os.chmod(dst, stat.S_IRWXO)
302 shutil.copymode(src_link, dst_link)
303 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100304
305 @unittest.skipUnless(hasattr(os, 'lchmod'), 'requires os.lchmod')
306 @support.skip_unless_symlink
307 def test_copymode_symlink_to_symlink(self):
308 tmp_dir = self.mkdtemp()
309 src = os.path.join(tmp_dir, 'foo')
310 dst = os.path.join(tmp_dir, 'bar')
311 src_link = os.path.join(tmp_dir, 'baz')
312 dst_link = os.path.join(tmp_dir, 'quux')
313 write_file(src, 'foo')
314 write_file(dst, 'foo')
315 os.symlink(src, src_link)
316 os.symlink(dst, dst_link)
317 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
318 os.chmod(dst, stat.S_IRWXU)
319 os.lchmod(src_link, stat.S_IRWXO|stat.S_IRWXG)
320 # link to link
321 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700322 shutil.copymode(src_link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100323 self.assertEqual(os.lstat(src_link).st_mode,
324 os.lstat(dst_link).st_mode)
325 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
326 # src link - use chmod
327 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700328 shutil.copymode(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100329 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
330 # dst link - use chmod
331 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700332 shutil.copymode(src, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100333 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
334
335 @unittest.skipIf(hasattr(os, 'lchmod'), 'requires os.lchmod to be missing')
336 @support.skip_unless_symlink
337 def test_copymode_symlink_to_symlink_wo_lchmod(self):
338 tmp_dir = self.mkdtemp()
339 src = os.path.join(tmp_dir, 'foo')
340 dst = os.path.join(tmp_dir, 'bar')
341 src_link = os.path.join(tmp_dir, 'baz')
342 dst_link = os.path.join(tmp_dir, 'quux')
343 write_file(src, 'foo')
344 write_file(dst, 'foo')
345 os.symlink(src, src_link)
346 os.symlink(dst, dst_link)
Larry Hastingsb4038062012-07-15 10:57:38 -0700347 shutil.copymode(src_link, dst_link, follow_symlinks=False) # silent fail
Antoine Pitrou78091e62011-12-29 18:54:15 +0100348
349 @support.skip_unless_symlink
350 def test_copystat_symlinks(self):
351 tmp_dir = self.mkdtemp()
352 src = os.path.join(tmp_dir, 'foo')
353 dst = os.path.join(tmp_dir, 'bar')
354 src_link = os.path.join(tmp_dir, 'baz')
355 dst_link = os.path.join(tmp_dir, 'qux')
356 write_file(src, 'foo')
357 src_stat = os.stat(src)
358 os.utime(src, (src_stat.st_atime,
359 src_stat.st_mtime - 42.0)) # ensure different mtimes
360 write_file(dst, 'bar')
361 self.assertNotEqual(os.stat(src).st_mtime, os.stat(dst).st_mtime)
362 os.symlink(src, src_link)
363 os.symlink(dst, dst_link)
364 if hasattr(os, 'lchmod'):
365 os.lchmod(src_link, stat.S_IRWXO)
366 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
367 os.lchflags(src_link, stat.UF_NODUMP)
368 src_link_stat = os.lstat(src_link)
369 # follow
370 if hasattr(os, 'lchmod'):
Larry Hastingsb4038062012-07-15 10:57:38 -0700371 shutil.copystat(src_link, dst_link, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100372 self.assertNotEqual(src_link_stat.st_mode, os.stat(dst).st_mode)
373 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700374 shutil.copystat(src_link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100375 dst_link_stat = os.lstat(dst_link)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700376 if os.utime in os.supports_follow_symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100377 for attr in 'st_atime', 'st_mtime':
378 # The modification times may be truncated in the new file.
379 self.assertLessEqual(getattr(src_link_stat, attr),
380 getattr(dst_link_stat, attr) + 1)
381 if hasattr(os, 'lchmod'):
382 self.assertEqual(src_link_stat.st_mode, dst_link_stat.st_mode)
383 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
384 self.assertEqual(src_link_stat.st_flags, dst_link_stat.st_flags)
385 # tell to follow but dst is not a link
Larry Hastingsb4038062012-07-15 10:57:38 -0700386 shutil.copystat(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100387 self.assertTrue(abs(os.stat(src).st_mtime - os.stat(dst).st_mtime) <
388 00000.1)
389
Ned Deilybaf75712012-05-10 17:05:19 -0700390 @unittest.skipUnless(hasattr(os, 'chflags') and
391 hasattr(errno, 'EOPNOTSUPP') and
392 hasattr(errno, 'ENOTSUP'),
393 "requires os.chflags, EOPNOTSUPP & ENOTSUP")
394 def test_copystat_handles_harmless_chflags_errors(self):
395 tmpdir = self.mkdtemp()
396 file1 = os.path.join(tmpdir, 'file1')
397 file2 = os.path.join(tmpdir, 'file2')
398 write_file(file1, 'xxx')
399 write_file(file2, 'xxx')
400
401 def make_chflags_raiser(err):
402 ex = OSError()
403
Larry Hastings90867a52012-06-22 17:01:41 -0700404 def _chflags_raiser(path, flags, *, follow_symlinks=True):
Ned Deilybaf75712012-05-10 17:05:19 -0700405 ex.errno = err
406 raise ex
407 return _chflags_raiser
408 old_chflags = os.chflags
409 try:
410 for err in errno.EOPNOTSUPP, errno.ENOTSUP:
411 os.chflags = make_chflags_raiser(err)
412 shutil.copystat(file1, file2)
413 # assert others errors break it
414 os.chflags = make_chflags_raiser(errno.EOPNOTSUPP + errno.ENOTSUP)
415 self.assertRaises(OSError, shutil.copystat, file1, file2)
416 finally:
417 os.chflags = old_chflags
418
Antoine Pitrou424246f2012-05-12 19:02:01 +0200419 @support.skip_unless_xattr
420 def test_copyxattr(self):
421 tmp_dir = self.mkdtemp()
422 src = os.path.join(tmp_dir, 'foo')
423 write_file(src, 'foo')
424 dst = os.path.join(tmp_dir, 'bar')
425 write_file(dst, 'bar')
426
427 # no xattr == no problem
428 shutil._copyxattr(src, dst)
429 # common case
430 os.setxattr(src, 'user.foo', b'42')
431 os.setxattr(src, 'user.bar', b'43')
432 shutil._copyxattr(src, dst)
433 self.assertEqual(os.listxattr(src), os.listxattr(dst))
434 self.assertEqual(
435 os.getxattr(src, 'user.foo'),
436 os.getxattr(dst, 'user.foo'))
437 # check errors don't affect other attrs
438 os.remove(dst)
439 write_file(dst, 'bar')
440 os_error = OSError(errno.EPERM, 'EPERM')
441
Larry Hastings9cf065c2012-06-22 16:30:09 -0700442 def _raise_on_user_foo(fname, attr, val, **kwargs):
Antoine Pitrou424246f2012-05-12 19:02:01 +0200443 if attr == 'user.foo':
444 raise os_error
445 else:
Larry Hastings9cf065c2012-06-22 16:30:09 -0700446 orig_setxattr(fname, attr, val, **kwargs)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200447 try:
448 orig_setxattr = os.setxattr
449 os.setxattr = _raise_on_user_foo
450 shutil._copyxattr(src, dst)
Antoine Pitrou61597d32012-05-12 23:37:35 +0200451 self.assertIn('user.bar', os.listxattr(dst))
Antoine Pitrou424246f2012-05-12 19:02:01 +0200452 finally:
453 os.setxattr = orig_setxattr
Hynek Schlawack0beab052013-02-05 08:22:44 +0100454 # the source filesystem not supporting xattrs should be ok, too.
455 def _raise_on_src(fname, *, follow_symlinks=True):
456 if fname == src:
457 raise OSError(errno.ENOTSUP, 'Operation not supported')
458 return orig_listxattr(fname, follow_symlinks=follow_symlinks)
459 try:
460 orig_listxattr = os.listxattr
461 os.listxattr = _raise_on_src
462 shutil._copyxattr(src, dst)
463 finally:
464 os.listxattr = orig_listxattr
Antoine Pitrou424246f2012-05-12 19:02:01 +0200465
Larry Hastingsad5ae042012-07-14 17:55:11 -0700466 # test that shutil.copystat copies xattrs
467 src = os.path.join(tmp_dir, 'the_original')
468 write_file(src, src)
469 os.setxattr(src, 'user.the_value', b'fiddly')
470 dst = os.path.join(tmp_dir, 'the_copy')
471 write_file(dst, dst)
472 shutil.copystat(src, dst)
Hynek Schlawackc2d481f2012-07-16 17:11:10 +0200473 self.assertEqual(os.getxattr(dst, 'user.the_value'), b'fiddly')
Larry Hastingsad5ae042012-07-14 17:55:11 -0700474
Antoine Pitrou424246f2012-05-12 19:02:01 +0200475 @support.skip_unless_symlink
476 @support.skip_unless_xattr
477 @unittest.skipUnless(hasattr(os, 'geteuid') and os.geteuid() == 0,
478 'root privileges required')
479 def test_copyxattr_symlinks(self):
480 # On Linux, it's only possible to access non-user xattr for symlinks;
481 # which in turn require root privileges. This test should be expanded
482 # as soon as other platforms gain support for extended attributes.
483 tmp_dir = self.mkdtemp()
484 src = os.path.join(tmp_dir, 'foo')
485 src_link = os.path.join(tmp_dir, 'baz')
486 write_file(src, 'foo')
487 os.symlink(src, src_link)
488 os.setxattr(src, 'trusted.foo', b'42')
Larry Hastings9cf065c2012-06-22 16:30:09 -0700489 os.setxattr(src_link, 'trusted.foo', b'43', follow_symlinks=False)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200490 dst = os.path.join(tmp_dir, 'bar')
491 dst_link = os.path.join(tmp_dir, 'qux')
492 write_file(dst, 'bar')
493 os.symlink(dst, dst_link)
Larry Hastingsb4038062012-07-15 10:57:38 -0700494 shutil._copyxattr(src_link, dst_link, follow_symlinks=False)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700495 self.assertEqual(os.getxattr(dst_link, 'trusted.foo', follow_symlinks=False), b'43')
Antoine Pitrou424246f2012-05-12 19:02:01 +0200496 self.assertRaises(OSError, os.getxattr, dst, 'trusted.foo')
Larry Hastingsb4038062012-07-15 10:57:38 -0700497 shutil._copyxattr(src_link, dst, follow_symlinks=False)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200498 self.assertEqual(os.getxattr(dst, 'trusted.foo'), b'43')
499
Antoine Pitrou78091e62011-12-29 18:54:15 +0100500 @support.skip_unless_symlink
501 def test_copy_symlinks(self):
502 tmp_dir = self.mkdtemp()
503 src = os.path.join(tmp_dir, 'foo')
504 dst = os.path.join(tmp_dir, 'bar')
505 src_link = os.path.join(tmp_dir, 'baz')
506 write_file(src, 'foo')
507 os.symlink(src, src_link)
508 if hasattr(os, 'lchmod'):
509 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
510 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700511 shutil.copy(src_link, dst, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100512 self.assertFalse(os.path.islink(dst))
513 self.assertEqual(read_file(src), read_file(dst))
514 os.remove(dst)
515 # follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700516 shutil.copy(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100517 self.assertTrue(os.path.islink(dst))
518 self.assertEqual(os.readlink(dst), os.readlink(src_link))
519 if hasattr(os, 'lchmod'):
520 self.assertEqual(os.lstat(src_link).st_mode,
521 os.lstat(dst).st_mode)
522
523 @support.skip_unless_symlink
524 def test_copy2_symlinks(self):
525 tmp_dir = self.mkdtemp()
526 src = os.path.join(tmp_dir, 'foo')
527 dst = os.path.join(tmp_dir, 'bar')
528 src_link = os.path.join(tmp_dir, 'baz')
529 write_file(src, 'foo')
530 os.symlink(src, src_link)
531 if hasattr(os, 'lchmod'):
532 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
533 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
534 os.lchflags(src_link, stat.UF_NODUMP)
535 src_stat = os.stat(src)
536 src_link_stat = os.lstat(src_link)
537 # follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700538 shutil.copy2(src_link, dst, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100539 self.assertFalse(os.path.islink(dst))
540 self.assertEqual(read_file(src), read_file(dst))
541 os.remove(dst)
542 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700543 shutil.copy2(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100544 self.assertTrue(os.path.islink(dst))
545 self.assertEqual(os.readlink(dst), os.readlink(src_link))
546 dst_stat = os.lstat(dst)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700547 if os.utime in os.supports_follow_symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100548 for attr in 'st_atime', 'st_mtime':
549 # The modification times may be truncated in the new file.
550 self.assertLessEqual(getattr(src_link_stat, attr),
551 getattr(dst_stat, attr) + 1)
552 if hasattr(os, 'lchmod'):
553 self.assertEqual(src_link_stat.st_mode, dst_stat.st_mode)
554 self.assertNotEqual(src_stat.st_mode, dst_stat.st_mode)
555 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
556 self.assertEqual(src_link_stat.st_flags, dst_stat.st_flags)
557
Antoine Pitrou424246f2012-05-12 19:02:01 +0200558 @support.skip_unless_xattr
559 def test_copy2_xattr(self):
560 tmp_dir = self.mkdtemp()
561 src = os.path.join(tmp_dir, 'foo')
562 dst = os.path.join(tmp_dir, 'bar')
563 write_file(src, 'foo')
564 os.setxattr(src, 'user.foo', b'42')
565 shutil.copy2(src, dst)
566 self.assertEqual(
567 os.getxattr(src, 'user.foo'),
568 os.getxattr(dst, 'user.foo'))
569 os.remove(dst)
570
Antoine Pitrou78091e62011-12-29 18:54:15 +0100571 @support.skip_unless_symlink
572 def test_copyfile_symlinks(self):
573 tmp_dir = self.mkdtemp()
574 src = os.path.join(tmp_dir, 'src')
575 dst = os.path.join(tmp_dir, 'dst')
576 dst_link = os.path.join(tmp_dir, 'dst_link')
577 link = os.path.join(tmp_dir, 'link')
578 write_file(src, 'foo')
579 os.symlink(src, link)
580 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700581 shutil.copyfile(link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100582 self.assertTrue(os.path.islink(dst_link))
583 self.assertEqual(os.readlink(link), os.readlink(dst_link))
584 # follow
585 shutil.copyfile(link, dst)
586 self.assertFalse(os.path.islink(dst))
587
Hynek Schlawack2100b422012-06-23 20:28:32 +0200588 def test_rmtree_uses_safe_fd_version_if_available(self):
Hynek Schlawackd0f6e0a2012-06-29 08:28:20 +0200589 _use_fd_functions = ({os.open, os.stat, os.unlink, os.rmdir} <=
590 os.supports_dir_fd and
591 os.listdir in os.supports_fd and
592 os.stat in os.supports_follow_symlinks)
593 if _use_fd_functions:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200594 self.assertTrue(shutil._use_fd_functions)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000595 self.assertTrue(shutil.rmtree.avoids_symlink_attacks)
Hynek Schlawack2100b422012-06-23 20:28:32 +0200596 tmp_dir = self.mkdtemp()
597 d = os.path.join(tmp_dir, 'a')
598 os.mkdir(d)
599 try:
600 real_rmtree = shutil._rmtree_safe_fd
601 class Called(Exception): pass
602 def _raiser(*args, **kwargs):
603 raise Called
604 shutil._rmtree_safe_fd = _raiser
605 self.assertRaises(Called, shutil.rmtree, d)
606 finally:
607 shutil._rmtree_safe_fd = real_rmtree
608 else:
609 self.assertFalse(shutil._use_fd_functions)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000610 self.assertFalse(shutil.rmtree.avoids_symlink_attacks)
Hynek Schlawack2100b422012-06-23 20:28:32 +0200611
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000612 def test_rmtree_dont_delete_file(self):
613 # When called on a file instead of a directory, don't delete it.
614 handle, path = tempfile.mkstemp()
Victor Stinnerbf816222011-06-30 23:25:47 +0200615 os.close(handle)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200616 self.assertRaises(NotADirectoryError, shutil.rmtree, path)
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000617 os.remove(path)
618
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000619 def test_copytree_simple(self):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000620 src_dir = tempfile.mkdtemp()
621 dst_dir = os.path.join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200622 self.addCleanup(shutil.rmtree, src_dir)
623 self.addCleanup(shutil.rmtree, os.path.dirname(dst_dir))
624 write_file((src_dir, 'test.txt'), '123')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000625 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200626 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000627
Éric Araujoa7e33a12011-08-12 19:51:35 +0200628 shutil.copytree(src_dir, dst_dir)
629 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test.txt')))
630 self.assertTrue(os.path.isdir(os.path.join(dst_dir, 'test_dir')))
631 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test_dir',
632 'test.txt')))
633 actual = read_file((dst_dir, 'test.txt'))
634 self.assertEqual(actual, '123')
635 actual = read_file((dst_dir, 'test_dir', 'test.txt'))
636 self.assertEqual(actual, '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000637
Antoine Pitrou78091e62011-12-29 18:54:15 +0100638 @support.skip_unless_symlink
639 def test_copytree_symlinks(self):
640 tmp_dir = self.mkdtemp()
641 src_dir = os.path.join(tmp_dir, 'src')
642 dst_dir = os.path.join(tmp_dir, 'dst')
643 sub_dir = os.path.join(src_dir, 'sub')
644 os.mkdir(src_dir)
645 os.mkdir(sub_dir)
646 write_file((src_dir, 'file.txt'), 'foo')
647 src_link = os.path.join(sub_dir, 'link')
648 dst_link = os.path.join(dst_dir, 'sub/link')
649 os.symlink(os.path.join(src_dir, 'file.txt'),
650 src_link)
651 if hasattr(os, 'lchmod'):
652 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
653 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
654 os.lchflags(src_link, stat.UF_NODUMP)
655 src_stat = os.lstat(src_link)
656 shutil.copytree(src_dir, dst_dir, symlinks=True)
657 self.assertTrue(os.path.islink(os.path.join(dst_dir, 'sub', 'link')))
658 self.assertEqual(os.readlink(os.path.join(dst_dir, 'sub', 'link')),
659 os.path.join(src_dir, 'file.txt'))
660 dst_stat = os.lstat(dst_link)
661 if hasattr(os, 'lchmod'):
662 self.assertEqual(dst_stat.st_mode, src_stat.st_mode)
663 if hasattr(os, 'lchflags'):
664 self.assertEqual(dst_stat.st_flags, src_stat.st_flags)
665
Georg Brandl2ee470f2008-07-16 12:55:28 +0000666 def test_copytree_with_exclude(self):
Georg Brandl2ee470f2008-07-16 12:55:28 +0000667 # creating data
668 join = os.path.join
669 exists = os.path.exists
670 src_dir = tempfile.mkdtemp()
Georg Brandl2ee470f2008-07-16 12:55:28 +0000671 try:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000672 dst_dir = join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200673 write_file((src_dir, 'test.txt'), '123')
674 write_file((src_dir, 'test.tmp'), '123')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000675 os.mkdir(join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200676 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000677 os.mkdir(join(src_dir, 'test_dir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200678 write_file((src_dir, 'test_dir2', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000679 os.mkdir(join(src_dir, 'test_dir2', 'subdir'))
680 os.mkdir(join(src_dir, 'test_dir2', 'subdir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200681 write_file((src_dir, 'test_dir2', 'subdir', 'test.txt'), '456')
682 write_file((src_dir, 'test_dir2', 'subdir2', 'test.py'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000683
684 # testing glob-like patterns
685 try:
686 patterns = shutil.ignore_patterns('*.tmp', 'test_dir2')
687 shutil.copytree(src_dir, dst_dir, ignore=patterns)
688 # checking the result: some elements should not be copied
689 self.assertTrue(exists(join(dst_dir, 'test.txt')))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200690 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
691 self.assertFalse(exists(join(dst_dir, 'test_dir2')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000692 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200693 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000694 try:
695 patterns = shutil.ignore_patterns('*.tmp', 'subdir*')
696 shutil.copytree(src_dir, dst_dir, ignore=patterns)
697 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200698 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
699 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2')))
700 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000701 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200702 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000703
704 # testing callable-style
705 try:
706 def _filter(src, names):
707 res = []
708 for name in names:
709 path = os.path.join(src, name)
710
711 if (os.path.isdir(path) and
712 path.split()[-1] == 'subdir'):
713 res.append(name)
714 elif os.path.splitext(path)[-1] in ('.py'):
715 res.append(name)
716 return res
717
718 shutil.copytree(src_dir, dst_dir, ignore=_filter)
719
720 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200721 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2',
722 'test.py')))
723 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000724
725 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200726 shutil.rmtree(dst_dir)
Georg Brandl2ee470f2008-07-16 12:55:28 +0000727 finally:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000728 shutil.rmtree(src_dir)
729 shutil.rmtree(os.path.dirname(dst_dir))
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000730
Antoine Pitrouac601602013-08-16 19:35:02 +0200731 def test_copytree_retains_permissions(self):
732 tmp_dir = tempfile.mkdtemp()
733 src_dir = os.path.join(tmp_dir, 'source')
734 os.mkdir(src_dir)
735 dst_dir = os.path.join(tmp_dir, 'destination')
736 self.addCleanup(shutil.rmtree, tmp_dir)
737
738 os.chmod(src_dir, 0o777)
739 write_file((src_dir, 'permissive.txt'), '123')
740 os.chmod(os.path.join(src_dir, 'permissive.txt'), 0o777)
741 write_file((src_dir, 'restrictive.txt'), '456')
742 os.chmod(os.path.join(src_dir, 'restrictive.txt'), 0o600)
743 restrictive_subdir = tempfile.mkdtemp(dir=src_dir)
744 os.chmod(restrictive_subdir, 0o600)
745
746 shutil.copytree(src_dir, dst_dir)
Antoine Pitrou492b9892013-12-21 22:19:46 +0100747 self.assertEqual(os.stat(src_dir).st_mode, os.stat(dst_dir).st_mode)
748 self.assertEqual(os.stat(os.path.join(src_dir, 'permissive.txt')).st_mode,
749 os.stat(os.path.join(dst_dir, 'permissive.txt')).st_mode)
750 self.assertEqual(os.stat(os.path.join(src_dir, 'restrictive.txt')).st_mode,
751 os.stat(os.path.join(dst_dir, 'restrictive.txt')).st_mode)
Antoine Pitrouac601602013-08-16 19:35:02 +0200752 restrictive_subdir_dst = os.path.join(dst_dir,
753 os.path.split(restrictive_subdir)[1])
Antoine Pitrou492b9892013-12-21 22:19:46 +0100754 self.assertEqual(os.stat(restrictive_subdir).st_mode,
755 os.stat(restrictive_subdir_dst).st_mode)
Antoine Pitrouac601602013-08-16 19:35:02 +0200756
Zachary Ware9fe6d862013-12-08 00:20:35 -0600757 @unittest.skipIf(os.name == 'nt', 'temporarily disabled on Windows')
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000758 @unittest.skipUnless(hasattr(os, 'link'), 'requires os.link')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000759 def test_dont_copy_file_onto_link_to_itself(self):
760 # 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
Serhiy Storchaka79080682013-11-03 21:31:18 +0200809 # Issue #3002: copyfile and copytree block indefinitely on named pipes
810 @unittest.skipUnless(hasattr(os, "mkfifo"), 'requires os.mkfifo()')
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
Serhiy Storchaka79080682013-11-03 21:31:18 +0200821 @unittest.skipUnless(hasattr(os, "mkfifo"), 'requires os.mkfifo()')
822 @support.skip_unless_symlink
823 def test_copytree_named_pipe(self):
824 os.mkdir(TESTFN)
825 try:
826 subdir = os.path.join(TESTFN, "subdir")
827 os.mkdir(subdir)
828 pipe = os.path.join(subdir, "mypipe")
829 os.mkfifo(pipe)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000830 try:
Serhiy Storchaka79080682013-11-03 21:31:18 +0200831 shutil.copytree(TESTFN, TESTFN2)
832 except shutil.Error as e:
833 errors = e.args[0]
834 self.assertEqual(len(errors), 1)
835 src, dst, error_msg = errors[0]
836 self.assertEqual("`%s` is a named pipe" % pipe, error_msg)
837 else:
838 self.fail("shutil.Error should have been raised")
839 finally:
840 shutil.rmtree(TESTFN, ignore_errors=True)
841 shutil.rmtree(TESTFN2, ignore_errors=True)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000842
Tarek Ziadé5340db32010-04-19 22:30:51 +0000843 def test_copytree_special_func(self):
844
845 src_dir = self.mkdtemp()
846 dst_dir = os.path.join(self.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200847 write_file((src_dir, 'test.txt'), '123')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000848 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200849 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000850
851 copied = []
852 def _copy(src, dst):
853 copied.append((src, dst))
854
855 shutil.copytree(src_dir, dst_dir, copy_function=_copy)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000856 self.assertEqual(len(copied), 2)
Tarek Ziadé5340db32010-04-19 22:30:51 +0000857
Brian Curtin3b4499c2010-12-28 14:31:47 +0000858 @support.skip_unless_symlink
Tarek Ziadéfb437512010-04-20 08:57:33 +0000859 def test_copytree_dangling_symlinks(self):
860
861 # a dangling symlink raises an error at the end
862 src_dir = self.mkdtemp()
863 dst_dir = os.path.join(self.mkdtemp(), 'destination')
864 os.symlink('IDONTEXIST', os.path.join(src_dir, 'test.txt'))
865 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200866 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadéfb437512010-04-20 08:57:33 +0000867 self.assertRaises(Error, shutil.copytree, src_dir, dst_dir)
868
869 # a dangling symlink is ignored with the proper flag
870 dst_dir = os.path.join(self.mkdtemp(), 'destination2')
871 shutil.copytree(src_dir, dst_dir, ignore_dangling_symlinks=True)
872 self.assertNotIn('test.txt', os.listdir(dst_dir))
873
874 # a dangling symlink is copied if symlinks=True
875 dst_dir = os.path.join(self.mkdtemp(), 'destination3')
876 shutil.copytree(src_dir, dst_dir, symlinks=True)
877 self.assertIn('test.txt', os.listdir(dst_dir))
878
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400879 def _copy_file(self, method):
880 fname = 'test.txt'
881 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200882 write_file((tmpdir, fname), 'xxx')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400883 file1 = os.path.join(tmpdir, fname)
884 tmpdir2 = self.mkdtemp()
885 method(file1, tmpdir2)
886 file2 = os.path.join(tmpdir2, fname)
887 return (file1, file2)
888
889 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
890 def test_copy(self):
891 # Ensure that the copied file exists and has the same mode bits.
892 file1, file2 = self._copy_file(shutil.copy)
893 self.assertTrue(os.path.exists(file2))
894 self.assertEqual(os.stat(file1).st_mode, os.stat(file2).st_mode)
895
896 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
Senthil Kumaran0c2dba52011-07-03 18:21:38 -0700897 @unittest.skipUnless(hasattr(os, 'utime'), 'requires os.utime')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400898 def test_copy2(self):
899 # Ensure that the copied file exists and has the same mode and
900 # modification time bits.
901 file1, file2 = self._copy_file(shutil.copy2)
902 self.assertTrue(os.path.exists(file2))
903 file1_stat = os.stat(file1)
904 file2_stat = os.stat(file2)
905 self.assertEqual(file1_stat.st_mode, file2_stat.st_mode)
906 for attr in 'st_atime', 'st_mtime':
907 # The modification times may be truncated in the new file.
908 self.assertLessEqual(getattr(file1_stat, attr),
909 getattr(file2_stat, attr) + 1)
910 if hasattr(os, 'chflags') and hasattr(file1_stat, 'st_flags'):
911 self.assertEqual(getattr(file1_stat, 'st_flags'),
912 getattr(file2_stat, 'st_flags'))
913
Ezio Melotti975077a2011-05-19 22:03:22 +0300914 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000915 def test_make_tarball(self):
916 # creating something to tar
917 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200918 write_file((tmpdir, 'file1'), 'xxx')
919 write_file((tmpdir, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000920 os.mkdir(os.path.join(tmpdir, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200921 write_file((tmpdir, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000922
923 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400924 # force shutil to create the directory
925 os.rmdir(tmpdir2)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000926 unittest.skipUnless(splitdrive(tmpdir)[0] == splitdrive(tmpdir2)[0],
927 "source and target should be on same drive")
928
929 base_name = os.path.join(tmpdir2, 'archive')
930
931 # working with relative paths to avoid tar warnings
932 old_dir = os.getcwd()
933 os.chdir(tmpdir)
934 try:
935 _make_tarball(splitdrive(base_name)[1], '.')
936 finally:
937 os.chdir(old_dir)
938
939 # check if the compressed tarball was created
940 tarball = base_name + '.tar.gz'
941 self.assertTrue(os.path.exists(tarball))
942
943 # trying an uncompressed one
944 base_name = os.path.join(tmpdir2, 'archive')
945 old_dir = os.getcwd()
946 os.chdir(tmpdir)
947 try:
948 _make_tarball(splitdrive(base_name)[1], '.', compress=None)
949 finally:
950 os.chdir(old_dir)
951 tarball = base_name + '.tar'
952 self.assertTrue(os.path.exists(tarball))
953
954 def _tarinfo(self, path):
955 tar = tarfile.open(path)
956 try:
957 names = tar.getnames()
958 names.sort()
959 return tuple(names)
960 finally:
961 tar.close()
962
963 def _create_files(self):
964 # creating something to tar
965 tmpdir = self.mkdtemp()
966 dist = os.path.join(tmpdir, 'dist')
967 os.mkdir(dist)
Éric Araujoa7e33a12011-08-12 19:51:35 +0200968 write_file((dist, 'file1'), 'xxx')
969 write_file((dist, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000970 os.mkdir(os.path.join(dist, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200971 write_file((dist, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000972 os.mkdir(os.path.join(dist, 'sub2'))
973 tmpdir2 = self.mkdtemp()
974 base_name = os.path.join(tmpdir2, 'archive')
975 return tmpdir, tmpdir2, base_name
976
Ezio Melotti975077a2011-05-19 22:03:22 +0300977 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000978 @unittest.skipUnless(find_executable('tar') and find_executable('gzip'),
979 'Need the tar command to run')
980 def test_tarfile_vs_tar(self):
981 tmpdir, tmpdir2, base_name = self._create_files()
982 old_dir = os.getcwd()
983 os.chdir(tmpdir)
984 try:
985 _make_tarball(base_name, 'dist')
986 finally:
987 os.chdir(old_dir)
988
989 # check if the compressed tarball was created
990 tarball = base_name + '.tar.gz'
991 self.assertTrue(os.path.exists(tarball))
992
993 # now create another tarball using `tar`
994 tarball2 = os.path.join(tmpdir, 'archive2.tar.gz')
995 tar_cmd = ['tar', '-cf', 'archive2.tar', 'dist']
996 gzip_cmd = ['gzip', '-f9', 'archive2.tar']
997 old_dir = os.getcwd()
998 os.chdir(tmpdir)
999 try:
1000 with captured_stdout() as s:
1001 spawn(tar_cmd)
1002 spawn(gzip_cmd)
1003 finally:
1004 os.chdir(old_dir)
1005
1006 self.assertTrue(os.path.exists(tarball2))
1007 # let's compare both tarballs
Ezio Melottib3aedd42010-11-20 19:04:17 +00001008 self.assertEqual(self._tarinfo(tarball), self._tarinfo(tarball2))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001009
1010 # trying an uncompressed one
1011 base_name = os.path.join(tmpdir2, 'archive')
1012 old_dir = os.getcwd()
1013 os.chdir(tmpdir)
1014 try:
1015 _make_tarball(base_name, 'dist', compress=None)
1016 finally:
1017 os.chdir(old_dir)
1018 tarball = base_name + '.tar'
1019 self.assertTrue(os.path.exists(tarball))
1020
1021 # now for a dry_run
1022 base_name = os.path.join(tmpdir2, 'archive')
1023 old_dir = os.getcwd()
1024 os.chdir(tmpdir)
1025 try:
1026 _make_tarball(base_name, 'dist', compress=None, dry_run=True)
1027 finally:
1028 os.chdir(old_dir)
1029 tarball = base_name + '.tar'
1030 self.assertTrue(os.path.exists(tarball))
1031
Ezio Melotti975077a2011-05-19 22:03:22 +03001032 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001033 @unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run')
1034 def test_make_zipfile(self):
1035 # creating something to tar
1036 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +02001037 write_file((tmpdir, 'file1'), 'xxx')
1038 write_file((tmpdir, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +00001039
1040 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001041 # force shutil to create the directory
1042 os.rmdir(tmpdir2)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001043 base_name = os.path.join(tmpdir2, 'archive')
1044 _make_zipfile(base_name, tmpdir)
1045
1046 # check if the compressed tarball was created
1047 tarball = base_name + '.zip'
Éric Araujo1c505492010-11-06 02:12:51 +00001048 self.assertTrue(os.path.exists(tarball))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001049
1050
1051 def test_make_archive(self):
1052 tmpdir = self.mkdtemp()
1053 base_name = os.path.join(tmpdir, 'archive')
1054 self.assertRaises(ValueError, make_archive, base_name, 'xxx')
1055
Ezio Melotti975077a2011-05-19 22:03:22 +03001056 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001057 def test_make_archive_owner_group(self):
1058 # testing make_archive with owner and group, with various combinations
1059 # this works even if there's not gid/uid support
1060 if UID_GID_SUPPORT:
1061 group = grp.getgrgid(0)[0]
1062 owner = pwd.getpwuid(0)[0]
1063 else:
1064 group = owner = 'root'
1065
1066 base_dir, root_dir, base_name = self._create_files()
1067 base_name = os.path.join(self.mkdtemp() , 'archive')
1068 res = make_archive(base_name, 'zip', root_dir, base_dir, owner=owner,
1069 group=group)
1070 self.assertTrue(os.path.exists(res))
1071
1072 res = make_archive(base_name, 'zip', root_dir, base_dir)
1073 self.assertTrue(os.path.exists(res))
1074
1075 res = make_archive(base_name, 'tar', root_dir, base_dir,
1076 owner=owner, group=group)
1077 self.assertTrue(os.path.exists(res))
1078
1079 res = make_archive(base_name, 'tar', root_dir, base_dir,
1080 owner='kjhkjhkjg', group='oihohoh')
1081 self.assertTrue(os.path.exists(res))
1082
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001083
Ezio Melotti975077a2011-05-19 22:03:22 +03001084 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001085 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1086 def test_tarfile_root_owner(self):
1087 tmpdir, tmpdir2, base_name = self._create_files()
1088 old_dir = os.getcwd()
1089 os.chdir(tmpdir)
1090 group = grp.getgrgid(0)[0]
1091 owner = pwd.getpwuid(0)[0]
1092 try:
1093 archive_name = _make_tarball(base_name, 'dist', compress=None,
1094 owner=owner, group=group)
1095 finally:
1096 os.chdir(old_dir)
1097
1098 # check if the compressed tarball was created
1099 self.assertTrue(os.path.exists(archive_name))
1100
1101 # now checks the rights
1102 archive = tarfile.open(archive_name)
1103 try:
1104 for member in archive.getmembers():
Ezio Melottib3aedd42010-11-20 19:04:17 +00001105 self.assertEqual(member.uid, 0)
1106 self.assertEqual(member.gid, 0)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001107 finally:
1108 archive.close()
1109
1110 def test_make_archive_cwd(self):
1111 current_dir = os.getcwd()
1112 def _breaks(*args, **kw):
1113 raise RuntimeError()
1114
1115 register_archive_format('xxx', _breaks, [], 'xxx file')
1116 try:
1117 try:
1118 make_archive('xxx', 'xxx', root_dir=self.mkdtemp())
1119 except Exception:
1120 pass
Ezio Melottib3aedd42010-11-20 19:04:17 +00001121 self.assertEqual(os.getcwd(), current_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001122 finally:
1123 unregister_archive_format('xxx')
1124
1125 def test_register_archive_format(self):
1126
1127 self.assertRaises(TypeError, register_archive_format, 'xxx', 1)
1128 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1129 1)
1130 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1131 [(1, 2), (1, 2, 3)])
1132
1133 register_archive_format('xxx', lambda: x, [(1, 2)], 'xxx file')
1134 formats = [name for name, params in get_archive_formats()]
1135 self.assertIn('xxx', formats)
1136
1137 unregister_archive_format('xxx')
1138 formats = [name for name, params in get_archive_formats()]
1139 self.assertNotIn('xxx', formats)
1140
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001141 def _compare_dirs(self, dir1, dir2):
1142 # check that dir1 and dir2 are equivalent,
1143 # return the diff
1144 diff = []
1145 for root, dirs, files in os.walk(dir1):
1146 for file_ in files:
1147 path = os.path.join(root, file_)
1148 target_path = os.path.join(dir2, os.path.split(path)[-1])
1149 if not os.path.exists(target_path):
1150 diff.append(file_)
1151 return diff
1152
Ezio Melotti975077a2011-05-19 22:03:22 +03001153 @requires_zlib
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001154 def test_unpack_archive(self):
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001155 formats = ['tar', 'gztar', 'zip']
1156 if BZ2_SUPPORTED:
1157 formats.append('bztar')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001158
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001159 for format in formats:
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001160 tmpdir = self.mkdtemp()
1161 base_dir, root_dir, base_name = self._create_files()
1162 tmpdir2 = self.mkdtemp()
1163 filename = make_archive(base_name, format, root_dir, base_dir)
1164
1165 # let's try to unpack it now
1166 unpack_archive(filename, tmpdir2)
1167 diff = self._compare_dirs(tmpdir, tmpdir2)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001168 self.assertEqual(diff, [])
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001169
Nick Coghlanabf202d2011-03-16 13:52:20 -04001170 # and again, this time with the format specified
1171 tmpdir3 = self.mkdtemp()
1172 unpack_archive(filename, tmpdir3, format=format)
1173 diff = self._compare_dirs(tmpdir, tmpdir3)
1174 self.assertEqual(diff, [])
1175 self.assertRaises(shutil.ReadError, unpack_archive, TESTFN)
1176 self.assertRaises(ValueError, unpack_archive, TESTFN, format='xxx')
1177
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001178 def test_unpack_registery(self):
1179
1180 formats = get_unpack_formats()
1181
1182 def _boo(filename, extract_dir, extra):
Ezio Melottib3aedd42010-11-20 19:04:17 +00001183 self.assertEqual(extra, 1)
1184 self.assertEqual(filename, 'stuff.boo')
1185 self.assertEqual(extract_dir, 'xx')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001186
1187 register_unpack_format('Boo', ['.boo', '.b2'], _boo, [('extra', 1)])
1188 unpack_archive('stuff.boo', 'xx')
1189
1190 # trying to register a .boo unpacker again
1191 self.assertRaises(RegistryError, register_unpack_format, 'Boo2',
1192 ['.boo'], _boo)
1193
1194 # should work now
1195 unregister_unpack_format('Boo')
1196 register_unpack_format('Boo2', ['.boo'], _boo)
1197 self.assertIn(('Boo2', ['.boo'], ''), get_unpack_formats())
1198 self.assertNotIn(('Boo', ['.boo'], ''), get_unpack_formats())
1199
1200 # let's leave a clean state
1201 unregister_unpack_format('Boo2')
Ezio Melottib3aedd42010-11-20 19:04:17 +00001202 self.assertEqual(get_unpack_formats(), formats)
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001203
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001204 @unittest.skipUnless(hasattr(shutil, 'disk_usage'),
1205 "disk_usage not available on this platform")
1206 def test_disk_usage(self):
1207 usage = shutil.disk_usage(os.getcwd())
Éric Araujo2ee61882011-07-02 16:45:45 +02001208 self.assertGreater(usage.total, 0)
1209 self.assertGreater(usage.used, 0)
1210 self.assertGreaterEqual(usage.free, 0)
1211 self.assertGreaterEqual(usage.total, usage.used)
1212 self.assertGreater(usage.total, usage.free)
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001213
Sandro Tosid902a142011-08-22 23:28:27 +02001214 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1215 @unittest.skipUnless(hasattr(os, 'chown'), 'requires os.chown')
1216 def test_chown(self):
1217
1218 # cleaned-up automatically by TestShutil.tearDown method
1219 dirname = self.mkdtemp()
1220 filename = tempfile.mktemp(dir=dirname)
1221 write_file(filename, 'testing chown function')
1222
1223 with self.assertRaises(ValueError):
1224 shutil.chown(filename)
1225
1226 with self.assertRaises(LookupError):
1227 shutil.chown(filename, user='non-exising username')
1228
1229 with self.assertRaises(LookupError):
1230 shutil.chown(filename, group='non-exising groupname')
1231
1232 with self.assertRaises(TypeError):
1233 shutil.chown(filename, b'spam')
1234
1235 with self.assertRaises(TypeError):
1236 shutil.chown(filename, 3.14)
1237
1238 uid = os.getuid()
1239 gid = os.getgid()
1240
1241 def check_chown(path, uid=None, gid=None):
1242 s = os.stat(filename)
1243 if uid is not None:
1244 self.assertEqual(uid, s.st_uid)
1245 if gid is not None:
1246 self.assertEqual(gid, s.st_gid)
1247
1248 shutil.chown(filename, uid, gid)
1249 check_chown(filename, uid, gid)
1250 shutil.chown(filename, uid)
1251 check_chown(filename, uid)
1252 shutil.chown(filename, user=uid)
1253 check_chown(filename, uid)
1254 shutil.chown(filename, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001255 check_chown(filename, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001256
1257 shutil.chown(dirname, uid, gid)
1258 check_chown(dirname, uid, gid)
1259 shutil.chown(dirname, uid)
1260 check_chown(dirname, uid)
1261 shutil.chown(dirname, user=uid)
1262 check_chown(dirname, uid)
1263 shutil.chown(dirname, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001264 check_chown(dirname, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001265
1266 user = pwd.getpwuid(uid)[0]
1267 group = grp.getgrgid(gid)[0]
1268 shutil.chown(filename, user, group)
1269 check_chown(filename, uid, gid)
1270 shutil.chown(dirname, user, group)
1271 check_chown(dirname, uid, gid)
1272
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001273 def test_copy_return_value(self):
1274 # copy and copy2 both return their destination path.
1275 for fn in (shutil.copy, shutil.copy2):
1276 src_dir = self.mkdtemp()
1277 dst_dir = self.mkdtemp()
1278 src = os.path.join(src_dir, 'foo')
1279 write_file(src, 'foo')
1280 rv = fn(src, dst_dir)
1281 self.assertEqual(rv, os.path.join(dst_dir, 'foo'))
1282 rv = fn(src, os.path.join(dst_dir, 'bar'))
1283 self.assertEqual(rv, os.path.join(dst_dir, 'bar'))
1284
1285 def test_copyfile_return_value(self):
1286 # copytree returns its destination path.
1287 src_dir = self.mkdtemp()
1288 dst_dir = self.mkdtemp()
1289 dst_file = os.path.join(dst_dir, 'bar')
1290 src_file = os.path.join(src_dir, 'foo')
1291 write_file(src_file, 'foo')
1292 rv = shutil.copyfile(src_file, dst_file)
1293 self.assertTrue(os.path.exists(rv))
1294 self.assertEqual(read_file(src_file), read_file(dst_file))
1295
1296 def test_copytree_return_value(self):
1297 # copytree returns its destination path.
1298 src_dir = self.mkdtemp()
1299 dst_dir = src_dir + "dest"
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001300 self.addCleanup(shutil.rmtree, dst_dir, True)
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001301 src = os.path.join(src_dir, 'foo')
1302 write_file(src, 'foo')
1303 rv = shutil.copytree(src_dir, dst_dir)
1304 self.assertEqual(['foo'], os.listdir(rv))
1305
Christian Heimes9bd667a2008-01-20 15:14:11 +00001306
Brian Curtinc57a3452012-06-22 16:00:30 -05001307class TestWhich(unittest.TestCase):
1308
1309 def setUp(self):
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001310 self.temp_dir = tempfile.mkdtemp(prefix="Tmp")
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001311 self.addCleanup(shutil.rmtree, self.temp_dir, True)
Brian Curtinc57a3452012-06-22 16:00:30 -05001312 # Give the temp_file an ".exe" suffix for all.
1313 # It's needed on Windows and not harmful on other platforms.
1314 self.temp_file = tempfile.NamedTemporaryFile(dir=self.temp_dir,
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001315 prefix="Tmp",
1316 suffix=".Exe")
Brian Curtinc57a3452012-06-22 16:00:30 -05001317 os.chmod(self.temp_file.name, stat.S_IXUSR)
1318 self.addCleanup(self.temp_file.close)
1319 self.dir, self.file = os.path.split(self.temp_file.name)
1320
1321 def test_basic(self):
1322 # Given an EXE in a directory, it should be returned.
1323 rv = shutil.which(self.file, path=self.dir)
1324 self.assertEqual(rv, self.temp_file.name)
1325
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001326 def test_absolute_cmd(self):
Brian Curtinc57a3452012-06-22 16:00:30 -05001327 # When given the fully qualified path to an executable that exists,
1328 # it should be returned.
1329 rv = shutil.which(self.temp_file.name, path=self.temp_dir)
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001330 self.assertEqual(rv, self.temp_file.name)
1331
1332 def test_relative_cmd(self):
1333 # When given the relative path with a directory part to an executable
1334 # that exists, it should be returned.
1335 base_dir, tail_dir = os.path.split(self.dir)
1336 relpath = os.path.join(tail_dir, self.file)
Nick Coghlan55175962013-07-28 22:11:50 +10001337 with support.change_cwd(path=base_dir):
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001338 rv = shutil.which(relpath, path=self.temp_dir)
1339 self.assertEqual(rv, relpath)
1340 # But it shouldn't be searched in PATH directories (issue #16957).
Nick Coghlan55175962013-07-28 22:11:50 +10001341 with support.change_cwd(path=self.dir):
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001342 rv = shutil.which(relpath, path=base_dir)
1343 self.assertIsNone(rv)
1344
1345 def test_cwd(self):
1346 # Issue #16957
1347 base_dir = os.path.dirname(self.dir)
Nick Coghlan55175962013-07-28 22:11:50 +10001348 with support.change_cwd(path=self.dir):
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001349 rv = shutil.which(self.file, path=base_dir)
1350 if sys.platform == "win32":
1351 # Windows: current directory implicitly on PATH
1352 self.assertEqual(rv, os.path.join(os.curdir, self.file))
1353 else:
1354 # Other platforms: shouldn't match in the current directory.
1355 self.assertIsNone(rv)
Brian Curtinc57a3452012-06-22 16:00:30 -05001356
Serhiy Storchaka12516e22013-05-28 15:50:15 +03001357 @unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0,
1358 'non-root user required')
Brian Curtinc57a3452012-06-22 16:00:30 -05001359 def test_non_matching_mode(self):
1360 # Set the file read-only and ask for writeable files.
1361 os.chmod(self.temp_file.name, stat.S_IREAD)
Serhiy Storchaka12516e22013-05-28 15:50:15 +03001362 if os.access(self.temp_file.name, os.W_OK):
1363 self.skipTest("can't set the file read-only")
Brian Curtinc57a3452012-06-22 16:00:30 -05001364 rv = shutil.which(self.file, path=self.dir, mode=os.W_OK)
1365 self.assertIsNone(rv)
1366
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001367 def test_relative_path(self):
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001368 base_dir, tail_dir = os.path.split(self.dir)
Nick Coghlan55175962013-07-28 22:11:50 +10001369 with support.change_cwd(path=base_dir):
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001370 rv = shutil.which(self.file, path=tail_dir)
1371 self.assertEqual(rv, os.path.join(tail_dir, self.file))
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001372
Brian Curtinc57a3452012-06-22 16:00:30 -05001373 def test_nonexistent_file(self):
1374 # Return None when no matching executable file is found on the path.
1375 rv = shutil.which("foo.exe", path=self.dir)
1376 self.assertIsNone(rv)
1377
1378 @unittest.skipUnless(sys.platform == "win32",
1379 "pathext check is Windows-only")
1380 def test_pathext_checking(self):
1381 # Ask for the file without the ".exe" extension, then ensure that
1382 # it gets found properly with the extension.
Serhiy Storchakad70127a2013-01-24 20:03:49 +02001383 rv = shutil.which(self.file[:-4], path=self.dir)
Serhiy Storchaka80c88f42013-01-22 10:31:36 +02001384 self.assertEqual(rv, self.temp_file.name[:-4] + ".EXE")
Brian Curtinc57a3452012-06-22 16:00:30 -05001385
Barry Warsaw618738b2013-04-16 11:05:03 -04001386 def test_environ_path(self):
1387 with support.EnvironmentVarGuard() as env:
1388 env['PATH'] = self.dir
1389 rv = shutil.which(self.file)
1390 self.assertEqual(rv, self.temp_file.name)
1391
1392 def test_empty_path(self):
1393 base_dir = os.path.dirname(self.dir)
Nick Coghlan55175962013-07-28 22:11:50 +10001394 with support.change_cwd(path=self.dir), \
Barry Warsaw618738b2013-04-16 11:05:03 -04001395 support.EnvironmentVarGuard() as env:
1396 env['PATH'] = self.dir
1397 rv = shutil.which(self.file, path='')
1398 self.assertIsNone(rv)
1399
1400 def test_empty_path_no_PATH(self):
1401 with support.EnvironmentVarGuard() as env:
1402 env.pop('PATH', None)
1403 rv = shutil.which(self.file)
1404 self.assertIsNone(rv)
1405
Brian Curtinc57a3452012-06-22 16:00:30 -05001406
Christian Heimesada8c3b2008-03-18 18:26:33 +00001407class TestMove(unittest.TestCase):
1408
1409 def setUp(self):
1410 filename = "foo"
1411 self.src_dir = tempfile.mkdtemp()
1412 self.dst_dir = tempfile.mkdtemp()
1413 self.src_file = os.path.join(self.src_dir, filename)
1414 self.dst_file = os.path.join(self.dst_dir, filename)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001415 with open(self.src_file, "wb") as f:
1416 f.write(b"spam")
1417
1418 def tearDown(self):
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001419 for d in (self.src_dir, self.dst_dir):
Christian Heimesada8c3b2008-03-18 18:26:33 +00001420 try:
1421 if d:
1422 shutil.rmtree(d)
1423 except:
1424 pass
1425
1426 def _check_move_file(self, src, dst, real_dst):
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001427 with open(src, "rb") as f:
1428 contents = f.read()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001429 shutil.move(src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001430 with open(real_dst, "rb") as f:
1431 self.assertEqual(contents, f.read())
Christian Heimesada8c3b2008-03-18 18:26:33 +00001432 self.assertFalse(os.path.exists(src))
1433
1434 def _check_move_dir(self, src, dst, real_dst):
1435 contents = sorted(os.listdir(src))
1436 shutil.move(src, dst)
1437 self.assertEqual(contents, sorted(os.listdir(real_dst)))
1438 self.assertFalse(os.path.exists(src))
1439
1440 def test_move_file(self):
1441 # Move a file to another location on the same filesystem.
1442 self._check_move_file(self.src_file, self.dst_file, self.dst_file)
1443
1444 def test_move_file_to_dir(self):
1445 # Move a file inside an existing dir on the same filesystem.
1446 self._check_move_file(self.src_file, self.dst_dir, self.dst_file)
1447
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001448 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001449 def test_move_file_other_fs(self):
1450 # Move a file to an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001451 self.test_move_file()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001452
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001453 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001454 def test_move_file_to_dir_other_fs(self):
1455 # Move a file to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001456 self.test_move_file_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001457
1458 def test_move_dir(self):
1459 # Move a dir to another location on the same filesystem.
1460 dst_dir = tempfile.mktemp()
1461 try:
1462 self._check_move_dir(self.src_dir, dst_dir, dst_dir)
1463 finally:
1464 try:
1465 shutil.rmtree(dst_dir)
1466 except:
1467 pass
1468
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001469 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001470 def test_move_dir_other_fs(self):
1471 # Move a dir to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001472 self.test_move_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001473
1474 def test_move_dir_to_dir(self):
1475 # Move a dir inside an existing dir on the same filesystem.
1476 self._check_move_dir(self.src_dir, self.dst_dir,
1477 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1478
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001479 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001480 def test_move_dir_to_dir_other_fs(self):
1481 # Move a dir inside an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001482 self.test_move_dir_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001483
1484 def test_existing_file_inside_dest_dir(self):
1485 # A file with the same name inside the destination dir already exists.
1486 with open(self.dst_file, "wb"):
1487 pass
1488 self.assertRaises(shutil.Error, shutil.move, self.src_file, self.dst_dir)
1489
1490 def test_dont_move_dir_in_itself(self):
1491 # Moving a dir inside itself raises an Error.
1492 dst = os.path.join(self.src_dir, "bar")
1493 self.assertRaises(shutil.Error, shutil.move, self.src_dir, dst)
1494
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001495 def test_destinsrc_false_negative(self):
1496 os.mkdir(TESTFN)
1497 try:
1498 for src, dst in [('srcdir', 'srcdir/dest')]:
1499 src = os.path.join(TESTFN, src)
1500 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001501 self.assertTrue(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001502 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001503 'dst (%s) is not in src (%s)' % (dst, src))
1504 finally:
1505 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001506
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001507 def test_destinsrc_false_positive(self):
1508 os.mkdir(TESTFN)
1509 try:
1510 for src, dst in [('srcdir', 'src/dest'), ('srcdir', 'srcdir.new')]:
1511 src = os.path.join(TESTFN, src)
1512 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001513 self.assertFalse(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001514 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001515 'dst (%s) is in src (%s)' % (dst, src))
1516 finally:
1517 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimes9bd667a2008-01-20 15:14:11 +00001518
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +01001519 @support.skip_unless_symlink
1520 @mock_rename
1521 def test_move_file_symlink(self):
1522 dst = os.path.join(self.src_dir, 'bar')
1523 os.symlink(self.src_file, dst)
1524 shutil.move(dst, self.dst_file)
1525 self.assertTrue(os.path.islink(self.dst_file))
1526 self.assertTrue(os.path.samefile(self.src_file, self.dst_file))
1527
1528 @support.skip_unless_symlink
1529 @mock_rename
1530 def test_move_file_symlink_to_dir(self):
1531 filename = "bar"
1532 dst = os.path.join(self.src_dir, filename)
1533 os.symlink(self.src_file, dst)
1534 shutil.move(dst, self.dst_dir)
1535 final_link = os.path.join(self.dst_dir, filename)
1536 self.assertTrue(os.path.islink(final_link))
1537 self.assertTrue(os.path.samefile(self.src_file, final_link))
1538
1539 @support.skip_unless_symlink
1540 @mock_rename
1541 def test_move_dangling_symlink(self):
1542 src = os.path.join(self.src_dir, 'baz')
1543 dst = os.path.join(self.src_dir, 'bar')
1544 os.symlink(src, dst)
1545 dst_link = os.path.join(self.dst_dir, 'quux')
1546 shutil.move(dst, dst_link)
1547 self.assertTrue(os.path.islink(dst_link))
Antoine Pitrou3f48ac92014-01-01 02:50:45 +01001548 # On Windows, os.path.realpath does not follow symlinks (issue #9949)
1549 if os.name == 'nt':
1550 self.assertEqual(os.path.realpath(src), os.readlink(dst_link))
1551 else:
1552 self.assertEqual(os.path.realpath(src), os.path.realpath(dst_link))
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +01001553
1554 @support.skip_unless_symlink
1555 @mock_rename
1556 def test_move_dir_symlink(self):
1557 src = os.path.join(self.src_dir, 'baz')
1558 dst = os.path.join(self.src_dir, 'bar')
1559 os.mkdir(src)
1560 os.symlink(src, dst)
1561 dst_link = os.path.join(self.dst_dir, 'quux')
1562 shutil.move(dst, dst_link)
1563 self.assertTrue(os.path.islink(dst_link))
1564 self.assertTrue(os.path.samefile(src, dst_link))
1565
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001566 def test_move_return_value(self):
1567 rv = shutil.move(self.src_file, self.dst_dir)
1568 self.assertEqual(rv,
1569 os.path.join(self.dst_dir, os.path.basename(self.src_file)))
1570
1571 def test_move_as_rename_return_value(self):
1572 rv = shutil.move(self.src_file, os.path.join(self.dst_dir, 'bar'))
1573 self.assertEqual(rv, os.path.join(self.dst_dir, 'bar'))
1574
Tarek Ziadé5340db32010-04-19 22:30:51 +00001575
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001576class TestCopyFile(unittest.TestCase):
1577
1578 _delete = False
1579
1580 class Faux(object):
1581 _entered = False
1582 _exited_with = None
1583 _raised = False
1584 def __init__(self, raise_in_exit=False, suppress_at_exit=True):
1585 self._raise_in_exit = raise_in_exit
1586 self._suppress_at_exit = suppress_at_exit
1587 def read(self, *args):
1588 return ''
1589 def __enter__(self):
1590 self._entered = True
1591 def __exit__(self, exc_type, exc_val, exc_tb):
1592 self._exited_with = exc_type, exc_val, exc_tb
1593 if self._raise_in_exit:
1594 self._raised = True
1595 raise IOError("Cannot close")
1596 return self._suppress_at_exit
1597
1598 def tearDown(self):
1599 if self._delete:
1600 del shutil.open
1601
1602 def _set_shutil_open(self, func):
1603 shutil.open = func
1604 self._delete = True
1605
1606 def test_w_source_open_fails(self):
1607 def _open(filename, mode='r'):
1608 if filename == 'srcfile':
1609 raise IOError('Cannot open "srcfile"')
1610 assert 0 # shouldn't reach here.
1611
1612 self._set_shutil_open(_open)
1613
1614 self.assertRaises(IOError, shutil.copyfile, 'srcfile', 'destfile')
1615
1616 def test_w_dest_open_fails(self):
1617
1618 srcfile = self.Faux()
1619
1620 def _open(filename, mode='r'):
1621 if filename == 'srcfile':
1622 return srcfile
1623 if filename == 'destfile':
1624 raise IOError('Cannot open "destfile"')
1625 assert 0 # shouldn't reach here.
1626
1627 self._set_shutil_open(_open)
1628
1629 shutil.copyfile('srcfile', 'destfile')
1630 self.assertTrue(srcfile._entered)
1631 self.assertTrue(srcfile._exited_with[0] is IOError)
1632 self.assertEqual(srcfile._exited_with[1].args,
1633 ('Cannot open "destfile"',))
1634
1635 def test_w_dest_close_fails(self):
1636
1637 srcfile = self.Faux()
1638 destfile = self.Faux(True)
1639
1640 def _open(filename, mode='r'):
1641 if filename == 'srcfile':
1642 return srcfile
1643 if filename == 'destfile':
1644 return destfile
1645 assert 0 # shouldn't reach here.
1646
1647 self._set_shutil_open(_open)
1648
1649 shutil.copyfile('srcfile', 'destfile')
1650 self.assertTrue(srcfile._entered)
1651 self.assertTrue(destfile._entered)
1652 self.assertTrue(destfile._raised)
1653 self.assertTrue(srcfile._exited_with[0] is IOError)
1654 self.assertEqual(srcfile._exited_with[1].args,
1655 ('Cannot close',))
1656
1657 def test_w_source_close_fails(self):
1658
1659 srcfile = self.Faux(True)
1660 destfile = self.Faux()
1661
1662 def _open(filename, mode='r'):
1663 if filename == 'srcfile':
1664 return srcfile
1665 if filename == 'destfile':
1666 return destfile
1667 assert 0 # shouldn't reach here.
1668
1669 self._set_shutil_open(_open)
1670
1671 self.assertRaises(IOError,
1672 shutil.copyfile, 'srcfile', 'destfile')
1673 self.assertTrue(srcfile._entered)
1674 self.assertTrue(destfile._entered)
1675 self.assertFalse(destfile._raised)
1676 self.assertTrue(srcfile._exited_with[0] is None)
1677 self.assertTrue(srcfile._raised)
1678
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001679 def test_move_dir_caseinsensitive(self):
1680 # Renames a folder to the same name
1681 # but a different case.
1682
1683 self.src_dir = tempfile.mkdtemp()
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001684 self.addCleanup(shutil.rmtree, self.src_dir, True)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001685 dst_dir = os.path.join(
1686 os.path.dirname(self.src_dir),
1687 os.path.basename(self.src_dir).upper())
1688 self.assertNotEqual(self.src_dir, dst_dir)
1689
1690 try:
1691 shutil.move(self.src_dir, dst_dir)
1692 self.assertTrue(os.path.isdir(dst_dir))
1693 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +02001694 os.rmdir(dst_dir)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001695
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001696class TermsizeTests(unittest.TestCase):
1697 def test_does_not_crash(self):
1698 """Check if get_terminal_size() returns a meaningful value.
1699
1700 There's no easy portable way to actually check the size of the
1701 terminal, so let's check if it returns something sensible instead.
1702 """
1703 size = shutil.get_terminal_size()
Antoine Pitroucfade362012-02-08 23:48:59 +01001704 self.assertGreaterEqual(size.columns, 0)
1705 self.assertGreaterEqual(size.lines, 0)
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001706
1707 def test_os_environ_first(self):
1708 "Check if environment variables have precedence"
1709
1710 with support.EnvironmentVarGuard() as env:
1711 env['COLUMNS'] = '777'
1712 size = shutil.get_terminal_size()
1713 self.assertEqual(size.columns, 777)
1714
1715 with support.EnvironmentVarGuard() as env:
1716 env['LINES'] = '888'
1717 size = shutil.get_terminal_size()
1718 self.assertEqual(size.lines, 888)
1719
1720 @unittest.skipUnless(os.isatty(sys.__stdout__.fileno()), "not on tty")
1721 def test_stty_match(self):
1722 """Check if stty returns the same results ignoring env
1723
1724 This test will fail if stdin and stdout are connected to
1725 different terminals with different sizes. Nevertheless, such
1726 situations should be pretty rare.
1727 """
1728 try:
1729 size = subprocess.check_output(['stty', 'size']).decode().split()
1730 except (FileNotFoundError, subprocess.CalledProcessError):
1731 self.skipTest("stty invocation failed")
1732 expected = (int(size[1]), int(size[0])) # reversed order
1733
1734 with support.EnvironmentVarGuard() as env:
1735 del env['LINES']
1736 del env['COLUMNS']
1737 actual = shutil.get_terminal_size()
1738
1739 self.assertEqual(expected, actual)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001740
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001741
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001742def test_main():
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001743 support.run_unittest(TestShutil, TestMove, TestCopyFile,
Brian Curtinc57a3452012-06-22 16:00:30 -05001744 TermsizeTests, TestWhich)
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001745
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001746if __name__ == '__main__':
Walter Dörwald21d3a322003-05-01 17:45:56 +00001747 test_main()