blob: 411c19a87a7f5e64611284320a4996417c4dd959 [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)
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
Zachary Ware9fe6d862013-12-08 00:20:35 -0600755 @unittest.skipIf(os.name == 'nt', 'temporarily disabled on Windows')
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000756 @unittest.skipUnless(hasattr(os, 'link'), 'requires os.link')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000757 def test_dont_copy_file_onto_link_to_itself(self):
758 # bug 851123.
759 os.mkdir(TESTFN)
760 src = os.path.join(TESTFN, 'cheese')
761 dst = os.path.join(TESTFN, 'shop')
762 try:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000763 with open(src, 'w') as f:
764 f.write('cheddar')
765 os.link(src, dst)
Hynek Schlawack26fe37d2012-07-19 21:41:02 +0200766 self.assertRaises(shutil.Error, shutil.copyfile, src, dst)
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000767 with open(src, 'r') as f:
768 self.assertEqual(f.read(), 'cheddar')
769 os.remove(dst)
770 finally:
771 shutil.rmtree(TESTFN, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000772
Brian Curtin3b4499c2010-12-28 14:31:47 +0000773 @support.skip_unless_symlink
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000774 def test_dont_copy_file_onto_symlink_to_itself(self):
775 # bug 851123.
776 os.mkdir(TESTFN)
777 src = os.path.join(TESTFN, 'cheese')
778 dst = os.path.join(TESTFN, 'shop')
779 try:
780 with open(src, 'w') as f:
781 f.write('cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000782 # Using `src` here would mean we end up with a symlink pointing
783 # to TESTFN/TESTFN/cheese, while it should point at
784 # TESTFN/cheese.
785 os.symlink('cheese', dst)
Hynek Schlawack26fe37d2012-07-19 21:41:02 +0200786 self.assertRaises(shutil.Error, shutil.copyfile, src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +0000787 with open(src, 'r') as f:
788 self.assertEqual(f.read(), 'cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000789 os.remove(dst)
790 finally:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000791 shutil.rmtree(TESTFN, ignore_errors=True)
Johannes Gijsbers68128712004-08-14 13:57:08 +0000792
Brian Curtin3b4499c2010-12-28 14:31:47 +0000793 @support.skip_unless_symlink
Brian Curtind40e6f72010-07-08 21:39:08 +0000794 def test_rmtree_on_symlink(self):
795 # bug 1669.
796 os.mkdir(TESTFN)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000797 try:
Brian Curtind40e6f72010-07-08 21:39:08 +0000798 src = os.path.join(TESTFN, 'cheese')
799 dst = os.path.join(TESTFN, 'shop')
800 os.mkdir(src)
801 os.symlink(src, dst)
802 self.assertRaises(OSError, shutil.rmtree, dst)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200803 shutil.rmtree(dst, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000804 finally:
Brian Curtind40e6f72010-07-08 21:39:08 +0000805 shutil.rmtree(TESTFN, ignore_errors=True)
806
Serhiy Storchaka79080682013-11-03 21:31:18 +0200807 # Issue #3002: copyfile and copytree block indefinitely on named pipes
808 @unittest.skipUnless(hasattr(os, "mkfifo"), 'requires os.mkfifo()')
809 def test_copyfile_named_pipe(self):
810 os.mkfifo(TESTFN)
811 try:
812 self.assertRaises(shutil.SpecialFileError,
813 shutil.copyfile, TESTFN, TESTFN2)
814 self.assertRaises(shutil.SpecialFileError,
815 shutil.copyfile, __file__, TESTFN)
816 finally:
817 os.remove(TESTFN)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000818
Serhiy Storchaka79080682013-11-03 21:31:18 +0200819 @unittest.skipUnless(hasattr(os, "mkfifo"), 'requires os.mkfifo()')
820 @support.skip_unless_symlink
821 def test_copytree_named_pipe(self):
822 os.mkdir(TESTFN)
823 try:
824 subdir = os.path.join(TESTFN, "subdir")
825 os.mkdir(subdir)
826 pipe = os.path.join(subdir, "mypipe")
827 os.mkfifo(pipe)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000828 try:
Serhiy Storchaka79080682013-11-03 21:31:18 +0200829 shutil.copytree(TESTFN, TESTFN2)
830 except shutil.Error as e:
831 errors = e.args[0]
832 self.assertEqual(len(errors), 1)
833 src, dst, error_msg = errors[0]
834 self.assertEqual("`%s` is a named pipe" % pipe, error_msg)
835 else:
836 self.fail("shutil.Error should have been raised")
837 finally:
838 shutil.rmtree(TESTFN, ignore_errors=True)
839 shutil.rmtree(TESTFN2, ignore_errors=True)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000840
Tarek Ziadé5340db32010-04-19 22:30:51 +0000841 def test_copytree_special_func(self):
842
843 src_dir = self.mkdtemp()
844 dst_dir = os.path.join(self.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200845 write_file((src_dir, 'test.txt'), '123')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000846 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200847 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000848
849 copied = []
850 def _copy(src, dst):
851 copied.append((src, dst))
852
853 shutil.copytree(src_dir, dst_dir, copy_function=_copy)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000854 self.assertEqual(len(copied), 2)
Tarek Ziadé5340db32010-04-19 22:30:51 +0000855
Brian Curtin3b4499c2010-12-28 14:31:47 +0000856 @support.skip_unless_symlink
Tarek Ziadéfb437512010-04-20 08:57:33 +0000857 def test_copytree_dangling_symlinks(self):
858
859 # a dangling symlink raises an error at the end
860 src_dir = self.mkdtemp()
861 dst_dir = os.path.join(self.mkdtemp(), 'destination')
862 os.symlink('IDONTEXIST', os.path.join(src_dir, 'test.txt'))
863 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200864 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadéfb437512010-04-20 08:57:33 +0000865 self.assertRaises(Error, shutil.copytree, src_dir, dst_dir)
866
867 # a dangling symlink is ignored with the proper flag
868 dst_dir = os.path.join(self.mkdtemp(), 'destination2')
869 shutil.copytree(src_dir, dst_dir, ignore_dangling_symlinks=True)
870 self.assertNotIn('test.txt', os.listdir(dst_dir))
871
872 # a dangling symlink is copied if symlinks=True
873 dst_dir = os.path.join(self.mkdtemp(), 'destination3')
874 shutil.copytree(src_dir, dst_dir, symlinks=True)
875 self.assertIn('test.txt', os.listdir(dst_dir))
876
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400877 def _copy_file(self, method):
878 fname = 'test.txt'
879 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200880 write_file((tmpdir, fname), 'xxx')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400881 file1 = os.path.join(tmpdir, fname)
882 tmpdir2 = self.mkdtemp()
883 method(file1, tmpdir2)
884 file2 = os.path.join(tmpdir2, fname)
885 return (file1, file2)
886
887 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
888 def test_copy(self):
889 # Ensure that the copied file exists and has the same mode bits.
890 file1, file2 = self._copy_file(shutil.copy)
891 self.assertTrue(os.path.exists(file2))
892 self.assertEqual(os.stat(file1).st_mode, os.stat(file2).st_mode)
893
894 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
Senthil Kumaran0c2dba52011-07-03 18:21:38 -0700895 @unittest.skipUnless(hasattr(os, 'utime'), 'requires os.utime')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400896 def test_copy2(self):
897 # Ensure that the copied file exists and has the same mode and
898 # modification time bits.
899 file1, file2 = self._copy_file(shutil.copy2)
900 self.assertTrue(os.path.exists(file2))
901 file1_stat = os.stat(file1)
902 file2_stat = os.stat(file2)
903 self.assertEqual(file1_stat.st_mode, file2_stat.st_mode)
904 for attr in 'st_atime', 'st_mtime':
905 # The modification times may be truncated in the new file.
906 self.assertLessEqual(getattr(file1_stat, attr),
907 getattr(file2_stat, attr) + 1)
908 if hasattr(os, 'chflags') and hasattr(file1_stat, 'st_flags'):
909 self.assertEqual(getattr(file1_stat, 'st_flags'),
910 getattr(file2_stat, 'st_flags'))
911
Ezio Melotti975077a2011-05-19 22:03:22 +0300912 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000913 def test_make_tarball(self):
914 # creating something to tar
915 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200916 write_file((tmpdir, 'file1'), 'xxx')
917 write_file((tmpdir, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000918 os.mkdir(os.path.join(tmpdir, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200919 write_file((tmpdir, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000920
921 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400922 # force shutil to create the directory
923 os.rmdir(tmpdir2)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000924 unittest.skipUnless(splitdrive(tmpdir)[0] == splitdrive(tmpdir2)[0],
925 "source and target should be on same drive")
926
927 base_name = os.path.join(tmpdir2, 'archive')
928
929 # working with relative paths to avoid tar warnings
930 old_dir = os.getcwd()
931 os.chdir(tmpdir)
932 try:
933 _make_tarball(splitdrive(base_name)[1], '.')
934 finally:
935 os.chdir(old_dir)
936
937 # check if the compressed tarball was created
938 tarball = base_name + '.tar.gz'
939 self.assertTrue(os.path.exists(tarball))
940
941 # trying an uncompressed one
942 base_name = os.path.join(tmpdir2, 'archive')
943 old_dir = os.getcwd()
944 os.chdir(tmpdir)
945 try:
946 _make_tarball(splitdrive(base_name)[1], '.', compress=None)
947 finally:
948 os.chdir(old_dir)
949 tarball = base_name + '.tar'
950 self.assertTrue(os.path.exists(tarball))
951
952 def _tarinfo(self, path):
953 tar = tarfile.open(path)
954 try:
955 names = tar.getnames()
956 names.sort()
957 return tuple(names)
958 finally:
959 tar.close()
960
961 def _create_files(self):
962 # creating something to tar
963 tmpdir = self.mkdtemp()
964 dist = os.path.join(tmpdir, 'dist')
965 os.mkdir(dist)
Éric Araujoa7e33a12011-08-12 19:51:35 +0200966 write_file((dist, 'file1'), 'xxx')
967 write_file((dist, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000968 os.mkdir(os.path.join(dist, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200969 write_file((dist, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000970 os.mkdir(os.path.join(dist, 'sub2'))
971 tmpdir2 = self.mkdtemp()
972 base_name = os.path.join(tmpdir2, 'archive')
973 return tmpdir, tmpdir2, base_name
974
Ezio Melotti975077a2011-05-19 22:03:22 +0300975 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000976 @unittest.skipUnless(find_executable('tar') and find_executable('gzip'),
977 'Need the tar command to run')
978 def test_tarfile_vs_tar(self):
979 tmpdir, tmpdir2, base_name = self._create_files()
980 old_dir = os.getcwd()
981 os.chdir(tmpdir)
982 try:
983 _make_tarball(base_name, 'dist')
984 finally:
985 os.chdir(old_dir)
986
987 # check if the compressed tarball was created
988 tarball = base_name + '.tar.gz'
989 self.assertTrue(os.path.exists(tarball))
990
991 # now create another tarball using `tar`
992 tarball2 = os.path.join(tmpdir, 'archive2.tar.gz')
993 tar_cmd = ['tar', '-cf', 'archive2.tar', 'dist']
994 gzip_cmd = ['gzip', '-f9', 'archive2.tar']
995 old_dir = os.getcwd()
996 os.chdir(tmpdir)
997 try:
998 with captured_stdout() as s:
999 spawn(tar_cmd)
1000 spawn(gzip_cmd)
1001 finally:
1002 os.chdir(old_dir)
1003
1004 self.assertTrue(os.path.exists(tarball2))
1005 # let's compare both tarballs
Ezio Melottib3aedd42010-11-20 19:04:17 +00001006 self.assertEqual(self._tarinfo(tarball), self._tarinfo(tarball2))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001007
1008 # trying an uncompressed one
1009 base_name = os.path.join(tmpdir2, 'archive')
1010 old_dir = os.getcwd()
1011 os.chdir(tmpdir)
1012 try:
1013 _make_tarball(base_name, 'dist', compress=None)
1014 finally:
1015 os.chdir(old_dir)
1016 tarball = base_name + '.tar'
1017 self.assertTrue(os.path.exists(tarball))
1018
1019 # now for a dry_run
1020 base_name = os.path.join(tmpdir2, 'archive')
1021 old_dir = os.getcwd()
1022 os.chdir(tmpdir)
1023 try:
1024 _make_tarball(base_name, 'dist', compress=None, dry_run=True)
1025 finally:
1026 os.chdir(old_dir)
1027 tarball = base_name + '.tar'
1028 self.assertTrue(os.path.exists(tarball))
1029
Ezio Melotti975077a2011-05-19 22:03:22 +03001030 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001031 @unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run')
1032 def test_make_zipfile(self):
1033 # creating something to tar
1034 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +02001035 write_file((tmpdir, 'file1'), 'xxx')
1036 write_file((tmpdir, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +00001037
1038 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001039 # force shutil to create the directory
1040 os.rmdir(tmpdir2)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001041 base_name = os.path.join(tmpdir2, 'archive')
1042 _make_zipfile(base_name, tmpdir)
1043
1044 # check if the compressed tarball was created
1045 tarball = base_name + '.zip'
Éric Araujo1c505492010-11-06 02:12:51 +00001046 self.assertTrue(os.path.exists(tarball))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001047
1048
1049 def test_make_archive(self):
1050 tmpdir = self.mkdtemp()
1051 base_name = os.path.join(tmpdir, 'archive')
1052 self.assertRaises(ValueError, make_archive, base_name, 'xxx')
1053
Ezio Melotti975077a2011-05-19 22:03:22 +03001054 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001055 def test_make_archive_owner_group(self):
1056 # testing make_archive with owner and group, with various combinations
1057 # this works even if there's not gid/uid support
1058 if UID_GID_SUPPORT:
1059 group = grp.getgrgid(0)[0]
1060 owner = pwd.getpwuid(0)[0]
1061 else:
1062 group = owner = 'root'
1063
1064 base_dir, root_dir, base_name = self._create_files()
1065 base_name = os.path.join(self.mkdtemp() , 'archive')
1066 res = make_archive(base_name, 'zip', root_dir, base_dir, owner=owner,
1067 group=group)
1068 self.assertTrue(os.path.exists(res))
1069
1070 res = make_archive(base_name, 'zip', root_dir, base_dir)
1071 self.assertTrue(os.path.exists(res))
1072
1073 res = make_archive(base_name, 'tar', root_dir, base_dir,
1074 owner=owner, group=group)
1075 self.assertTrue(os.path.exists(res))
1076
1077 res = make_archive(base_name, 'tar', root_dir, base_dir,
1078 owner='kjhkjhkjg', group='oihohoh')
1079 self.assertTrue(os.path.exists(res))
1080
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001081
Ezio Melotti975077a2011-05-19 22:03:22 +03001082 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001083 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1084 def test_tarfile_root_owner(self):
1085 tmpdir, tmpdir2, base_name = self._create_files()
1086 old_dir = os.getcwd()
1087 os.chdir(tmpdir)
1088 group = grp.getgrgid(0)[0]
1089 owner = pwd.getpwuid(0)[0]
1090 try:
1091 archive_name = _make_tarball(base_name, 'dist', compress=None,
1092 owner=owner, group=group)
1093 finally:
1094 os.chdir(old_dir)
1095
1096 # check if the compressed tarball was created
1097 self.assertTrue(os.path.exists(archive_name))
1098
1099 # now checks the rights
1100 archive = tarfile.open(archive_name)
1101 try:
1102 for member in archive.getmembers():
Ezio Melottib3aedd42010-11-20 19:04:17 +00001103 self.assertEqual(member.uid, 0)
1104 self.assertEqual(member.gid, 0)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001105 finally:
1106 archive.close()
1107
1108 def test_make_archive_cwd(self):
1109 current_dir = os.getcwd()
1110 def _breaks(*args, **kw):
1111 raise RuntimeError()
1112
1113 register_archive_format('xxx', _breaks, [], 'xxx file')
1114 try:
1115 try:
1116 make_archive('xxx', 'xxx', root_dir=self.mkdtemp())
1117 except Exception:
1118 pass
Ezio Melottib3aedd42010-11-20 19:04:17 +00001119 self.assertEqual(os.getcwd(), current_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001120 finally:
1121 unregister_archive_format('xxx')
1122
1123 def test_register_archive_format(self):
1124
1125 self.assertRaises(TypeError, register_archive_format, 'xxx', 1)
1126 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1127 1)
1128 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1129 [(1, 2), (1, 2, 3)])
1130
1131 register_archive_format('xxx', lambda: x, [(1, 2)], 'xxx file')
1132 formats = [name for name, params in get_archive_formats()]
1133 self.assertIn('xxx', formats)
1134
1135 unregister_archive_format('xxx')
1136 formats = [name for name, params in get_archive_formats()]
1137 self.assertNotIn('xxx', formats)
1138
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001139 def _compare_dirs(self, dir1, dir2):
1140 # check that dir1 and dir2 are equivalent,
1141 # return the diff
1142 diff = []
1143 for root, dirs, files in os.walk(dir1):
1144 for file_ in files:
1145 path = os.path.join(root, file_)
1146 target_path = os.path.join(dir2, os.path.split(path)[-1])
1147 if not os.path.exists(target_path):
1148 diff.append(file_)
1149 return diff
1150
Ezio Melotti975077a2011-05-19 22:03:22 +03001151 @requires_zlib
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001152 def test_unpack_archive(self):
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001153 formats = ['tar', 'gztar', 'zip']
1154 if BZ2_SUPPORTED:
1155 formats.append('bztar')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001156
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001157 for format in formats:
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001158 tmpdir = self.mkdtemp()
1159 base_dir, root_dir, base_name = self._create_files()
1160 tmpdir2 = self.mkdtemp()
1161 filename = make_archive(base_name, format, root_dir, base_dir)
1162
1163 # let's try to unpack it now
1164 unpack_archive(filename, tmpdir2)
1165 diff = self._compare_dirs(tmpdir, tmpdir2)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001166 self.assertEqual(diff, [])
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001167
Nick Coghlanabf202d2011-03-16 13:52:20 -04001168 # and again, this time with the format specified
1169 tmpdir3 = self.mkdtemp()
1170 unpack_archive(filename, tmpdir3, format=format)
1171 diff = self._compare_dirs(tmpdir, tmpdir3)
1172 self.assertEqual(diff, [])
1173 self.assertRaises(shutil.ReadError, unpack_archive, TESTFN)
1174 self.assertRaises(ValueError, unpack_archive, TESTFN, format='xxx')
1175
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001176 def test_unpack_registery(self):
1177
1178 formats = get_unpack_formats()
1179
1180 def _boo(filename, extract_dir, extra):
Ezio Melottib3aedd42010-11-20 19:04:17 +00001181 self.assertEqual(extra, 1)
1182 self.assertEqual(filename, 'stuff.boo')
1183 self.assertEqual(extract_dir, 'xx')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001184
1185 register_unpack_format('Boo', ['.boo', '.b2'], _boo, [('extra', 1)])
1186 unpack_archive('stuff.boo', 'xx')
1187
1188 # trying to register a .boo unpacker again
1189 self.assertRaises(RegistryError, register_unpack_format, 'Boo2',
1190 ['.boo'], _boo)
1191
1192 # should work now
1193 unregister_unpack_format('Boo')
1194 register_unpack_format('Boo2', ['.boo'], _boo)
1195 self.assertIn(('Boo2', ['.boo'], ''), get_unpack_formats())
1196 self.assertNotIn(('Boo', ['.boo'], ''), get_unpack_formats())
1197
1198 # let's leave a clean state
1199 unregister_unpack_format('Boo2')
Ezio Melottib3aedd42010-11-20 19:04:17 +00001200 self.assertEqual(get_unpack_formats(), formats)
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001201
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001202 @unittest.skipUnless(hasattr(shutil, 'disk_usage'),
1203 "disk_usage not available on this platform")
1204 def test_disk_usage(self):
1205 usage = shutil.disk_usage(os.getcwd())
Éric Araujo2ee61882011-07-02 16:45:45 +02001206 self.assertGreater(usage.total, 0)
1207 self.assertGreater(usage.used, 0)
1208 self.assertGreaterEqual(usage.free, 0)
1209 self.assertGreaterEqual(usage.total, usage.used)
1210 self.assertGreater(usage.total, usage.free)
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001211
Sandro Tosid902a142011-08-22 23:28:27 +02001212 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1213 @unittest.skipUnless(hasattr(os, 'chown'), 'requires os.chown')
1214 def test_chown(self):
1215
1216 # cleaned-up automatically by TestShutil.tearDown method
1217 dirname = self.mkdtemp()
1218 filename = tempfile.mktemp(dir=dirname)
1219 write_file(filename, 'testing chown function')
1220
1221 with self.assertRaises(ValueError):
1222 shutil.chown(filename)
1223
1224 with self.assertRaises(LookupError):
1225 shutil.chown(filename, user='non-exising username')
1226
1227 with self.assertRaises(LookupError):
1228 shutil.chown(filename, group='non-exising groupname')
1229
1230 with self.assertRaises(TypeError):
1231 shutil.chown(filename, b'spam')
1232
1233 with self.assertRaises(TypeError):
1234 shutil.chown(filename, 3.14)
1235
1236 uid = os.getuid()
1237 gid = os.getgid()
1238
1239 def check_chown(path, uid=None, gid=None):
1240 s = os.stat(filename)
1241 if uid is not None:
1242 self.assertEqual(uid, s.st_uid)
1243 if gid is not None:
1244 self.assertEqual(gid, s.st_gid)
1245
1246 shutil.chown(filename, uid, gid)
1247 check_chown(filename, uid, gid)
1248 shutil.chown(filename, uid)
1249 check_chown(filename, uid)
1250 shutil.chown(filename, user=uid)
1251 check_chown(filename, uid)
1252 shutil.chown(filename, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001253 check_chown(filename, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001254
1255 shutil.chown(dirname, uid, gid)
1256 check_chown(dirname, uid, gid)
1257 shutil.chown(dirname, uid)
1258 check_chown(dirname, uid)
1259 shutil.chown(dirname, user=uid)
1260 check_chown(dirname, uid)
1261 shutil.chown(dirname, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001262 check_chown(dirname, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001263
1264 user = pwd.getpwuid(uid)[0]
1265 group = grp.getgrgid(gid)[0]
1266 shutil.chown(filename, user, group)
1267 check_chown(filename, uid, gid)
1268 shutil.chown(dirname, user, group)
1269 check_chown(dirname, uid, gid)
1270
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001271 def test_copy_return_value(self):
1272 # copy and copy2 both return their destination path.
1273 for fn in (shutil.copy, shutil.copy2):
1274 src_dir = self.mkdtemp()
1275 dst_dir = self.mkdtemp()
1276 src = os.path.join(src_dir, 'foo')
1277 write_file(src, 'foo')
1278 rv = fn(src, dst_dir)
1279 self.assertEqual(rv, os.path.join(dst_dir, 'foo'))
1280 rv = fn(src, os.path.join(dst_dir, 'bar'))
1281 self.assertEqual(rv, os.path.join(dst_dir, 'bar'))
1282
1283 def test_copyfile_return_value(self):
1284 # copytree returns its destination path.
1285 src_dir = self.mkdtemp()
1286 dst_dir = self.mkdtemp()
1287 dst_file = os.path.join(dst_dir, 'bar')
1288 src_file = os.path.join(src_dir, 'foo')
1289 write_file(src_file, 'foo')
1290 rv = shutil.copyfile(src_file, dst_file)
1291 self.assertTrue(os.path.exists(rv))
1292 self.assertEqual(read_file(src_file), read_file(dst_file))
1293
1294 def test_copytree_return_value(self):
1295 # copytree returns its destination path.
1296 src_dir = self.mkdtemp()
1297 dst_dir = src_dir + "dest"
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001298 self.addCleanup(shutil.rmtree, dst_dir, True)
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001299 src = os.path.join(src_dir, 'foo')
1300 write_file(src, 'foo')
1301 rv = shutil.copytree(src_dir, dst_dir)
1302 self.assertEqual(['foo'], os.listdir(rv))
1303
Christian Heimes9bd667a2008-01-20 15:14:11 +00001304
Brian Curtinc57a3452012-06-22 16:00:30 -05001305class TestWhich(unittest.TestCase):
1306
1307 def setUp(self):
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001308 self.temp_dir = tempfile.mkdtemp(prefix="Tmp")
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001309 self.addCleanup(shutil.rmtree, self.temp_dir, True)
Brian Curtinc57a3452012-06-22 16:00:30 -05001310 # Give the temp_file an ".exe" suffix for all.
1311 # It's needed on Windows and not harmful on other platforms.
1312 self.temp_file = tempfile.NamedTemporaryFile(dir=self.temp_dir,
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001313 prefix="Tmp",
1314 suffix=".Exe")
Brian Curtinc57a3452012-06-22 16:00:30 -05001315 os.chmod(self.temp_file.name, stat.S_IXUSR)
1316 self.addCleanup(self.temp_file.close)
1317 self.dir, self.file = os.path.split(self.temp_file.name)
1318
1319 def test_basic(self):
1320 # Given an EXE in a directory, it should be returned.
1321 rv = shutil.which(self.file, path=self.dir)
1322 self.assertEqual(rv, self.temp_file.name)
1323
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001324 def test_absolute_cmd(self):
Brian Curtinc57a3452012-06-22 16:00:30 -05001325 # When given the fully qualified path to an executable that exists,
1326 # it should be returned.
1327 rv = shutil.which(self.temp_file.name, path=self.temp_dir)
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001328 self.assertEqual(rv, self.temp_file.name)
1329
1330 def test_relative_cmd(self):
1331 # When given the relative path with a directory part to an executable
1332 # that exists, it should be returned.
1333 base_dir, tail_dir = os.path.split(self.dir)
1334 relpath = os.path.join(tail_dir, self.file)
Nick Coghlan55175962013-07-28 22:11:50 +10001335 with support.change_cwd(path=base_dir):
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001336 rv = shutil.which(relpath, path=self.temp_dir)
1337 self.assertEqual(rv, relpath)
1338 # But it shouldn't be searched in PATH directories (issue #16957).
Nick Coghlan55175962013-07-28 22:11:50 +10001339 with support.change_cwd(path=self.dir):
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001340 rv = shutil.which(relpath, path=base_dir)
1341 self.assertIsNone(rv)
1342
1343 def test_cwd(self):
1344 # Issue #16957
1345 base_dir = os.path.dirname(self.dir)
Nick Coghlan55175962013-07-28 22:11:50 +10001346 with support.change_cwd(path=self.dir):
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001347 rv = shutil.which(self.file, path=base_dir)
1348 if sys.platform == "win32":
1349 # Windows: current directory implicitly on PATH
1350 self.assertEqual(rv, os.path.join(os.curdir, self.file))
1351 else:
1352 # Other platforms: shouldn't match in the current directory.
1353 self.assertIsNone(rv)
Brian Curtinc57a3452012-06-22 16:00:30 -05001354
Serhiy Storchaka12516e22013-05-28 15:50:15 +03001355 @unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0,
1356 'non-root user required')
Brian Curtinc57a3452012-06-22 16:00:30 -05001357 def test_non_matching_mode(self):
1358 # Set the file read-only and ask for writeable files.
1359 os.chmod(self.temp_file.name, stat.S_IREAD)
Serhiy Storchaka12516e22013-05-28 15:50:15 +03001360 if os.access(self.temp_file.name, os.W_OK):
1361 self.skipTest("can't set the file read-only")
Brian Curtinc57a3452012-06-22 16:00:30 -05001362 rv = shutil.which(self.file, path=self.dir, mode=os.W_OK)
1363 self.assertIsNone(rv)
1364
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001365 def test_relative_path(self):
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001366 base_dir, tail_dir = os.path.split(self.dir)
Nick Coghlan55175962013-07-28 22:11:50 +10001367 with support.change_cwd(path=base_dir):
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001368 rv = shutil.which(self.file, path=tail_dir)
1369 self.assertEqual(rv, os.path.join(tail_dir, self.file))
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001370
Brian Curtinc57a3452012-06-22 16:00:30 -05001371 def test_nonexistent_file(self):
1372 # Return None when no matching executable file is found on the path.
1373 rv = shutil.which("foo.exe", path=self.dir)
1374 self.assertIsNone(rv)
1375
1376 @unittest.skipUnless(sys.platform == "win32",
1377 "pathext check is Windows-only")
1378 def test_pathext_checking(self):
1379 # Ask for the file without the ".exe" extension, then ensure that
1380 # it gets found properly with the extension.
Serhiy Storchakad70127a2013-01-24 20:03:49 +02001381 rv = shutil.which(self.file[:-4], path=self.dir)
Serhiy Storchaka80c88f42013-01-22 10:31:36 +02001382 self.assertEqual(rv, self.temp_file.name[:-4] + ".EXE")
Brian Curtinc57a3452012-06-22 16:00:30 -05001383
Barry Warsaw618738b2013-04-16 11:05:03 -04001384 def test_environ_path(self):
1385 with support.EnvironmentVarGuard() as env:
1386 env['PATH'] = self.dir
1387 rv = shutil.which(self.file)
1388 self.assertEqual(rv, self.temp_file.name)
1389
1390 def test_empty_path(self):
1391 base_dir = os.path.dirname(self.dir)
Nick Coghlan55175962013-07-28 22:11:50 +10001392 with support.change_cwd(path=self.dir), \
Barry Warsaw618738b2013-04-16 11:05:03 -04001393 support.EnvironmentVarGuard() as env:
1394 env['PATH'] = self.dir
1395 rv = shutil.which(self.file, path='')
1396 self.assertIsNone(rv)
1397
1398 def test_empty_path_no_PATH(self):
1399 with support.EnvironmentVarGuard() as env:
1400 env.pop('PATH', None)
1401 rv = shutil.which(self.file)
1402 self.assertIsNone(rv)
1403
Brian Curtinc57a3452012-06-22 16:00:30 -05001404
Christian Heimesada8c3b2008-03-18 18:26:33 +00001405class TestMove(unittest.TestCase):
1406
1407 def setUp(self):
1408 filename = "foo"
1409 self.src_dir = tempfile.mkdtemp()
1410 self.dst_dir = tempfile.mkdtemp()
1411 self.src_file = os.path.join(self.src_dir, filename)
1412 self.dst_file = os.path.join(self.dst_dir, filename)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001413 with open(self.src_file, "wb") as f:
1414 f.write(b"spam")
1415
1416 def tearDown(self):
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001417 for d in (self.src_dir, self.dst_dir):
Christian Heimesada8c3b2008-03-18 18:26:33 +00001418 try:
1419 if d:
1420 shutil.rmtree(d)
1421 except:
1422 pass
1423
1424 def _check_move_file(self, src, dst, real_dst):
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001425 with open(src, "rb") as f:
1426 contents = f.read()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001427 shutil.move(src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001428 with open(real_dst, "rb") as f:
1429 self.assertEqual(contents, f.read())
Christian Heimesada8c3b2008-03-18 18:26:33 +00001430 self.assertFalse(os.path.exists(src))
1431
1432 def _check_move_dir(self, src, dst, real_dst):
1433 contents = sorted(os.listdir(src))
1434 shutil.move(src, dst)
1435 self.assertEqual(contents, sorted(os.listdir(real_dst)))
1436 self.assertFalse(os.path.exists(src))
1437
1438 def test_move_file(self):
1439 # Move a file to another location on the same filesystem.
1440 self._check_move_file(self.src_file, self.dst_file, self.dst_file)
1441
1442 def test_move_file_to_dir(self):
1443 # Move a file inside an existing dir on the same filesystem.
1444 self._check_move_file(self.src_file, self.dst_dir, self.dst_file)
1445
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001446 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001447 def test_move_file_other_fs(self):
1448 # Move a file to an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001449 self.test_move_file()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001450
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001451 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001452 def test_move_file_to_dir_other_fs(self):
1453 # Move a file to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001454 self.test_move_file_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001455
1456 def test_move_dir(self):
1457 # Move a dir to another location on the same filesystem.
1458 dst_dir = tempfile.mktemp()
1459 try:
1460 self._check_move_dir(self.src_dir, dst_dir, dst_dir)
1461 finally:
1462 try:
1463 shutil.rmtree(dst_dir)
1464 except:
1465 pass
1466
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001467 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001468 def test_move_dir_other_fs(self):
1469 # Move a dir to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001470 self.test_move_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001471
1472 def test_move_dir_to_dir(self):
1473 # Move a dir inside an existing dir on the same filesystem.
1474 self._check_move_dir(self.src_dir, self.dst_dir,
1475 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1476
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001477 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001478 def test_move_dir_to_dir_other_fs(self):
1479 # Move a dir inside an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001480 self.test_move_dir_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001481
1482 def test_existing_file_inside_dest_dir(self):
1483 # A file with the same name inside the destination dir already exists.
1484 with open(self.dst_file, "wb"):
1485 pass
1486 self.assertRaises(shutil.Error, shutil.move, self.src_file, self.dst_dir)
1487
1488 def test_dont_move_dir_in_itself(self):
1489 # Moving a dir inside itself raises an Error.
1490 dst = os.path.join(self.src_dir, "bar")
1491 self.assertRaises(shutil.Error, shutil.move, self.src_dir, dst)
1492
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001493 def test_destinsrc_false_negative(self):
1494 os.mkdir(TESTFN)
1495 try:
1496 for src, dst in [('srcdir', 'srcdir/dest')]:
1497 src = os.path.join(TESTFN, src)
1498 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001499 self.assertTrue(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001500 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001501 'dst (%s) is not in src (%s)' % (dst, src))
1502 finally:
1503 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001504
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001505 def test_destinsrc_false_positive(self):
1506 os.mkdir(TESTFN)
1507 try:
1508 for src, dst in [('srcdir', 'src/dest'), ('srcdir', 'srcdir.new')]:
1509 src = os.path.join(TESTFN, src)
1510 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001511 self.assertFalse(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001512 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001513 'dst (%s) is in src (%s)' % (dst, src))
1514 finally:
1515 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimes9bd667a2008-01-20 15:14:11 +00001516
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +01001517 @support.skip_unless_symlink
1518 @mock_rename
1519 def test_move_file_symlink(self):
1520 dst = os.path.join(self.src_dir, 'bar')
1521 os.symlink(self.src_file, dst)
1522 shutil.move(dst, self.dst_file)
1523 self.assertTrue(os.path.islink(self.dst_file))
1524 self.assertTrue(os.path.samefile(self.src_file, self.dst_file))
1525
1526 @support.skip_unless_symlink
1527 @mock_rename
1528 def test_move_file_symlink_to_dir(self):
1529 filename = "bar"
1530 dst = os.path.join(self.src_dir, filename)
1531 os.symlink(self.src_file, dst)
1532 shutil.move(dst, self.dst_dir)
1533 final_link = os.path.join(self.dst_dir, filename)
1534 self.assertTrue(os.path.islink(final_link))
1535 self.assertTrue(os.path.samefile(self.src_file, final_link))
1536
1537 @support.skip_unless_symlink
1538 @mock_rename
1539 def test_move_dangling_symlink(self):
1540 src = os.path.join(self.src_dir, 'baz')
1541 dst = os.path.join(self.src_dir, 'bar')
1542 os.symlink(src, dst)
1543 dst_link = os.path.join(self.dst_dir, 'quux')
1544 shutil.move(dst, dst_link)
1545 self.assertTrue(os.path.islink(dst_link))
1546 self.assertEqual(os.path.realpath(src), os.path.realpath(dst_link))
1547
1548 @support.skip_unless_symlink
1549 @mock_rename
1550 def test_move_dir_symlink(self):
1551 src = os.path.join(self.src_dir, 'baz')
1552 dst = os.path.join(self.src_dir, 'bar')
1553 os.mkdir(src)
1554 os.symlink(src, dst)
1555 dst_link = os.path.join(self.dst_dir, 'quux')
1556 shutil.move(dst, dst_link)
1557 self.assertTrue(os.path.islink(dst_link))
1558 self.assertTrue(os.path.samefile(src, dst_link))
1559
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001560 def test_move_return_value(self):
1561 rv = shutil.move(self.src_file, self.dst_dir)
1562 self.assertEqual(rv,
1563 os.path.join(self.dst_dir, os.path.basename(self.src_file)))
1564
1565 def test_move_as_rename_return_value(self):
1566 rv = shutil.move(self.src_file, os.path.join(self.dst_dir, 'bar'))
1567 self.assertEqual(rv, os.path.join(self.dst_dir, 'bar'))
1568
Tarek Ziadé5340db32010-04-19 22:30:51 +00001569
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001570class TestCopyFile(unittest.TestCase):
1571
1572 _delete = False
1573
1574 class Faux(object):
1575 _entered = False
1576 _exited_with = None
1577 _raised = False
1578 def __init__(self, raise_in_exit=False, suppress_at_exit=True):
1579 self._raise_in_exit = raise_in_exit
1580 self._suppress_at_exit = suppress_at_exit
1581 def read(self, *args):
1582 return ''
1583 def __enter__(self):
1584 self._entered = True
1585 def __exit__(self, exc_type, exc_val, exc_tb):
1586 self._exited_with = exc_type, exc_val, exc_tb
1587 if self._raise_in_exit:
1588 self._raised = True
1589 raise IOError("Cannot close")
1590 return self._suppress_at_exit
1591
1592 def tearDown(self):
1593 if self._delete:
1594 del shutil.open
1595
1596 def _set_shutil_open(self, func):
1597 shutil.open = func
1598 self._delete = True
1599
1600 def test_w_source_open_fails(self):
1601 def _open(filename, mode='r'):
1602 if filename == 'srcfile':
1603 raise IOError('Cannot open "srcfile"')
1604 assert 0 # shouldn't reach here.
1605
1606 self._set_shutil_open(_open)
1607
1608 self.assertRaises(IOError, shutil.copyfile, 'srcfile', 'destfile')
1609
1610 def test_w_dest_open_fails(self):
1611
1612 srcfile = self.Faux()
1613
1614 def _open(filename, mode='r'):
1615 if filename == 'srcfile':
1616 return srcfile
1617 if filename == 'destfile':
1618 raise IOError('Cannot open "destfile"')
1619 assert 0 # shouldn't reach here.
1620
1621 self._set_shutil_open(_open)
1622
1623 shutil.copyfile('srcfile', 'destfile')
1624 self.assertTrue(srcfile._entered)
1625 self.assertTrue(srcfile._exited_with[0] is IOError)
1626 self.assertEqual(srcfile._exited_with[1].args,
1627 ('Cannot open "destfile"',))
1628
1629 def test_w_dest_close_fails(self):
1630
1631 srcfile = self.Faux()
1632 destfile = self.Faux(True)
1633
1634 def _open(filename, mode='r'):
1635 if filename == 'srcfile':
1636 return srcfile
1637 if filename == 'destfile':
1638 return destfile
1639 assert 0 # shouldn't reach here.
1640
1641 self._set_shutil_open(_open)
1642
1643 shutil.copyfile('srcfile', 'destfile')
1644 self.assertTrue(srcfile._entered)
1645 self.assertTrue(destfile._entered)
1646 self.assertTrue(destfile._raised)
1647 self.assertTrue(srcfile._exited_with[0] is IOError)
1648 self.assertEqual(srcfile._exited_with[1].args,
1649 ('Cannot close',))
1650
1651 def test_w_source_close_fails(self):
1652
1653 srcfile = self.Faux(True)
1654 destfile = self.Faux()
1655
1656 def _open(filename, mode='r'):
1657 if filename == 'srcfile':
1658 return srcfile
1659 if filename == 'destfile':
1660 return destfile
1661 assert 0 # shouldn't reach here.
1662
1663 self._set_shutil_open(_open)
1664
1665 self.assertRaises(IOError,
1666 shutil.copyfile, 'srcfile', 'destfile')
1667 self.assertTrue(srcfile._entered)
1668 self.assertTrue(destfile._entered)
1669 self.assertFalse(destfile._raised)
1670 self.assertTrue(srcfile._exited_with[0] is None)
1671 self.assertTrue(srcfile._raised)
1672
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001673 def test_move_dir_caseinsensitive(self):
1674 # Renames a folder to the same name
1675 # but a different case.
1676
1677 self.src_dir = tempfile.mkdtemp()
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001678 self.addCleanup(shutil.rmtree, self.src_dir, True)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001679 dst_dir = os.path.join(
1680 os.path.dirname(self.src_dir),
1681 os.path.basename(self.src_dir).upper())
1682 self.assertNotEqual(self.src_dir, dst_dir)
1683
1684 try:
1685 shutil.move(self.src_dir, dst_dir)
1686 self.assertTrue(os.path.isdir(dst_dir))
1687 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +02001688 os.rmdir(dst_dir)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001689
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001690class TermsizeTests(unittest.TestCase):
1691 def test_does_not_crash(self):
1692 """Check if get_terminal_size() returns a meaningful value.
1693
1694 There's no easy portable way to actually check the size of the
1695 terminal, so let's check if it returns something sensible instead.
1696 """
1697 size = shutil.get_terminal_size()
Antoine Pitroucfade362012-02-08 23:48:59 +01001698 self.assertGreaterEqual(size.columns, 0)
1699 self.assertGreaterEqual(size.lines, 0)
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001700
1701 def test_os_environ_first(self):
1702 "Check if environment variables have precedence"
1703
1704 with support.EnvironmentVarGuard() as env:
1705 env['COLUMNS'] = '777'
1706 size = shutil.get_terminal_size()
1707 self.assertEqual(size.columns, 777)
1708
1709 with support.EnvironmentVarGuard() as env:
1710 env['LINES'] = '888'
1711 size = shutil.get_terminal_size()
1712 self.assertEqual(size.lines, 888)
1713
1714 @unittest.skipUnless(os.isatty(sys.__stdout__.fileno()), "not on tty")
1715 def test_stty_match(self):
1716 """Check if stty returns the same results ignoring env
1717
1718 This test will fail if stdin and stdout are connected to
1719 different terminals with different sizes. Nevertheless, such
1720 situations should be pretty rare.
1721 """
1722 try:
1723 size = subprocess.check_output(['stty', 'size']).decode().split()
1724 except (FileNotFoundError, subprocess.CalledProcessError):
1725 self.skipTest("stty invocation failed")
1726 expected = (int(size[1]), int(size[0])) # reversed order
1727
1728 with support.EnvironmentVarGuard() as env:
1729 del env['LINES']
1730 del env['COLUMNS']
1731 actual = shutil.get_terminal_size()
1732
1733 self.assertEqual(expected, actual)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001734
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001735
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001736def test_main():
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001737 support.run_unittest(TestShutil, TestMove, TestCopyFile,
Brian Curtinc57a3452012-06-22 16:00:30 -05001738 TermsizeTests, TestWhich)
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001739
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001740if __name__ == '__main__':
Walter Dörwald21d3a322003-05-01 17:45:56 +00001741 test_main()