blob: 6ae051b0aecbb1b5124e871f26d5bbf35044b250 [file] [log] [blame]
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001# Copyright (C) 2003 Python Software Foundation
2
3import unittest
4import shutil
5import tempfile
Johannes Gijsbers8e6f2de2004-11-23 09:27:27 +00006import sys
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +00007import stat
Brett Cannon1c3fa182004-06-19 21:11:35 +00008import os
9import os.path
Antoine Pitrouc041ab62012-01-02 19:18:02 +010010import errno
Nick Coghlan8ed3cf32011-03-16 14:05:35 -040011import functools
Antoine Pitroubcf2b592012-02-08 23:28:36 +010012import subprocess
Benjamin Petersonee8712c2008-05-20 21:35:26 +000013from test import support
14from test.support import TESTFN
Tarek Ziadé396fad72010-02-23 05:30:31 +000015from os.path import splitdrive
16from distutils.spawn import find_executable, spawn
17from shutil import (_make_tarball, _make_zipfile, make_archive,
18 register_archive_format, unregister_archive_format,
Tarek Ziadé6ac91722010-04-28 17:51:36 +000019 get_archive_formats, Error, unpack_archive,
20 register_unpack_format, RegistryError,
Hynek Schlawack26fe37d2012-07-19 21:41:02 +020021 unregister_unpack_format, get_unpack_formats)
Tarek Ziadé396fad72010-02-23 05:30:31 +000022import tarfile
23import warnings
24
25from test import support
Ezio Melotti975077a2011-05-19 22:03:22 +030026from test.support import TESTFN, check_warnings, captured_stdout, requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +000027
Tarek Ziadéffa155a2010-04-29 13:34:35 +000028try:
29 import bz2
30 BZ2_SUPPORTED = True
31except ImportError:
32 BZ2_SUPPORTED = False
33
Antoine Pitrou7fff0962009-05-01 21:09:44 +000034TESTFN2 = TESTFN + "2"
Barry Warsaw7fc2cca2003-01-24 17:34:13 +000035
Tarek Ziadé396fad72010-02-23 05:30:31 +000036try:
37 import grp
38 import pwd
39 UID_GID_SUPPORT = True
40except ImportError:
41 UID_GID_SUPPORT = False
42
43try:
Tarek Ziadé396fad72010-02-23 05:30:31 +000044 import zipfile
45 ZIP_SUPPORT = True
46except ImportError:
47 ZIP_SUPPORT = find_executable('zip')
48
Nick Coghlan8ed3cf32011-03-16 14:05:35 -040049def _fake_rename(*args, **kwargs):
50 # Pretend the destination path is on a different filesystem.
Antoine Pitrouc041ab62012-01-02 19:18:02 +010051 raise OSError(getattr(errno, 'EXDEV', 18), "Invalid cross-device link")
Nick Coghlan8ed3cf32011-03-16 14:05:35 -040052
53def mock_rename(func):
54 @functools.wraps(func)
55 def wrap(*args, **kwargs):
56 try:
57 builtin_rename = os.rename
58 os.rename = _fake_rename
59 return func(*args, **kwargs)
60 finally:
61 os.rename = builtin_rename
62 return wrap
63
Éric Araujoa7e33a12011-08-12 19:51:35 +020064def write_file(path, content, binary=False):
65 """Write *content* to a file located at *path*.
66
67 If *path* is a tuple instead of a string, os.path.join will be used to
68 make a path. If *binary* is true, the file will be opened in binary
69 mode.
70 """
71 if isinstance(path, tuple):
72 path = os.path.join(*path)
73 with open(path, 'wb' if binary else 'w') as fp:
74 fp.write(content)
75
76def read_file(path, binary=False):
77 """Return contents from a file located at *path*.
78
79 If *path* is a tuple instead of a string, os.path.join will be used to
80 make a path. If *binary* is true, the file will be opened in binary
81 mode.
82 """
83 if isinstance(path, tuple):
84 path = os.path.join(*path)
85 with open(path, 'rb' if binary else 'r') as fp:
86 return fp.read()
87
88
Barry Warsaw7fc2cca2003-01-24 17:34:13 +000089class TestShutil(unittest.TestCase):
Tarek Ziadé396fad72010-02-23 05:30:31 +000090
91 def setUp(self):
92 super(TestShutil, self).setUp()
93 self.tempdirs = []
94
95 def tearDown(self):
96 super(TestShutil, self).tearDown()
97 while self.tempdirs:
98 d = self.tempdirs.pop()
99 shutil.rmtree(d, os.name in ('nt', 'cygwin'))
100
Tarek Ziadé396fad72010-02-23 05:30:31 +0000101
102 def mkdtemp(self):
103 """Create a temporary directory that will be cleaned up.
104
105 Returns the path of the directory.
106 """
107 d = tempfile.mkdtemp()
108 self.tempdirs.append(d)
109 return d
Tarek Ziadé5340db32010-04-19 22:30:51 +0000110
Hynek Schlawack3b527782012-06-25 13:27:31 +0200111 def test_rmtree_works_on_bytes(self):
112 tmp = self.mkdtemp()
113 victim = os.path.join(tmp, 'killme')
114 os.mkdir(victim)
115 write_file(os.path.join(victim, 'somefile'), 'foo')
116 victim = os.fsencode(victim)
117 self.assertIsInstance(victim, bytes)
118 shutil.rmtree(victim)
119
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200120 @support.skip_unless_symlink
121 def test_rmtree_fails_on_symlink(self):
122 tmp = self.mkdtemp()
123 dir_ = os.path.join(tmp, 'dir')
124 os.mkdir(dir_)
125 link = os.path.join(tmp, 'link')
126 os.symlink(dir_, link)
127 self.assertRaises(OSError, shutil.rmtree, link)
128 self.assertTrue(os.path.exists(dir_))
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100129 self.assertTrue(os.path.lexists(link))
130 errors = []
131 def onerror(*args):
132 errors.append(args)
133 shutil.rmtree(link, onerror=onerror)
134 self.assertEqual(len(errors), 1)
135 self.assertIs(errors[0][0], os.path.islink)
136 self.assertEqual(errors[0][1], link)
137 self.assertIsInstance(errors[0][2][1], OSError)
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200138
139 @support.skip_unless_symlink
140 def test_rmtree_works_on_symlinks(self):
141 tmp = self.mkdtemp()
142 dir1 = os.path.join(tmp, 'dir1')
143 dir2 = os.path.join(dir1, 'dir2')
144 dir3 = os.path.join(tmp, 'dir3')
145 for d in dir1, dir2, dir3:
146 os.mkdir(d)
147 file1 = os.path.join(tmp, 'file1')
148 write_file(file1, 'foo')
149 link1 = os.path.join(dir1, 'link1')
150 os.symlink(dir2, link1)
151 link2 = os.path.join(dir1, 'link2')
152 os.symlink(dir3, link2)
153 link3 = os.path.join(dir1, 'link3')
154 os.symlink(file1, link3)
155 # make sure symlinks are removed but not followed
156 shutil.rmtree(dir1)
157 self.assertFalse(os.path.exists(dir1))
158 self.assertTrue(os.path.exists(dir3))
159 self.assertTrue(os.path.exists(file1))
160
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000161 def test_rmtree_errors(self):
162 # filename is guaranteed not to exist
163 filename = tempfile.mktemp()
Hynek Schlawackb5501102012-12-10 09:11:25 +0100164 self.assertRaises(FileNotFoundError, shutil.rmtree, filename)
165 # test that ignore_errors option is honored
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100166 shutil.rmtree(filename, ignore_errors=True)
167
168 # existing file
169 tmpdir = self.mkdtemp()
Hynek Schlawackb5501102012-12-10 09:11:25 +0100170 write_file((tmpdir, "tstfile"), "")
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100171 filename = os.path.join(tmpdir, "tstfile")
Hynek Schlawackb5501102012-12-10 09:11:25 +0100172 with self.assertRaises(NotADirectoryError) as cm:
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100173 shutil.rmtree(filename)
Hynek Schlawack87f9b462012-12-10 16:29:57 +0100174 # The reason for this rather odd construct is that Windows sprinkles
175 # a \*.* at the end of file names. But only sometimes on some buildbots
176 possible_args = [filename, os.path.join(filename, '*.*')]
177 self.assertIn(cm.exception.filename, possible_args)
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100178 self.assertTrue(os.path.exists(filename))
Hynek Schlawackb5501102012-12-10 09:11:25 +0100179 # test that ignore_errors option is honored
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100180 shutil.rmtree(filename, ignore_errors=True)
181 self.assertTrue(os.path.exists(filename))
182 errors = []
183 def onerror(*args):
184 errors.append(args)
185 shutil.rmtree(filename, onerror=onerror)
186 self.assertEqual(len(errors), 2)
187 self.assertIs(errors[0][0], os.listdir)
188 self.assertEqual(errors[0][1], filename)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100189 self.assertIsInstance(errors[0][2][1], NotADirectoryError)
Hynek Schlawack87f9b462012-12-10 16:29:57 +0100190 self.assertIn(errors[0][2][1].filename, possible_args)
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100191 self.assertIs(errors[1][0], os.rmdir)
192 self.assertEqual(errors[1][1], filename)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100193 self.assertIsInstance(errors[1][2][1], NotADirectoryError)
Hynek Schlawack87f9b462012-12-10 16:29:57 +0100194 self.assertIn(errors[1][2][1].filename, possible_args)
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000195
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000196
Johannes Gijsbersb8b09d02004-12-06 20:50:15 +0000197 # See bug #1071513 for why we don't run this on cygwin
198 # and bug #1076467 for why we don't run this as root.
199 if (hasattr(os, 'chmod') and sys.platform[:6] != 'cygwin'
Johannes Gijsbers6b220b02004-12-12 15:52:57 +0000200 and not (hasattr(os, 'geteuid') and os.geteuid() == 0)):
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000201 def test_on_error(self):
202 self.errorState = 0
203 os.mkdir(TESTFN)
Antoine Pitrou2f8a75c2012-06-23 21:28:15 +0200204 self.addCleanup(shutil.rmtree, TESTFN)
205
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200206 self.child_file_path = os.path.join(TESTFN, 'a')
207 self.child_dir_path = os.path.join(TESTFN, 'b')
208 support.create_empty_file(self.child_file_path)
209 os.mkdir(self.child_dir_path)
Tim Peters4590c002004-11-01 02:40:52 +0000210 old_dir_mode = os.stat(TESTFN).st_mode
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200211 old_child_file_mode = os.stat(self.child_file_path).st_mode
212 old_child_dir_mode = os.stat(self.child_dir_path).st_mode
Tim Peters4590c002004-11-01 02:40:52 +0000213 # Make unwritable.
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200214 new_mode = stat.S_IREAD|stat.S_IEXEC
215 os.chmod(self.child_file_path, new_mode)
216 os.chmod(self.child_dir_path, new_mode)
217 os.chmod(TESTFN, new_mode)
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000218
Antoine Pitrou2f8a75c2012-06-23 21:28:15 +0200219 self.addCleanup(os.chmod, TESTFN, old_dir_mode)
220 self.addCleanup(os.chmod, self.child_file_path, old_child_file_mode)
221 self.addCleanup(os.chmod, self.child_dir_path, old_child_dir_mode)
222
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000223 shutil.rmtree(TESTFN, onerror=self.check_args_to_onerror)
Johannes Gijsbers8e6f2de2004-11-23 09:27:27 +0000224 # Test whether onerror has actually been called.
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200225 self.assertEqual(self.errorState, 3,
226 "Expected call to onerror function did not "
227 "happen.")
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000228
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000229 def check_args_to_onerror(self, func, arg, exc):
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000230 # test_rmtree_errors deliberately runs rmtree
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200231 # on a directory that is chmod 500, which will fail.
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000232 # This function is run when shutil.rmtree fails.
233 # 99.9% of the time it initially fails to remove
234 # a file in the directory, so the first time through
235 # func is os.remove.
236 # However, some Linux machines running ZFS on
237 # FUSE experienced a failure earlier in the process
238 # at os.listdir. The first failure may legally
239 # be either.
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200240 if self.errorState < 2:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200241 if func is os.unlink:
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200242 self.assertEqual(arg, self.child_file_path)
243 elif func is os.rmdir:
244 self.assertEqual(arg, self.child_dir_path)
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000245 else:
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200246 self.assertIs(func, os.listdir)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200247 self.assertIn(arg, [TESTFN, self.child_dir_path])
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000248 self.assertTrue(issubclass(exc[0], OSError))
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200249 self.errorState += 1
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000250 else:
251 self.assertEqual(func, os.rmdir)
252 self.assertEqual(arg, TESTFN)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000253 self.assertTrue(issubclass(exc[0], OSError))
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200254 self.errorState = 3
255
256 def test_rmtree_does_not_choke_on_failing_lstat(self):
257 try:
258 orig_lstat = os.lstat
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200259 def raiser(fn, *args, **kwargs):
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200260 if fn != TESTFN:
261 raise OSError()
262 else:
263 return orig_lstat(fn)
264 os.lstat = raiser
265
266 os.mkdir(TESTFN)
267 write_file((TESTFN, 'foo'), 'foo')
268 shutil.rmtree(TESTFN)
269 finally:
270 os.lstat = orig_lstat
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000271
Antoine Pitrou78091e62011-12-29 18:54:15 +0100272 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
273 @support.skip_unless_symlink
274 def test_copymode_follow_symlinks(self):
275 tmp_dir = self.mkdtemp()
276 src = os.path.join(tmp_dir, 'foo')
277 dst = os.path.join(tmp_dir, 'bar')
278 src_link = os.path.join(tmp_dir, 'baz')
279 dst_link = os.path.join(tmp_dir, 'quux')
280 write_file(src, 'foo')
281 write_file(dst, 'foo')
282 os.symlink(src, src_link)
283 os.symlink(dst, dst_link)
284 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
285 # file to file
286 os.chmod(dst, stat.S_IRWXO)
287 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
288 shutil.copymode(src, dst)
289 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
290 # follow src link
291 os.chmod(dst, stat.S_IRWXO)
292 shutil.copymode(src_link, dst)
293 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
294 # follow dst link
295 os.chmod(dst, stat.S_IRWXO)
296 shutil.copymode(src, dst_link)
297 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
298 # follow both links
299 os.chmod(dst, stat.S_IRWXO)
300 shutil.copymode(src_link, dst)
301 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
302
303 @unittest.skipUnless(hasattr(os, 'lchmod'), 'requires os.lchmod')
304 @support.skip_unless_symlink
305 def test_copymode_symlink_to_symlink(self):
306 tmp_dir = self.mkdtemp()
307 src = os.path.join(tmp_dir, 'foo')
308 dst = os.path.join(tmp_dir, 'bar')
309 src_link = os.path.join(tmp_dir, 'baz')
310 dst_link = os.path.join(tmp_dir, 'quux')
311 write_file(src, 'foo')
312 write_file(dst, 'foo')
313 os.symlink(src, src_link)
314 os.symlink(dst, dst_link)
315 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
316 os.chmod(dst, stat.S_IRWXU)
317 os.lchmod(src_link, stat.S_IRWXO|stat.S_IRWXG)
318 # link to link
319 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700320 shutil.copymode(src_link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100321 self.assertEqual(os.lstat(src_link).st_mode,
322 os.lstat(dst_link).st_mode)
323 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
324 # src link - use chmod
325 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700326 shutil.copymode(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100327 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
328 # dst link - use chmod
329 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700330 shutil.copymode(src, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100331 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
332
333 @unittest.skipIf(hasattr(os, 'lchmod'), 'requires os.lchmod to be missing')
334 @support.skip_unless_symlink
335 def test_copymode_symlink_to_symlink_wo_lchmod(self):
336 tmp_dir = self.mkdtemp()
337 src = os.path.join(tmp_dir, 'foo')
338 dst = os.path.join(tmp_dir, 'bar')
339 src_link = os.path.join(tmp_dir, 'baz')
340 dst_link = os.path.join(tmp_dir, 'quux')
341 write_file(src, 'foo')
342 write_file(dst, 'foo')
343 os.symlink(src, src_link)
344 os.symlink(dst, dst_link)
Larry Hastingsb4038062012-07-15 10:57:38 -0700345 shutil.copymode(src_link, dst_link, follow_symlinks=False) # silent fail
Antoine Pitrou78091e62011-12-29 18:54:15 +0100346
347 @support.skip_unless_symlink
348 def test_copystat_symlinks(self):
349 tmp_dir = self.mkdtemp()
350 src = os.path.join(tmp_dir, 'foo')
351 dst = os.path.join(tmp_dir, 'bar')
352 src_link = os.path.join(tmp_dir, 'baz')
353 dst_link = os.path.join(tmp_dir, 'qux')
354 write_file(src, 'foo')
355 src_stat = os.stat(src)
356 os.utime(src, (src_stat.st_atime,
357 src_stat.st_mtime - 42.0)) # ensure different mtimes
358 write_file(dst, 'bar')
359 self.assertNotEqual(os.stat(src).st_mtime, os.stat(dst).st_mtime)
360 os.symlink(src, src_link)
361 os.symlink(dst, dst_link)
362 if hasattr(os, 'lchmod'):
363 os.lchmod(src_link, stat.S_IRWXO)
364 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
365 os.lchflags(src_link, stat.UF_NODUMP)
366 src_link_stat = os.lstat(src_link)
367 # follow
368 if hasattr(os, 'lchmod'):
Larry Hastingsb4038062012-07-15 10:57:38 -0700369 shutil.copystat(src_link, dst_link, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100370 self.assertNotEqual(src_link_stat.st_mode, os.stat(dst).st_mode)
371 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700372 shutil.copystat(src_link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100373 dst_link_stat = os.lstat(dst_link)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700374 if os.utime in os.supports_follow_symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100375 for attr in 'st_atime', 'st_mtime':
376 # The modification times may be truncated in the new file.
377 self.assertLessEqual(getattr(src_link_stat, attr),
378 getattr(dst_link_stat, attr) + 1)
379 if hasattr(os, 'lchmod'):
380 self.assertEqual(src_link_stat.st_mode, dst_link_stat.st_mode)
381 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
382 self.assertEqual(src_link_stat.st_flags, dst_link_stat.st_flags)
383 # tell to follow but dst is not a link
Larry Hastingsb4038062012-07-15 10:57:38 -0700384 shutil.copystat(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100385 self.assertTrue(abs(os.stat(src).st_mtime - os.stat(dst).st_mtime) <
386 00000.1)
387
Ned Deilybaf75712012-05-10 17:05:19 -0700388 @unittest.skipUnless(hasattr(os, 'chflags') and
389 hasattr(errno, 'EOPNOTSUPP') and
390 hasattr(errno, 'ENOTSUP'),
391 "requires os.chflags, EOPNOTSUPP & ENOTSUP")
392 def test_copystat_handles_harmless_chflags_errors(self):
393 tmpdir = self.mkdtemp()
394 file1 = os.path.join(tmpdir, 'file1')
395 file2 = os.path.join(tmpdir, 'file2')
396 write_file(file1, 'xxx')
397 write_file(file2, 'xxx')
398
399 def make_chflags_raiser(err):
400 ex = OSError()
401
Larry Hastings90867a52012-06-22 17:01:41 -0700402 def _chflags_raiser(path, flags, *, follow_symlinks=True):
Ned Deilybaf75712012-05-10 17:05:19 -0700403 ex.errno = err
404 raise ex
405 return _chflags_raiser
406 old_chflags = os.chflags
407 try:
408 for err in errno.EOPNOTSUPP, errno.ENOTSUP:
409 os.chflags = make_chflags_raiser(err)
410 shutil.copystat(file1, file2)
411 # assert others errors break it
412 os.chflags = make_chflags_raiser(errno.EOPNOTSUPP + errno.ENOTSUP)
413 self.assertRaises(OSError, shutil.copystat, file1, file2)
414 finally:
415 os.chflags = old_chflags
416
Antoine Pitrou424246f2012-05-12 19:02:01 +0200417 @support.skip_unless_xattr
418 def test_copyxattr(self):
419 tmp_dir = self.mkdtemp()
420 src = os.path.join(tmp_dir, 'foo')
421 write_file(src, 'foo')
422 dst = os.path.join(tmp_dir, 'bar')
423 write_file(dst, 'bar')
424
425 # no xattr == no problem
426 shutil._copyxattr(src, dst)
427 # common case
428 os.setxattr(src, 'user.foo', b'42')
429 os.setxattr(src, 'user.bar', b'43')
430 shutil._copyxattr(src, dst)
431 self.assertEqual(os.listxattr(src), os.listxattr(dst))
432 self.assertEqual(
433 os.getxattr(src, 'user.foo'),
434 os.getxattr(dst, 'user.foo'))
435 # check errors don't affect other attrs
436 os.remove(dst)
437 write_file(dst, 'bar')
438 os_error = OSError(errno.EPERM, 'EPERM')
439
Larry Hastings9cf065c2012-06-22 16:30:09 -0700440 def _raise_on_user_foo(fname, attr, val, **kwargs):
Antoine Pitrou424246f2012-05-12 19:02:01 +0200441 if attr == 'user.foo':
442 raise os_error
443 else:
Larry Hastings9cf065c2012-06-22 16:30:09 -0700444 orig_setxattr(fname, attr, val, **kwargs)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200445 try:
446 orig_setxattr = os.setxattr
447 os.setxattr = _raise_on_user_foo
448 shutil._copyxattr(src, dst)
Antoine Pitrou61597d32012-05-12 23:37:35 +0200449 self.assertIn('user.bar', os.listxattr(dst))
Antoine Pitrou424246f2012-05-12 19:02:01 +0200450 finally:
451 os.setxattr = orig_setxattr
452
Larry Hastingsad5ae042012-07-14 17:55:11 -0700453 # test that shutil.copystat copies xattrs
454 src = os.path.join(tmp_dir, 'the_original')
455 write_file(src, src)
456 os.setxattr(src, 'user.the_value', b'fiddly')
457 dst = os.path.join(tmp_dir, 'the_copy')
458 write_file(dst, dst)
459 shutil.copystat(src, dst)
Hynek Schlawackc2d481f2012-07-16 17:11:10 +0200460 self.assertEqual(os.getxattr(dst, 'user.the_value'), b'fiddly')
Larry Hastingsad5ae042012-07-14 17:55:11 -0700461
Antoine Pitrou424246f2012-05-12 19:02:01 +0200462 @support.skip_unless_symlink
463 @support.skip_unless_xattr
464 @unittest.skipUnless(hasattr(os, 'geteuid') and os.geteuid() == 0,
465 'root privileges required')
466 def test_copyxattr_symlinks(self):
467 # On Linux, it's only possible to access non-user xattr for symlinks;
468 # which in turn require root privileges. This test should be expanded
469 # as soon as other platforms gain support for extended attributes.
470 tmp_dir = self.mkdtemp()
471 src = os.path.join(tmp_dir, 'foo')
472 src_link = os.path.join(tmp_dir, 'baz')
473 write_file(src, 'foo')
474 os.symlink(src, src_link)
475 os.setxattr(src, 'trusted.foo', b'42')
Larry Hastings9cf065c2012-06-22 16:30:09 -0700476 os.setxattr(src_link, 'trusted.foo', b'43', follow_symlinks=False)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200477 dst = os.path.join(tmp_dir, 'bar')
478 dst_link = os.path.join(tmp_dir, 'qux')
479 write_file(dst, 'bar')
480 os.symlink(dst, dst_link)
Larry Hastingsb4038062012-07-15 10:57:38 -0700481 shutil._copyxattr(src_link, dst_link, follow_symlinks=False)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700482 self.assertEqual(os.getxattr(dst_link, 'trusted.foo', follow_symlinks=False), b'43')
Antoine Pitrou424246f2012-05-12 19:02:01 +0200483 self.assertRaises(OSError, os.getxattr, dst, 'trusted.foo')
Larry Hastingsb4038062012-07-15 10:57:38 -0700484 shutil._copyxattr(src_link, dst, follow_symlinks=False)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200485 self.assertEqual(os.getxattr(dst, 'trusted.foo'), b'43')
486
Antoine Pitrou78091e62011-12-29 18:54:15 +0100487 @support.skip_unless_symlink
488 def test_copy_symlinks(self):
489 tmp_dir = self.mkdtemp()
490 src = os.path.join(tmp_dir, 'foo')
491 dst = os.path.join(tmp_dir, 'bar')
492 src_link = os.path.join(tmp_dir, 'baz')
493 write_file(src, 'foo')
494 os.symlink(src, src_link)
495 if hasattr(os, 'lchmod'):
496 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
497 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700498 shutil.copy(src_link, dst, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100499 self.assertFalse(os.path.islink(dst))
500 self.assertEqual(read_file(src), read_file(dst))
501 os.remove(dst)
502 # follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700503 shutil.copy(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100504 self.assertTrue(os.path.islink(dst))
505 self.assertEqual(os.readlink(dst), os.readlink(src_link))
506 if hasattr(os, 'lchmod'):
507 self.assertEqual(os.lstat(src_link).st_mode,
508 os.lstat(dst).st_mode)
509
510 @support.skip_unless_symlink
511 def test_copy2_symlinks(self):
512 tmp_dir = self.mkdtemp()
513 src = os.path.join(tmp_dir, 'foo')
514 dst = os.path.join(tmp_dir, 'bar')
515 src_link = os.path.join(tmp_dir, 'baz')
516 write_file(src, 'foo')
517 os.symlink(src, src_link)
518 if hasattr(os, 'lchmod'):
519 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
520 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
521 os.lchflags(src_link, stat.UF_NODUMP)
522 src_stat = os.stat(src)
523 src_link_stat = os.lstat(src_link)
524 # follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700525 shutil.copy2(src_link, dst, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100526 self.assertFalse(os.path.islink(dst))
527 self.assertEqual(read_file(src), read_file(dst))
528 os.remove(dst)
529 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700530 shutil.copy2(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100531 self.assertTrue(os.path.islink(dst))
532 self.assertEqual(os.readlink(dst), os.readlink(src_link))
533 dst_stat = os.lstat(dst)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700534 if os.utime in os.supports_follow_symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100535 for attr in 'st_atime', 'st_mtime':
536 # The modification times may be truncated in the new file.
537 self.assertLessEqual(getattr(src_link_stat, attr),
538 getattr(dst_stat, attr) + 1)
539 if hasattr(os, 'lchmod'):
540 self.assertEqual(src_link_stat.st_mode, dst_stat.st_mode)
541 self.assertNotEqual(src_stat.st_mode, dst_stat.st_mode)
542 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
543 self.assertEqual(src_link_stat.st_flags, dst_stat.st_flags)
544
Antoine Pitrou424246f2012-05-12 19:02:01 +0200545 @support.skip_unless_xattr
546 def test_copy2_xattr(self):
547 tmp_dir = self.mkdtemp()
548 src = os.path.join(tmp_dir, 'foo')
549 dst = os.path.join(tmp_dir, 'bar')
550 write_file(src, 'foo')
551 os.setxattr(src, 'user.foo', b'42')
552 shutil.copy2(src, dst)
553 self.assertEqual(
554 os.getxattr(src, 'user.foo'),
555 os.getxattr(dst, 'user.foo'))
556 os.remove(dst)
557
Antoine Pitrou78091e62011-12-29 18:54:15 +0100558 @support.skip_unless_symlink
559 def test_copyfile_symlinks(self):
560 tmp_dir = self.mkdtemp()
561 src = os.path.join(tmp_dir, 'src')
562 dst = os.path.join(tmp_dir, 'dst')
563 dst_link = os.path.join(tmp_dir, 'dst_link')
564 link = os.path.join(tmp_dir, 'link')
565 write_file(src, 'foo')
566 os.symlink(src, link)
567 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700568 shutil.copyfile(link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100569 self.assertTrue(os.path.islink(dst_link))
570 self.assertEqual(os.readlink(link), os.readlink(dst_link))
571 # follow
572 shutil.copyfile(link, dst)
573 self.assertFalse(os.path.islink(dst))
574
Hynek Schlawack2100b422012-06-23 20:28:32 +0200575 def test_rmtree_uses_safe_fd_version_if_available(self):
Hynek Schlawackd0f6e0a2012-06-29 08:28:20 +0200576 _use_fd_functions = ({os.open, os.stat, os.unlink, os.rmdir} <=
577 os.supports_dir_fd and
578 os.listdir in os.supports_fd and
579 os.stat in os.supports_follow_symlinks)
580 if _use_fd_functions:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200581 self.assertTrue(shutil._use_fd_functions)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000582 self.assertTrue(shutil.rmtree.avoids_symlink_attacks)
Hynek Schlawack2100b422012-06-23 20:28:32 +0200583 tmp_dir = self.mkdtemp()
584 d = os.path.join(tmp_dir, 'a')
585 os.mkdir(d)
586 try:
587 real_rmtree = shutil._rmtree_safe_fd
588 class Called(Exception): pass
589 def _raiser(*args, **kwargs):
590 raise Called
591 shutil._rmtree_safe_fd = _raiser
592 self.assertRaises(Called, shutil.rmtree, d)
593 finally:
594 shutil._rmtree_safe_fd = real_rmtree
595 else:
596 self.assertFalse(shutil._use_fd_functions)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000597 self.assertFalse(shutil.rmtree.avoids_symlink_attacks)
Hynek Schlawack2100b422012-06-23 20:28:32 +0200598
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000599 def test_rmtree_dont_delete_file(self):
600 # When called on a file instead of a directory, don't delete it.
601 handle, path = tempfile.mkstemp()
Victor Stinnerbf816222011-06-30 23:25:47 +0200602 os.close(handle)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200603 self.assertRaises(NotADirectoryError, shutil.rmtree, path)
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000604 os.remove(path)
605
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000606 def test_copytree_simple(self):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000607 src_dir = tempfile.mkdtemp()
608 dst_dir = os.path.join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200609 self.addCleanup(shutil.rmtree, src_dir)
610 self.addCleanup(shutil.rmtree, os.path.dirname(dst_dir))
611 write_file((src_dir, 'test.txt'), '123')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000612 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200613 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000614
Éric Araujoa7e33a12011-08-12 19:51:35 +0200615 shutil.copytree(src_dir, dst_dir)
616 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test.txt')))
617 self.assertTrue(os.path.isdir(os.path.join(dst_dir, 'test_dir')))
618 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test_dir',
619 'test.txt')))
620 actual = read_file((dst_dir, 'test.txt'))
621 self.assertEqual(actual, '123')
622 actual = read_file((dst_dir, 'test_dir', 'test.txt'))
623 self.assertEqual(actual, '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000624
Antoine Pitrou78091e62011-12-29 18:54:15 +0100625 @support.skip_unless_symlink
626 def test_copytree_symlinks(self):
627 tmp_dir = self.mkdtemp()
628 src_dir = os.path.join(tmp_dir, 'src')
629 dst_dir = os.path.join(tmp_dir, 'dst')
630 sub_dir = os.path.join(src_dir, 'sub')
631 os.mkdir(src_dir)
632 os.mkdir(sub_dir)
633 write_file((src_dir, 'file.txt'), 'foo')
634 src_link = os.path.join(sub_dir, 'link')
635 dst_link = os.path.join(dst_dir, 'sub/link')
636 os.symlink(os.path.join(src_dir, 'file.txt'),
637 src_link)
638 if hasattr(os, 'lchmod'):
639 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
640 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
641 os.lchflags(src_link, stat.UF_NODUMP)
642 src_stat = os.lstat(src_link)
643 shutil.copytree(src_dir, dst_dir, symlinks=True)
644 self.assertTrue(os.path.islink(os.path.join(dst_dir, 'sub', 'link')))
645 self.assertEqual(os.readlink(os.path.join(dst_dir, 'sub', 'link')),
646 os.path.join(src_dir, 'file.txt'))
647 dst_stat = os.lstat(dst_link)
648 if hasattr(os, 'lchmod'):
649 self.assertEqual(dst_stat.st_mode, src_stat.st_mode)
650 if hasattr(os, 'lchflags'):
651 self.assertEqual(dst_stat.st_flags, src_stat.st_flags)
652
Georg Brandl2ee470f2008-07-16 12:55:28 +0000653 def test_copytree_with_exclude(self):
Georg Brandl2ee470f2008-07-16 12:55:28 +0000654 # creating data
655 join = os.path.join
656 exists = os.path.exists
657 src_dir = tempfile.mkdtemp()
Georg Brandl2ee470f2008-07-16 12:55:28 +0000658 try:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000659 dst_dir = join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200660 write_file((src_dir, 'test.txt'), '123')
661 write_file((src_dir, 'test.tmp'), '123')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000662 os.mkdir(join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200663 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000664 os.mkdir(join(src_dir, 'test_dir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200665 write_file((src_dir, 'test_dir2', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000666 os.mkdir(join(src_dir, 'test_dir2', 'subdir'))
667 os.mkdir(join(src_dir, 'test_dir2', 'subdir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200668 write_file((src_dir, 'test_dir2', 'subdir', 'test.txt'), '456')
669 write_file((src_dir, 'test_dir2', 'subdir2', 'test.py'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000670
671 # testing glob-like patterns
672 try:
673 patterns = shutil.ignore_patterns('*.tmp', 'test_dir2')
674 shutil.copytree(src_dir, dst_dir, ignore=patterns)
675 # checking the result: some elements should not be copied
676 self.assertTrue(exists(join(dst_dir, 'test.txt')))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200677 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
678 self.assertFalse(exists(join(dst_dir, 'test_dir2')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000679 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200680 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000681 try:
682 patterns = shutil.ignore_patterns('*.tmp', 'subdir*')
683 shutil.copytree(src_dir, dst_dir, ignore=patterns)
684 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200685 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
686 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2')))
687 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000688 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200689 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000690
691 # testing callable-style
692 try:
693 def _filter(src, names):
694 res = []
695 for name in names:
696 path = os.path.join(src, name)
697
698 if (os.path.isdir(path) and
699 path.split()[-1] == 'subdir'):
700 res.append(name)
701 elif os.path.splitext(path)[-1] in ('.py'):
702 res.append(name)
703 return res
704
705 shutil.copytree(src_dir, dst_dir, ignore=_filter)
706
707 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200708 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2',
709 'test.py')))
710 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000711
712 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200713 shutil.rmtree(dst_dir)
Georg Brandl2ee470f2008-07-16 12:55:28 +0000714 finally:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000715 shutil.rmtree(src_dir)
716 shutil.rmtree(os.path.dirname(dst_dir))
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000717
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000718 @unittest.skipUnless(hasattr(os, 'link'), 'requires os.link')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000719 def test_dont_copy_file_onto_link_to_itself(self):
Georg Brandl724d0892010-12-05 07:51:39 +0000720 # Temporarily disable test on Windows.
721 if os.name == 'nt':
722 return
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000723 # bug 851123.
724 os.mkdir(TESTFN)
725 src = os.path.join(TESTFN, 'cheese')
726 dst = os.path.join(TESTFN, 'shop')
727 try:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000728 with open(src, 'w') as f:
729 f.write('cheddar')
730 os.link(src, dst)
Hynek Schlawack26fe37d2012-07-19 21:41:02 +0200731 self.assertRaises(shutil.Error, shutil.copyfile, src, dst)
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000732 with open(src, 'r') as f:
733 self.assertEqual(f.read(), 'cheddar')
734 os.remove(dst)
735 finally:
736 shutil.rmtree(TESTFN, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000737
Brian Curtin3b4499c2010-12-28 14:31:47 +0000738 @support.skip_unless_symlink
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000739 def test_dont_copy_file_onto_symlink_to_itself(self):
740 # bug 851123.
741 os.mkdir(TESTFN)
742 src = os.path.join(TESTFN, 'cheese')
743 dst = os.path.join(TESTFN, 'shop')
744 try:
745 with open(src, 'w') as f:
746 f.write('cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000747 # Using `src` here would mean we end up with a symlink pointing
748 # to TESTFN/TESTFN/cheese, while it should point at
749 # TESTFN/cheese.
750 os.symlink('cheese', dst)
Hynek Schlawack26fe37d2012-07-19 21:41:02 +0200751 self.assertRaises(shutil.Error, shutil.copyfile, src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +0000752 with open(src, 'r') as f:
753 self.assertEqual(f.read(), 'cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000754 os.remove(dst)
755 finally:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000756 shutil.rmtree(TESTFN, ignore_errors=True)
Johannes Gijsbers68128712004-08-14 13:57:08 +0000757
Brian Curtin3b4499c2010-12-28 14:31:47 +0000758 @support.skip_unless_symlink
Brian Curtind40e6f72010-07-08 21:39:08 +0000759 def test_rmtree_on_symlink(self):
760 # bug 1669.
761 os.mkdir(TESTFN)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000762 try:
Brian Curtind40e6f72010-07-08 21:39:08 +0000763 src = os.path.join(TESTFN, 'cheese')
764 dst = os.path.join(TESTFN, 'shop')
765 os.mkdir(src)
766 os.symlink(src, dst)
767 self.assertRaises(OSError, shutil.rmtree, dst)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200768 shutil.rmtree(dst, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000769 finally:
Brian Curtind40e6f72010-07-08 21:39:08 +0000770 shutil.rmtree(TESTFN, ignore_errors=True)
771
772 if hasattr(os, "mkfifo"):
773 # Issue #3002: copyfile and copytree block indefinitely on named pipes
774 def test_copyfile_named_pipe(self):
775 os.mkfifo(TESTFN)
776 try:
777 self.assertRaises(shutil.SpecialFileError,
778 shutil.copyfile, TESTFN, TESTFN2)
779 self.assertRaises(shutil.SpecialFileError,
780 shutil.copyfile, __file__, TESTFN)
781 finally:
782 os.remove(TESTFN)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000783
Brian Curtin3b4499c2010-12-28 14:31:47 +0000784 @support.skip_unless_symlink
Brian Curtin52173d42010-12-02 18:29:18 +0000785 def test_copytree_named_pipe(self):
786 os.mkdir(TESTFN)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000787 try:
Brian Curtin52173d42010-12-02 18:29:18 +0000788 subdir = os.path.join(TESTFN, "subdir")
789 os.mkdir(subdir)
790 pipe = os.path.join(subdir, "mypipe")
791 os.mkfifo(pipe)
792 try:
793 shutil.copytree(TESTFN, TESTFN2)
794 except shutil.Error as e:
795 errors = e.args[0]
796 self.assertEqual(len(errors), 1)
797 src, dst, error_msg = errors[0]
798 self.assertEqual("`%s` is a named pipe" % pipe, error_msg)
799 else:
800 self.fail("shutil.Error should have been raised")
801 finally:
802 shutil.rmtree(TESTFN, ignore_errors=True)
803 shutil.rmtree(TESTFN2, ignore_errors=True)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000804
Tarek Ziadé5340db32010-04-19 22:30:51 +0000805 def test_copytree_special_func(self):
806
807 src_dir = self.mkdtemp()
808 dst_dir = os.path.join(self.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200809 write_file((src_dir, 'test.txt'), '123')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000810 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200811 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000812
813 copied = []
814 def _copy(src, dst):
815 copied.append((src, dst))
816
817 shutil.copytree(src_dir, dst_dir, copy_function=_copy)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000818 self.assertEqual(len(copied), 2)
Tarek Ziadé5340db32010-04-19 22:30:51 +0000819
Brian Curtin3b4499c2010-12-28 14:31:47 +0000820 @support.skip_unless_symlink
Tarek Ziadéfb437512010-04-20 08:57:33 +0000821 def test_copytree_dangling_symlinks(self):
822
823 # a dangling symlink raises an error at the end
824 src_dir = self.mkdtemp()
825 dst_dir = os.path.join(self.mkdtemp(), 'destination')
826 os.symlink('IDONTEXIST', os.path.join(src_dir, 'test.txt'))
827 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200828 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadéfb437512010-04-20 08:57:33 +0000829 self.assertRaises(Error, shutil.copytree, src_dir, dst_dir)
830
831 # a dangling symlink is ignored with the proper flag
832 dst_dir = os.path.join(self.mkdtemp(), 'destination2')
833 shutil.copytree(src_dir, dst_dir, ignore_dangling_symlinks=True)
834 self.assertNotIn('test.txt', os.listdir(dst_dir))
835
836 # a dangling symlink is copied if symlinks=True
837 dst_dir = os.path.join(self.mkdtemp(), 'destination3')
838 shutil.copytree(src_dir, dst_dir, symlinks=True)
839 self.assertIn('test.txt', os.listdir(dst_dir))
840
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400841 def _copy_file(self, method):
842 fname = 'test.txt'
843 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200844 write_file((tmpdir, fname), 'xxx')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400845 file1 = os.path.join(tmpdir, fname)
846 tmpdir2 = self.mkdtemp()
847 method(file1, tmpdir2)
848 file2 = os.path.join(tmpdir2, fname)
849 return (file1, file2)
850
851 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
852 def test_copy(self):
853 # Ensure that the copied file exists and has the same mode bits.
854 file1, file2 = self._copy_file(shutil.copy)
855 self.assertTrue(os.path.exists(file2))
856 self.assertEqual(os.stat(file1).st_mode, os.stat(file2).st_mode)
857
858 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
Senthil Kumaran0c2dba52011-07-03 18:21:38 -0700859 @unittest.skipUnless(hasattr(os, 'utime'), 'requires os.utime')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400860 def test_copy2(self):
861 # Ensure that the copied file exists and has the same mode and
862 # modification time bits.
863 file1, file2 = self._copy_file(shutil.copy2)
864 self.assertTrue(os.path.exists(file2))
865 file1_stat = os.stat(file1)
866 file2_stat = os.stat(file2)
867 self.assertEqual(file1_stat.st_mode, file2_stat.st_mode)
868 for attr in 'st_atime', 'st_mtime':
869 # The modification times may be truncated in the new file.
870 self.assertLessEqual(getattr(file1_stat, attr),
871 getattr(file2_stat, attr) + 1)
872 if hasattr(os, 'chflags') and hasattr(file1_stat, 'st_flags'):
873 self.assertEqual(getattr(file1_stat, 'st_flags'),
874 getattr(file2_stat, 'st_flags'))
875
Ezio Melotti975077a2011-05-19 22:03:22 +0300876 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000877 def test_make_tarball(self):
878 # creating something to tar
879 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200880 write_file((tmpdir, 'file1'), 'xxx')
881 write_file((tmpdir, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000882 os.mkdir(os.path.join(tmpdir, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200883 write_file((tmpdir, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000884
885 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400886 # force shutil to create the directory
887 os.rmdir(tmpdir2)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000888 unittest.skipUnless(splitdrive(tmpdir)[0] == splitdrive(tmpdir2)[0],
889 "source and target should be on same drive")
890
891 base_name = os.path.join(tmpdir2, 'archive')
892
893 # working with relative paths to avoid tar warnings
894 old_dir = os.getcwd()
895 os.chdir(tmpdir)
896 try:
897 _make_tarball(splitdrive(base_name)[1], '.')
898 finally:
899 os.chdir(old_dir)
900
901 # check if the compressed tarball was created
902 tarball = base_name + '.tar.gz'
903 self.assertTrue(os.path.exists(tarball))
904
905 # trying an uncompressed one
906 base_name = os.path.join(tmpdir2, 'archive')
907 old_dir = os.getcwd()
908 os.chdir(tmpdir)
909 try:
910 _make_tarball(splitdrive(base_name)[1], '.', compress=None)
911 finally:
912 os.chdir(old_dir)
913 tarball = base_name + '.tar'
914 self.assertTrue(os.path.exists(tarball))
915
916 def _tarinfo(self, path):
917 tar = tarfile.open(path)
918 try:
919 names = tar.getnames()
920 names.sort()
921 return tuple(names)
922 finally:
923 tar.close()
924
925 def _create_files(self):
926 # creating something to tar
927 tmpdir = self.mkdtemp()
928 dist = os.path.join(tmpdir, 'dist')
929 os.mkdir(dist)
Éric Araujoa7e33a12011-08-12 19:51:35 +0200930 write_file((dist, 'file1'), 'xxx')
931 write_file((dist, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000932 os.mkdir(os.path.join(dist, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200933 write_file((dist, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000934 os.mkdir(os.path.join(dist, 'sub2'))
935 tmpdir2 = self.mkdtemp()
936 base_name = os.path.join(tmpdir2, 'archive')
937 return tmpdir, tmpdir2, base_name
938
Ezio Melotti975077a2011-05-19 22:03:22 +0300939 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000940 @unittest.skipUnless(find_executable('tar') and find_executable('gzip'),
941 'Need the tar command to run')
942 def test_tarfile_vs_tar(self):
943 tmpdir, tmpdir2, base_name = self._create_files()
944 old_dir = os.getcwd()
945 os.chdir(tmpdir)
946 try:
947 _make_tarball(base_name, 'dist')
948 finally:
949 os.chdir(old_dir)
950
951 # check if the compressed tarball was created
952 tarball = base_name + '.tar.gz'
953 self.assertTrue(os.path.exists(tarball))
954
955 # now create another tarball using `tar`
956 tarball2 = os.path.join(tmpdir, 'archive2.tar.gz')
957 tar_cmd = ['tar', '-cf', 'archive2.tar', 'dist']
958 gzip_cmd = ['gzip', '-f9', 'archive2.tar']
959 old_dir = os.getcwd()
960 os.chdir(tmpdir)
961 try:
962 with captured_stdout() as s:
963 spawn(tar_cmd)
964 spawn(gzip_cmd)
965 finally:
966 os.chdir(old_dir)
967
968 self.assertTrue(os.path.exists(tarball2))
969 # let's compare both tarballs
Ezio Melottib3aedd42010-11-20 19:04:17 +0000970 self.assertEqual(self._tarinfo(tarball), self._tarinfo(tarball2))
Tarek Ziadé396fad72010-02-23 05:30:31 +0000971
972 # trying an uncompressed one
973 base_name = os.path.join(tmpdir2, 'archive')
974 old_dir = os.getcwd()
975 os.chdir(tmpdir)
976 try:
977 _make_tarball(base_name, 'dist', compress=None)
978 finally:
979 os.chdir(old_dir)
980 tarball = base_name + '.tar'
981 self.assertTrue(os.path.exists(tarball))
982
983 # now for a dry_run
984 base_name = os.path.join(tmpdir2, 'archive')
985 old_dir = os.getcwd()
986 os.chdir(tmpdir)
987 try:
988 _make_tarball(base_name, 'dist', compress=None, dry_run=True)
989 finally:
990 os.chdir(old_dir)
991 tarball = base_name + '.tar'
992 self.assertTrue(os.path.exists(tarball))
993
Ezio Melotti975077a2011-05-19 22:03:22 +0300994 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000995 @unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run')
996 def test_make_zipfile(self):
997 # creating something to tar
998 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200999 write_file((tmpdir, 'file1'), 'xxx')
1000 write_file((tmpdir, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +00001001
1002 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001003 # force shutil to create the directory
1004 os.rmdir(tmpdir2)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001005 base_name = os.path.join(tmpdir2, 'archive')
1006 _make_zipfile(base_name, tmpdir)
1007
1008 # check if the compressed tarball was created
1009 tarball = base_name + '.zip'
Éric Araujo1c505492010-11-06 02:12:51 +00001010 self.assertTrue(os.path.exists(tarball))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001011
1012
1013 def test_make_archive(self):
1014 tmpdir = self.mkdtemp()
1015 base_name = os.path.join(tmpdir, 'archive')
1016 self.assertRaises(ValueError, make_archive, base_name, 'xxx')
1017
Ezio Melotti975077a2011-05-19 22:03:22 +03001018 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001019 def test_make_archive_owner_group(self):
1020 # testing make_archive with owner and group, with various combinations
1021 # this works even if there's not gid/uid support
1022 if UID_GID_SUPPORT:
1023 group = grp.getgrgid(0)[0]
1024 owner = pwd.getpwuid(0)[0]
1025 else:
1026 group = owner = 'root'
1027
1028 base_dir, root_dir, base_name = self._create_files()
1029 base_name = os.path.join(self.mkdtemp() , 'archive')
1030 res = make_archive(base_name, 'zip', root_dir, base_dir, owner=owner,
1031 group=group)
1032 self.assertTrue(os.path.exists(res))
1033
1034 res = make_archive(base_name, 'zip', root_dir, base_dir)
1035 self.assertTrue(os.path.exists(res))
1036
1037 res = make_archive(base_name, 'tar', root_dir, base_dir,
1038 owner=owner, group=group)
1039 self.assertTrue(os.path.exists(res))
1040
1041 res = make_archive(base_name, 'tar', root_dir, base_dir,
1042 owner='kjhkjhkjg', group='oihohoh')
1043 self.assertTrue(os.path.exists(res))
1044
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001045
Ezio Melotti975077a2011-05-19 22:03:22 +03001046 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001047 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1048 def test_tarfile_root_owner(self):
1049 tmpdir, tmpdir2, base_name = self._create_files()
1050 old_dir = os.getcwd()
1051 os.chdir(tmpdir)
1052 group = grp.getgrgid(0)[0]
1053 owner = pwd.getpwuid(0)[0]
1054 try:
1055 archive_name = _make_tarball(base_name, 'dist', compress=None,
1056 owner=owner, group=group)
1057 finally:
1058 os.chdir(old_dir)
1059
1060 # check if the compressed tarball was created
1061 self.assertTrue(os.path.exists(archive_name))
1062
1063 # now checks the rights
1064 archive = tarfile.open(archive_name)
1065 try:
1066 for member in archive.getmembers():
Ezio Melottib3aedd42010-11-20 19:04:17 +00001067 self.assertEqual(member.uid, 0)
1068 self.assertEqual(member.gid, 0)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001069 finally:
1070 archive.close()
1071
1072 def test_make_archive_cwd(self):
1073 current_dir = os.getcwd()
1074 def _breaks(*args, **kw):
1075 raise RuntimeError()
1076
1077 register_archive_format('xxx', _breaks, [], 'xxx file')
1078 try:
1079 try:
1080 make_archive('xxx', 'xxx', root_dir=self.mkdtemp())
1081 except Exception:
1082 pass
Ezio Melottib3aedd42010-11-20 19:04:17 +00001083 self.assertEqual(os.getcwd(), current_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001084 finally:
1085 unregister_archive_format('xxx')
1086
1087 def test_register_archive_format(self):
1088
1089 self.assertRaises(TypeError, register_archive_format, 'xxx', 1)
1090 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1091 1)
1092 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1093 [(1, 2), (1, 2, 3)])
1094
1095 register_archive_format('xxx', lambda: x, [(1, 2)], 'xxx file')
1096 formats = [name for name, params in get_archive_formats()]
1097 self.assertIn('xxx', formats)
1098
1099 unregister_archive_format('xxx')
1100 formats = [name for name, params in get_archive_formats()]
1101 self.assertNotIn('xxx', formats)
1102
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001103 def _compare_dirs(self, dir1, dir2):
1104 # check that dir1 and dir2 are equivalent,
1105 # return the diff
1106 diff = []
1107 for root, dirs, files in os.walk(dir1):
1108 for file_ in files:
1109 path = os.path.join(root, file_)
1110 target_path = os.path.join(dir2, os.path.split(path)[-1])
1111 if not os.path.exists(target_path):
1112 diff.append(file_)
1113 return diff
1114
Ezio Melotti975077a2011-05-19 22:03:22 +03001115 @requires_zlib
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001116 def test_unpack_archive(self):
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001117 formats = ['tar', 'gztar', 'zip']
1118 if BZ2_SUPPORTED:
1119 formats.append('bztar')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001120
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001121 for format in formats:
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001122 tmpdir = self.mkdtemp()
1123 base_dir, root_dir, base_name = self._create_files()
1124 tmpdir2 = self.mkdtemp()
1125 filename = make_archive(base_name, format, root_dir, base_dir)
1126
1127 # let's try to unpack it now
1128 unpack_archive(filename, tmpdir2)
1129 diff = self._compare_dirs(tmpdir, tmpdir2)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001130 self.assertEqual(diff, [])
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001131
Nick Coghlanabf202d2011-03-16 13:52:20 -04001132 # and again, this time with the format specified
1133 tmpdir3 = self.mkdtemp()
1134 unpack_archive(filename, tmpdir3, format=format)
1135 diff = self._compare_dirs(tmpdir, tmpdir3)
1136 self.assertEqual(diff, [])
1137 self.assertRaises(shutil.ReadError, unpack_archive, TESTFN)
1138 self.assertRaises(ValueError, unpack_archive, TESTFN, format='xxx')
1139
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001140 def test_unpack_registery(self):
1141
1142 formats = get_unpack_formats()
1143
1144 def _boo(filename, extract_dir, extra):
Ezio Melottib3aedd42010-11-20 19:04:17 +00001145 self.assertEqual(extra, 1)
1146 self.assertEqual(filename, 'stuff.boo')
1147 self.assertEqual(extract_dir, 'xx')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001148
1149 register_unpack_format('Boo', ['.boo', '.b2'], _boo, [('extra', 1)])
1150 unpack_archive('stuff.boo', 'xx')
1151
1152 # trying to register a .boo unpacker again
1153 self.assertRaises(RegistryError, register_unpack_format, 'Boo2',
1154 ['.boo'], _boo)
1155
1156 # should work now
1157 unregister_unpack_format('Boo')
1158 register_unpack_format('Boo2', ['.boo'], _boo)
1159 self.assertIn(('Boo2', ['.boo'], ''), get_unpack_formats())
1160 self.assertNotIn(('Boo', ['.boo'], ''), get_unpack_formats())
1161
1162 # let's leave a clean state
1163 unregister_unpack_format('Boo2')
Ezio Melottib3aedd42010-11-20 19:04:17 +00001164 self.assertEqual(get_unpack_formats(), formats)
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001165
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001166 @unittest.skipUnless(hasattr(shutil, 'disk_usage'),
1167 "disk_usage not available on this platform")
1168 def test_disk_usage(self):
1169 usage = shutil.disk_usage(os.getcwd())
Éric Araujo2ee61882011-07-02 16:45:45 +02001170 self.assertGreater(usage.total, 0)
1171 self.assertGreater(usage.used, 0)
1172 self.assertGreaterEqual(usage.free, 0)
1173 self.assertGreaterEqual(usage.total, usage.used)
1174 self.assertGreater(usage.total, usage.free)
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001175
Sandro Tosid902a142011-08-22 23:28:27 +02001176 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1177 @unittest.skipUnless(hasattr(os, 'chown'), 'requires os.chown')
1178 def test_chown(self):
1179
1180 # cleaned-up automatically by TestShutil.tearDown method
1181 dirname = self.mkdtemp()
1182 filename = tempfile.mktemp(dir=dirname)
1183 write_file(filename, 'testing chown function')
1184
1185 with self.assertRaises(ValueError):
1186 shutil.chown(filename)
1187
1188 with self.assertRaises(LookupError):
1189 shutil.chown(filename, user='non-exising username')
1190
1191 with self.assertRaises(LookupError):
1192 shutil.chown(filename, group='non-exising groupname')
1193
1194 with self.assertRaises(TypeError):
1195 shutil.chown(filename, b'spam')
1196
1197 with self.assertRaises(TypeError):
1198 shutil.chown(filename, 3.14)
1199
1200 uid = os.getuid()
1201 gid = os.getgid()
1202
1203 def check_chown(path, uid=None, gid=None):
1204 s = os.stat(filename)
1205 if uid is not None:
1206 self.assertEqual(uid, s.st_uid)
1207 if gid is not None:
1208 self.assertEqual(gid, s.st_gid)
1209
1210 shutil.chown(filename, uid, gid)
1211 check_chown(filename, uid, gid)
1212 shutil.chown(filename, uid)
1213 check_chown(filename, uid)
1214 shutil.chown(filename, user=uid)
1215 check_chown(filename, uid)
1216 shutil.chown(filename, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001217 check_chown(filename, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001218
1219 shutil.chown(dirname, uid, gid)
1220 check_chown(dirname, uid, gid)
1221 shutil.chown(dirname, uid)
1222 check_chown(dirname, uid)
1223 shutil.chown(dirname, user=uid)
1224 check_chown(dirname, uid)
1225 shutil.chown(dirname, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001226 check_chown(dirname, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001227
1228 user = pwd.getpwuid(uid)[0]
1229 group = grp.getgrgid(gid)[0]
1230 shutil.chown(filename, user, group)
1231 check_chown(filename, uid, gid)
1232 shutil.chown(dirname, user, group)
1233 check_chown(dirname, uid, gid)
1234
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001235 def test_copy_return_value(self):
1236 # copy and copy2 both return their destination path.
1237 for fn in (shutil.copy, shutil.copy2):
1238 src_dir = self.mkdtemp()
1239 dst_dir = self.mkdtemp()
1240 src = os.path.join(src_dir, 'foo')
1241 write_file(src, 'foo')
1242 rv = fn(src, dst_dir)
1243 self.assertEqual(rv, os.path.join(dst_dir, 'foo'))
1244 rv = fn(src, os.path.join(dst_dir, 'bar'))
1245 self.assertEqual(rv, os.path.join(dst_dir, 'bar'))
1246
1247 def test_copyfile_return_value(self):
1248 # copytree returns its destination path.
1249 src_dir = self.mkdtemp()
1250 dst_dir = self.mkdtemp()
1251 dst_file = os.path.join(dst_dir, 'bar')
1252 src_file = os.path.join(src_dir, 'foo')
1253 write_file(src_file, 'foo')
1254 rv = shutil.copyfile(src_file, dst_file)
1255 self.assertTrue(os.path.exists(rv))
1256 self.assertEqual(read_file(src_file), read_file(dst_file))
1257
1258 def test_copytree_return_value(self):
1259 # copytree returns its destination path.
1260 src_dir = self.mkdtemp()
1261 dst_dir = src_dir + "dest"
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001262 self.addCleanup(shutil.rmtree, dst_dir, True)
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001263 src = os.path.join(src_dir, 'foo')
1264 write_file(src, 'foo')
1265 rv = shutil.copytree(src_dir, dst_dir)
1266 self.assertEqual(['foo'], os.listdir(rv))
1267
Christian Heimes9bd667a2008-01-20 15:14:11 +00001268
Brian Curtinc57a3452012-06-22 16:00:30 -05001269class TestWhich(unittest.TestCase):
1270
1271 def setUp(self):
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001272 self.temp_dir = tempfile.mkdtemp(prefix="Tmp")
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001273 self.addCleanup(shutil.rmtree, self.temp_dir, True)
Brian Curtinc57a3452012-06-22 16:00:30 -05001274 # Give the temp_file an ".exe" suffix for all.
1275 # It's needed on Windows and not harmful on other platforms.
1276 self.temp_file = tempfile.NamedTemporaryFile(dir=self.temp_dir,
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001277 prefix="Tmp",
1278 suffix=".Exe")
Brian Curtinc57a3452012-06-22 16:00:30 -05001279 os.chmod(self.temp_file.name, stat.S_IXUSR)
1280 self.addCleanup(self.temp_file.close)
1281 self.dir, self.file = os.path.split(self.temp_file.name)
1282
1283 def test_basic(self):
1284 # Given an EXE in a directory, it should be returned.
1285 rv = shutil.which(self.file, path=self.dir)
1286 self.assertEqual(rv, self.temp_file.name)
1287
1288 def test_full_path_short_circuit(self):
1289 # When given the fully qualified path to an executable that exists,
1290 # it should be returned.
1291 rv = shutil.which(self.temp_file.name, path=self.temp_dir)
1292 self.assertEqual(self.temp_file.name, rv)
1293
1294 def test_non_matching_mode(self):
1295 # Set the file read-only and ask for writeable files.
1296 os.chmod(self.temp_file.name, stat.S_IREAD)
1297 rv = shutil.which(self.file, path=self.dir, mode=os.W_OK)
1298 self.assertIsNone(rv)
1299
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001300 def test_relative(self):
1301 old_cwd = os.getcwd()
1302 base_dir, tail_dir = os.path.split(self.dir)
1303 os.chdir(base_dir)
1304 try:
1305 rv = shutil.which(self.file, path=tail_dir)
1306 self.assertEqual(rv, os.path.join(tail_dir, self.file))
1307 finally:
1308 os.chdir(old_cwd)
1309
Brian Curtinc57a3452012-06-22 16:00:30 -05001310 def test_nonexistent_file(self):
1311 # Return None when no matching executable file is found on the path.
1312 rv = shutil.which("foo.exe", path=self.dir)
1313 self.assertIsNone(rv)
1314
1315 @unittest.skipUnless(sys.platform == "win32",
1316 "pathext check is Windows-only")
1317 def test_pathext_checking(self):
1318 # Ask for the file without the ".exe" extension, then ensure that
1319 # it gets found properly with the extension.
1320 rv = shutil.which(self.temp_file.name[:-4], path=self.dir)
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001321 self.assertEqual(rv, self.temp_file.name[:-4] + ".exe")
Brian Curtinc57a3452012-06-22 16:00:30 -05001322
1323
Christian Heimesada8c3b2008-03-18 18:26:33 +00001324class TestMove(unittest.TestCase):
1325
1326 def setUp(self):
1327 filename = "foo"
1328 self.src_dir = tempfile.mkdtemp()
1329 self.dst_dir = tempfile.mkdtemp()
1330 self.src_file = os.path.join(self.src_dir, filename)
1331 self.dst_file = os.path.join(self.dst_dir, filename)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001332 with open(self.src_file, "wb") as f:
1333 f.write(b"spam")
1334
1335 def tearDown(self):
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001336 for d in (self.src_dir, self.dst_dir):
Christian Heimesada8c3b2008-03-18 18:26:33 +00001337 try:
1338 if d:
1339 shutil.rmtree(d)
1340 except:
1341 pass
1342
1343 def _check_move_file(self, src, dst, real_dst):
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001344 with open(src, "rb") as f:
1345 contents = f.read()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001346 shutil.move(src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001347 with open(real_dst, "rb") as f:
1348 self.assertEqual(contents, f.read())
Christian Heimesada8c3b2008-03-18 18:26:33 +00001349 self.assertFalse(os.path.exists(src))
1350
1351 def _check_move_dir(self, src, dst, real_dst):
1352 contents = sorted(os.listdir(src))
1353 shutil.move(src, dst)
1354 self.assertEqual(contents, sorted(os.listdir(real_dst)))
1355 self.assertFalse(os.path.exists(src))
1356
1357 def test_move_file(self):
1358 # Move a file to another location on the same filesystem.
1359 self._check_move_file(self.src_file, self.dst_file, self.dst_file)
1360
1361 def test_move_file_to_dir(self):
1362 # Move a file inside an existing dir on the same filesystem.
1363 self._check_move_file(self.src_file, self.dst_dir, self.dst_file)
1364
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001365 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001366 def test_move_file_other_fs(self):
1367 # Move a file to an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001368 self.test_move_file()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001369
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001370 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001371 def test_move_file_to_dir_other_fs(self):
1372 # Move a file to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001373 self.test_move_file_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001374
1375 def test_move_dir(self):
1376 # Move a dir to another location on the same filesystem.
1377 dst_dir = tempfile.mktemp()
1378 try:
1379 self._check_move_dir(self.src_dir, dst_dir, dst_dir)
1380 finally:
1381 try:
1382 shutil.rmtree(dst_dir)
1383 except:
1384 pass
1385
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001386 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001387 def test_move_dir_other_fs(self):
1388 # Move a dir to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001389 self.test_move_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001390
1391 def test_move_dir_to_dir(self):
1392 # Move a dir inside an existing dir on the same filesystem.
1393 self._check_move_dir(self.src_dir, self.dst_dir,
1394 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1395
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001396 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001397 def test_move_dir_to_dir_other_fs(self):
1398 # Move a dir inside an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001399 self.test_move_dir_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001400
1401 def test_existing_file_inside_dest_dir(self):
1402 # A file with the same name inside the destination dir already exists.
1403 with open(self.dst_file, "wb"):
1404 pass
1405 self.assertRaises(shutil.Error, shutil.move, self.src_file, self.dst_dir)
1406
1407 def test_dont_move_dir_in_itself(self):
1408 # Moving a dir inside itself raises an Error.
1409 dst = os.path.join(self.src_dir, "bar")
1410 self.assertRaises(shutil.Error, shutil.move, self.src_dir, dst)
1411
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001412 def test_destinsrc_false_negative(self):
1413 os.mkdir(TESTFN)
1414 try:
1415 for src, dst in [('srcdir', 'srcdir/dest')]:
1416 src = os.path.join(TESTFN, src)
1417 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001418 self.assertTrue(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001419 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001420 'dst (%s) is not in src (%s)' % (dst, src))
1421 finally:
1422 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001423
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001424 def test_destinsrc_false_positive(self):
1425 os.mkdir(TESTFN)
1426 try:
1427 for src, dst in [('srcdir', 'src/dest'), ('srcdir', 'srcdir.new')]:
1428 src = os.path.join(TESTFN, src)
1429 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001430 self.assertFalse(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001431 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001432 'dst (%s) is in src (%s)' % (dst, src))
1433 finally:
1434 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimes9bd667a2008-01-20 15:14:11 +00001435
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +01001436 @support.skip_unless_symlink
1437 @mock_rename
1438 def test_move_file_symlink(self):
1439 dst = os.path.join(self.src_dir, 'bar')
1440 os.symlink(self.src_file, dst)
1441 shutil.move(dst, self.dst_file)
1442 self.assertTrue(os.path.islink(self.dst_file))
1443 self.assertTrue(os.path.samefile(self.src_file, self.dst_file))
1444
1445 @support.skip_unless_symlink
1446 @mock_rename
1447 def test_move_file_symlink_to_dir(self):
1448 filename = "bar"
1449 dst = os.path.join(self.src_dir, filename)
1450 os.symlink(self.src_file, dst)
1451 shutil.move(dst, self.dst_dir)
1452 final_link = os.path.join(self.dst_dir, filename)
1453 self.assertTrue(os.path.islink(final_link))
1454 self.assertTrue(os.path.samefile(self.src_file, final_link))
1455
1456 @support.skip_unless_symlink
1457 @mock_rename
1458 def test_move_dangling_symlink(self):
1459 src = os.path.join(self.src_dir, 'baz')
1460 dst = os.path.join(self.src_dir, 'bar')
1461 os.symlink(src, dst)
1462 dst_link = os.path.join(self.dst_dir, 'quux')
1463 shutil.move(dst, dst_link)
1464 self.assertTrue(os.path.islink(dst_link))
1465 self.assertEqual(os.path.realpath(src), os.path.realpath(dst_link))
1466
1467 @support.skip_unless_symlink
1468 @mock_rename
1469 def test_move_dir_symlink(self):
1470 src = os.path.join(self.src_dir, 'baz')
1471 dst = os.path.join(self.src_dir, 'bar')
1472 os.mkdir(src)
1473 os.symlink(src, dst)
1474 dst_link = os.path.join(self.dst_dir, 'quux')
1475 shutil.move(dst, dst_link)
1476 self.assertTrue(os.path.islink(dst_link))
1477 self.assertTrue(os.path.samefile(src, dst_link))
1478
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001479 def test_move_return_value(self):
1480 rv = shutil.move(self.src_file, self.dst_dir)
1481 self.assertEqual(rv,
1482 os.path.join(self.dst_dir, os.path.basename(self.src_file)))
1483
1484 def test_move_as_rename_return_value(self):
1485 rv = shutil.move(self.src_file, os.path.join(self.dst_dir, 'bar'))
1486 self.assertEqual(rv, os.path.join(self.dst_dir, 'bar'))
1487
Tarek Ziadé5340db32010-04-19 22:30:51 +00001488
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001489class TestCopyFile(unittest.TestCase):
1490
1491 _delete = False
1492
1493 class Faux(object):
1494 _entered = False
1495 _exited_with = None
1496 _raised = False
1497 def __init__(self, raise_in_exit=False, suppress_at_exit=True):
1498 self._raise_in_exit = raise_in_exit
1499 self._suppress_at_exit = suppress_at_exit
1500 def read(self, *args):
1501 return ''
1502 def __enter__(self):
1503 self._entered = True
1504 def __exit__(self, exc_type, exc_val, exc_tb):
1505 self._exited_with = exc_type, exc_val, exc_tb
1506 if self._raise_in_exit:
1507 self._raised = True
1508 raise IOError("Cannot close")
1509 return self._suppress_at_exit
1510
1511 def tearDown(self):
1512 if self._delete:
1513 del shutil.open
1514
1515 def _set_shutil_open(self, func):
1516 shutil.open = func
1517 self._delete = True
1518
1519 def test_w_source_open_fails(self):
1520 def _open(filename, mode='r'):
1521 if filename == 'srcfile':
1522 raise IOError('Cannot open "srcfile"')
1523 assert 0 # shouldn't reach here.
1524
1525 self._set_shutil_open(_open)
1526
1527 self.assertRaises(IOError, shutil.copyfile, 'srcfile', 'destfile')
1528
1529 def test_w_dest_open_fails(self):
1530
1531 srcfile = self.Faux()
1532
1533 def _open(filename, mode='r'):
1534 if filename == 'srcfile':
1535 return srcfile
1536 if filename == 'destfile':
1537 raise IOError('Cannot open "destfile"')
1538 assert 0 # shouldn't reach here.
1539
1540 self._set_shutil_open(_open)
1541
1542 shutil.copyfile('srcfile', 'destfile')
1543 self.assertTrue(srcfile._entered)
1544 self.assertTrue(srcfile._exited_with[0] is IOError)
1545 self.assertEqual(srcfile._exited_with[1].args,
1546 ('Cannot open "destfile"',))
1547
1548 def test_w_dest_close_fails(self):
1549
1550 srcfile = self.Faux()
1551 destfile = self.Faux(True)
1552
1553 def _open(filename, mode='r'):
1554 if filename == 'srcfile':
1555 return srcfile
1556 if filename == 'destfile':
1557 return destfile
1558 assert 0 # shouldn't reach here.
1559
1560 self._set_shutil_open(_open)
1561
1562 shutil.copyfile('srcfile', 'destfile')
1563 self.assertTrue(srcfile._entered)
1564 self.assertTrue(destfile._entered)
1565 self.assertTrue(destfile._raised)
1566 self.assertTrue(srcfile._exited_with[0] is IOError)
1567 self.assertEqual(srcfile._exited_with[1].args,
1568 ('Cannot close',))
1569
1570 def test_w_source_close_fails(self):
1571
1572 srcfile = self.Faux(True)
1573 destfile = self.Faux()
1574
1575 def _open(filename, mode='r'):
1576 if filename == 'srcfile':
1577 return srcfile
1578 if filename == 'destfile':
1579 return destfile
1580 assert 0 # shouldn't reach here.
1581
1582 self._set_shutil_open(_open)
1583
1584 self.assertRaises(IOError,
1585 shutil.copyfile, 'srcfile', 'destfile')
1586 self.assertTrue(srcfile._entered)
1587 self.assertTrue(destfile._entered)
1588 self.assertFalse(destfile._raised)
1589 self.assertTrue(srcfile._exited_with[0] is None)
1590 self.assertTrue(srcfile._raised)
1591
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001592 def test_move_dir_caseinsensitive(self):
1593 # Renames a folder to the same name
1594 # but a different case.
1595
1596 self.src_dir = tempfile.mkdtemp()
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001597 self.addCleanup(shutil.rmtree, self.src_dir, True)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001598 dst_dir = os.path.join(
1599 os.path.dirname(self.src_dir),
1600 os.path.basename(self.src_dir).upper())
1601 self.assertNotEqual(self.src_dir, dst_dir)
1602
1603 try:
1604 shutil.move(self.src_dir, dst_dir)
1605 self.assertTrue(os.path.isdir(dst_dir))
1606 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +02001607 os.rmdir(dst_dir)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001608
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001609class TermsizeTests(unittest.TestCase):
1610 def test_does_not_crash(self):
1611 """Check if get_terminal_size() returns a meaningful value.
1612
1613 There's no easy portable way to actually check the size of the
1614 terminal, so let's check if it returns something sensible instead.
1615 """
1616 size = shutil.get_terminal_size()
Antoine Pitroucfade362012-02-08 23:48:59 +01001617 self.assertGreaterEqual(size.columns, 0)
1618 self.assertGreaterEqual(size.lines, 0)
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001619
1620 def test_os_environ_first(self):
1621 "Check if environment variables have precedence"
1622
1623 with support.EnvironmentVarGuard() as env:
1624 env['COLUMNS'] = '777'
1625 size = shutil.get_terminal_size()
1626 self.assertEqual(size.columns, 777)
1627
1628 with support.EnvironmentVarGuard() as env:
1629 env['LINES'] = '888'
1630 size = shutil.get_terminal_size()
1631 self.assertEqual(size.lines, 888)
1632
1633 @unittest.skipUnless(os.isatty(sys.__stdout__.fileno()), "not on tty")
1634 def test_stty_match(self):
1635 """Check if stty returns the same results ignoring env
1636
1637 This test will fail if stdin and stdout are connected to
1638 different terminals with different sizes. Nevertheless, such
1639 situations should be pretty rare.
1640 """
1641 try:
1642 size = subprocess.check_output(['stty', 'size']).decode().split()
1643 except (FileNotFoundError, subprocess.CalledProcessError):
1644 self.skipTest("stty invocation failed")
1645 expected = (int(size[1]), int(size[0])) # reversed order
1646
1647 with support.EnvironmentVarGuard() as env:
1648 del env['LINES']
1649 del env['COLUMNS']
1650 actual = shutil.get_terminal_size()
1651
1652 self.assertEqual(expected, actual)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001653
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001654
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001655def test_main():
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001656 support.run_unittest(TestShutil, TestMove, TestCopyFile,
Brian Curtinc57a3452012-06-22 16:00:30 -05001657 TermsizeTests, TestWhich)
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001658
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001659if __name__ == '__main__':
Walter Dörwald21d3a322003-05-01 17:45:56 +00001660 test_main()