blob: f6e5a9c41d4f17c6b098fa5543511c97e6735c8c [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
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001288 def test_absolute_cmd(self):
Brian Curtinc57a3452012-06-22 16:00:30 -05001289 # 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)
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001292 self.assertEqual(rv, self.temp_file.name)
1293
1294 def test_relative_cmd(self):
1295 # When given the relative path with a directory part to an executable
1296 # that exists, it should be returned.
1297 base_dir, tail_dir = os.path.split(self.dir)
1298 relpath = os.path.join(tail_dir, self.file)
1299 with support.temp_cwd(path=base_dir):
1300 rv = shutil.which(relpath, path=self.temp_dir)
1301 self.assertEqual(rv, relpath)
1302 # But it shouldn't be searched in PATH directories (issue #16957).
1303 with support.temp_cwd(path=self.dir):
1304 rv = shutil.which(relpath, path=base_dir)
1305 self.assertIsNone(rv)
1306
1307 def test_cwd(self):
1308 # Issue #16957
1309 base_dir = os.path.dirname(self.dir)
1310 with support.temp_cwd(path=self.dir):
1311 rv = shutil.which(self.file, path=base_dir)
1312 if sys.platform == "win32":
1313 # Windows: current directory implicitly on PATH
1314 self.assertEqual(rv, os.path.join(os.curdir, self.file))
1315 else:
1316 # Other platforms: shouldn't match in the current directory.
1317 self.assertIsNone(rv)
Brian Curtinc57a3452012-06-22 16:00:30 -05001318
1319 def test_non_matching_mode(self):
1320 # Set the file read-only and ask for writeable files.
1321 os.chmod(self.temp_file.name, stat.S_IREAD)
1322 rv = shutil.which(self.file, path=self.dir, mode=os.W_OK)
1323 self.assertIsNone(rv)
1324
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001325 def test_relative_path(self):
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001326 base_dir, tail_dir = os.path.split(self.dir)
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001327 with support.temp_cwd(path=base_dir):
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001328 rv = shutil.which(self.file, path=tail_dir)
1329 self.assertEqual(rv, os.path.join(tail_dir, self.file))
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001330
Brian Curtinc57a3452012-06-22 16:00:30 -05001331 def test_nonexistent_file(self):
1332 # Return None when no matching executable file is found on the path.
1333 rv = shutil.which("foo.exe", path=self.dir)
1334 self.assertIsNone(rv)
1335
1336 @unittest.skipUnless(sys.platform == "win32",
1337 "pathext check is Windows-only")
1338 def test_pathext_checking(self):
1339 # Ask for the file without the ".exe" extension, then ensure that
1340 # it gets found properly with the extension.
1341 rv = shutil.which(self.temp_file.name[:-4], path=self.dir)
Serhiy Storchaka80c88f42013-01-22 10:31:36 +02001342 self.assertEqual(rv, self.temp_file.name[:-4] + ".EXE")
Brian Curtinc57a3452012-06-22 16:00:30 -05001343
1344
Christian Heimesada8c3b2008-03-18 18:26:33 +00001345class TestMove(unittest.TestCase):
1346
1347 def setUp(self):
1348 filename = "foo"
1349 self.src_dir = tempfile.mkdtemp()
1350 self.dst_dir = tempfile.mkdtemp()
1351 self.src_file = os.path.join(self.src_dir, filename)
1352 self.dst_file = os.path.join(self.dst_dir, filename)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001353 with open(self.src_file, "wb") as f:
1354 f.write(b"spam")
1355
1356 def tearDown(self):
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001357 for d in (self.src_dir, self.dst_dir):
Christian Heimesada8c3b2008-03-18 18:26:33 +00001358 try:
1359 if d:
1360 shutil.rmtree(d)
1361 except:
1362 pass
1363
1364 def _check_move_file(self, src, dst, real_dst):
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001365 with open(src, "rb") as f:
1366 contents = f.read()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001367 shutil.move(src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001368 with open(real_dst, "rb") as f:
1369 self.assertEqual(contents, f.read())
Christian Heimesada8c3b2008-03-18 18:26:33 +00001370 self.assertFalse(os.path.exists(src))
1371
1372 def _check_move_dir(self, src, dst, real_dst):
1373 contents = sorted(os.listdir(src))
1374 shutil.move(src, dst)
1375 self.assertEqual(contents, sorted(os.listdir(real_dst)))
1376 self.assertFalse(os.path.exists(src))
1377
1378 def test_move_file(self):
1379 # Move a file to another location on the same filesystem.
1380 self._check_move_file(self.src_file, self.dst_file, self.dst_file)
1381
1382 def test_move_file_to_dir(self):
1383 # Move a file inside an existing dir on the same filesystem.
1384 self._check_move_file(self.src_file, self.dst_dir, self.dst_file)
1385
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001386 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001387 def test_move_file_other_fs(self):
1388 # Move a file to an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001389 self.test_move_file()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001390
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001391 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001392 def test_move_file_to_dir_other_fs(self):
1393 # Move a file to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001394 self.test_move_file_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001395
1396 def test_move_dir(self):
1397 # Move a dir to another location on the same filesystem.
1398 dst_dir = tempfile.mktemp()
1399 try:
1400 self._check_move_dir(self.src_dir, dst_dir, dst_dir)
1401 finally:
1402 try:
1403 shutil.rmtree(dst_dir)
1404 except:
1405 pass
1406
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001407 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001408 def test_move_dir_other_fs(self):
1409 # Move a dir to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001410 self.test_move_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001411
1412 def test_move_dir_to_dir(self):
1413 # Move a dir inside an existing dir on the same filesystem.
1414 self._check_move_dir(self.src_dir, self.dst_dir,
1415 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1416
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001417 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001418 def test_move_dir_to_dir_other_fs(self):
1419 # Move a dir inside an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001420 self.test_move_dir_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001421
1422 def test_existing_file_inside_dest_dir(self):
1423 # A file with the same name inside the destination dir already exists.
1424 with open(self.dst_file, "wb"):
1425 pass
1426 self.assertRaises(shutil.Error, shutil.move, self.src_file, self.dst_dir)
1427
1428 def test_dont_move_dir_in_itself(self):
1429 # Moving a dir inside itself raises an Error.
1430 dst = os.path.join(self.src_dir, "bar")
1431 self.assertRaises(shutil.Error, shutil.move, self.src_dir, dst)
1432
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001433 def test_destinsrc_false_negative(self):
1434 os.mkdir(TESTFN)
1435 try:
1436 for src, dst in [('srcdir', 'srcdir/dest')]:
1437 src = os.path.join(TESTFN, src)
1438 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001439 self.assertTrue(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001440 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001441 'dst (%s) is not in src (%s)' % (dst, src))
1442 finally:
1443 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001444
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001445 def test_destinsrc_false_positive(self):
1446 os.mkdir(TESTFN)
1447 try:
1448 for src, dst in [('srcdir', 'src/dest'), ('srcdir', 'srcdir.new')]:
1449 src = os.path.join(TESTFN, src)
1450 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001451 self.assertFalse(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001452 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001453 'dst (%s) is in src (%s)' % (dst, src))
1454 finally:
1455 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimes9bd667a2008-01-20 15:14:11 +00001456
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +01001457 @support.skip_unless_symlink
1458 @mock_rename
1459 def test_move_file_symlink(self):
1460 dst = os.path.join(self.src_dir, 'bar')
1461 os.symlink(self.src_file, dst)
1462 shutil.move(dst, self.dst_file)
1463 self.assertTrue(os.path.islink(self.dst_file))
1464 self.assertTrue(os.path.samefile(self.src_file, self.dst_file))
1465
1466 @support.skip_unless_symlink
1467 @mock_rename
1468 def test_move_file_symlink_to_dir(self):
1469 filename = "bar"
1470 dst = os.path.join(self.src_dir, filename)
1471 os.symlink(self.src_file, dst)
1472 shutil.move(dst, self.dst_dir)
1473 final_link = os.path.join(self.dst_dir, filename)
1474 self.assertTrue(os.path.islink(final_link))
1475 self.assertTrue(os.path.samefile(self.src_file, final_link))
1476
1477 @support.skip_unless_symlink
1478 @mock_rename
1479 def test_move_dangling_symlink(self):
1480 src = os.path.join(self.src_dir, 'baz')
1481 dst = os.path.join(self.src_dir, 'bar')
1482 os.symlink(src, dst)
1483 dst_link = os.path.join(self.dst_dir, 'quux')
1484 shutil.move(dst, dst_link)
1485 self.assertTrue(os.path.islink(dst_link))
1486 self.assertEqual(os.path.realpath(src), os.path.realpath(dst_link))
1487
1488 @support.skip_unless_symlink
1489 @mock_rename
1490 def test_move_dir_symlink(self):
1491 src = os.path.join(self.src_dir, 'baz')
1492 dst = os.path.join(self.src_dir, 'bar')
1493 os.mkdir(src)
1494 os.symlink(src, dst)
1495 dst_link = os.path.join(self.dst_dir, 'quux')
1496 shutil.move(dst, dst_link)
1497 self.assertTrue(os.path.islink(dst_link))
1498 self.assertTrue(os.path.samefile(src, dst_link))
1499
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001500 def test_move_return_value(self):
1501 rv = shutil.move(self.src_file, self.dst_dir)
1502 self.assertEqual(rv,
1503 os.path.join(self.dst_dir, os.path.basename(self.src_file)))
1504
1505 def test_move_as_rename_return_value(self):
1506 rv = shutil.move(self.src_file, os.path.join(self.dst_dir, 'bar'))
1507 self.assertEqual(rv, os.path.join(self.dst_dir, 'bar'))
1508
Tarek Ziadé5340db32010-04-19 22:30:51 +00001509
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001510class TestCopyFile(unittest.TestCase):
1511
1512 _delete = False
1513
1514 class Faux(object):
1515 _entered = False
1516 _exited_with = None
1517 _raised = False
1518 def __init__(self, raise_in_exit=False, suppress_at_exit=True):
1519 self._raise_in_exit = raise_in_exit
1520 self._suppress_at_exit = suppress_at_exit
1521 def read(self, *args):
1522 return ''
1523 def __enter__(self):
1524 self._entered = True
1525 def __exit__(self, exc_type, exc_val, exc_tb):
1526 self._exited_with = exc_type, exc_val, exc_tb
1527 if self._raise_in_exit:
1528 self._raised = True
1529 raise IOError("Cannot close")
1530 return self._suppress_at_exit
1531
1532 def tearDown(self):
1533 if self._delete:
1534 del shutil.open
1535
1536 def _set_shutil_open(self, func):
1537 shutil.open = func
1538 self._delete = True
1539
1540 def test_w_source_open_fails(self):
1541 def _open(filename, mode='r'):
1542 if filename == 'srcfile':
1543 raise IOError('Cannot open "srcfile"')
1544 assert 0 # shouldn't reach here.
1545
1546 self._set_shutil_open(_open)
1547
1548 self.assertRaises(IOError, shutil.copyfile, 'srcfile', 'destfile')
1549
1550 def test_w_dest_open_fails(self):
1551
1552 srcfile = self.Faux()
1553
1554 def _open(filename, mode='r'):
1555 if filename == 'srcfile':
1556 return srcfile
1557 if filename == 'destfile':
1558 raise IOError('Cannot open "destfile"')
1559 assert 0 # shouldn't reach here.
1560
1561 self._set_shutil_open(_open)
1562
1563 shutil.copyfile('srcfile', 'destfile')
1564 self.assertTrue(srcfile._entered)
1565 self.assertTrue(srcfile._exited_with[0] is IOError)
1566 self.assertEqual(srcfile._exited_with[1].args,
1567 ('Cannot open "destfile"',))
1568
1569 def test_w_dest_close_fails(self):
1570
1571 srcfile = self.Faux()
1572 destfile = self.Faux(True)
1573
1574 def _open(filename, mode='r'):
1575 if filename == 'srcfile':
1576 return srcfile
1577 if filename == 'destfile':
1578 return destfile
1579 assert 0 # shouldn't reach here.
1580
1581 self._set_shutil_open(_open)
1582
1583 shutil.copyfile('srcfile', 'destfile')
1584 self.assertTrue(srcfile._entered)
1585 self.assertTrue(destfile._entered)
1586 self.assertTrue(destfile._raised)
1587 self.assertTrue(srcfile._exited_with[0] is IOError)
1588 self.assertEqual(srcfile._exited_with[1].args,
1589 ('Cannot close',))
1590
1591 def test_w_source_close_fails(self):
1592
1593 srcfile = self.Faux(True)
1594 destfile = self.Faux()
1595
1596 def _open(filename, mode='r'):
1597 if filename == 'srcfile':
1598 return srcfile
1599 if filename == 'destfile':
1600 return destfile
1601 assert 0 # shouldn't reach here.
1602
1603 self._set_shutil_open(_open)
1604
1605 self.assertRaises(IOError,
1606 shutil.copyfile, 'srcfile', 'destfile')
1607 self.assertTrue(srcfile._entered)
1608 self.assertTrue(destfile._entered)
1609 self.assertFalse(destfile._raised)
1610 self.assertTrue(srcfile._exited_with[0] is None)
1611 self.assertTrue(srcfile._raised)
1612
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001613 def test_move_dir_caseinsensitive(self):
1614 # Renames a folder to the same name
1615 # but a different case.
1616
1617 self.src_dir = tempfile.mkdtemp()
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001618 self.addCleanup(shutil.rmtree, self.src_dir, True)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001619 dst_dir = os.path.join(
1620 os.path.dirname(self.src_dir),
1621 os.path.basename(self.src_dir).upper())
1622 self.assertNotEqual(self.src_dir, dst_dir)
1623
1624 try:
1625 shutil.move(self.src_dir, dst_dir)
1626 self.assertTrue(os.path.isdir(dst_dir))
1627 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +02001628 os.rmdir(dst_dir)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001629
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001630class TermsizeTests(unittest.TestCase):
1631 def test_does_not_crash(self):
1632 """Check if get_terminal_size() returns a meaningful value.
1633
1634 There's no easy portable way to actually check the size of the
1635 terminal, so let's check if it returns something sensible instead.
1636 """
1637 size = shutil.get_terminal_size()
Antoine Pitroucfade362012-02-08 23:48:59 +01001638 self.assertGreaterEqual(size.columns, 0)
1639 self.assertGreaterEqual(size.lines, 0)
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001640
1641 def test_os_environ_first(self):
1642 "Check if environment variables have precedence"
1643
1644 with support.EnvironmentVarGuard() as env:
1645 env['COLUMNS'] = '777'
1646 size = shutil.get_terminal_size()
1647 self.assertEqual(size.columns, 777)
1648
1649 with support.EnvironmentVarGuard() as env:
1650 env['LINES'] = '888'
1651 size = shutil.get_terminal_size()
1652 self.assertEqual(size.lines, 888)
1653
1654 @unittest.skipUnless(os.isatty(sys.__stdout__.fileno()), "not on tty")
1655 def test_stty_match(self):
1656 """Check if stty returns the same results ignoring env
1657
1658 This test will fail if stdin and stdout are connected to
1659 different terminals with different sizes. Nevertheless, such
1660 situations should be pretty rare.
1661 """
1662 try:
1663 size = subprocess.check_output(['stty', 'size']).decode().split()
1664 except (FileNotFoundError, subprocess.CalledProcessError):
1665 self.skipTest("stty invocation failed")
1666 expected = (int(size[1]), int(size[0])) # reversed order
1667
1668 with support.EnvironmentVarGuard() as env:
1669 del env['LINES']
1670 del env['COLUMNS']
1671 actual = shutil.get_terminal_size()
1672
1673 self.assertEqual(expected, actual)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001674
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001675
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001676def test_main():
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001677 support.run_unittest(TestShutil, TestMove, TestCopyFile,
Brian Curtinc57a3452012-06-22 16:00:30 -05001678 TermsizeTests, TestWhich)
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001679
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001680if __name__ == '__main__':
Walter Dörwald21d3a322003-05-01 17:45:56 +00001681 test_main()