blob: 6794a9357459a192b00c9479840e1917500d0dcb [file] [log] [blame]
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001# Copyright (C) 2003 Python Software Foundation
2
3import unittest
4import shutil
5import tempfile
Johannes Gijsbers8e6f2de2004-11-23 09:27:27 +00006import sys
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +00007import stat
Brett Cannon1c3fa182004-06-19 21:11:35 +00008import os
9import os.path
Antoine Pitrouc041ab62012-01-02 19:18:02 +010010import errno
Nick Coghlan8ed3cf32011-03-16 14:05:35 -040011import functools
Antoine Pitroubcf2b592012-02-08 23:28:36 +010012import subprocess
Benjamin Petersonee8712c2008-05-20 21:35:26 +000013from test import support
14from test.support import TESTFN
Tarek Ziadé396fad72010-02-23 05:30:31 +000015from os.path import splitdrive
16from distutils.spawn import find_executable, spawn
17from shutil import (_make_tarball, _make_zipfile, make_archive,
18 register_archive_format, unregister_archive_format,
Tarek Ziadé6ac91722010-04-28 17:51:36 +000019 get_archive_formats, Error, unpack_archive,
20 register_unpack_format, RegistryError,
Hynek Schlawack26fe37d2012-07-19 21:41:02 +020021 unregister_unpack_format, get_unpack_formats)
Tarek Ziadé396fad72010-02-23 05:30:31 +000022import tarfile
23import warnings
24
25from test import support
Ezio Melotti975077a2011-05-19 22:03:22 +030026from test.support import TESTFN, check_warnings, captured_stdout, requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +000027
Tarek Ziadéffa155a2010-04-29 13:34:35 +000028try:
29 import bz2
30 BZ2_SUPPORTED = True
31except ImportError:
32 BZ2_SUPPORTED = False
33
Antoine Pitrou7fff0962009-05-01 21:09:44 +000034TESTFN2 = TESTFN + "2"
Barry Warsaw7fc2cca2003-01-24 17:34:13 +000035
Tarek Ziadé396fad72010-02-23 05:30:31 +000036try:
37 import grp
38 import pwd
39 UID_GID_SUPPORT = True
40except ImportError:
41 UID_GID_SUPPORT = False
42
43try:
Tarek Ziadé396fad72010-02-23 05:30:31 +000044 import zipfile
45 ZIP_SUPPORT = True
46except ImportError:
47 ZIP_SUPPORT = find_executable('zip')
48
Nick Coghlan8ed3cf32011-03-16 14:05:35 -040049def _fake_rename(*args, **kwargs):
50 # Pretend the destination path is on a different filesystem.
Antoine Pitrouc041ab62012-01-02 19:18:02 +010051 raise OSError(getattr(errno, 'EXDEV', 18), "Invalid cross-device link")
Nick Coghlan8ed3cf32011-03-16 14:05:35 -040052
53def mock_rename(func):
54 @functools.wraps(func)
55 def wrap(*args, **kwargs):
56 try:
57 builtin_rename = os.rename
58 os.rename = _fake_rename
59 return func(*args, **kwargs)
60 finally:
61 os.rename = builtin_rename
62 return wrap
63
Éric Araujoa7e33a12011-08-12 19:51:35 +020064def write_file(path, content, binary=False):
65 """Write *content* to a file located at *path*.
66
67 If *path* is a tuple instead of a string, os.path.join will be used to
68 make a path. If *binary* is true, the file will be opened in binary
69 mode.
70 """
71 if isinstance(path, tuple):
72 path = os.path.join(*path)
73 with open(path, 'wb' if binary else 'w') as fp:
74 fp.write(content)
75
76def read_file(path, binary=False):
77 """Return contents from a file located at *path*.
78
79 If *path* is a tuple instead of a string, os.path.join will be used to
80 make a path. If *binary* is true, the file will be opened in binary
81 mode.
82 """
83 if isinstance(path, tuple):
84 path = os.path.join(*path)
85 with open(path, 'rb' if binary else 'r') as fp:
86 return fp.read()
87
88
Barry Warsaw7fc2cca2003-01-24 17:34:13 +000089class TestShutil(unittest.TestCase):
Tarek Ziadé396fad72010-02-23 05:30:31 +000090
91 def setUp(self):
92 super(TestShutil, self).setUp()
93 self.tempdirs = []
94
95 def tearDown(self):
96 super(TestShutil, self).tearDown()
97 while self.tempdirs:
98 d = self.tempdirs.pop()
99 shutil.rmtree(d, os.name in ('nt', 'cygwin'))
100
Tarek Ziadé396fad72010-02-23 05:30:31 +0000101
102 def mkdtemp(self):
103 """Create a temporary directory that will be cleaned up.
104
105 Returns the path of the directory.
106 """
107 d = tempfile.mkdtemp()
108 self.tempdirs.append(d)
109 return d
Tarek Ziadé5340db32010-04-19 22:30:51 +0000110
Hynek Schlawack3b527782012-06-25 13:27:31 +0200111 def test_rmtree_works_on_bytes(self):
112 tmp = self.mkdtemp()
113 victim = os.path.join(tmp, 'killme')
114 os.mkdir(victim)
115 write_file(os.path.join(victim, 'somefile'), 'foo')
116 victim = os.fsencode(victim)
117 self.assertIsInstance(victim, bytes)
118 shutil.rmtree(victim)
119
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200120 @support.skip_unless_symlink
121 def test_rmtree_fails_on_symlink(self):
122 tmp = self.mkdtemp()
123 dir_ = os.path.join(tmp, 'dir')
124 os.mkdir(dir_)
125 link = os.path.join(tmp, 'link')
126 os.symlink(dir_, link)
127 self.assertRaises(OSError, shutil.rmtree, link)
128 self.assertTrue(os.path.exists(dir_))
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100129 self.assertTrue(os.path.lexists(link))
130 errors = []
131 def onerror(*args):
132 errors.append(args)
133 shutil.rmtree(link, onerror=onerror)
134 self.assertEqual(len(errors), 1)
135 self.assertIs(errors[0][0], os.path.islink)
136 self.assertEqual(errors[0][1], link)
137 self.assertIsInstance(errors[0][2][1], OSError)
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200138
139 @support.skip_unless_symlink
140 def test_rmtree_works_on_symlinks(self):
141 tmp = self.mkdtemp()
142 dir1 = os.path.join(tmp, 'dir1')
143 dir2 = os.path.join(dir1, 'dir2')
144 dir3 = os.path.join(tmp, 'dir3')
145 for d in dir1, dir2, dir3:
146 os.mkdir(d)
147 file1 = os.path.join(tmp, 'file1')
148 write_file(file1, 'foo')
149 link1 = os.path.join(dir1, 'link1')
150 os.symlink(dir2, link1)
151 link2 = os.path.join(dir1, 'link2')
152 os.symlink(dir3, link2)
153 link3 = os.path.join(dir1, 'link3')
154 os.symlink(file1, link3)
155 # make sure symlinks are removed but not followed
156 shutil.rmtree(dir1)
157 self.assertFalse(os.path.exists(dir1))
158 self.assertTrue(os.path.exists(dir3))
159 self.assertTrue(os.path.exists(file1))
160
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000161 def test_rmtree_errors(self):
162 # filename is guaranteed not to exist
163 filename = tempfile.mktemp()
Hynek Schlawackb5501102012-12-10 09:11:25 +0100164 self.assertRaises(FileNotFoundError, shutil.rmtree, filename)
165 # test that ignore_errors option is honored
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100166 shutil.rmtree(filename, ignore_errors=True)
167
168 # existing file
169 tmpdir = self.mkdtemp()
Hynek Schlawackb5501102012-12-10 09:11:25 +0100170 write_file((tmpdir, "tstfile"), "")
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100171 filename = os.path.join(tmpdir, "tstfile")
Hynek Schlawackb5501102012-12-10 09:11:25 +0100172 with self.assertRaises(NotADirectoryError) as cm:
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100173 shutil.rmtree(filename)
Hynek Schlawack87f9b462012-12-10 16:29:57 +0100174 # The reason for this rather odd construct is that Windows sprinkles
175 # a \*.* at the end of file names. But only sometimes on some buildbots
176 possible_args = [filename, os.path.join(filename, '*.*')]
177 self.assertIn(cm.exception.filename, possible_args)
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100178 self.assertTrue(os.path.exists(filename))
Hynek Schlawackb5501102012-12-10 09:11:25 +0100179 # test that ignore_errors option is honored
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100180 shutil.rmtree(filename, ignore_errors=True)
181 self.assertTrue(os.path.exists(filename))
182 errors = []
183 def onerror(*args):
184 errors.append(args)
185 shutil.rmtree(filename, onerror=onerror)
186 self.assertEqual(len(errors), 2)
187 self.assertIs(errors[0][0], os.listdir)
188 self.assertEqual(errors[0][1], filename)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100189 self.assertIsInstance(errors[0][2][1], NotADirectoryError)
Hynek Schlawack87f9b462012-12-10 16:29:57 +0100190 self.assertIn(errors[0][2][1].filename, possible_args)
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100191 self.assertIs(errors[1][0], os.rmdir)
192 self.assertEqual(errors[1][1], filename)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100193 self.assertIsInstance(errors[1][2][1], NotADirectoryError)
Hynek Schlawack87f9b462012-12-10 16:29:57 +0100194 self.assertIn(errors[1][2][1].filename, possible_args)
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000195
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000196
Johannes Gijsbersb8b09d02004-12-06 20:50:15 +0000197 # See bug #1071513 for why we don't run this on cygwin
198 # and bug #1076467 for why we don't run this as root.
199 if (hasattr(os, 'chmod') and sys.platform[:6] != 'cygwin'
Johannes Gijsbers6b220b02004-12-12 15:52:57 +0000200 and not (hasattr(os, 'geteuid') and os.geteuid() == 0)):
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000201 def test_on_error(self):
202 self.errorState = 0
203 os.mkdir(TESTFN)
Antoine Pitrou2f8a75c2012-06-23 21:28:15 +0200204 self.addCleanup(shutil.rmtree, TESTFN)
205
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200206 self.child_file_path = os.path.join(TESTFN, 'a')
207 self.child_dir_path = os.path.join(TESTFN, 'b')
208 support.create_empty_file(self.child_file_path)
209 os.mkdir(self.child_dir_path)
Tim Peters4590c002004-11-01 02:40:52 +0000210 old_dir_mode = os.stat(TESTFN).st_mode
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200211 old_child_file_mode = os.stat(self.child_file_path).st_mode
212 old_child_dir_mode = os.stat(self.child_dir_path).st_mode
Tim Peters4590c002004-11-01 02:40:52 +0000213 # Make unwritable.
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200214 new_mode = stat.S_IREAD|stat.S_IEXEC
215 os.chmod(self.child_file_path, new_mode)
216 os.chmod(self.child_dir_path, new_mode)
217 os.chmod(TESTFN, new_mode)
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000218
Antoine Pitrou2f8a75c2012-06-23 21:28:15 +0200219 self.addCleanup(os.chmod, TESTFN, old_dir_mode)
220 self.addCleanup(os.chmod, self.child_file_path, old_child_file_mode)
221 self.addCleanup(os.chmod, self.child_dir_path, old_child_dir_mode)
222
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000223 shutil.rmtree(TESTFN, onerror=self.check_args_to_onerror)
Johannes Gijsbers8e6f2de2004-11-23 09:27:27 +0000224 # Test whether onerror has actually been called.
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200225 self.assertEqual(self.errorState, 3,
226 "Expected call to onerror function did not "
227 "happen.")
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000228
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000229 def check_args_to_onerror(self, func, arg, exc):
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000230 # test_rmtree_errors deliberately runs rmtree
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200231 # on a directory that is chmod 500, which will fail.
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000232 # This function is run when shutil.rmtree fails.
233 # 99.9% of the time it initially fails to remove
234 # a file in the directory, so the first time through
235 # func is os.remove.
236 # However, some Linux machines running ZFS on
237 # FUSE experienced a failure earlier in the process
238 # at os.listdir. The first failure may legally
239 # be either.
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200240 if self.errorState < 2:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200241 if func is os.unlink:
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200242 self.assertEqual(arg, self.child_file_path)
243 elif func is os.rmdir:
244 self.assertEqual(arg, self.child_dir_path)
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000245 else:
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200246 self.assertIs(func, os.listdir)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200247 self.assertIn(arg, [TESTFN, self.child_dir_path])
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000248 self.assertTrue(issubclass(exc[0], OSError))
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200249 self.errorState += 1
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000250 else:
251 self.assertEqual(func, os.rmdir)
252 self.assertEqual(arg, TESTFN)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000253 self.assertTrue(issubclass(exc[0], OSError))
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200254 self.errorState = 3
255
256 def test_rmtree_does_not_choke_on_failing_lstat(self):
257 try:
258 orig_lstat = os.lstat
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200259 def raiser(fn, *args, **kwargs):
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200260 if fn != TESTFN:
261 raise OSError()
262 else:
263 return orig_lstat(fn)
264 os.lstat = raiser
265
266 os.mkdir(TESTFN)
267 write_file((TESTFN, 'foo'), 'foo')
268 shutil.rmtree(TESTFN)
269 finally:
270 os.lstat = orig_lstat
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000271
Antoine Pitrou78091e62011-12-29 18:54:15 +0100272 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
273 @support.skip_unless_symlink
274 def test_copymode_follow_symlinks(self):
275 tmp_dir = self.mkdtemp()
276 src = os.path.join(tmp_dir, 'foo')
277 dst = os.path.join(tmp_dir, 'bar')
278 src_link = os.path.join(tmp_dir, 'baz')
279 dst_link = os.path.join(tmp_dir, 'quux')
280 write_file(src, 'foo')
281 write_file(dst, 'foo')
282 os.symlink(src, src_link)
283 os.symlink(dst, dst_link)
284 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
285 # file to file
286 os.chmod(dst, stat.S_IRWXO)
287 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
288 shutil.copymode(src, dst)
289 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
290 # follow src link
291 os.chmod(dst, stat.S_IRWXO)
292 shutil.copymode(src_link, dst)
293 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
294 # follow dst link
295 os.chmod(dst, stat.S_IRWXO)
296 shutil.copymode(src, dst_link)
297 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
298 # follow both links
299 os.chmod(dst, stat.S_IRWXO)
300 shutil.copymode(src_link, dst)
301 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
302
303 @unittest.skipUnless(hasattr(os, 'lchmod'), 'requires os.lchmod')
304 @support.skip_unless_symlink
305 def test_copymode_symlink_to_symlink(self):
306 tmp_dir = self.mkdtemp()
307 src = os.path.join(tmp_dir, 'foo')
308 dst = os.path.join(tmp_dir, 'bar')
309 src_link = os.path.join(tmp_dir, 'baz')
310 dst_link = os.path.join(tmp_dir, 'quux')
311 write_file(src, 'foo')
312 write_file(dst, 'foo')
313 os.symlink(src, src_link)
314 os.symlink(dst, dst_link)
315 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
316 os.chmod(dst, stat.S_IRWXU)
317 os.lchmod(src_link, stat.S_IRWXO|stat.S_IRWXG)
318 # link to link
319 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700320 shutil.copymode(src_link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100321 self.assertEqual(os.lstat(src_link).st_mode,
322 os.lstat(dst_link).st_mode)
323 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
324 # src link - use chmod
325 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700326 shutil.copymode(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100327 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
328 # dst link - use chmod
329 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700330 shutil.copymode(src, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100331 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
332
333 @unittest.skipIf(hasattr(os, 'lchmod'), 'requires os.lchmod to be missing')
334 @support.skip_unless_symlink
335 def test_copymode_symlink_to_symlink_wo_lchmod(self):
336 tmp_dir = self.mkdtemp()
337 src = os.path.join(tmp_dir, 'foo')
338 dst = os.path.join(tmp_dir, 'bar')
339 src_link = os.path.join(tmp_dir, 'baz')
340 dst_link = os.path.join(tmp_dir, 'quux')
341 write_file(src, 'foo')
342 write_file(dst, 'foo')
343 os.symlink(src, src_link)
344 os.symlink(dst, dst_link)
Larry Hastingsb4038062012-07-15 10:57:38 -0700345 shutil.copymode(src_link, dst_link, follow_symlinks=False) # silent fail
Antoine Pitrou78091e62011-12-29 18:54:15 +0100346
347 @support.skip_unless_symlink
348 def test_copystat_symlinks(self):
349 tmp_dir = self.mkdtemp()
350 src = os.path.join(tmp_dir, 'foo')
351 dst = os.path.join(tmp_dir, 'bar')
352 src_link = os.path.join(tmp_dir, 'baz')
353 dst_link = os.path.join(tmp_dir, 'qux')
354 write_file(src, 'foo')
355 src_stat = os.stat(src)
356 os.utime(src, (src_stat.st_atime,
357 src_stat.st_mtime - 42.0)) # ensure different mtimes
358 write_file(dst, 'bar')
359 self.assertNotEqual(os.stat(src).st_mtime, os.stat(dst).st_mtime)
360 os.symlink(src, src_link)
361 os.symlink(dst, dst_link)
362 if hasattr(os, 'lchmod'):
363 os.lchmod(src_link, stat.S_IRWXO)
364 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
365 os.lchflags(src_link, stat.UF_NODUMP)
366 src_link_stat = os.lstat(src_link)
367 # follow
368 if hasattr(os, 'lchmod'):
Larry Hastingsb4038062012-07-15 10:57:38 -0700369 shutil.copystat(src_link, dst_link, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100370 self.assertNotEqual(src_link_stat.st_mode, os.stat(dst).st_mode)
371 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700372 shutil.copystat(src_link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100373 dst_link_stat = os.lstat(dst_link)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700374 if os.utime in os.supports_follow_symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100375 for attr in 'st_atime', 'st_mtime':
376 # The modification times may be truncated in the new file.
377 self.assertLessEqual(getattr(src_link_stat, attr),
378 getattr(dst_link_stat, attr) + 1)
379 if hasattr(os, 'lchmod'):
380 self.assertEqual(src_link_stat.st_mode, dst_link_stat.st_mode)
381 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
382 self.assertEqual(src_link_stat.st_flags, dst_link_stat.st_flags)
383 # tell to follow but dst is not a link
Larry Hastingsb4038062012-07-15 10:57:38 -0700384 shutil.copystat(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100385 self.assertTrue(abs(os.stat(src).st_mtime - os.stat(dst).st_mtime) <
386 00000.1)
387
Ned Deilybaf75712012-05-10 17:05:19 -0700388 @unittest.skipUnless(hasattr(os, 'chflags') and
389 hasattr(errno, 'EOPNOTSUPP') and
390 hasattr(errno, 'ENOTSUP'),
391 "requires os.chflags, EOPNOTSUPP & ENOTSUP")
392 def test_copystat_handles_harmless_chflags_errors(self):
393 tmpdir = self.mkdtemp()
394 file1 = os.path.join(tmpdir, 'file1')
395 file2 = os.path.join(tmpdir, 'file2')
396 write_file(file1, 'xxx')
397 write_file(file2, 'xxx')
398
399 def make_chflags_raiser(err):
400 ex = OSError()
401
Larry Hastings90867a52012-06-22 17:01:41 -0700402 def _chflags_raiser(path, flags, *, follow_symlinks=True):
Ned Deilybaf75712012-05-10 17:05:19 -0700403 ex.errno = err
404 raise ex
405 return _chflags_raiser
406 old_chflags = os.chflags
407 try:
408 for err in errno.EOPNOTSUPP, errno.ENOTSUP:
409 os.chflags = make_chflags_raiser(err)
410 shutil.copystat(file1, file2)
411 # assert others errors break it
412 os.chflags = make_chflags_raiser(errno.EOPNOTSUPP + errno.ENOTSUP)
413 self.assertRaises(OSError, shutil.copystat, file1, file2)
414 finally:
415 os.chflags = old_chflags
416
Antoine Pitrou424246f2012-05-12 19:02:01 +0200417 @support.skip_unless_xattr
418 def test_copyxattr(self):
419 tmp_dir = self.mkdtemp()
420 src = os.path.join(tmp_dir, 'foo')
421 write_file(src, 'foo')
422 dst = os.path.join(tmp_dir, 'bar')
423 write_file(dst, 'bar')
424
425 # no xattr == no problem
426 shutil._copyxattr(src, dst)
427 # common case
428 os.setxattr(src, 'user.foo', b'42')
429 os.setxattr(src, 'user.bar', b'43')
430 shutil._copyxattr(src, dst)
431 self.assertEqual(os.listxattr(src), os.listxattr(dst))
432 self.assertEqual(
433 os.getxattr(src, 'user.foo'),
434 os.getxattr(dst, 'user.foo'))
435 # check errors don't affect other attrs
436 os.remove(dst)
437 write_file(dst, 'bar')
438 os_error = OSError(errno.EPERM, 'EPERM')
439
Larry Hastings9cf065c2012-06-22 16:30:09 -0700440 def _raise_on_user_foo(fname, attr, val, **kwargs):
Antoine Pitrou424246f2012-05-12 19:02:01 +0200441 if attr == 'user.foo':
442 raise os_error
443 else:
Larry Hastings9cf065c2012-06-22 16:30:09 -0700444 orig_setxattr(fname, attr, val, **kwargs)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200445 try:
446 orig_setxattr = os.setxattr
447 os.setxattr = _raise_on_user_foo
448 shutil._copyxattr(src, dst)
Antoine Pitrou61597d32012-05-12 23:37:35 +0200449 self.assertIn('user.bar', os.listxattr(dst))
Antoine Pitrou424246f2012-05-12 19:02:01 +0200450 finally:
451 os.setxattr = orig_setxattr
Hynek Schlawack0beab052013-02-05 08:22:44 +0100452 # the source filesystem not supporting xattrs should be ok, too.
453 def _raise_on_src(fname, *, follow_symlinks=True):
454 if fname == src:
455 raise OSError(errno.ENOTSUP, 'Operation not supported')
456 return orig_listxattr(fname, follow_symlinks=follow_symlinks)
457 try:
458 orig_listxattr = os.listxattr
459 os.listxattr = _raise_on_src
460 shutil._copyxattr(src, dst)
461 finally:
462 os.listxattr = orig_listxattr
Antoine Pitrou424246f2012-05-12 19:02:01 +0200463
Larry Hastingsad5ae042012-07-14 17:55:11 -0700464 # test that shutil.copystat copies xattrs
465 src = os.path.join(tmp_dir, 'the_original')
466 write_file(src, src)
467 os.setxattr(src, 'user.the_value', b'fiddly')
468 dst = os.path.join(tmp_dir, 'the_copy')
469 write_file(dst, dst)
470 shutil.copystat(src, dst)
Hynek Schlawackc2d481f2012-07-16 17:11:10 +0200471 self.assertEqual(os.getxattr(dst, 'user.the_value'), b'fiddly')
Larry Hastingsad5ae042012-07-14 17:55:11 -0700472
Antoine Pitrou424246f2012-05-12 19:02:01 +0200473 @support.skip_unless_symlink
474 @support.skip_unless_xattr
475 @unittest.skipUnless(hasattr(os, 'geteuid') and os.geteuid() == 0,
476 'root privileges required')
477 def test_copyxattr_symlinks(self):
478 # On Linux, it's only possible to access non-user xattr for symlinks;
479 # which in turn require root privileges. This test should be expanded
480 # as soon as other platforms gain support for extended attributes.
481 tmp_dir = self.mkdtemp()
482 src = os.path.join(tmp_dir, 'foo')
483 src_link = os.path.join(tmp_dir, 'baz')
484 write_file(src, 'foo')
485 os.symlink(src, src_link)
486 os.setxattr(src, 'trusted.foo', b'42')
Larry Hastings9cf065c2012-06-22 16:30:09 -0700487 os.setxattr(src_link, 'trusted.foo', b'43', follow_symlinks=False)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200488 dst = os.path.join(tmp_dir, 'bar')
489 dst_link = os.path.join(tmp_dir, 'qux')
490 write_file(dst, 'bar')
491 os.symlink(dst, dst_link)
Larry Hastingsb4038062012-07-15 10:57:38 -0700492 shutil._copyxattr(src_link, dst_link, follow_symlinks=False)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700493 self.assertEqual(os.getxattr(dst_link, 'trusted.foo', follow_symlinks=False), b'43')
Antoine Pitrou424246f2012-05-12 19:02:01 +0200494 self.assertRaises(OSError, os.getxattr, dst, 'trusted.foo')
Larry Hastingsb4038062012-07-15 10:57:38 -0700495 shutil._copyxattr(src_link, dst, follow_symlinks=False)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200496 self.assertEqual(os.getxattr(dst, 'trusted.foo'), b'43')
497
Antoine Pitrou78091e62011-12-29 18:54:15 +0100498 @support.skip_unless_symlink
499 def test_copy_symlinks(self):
500 tmp_dir = self.mkdtemp()
501 src = os.path.join(tmp_dir, 'foo')
502 dst = os.path.join(tmp_dir, 'bar')
503 src_link = os.path.join(tmp_dir, 'baz')
504 write_file(src, 'foo')
505 os.symlink(src, src_link)
506 if hasattr(os, 'lchmod'):
507 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
508 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700509 shutil.copy(src_link, dst, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100510 self.assertFalse(os.path.islink(dst))
511 self.assertEqual(read_file(src), read_file(dst))
512 os.remove(dst)
513 # follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700514 shutil.copy(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100515 self.assertTrue(os.path.islink(dst))
516 self.assertEqual(os.readlink(dst), os.readlink(src_link))
517 if hasattr(os, 'lchmod'):
518 self.assertEqual(os.lstat(src_link).st_mode,
519 os.lstat(dst).st_mode)
520
521 @support.skip_unless_symlink
522 def test_copy2_symlinks(self):
523 tmp_dir = self.mkdtemp()
524 src = os.path.join(tmp_dir, 'foo')
525 dst = os.path.join(tmp_dir, 'bar')
526 src_link = os.path.join(tmp_dir, 'baz')
527 write_file(src, 'foo')
528 os.symlink(src, src_link)
529 if hasattr(os, 'lchmod'):
530 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
531 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
532 os.lchflags(src_link, stat.UF_NODUMP)
533 src_stat = os.stat(src)
534 src_link_stat = os.lstat(src_link)
535 # follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700536 shutil.copy2(src_link, dst, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100537 self.assertFalse(os.path.islink(dst))
538 self.assertEqual(read_file(src), read_file(dst))
539 os.remove(dst)
540 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700541 shutil.copy2(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100542 self.assertTrue(os.path.islink(dst))
543 self.assertEqual(os.readlink(dst), os.readlink(src_link))
544 dst_stat = os.lstat(dst)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700545 if os.utime in os.supports_follow_symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100546 for attr in 'st_atime', 'st_mtime':
547 # The modification times may be truncated in the new file.
548 self.assertLessEqual(getattr(src_link_stat, attr),
549 getattr(dst_stat, attr) + 1)
550 if hasattr(os, 'lchmod'):
551 self.assertEqual(src_link_stat.st_mode, dst_stat.st_mode)
552 self.assertNotEqual(src_stat.st_mode, dst_stat.st_mode)
553 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
554 self.assertEqual(src_link_stat.st_flags, dst_stat.st_flags)
555
Antoine Pitrou424246f2012-05-12 19:02:01 +0200556 @support.skip_unless_xattr
557 def test_copy2_xattr(self):
558 tmp_dir = self.mkdtemp()
559 src = os.path.join(tmp_dir, 'foo')
560 dst = os.path.join(tmp_dir, 'bar')
561 write_file(src, 'foo')
562 os.setxattr(src, 'user.foo', b'42')
563 shutil.copy2(src, dst)
564 self.assertEqual(
565 os.getxattr(src, 'user.foo'),
566 os.getxattr(dst, 'user.foo'))
567 os.remove(dst)
568
Antoine Pitrou78091e62011-12-29 18:54:15 +0100569 @support.skip_unless_symlink
570 def test_copyfile_symlinks(self):
571 tmp_dir = self.mkdtemp()
572 src = os.path.join(tmp_dir, 'src')
573 dst = os.path.join(tmp_dir, 'dst')
574 dst_link = os.path.join(tmp_dir, 'dst_link')
575 link = os.path.join(tmp_dir, 'link')
576 write_file(src, 'foo')
577 os.symlink(src, link)
578 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700579 shutil.copyfile(link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100580 self.assertTrue(os.path.islink(dst_link))
581 self.assertEqual(os.readlink(link), os.readlink(dst_link))
582 # follow
583 shutil.copyfile(link, dst)
584 self.assertFalse(os.path.islink(dst))
585
Hynek Schlawack2100b422012-06-23 20:28:32 +0200586 def test_rmtree_uses_safe_fd_version_if_available(self):
Hynek Schlawackd0f6e0a2012-06-29 08:28:20 +0200587 _use_fd_functions = ({os.open, os.stat, os.unlink, os.rmdir} <=
588 os.supports_dir_fd and
589 os.listdir in os.supports_fd and
590 os.stat in os.supports_follow_symlinks)
591 if _use_fd_functions:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200592 self.assertTrue(shutil._use_fd_functions)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000593 self.assertTrue(shutil.rmtree.avoids_symlink_attacks)
Hynek Schlawack2100b422012-06-23 20:28:32 +0200594 tmp_dir = self.mkdtemp()
595 d = os.path.join(tmp_dir, 'a')
596 os.mkdir(d)
597 try:
598 real_rmtree = shutil._rmtree_safe_fd
599 class Called(Exception): pass
600 def _raiser(*args, **kwargs):
601 raise Called
602 shutil._rmtree_safe_fd = _raiser
603 self.assertRaises(Called, shutil.rmtree, d)
604 finally:
605 shutil._rmtree_safe_fd = real_rmtree
606 else:
607 self.assertFalse(shutil._use_fd_functions)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000608 self.assertFalse(shutil.rmtree.avoids_symlink_attacks)
Hynek Schlawack2100b422012-06-23 20:28:32 +0200609
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000610 def test_rmtree_dont_delete_file(self):
611 # When called on a file instead of a directory, don't delete it.
612 handle, path = tempfile.mkstemp()
Victor Stinnerbf816222011-06-30 23:25:47 +0200613 os.close(handle)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200614 self.assertRaises(NotADirectoryError, shutil.rmtree, path)
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000615 os.remove(path)
616
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000617 def test_copytree_simple(self):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000618 src_dir = tempfile.mkdtemp()
619 dst_dir = os.path.join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200620 self.addCleanup(shutil.rmtree, src_dir)
621 self.addCleanup(shutil.rmtree, os.path.dirname(dst_dir))
622 write_file((src_dir, 'test.txt'), '123')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000623 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200624 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000625
Éric Araujoa7e33a12011-08-12 19:51:35 +0200626 shutil.copytree(src_dir, dst_dir)
627 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test.txt')))
628 self.assertTrue(os.path.isdir(os.path.join(dst_dir, 'test_dir')))
629 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test_dir',
630 'test.txt')))
631 actual = read_file((dst_dir, 'test.txt'))
632 self.assertEqual(actual, '123')
633 actual = read_file((dst_dir, 'test_dir', 'test.txt'))
634 self.assertEqual(actual, '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000635
Antoine Pitrou78091e62011-12-29 18:54:15 +0100636 @support.skip_unless_symlink
637 def test_copytree_symlinks(self):
638 tmp_dir = self.mkdtemp()
639 src_dir = os.path.join(tmp_dir, 'src')
640 dst_dir = os.path.join(tmp_dir, 'dst')
641 sub_dir = os.path.join(src_dir, 'sub')
642 os.mkdir(src_dir)
643 os.mkdir(sub_dir)
644 write_file((src_dir, 'file.txt'), 'foo')
645 src_link = os.path.join(sub_dir, 'link')
646 dst_link = os.path.join(dst_dir, 'sub/link')
647 os.symlink(os.path.join(src_dir, 'file.txt'),
648 src_link)
649 if hasattr(os, 'lchmod'):
650 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
651 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
652 os.lchflags(src_link, stat.UF_NODUMP)
653 src_stat = os.lstat(src_link)
654 shutil.copytree(src_dir, dst_dir, symlinks=True)
655 self.assertTrue(os.path.islink(os.path.join(dst_dir, 'sub', 'link')))
656 self.assertEqual(os.readlink(os.path.join(dst_dir, 'sub', 'link')),
657 os.path.join(src_dir, 'file.txt'))
658 dst_stat = os.lstat(dst_link)
659 if hasattr(os, 'lchmod'):
660 self.assertEqual(dst_stat.st_mode, src_stat.st_mode)
661 if hasattr(os, 'lchflags'):
662 self.assertEqual(dst_stat.st_flags, src_stat.st_flags)
663
Georg Brandl2ee470f2008-07-16 12:55:28 +0000664 def test_copytree_with_exclude(self):
Georg Brandl2ee470f2008-07-16 12:55:28 +0000665 # creating data
666 join = os.path.join
667 exists = os.path.exists
668 src_dir = tempfile.mkdtemp()
Georg Brandl2ee470f2008-07-16 12:55:28 +0000669 try:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000670 dst_dir = join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200671 write_file((src_dir, 'test.txt'), '123')
672 write_file((src_dir, 'test.tmp'), '123')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000673 os.mkdir(join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200674 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000675 os.mkdir(join(src_dir, 'test_dir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200676 write_file((src_dir, 'test_dir2', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000677 os.mkdir(join(src_dir, 'test_dir2', 'subdir'))
678 os.mkdir(join(src_dir, 'test_dir2', 'subdir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200679 write_file((src_dir, 'test_dir2', 'subdir', 'test.txt'), '456')
680 write_file((src_dir, 'test_dir2', 'subdir2', 'test.py'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000681
682 # testing glob-like patterns
683 try:
684 patterns = shutil.ignore_patterns('*.tmp', 'test_dir2')
685 shutil.copytree(src_dir, dst_dir, ignore=patterns)
686 # checking the result: some elements should not be copied
687 self.assertTrue(exists(join(dst_dir, 'test.txt')))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200688 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
689 self.assertFalse(exists(join(dst_dir, 'test_dir2')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000690 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200691 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000692 try:
693 patterns = shutil.ignore_patterns('*.tmp', 'subdir*')
694 shutil.copytree(src_dir, dst_dir, ignore=patterns)
695 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200696 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
697 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2')))
698 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000699 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200700 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000701
702 # testing callable-style
703 try:
704 def _filter(src, names):
705 res = []
706 for name in names:
707 path = os.path.join(src, name)
708
709 if (os.path.isdir(path) and
710 path.split()[-1] == 'subdir'):
711 res.append(name)
712 elif os.path.splitext(path)[-1] in ('.py'):
713 res.append(name)
714 return res
715
716 shutil.copytree(src_dir, dst_dir, ignore=_filter)
717
718 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200719 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2',
720 'test.py')))
721 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000722
723 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200724 shutil.rmtree(dst_dir)
Georg Brandl2ee470f2008-07-16 12:55:28 +0000725 finally:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000726 shutil.rmtree(src_dir)
727 shutil.rmtree(os.path.dirname(dst_dir))
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000728
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000729 @unittest.skipUnless(hasattr(os, 'link'), 'requires os.link')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000730 def test_dont_copy_file_onto_link_to_itself(self):
Georg Brandl724d0892010-12-05 07:51:39 +0000731 # Temporarily disable test on Windows.
732 if os.name == 'nt':
733 return
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000734 # bug 851123.
735 os.mkdir(TESTFN)
736 src = os.path.join(TESTFN, 'cheese')
737 dst = os.path.join(TESTFN, 'shop')
738 try:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000739 with open(src, 'w') as f:
740 f.write('cheddar')
741 os.link(src, dst)
Hynek Schlawack26fe37d2012-07-19 21:41:02 +0200742 self.assertRaises(shutil.Error, shutil.copyfile, src, dst)
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000743 with open(src, 'r') as f:
744 self.assertEqual(f.read(), 'cheddar')
745 os.remove(dst)
746 finally:
747 shutil.rmtree(TESTFN, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000748
Brian Curtin3b4499c2010-12-28 14:31:47 +0000749 @support.skip_unless_symlink
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000750 def test_dont_copy_file_onto_symlink_to_itself(self):
751 # bug 851123.
752 os.mkdir(TESTFN)
753 src = os.path.join(TESTFN, 'cheese')
754 dst = os.path.join(TESTFN, 'shop')
755 try:
756 with open(src, 'w') as f:
757 f.write('cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000758 # Using `src` here would mean we end up with a symlink pointing
759 # to TESTFN/TESTFN/cheese, while it should point at
760 # TESTFN/cheese.
761 os.symlink('cheese', dst)
Hynek Schlawack26fe37d2012-07-19 21:41:02 +0200762 self.assertRaises(shutil.Error, shutil.copyfile, src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +0000763 with open(src, 'r') as f:
764 self.assertEqual(f.read(), 'cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000765 os.remove(dst)
766 finally:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000767 shutil.rmtree(TESTFN, ignore_errors=True)
Johannes Gijsbers68128712004-08-14 13:57:08 +0000768
Brian Curtin3b4499c2010-12-28 14:31:47 +0000769 @support.skip_unless_symlink
Brian Curtind40e6f72010-07-08 21:39:08 +0000770 def test_rmtree_on_symlink(self):
771 # bug 1669.
772 os.mkdir(TESTFN)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000773 try:
Brian Curtind40e6f72010-07-08 21:39:08 +0000774 src = os.path.join(TESTFN, 'cheese')
775 dst = os.path.join(TESTFN, 'shop')
776 os.mkdir(src)
777 os.symlink(src, dst)
778 self.assertRaises(OSError, shutil.rmtree, dst)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200779 shutil.rmtree(dst, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000780 finally:
Brian Curtind40e6f72010-07-08 21:39:08 +0000781 shutil.rmtree(TESTFN, ignore_errors=True)
782
783 if hasattr(os, "mkfifo"):
784 # Issue #3002: copyfile and copytree block indefinitely on named pipes
785 def test_copyfile_named_pipe(self):
786 os.mkfifo(TESTFN)
787 try:
788 self.assertRaises(shutil.SpecialFileError,
789 shutil.copyfile, TESTFN, TESTFN2)
790 self.assertRaises(shutil.SpecialFileError,
791 shutil.copyfile, __file__, TESTFN)
792 finally:
793 os.remove(TESTFN)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000794
Brian Curtin3b4499c2010-12-28 14:31:47 +0000795 @support.skip_unless_symlink
Brian Curtin52173d42010-12-02 18:29:18 +0000796 def test_copytree_named_pipe(self):
797 os.mkdir(TESTFN)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000798 try:
Brian Curtin52173d42010-12-02 18:29:18 +0000799 subdir = os.path.join(TESTFN, "subdir")
800 os.mkdir(subdir)
801 pipe = os.path.join(subdir, "mypipe")
802 os.mkfifo(pipe)
803 try:
804 shutil.copytree(TESTFN, TESTFN2)
805 except shutil.Error as e:
806 errors = e.args[0]
807 self.assertEqual(len(errors), 1)
808 src, dst, error_msg = errors[0]
809 self.assertEqual("`%s` is a named pipe" % pipe, error_msg)
810 else:
811 self.fail("shutil.Error should have been raised")
812 finally:
813 shutil.rmtree(TESTFN, ignore_errors=True)
814 shutil.rmtree(TESTFN2, ignore_errors=True)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000815
Tarek Ziadé5340db32010-04-19 22:30:51 +0000816 def test_copytree_special_func(self):
817
818 src_dir = self.mkdtemp()
819 dst_dir = os.path.join(self.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200820 write_file((src_dir, 'test.txt'), '123')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000821 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200822 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000823
824 copied = []
825 def _copy(src, dst):
826 copied.append((src, dst))
827
828 shutil.copytree(src_dir, dst_dir, copy_function=_copy)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000829 self.assertEqual(len(copied), 2)
Tarek Ziadé5340db32010-04-19 22:30:51 +0000830
Brian Curtin3b4499c2010-12-28 14:31:47 +0000831 @support.skip_unless_symlink
Tarek Ziadéfb437512010-04-20 08:57:33 +0000832 def test_copytree_dangling_symlinks(self):
833
834 # a dangling symlink raises an error at the end
835 src_dir = self.mkdtemp()
836 dst_dir = os.path.join(self.mkdtemp(), 'destination')
837 os.symlink('IDONTEXIST', os.path.join(src_dir, 'test.txt'))
838 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200839 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadéfb437512010-04-20 08:57:33 +0000840 self.assertRaises(Error, shutil.copytree, src_dir, dst_dir)
841
842 # a dangling symlink is ignored with the proper flag
843 dst_dir = os.path.join(self.mkdtemp(), 'destination2')
844 shutil.copytree(src_dir, dst_dir, ignore_dangling_symlinks=True)
845 self.assertNotIn('test.txt', os.listdir(dst_dir))
846
847 # a dangling symlink is copied if symlinks=True
848 dst_dir = os.path.join(self.mkdtemp(), 'destination3')
849 shutil.copytree(src_dir, dst_dir, symlinks=True)
850 self.assertIn('test.txt', os.listdir(dst_dir))
851
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400852 def _copy_file(self, method):
853 fname = 'test.txt'
854 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200855 write_file((tmpdir, fname), 'xxx')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400856 file1 = os.path.join(tmpdir, fname)
857 tmpdir2 = self.mkdtemp()
858 method(file1, tmpdir2)
859 file2 = os.path.join(tmpdir2, fname)
860 return (file1, file2)
861
862 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
863 def test_copy(self):
864 # Ensure that the copied file exists and has the same mode bits.
865 file1, file2 = self._copy_file(shutil.copy)
866 self.assertTrue(os.path.exists(file2))
867 self.assertEqual(os.stat(file1).st_mode, os.stat(file2).st_mode)
868
869 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
Senthil Kumaran0c2dba52011-07-03 18:21:38 -0700870 @unittest.skipUnless(hasattr(os, 'utime'), 'requires os.utime')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400871 def test_copy2(self):
872 # Ensure that the copied file exists and has the same mode and
873 # modification time bits.
874 file1, file2 = self._copy_file(shutil.copy2)
875 self.assertTrue(os.path.exists(file2))
876 file1_stat = os.stat(file1)
877 file2_stat = os.stat(file2)
878 self.assertEqual(file1_stat.st_mode, file2_stat.st_mode)
879 for attr in 'st_atime', 'st_mtime':
880 # The modification times may be truncated in the new file.
881 self.assertLessEqual(getattr(file1_stat, attr),
882 getattr(file2_stat, attr) + 1)
883 if hasattr(os, 'chflags') and hasattr(file1_stat, 'st_flags'):
884 self.assertEqual(getattr(file1_stat, 'st_flags'),
885 getattr(file2_stat, 'st_flags'))
886
Ezio Melotti975077a2011-05-19 22:03:22 +0300887 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000888 def test_make_tarball(self):
889 # creating something to tar
890 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200891 write_file((tmpdir, 'file1'), 'xxx')
892 write_file((tmpdir, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000893 os.mkdir(os.path.join(tmpdir, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200894 write_file((tmpdir, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000895
896 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400897 # force shutil to create the directory
898 os.rmdir(tmpdir2)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000899 unittest.skipUnless(splitdrive(tmpdir)[0] == splitdrive(tmpdir2)[0],
900 "source and target should be on same drive")
901
902 base_name = os.path.join(tmpdir2, 'archive')
903
904 # working with relative paths to avoid tar warnings
905 old_dir = os.getcwd()
906 os.chdir(tmpdir)
907 try:
908 _make_tarball(splitdrive(base_name)[1], '.')
909 finally:
910 os.chdir(old_dir)
911
912 # check if the compressed tarball was created
913 tarball = base_name + '.tar.gz'
914 self.assertTrue(os.path.exists(tarball))
915
916 # trying an uncompressed one
917 base_name = os.path.join(tmpdir2, 'archive')
918 old_dir = os.getcwd()
919 os.chdir(tmpdir)
920 try:
921 _make_tarball(splitdrive(base_name)[1], '.', compress=None)
922 finally:
923 os.chdir(old_dir)
924 tarball = base_name + '.tar'
925 self.assertTrue(os.path.exists(tarball))
926
927 def _tarinfo(self, path):
928 tar = tarfile.open(path)
929 try:
930 names = tar.getnames()
931 names.sort()
932 return tuple(names)
933 finally:
934 tar.close()
935
936 def _create_files(self):
937 # creating something to tar
938 tmpdir = self.mkdtemp()
939 dist = os.path.join(tmpdir, 'dist')
940 os.mkdir(dist)
Éric Araujoa7e33a12011-08-12 19:51:35 +0200941 write_file((dist, 'file1'), 'xxx')
942 write_file((dist, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000943 os.mkdir(os.path.join(dist, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200944 write_file((dist, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000945 os.mkdir(os.path.join(dist, 'sub2'))
946 tmpdir2 = self.mkdtemp()
947 base_name = os.path.join(tmpdir2, 'archive')
948 return tmpdir, tmpdir2, base_name
949
Ezio Melotti975077a2011-05-19 22:03:22 +0300950 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000951 @unittest.skipUnless(find_executable('tar') and find_executable('gzip'),
952 'Need the tar command to run')
953 def test_tarfile_vs_tar(self):
954 tmpdir, tmpdir2, base_name = self._create_files()
955 old_dir = os.getcwd()
956 os.chdir(tmpdir)
957 try:
958 _make_tarball(base_name, 'dist')
959 finally:
960 os.chdir(old_dir)
961
962 # check if the compressed tarball was created
963 tarball = base_name + '.tar.gz'
964 self.assertTrue(os.path.exists(tarball))
965
966 # now create another tarball using `tar`
967 tarball2 = os.path.join(tmpdir, 'archive2.tar.gz')
968 tar_cmd = ['tar', '-cf', 'archive2.tar', 'dist']
969 gzip_cmd = ['gzip', '-f9', 'archive2.tar']
970 old_dir = os.getcwd()
971 os.chdir(tmpdir)
972 try:
973 with captured_stdout() as s:
974 spawn(tar_cmd)
975 spawn(gzip_cmd)
976 finally:
977 os.chdir(old_dir)
978
979 self.assertTrue(os.path.exists(tarball2))
980 # let's compare both tarballs
Ezio Melottib3aedd42010-11-20 19:04:17 +0000981 self.assertEqual(self._tarinfo(tarball), self._tarinfo(tarball2))
Tarek Ziadé396fad72010-02-23 05:30:31 +0000982
983 # trying an uncompressed one
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)
989 finally:
990 os.chdir(old_dir)
991 tarball = base_name + '.tar'
992 self.assertTrue(os.path.exists(tarball))
993
994 # now for a dry_run
995 base_name = os.path.join(tmpdir2, 'archive')
996 old_dir = os.getcwd()
997 os.chdir(tmpdir)
998 try:
999 _make_tarball(base_name, 'dist', compress=None, dry_run=True)
1000 finally:
1001 os.chdir(old_dir)
1002 tarball = base_name + '.tar'
1003 self.assertTrue(os.path.exists(tarball))
1004
Ezio Melotti975077a2011-05-19 22:03:22 +03001005 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001006 @unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run')
1007 def test_make_zipfile(self):
1008 # creating something to tar
1009 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +02001010 write_file((tmpdir, 'file1'), 'xxx')
1011 write_file((tmpdir, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +00001012
1013 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001014 # force shutil to create the directory
1015 os.rmdir(tmpdir2)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001016 base_name = os.path.join(tmpdir2, 'archive')
1017 _make_zipfile(base_name, tmpdir)
1018
1019 # check if the compressed tarball was created
1020 tarball = base_name + '.zip'
Éric Araujo1c505492010-11-06 02:12:51 +00001021 self.assertTrue(os.path.exists(tarball))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001022
1023
1024 def test_make_archive(self):
1025 tmpdir = self.mkdtemp()
1026 base_name = os.path.join(tmpdir, 'archive')
1027 self.assertRaises(ValueError, make_archive, base_name, 'xxx')
1028
Ezio Melotti975077a2011-05-19 22:03:22 +03001029 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001030 def test_make_archive_owner_group(self):
1031 # testing make_archive with owner and group, with various combinations
1032 # this works even if there's not gid/uid support
1033 if UID_GID_SUPPORT:
1034 group = grp.getgrgid(0)[0]
1035 owner = pwd.getpwuid(0)[0]
1036 else:
1037 group = owner = 'root'
1038
1039 base_dir, root_dir, base_name = self._create_files()
1040 base_name = os.path.join(self.mkdtemp() , 'archive')
1041 res = make_archive(base_name, 'zip', root_dir, base_dir, owner=owner,
1042 group=group)
1043 self.assertTrue(os.path.exists(res))
1044
1045 res = make_archive(base_name, 'zip', root_dir, base_dir)
1046 self.assertTrue(os.path.exists(res))
1047
1048 res = make_archive(base_name, 'tar', root_dir, base_dir,
1049 owner=owner, group=group)
1050 self.assertTrue(os.path.exists(res))
1051
1052 res = make_archive(base_name, 'tar', root_dir, base_dir,
1053 owner='kjhkjhkjg', group='oihohoh')
1054 self.assertTrue(os.path.exists(res))
1055
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001056
Ezio Melotti975077a2011-05-19 22:03:22 +03001057 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001058 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1059 def test_tarfile_root_owner(self):
1060 tmpdir, tmpdir2, base_name = self._create_files()
1061 old_dir = os.getcwd()
1062 os.chdir(tmpdir)
1063 group = grp.getgrgid(0)[0]
1064 owner = pwd.getpwuid(0)[0]
1065 try:
1066 archive_name = _make_tarball(base_name, 'dist', compress=None,
1067 owner=owner, group=group)
1068 finally:
1069 os.chdir(old_dir)
1070
1071 # check if the compressed tarball was created
1072 self.assertTrue(os.path.exists(archive_name))
1073
1074 # now checks the rights
1075 archive = tarfile.open(archive_name)
1076 try:
1077 for member in archive.getmembers():
Ezio Melottib3aedd42010-11-20 19:04:17 +00001078 self.assertEqual(member.uid, 0)
1079 self.assertEqual(member.gid, 0)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001080 finally:
1081 archive.close()
1082
1083 def test_make_archive_cwd(self):
1084 current_dir = os.getcwd()
1085 def _breaks(*args, **kw):
1086 raise RuntimeError()
1087
1088 register_archive_format('xxx', _breaks, [], 'xxx file')
1089 try:
1090 try:
1091 make_archive('xxx', 'xxx', root_dir=self.mkdtemp())
1092 except Exception:
1093 pass
Ezio Melottib3aedd42010-11-20 19:04:17 +00001094 self.assertEqual(os.getcwd(), current_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001095 finally:
1096 unregister_archive_format('xxx')
1097
1098 def test_register_archive_format(self):
1099
1100 self.assertRaises(TypeError, register_archive_format, 'xxx', 1)
1101 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1102 1)
1103 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1104 [(1, 2), (1, 2, 3)])
1105
1106 register_archive_format('xxx', lambda: x, [(1, 2)], 'xxx file')
1107 formats = [name for name, params in get_archive_formats()]
1108 self.assertIn('xxx', formats)
1109
1110 unregister_archive_format('xxx')
1111 formats = [name for name, params in get_archive_formats()]
1112 self.assertNotIn('xxx', formats)
1113
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001114 def _compare_dirs(self, dir1, dir2):
1115 # check that dir1 and dir2 are equivalent,
1116 # return the diff
1117 diff = []
1118 for root, dirs, files in os.walk(dir1):
1119 for file_ in files:
1120 path = os.path.join(root, file_)
1121 target_path = os.path.join(dir2, os.path.split(path)[-1])
1122 if not os.path.exists(target_path):
1123 diff.append(file_)
1124 return diff
1125
Ezio Melotti975077a2011-05-19 22:03:22 +03001126 @requires_zlib
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001127 def test_unpack_archive(self):
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001128 formats = ['tar', 'gztar', 'zip']
1129 if BZ2_SUPPORTED:
1130 formats.append('bztar')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001131
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001132 for format in formats:
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001133 tmpdir = self.mkdtemp()
1134 base_dir, root_dir, base_name = self._create_files()
1135 tmpdir2 = self.mkdtemp()
1136 filename = make_archive(base_name, format, root_dir, base_dir)
1137
1138 # let's try to unpack it now
1139 unpack_archive(filename, tmpdir2)
1140 diff = self._compare_dirs(tmpdir, tmpdir2)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001141 self.assertEqual(diff, [])
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001142
Nick Coghlanabf202d2011-03-16 13:52:20 -04001143 # and again, this time with the format specified
1144 tmpdir3 = self.mkdtemp()
1145 unpack_archive(filename, tmpdir3, format=format)
1146 diff = self._compare_dirs(tmpdir, tmpdir3)
1147 self.assertEqual(diff, [])
1148 self.assertRaises(shutil.ReadError, unpack_archive, TESTFN)
1149 self.assertRaises(ValueError, unpack_archive, TESTFN, format='xxx')
1150
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001151 def test_unpack_registery(self):
1152
1153 formats = get_unpack_formats()
1154
1155 def _boo(filename, extract_dir, extra):
Ezio Melottib3aedd42010-11-20 19:04:17 +00001156 self.assertEqual(extra, 1)
1157 self.assertEqual(filename, 'stuff.boo')
1158 self.assertEqual(extract_dir, 'xx')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001159
1160 register_unpack_format('Boo', ['.boo', '.b2'], _boo, [('extra', 1)])
1161 unpack_archive('stuff.boo', 'xx')
1162
1163 # trying to register a .boo unpacker again
1164 self.assertRaises(RegistryError, register_unpack_format, 'Boo2',
1165 ['.boo'], _boo)
1166
1167 # should work now
1168 unregister_unpack_format('Boo')
1169 register_unpack_format('Boo2', ['.boo'], _boo)
1170 self.assertIn(('Boo2', ['.boo'], ''), get_unpack_formats())
1171 self.assertNotIn(('Boo', ['.boo'], ''), get_unpack_formats())
1172
1173 # let's leave a clean state
1174 unregister_unpack_format('Boo2')
Ezio Melottib3aedd42010-11-20 19:04:17 +00001175 self.assertEqual(get_unpack_formats(), formats)
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001176
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001177 @unittest.skipUnless(hasattr(shutil, 'disk_usage'),
1178 "disk_usage not available on this platform")
1179 def test_disk_usage(self):
1180 usage = shutil.disk_usage(os.getcwd())
Éric Araujo2ee61882011-07-02 16:45:45 +02001181 self.assertGreater(usage.total, 0)
1182 self.assertGreater(usage.used, 0)
1183 self.assertGreaterEqual(usage.free, 0)
1184 self.assertGreaterEqual(usage.total, usage.used)
1185 self.assertGreater(usage.total, usage.free)
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001186
Sandro Tosid902a142011-08-22 23:28:27 +02001187 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1188 @unittest.skipUnless(hasattr(os, 'chown'), 'requires os.chown')
1189 def test_chown(self):
1190
1191 # cleaned-up automatically by TestShutil.tearDown method
1192 dirname = self.mkdtemp()
1193 filename = tempfile.mktemp(dir=dirname)
1194 write_file(filename, 'testing chown function')
1195
1196 with self.assertRaises(ValueError):
1197 shutil.chown(filename)
1198
1199 with self.assertRaises(LookupError):
1200 shutil.chown(filename, user='non-exising username')
1201
1202 with self.assertRaises(LookupError):
1203 shutil.chown(filename, group='non-exising groupname')
1204
1205 with self.assertRaises(TypeError):
1206 shutil.chown(filename, b'spam')
1207
1208 with self.assertRaises(TypeError):
1209 shutil.chown(filename, 3.14)
1210
1211 uid = os.getuid()
1212 gid = os.getgid()
1213
1214 def check_chown(path, uid=None, gid=None):
1215 s = os.stat(filename)
1216 if uid is not None:
1217 self.assertEqual(uid, s.st_uid)
1218 if gid is not None:
1219 self.assertEqual(gid, s.st_gid)
1220
1221 shutil.chown(filename, uid, gid)
1222 check_chown(filename, uid, gid)
1223 shutil.chown(filename, uid)
1224 check_chown(filename, uid)
1225 shutil.chown(filename, user=uid)
1226 check_chown(filename, uid)
1227 shutil.chown(filename, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001228 check_chown(filename, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001229
1230 shutil.chown(dirname, uid, gid)
1231 check_chown(dirname, uid, gid)
1232 shutil.chown(dirname, uid)
1233 check_chown(dirname, uid)
1234 shutil.chown(dirname, user=uid)
1235 check_chown(dirname, uid)
1236 shutil.chown(dirname, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001237 check_chown(dirname, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001238
1239 user = pwd.getpwuid(uid)[0]
1240 group = grp.getgrgid(gid)[0]
1241 shutil.chown(filename, user, group)
1242 check_chown(filename, uid, gid)
1243 shutil.chown(dirname, user, group)
1244 check_chown(dirname, uid, gid)
1245
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001246 def test_copy_return_value(self):
1247 # copy and copy2 both return their destination path.
1248 for fn in (shutil.copy, shutil.copy2):
1249 src_dir = self.mkdtemp()
1250 dst_dir = self.mkdtemp()
1251 src = os.path.join(src_dir, 'foo')
1252 write_file(src, 'foo')
1253 rv = fn(src, dst_dir)
1254 self.assertEqual(rv, os.path.join(dst_dir, 'foo'))
1255 rv = fn(src, os.path.join(dst_dir, 'bar'))
1256 self.assertEqual(rv, os.path.join(dst_dir, 'bar'))
1257
1258 def test_copyfile_return_value(self):
1259 # copytree returns its destination path.
1260 src_dir = self.mkdtemp()
1261 dst_dir = self.mkdtemp()
1262 dst_file = os.path.join(dst_dir, 'bar')
1263 src_file = os.path.join(src_dir, 'foo')
1264 write_file(src_file, 'foo')
1265 rv = shutil.copyfile(src_file, dst_file)
1266 self.assertTrue(os.path.exists(rv))
1267 self.assertEqual(read_file(src_file), read_file(dst_file))
1268
1269 def test_copytree_return_value(self):
1270 # copytree returns its destination path.
1271 src_dir = self.mkdtemp()
1272 dst_dir = src_dir + "dest"
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001273 self.addCleanup(shutil.rmtree, dst_dir, True)
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001274 src = os.path.join(src_dir, 'foo')
1275 write_file(src, 'foo')
1276 rv = shutil.copytree(src_dir, dst_dir)
1277 self.assertEqual(['foo'], os.listdir(rv))
1278
Christian Heimes9bd667a2008-01-20 15:14:11 +00001279
Brian Curtinc57a3452012-06-22 16:00:30 -05001280class TestWhich(unittest.TestCase):
1281
1282 def setUp(self):
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001283 self.temp_dir = tempfile.mkdtemp(prefix="Tmp")
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001284 self.addCleanup(shutil.rmtree, self.temp_dir, True)
Brian Curtinc57a3452012-06-22 16:00:30 -05001285 # Give the temp_file an ".exe" suffix for all.
1286 # It's needed on Windows and not harmful on other platforms.
1287 self.temp_file = tempfile.NamedTemporaryFile(dir=self.temp_dir,
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001288 prefix="Tmp",
1289 suffix=".Exe")
Brian Curtinc57a3452012-06-22 16:00:30 -05001290 os.chmod(self.temp_file.name, stat.S_IXUSR)
1291 self.addCleanup(self.temp_file.close)
1292 self.dir, self.file = os.path.split(self.temp_file.name)
1293
1294 def test_basic(self):
1295 # Given an EXE in a directory, it should be returned.
1296 rv = shutil.which(self.file, path=self.dir)
1297 self.assertEqual(rv, self.temp_file.name)
1298
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001299 def test_absolute_cmd(self):
Brian Curtinc57a3452012-06-22 16:00:30 -05001300 # When given the fully qualified path to an executable that exists,
1301 # it should be returned.
1302 rv = shutil.which(self.temp_file.name, path=self.temp_dir)
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001303 self.assertEqual(rv, self.temp_file.name)
1304
1305 def test_relative_cmd(self):
1306 # When given the relative path with a directory part to an executable
1307 # that exists, it should be returned.
1308 base_dir, tail_dir = os.path.split(self.dir)
1309 relpath = os.path.join(tail_dir, self.file)
1310 with support.temp_cwd(path=base_dir):
1311 rv = shutil.which(relpath, path=self.temp_dir)
1312 self.assertEqual(rv, relpath)
1313 # But it shouldn't be searched in PATH directories (issue #16957).
1314 with support.temp_cwd(path=self.dir):
1315 rv = shutil.which(relpath, path=base_dir)
1316 self.assertIsNone(rv)
1317
1318 def test_cwd(self):
1319 # Issue #16957
1320 base_dir = os.path.dirname(self.dir)
1321 with support.temp_cwd(path=self.dir):
1322 rv = shutil.which(self.file, path=base_dir)
1323 if sys.platform == "win32":
1324 # Windows: current directory implicitly on PATH
1325 self.assertEqual(rv, os.path.join(os.curdir, self.file))
1326 else:
1327 # Other platforms: shouldn't match in the current directory.
1328 self.assertIsNone(rv)
Brian Curtinc57a3452012-06-22 16:00:30 -05001329
Serhiy Storchaka12516e22013-05-28 15:50:15 +03001330 @unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0,
1331 'non-root user required')
Brian Curtinc57a3452012-06-22 16:00:30 -05001332 def test_non_matching_mode(self):
1333 # Set the file read-only and ask for writeable files.
1334 os.chmod(self.temp_file.name, stat.S_IREAD)
Serhiy Storchaka12516e22013-05-28 15:50:15 +03001335 if os.access(self.temp_file.name, os.W_OK):
1336 self.skipTest("can't set the file read-only")
Brian Curtinc57a3452012-06-22 16:00:30 -05001337 rv = shutil.which(self.file, path=self.dir, mode=os.W_OK)
1338 self.assertIsNone(rv)
1339
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001340 def test_relative_path(self):
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001341 base_dir, tail_dir = os.path.split(self.dir)
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001342 with support.temp_cwd(path=base_dir):
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001343 rv = shutil.which(self.file, path=tail_dir)
1344 self.assertEqual(rv, os.path.join(tail_dir, self.file))
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001345
Brian Curtinc57a3452012-06-22 16:00:30 -05001346 def test_nonexistent_file(self):
1347 # Return None when no matching executable file is found on the path.
1348 rv = shutil.which("foo.exe", path=self.dir)
1349 self.assertIsNone(rv)
1350
1351 @unittest.skipUnless(sys.platform == "win32",
1352 "pathext check is Windows-only")
1353 def test_pathext_checking(self):
1354 # Ask for the file without the ".exe" extension, then ensure that
1355 # it gets found properly with the extension.
Serhiy Storchakad70127a2013-01-24 20:03:49 +02001356 rv = shutil.which(self.file[:-4], path=self.dir)
Serhiy Storchaka80c88f42013-01-22 10:31:36 +02001357 self.assertEqual(rv, self.temp_file.name[:-4] + ".EXE")
Brian Curtinc57a3452012-06-22 16:00:30 -05001358
Barry Warsaw618738b2013-04-16 11:05:03 -04001359 def test_environ_path(self):
1360 with support.EnvironmentVarGuard() as env:
1361 env['PATH'] = self.dir
1362 rv = shutil.which(self.file)
1363 self.assertEqual(rv, self.temp_file.name)
1364
1365 def test_empty_path(self):
1366 base_dir = os.path.dirname(self.dir)
1367 with support.temp_cwd(path=self.dir), \
1368 support.EnvironmentVarGuard() as env:
1369 env['PATH'] = self.dir
1370 rv = shutil.which(self.file, path='')
1371 self.assertIsNone(rv)
1372
1373 def test_empty_path_no_PATH(self):
1374 with support.EnvironmentVarGuard() as env:
1375 env.pop('PATH', None)
1376 rv = shutil.which(self.file)
1377 self.assertIsNone(rv)
1378
Brian Curtinc57a3452012-06-22 16:00:30 -05001379
Christian Heimesada8c3b2008-03-18 18:26:33 +00001380class TestMove(unittest.TestCase):
1381
1382 def setUp(self):
1383 filename = "foo"
1384 self.src_dir = tempfile.mkdtemp()
1385 self.dst_dir = tempfile.mkdtemp()
1386 self.src_file = os.path.join(self.src_dir, filename)
1387 self.dst_file = os.path.join(self.dst_dir, filename)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001388 with open(self.src_file, "wb") as f:
1389 f.write(b"spam")
1390
1391 def tearDown(self):
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001392 for d in (self.src_dir, self.dst_dir):
Christian Heimesada8c3b2008-03-18 18:26:33 +00001393 try:
1394 if d:
1395 shutil.rmtree(d)
1396 except:
1397 pass
1398
1399 def _check_move_file(self, src, dst, real_dst):
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001400 with open(src, "rb") as f:
1401 contents = f.read()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001402 shutil.move(src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001403 with open(real_dst, "rb") as f:
1404 self.assertEqual(contents, f.read())
Christian Heimesada8c3b2008-03-18 18:26:33 +00001405 self.assertFalse(os.path.exists(src))
1406
1407 def _check_move_dir(self, src, dst, real_dst):
1408 contents = sorted(os.listdir(src))
1409 shutil.move(src, dst)
1410 self.assertEqual(contents, sorted(os.listdir(real_dst)))
1411 self.assertFalse(os.path.exists(src))
1412
1413 def test_move_file(self):
1414 # Move a file to another location on the same filesystem.
1415 self._check_move_file(self.src_file, self.dst_file, self.dst_file)
1416
1417 def test_move_file_to_dir(self):
1418 # Move a file inside an existing dir on the same filesystem.
1419 self._check_move_file(self.src_file, self.dst_dir, self.dst_file)
1420
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001421 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001422 def test_move_file_other_fs(self):
1423 # Move a file to an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001424 self.test_move_file()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001425
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001426 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001427 def test_move_file_to_dir_other_fs(self):
1428 # Move a file to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001429 self.test_move_file_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001430
1431 def test_move_dir(self):
1432 # Move a dir to another location on the same filesystem.
1433 dst_dir = tempfile.mktemp()
1434 try:
1435 self._check_move_dir(self.src_dir, dst_dir, dst_dir)
1436 finally:
1437 try:
1438 shutil.rmtree(dst_dir)
1439 except:
1440 pass
1441
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001442 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001443 def test_move_dir_other_fs(self):
1444 # Move a dir to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001445 self.test_move_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001446
1447 def test_move_dir_to_dir(self):
1448 # Move a dir inside an existing dir on the same filesystem.
1449 self._check_move_dir(self.src_dir, self.dst_dir,
1450 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1451
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001452 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001453 def test_move_dir_to_dir_other_fs(self):
1454 # Move a dir inside an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001455 self.test_move_dir_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001456
1457 def test_existing_file_inside_dest_dir(self):
1458 # A file with the same name inside the destination dir already exists.
1459 with open(self.dst_file, "wb"):
1460 pass
1461 self.assertRaises(shutil.Error, shutil.move, self.src_file, self.dst_dir)
1462
1463 def test_dont_move_dir_in_itself(self):
1464 # Moving a dir inside itself raises an Error.
1465 dst = os.path.join(self.src_dir, "bar")
1466 self.assertRaises(shutil.Error, shutil.move, self.src_dir, dst)
1467
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001468 def test_destinsrc_false_negative(self):
1469 os.mkdir(TESTFN)
1470 try:
1471 for src, dst in [('srcdir', 'srcdir/dest')]:
1472 src = os.path.join(TESTFN, src)
1473 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001474 self.assertTrue(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001475 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001476 'dst (%s) is not in src (%s)' % (dst, src))
1477 finally:
1478 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001479
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001480 def test_destinsrc_false_positive(self):
1481 os.mkdir(TESTFN)
1482 try:
1483 for src, dst in [('srcdir', 'src/dest'), ('srcdir', 'srcdir.new')]:
1484 src = os.path.join(TESTFN, src)
1485 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001486 self.assertFalse(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001487 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001488 'dst (%s) is in src (%s)' % (dst, src))
1489 finally:
1490 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimes9bd667a2008-01-20 15:14:11 +00001491
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +01001492 @support.skip_unless_symlink
1493 @mock_rename
1494 def test_move_file_symlink(self):
1495 dst = os.path.join(self.src_dir, 'bar')
1496 os.symlink(self.src_file, dst)
1497 shutil.move(dst, self.dst_file)
1498 self.assertTrue(os.path.islink(self.dst_file))
1499 self.assertTrue(os.path.samefile(self.src_file, self.dst_file))
1500
1501 @support.skip_unless_symlink
1502 @mock_rename
1503 def test_move_file_symlink_to_dir(self):
1504 filename = "bar"
1505 dst = os.path.join(self.src_dir, filename)
1506 os.symlink(self.src_file, dst)
1507 shutil.move(dst, self.dst_dir)
1508 final_link = os.path.join(self.dst_dir, filename)
1509 self.assertTrue(os.path.islink(final_link))
1510 self.assertTrue(os.path.samefile(self.src_file, final_link))
1511
1512 @support.skip_unless_symlink
1513 @mock_rename
1514 def test_move_dangling_symlink(self):
1515 src = os.path.join(self.src_dir, 'baz')
1516 dst = os.path.join(self.src_dir, 'bar')
1517 os.symlink(src, dst)
1518 dst_link = os.path.join(self.dst_dir, 'quux')
1519 shutil.move(dst, dst_link)
1520 self.assertTrue(os.path.islink(dst_link))
1521 self.assertEqual(os.path.realpath(src), os.path.realpath(dst_link))
1522
1523 @support.skip_unless_symlink
1524 @mock_rename
1525 def test_move_dir_symlink(self):
1526 src = os.path.join(self.src_dir, 'baz')
1527 dst = os.path.join(self.src_dir, 'bar')
1528 os.mkdir(src)
1529 os.symlink(src, dst)
1530 dst_link = os.path.join(self.dst_dir, 'quux')
1531 shutil.move(dst, dst_link)
1532 self.assertTrue(os.path.islink(dst_link))
1533 self.assertTrue(os.path.samefile(src, dst_link))
1534
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001535 def test_move_return_value(self):
1536 rv = shutil.move(self.src_file, self.dst_dir)
1537 self.assertEqual(rv,
1538 os.path.join(self.dst_dir, os.path.basename(self.src_file)))
1539
1540 def test_move_as_rename_return_value(self):
1541 rv = shutil.move(self.src_file, os.path.join(self.dst_dir, 'bar'))
1542 self.assertEqual(rv, os.path.join(self.dst_dir, 'bar'))
1543
Tarek Ziadé5340db32010-04-19 22:30:51 +00001544
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001545class TestCopyFile(unittest.TestCase):
1546
1547 _delete = False
1548
1549 class Faux(object):
1550 _entered = False
1551 _exited_with = None
1552 _raised = False
1553 def __init__(self, raise_in_exit=False, suppress_at_exit=True):
1554 self._raise_in_exit = raise_in_exit
1555 self._suppress_at_exit = suppress_at_exit
1556 def read(self, *args):
1557 return ''
1558 def __enter__(self):
1559 self._entered = True
1560 def __exit__(self, exc_type, exc_val, exc_tb):
1561 self._exited_with = exc_type, exc_val, exc_tb
1562 if self._raise_in_exit:
1563 self._raised = True
1564 raise IOError("Cannot close")
1565 return self._suppress_at_exit
1566
1567 def tearDown(self):
1568 if self._delete:
1569 del shutil.open
1570
1571 def _set_shutil_open(self, func):
1572 shutil.open = func
1573 self._delete = True
1574
1575 def test_w_source_open_fails(self):
1576 def _open(filename, mode='r'):
1577 if filename == 'srcfile':
1578 raise IOError('Cannot open "srcfile"')
1579 assert 0 # shouldn't reach here.
1580
1581 self._set_shutil_open(_open)
1582
1583 self.assertRaises(IOError, shutil.copyfile, 'srcfile', 'destfile')
1584
1585 def test_w_dest_open_fails(self):
1586
1587 srcfile = self.Faux()
1588
1589 def _open(filename, mode='r'):
1590 if filename == 'srcfile':
1591 return srcfile
1592 if filename == 'destfile':
1593 raise IOError('Cannot open "destfile"')
1594 assert 0 # shouldn't reach here.
1595
1596 self._set_shutil_open(_open)
1597
1598 shutil.copyfile('srcfile', 'destfile')
1599 self.assertTrue(srcfile._entered)
1600 self.assertTrue(srcfile._exited_with[0] is IOError)
1601 self.assertEqual(srcfile._exited_with[1].args,
1602 ('Cannot open "destfile"',))
1603
1604 def test_w_dest_close_fails(self):
1605
1606 srcfile = self.Faux()
1607 destfile = self.Faux(True)
1608
1609 def _open(filename, mode='r'):
1610 if filename == 'srcfile':
1611 return srcfile
1612 if filename == 'destfile':
1613 return destfile
1614 assert 0 # shouldn't reach here.
1615
1616 self._set_shutil_open(_open)
1617
1618 shutil.copyfile('srcfile', 'destfile')
1619 self.assertTrue(srcfile._entered)
1620 self.assertTrue(destfile._entered)
1621 self.assertTrue(destfile._raised)
1622 self.assertTrue(srcfile._exited_with[0] is IOError)
1623 self.assertEqual(srcfile._exited_with[1].args,
1624 ('Cannot close',))
1625
1626 def test_w_source_close_fails(self):
1627
1628 srcfile = self.Faux(True)
1629 destfile = self.Faux()
1630
1631 def _open(filename, mode='r'):
1632 if filename == 'srcfile':
1633 return srcfile
1634 if filename == 'destfile':
1635 return destfile
1636 assert 0 # shouldn't reach here.
1637
1638 self._set_shutil_open(_open)
1639
1640 self.assertRaises(IOError,
1641 shutil.copyfile, 'srcfile', 'destfile')
1642 self.assertTrue(srcfile._entered)
1643 self.assertTrue(destfile._entered)
1644 self.assertFalse(destfile._raised)
1645 self.assertTrue(srcfile._exited_with[0] is None)
1646 self.assertTrue(srcfile._raised)
1647
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001648 def test_move_dir_caseinsensitive(self):
1649 # Renames a folder to the same name
1650 # but a different case.
1651
1652 self.src_dir = tempfile.mkdtemp()
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001653 self.addCleanup(shutil.rmtree, self.src_dir, True)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001654 dst_dir = os.path.join(
1655 os.path.dirname(self.src_dir),
1656 os.path.basename(self.src_dir).upper())
1657 self.assertNotEqual(self.src_dir, dst_dir)
1658
1659 try:
1660 shutil.move(self.src_dir, dst_dir)
1661 self.assertTrue(os.path.isdir(dst_dir))
1662 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +02001663 os.rmdir(dst_dir)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001664
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001665class TermsizeTests(unittest.TestCase):
1666 def test_does_not_crash(self):
1667 """Check if get_terminal_size() returns a meaningful value.
1668
1669 There's no easy portable way to actually check the size of the
1670 terminal, so let's check if it returns something sensible instead.
1671 """
1672 size = shutil.get_terminal_size()
Antoine Pitroucfade362012-02-08 23:48:59 +01001673 self.assertGreaterEqual(size.columns, 0)
1674 self.assertGreaterEqual(size.lines, 0)
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001675
1676 def test_os_environ_first(self):
1677 "Check if environment variables have precedence"
1678
1679 with support.EnvironmentVarGuard() as env:
1680 env['COLUMNS'] = '777'
1681 size = shutil.get_terminal_size()
1682 self.assertEqual(size.columns, 777)
1683
1684 with support.EnvironmentVarGuard() as env:
1685 env['LINES'] = '888'
1686 size = shutil.get_terminal_size()
1687 self.assertEqual(size.lines, 888)
1688
1689 @unittest.skipUnless(os.isatty(sys.__stdout__.fileno()), "not on tty")
1690 def test_stty_match(self):
1691 """Check if stty returns the same results ignoring env
1692
1693 This test will fail if stdin and stdout are connected to
1694 different terminals with different sizes. Nevertheless, such
1695 situations should be pretty rare.
1696 """
1697 try:
1698 size = subprocess.check_output(['stty', 'size']).decode().split()
1699 except (FileNotFoundError, subprocess.CalledProcessError):
1700 self.skipTest("stty invocation failed")
1701 expected = (int(size[1]), int(size[0])) # reversed order
1702
1703 with support.EnvironmentVarGuard() as env:
1704 del env['LINES']
1705 del env['COLUMNS']
1706 actual = shutil.get_terminal_size()
1707
1708 self.assertEqual(expected, actual)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001709
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001710
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001711def test_main():
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001712 support.run_unittest(TestShutil, TestMove, TestCopyFile,
Brian Curtinc57a3452012-06-22 16:00:30 -05001713 TermsizeTests, TestWhich)
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001714
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001715if __name__ == '__main__':
Walter Dörwald21d3a322003-05-01 17:45:56 +00001716 test_main()