blob: 5a78440580388be0d9f8b71147d71029a67acd12 [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 Schlawack48653762012-10-07 12:49:58 +020021 unregister_unpack_format, get_unpack_formats,
22 SameFileError)
Tarek Ziadé396fad72010-02-23 05:30:31 +000023import tarfile
24import warnings
25
26from test import support
Ezio Melotti975077a2011-05-19 22:03:22 +030027from test.support import TESTFN, check_warnings, captured_stdout, requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +000028
Tarek Ziadéffa155a2010-04-29 13:34:35 +000029try:
30 import bz2
31 BZ2_SUPPORTED = True
32except ImportError:
33 BZ2_SUPPORTED = False
34
Antoine Pitrou7fff0962009-05-01 21:09:44 +000035TESTFN2 = TESTFN + "2"
Barry Warsaw7fc2cca2003-01-24 17:34:13 +000036
Tarek Ziadé396fad72010-02-23 05:30:31 +000037try:
38 import grp
39 import pwd
40 UID_GID_SUPPORT = True
41except ImportError:
42 UID_GID_SUPPORT = False
43
44try:
Tarek Ziadé396fad72010-02-23 05:30:31 +000045 import zipfile
46 ZIP_SUPPORT = True
47except ImportError:
48 ZIP_SUPPORT = find_executable('zip')
49
Nick Coghlan8ed3cf32011-03-16 14:05:35 -040050def _fake_rename(*args, **kwargs):
51 # Pretend the destination path is on a different filesystem.
Antoine Pitrouc041ab62012-01-02 19:18:02 +010052 raise OSError(getattr(errno, 'EXDEV', 18), "Invalid cross-device link")
Nick Coghlan8ed3cf32011-03-16 14:05:35 -040053
54def mock_rename(func):
55 @functools.wraps(func)
56 def wrap(*args, **kwargs):
57 try:
58 builtin_rename = os.rename
59 os.rename = _fake_rename
60 return func(*args, **kwargs)
61 finally:
62 os.rename = builtin_rename
63 return wrap
64
Éric Araujoa7e33a12011-08-12 19:51:35 +020065def write_file(path, content, binary=False):
66 """Write *content* to a file located at *path*.
67
68 If *path* is a tuple instead of a string, os.path.join will be used to
69 make a path. If *binary* is true, the file will be opened in binary
70 mode.
71 """
72 if isinstance(path, tuple):
73 path = os.path.join(*path)
74 with open(path, 'wb' if binary else 'w') as fp:
75 fp.write(content)
76
77def read_file(path, binary=False):
78 """Return contents from a file located at *path*.
79
80 If *path* is a tuple instead of a string, os.path.join will be used to
81 make a path. If *binary* is true, the file will be opened in binary
82 mode.
83 """
84 if isinstance(path, tuple):
85 path = os.path.join(*path)
86 with open(path, 'rb' if binary else 'r') as fp:
87 return fp.read()
88
89
Barry Warsaw7fc2cca2003-01-24 17:34:13 +000090class TestShutil(unittest.TestCase):
Tarek Ziadé396fad72010-02-23 05:30:31 +000091
92 def setUp(self):
93 super(TestShutil, self).setUp()
94 self.tempdirs = []
95
96 def tearDown(self):
97 super(TestShutil, self).tearDown()
98 while self.tempdirs:
99 d = self.tempdirs.pop()
100 shutil.rmtree(d, os.name in ('nt', 'cygwin'))
101
Tarek Ziadé396fad72010-02-23 05:30:31 +0000102
103 def mkdtemp(self):
104 """Create a temporary directory that will be cleaned up.
105
106 Returns the path of the directory.
107 """
108 d = tempfile.mkdtemp()
109 self.tempdirs.append(d)
110 return d
Tarek Ziadé5340db32010-04-19 22:30:51 +0000111
Hynek Schlawack3b527782012-06-25 13:27:31 +0200112 def test_rmtree_works_on_bytes(self):
113 tmp = self.mkdtemp()
114 victim = os.path.join(tmp, 'killme')
115 os.mkdir(victim)
116 write_file(os.path.join(victim, 'somefile'), 'foo')
117 victim = os.fsencode(victim)
118 self.assertIsInstance(victim, bytes)
119 shutil.rmtree(victim)
120
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200121 @support.skip_unless_symlink
122 def test_rmtree_fails_on_symlink(self):
123 tmp = self.mkdtemp()
124 dir_ = os.path.join(tmp, 'dir')
125 os.mkdir(dir_)
126 link = os.path.join(tmp, 'link')
127 os.symlink(dir_, link)
128 self.assertRaises(OSError, shutil.rmtree, link)
129 self.assertTrue(os.path.exists(dir_))
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100130 self.assertTrue(os.path.lexists(link))
131 errors = []
132 def onerror(*args):
133 errors.append(args)
134 shutil.rmtree(link, onerror=onerror)
135 self.assertEqual(len(errors), 1)
136 self.assertIs(errors[0][0], os.path.islink)
137 self.assertEqual(errors[0][1], link)
138 self.assertIsInstance(errors[0][2][1], OSError)
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200139
140 @support.skip_unless_symlink
141 def test_rmtree_works_on_symlinks(self):
142 tmp = self.mkdtemp()
143 dir1 = os.path.join(tmp, 'dir1')
144 dir2 = os.path.join(dir1, 'dir2')
145 dir3 = os.path.join(tmp, 'dir3')
146 for d in dir1, dir2, dir3:
147 os.mkdir(d)
148 file1 = os.path.join(tmp, 'file1')
149 write_file(file1, 'foo')
150 link1 = os.path.join(dir1, 'link1')
151 os.symlink(dir2, link1)
152 link2 = os.path.join(dir1, 'link2')
153 os.symlink(dir3, link2)
154 link3 = os.path.join(dir1, 'link3')
155 os.symlink(file1, link3)
156 # make sure symlinks are removed but not followed
157 shutil.rmtree(dir1)
158 self.assertFalse(os.path.exists(dir1))
159 self.assertTrue(os.path.exists(dir3))
160 self.assertTrue(os.path.exists(file1))
161
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000162 def test_rmtree_errors(self):
163 # filename is guaranteed not to exist
164 filename = tempfile.mktemp()
Hynek Schlawackb5501102012-12-10 09:11:25 +0100165 self.assertRaises(FileNotFoundError, shutil.rmtree, filename)
166 # test that ignore_errors option is honored
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100167 shutil.rmtree(filename, ignore_errors=True)
168
169 # existing file
170 tmpdir = self.mkdtemp()
Hynek Schlawackb5501102012-12-10 09:11:25 +0100171 write_file((tmpdir, "tstfile"), "")
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100172 filename = os.path.join(tmpdir, "tstfile")
Hynek Schlawackb5501102012-12-10 09:11:25 +0100173 with self.assertRaises(NotADirectoryError) as cm:
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100174 shutil.rmtree(filename)
Hynek Schlawack87f9b462012-12-10 16:29:57 +0100175 # The reason for this rather odd construct is that Windows sprinkles
176 # a \*.* at the end of file names. But only sometimes on some buildbots
177 possible_args = [filename, os.path.join(filename, '*.*')]
178 self.assertIn(cm.exception.filename, possible_args)
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100179 self.assertTrue(os.path.exists(filename))
Hynek Schlawackb5501102012-12-10 09:11:25 +0100180 # test that ignore_errors option is honored
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100181 shutil.rmtree(filename, ignore_errors=True)
182 self.assertTrue(os.path.exists(filename))
183 errors = []
184 def onerror(*args):
185 errors.append(args)
186 shutil.rmtree(filename, onerror=onerror)
187 self.assertEqual(len(errors), 2)
188 self.assertIs(errors[0][0], os.listdir)
189 self.assertEqual(errors[0][1], filename)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100190 self.assertIsInstance(errors[0][2][1], NotADirectoryError)
Hynek Schlawack87f9b462012-12-10 16:29:57 +0100191 self.assertIn(errors[0][2][1].filename, possible_args)
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100192 self.assertIs(errors[1][0], os.rmdir)
193 self.assertEqual(errors[1][1], filename)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100194 self.assertIsInstance(errors[1][2][1], NotADirectoryError)
Hynek Schlawack87f9b462012-12-10 16:29:57 +0100195 self.assertIn(errors[1][2][1].filename, possible_args)
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000196
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000197
Johannes Gijsbersb8b09d02004-12-06 20:50:15 +0000198 # See bug #1071513 for why we don't run this on cygwin
199 # and bug #1076467 for why we don't run this as root.
200 if (hasattr(os, 'chmod') and sys.platform[:6] != 'cygwin'
Johannes Gijsbers6b220b02004-12-12 15:52:57 +0000201 and not (hasattr(os, 'geteuid') and os.geteuid() == 0)):
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000202 def test_on_error(self):
203 self.errorState = 0
204 os.mkdir(TESTFN)
Antoine Pitrou2f8a75c2012-06-23 21:28:15 +0200205 self.addCleanup(shutil.rmtree, TESTFN)
206
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200207 self.child_file_path = os.path.join(TESTFN, 'a')
208 self.child_dir_path = os.path.join(TESTFN, 'b')
209 support.create_empty_file(self.child_file_path)
210 os.mkdir(self.child_dir_path)
Tim Peters4590c002004-11-01 02:40:52 +0000211 old_dir_mode = os.stat(TESTFN).st_mode
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200212 old_child_file_mode = os.stat(self.child_file_path).st_mode
213 old_child_dir_mode = os.stat(self.child_dir_path).st_mode
Tim Peters4590c002004-11-01 02:40:52 +0000214 # Make unwritable.
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200215 new_mode = stat.S_IREAD|stat.S_IEXEC
216 os.chmod(self.child_file_path, new_mode)
217 os.chmod(self.child_dir_path, new_mode)
218 os.chmod(TESTFN, new_mode)
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000219
Antoine Pitrou2f8a75c2012-06-23 21:28:15 +0200220 self.addCleanup(os.chmod, TESTFN, old_dir_mode)
221 self.addCleanup(os.chmod, self.child_file_path, old_child_file_mode)
222 self.addCleanup(os.chmod, self.child_dir_path, old_child_dir_mode)
223
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000224 shutil.rmtree(TESTFN, onerror=self.check_args_to_onerror)
Johannes Gijsbers8e6f2de2004-11-23 09:27:27 +0000225 # Test whether onerror has actually been called.
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200226 self.assertEqual(self.errorState, 3,
227 "Expected call to onerror function did not "
228 "happen.")
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000229
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000230 def check_args_to_onerror(self, func, arg, exc):
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000231 # test_rmtree_errors deliberately runs rmtree
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200232 # on a directory that is chmod 500, which will fail.
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000233 # This function is run when shutil.rmtree fails.
234 # 99.9% of the time it initially fails to remove
235 # a file in the directory, so the first time through
236 # func is os.remove.
237 # However, some Linux machines running ZFS on
238 # FUSE experienced a failure earlier in the process
239 # at os.listdir. The first failure may legally
240 # be either.
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200241 if self.errorState < 2:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200242 if func is os.unlink:
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200243 self.assertEqual(arg, self.child_file_path)
244 elif func is os.rmdir:
245 self.assertEqual(arg, self.child_dir_path)
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000246 else:
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200247 self.assertIs(func, os.listdir)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200248 self.assertIn(arg, [TESTFN, self.child_dir_path])
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000249 self.assertTrue(issubclass(exc[0], OSError))
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200250 self.errorState += 1
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000251 else:
252 self.assertEqual(func, os.rmdir)
253 self.assertEqual(arg, TESTFN)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000254 self.assertTrue(issubclass(exc[0], OSError))
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200255 self.errorState = 3
256
257 def test_rmtree_does_not_choke_on_failing_lstat(self):
258 try:
259 orig_lstat = os.lstat
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200260 def raiser(fn, *args, **kwargs):
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200261 if fn != TESTFN:
262 raise OSError()
263 else:
264 return orig_lstat(fn)
265 os.lstat = raiser
266
267 os.mkdir(TESTFN)
268 write_file((TESTFN, 'foo'), 'foo')
269 shutil.rmtree(TESTFN)
270 finally:
271 os.lstat = orig_lstat
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000272
Antoine Pitrou78091e62011-12-29 18:54:15 +0100273 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
274 @support.skip_unless_symlink
275 def test_copymode_follow_symlinks(self):
276 tmp_dir = self.mkdtemp()
277 src = os.path.join(tmp_dir, 'foo')
278 dst = os.path.join(tmp_dir, 'bar')
279 src_link = os.path.join(tmp_dir, 'baz')
280 dst_link = os.path.join(tmp_dir, 'quux')
281 write_file(src, 'foo')
282 write_file(dst, 'foo')
283 os.symlink(src, src_link)
284 os.symlink(dst, dst_link)
285 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
286 # file to file
287 os.chmod(dst, stat.S_IRWXO)
288 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
289 shutil.copymode(src, dst)
290 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
291 # follow src link
292 os.chmod(dst, stat.S_IRWXO)
293 shutil.copymode(src_link, dst)
294 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
295 # follow dst link
296 os.chmod(dst, stat.S_IRWXO)
297 shutil.copymode(src, dst_link)
298 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
299 # follow both links
300 os.chmod(dst, stat.S_IRWXO)
301 shutil.copymode(src_link, dst)
302 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
303
304 @unittest.skipUnless(hasattr(os, 'lchmod'), 'requires os.lchmod')
305 @support.skip_unless_symlink
306 def test_copymode_symlink_to_symlink(self):
307 tmp_dir = self.mkdtemp()
308 src = os.path.join(tmp_dir, 'foo')
309 dst = os.path.join(tmp_dir, 'bar')
310 src_link = os.path.join(tmp_dir, 'baz')
311 dst_link = os.path.join(tmp_dir, 'quux')
312 write_file(src, 'foo')
313 write_file(dst, 'foo')
314 os.symlink(src, src_link)
315 os.symlink(dst, dst_link)
316 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
317 os.chmod(dst, stat.S_IRWXU)
318 os.lchmod(src_link, stat.S_IRWXO|stat.S_IRWXG)
319 # link to link
320 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700321 shutil.copymode(src_link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100322 self.assertEqual(os.lstat(src_link).st_mode,
323 os.lstat(dst_link).st_mode)
324 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
325 # src link - use chmod
326 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700327 shutil.copymode(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100328 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
329 # dst link - use chmod
330 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700331 shutil.copymode(src, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100332 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
333
334 @unittest.skipIf(hasattr(os, 'lchmod'), 'requires os.lchmod to be missing')
335 @support.skip_unless_symlink
336 def test_copymode_symlink_to_symlink_wo_lchmod(self):
337 tmp_dir = self.mkdtemp()
338 src = os.path.join(tmp_dir, 'foo')
339 dst = os.path.join(tmp_dir, 'bar')
340 src_link = os.path.join(tmp_dir, 'baz')
341 dst_link = os.path.join(tmp_dir, 'quux')
342 write_file(src, 'foo')
343 write_file(dst, 'foo')
344 os.symlink(src, src_link)
345 os.symlink(dst, dst_link)
Larry Hastingsb4038062012-07-15 10:57:38 -0700346 shutil.copymode(src_link, dst_link, follow_symlinks=False) # silent fail
Antoine Pitrou78091e62011-12-29 18:54:15 +0100347
348 @support.skip_unless_symlink
349 def test_copystat_symlinks(self):
350 tmp_dir = self.mkdtemp()
351 src = os.path.join(tmp_dir, 'foo')
352 dst = os.path.join(tmp_dir, 'bar')
353 src_link = os.path.join(tmp_dir, 'baz')
354 dst_link = os.path.join(tmp_dir, 'qux')
355 write_file(src, 'foo')
356 src_stat = os.stat(src)
357 os.utime(src, (src_stat.st_atime,
358 src_stat.st_mtime - 42.0)) # ensure different mtimes
359 write_file(dst, 'bar')
360 self.assertNotEqual(os.stat(src).st_mtime, os.stat(dst).st_mtime)
361 os.symlink(src, src_link)
362 os.symlink(dst, dst_link)
363 if hasattr(os, 'lchmod'):
364 os.lchmod(src_link, stat.S_IRWXO)
365 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
366 os.lchflags(src_link, stat.UF_NODUMP)
367 src_link_stat = os.lstat(src_link)
368 # follow
369 if hasattr(os, 'lchmod'):
Larry Hastingsb4038062012-07-15 10:57:38 -0700370 shutil.copystat(src_link, dst_link, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100371 self.assertNotEqual(src_link_stat.st_mode, os.stat(dst).st_mode)
372 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700373 shutil.copystat(src_link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100374 dst_link_stat = os.lstat(dst_link)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700375 if os.utime in os.supports_follow_symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100376 for attr in 'st_atime', 'st_mtime':
377 # The modification times may be truncated in the new file.
378 self.assertLessEqual(getattr(src_link_stat, attr),
379 getattr(dst_link_stat, attr) + 1)
380 if hasattr(os, 'lchmod'):
381 self.assertEqual(src_link_stat.st_mode, dst_link_stat.st_mode)
382 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
383 self.assertEqual(src_link_stat.st_flags, dst_link_stat.st_flags)
384 # tell to follow but dst is not a link
Larry Hastingsb4038062012-07-15 10:57:38 -0700385 shutil.copystat(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100386 self.assertTrue(abs(os.stat(src).st_mtime - os.stat(dst).st_mtime) <
387 00000.1)
388
Ned Deilybaf75712012-05-10 17:05:19 -0700389 @unittest.skipUnless(hasattr(os, 'chflags') and
390 hasattr(errno, 'EOPNOTSUPP') and
391 hasattr(errno, 'ENOTSUP'),
392 "requires os.chflags, EOPNOTSUPP & ENOTSUP")
393 def test_copystat_handles_harmless_chflags_errors(self):
394 tmpdir = self.mkdtemp()
395 file1 = os.path.join(tmpdir, 'file1')
396 file2 = os.path.join(tmpdir, 'file2')
397 write_file(file1, 'xxx')
398 write_file(file2, 'xxx')
399
400 def make_chflags_raiser(err):
401 ex = OSError()
402
Larry Hastings90867a52012-06-22 17:01:41 -0700403 def _chflags_raiser(path, flags, *, follow_symlinks=True):
Ned Deilybaf75712012-05-10 17:05:19 -0700404 ex.errno = err
405 raise ex
406 return _chflags_raiser
407 old_chflags = os.chflags
408 try:
409 for err in errno.EOPNOTSUPP, errno.ENOTSUP:
410 os.chflags = make_chflags_raiser(err)
411 shutil.copystat(file1, file2)
412 # assert others errors break it
413 os.chflags = make_chflags_raiser(errno.EOPNOTSUPP + errno.ENOTSUP)
414 self.assertRaises(OSError, shutil.copystat, file1, file2)
415 finally:
416 os.chflags = old_chflags
417
Antoine Pitrou424246f2012-05-12 19:02:01 +0200418 @support.skip_unless_xattr
419 def test_copyxattr(self):
420 tmp_dir = self.mkdtemp()
421 src = os.path.join(tmp_dir, 'foo')
422 write_file(src, 'foo')
423 dst = os.path.join(tmp_dir, 'bar')
424 write_file(dst, 'bar')
425
426 # no xattr == no problem
427 shutil._copyxattr(src, dst)
428 # common case
429 os.setxattr(src, 'user.foo', b'42')
430 os.setxattr(src, 'user.bar', b'43')
431 shutil._copyxattr(src, dst)
432 self.assertEqual(os.listxattr(src), os.listxattr(dst))
433 self.assertEqual(
434 os.getxattr(src, 'user.foo'),
435 os.getxattr(dst, 'user.foo'))
436 # check errors don't affect other attrs
437 os.remove(dst)
438 write_file(dst, 'bar')
439 os_error = OSError(errno.EPERM, 'EPERM')
440
Larry Hastings9cf065c2012-06-22 16:30:09 -0700441 def _raise_on_user_foo(fname, attr, val, **kwargs):
Antoine Pitrou424246f2012-05-12 19:02:01 +0200442 if attr == 'user.foo':
443 raise os_error
444 else:
Larry Hastings9cf065c2012-06-22 16:30:09 -0700445 orig_setxattr(fname, attr, val, **kwargs)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200446 try:
447 orig_setxattr = os.setxattr
448 os.setxattr = _raise_on_user_foo
449 shutil._copyxattr(src, dst)
Antoine Pitrou61597d32012-05-12 23:37:35 +0200450 self.assertIn('user.bar', os.listxattr(dst))
Antoine Pitrou424246f2012-05-12 19:02:01 +0200451 finally:
452 os.setxattr = orig_setxattr
Hynek Schlawack0beab052013-02-05 08:22:44 +0100453 # the source filesystem not supporting xattrs should be ok, too.
454 def _raise_on_src(fname, *, follow_symlinks=True):
455 if fname == src:
456 raise OSError(errno.ENOTSUP, 'Operation not supported')
457 return orig_listxattr(fname, follow_symlinks=follow_symlinks)
458 try:
459 orig_listxattr = os.listxattr
460 os.listxattr = _raise_on_src
461 shutil._copyxattr(src, dst)
462 finally:
463 os.listxattr = orig_listxattr
Antoine Pitrou424246f2012-05-12 19:02:01 +0200464
Larry Hastingsad5ae042012-07-14 17:55:11 -0700465 # test that shutil.copystat copies xattrs
466 src = os.path.join(tmp_dir, 'the_original')
467 write_file(src, src)
468 os.setxattr(src, 'user.the_value', b'fiddly')
469 dst = os.path.join(tmp_dir, 'the_copy')
470 write_file(dst, dst)
471 shutil.copystat(src, dst)
Hynek Schlawackc2d481f2012-07-16 17:11:10 +0200472 self.assertEqual(os.getxattr(dst, 'user.the_value'), b'fiddly')
Larry Hastingsad5ae042012-07-14 17:55:11 -0700473
Antoine Pitrou424246f2012-05-12 19:02:01 +0200474 @support.skip_unless_symlink
475 @support.skip_unless_xattr
476 @unittest.skipUnless(hasattr(os, 'geteuid') and os.geteuid() == 0,
477 'root privileges required')
478 def test_copyxattr_symlinks(self):
479 # On Linux, it's only possible to access non-user xattr for symlinks;
480 # which in turn require root privileges. This test should be expanded
481 # as soon as other platforms gain support for extended attributes.
482 tmp_dir = self.mkdtemp()
483 src = os.path.join(tmp_dir, 'foo')
484 src_link = os.path.join(tmp_dir, 'baz')
485 write_file(src, 'foo')
486 os.symlink(src, src_link)
487 os.setxattr(src, 'trusted.foo', b'42')
Larry Hastings9cf065c2012-06-22 16:30:09 -0700488 os.setxattr(src_link, 'trusted.foo', b'43', follow_symlinks=False)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200489 dst = os.path.join(tmp_dir, 'bar')
490 dst_link = os.path.join(tmp_dir, 'qux')
491 write_file(dst, 'bar')
492 os.symlink(dst, dst_link)
Larry Hastingsb4038062012-07-15 10:57:38 -0700493 shutil._copyxattr(src_link, dst_link, follow_symlinks=False)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700494 self.assertEqual(os.getxattr(dst_link, 'trusted.foo', follow_symlinks=False), b'43')
Antoine Pitrou424246f2012-05-12 19:02:01 +0200495 self.assertRaises(OSError, os.getxattr, dst, 'trusted.foo')
Larry Hastingsb4038062012-07-15 10:57:38 -0700496 shutil._copyxattr(src_link, dst, follow_symlinks=False)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200497 self.assertEqual(os.getxattr(dst, 'trusted.foo'), b'43')
498
Antoine Pitrou78091e62011-12-29 18:54:15 +0100499 @support.skip_unless_symlink
500 def test_copy_symlinks(self):
501 tmp_dir = self.mkdtemp()
502 src = os.path.join(tmp_dir, 'foo')
503 dst = os.path.join(tmp_dir, 'bar')
504 src_link = os.path.join(tmp_dir, 'baz')
505 write_file(src, 'foo')
506 os.symlink(src, src_link)
507 if hasattr(os, 'lchmod'):
508 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
509 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700510 shutil.copy(src_link, dst, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100511 self.assertFalse(os.path.islink(dst))
512 self.assertEqual(read_file(src), read_file(dst))
513 os.remove(dst)
514 # follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700515 shutil.copy(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100516 self.assertTrue(os.path.islink(dst))
517 self.assertEqual(os.readlink(dst), os.readlink(src_link))
518 if hasattr(os, 'lchmod'):
519 self.assertEqual(os.lstat(src_link).st_mode,
520 os.lstat(dst).st_mode)
521
522 @support.skip_unless_symlink
523 def test_copy2_symlinks(self):
524 tmp_dir = self.mkdtemp()
525 src = os.path.join(tmp_dir, 'foo')
526 dst = os.path.join(tmp_dir, 'bar')
527 src_link = os.path.join(tmp_dir, 'baz')
528 write_file(src, 'foo')
529 os.symlink(src, src_link)
530 if hasattr(os, 'lchmod'):
531 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
532 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
533 os.lchflags(src_link, stat.UF_NODUMP)
534 src_stat = os.stat(src)
535 src_link_stat = os.lstat(src_link)
536 # follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700537 shutil.copy2(src_link, dst, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100538 self.assertFalse(os.path.islink(dst))
539 self.assertEqual(read_file(src), read_file(dst))
540 os.remove(dst)
541 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700542 shutil.copy2(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100543 self.assertTrue(os.path.islink(dst))
544 self.assertEqual(os.readlink(dst), os.readlink(src_link))
545 dst_stat = os.lstat(dst)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700546 if os.utime in os.supports_follow_symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100547 for attr in 'st_atime', 'st_mtime':
548 # The modification times may be truncated in the new file.
549 self.assertLessEqual(getattr(src_link_stat, attr),
550 getattr(dst_stat, attr) + 1)
551 if hasattr(os, 'lchmod'):
552 self.assertEqual(src_link_stat.st_mode, dst_stat.st_mode)
553 self.assertNotEqual(src_stat.st_mode, dst_stat.st_mode)
554 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
555 self.assertEqual(src_link_stat.st_flags, dst_stat.st_flags)
556
Antoine Pitrou424246f2012-05-12 19:02:01 +0200557 @support.skip_unless_xattr
558 def test_copy2_xattr(self):
559 tmp_dir = self.mkdtemp()
560 src = os.path.join(tmp_dir, 'foo')
561 dst = os.path.join(tmp_dir, 'bar')
562 write_file(src, 'foo')
563 os.setxattr(src, 'user.foo', b'42')
564 shutil.copy2(src, dst)
565 self.assertEqual(
566 os.getxattr(src, 'user.foo'),
567 os.getxattr(dst, 'user.foo'))
568 os.remove(dst)
569
Antoine Pitrou78091e62011-12-29 18:54:15 +0100570 @support.skip_unless_symlink
571 def test_copyfile_symlinks(self):
572 tmp_dir = self.mkdtemp()
573 src = os.path.join(tmp_dir, 'src')
574 dst = os.path.join(tmp_dir, 'dst')
575 dst_link = os.path.join(tmp_dir, 'dst_link')
576 link = os.path.join(tmp_dir, 'link')
577 write_file(src, 'foo')
578 os.symlink(src, link)
579 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700580 shutil.copyfile(link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100581 self.assertTrue(os.path.islink(dst_link))
582 self.assertEqual(os.readlink(link), os.readlink(dst_link))
583 # follow
584 shutil.copyfile(link, dst)
585 self.assertFalse(os.path.islink(dst))
586
Hynek Schlawack2100b422012-06-23 20:28:32 +0200587 def test_rmtree_uses_safe_fd_version_if_available(self):
Hynek Schlawackd0f6e0a2012-06-29 08:28:20 +0200588 _use_fd_functions = ({os.open, os.stat, os.unlink, os.rmdir} <=
589 os.supports_dir_fd and
590 os.listdir in os.supports_fd and
591 os.stat in os.supports_follow_symlinks)
592 if _use_fd_functions:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200593 self.assertTrue(shutil._use_fd_functions)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000594 self.assertTrue(shutil.rmtree.avoids_symlink_attacks)
Hynek Schlawack2100b422012-06-23 20:28:32 +0200595 tmp_dir = self.mkdtemp()
596 d = os.path.join(tmp_dir, 'a')
597 os.mkdir(d)
598 try:
599 real_rmtree = shutil._rmtree_safe_fd
600 class Called(Exception): pass
601 def _raiser(*args, **kwargs):
602 raise Called
603 shutil._rmtree_safe_fd = _raiser
604 self.assertRaises(Called, shutil.rmtree, d)
605 finally:
606 shutil._rmtree_safe_fd = real_rmtree
607 else:
608 self.assertFalse(shutil._use_fd_functions)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000609 self.assertFalse(shutil.rmtree.avoids_symlink_attacks)
Hynek Schlawack2100b422012-06-23 20:28:32 +0200610
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000611 def test_rmtree_dont_delete_file(self):
612 # When called on a file instead of a directory, don't delete it.
613 handle, path = tempfile.mkstemp()
Victor Stinnerbf816222011-06-30 23:25:47 +0200614 os.close(handle)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200615 self.assertRaises(NotADirectoryError, shutil.rmtree, path)
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000616 os.remove(path)
617
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000618 def test_copytree_simple(self):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000619 src_dir = tempfile.mkdtemp()
620 dst_dir = os.path.join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200621 self.addCleanup(shutil.rmtree, src_dir)
622 self.addCleanup(shutil.rmtree, os.path.dirname(dst_dir))
623 write_file((src_dir, 'test.txt'), '123')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000624 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200625 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000626
Éric Araujoa7e33a12011-08-12 19:51:35 +0200627 shutil.copytree(src_dir, dst_dir)
628 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test.txt')))
629 self.assertTrue(os.path.isdir(os.path.join(dst_dir, 'test_dir')))
630 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test_dir',
631 'test.txt')))
632 actual = read_file((dst_dir, 'test.txt'))
633 self.assertEqual(actual, '123')
634 actual = read_file((dst_dir, 'test_dir', 'test.txt'))
635 self.assertEqual(actual, '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000636
Antoine Pitrou78091e62011-12-29 18:54:15 +0100637 @support.skip_unless_symlink
638 def test_copytree_symlinks(self):
639 tmp_dir = self.mkdtemp()
640 src_dir = os.path.join(tmp_dir, 'src')
641 dst_dir = os.path.join(tmp_dir, 'dst')
642 sub_dir = os.path.join(src_dir, 'sub')
643 os.mkdir(src_dir)
644 os.mkdir(sub_dir)
645 write_file((src_dir, 'file.txt'), 'foo')
646 src_link = os.path.join(sub_dir, 'link')
647 dst_link = os.path.join(dst_dir, 'sub/link')
648 os.symlink(os.path.join(src_dir, 'file.txt'),
649 src_link)
650 if hasattr(os, 'lchmod'):
651 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
652 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
653 os.lchflags(src_link, stat.UF_NODUMP)
654 src_stat = os.lstat(src_link)
655 shutil.copytree(src_dir, dst_dir, symlinks=True)
656 self.assertTrue(os.path.islink(os.path.join(dst_dir, 'sub', 'link')))
657 self.assertEqual(os.readlink(os.path.join(dst_dir, 'sub', 'link')),
658 os.path.join(src_dir, 'file.txt'))
659 dst_stat = os.lstat(dst_link)
660 if hasattr(os, 'lchmod'):
661 self.assertEqual(dst_stat.st_mode, src_stat.st_mode)
662 if hasattr(os, 'lchflags'):
663 self.assertEqual(dst_stat.st_flags, src_stat.st_flags)
664
Georg Brandl2ee470f2008-07-16 12:55:28 +0000665 def test_copytree_with_exclude(self):
Georg Brandl2ee470f2008-07-16 12:55:28 +0000666 # creating data
667 join = os.path.join
668 exists = os.path.exists
669 src_dir = tempfile.mkdtemp()
Georg Brandl2ee470f2008-07-16 12:55:28 +0000670 try:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000671 dst_dir = join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200672 write_file((src_dir, 'test.txt'), '123')
673 write_file((src_dir, 'test.tmp'), '123')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000674 os.mkdir(join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200675 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000676 os.mkdir(join(src_dir, 'test_dir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200677 write_file((src_dir, 'test_dir2', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000678 os.mkdir(join(src_dir, 'test_dir2', 'subdir'))
679 os.mkdir(join(src_dir, 'test_dir2', 'subdir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200680 write_file((src_dir, 'test_dir2', 'subdir', 'test.txt'), '456')
681 write_file((src_dir, 'test_dir2', 'subdir2', 'test.py'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000682
683 # testing glob-like patterns
684 try:
685 patterns = shutil.ignore_patterns('*.tmp', 'test_dir2')
686 shutil.copytree(src_dir, dst_dir, ignore=patterns)
687 # checking the result: some elements should not be copied
688 self.assertTrue(exists(join(dst_dir, 'test.txt')))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200689 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
690 self.assertFalse(exists(join(dst_dir, 'test_dir2')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000691 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200692 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000693 try:
694 patterns = shutil.ignore_patterns('*.tmp', 'subdir*')
695 shutil.copytree(src_dir, dst_dir, ignore=patterns)
696 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200697 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
698 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2')))
699 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000700 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200701 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000702
703 # testing callable-style
704 try:
705 def _filter(src, names):
706 res = []
707 for name in names:
708 path = os.path.join(src, name)
709
710 if (os.path.isdir(path) and
711 path.split()[-1] == 'subdir'):
712 res.append(name)
713 elif os.path.splitext(path)[-1] in ('.py'):
714 res.append(name)
715 return res
716
717 shutil.copytree(src_dir, dst_dir, ignore=_filter)
718
719 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200720 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2',
721 'test.py')))
722 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000723
724 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200725 shutil.rmtree(dst_dir)
Georg Brandl2ee470f2008-07-16 12:55:28 +0000726 finally:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000727 shutil.rmtree(src_dir)
728 shutil.rmtree(os.path.dirname(dst_dir))
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000729
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000730 @unittest.skipUnless(hasattr(os, 'link'), 'requires os.link')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000731 def test_dont_copy_file_onto_link_to_itself(self):
Georg Brandl724d0892010-12-05 07:51:39 +0000732 # Temporarily disable test on Windows.
733 if os.name == 'nt':
734 return
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000735 # bug 851123.
736 os.mkdir(TESTFN)
737 src = os.path.join(TESTFN, 'cheese')
738 dst = os.path.join(TESTFN, 'shop')
739 try:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000740 with open(src, 'w') as f:
741 f.write('cheddar')
742 os.link(src, dst)
Hynek Schlawack48653762012-10-07 12:49:58 +0200743 self.assertRaises(shutil.SameFileError, shutil.copyfile, src, dst)
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000744 with open(src, 'r') as f:
745 self.assertEqual(f.read(), 'cheddar')
746 os.remove(dst)
747 finally:
748 shutil.rmtree(TESTFN, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000749
Brian Curtin3b4499c2010-12-28 14:31:47 +0000750 @support.skip_unless_symlink
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000751 def test_dont_copy_file_onto_symlink_to_itself(self):
752 # bug 851123.
753 os.mkdir(TESTFN)
754 src = os.path.join(TESTFN, 'cheese')
755 dst = os.path.join(TESTFN, 'shop')
756 try:
757 with open(src, 'w') as f:
758 f.write('cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000759 # Using `src` here would mean we end up with a symlink pointing
760 # to TESTFN/TESTFN/cheese, while it should point at
761 # TESTFN/cheese.
762 os.symlink('cheese', dst)
Hynek Schlawack48653762012-10-07 12:49:58 +0200763 self.assertRaises(shutil.SameFileError, shutil.copyfile, src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +0000764 with open(src, 'r') as f:
765 self.assertEqual(f.read(), 'cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000766 os.remove(dst)
767 finally:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000768 shutil.rmtree(TESTFN, ignore_errors=True)
Johannes Gijsbers68128712004-08-14 13:57:08 +0000769
Brian Curtin3b4499c2010-12-28 14:31:47 +0000770 @support.skip_unless_symlink
Brian Curtind40e6f72010-07-08 21:39:08 +0000771 def test_rmtree_on_symlink(self):
772 # bug 1669.
773 os.mkdir(TESTFN)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000774 try:
Brian Curtind40e6f72010-07-08 21:39:08 +0000775 src = os.path.join(TESTFN, 'cheese')
776 dst = os.path.join(TESTFN, 'shop')
777 os.mkdir(src)
778 os.symlink(src, dst)
779 self.assertRaises(OSError, shutil.rmtree, dst)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200780 shutil.rmtree(dst, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000781 finally:
Brian Curtind40e6f72010-07-08 21:39:08 +0000782 shutil.rmtree(TESTFN, ignore_errors=True)
783
784 if hasattr(os, "mkfifo"):
785 # Issue #3002: copyfile and copytree block indefinitely on named pipes
786 def test_copyfile_named_pipe(self):
787 os.mkfifo(TESTFN)
788 try:
789 self.assertRaises(shutil.SpecialFileError,
790 shutil.copyfile, TESTFN, TESTFN2)
791 self.assertRaises(shutil.SpecialFileError,
792 shutil.copyfile, __file__, TESTFN)
793 finally:
794 os.remove(TESTFN)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000795
Brian Curtin3b4499c2010-12-28 14:31:47 +0000796 @support.skip_unless_symlink
Brian Curtin52173d42010-12-02 18:29:18 +0000797 def test_copytree_named_pipe(self):
798 os.mkdir(TESTFN)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000799 try:
Brian Curtin52173d42010-12-02 18:29:18 +0000800 subdir = os.path.join(TESTFN, "subdir")
801 os.mkdir(subdir)
802 pipe = os.path.join(subdir, "mypipe")
803 os.mkfifo(pipe)
804 try:
805 shutil.copytree(TESTFN, TESTFN2)
806 except shutil.Error as e:
807 errors = e.args[0]
808 self.assertEqual(len(errors), 1)
809 src, dst, error_msg = errors[0]
810 self.assertEqual("`%s` is a named pipe" % pipe, error_msg)
811 else:
812 self.fail("shutil.Error should have been raised")
813 finally:
814 shutil.rmtree(TESTFN, ignore_errors=True)
815 shutil.rmtree(TESTFN2, ignore_errors=True)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000816
Tarek Ziadé5340db32010-04-19 22:30:51 +0000817 def test_copytree_special_func(self):
818
819 src_dir = self.mkdtemp()
820 dst_dir = os.path.join(self.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200821 write_file((src_dir, 'test.txt'), '123')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000822 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200823 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000824
825 copied = []
826 def _copy(src, dst):
827 copied.append((src, dst))
828
829 shutil.copytree(src_dir, dst_dir, copy_function=_copy)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000830 self.assertEqual(len(copied), 2)
Tarek Ziadé5340db32010-04-19 22:30:51 +0000831
Brian Curtin3b4499c2010-12-28 14:31:47 +0000832 @support.skip_unless_symlink
Tarek Ziadéfb437512010-04-20 08:57:33 +0000833 def test_copytree_dangling_symlinks(self):
834
835 # a dangling symlink raises an error at the end
836 src_dir = self.mkdtemp()
837 dst_dir = os.path.join(self.mkdtemp(), 'destination')
838 os.symlink('IDONTEXIST', os.path.join(src_dir, 'test.txt'))
839 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200840 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadéfb437512010-04-20 08:57:33 +0000841 self.assertRaises(Error, shutil.copytree, src_dir, dst_dir)
842
843 # a dangling symlink is ignored with the proper flag
844 dst_dir = os.path.join(self.mkdtemp(), 'destination2')
845 shutil.copytree(src_dir, dst_dir, ignore_dangling_symlinks=True)
846 self.assertNotIn('test.txt', os.listdir(dst_dir))
847
848 # a dangling symlink is copied if symlinks=True
849 dst_dir = os.path.join(self.mkdtemp(), 'destination3')
850 shutil.copytree(src_dir, dst_dir, symlinks=True)
851 self.assertIn('test.txt', os.listdir(dst_dir))
852
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400853 def _copy_file(self, method):
854 fname = 'test.txt'
855 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200856 write_file((tmpdir, fname), 'xxx')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400857 file1 = os.path.join(tmpdir, fname)
858 tmpdir2 = self.mkdtemp()
859 method(file1, tmpdir2)
860 file2 = os.path.join(tmpdir2, fname)
861 return (file1, file2)
862
863 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
864 def test_copy(self):
865 # Ensure that the copied file exists and has the same mode bits.
866 file1, file2 = self._copy_file(shutil.copy)
867 self.assertTrue(os.path.exists(file2))
868 self.assertEqual(os.stat(file1).st_mode, os.stat(file2).st_mode)
869
870 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
Senthil Kumaran0c2dba52011-07-03 18:21:38 -0700871 @unittest.skipUnless(hasattr(os, 'utime'), 'requires os.utime')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400872 def test_copy2(self):
873 # Ensure that the copied file exists and has the same mode and
874 # modification time bits.
875 file1, file2 = self._copy_file(shutil.copy2)
876 self.assertTrue(os.path.exists(file2))
877 file1_stat = os.stat(file1)
878 file2_stat = os.stat(file2)
879 self.assertEqual(file1_stat.st_mode, file2_stat.st_mode)
880 for attr in 'st_atime', 'st_mtime':
881 # The modification times may be truncated in the new file.
882 self.assertLessEqual(getattr(file1_stat, attr),
883 getattr(file2_stat, attr) + 1)
884 if hasattr(os, 'chflags') and hasattr(file1_stat, 'st_flags'):
885 self.assertEqual(getattr(file1_stat, 'st_flags'),
886 getattr(file2_stat, 'st_flags'))
887
Ezio Melotti975077a2011-05-19 22:03:22 +0300888 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000889 def test_make_tarball(self):
890 # creating something to tar
891 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200892 write_file((tmpdir, 'file1'), 'xxx')
893 write_file((tmpdir, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000894 os.mkdir(os.path.join(tmpdir, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200895 write_file((tmpdir, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000896
897 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400898 # force shutil to create the directory
899 os.rmdir(tmpdir2)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000900 unittest.skipUnless(splitdrive(tmpdir)[0] == splitdrive(tmpdir2)[0],
901 "source and target should be on same drive")
902
903 base_name = os.path.join(tmpdir2, 'archive')
904
905 # working with relative paths to avoid tar warnings
906 old_dir = os.getcwd()
907 os.chdir(tmpdir)
908 try:
909 _make_tarball(splitdrive(base_name)[1], '.')
910 finally:
911 os.chdir(old_dir)
912
913 # check if the compressed tarball was created
914 tarball = base_name + '.tar.gz'
915 self.assertTrue(os.path.exists(tarball))
916
917 # trying an uncompressed one
918 base_name = os.path.join(tmpdir2, 'archive')
919 old_dir = os.getcwd()
920 os.chdir(tmpdir)
921 try:
922 _make_tarball(splitdrive(base_name)[1], '.', compress=None)
923 finally:
924 os.chdir(old_dir)
925 tarball = base_name + '.tar'
926 self.assertTrue(os.path.exists(tarball))
927
928 def _tarinfo(self, path):
929 tar = tarfile.open(path)
930 try:
931 names = tar.getnames()
932 names.sort()
933 return tuple(names)
934 finally:
935 tar.close()
936
937 def _create_files(self):
938 # creating something to tar
939 tmpdir = self.mkdtemp()
940 dist = os.path.join(tmpdir, 'dist')
941 os.mkdir(dist)
Éric Araujoa7e33a12011-08-12 19:51:35 +0200942 write_file((dist, 'file1'), 'xxx')
943 write_file((dist, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000944 os.mkdir(os.path.join(dist, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200945 write_file((dist, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000946 os.mkdir(os.path.join(dist, 'sub2'))
947 tmpdir2 = self.mkdtemp()
948 base_name = os.path.join(tmpdir2, 'archive')
949 return tmpdir, tmpdir2, base_name
950
Ezio Melotti975077a2011-05-19 22:03:22 +0300951 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000952 @unittest.skipUnless(find_executable('tar') and find_executable('gzip'),
953 'Need the tar command to run')
954 def test_tarfile_vs_tar(self):
955 tmpdir, tmpdir2, base_name = self._create_files()
956 old_dir = os.getcwd()
957 os.chdir(tmpdir)
958 try:
959 _make_tarball(base_name, 'dist')
960 finally:
961 os.chdir(old_dir)
962
963 # check if the compressed tarball was created
964 tarball = base_name + '.tar.gz'
965 self.assertTrue(os.path.exists(tarball))
966
967 # now create another tarball using `tar`
968 tarball2 = os.path.join(tmpdir, 'archive2.tar.gz')
969 tar_cmd = ['tar', '-cf', 'archive2.tar', 'dist']
970 gzip_cmd = ['gzip', '-f9', 'archive2.tar']
971 old_dir = os.getcwd()
972 os.chdir(tmpdir)
973 try:
974 with captured_stdout() as s:
975 spawn(tar_cmd)
976 spawn(gzip_cmd)
977 finally:
978 os.chdir(old_dir)
979
980 self.assertTrue(os.path.exists(tarball2))
981 # let's compare both tarballs
Ezio Melottib3aedd42010-11-20 19:04:17 +0000982 self.assertEqual(self._tarinfo(tarball), self._tarinfo(tarball2))
Tarek Ziadé396fad72010-02-23 05:30:31 +0000983
984 # trying an uncompressed one
985 base_name = os.path.join(tmpdir2, 'archive')
986 old_dir = os.getcwd()
987 os.chdir(tmpdir)
988 try:
989 _make_tarball(base_name, 'dist', compress=None)
990 finally:
991 os.chdir(old_dir)
992 tarball = base_name + '.tar'
993 self.assertTrue(os.path.exists(tarball))
994
995 # now for a dry_run
996 base_name = os.path.join(tmpdir2, 'archive')
997 old_dir = os.getcwd()
998 os.chdir(tmpdir)
999 try:
1000 _make_tarball(base_name, 'dist', compress=None, dry_run=True)
1001 finally:
1002 os.chdir(old_dir)
1003 tarball = base_name + '.tar'
1004 self.assertTrue(os.path.exists(tarball))
1005
Ezio Melotti975077a2011-05-19 22:03:22 +03001006 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001007 @unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run')
1008 def test_make_zipfile(self):
1009 # creating something to tar
1010 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +02001011 write_file((tmpdir, 'file1'), 'xxx')
1012 write_file((tmpdir, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +00001013
1014 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001015 # force shutil to create the directory
1016 os.rmdir(tmpdir2)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001017 base_name = os.path.join(tmpdir2, 'archive')
1018 _make_zipfile(base_name, tmpdir)
1019
1020 # check if the compressed tarball was created
1021 tarball = base_name + '.zip'
Éric Araujo1c505492010-11-06 02:12:51 +00001022 self.assertTrue(os.path.exists(tarball))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001023
1024
1025 def test_make_archive(self):
1026 tmpdir = self.mkdtemp()
1027 base_name = os.path.join(tmpdir, 'archive')
1028 self.assertRaises(ValueError, make_archive, base_name, 'xxx')
1029
Ezio Melotti975077a2011-05-19 22:03:22 +03001030 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001031 def test_make_archive_owner_group(self):
1032 # testing make_archive with owner and group, with various combinations
1033 # this works even if there's not gid/uid support
1034 if UID_GID_SUPPORT:
1035 group = grp.getgrgid(0)[0]
1036 owner = pwd.getpwuid(0)[0]
1037 else:
1038 group = owner = 'root'
1039
1040 base_dir, root_dir, base_name = self._create_files()
1041 base_name = os.path.join(self.mkdtemp() , 'archive')
1042 res = make_archive(base_name, 'zip', root_dir, base_dir, owner=owner,
1043 group=group)
1044 self.assertTrue(os.path.exists(res))
1045
1046 res = make_archive(base_name, 'zip', root_dir, base_dir)
1047 self.assertTrue(os.path.exists(res))
1048
1049 res = make_archive(base_name, 'tar', root_dir, base_dir,
1050 owner=owner, group=group)
1051 self.assertTrue(os.path.exists(res))
1052
1053 res = make_archive(base_name, 'tar', root_dir, base_dir,
1054 owner='kjhkjhkjg', group='oihohoh')
1055 self.assertTrue(os.path.exists(res))
1056
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001057
Ezio Melotti975077a2011-05-19 22:03:22 +03001058 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001059 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1060 def test_tarfile_root_owner(self):
1061 tmpdir, tmpdir2, base_name = self._create_files()
1062 old_dir = os.getcwd()
1063 os.chdir(tmpdir)
1064 group = grp.getgrgid(0)[0]
1065 owner = pwd.getpwuid(0)[0]
1066 try:
1067 archive_name = _make_tarball(base_name, 'dist', compress=None,
1068 owner=owner, group=group)
1069 finally:
1070 os.chdir(old_dir)
1071
1072 # check if the compressed tarball was created
1073 self.assertTrue(os.path.exists(archive_name))
1074
1075 # now checks the rights
1076 archive = tarfile.open(archive_name)
1077 try:
1078 for member in archive.getmembers():
Ezio Melottib3aedd42010-11-20 19:04:17 +00001079 self.assertEqual(member.uid, 0)
1080 self.assertEqual(member.gid, 0)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001081 finally:
1082 archive.close()
1083
1084 def test_make_archive_cwd(self):
1085 current_dir = os.getcwd()
1086 def _breaks(*args, **kw):
1087 raise RuntimeError()
1088
1089 register_archive_format('xxx', _breaks, [], 'xxx file')
1090 try:
1091 try:
1092 make_archive('xxx', 'xxx', root_dir=self.mkdtemp())
1093 except Exception:
1094 pass
Ezio Melottib3aedd42010-11-20 19:04:17 +00001095 self.assertEqual(os.getcwd(), current_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001096 finally:
1097 unregister_archive_format('xxx')
1098
1099 def test_register_archive_format(self):
1100
1101 self.assertRaises(TypeError, register_archive_format, 'xxx', 1)
1102 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1103 1)
1104 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1105 [(1, 2), (1, 2, 3)])
1106
1107 register_archive_format('xxx', lambda: x, [(1, 2)], 'xxx file')
1108 formats = [name for name, params in get_archive_formats()]
1109 self.assertIn('xxx', formats)
1110
1111 unregister_archive_format('xxx')
1112 formats = [name for name, params in get_archive_formats()]
1113 self.assertNotIn('xxx', formats)
1114
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001115 def _compare_dirs(self, dir1, dir2):
1116 # check that dir1 and dir2 are equivalent,
1117 # return the diff
1118 diff = []
1119 for root, dirs, files in os.walk(dir1):
1120 for file_ in files:
1121 path = os.path.join(root, file_)
1122 target_path = os.path.join(dir2, os.path.split(path)[-1])
1123 if not os.path.exists(target_path):
1124 diff.append(file_)
1125 return diff
1126
Ezio Melotti975077a2011-05-19 22:03:22 +03001127 @requires_zlib
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001128 def test_unpack_archive(self):
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001129 formats = ['tar', 'gztar', 'zip']
1130 if BZ2_SUPPORTED:
1131 formats.append('bztar')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001132
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001133 for format in formats:
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001134 tmpdir = self.mkdtemp()
1135 base_dir, root_dir, base_name = self._create_files()
1136 tmpdir2 = self.mkdtemp()
1137 filename = make_archive(base_name, format, root_dir, base_dir)
1138
1139 # let's try to unpack it now
1140 unpack_archive(filename, tmpdir2)
1141 diff = self._compare_dirs(tmpdir, tmpdir2)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001142 self.assertEqual(diff, [])
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001143
Nick Coghlanabf202d2011-03-16 13:52:20 -04001144 # and again, this time with the format specified
1145 tmpdir3 = self.mkdtemp()
1146 unpack_archive(filename, tmpdir3, format=format)
1147 diff = self._compare_dirs(tmpdir, tmpdir3)
1148 self.assertEqual(diff, [])
1149 self.assertRaises(shutil.ReadError, unpack_archive, TESTFN)
1150 self.assertRaises(ValueError, unpack_archive, TESTFN, format='xxx')
1151
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001152 def test_unpack_registery(self):
1153
1154 formats = get_unpack_formats()
1155
1156 def _boo(filename, extract_dir, extra):
Ezio Melottib3aedd42010-11-20 19:04:17 +00001157 self.assertEqual(extra, 1)
1158 self.assertEqual(filename, 'stuff.boo')
1159 self.assertEqual(extract_dir, 'xx')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001160
1161 register_unpack_format('Boo', ['.boo', '.b2'], _boo, [('extra', 1)])
1162 unpack_archive('stuff.boo', 'xx')
1163
1164 # trying to register a .boo unpacker again
1165 self.assertRaises(RegistryError, register_unpack_format, 'Boo2',
1166 ['.boo'], _boo)
1167
1168 # should work now
1169 unregister_unpack_format('Boo')
1170 register_unpack_format('Boo2', ['.boo'], _boo)
1171 self.assertIn(('Boo2', ['.boo'], ''), get_unpack_formats())
1172 self.assertNotIn(('Boo', ['.boo'], ''), get_unpack_formats())
1173
1174 # let's leave a clean state
1175 unregister_unpack_format('Boo2')
Ezio Melottib3aedd42010-11-20 19:04:17 +00001176 self.assertEqual(get_unpack_formats(), formats)
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001177
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001178 @unittest.skipUnless(hasattr(shutil, 'disk_usage'),
1179 "disk_usage not available on this platform")
1180 def test_disk_usage(self):
1181 usage = shutil.disk_usage(os.getcwd())
Éric Araujo2ee61882011-07-02 16:45:45 +02001182 self.assertGreater(usage.total, 0)
1183 self.assertGreater(usage.used, 0)
1184 self.assertGreaterEqual(usage.free, 0)
1185 self.assertGreaterEqual(usage.total, usage.used)
1186 self.assertGreater(usage.total, usage.free)
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001187
Sandro Tosid902a142011-08-22 23:28:27 +02001188 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1189 @unittest.skipUnless(hasattr(os, 'chown'), 'requires os.chown')
1190 def test_chown(self):
1191
1192 # cleaned-up automatically by TestShutil.tearDown method
1193 dirname = self.mkdtemp()
1194 filename = tempfile.mktemp(dir=dirname)
1195 write_file(filename, 'testing chown function')
1196
1197 with self.assertRaises(ValueError):
1198 shutil.chown(filename)
1199
1200 with self.assertRaises(LookupError):
1201 shutil.chown(filename, user='non-exising username')
1202
1203 with self.assertRaises(LookupError):
1204 shutil.chown(filename, group='non-exising groupname')
1205
1206 with self.assertRaises(TypeError):
1207 shutil.chown(filename, b'spam')
1208
1209 with self.assertRaises(TypeError):
1210 shutil.chown(filename, 3.14)
1211
1212 uid = os.getuid()
1213 gid = os.getgid()
1214
1215 def check_chown(path, uid=None, gid=None):
1216 s = os.stat(filename)
1217 if uid is not None:
1218 self.assertEqual(uid, s.st_uid)
1219 if gid is not None:
1220 self.assertEqual(gid, s.st_gid)
1221
1222 shutil.chown(filename, uid, gid)
1223 check_chown(filename, uid, gid)
1224 shutil.chown(filename, uid)
1225 check_chown(filename, uid)
1226 shutil.chown(filename, user=uid)
1227 check_chown(filename, uid)
1228 shutil.chown(filename, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001229 check_chown(filename, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001230
1231 shutil.chown(dirname, uid, gid)
1232 check_chown(dirname, uid, gid)
1233 shutil.chown(dirname, uid)
1234 check_chown(dirname, uid)
1235 shutil.chown(dirname, user=uid)
1236 check_chown(dirname, uid)
1237 shutil.chown(dirname, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001238 check_chown(dirname, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001239
1240 user = pwd.getpwuid(uid)[0]
1241 group = grp.getgrgid(gid)[0]
1242 shutil.chown(filename, user, group)
1243 check_chown(filename, uid, gid)
1244 shutil.chown(dirname, user, group)
1245 check_chown(dirname, uid, gid)
1246
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001247 def test_copy_return_value(self):
1248 # copy and copy2 both return their destination path.
1249 for fn in (shutil.copy, shutil.copy2):
1250 src_dir = self.mkdtemp()
1251 dst_dir = self.mkdtemp()
1252 src = os.path.join(src_dir, 'foo')
1253 write_file(src, 'foo')
1254 rv = fn(src, dst_dir)
1255 self.assertEqual(rv, os.path.join(dst_dir, 'foo'))
1256 rv = fn(src, os.path.join(dst_dir, 'bar'))
1257 self.assertEqual(rv, os.path.join(dst_dir, 'bar'))
1258
1259 def test_copyfile_return_value(self):
1260 # copytree returns its destination path.
1261 src_dir = self.mkdtemp()
1262 dst_dir = self.mkdtemp()
1263 dst_file = os.path.join(dst_dir, 'bar')
1264 src_file = os.path.join(src_dir, 'foo')
1265 write_file(src_file, 'foo')
1266 rv = shutil.copyfile(src_file, dst_file)
1267 self.assertTrue(os.path.exists(rv))
1268 self.assertEqual(read_file(src_file), read_file(dst_file))
1269
Hynek Schlawack48653762012-10-07 12:49:58 +02001270 def test_copyfile_same_file(self):
1271 # copyfile() should raise SameFileError if the source and destination
1272 # are the same.
1273 src_dir = self.mkdtemp()
1274 src_file = os.path.join(src_dir, 'foo')
1275 write_file(src_file, 'foo')
1276 self.assertRaises(SameFileError, shutil.copyfile, src_file, src_file)
Hynek Schlawack27ddb572012-10-28 13:59:27 +01001277 # But Error should work too, to stay backward compatible.
1278 self.assertRaises(Error, shutil.copyfile, src_file, src_file)
Hynek Schlawack48653762012-10-07 12:49:58 +02001279
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001280 def test_copytree_return_value(self):
1281 # copytree returns its destination path.
1282 src_dir = self.mkdtemp()
1283 dst_dir = src_dir + "dest"
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001284 self.addCleanup(shutil.rmtree, dst_dir, True)
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001285 src = os.path.join(src_dir, 'foo')
1286 write_file(src, 'foo')
1287 rv = shutil.copytree(src_dir, dst_dir)
1288 self.assertEqual(['foo'], os.listdir(rv))
1289
Christian Heimes9bd667a2008-01-20 15:14:11 +00001290
Brian Curtinc57a3452012-06-22 16:00:30 -05001291class TestWhich(unittest.TestCase):
1292
1293 def setUp(self):
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001294 self.temp_dir = tempfile.mkdtemp(prefix="Tmp")
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001295 self.addCleanup(shutil.rmtree, self.temp_dir, True)
Brian Curtinc57a3452012-06-22 16:00:30 -05001296 # Give the temp_file an ".exe" suffix for all.
1297 # It's needed on Windows and not harmful on other platforms.
1298 self.temp_file = tempfile.NamedTemporaryFile(dir=self.temp_dir,
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001299 prefix="Tmp",
1300 suffix=".Exe")
Brian Curtinc57a3452012-06-22 16:00:30 -05001301 os.chmod(self.temp_file.name, stat.S_IXUSR)
1302 self.addCleanup(self.temp_file.close)
1303 self.dir, self.file = os.path.split(self.temp_file.name)
1304
1305 def test_basic(self):
1306 # Given an EXE in a directory, it should be returned.
1307 rv = shutil.which(self.file, path=self.dir)
1308 self.assertEqual(rv, self.temp_file.name)
1309
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001310 def test_absolute_cmd(self):
Brian Curtinc57a3452012-06-22 16:00:30 -05001311 # When given the fully qualified path to an executable that exists,
1312 # it should be returned.
1313 rv = shutil.which(self.temp_file.name, path=self.temp_dir)
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001314 self.assertEqual(rv, self.temp_file.name)
1315
1316 def test_relative_cmd(self):
1317 # When given the relative path with a directory part to an executable
1318 # that exists, it should be returned.
1319 base_dir, tail_dir = os.path.split(self.dir)
1320 relpath = os.path.join(tail_dir, self.file)
1321 with support.temp_cwd(path=base_dir):
1322 rv = shutil.which(relpath, path=self.temp_dir)
1323 self.assertEqual(rv, relpath)
1324 # But it shouldn't be searched in PATH directories (issue #16957).
1325 with support.temp_cwd(path=self.dir):
1326 rv = shutil.which(relpath, path=base_dir)
1327 self.assertIsNone(rv)
1328
1329 def test_cwd(self):
1330 # Issue #16957
1331 base_dir = os.path.dirname(self.dir)
1332 with support.temp_cwd(path=self.dir):
1333 rv = shutil.which(self.file, path=base_dir)
1334 if sys.platform == "win32":
1335 # Windows: current directory implicitly on PATH
1336 self.assertEqual(rv, os.path.join(os.curdir, self.file))
1337 else:
1338 # Other platforms: shouldn't match in the current directory.
1339 self.assertIsNone(rv)
Brian Curtinc57a3452012-06-22 16:00:30 -05001340
1341 def test_non_matching_mode(self):
1342 # Set the file read-only and ask for writeable files.
1343 os.chmod(self.temp_file.name, stat.S_IREAD)
1344 rv = shutil.which(self.file, path=self.dir, mode=os.W_OK)
1345 self.assertIsNone(rv)
1346
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001347 def test_relative_path(self):
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001348 base_dir, tail_dir = os.path.split(self.dir)
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001349 with support.temp_cwd(path=base_dir):
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001350 rv = shutil.which(self.file, path=tail_dir)
1351 self.assertEqual(rv, os.path.join(tail_dir, self.file))
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001352
Brian Curtinc57a3452012-06-22 16:00:30 -05001353 def test_nonexistent_file(self):
1354 # Return None when no matching executable file is found on the path.
1355 rv = shutil.which("foo.exe", path=self.dir)
1356 self.assertIsNone(rv)
1357
1358 @unittest.skipUnless(sys.platform == "win32",
1359 "pathext check is Windows-only")
1360 def test_pathext_checking(self):
1361 # Ask for the file without the ".exe" extension, then ensure that
1362 # it gets found properly with the extension.
Serhiy Storchakad70127a2013-01-24 20:03:49 +02001363 rv = shutil.which(self.file[:-4], path=self.dir)
Serhiy Storchaka80c88f42013-01-22 10:31:36 +02001364 self.assertEqual(rv, self.temp_file.name[:-4] + ".EXE")
Brian Curtinc57a3452012-06-22 16:00:30 -05001365
1366
Christian Heimesada8c3b2008-03-18 18:26:33 +00001367class TestMove(unittest.TestCase):
1368
1369 def setUp(self):
1370 filename = "foo"
1371 self.src_dir = tempfile.mkdtemp()
1372 self.dst_dir = tempfile.mkdtemp()
1373 self.src_file = os.path.join(self.src_dir, filename)
1374 self.dst_file = os.path.join(self.dst_dir, filename)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001375 with open(self.src_file, "wb") as f:
1376 f.write(b"spam")
1377
1378 def tearDown(self):
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001379 for d in (self.src_dir, self.dst_dir):
Christian Heimesada8c3b2008-03-18 18:26:33 +00001380 try:
1381 if d:
1382 shutil.rmtree(d)
1383 except:
1384 pass
1385
1386 def _check_move_file(self, src, dst, real_dst):
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001387 with open(src, "rb") as f:
1388 contents = f.read()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001389 shutil.move(src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001390 with open(real_dst, "rb") as f:
1391 self.assertEqual(contents, f.read())
Christian Heimesada8c3b2008-03-18 18:26:33 +00001392 self.assertFalse(os.path.exists(src))
1393
1394 def _check_move_dir(self, src, dst, real_dst):
1395 contents = sorted(os.listdir(src))
1396 shutil.move(src, dst)
1397 self.assertEqual(contents, sorted(os.listdir(real_dst)))
1398 self.assertFalse(os.path.exists(src))
1399
1400 def test_move_file(self):
1401 # Move a file to another location on the same filesystem.
1402 self._check_move_file(self.src_file, self.dst_file, self.dst_file)
1403
1404 def test_move_file_to_dir(self):
1405 # Move a file inside an existing dir on the same filesystem.
1406 self._check_move_file(self.src_file, self.dst_dir, self.dst_file)
1407
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001408 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001409 def test_move_file_other_fs(self):
1410 # Move a file to an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001411 self.test_move_file()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001412
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001413 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001414 def test_move_file_to_dir_other_fs(self):
1415 # Move a file to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001416 self.test_move_file_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001417
1418 def test_move_dir(self):
1419 # Move a dir to another location on the same filesystem.
1420 dst_dir = tempfile.mktemp()
1421 try:
1422 self._check_move_dir(self.src_dir, dst_dir, dst_dir)
1423 finally:
1424 try:
1425 shutil.rmtree(dst_dir)
1426 except:
1427 pass
1428
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001429 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001430 def test_move_dir_other_fs(self):
1431 # Move a dir to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001432 self.test_move_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001433
1434 def test_move_dir_to_dir(self):
1435 # Move a dir inside an existing dir on the same filesystem.
1436 self._check_move_dir(self.src_dir, self.dst_dir,
1437 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1438
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001439 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001440 def test_move_dir_to_dir_other_fs(self):
1441 # Move a dir inside an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001442 self.test_move_dir_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001443
1444 def test_existing_file_inside_dest_dir(self):
1445 # A file with the same name inside the destination dir already exists.
1446 with open(self.dst_file, "wb"):
1447 pass
1448 self.assertRaises(shutil.Error, shutil.move, self.src_file, self.dst_dir)
1449
1450 def test_dont_move_dir_in_itself(self):
1451 # Moving a dir inside itself raises an Error.
1452 dst = os.path.join(self.src_dir, "bar")
1453 self.assertRaises(shutil.Error, shutil.move, self.src_dir, dst)
1454
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001455 def test_destinsrc_false_negative(self):
1456 os.mkdir(TESTFN)
1457 try:
1458 for src, dst in [('srcdir', 'srcdir/dest')]:
1459 src = os.path.join(TESTFN, src)
1460 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001461 self.assertTrue(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001462 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001463 'dst (%s) is not in src (%s)' % (dst, src))
1464 finally:
1465 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001466
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001467 def test_destinsrc_false_positive(self):
1468 os.mkdir(TESTFN)
1469 try:
1470 for src, dst in [('srcdir', 'src/dest'), ('srcdir', 'srcdir.new')]:
1471 src = os.path.join(TESTFN, src)
1472 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001473 self.assertFalse(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001474 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001475 'dst (%s) is in src (%s)' % (dst, src))
1476 finally:
1477 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimes9bd667a2008-01-20 15:14:11 +00001478
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +01001479 @support.skip_unless_symlink
1480 @mock_rename
1481 def test_move_file_symlink(self):
1482 dst = os.path.join(self.src_dir, 'bar')
1483 os.symlink(self.src_file, dst)
1484 shutil.move(dst, self.dst_file)
1485 self.assertTrue(os.path.islink(self.dst_file))
1486 self.assertTrue(os.path.samefile(self.src_file, self.dst_file))
1487
1488 @support.skip_unless_symlink
1489 @mock_rename
1490 def test_move_file_symlink_to_dir(self):
1491 filename = "bar"
1492 dst = os.path.join(self.src_dir, filename)
1493 os.symlink(self.src_file, dst)
1494 shutil.move(dst, self.dst_dir)
1495 final_link = os.path.join(self.dst_dir, filename)
1496 self.assertTrue(os.path.islink(final_link))
1497 self.assertTrue(os.path.samefile(self.src_file, final_link))
1498
1499 @support.skip_unless_symlink
1500 @mock_rename
1501 def test_move_dangling_symlink(self):
1502 src = os.path.join(self.src_dir, 'baz')
1503 dst = os.path.join(self.src_dir, 'bar')
1504 os.symlink(src, dst)
1505 dst_link = os.path.join(self.dst_dir, 'quux')
1506 shutil.move(dst, dst_link)
1507 self.assertTrue(os.path.islink(dst_link))
1508 self.assertEqual(os.path.realpath(src), os.path.realpath(dst_link))
1509
1510 @support.skip_unless_symlink
1511 @mock_rename
1512 def test_move_dir_symlink(self):
1513 src = os.path.join(self.src_dir, 'baz')
1514 dst = os.path.join(self.src_dir, 'bar')
1515 os.mkdir(src)
1516 os.symlink(src, dst)
1517 dst_link = os.path.join(self.dst_dir, 'quux')
1518 shutil.move(dst, dst_link)
1519 self.assertTrue(os.path.islink(dst_link))
1520 self.assertTrue(os.path.samefile(src, dst_link))
1521
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001522 def test_move_return_value(self):
1523 rv = shutil.move(self.src_file, self.dst_dir)
1524 self.assertEqual(rv,
1525 os.path.join(self.dst_dir, os.path.basename(self.src_file)))
1526
1527 def test_move_as_rename_return_value(self):
1528 rv = shutil.move(self.src_file, os.path.join(self.dst_dir, 'bar'))
1529 self.assertEqual(rv, os.path.join(self.dst_dir, 'bar'))
1530
Tarek Ziadé5340db32010-04-19 22:30:51 +00001531
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001532class TestCopyFile(unittest.TestCase):
1533
1534 _delete = False
1535
1536 class Faux(object):
1537 _entered = False
1538 _exited_with = None
1539 _raised = False
1540 def __init__(self, raise_in_exit=False, suppress_at_exit=True):
1541 self._raise_in_exit = raise_in_exit
1542 self._suppress_at_exit = suppress_at_exit
1543 def read(self, *args):
1544 return ''
1545 def __enter__(self):
1546 self._entered = True
1547 def __exit__(self, exc_type, exc_val, exc_tb):
1548 self._exited_with = exc_type, exc_val, exc_tb
1549 if self._raise_in_exit:
1550 self._raised = True
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001551 raise OSError("Cannot close")
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001552 return self._suppress_at_exit
1553
1554 def tearDown(self):
1555 if self._delete:
1556 del shutil.open
1557
1558 def _set_shutil_open(self, func):
1559 shutil.open = func
1560 self._delete = True
1561
1562 def test_w_source_open_fails(self):
1563 def _open(filename, mode='r'):
1564 if filename == 'srcfile':
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001565 raise OSError('Cannot open "srcfile"')
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001566 assert 0 # shouldn't reach here.
1567
1568 self._set_shutil_open(_open)
1569
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001570 self.assertRaises(OSError, shutil.copyfile, 'srcfile', 'destfile')
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001571
1572 def test_w_dest_open_fails(self):
1573
1574 srcfile = self.Faux()
1575
1576 def _open(filename, mode='r'):
1577 if filename == 'srcfile':
1578 return srcfile
1579 if filename == 'destfile':
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001580 raise OSError('Cannot open "destfile"')
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001581 assert 0 # shouldn't reach here.
1582
1583 self._set_shutil_open(_open)
1584
1585 shutil.copyfile('srcfile', 'destfile')
1586 self.assertTrue(srcfile._entered)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001587 self.assertTrue(srcfile._exited_with[0] is OSError)
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001588 self.assertEqual(srcfile._exited_with[1].args,
1589 ('Cannot open "destfile"',))
1590
1591 def test_w_dest_close_fails(self):
1592
1593 srcfile = self.Faux()
1594 destfile = self.Faux(True)
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 shutil.copyfile('srcfile', 'destfile')
1606 self.assertTrue(srcfile._entered)
1607 self.assertTrue(destfile._entered)
1608 self.assertTrue(destfile._raised)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001609 self.assertTrue(srcfile._exited_with[0] is OSError)
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001610 self.assertEqual(srcfile._exited_with[1].args,
1611 ('Cannot close',))
1612
1613 def test_w_source_close_fails(self):
1614
1615 srcfile = self.Faux(True)
1616 destfile = self.Faux()
1617
1618 def _open(filename, mode='r'):
1619 if filename == 'srcfile':
1620 return srcfile
1621 if filename == 'destfile':
1622 return destfile
1623 assert 0 # shouldn't reach here.
1624
1625 self._set_shutil_open(_open)
1626
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001627 self.assertRaises(OSError,
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001628 shutil.copyfile, 'srcfile', 'destfile')
1629 self.assertTrue(srcfile._entered)
1630 self.assertTrue(destfile._entered)
1631 self.assertFalse(destfile._raised)
1632 self.assertTrue(srcfile._exited_with[0] is None)
1633 self.assertTrue(srcfile._raised)
1634
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001635 def test_move_dir_caseinsensitive(self):
1636 # Renames a folder to the same name
1637 # but a different case.
1638
1639 self.src_dir = tempfile.mkdtemp()
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001640 self.addCleanup(shutil.rmtree, self.src_dir, True)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001641 dst_dir = os.path.join(
1642 os.path.dirname(self.src_dir),
1643 os.path.basename(self.src_dir).upper())
1644 self.assertNotEqual(self.src_dir, dst_dir)
1645
1646 try:
1647 shutil.move(self.src_dir, dst_dir)
1648 self.assertTrue(os.path.isdir(dst_dir))
1649 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +02001650 os.rmdir(dst_dir)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001651
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001652class TermsizeTests(unittest.TestCase):
1653 def test_does_not_crash(self):
1654 """Check if get_terminal_size() returns a meaningful value.
1655
1656 There's no easy portable way to actually check the size of the
1657 terminal, so let's check if it returns something sensible instead.
1658 """
1659 size = shutil.get_terminal_size()
Antoine Pitroucfade362012-02-08 23:48:59 +01001660 self.assertGreaterEqual(size.columns, 0)
1661 self.assertGreaterEqual(size.lines, 0)
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001662
1663 def test_os_environ_first(self):
1664 "Check if environment variables have precedence"
1665
1666 with support.EnvironmentVarGuard() as env:
1667 env['COLUMNS'] = '777'
1668 size = shutil.get_terminal_size()
1669 self.assertEqual(size.columns, 777)
1670
1671 with support.EnvironmentVarGuard() as env:
1672 env['LINES'] = '888'
1673 size = shutil.get_terminal_size()
1674 self.assertEqual(size.lines, 888)
1675
1676 @unittest.skipUnless(os.isatty(sys.__stdout__.fileno()), "not on tty")
1677 def test_stty_match(self):
1678 """Check if stty returns the same results ignoring env
1679
1680 This test will fail if stdin and stdout are connected to
1681 different terminals with different sizes. Nevertheless, such
1682 situations should be pretty rare.
1683 """
1684 try:
1685 size = subprocess.check_output(['stty', 'size']).decode().split()
1686 except (FileNotFoundError, subprocess.CalledProcessError):
1687 self.skipTest("stty invocation failed")
1688 expected = (int(size[1]), int(size[0])) # reversed order
1689
1690 with support.EnvironmentVarGuard() as env:
1691 del env['LINES']
1692 del env['COLUMNS']
1693 actual = shutil.get_terminal_size()
1694
1695 self.assertEqual(expected, actual)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001696
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001697
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001698def test_main():
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001699 support.run_unittest(TestShutil, TestMove, TestCopyFile,
Brian Curtinc57a3452012-06-22 16:00:30 -05001700 TermsizeTests, TestWhich)
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001701
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001702if __name__ == '__main__':
Walter Dörwald21d3a322003-05-01 17:45:56 +00001703 test_main()