blob: ad6228053be88dedd328599104d7ae2d8cc99cbe [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
453
Larry Hastingsad5ae042012-07-14 17:55:11 -0700454 # test that shutil.copystat copies xattrs
455 src = os.path.join(tmp_dir, 'the_original')
456 write_file(src, src)
457 os.setxattr(src, 'user.the_value', b'fiddly')
458 dst = os.path.join(tmp_dir, 'the_copy')
459 write_file(dst, dst)
460 shutil.copystat(src, dst)
Hynek Schlawackc2d481f2012-07-16 17:11:10 +0200461 self.assertEqual(os.getxattr(dst, 'user.the_value'), b'fiddly')
Larry Hastingsad5ae042012-07-14 17:55:11 -0700462
Antoine Pitrou424246f2012-05-12 19:02:01 +0200463 @support.skip_unless_symlink
464 @support.skip_unless_xattr
465 @unittest.skipUnless(hasattr(os, 'geteuid') and os.geteuid() == 0,
466 'root privileges required')
467 def test_copyxattr_symlinks(self):
468 # On Linux, it's only possible to access non-user xattr for symlinks;
469 # which in turn require root privileges. This test should be expanded
470 # as soon as other platforms gain support for extended attributes.
471 tmp_dir = self.mkdtemp()
472 src = os.path.join(tmp_dir, 'foo')
473 src_link = os.path.join(tmp_dir, 'baz')
474 write_file(src, 'foo')
475 os.symlink(src, src_link)
476 os.setxattr(src, 'trusted.foo', b'42')
Larry Hastings9cf065c2012-06-22 16:30:09 -0700477 os.setxattr(src_link, 'trusted.foo', b'43', follow_symlinks=False)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200478 dst = os.path.join(tmp_dir, 'bar')
479 dst_link = os.path.join(tmp_dir, 'qux')
480 write_file(dst, 'bar')
481 os.symlink(dst, dst_link)
Larry Hastingsb4038062012-07-15 10:57:38 -0700482 shutil._copyxattr(src_link, dst_link, follow_symlinks=False)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700483 self.assertEqual(os.getxattr(dst_link, 'trusted.foo', follow_symlinks=False), b'43')
Antoine Pitrou424246f2012-05-12 19:02:01 +0200484 self.assertRaises(OSError, os.getxattr, dst, 'trusted.foo')
Larry Hastingsb4038062012-07-15 10:57:38 -0700485 shutil._copyxattr(src_link, dst, follow_symlinks=False)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200486 self.assertEqual(os.getxattr(dst, 'trusted.foo'), b'43')
487
Antoine Pitrou78091e62011-12-29 18:54:15 +0100488 @support.skip_unless_symlink
489 def test_copy_symlinks(self):
490 tmp_dir = self.mkdtemp()
491 src = os.path.join(tmp_dir, 'foo')
492 dst = os.path.join(tmp_dir, 'bar')
493 src_link = os.path.join(tmp_dir, 'baz')
494 write_file(src, 'foo')
495 os.symlink(src, src_link)
496 if hasattr(os, 'lchmod'):
497 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
498 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700499 shutil.copy(src_link, dst, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100500 self.assertFalse(os.path.islink(dst))
501 self.assertEqual(read_file(src), read_file(dst))
502 os.remove(dst)
503 # follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700504 shutil.copy(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100505 self.assertTrue(os.path.islink(dst))
506 self.assertEqual(os.readlink(dst), os.readlink(src_link))
507 if hasattr(os, 'lchmod'):
508 self.assertEqual(os.lstat(src_link).st_mode,
509 os.lstat(dst).st_mode)
510
511 @support.skip_unless_symlink
512 def test_copy2_symlinks(self):
513 tmp_dir = self.mkdtemp()
514 src = os.path.join(tmp_dir, 'foo')
515 dst = os.path.join(tmp_dir, 'bar')
516 src_link = os.path.join(tmp_dir, 'baz')
517 write_file(src, 'foo')
518 os.symlink(src, src_link)
519 if hasattr(os, 'lchmod'):
520 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
521 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
522 os.lchflags(src_link, stat.UF_NODUMP)
523 src_stat = os.stat(src)
524 src_link_stat = os.lstat(src_link)
525 # follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700526 shutil.copy2(src_link, dst, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100527 self.assertFalse(os.path.islink(dst))
528 self.assertEqual(read_file(src), read_file(dst))
529 os.remove(dst)
530 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700531 shutil.copy2(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100532 self.assertTrue(os.path.islink(dst))
533 self.assertEqual(os.readlink(dst), os.readlink(src_link))
534 dst_stat = os.lstat(dst)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700535 if os.utime in os.supports_follow_symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100536 for attr in 'st_atime', 'st_mtime':
537 # The modification times may be truncated in the new file.
538 self.assertLessEqual(getattr(src_link_stat, attr),
539 getattr(dst_stat, attr) + 1)
540 if hasattr(os, 'lchmod'):
541 self.assertEqual(src_link_stat.st_mode, dst_stat.st_mode)
542 self.assertNotEqual(src_stat.st_mode, dst_stat.st_mode)
543 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
544 self.assertEqual(src_link_stat.st_flags, dst_stat.st_flags)
545
Antoine Pitrou424246f2012-05-12 19:02:01 +0200546 @support.skip_unless_xattr
547 def test_copy2_xattr(self):
548 tmp_dir = self.mkdtemp()
549 src = os.path.join(tmp_dir, 'foo')
550 dst = os.path.join(tmp_dir, 'bar')
551 write_file(src, 'foo')
552 os.setxattr(src, 'user.foo', b'42')
553 shutil.copy2(src, dst)
554 self.assertEqual(
555 os.getxattr(src, 'user.foo'),
556 os.getxattr(dst, 'user.foo'))
557 os.remove(dst)
558
Antoine Pitrou78091e62011-12-29 18:54:15 +0100559 @support.skip_unless_symlink
560 def test_copyfile_symlinks(self):
561 tmp_dir = self.mkdtemp()
562 src = os.path.join(tmp_dir, 'src')
563 dst = os.path.join(tmp_dir, 'dst')
564 dst_link = os.path.join(tmp_dir, 'dst_link')
565 link = os.path.join(tmp_dir, 'link')
566 write_file(src, 'foo')
567 os.symlink(src, link)
568 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700569 shutil.copyfile(link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100570 self.assertTrue(os.path.islink(dst_link))
571 self.assertEqual(os.readlink(link), os.readlink(dst_link))
572 # follow
573 shutil.copyfile(link, dst)
574 self.assertFalse(os.path.islink(dst))
575
Hynek Schlawack2100b422012-06-23 20:28:32 +0200576 def test_rmtree_uses_safe_fd_version_if_available(self):
Hynek Schlawackd0f6e0a2012-06-29 08:28:20 +0200577 _use_fd_functions = ({os.open, os.stat, os.unlink, os.rmdir} <=
578 os.supports_dir_fd and
579 os.listdir in os.supports_fd and
580 os.stat in os.supports_follow_symlinks)
581 if _use_fd_functions:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200582 self.assertTrue(shutil._use_fd_functions)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000583 self.assertTrue(shutil.rmtree.avoids_symlink_attacks)
Hynek Schlawack2100b422012-06-23 20:28:32 +0200584 tmp_dir = self.mkdtemp()
585 d = os.path.join(tmp_dir, 'a')
586 os.mkdir(d)
587 try:
588 real_rmtree = shutil._rmtree_safe_fd
589 class Called(Exception): pass
590 def _raiser(*args, **kwargs):
591 raise Called
592 shutil._rmtree_safe_fd = _raiser
593 self.assertRaises(Called, shutil.rmtree, d)
594 finally:
595 shutil._rmtree_safe_fd = real_rmtree
596 else:
597 self.assertFalse(shutil._use_fd_functions)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000598 self.assertFalse(shutil.rmtree.avoids_symlink_attacks)
Hynek Schlawack2100b422012-06-23 20:28:32 +0200599
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000600 def test_rmtree_dont_delete_file(self):
601 # When called on a file instead of a directory, don't delete it.
602 handle, path = tempfile.mkstemp()
Victor Stinnerbf816222011-06-30 23:25:47 +0200603 os.close(handle)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200604 self.assertRaises(NotADirectoryError, shutil.rmtree, path)
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000605 os.remove(path)
606
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000607 def test_copytree_simple(self):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000608 src_dir = tempfile.mkdtemp()
609 dst_dir = os.path.join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200610 self.addCleanup(shutil.rmtree, src_dir)
611 self.addCleanup(shutil.rmtree, os.path.dirname(dst_dir))
612 write_file((src_dir, 'test.txt'), '123')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000613 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200614 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000615
Éric Araujoa7e33a12011-08-12 19:51:35 +0200616 shutil.copytree(src_dir, dst_dir)
617 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test.txt')))
618 self.assertTrue(os.path.isdir(os.path.join(dst_dir, 'test_dir')))
619 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test_dir',
620 'test.txt')))
621 actual = read_file((dst_dir, 'test.txt'))
622 self.assertEqual(actual, '123')
623 actual = read_file((dst_dir, 'test_dir', 'test.txt'))
624 self.assertEqual(actual, '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000625
Antoine Pitrou78091e62011-12-29 18:54:15 +0100626 @support.skip_unless_symlink
627 def test_copytree_symlinks(self):
628 tmp_dir = self.mkdtemp()
629 src_dir = os.path.join(tmp_dir, 'src')
630 dst_dir = os.path.join(tmp_dir, 'dst')
631 sub_dir = os.path.join(src_dir, 'sub')
632 os.mkdir(src_dir)
633 os.mkdir(sub_dir)
634 write_file((src_dir, 'file.txt'), 'foo')
635 src_link = os.path.join(sub_dir, 'link')
636 dst_link = os.path.join(dst_dir, 'sub/link')
637 os.symlink(os.path.join(src_dir, 'file.txt'),
638 src_link)
639 if hasattr(os, 'lchmod'):
640 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
641 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
642 os.lchflags(src_link, stat.UF_NODUMP)
643 src_stat = os.lstat(src_link)
644 shutil.copytree(src_dir, dst_dir, symlinks=True)
645 self.assertTrue(os.path.islink(os.path.join(dst_dir, 'sub', 'link')))
646 self.assertEqual(os.readlink(os.path.join(dst_dir, 'sub', 'link')),
647 os.path.join(src_dir, 'file.txt'))
648 dst_stat = os.lstat(dst_link)
649 if hasattr(os, 'lchmod'):
650 self.assertEqual(dst_stat.st_mode, src_stat.st_mode)
651 if hasattr(os, 'lchflags'):
652 self.assertEqual(dst_stat.st_flags, src_stat.st_flags)
653
Georg Brandl2ee470f2008-07-16 12:55:28 +0000654 def test_copytree_with_exclude(self):
Georg Brandl2ee470f2008-07-16 12:55:28 +0000655 # creating data
656 join = os.path.join
657 exists = os.path.exists
658 src_dir = tempfile.mkdtemp()
Georg Brandl2ee470f2008-07-16 12:55:28 +0000659 try:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000660 dst_dir = join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200661 write_file((src_dir, 'test.txt'), '123')
662 write_file((src_dir, 'test.tmp'), '123')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000663 os.mkdir(join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200664 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000665 os.mkdir(join(src_dir, 'test_dir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200666 write_file((src_dir, 'test_dir2', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000667 os.mkdir(join(src_dir, 'test_dir2', 'subdir'))
668 os.mkdir(join(src_dir, 'test_dir2', 'subdir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200669 write_file((src_dir, 'test_dir2', 'subdir', 'test.txt'), '456')
670 write_file((src_dir, 'test_dir2', 'subdir2', 'test.py'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000671
672 # testing glob-like patterns
673 try:
674 patterns = shutil.ignore_patterns('*.tmp', 'test_dir2')
675 shutil.copytree(src_dir, dst_dir, ignore=patterns)
676 # checking the result: some elements should not be copied
677 self.assertTrue(exists(join(dst_dir, 'test.txt')))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200678 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
679 self.assertFalse(exists(join(dst_dir, 'test_dir2')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000680 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200681 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000682 try:
683 patterns = shutil.ignore_patterns('*.tmp', 'subdir*')
684 shutil.copytree(src_dir, dst_dir, ignore=patterns)
685 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200686 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
687 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2')))
688 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000689 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200690 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000691
692 # testing callable-style
693 try:
694 def _filter(src, names):
695 res = []
696 for name in names:
697 path = os.path.join(src, name)
698
699 if (os.path.isdir(path) and
700 path.split()[-1] == 'subdir'):
701 res.append(name)
702 elif os.path.splitext(path)[-1] in ('.py'):
703 res.append(name)
704 return res
705
706 shutil.copytree(src_dir, dst_dir, ignore=_filter)
707
708 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200709 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2',
710 'test.py')))
711 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000712
713 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200714 shutil.rmtree(dst_dir)
Georg Brandl2ee470f2008-07-16 12:55:28 +0000715 finally:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000716 shutil.rmtree(src_dir)
717 shutil.rmtree(os.path.dirname(dst_dir))
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000718
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000719 @unittest.skipUnless(hasattr(os, 'link'), 'requires os.link')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000720 def test_dont_copy_file_onto_link_to_itself(self):
Georg Brandl724d0892010-12-05 07:51:39 +0000721 # Temporarily disable test on Windows.
722 if os.name == 'nt':
723 return
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000724 # bug 851123.
725 os.mkdir(TESTFN)
726 src = os.path.join(TESTFN, 'cheese')
727 dst = os.path.join(TESTFN, 'shop')
728 try:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000729 with open(src, 'w') as f:
730 f.write('cheddar')
731 os.link(src, dst)
Hynek Schlawack48653762012-10-07 12:49:58 +0200732 self.assertRaises(shutil.SameFileError, shutil.copyfile, src, dst)
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000733 with open(src, 'r') as f:
734 self.assertEqual(f.read(), 'cheddar')
735 os.remove(dst)
736 finally:
737 shutil.rmtree(TESTFN, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000738
Brian Curtin3b4499c2010-12-28 14:31:47 +0000739 @support.skip_unless_symlink
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000740 def test_dont_copy_file_onto_symlink_to_itself(self):
741 # bug 851123.
742 os.mkdir(TESTFN)
743 src = os.path.join(TESTFN, 'cheese')
744 dst = os.path.join(TESTFN, 'shop')
745 try:
746 with open(src, 'w') as f:
747 f.write('cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000748 # Using `src` here would mean we end up with a symlink pointing
749 # to TESTFN/TESTFN/cheese, while it should point at
750 # TESTFN/cheese.
751 os.symlink('cheese', dst)
Hynek Schlawack48653762012-10-07 12:49:58 +0200752 self.assertRaises(shutil.SameFileError, shutil.copyfile, src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +0000753 with open(src, 'r') as f:
754 self.assertEqual(f.read(), 'cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000755 os.remove(dst)
756 finally:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000757 shutil.rmtree(TESTFN, ignore_errors=True)
Johannes Gijsbers68128712004-08-14 13:57:08 +0000758
Brian Curtin3b4499c2010-12-28 14:31:47 +0000759 @support.skip_unless_symlink
Brian Curtind40e6f72010-07-08 21:39:08 +0000760 def test_rmtree_on_symlink(self):
761 # bug 1669.
762 os.mkdir(TESTFN)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000763 try:
Brian Curtind40e6f72010-07-08 21:39:08 +0000764 src = os.path.join(TESTFN, 'cheese')
765 dst = os.path.join(TESTFN, 'shop')
766 os.mkdir(src)
767 os.symlink(src, dst)
768 self.assertRaises(OSError, shutil.rmtree, dst)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200769 shutil.rmtree(dst, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000770 finally:
Brian Curtind40e6f72010-07-08 21:39:08 +0000771 shutil.rmtree(TESTFN, ignore_errors=True)
772
773 if hasattr(os, "mkfifo"):
774 # Issue #3002: copyfile and copytree block indefinitely on named pipes
775 def test_copyfile_named_pipe(self):
776 os.mkfifo(TESTFN)
777 try:
778 self.assertRaises(shutil.SpecialFileError,
779 shutil.copyfile, TESTFN, TESTFN2)
780 self.assertRaises(shutil.SpecialFileError,
781 shutil.copyfile, __file__, TESTFN)
782 finally:
783 os.remove(TESTFN)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000784
Brian Curtin3b4499c2010-12-28 14:31:47 +0000785 @support.skip_unless_symlink
Brian Curtin52173d42010-12-02 18:29:18 +0000786 def test_copytree_named_pipe(self):
787 os.mkdir(TESTFN)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000788 try:
Brian Curtin52173d42010-12-02 18:29:18 +0000789 subdir = os.path.join(TESTFN, "subdir")
790 os.mkdir(subdir)
791 pipe = os.path.join(subdir, "mypipe")
792 os.mkfifo(pipe)
793 try:
794 shutil.copytree(TESTFN, TESTFN2)
795 except shutil.Error as e:
796 errors = e.args[0]
797 self.assertEqual(len(errors), 1)
798 src, dst, error_msg = errors[0]
799 self.assertEqual("`%s` is a named pipe" % pipe, error_msg)
800 else:
801 self.fail("shutil.Error should have been raised")
802 finally:
803 shutil.rmtree(TESTFN, ignore_errors=True)
804 shutil.rmtree(TESTFN2, ignore_errors=True)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000805
Tarek Ziadé5340db32010-04-19 22:30:51 +0000806 def test_copytree_special_func(self):
807
808 src_dir = self.mkdtemp()
809 dst_dir = os.path.join(self.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200810 write_file((src_dir, 'test.txt'), '123')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000811 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200812 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000813
814 copied = []
815 def _copy(src, dst):
816 copied.append((src, dst))
817
818 shutil.copytree(src_dir, dst_dir, copy_function=_copy)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000819 self.assertEqual(len(copied), 2)
Tarek Ziadé5340db32010-04-19 22:30:51 +0000820
Brian Curtin3b4499c2010-12-28 14:31:47 +0000821 @support.skip_unless_symlink
Tarek Ziadéfb437512010-04-20 08:57:33 +0000822 def test_copytree_dangling_symlinks(self):
823
824 # a dangling symlink raises an error at the end
825 src_dir = self.mkdtemp()
826 dst_dir = os.path.join(self.mkdtemp(), 'destination')
827 os.symlink('IDONTEXIST', os.path.join(src_dir, 'test.txt'))
828 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200829 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadéfb437512010-04-20 08:57:33 +0000830 self.assertRaises(Error, shutil.copytree, src_dir, dst_dir)
831
832 # a dangling symlink is ignored with the proper flag
833 dst_dir = os.path.join(self.mkdtemp(), 'destination2')
834 shutil.copytree(src_dir, dst_dir, ignore_dangling_symlinks=True)
835 self.assertNotIn('test.txt', os.listdir(dst_dir))
836
837 # a dangling symlink is copied if symlinks=True
838 dst_dir = os.path.join(self.mkdtemp(), 'destination3')
839 shutil.copytree(src_dir, dst_dir, symlinks=True)
840 self.assertIn('test.txt', os.listdir(dst_dir))
841
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400842 def _copy_file(self, method):
843 fname = 'test.txt'
844 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200845 write_file((tmpdir, fname), 'xxx')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400846 file1 = os.path.join(tmpdir, fname)
847 tmpdir2 = self.mkdtemp()
848 method(file1, tmpdir2)
849 file2 = os.path.join(tmpdir2, fname)
850 return (file1, file2)
851
852 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
853 def test_copy(self):
854 # Ensure that the copied file exists and has the same mode bits.
855 file1, file2 = self._copy_file(shutil.copy)
856 self.assertTrue(os.path.exists(file2))
857 self.assertEqual(os.stat(file1).st_mode, os.stat(file2).st_mode)
858
859 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
Senthil Kumaran0c2dba52011-07-03 18:21:38 -0700860 @unittest.skipUnless(hasattr(os, 'utime'), 'requires os.utime')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400861 def test_copy2(self):
862 # Ensure that the copied file exists and has the same mode and
863 # modification time bits.
864 file1, file2 = self._copy_file(shutil.copy2)
865 self.assertTrue(os.path.exists(file2))
866 file1_stat = os.stat(file1)
867 file2_stat = os.stat(file2)
868 self.assertEqual(file1_stat.st_mode, file2_stat.st_mode)
869 for attr in 'st_atime', 'st_mtime':
870 # The modification times may be truncated in the new file.
871 self.assertLessEqual(getattr(file1_stat, attr),
872 getattr(file2_stat, attr) + 1)
873 if hasattr(os, 'chflags') and hasattr(file1_stat, 'st_flags'):
874 self.assertEqual(getattr(file1_stat, 'st_flags'),
875 getattr(file2_stat, 'st_flags'))
876
Ezio Melotti975077a2011-05-19 22:03:22 +0300877 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000878 def test_make_tarball(self):
879 # creating something to tar
880 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200881 write_file((tmpdir, 'file1'), 'xxx')
882 write_file((tmpdir, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000883 os.mkdir(os.path.join(tmpdir, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200884 write_file((tmpdir, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000885
886 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400887 # force shutil to create the directory
888 os.rmdir(tmpdir2)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000889 unittest.skipUnless(splitdrive(tmpdir)[0] == splitdrive(tmpdir2)[0],
890 "source and target should be on same drive")
891
892 base_name = os.path.join(tmpdir2, 'archive')
893
894 # working with relative paths to avoid tar warnings
895 old_dir = os.getcwd()
896 os.chdir(tmpdir)
897 try:
898 _make_tarball(splitdrive(base_name)[1], '.')
899 finally:
900 os.chdir(old_dir)
901
902 # check if the compressed tarball was created
903 tarball = base_name + '.tar.gz'
904 self.assertTrue(os.path.exists(tarball))
905
906 # trying an uncompressed one
907 base_name = os.path.join(tmpdir2, 'archive')
908 old_dir = os.getcwd()
909 os.chdir(tmpdir)
910 try:
911 _make_tarball(splitdrive(base_name)[1], '.', compress=None)
912 finally:
913 os.chdir(old_dir)
914 tarball = base_name + '.tar'
915 self.assertTrue(os.path.exists(tarball))
916
917 def _tarinfo(self, path):
918 tar = tarfile.open(path)
919 try:
920 names = tar.getnames()
921 names.sort()
922 return tuple(names)
923 finally:
924 tar.close()
925
926 def _create_files(self):
927 # creating something to tar
928 tmpdir = self.mkdtemp()
929 dist = os.path.join(tmpdir, 'dist')
930 os.mkdir(dist)
Éric Araujoa7e33a12011-08-12 19:51:35 +0200931 write_file((dist, 'file1'), 'xxx')
932 write_file((dist, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000933 os.mkdir(os.path.join(dist, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200934 write_file((dist, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000935 os.mkdir(os.path.join(dist, 'sub2'))
936 tmpdir2 = self.mkdtemp()
937 base_name = os.path.join(tmpdir2, 'archive')
938 return tmpdir, tmpdir2, base_name
939
Ezio Melotti975077a2011-05-19 22:03:22 +0300940 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000941 @unittest.skipUnless(find_executable('tar') and find_executable('gzip'),
942 'Need the tar command to run')
943 def test_tarfile_vs_tar(self):
944 tmpdir, tmpdir2, base_name = self._create_files()
945 old_dir = os.getcwd()
946 os.chdir(tmpdir)
947 try:
948 _make_tarball(base_name, 'dist')
949 finally:
950 os.chdir(old_dir)
951
952 # check if the compressed tarball was created
953 tarball = base_name + '.tar.gz'
954 self.assertTrue(os.path.exists(tarball))
955
956 # now create another tarball using `tar`
957 tarball2 = os.path.join(tmpdir, 'archive2.tar.gz')
958 tar_cmd = ['tar', '-cf', 'archive2.tar', 'dist']
959 gzip_cmd = ['gzip', '-f9', 'archive2.tar']
960 old_dir = os.getcwd()
961 os.chdir(tmpdir)
962 try:
963 with captured_stdout() as s:
964 spawn(tar_cmd)
965 spawn(gzip_cmd)
966 finally:
967 os.chdir(old_dir)
968
969 self.assertTrue(os.path.exists(tarball2))
970 # let's compare both tarballs
Ezio Melottib3aedd42010-11-20 19:04:17 +0000971 self.assertEqual(self._tarinfo(tarball), self._tarinfo(tarball2))
Tarek Ziadé396fad72010-02-23 05:30:31 +0000972
973 # trying an uncompressed one
974 base_name = os.path.join(tmpdir2, 'archive')
975 old_dir = os.getcwd()
976 os.chdir(tmpdir)
977 try:
978 _make_tarball(base_name, 'dist', compress=None)
979 finally:
980 os.chdir(old_dir)
981 tarball = base_name + '.tar'
982 self.assertTrue(os.path.exists(tarball))
983
984 # now for a dry_run
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, dry_run=True)
990 finally:
991 os.chdir(old_dir)
992 tarball = base_name + '.tar'
993 self.assertTrue(os.path.exists(tarball))
994
Ezio Melotti975077a2011-05-19 22:03:22 +0300995 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000996 @unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run')
997 def test_make_zipfile(self):
998 # creating something to tar
999 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +02001000 write_file((tmpdir, 'file1'), 'xxx')
1001 write_file((tmpdir, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +00001002
1003 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001004 # force shutil to create the directory
1005 os.rmdir(tmpdir2)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001006 base_name = os.path.join(tmpdir2, 'archive')
1007 _make_zipfile(base_name, tmpdir)
1008
1009 # check if the compressed tarball was created
1010 tarball = base_name + '.zip'
Éric Araujo1c505492010-11-06 02:12:51 +00001011 self.assertTrue(os.path.exists(tarball))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001012
1013
1014 def test_make_archive(self):
1015 tmpdir = self.mkdtemp()
1016 base_name = os.path.join(tmpdir, 'archive')
1017 self.assertRaises(ValueError, make_archive, base_name, 'xxx')
1018
Ezio Melotti975077a2011-05-19 22:03:22 +03001019 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001020 def test_make_archive_owner_group(self):
1021 # testing make_archive with owner and group, with various combinations
1022 # this works even if there's not gid/uid support
1023 if UID_GID_SUPPORT:
1024 group = grp.getgrgid(0)[0]
1025 owner = pwd.getpwuid(0)[0]
1026 else:
1027 group = owner = 'root'
1028
1029 base_dir, root_dir, base_name = self._create_files()
1030 base_name = os.path.join(self.mkdtemp() , 'archive')
1031 res = make_archive(base_name, 'zip', root_dir, base_dir, owner=owner,
1032 group=group)
1033 self.assertTrue(os.path.exists(res))
1034
1035 res = make_archive(base_name, 'zip', root_dir, base_dir)
1036 self.assertTrue(os.path.exists(res))
1037
1038 res = make_archive(base_name, 'tar', root_dir, base_dir,
1039 owner=owner, group=group)
1040 self.assertTrue(os.path.exists(res))
1041
1042 res = make_archive(base_name, 'tar', root_dir, base_dir,
1043 owner='kjhkjhkjg', group='oihohoh')
1044 self.assertTrue(os.path.exists(res))
1045
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001046
Ezio Melotti975077a2011-05-19 22:03:22 +03001047 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001048 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1049 def test_tarfile_root_owner(self):
1050 tmpdir, tmpdir2, base_name = self._create_files()
1051 old_dir = os.getcwd()
1052 os.chdir(tmpdir)
1053 group = grp.getgrgid(0)[0]
1054 owner = pwd.getpwuid(0)[0]
1055 try:
1056 archive_name = _make_tarball(base_name, 'dist', compress=None,
1057 owner=owner, group=group)
1058 finally:
1059 os.chdir(old_dir)
1060
1061 # check if the compressed tarball was created
1062 self.assertTrue(os.path.exists(archive_name))
1063
1064 # now checks the rights
1065 archive = tarfile.open(archive_name)
1066 try:
1067 for member in archive.getmembers():
Ezio Melottib3aedd42010-11-20 19:04:17 +00001068 self.assertEqual(member.uid, 0)
1069 self.assertEqual(member.gid, 0)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001070 finally:
1071 archive.close()
1072
1073 def test_make_archive_cwd(self):
1074 current_dir = os.getcwd()
1075 def _breaks(*args, **kw):
1076 raise RuntimeError()
1077
1078 register_archive_format('xxx', _breaks, [], 'xxx file')
1079 try:
1080 try:
1081 make_archive('xxx', 'xxx', root_dir=self.mkdtemp())
1082 except Exception:
1083 pass
Ezio Melottib3aedd42010-11-20 19:04:17 +00001084 self.assertEqual(os.getcwd(), current_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001085 finally:
1086 unregister_archive_format('xxx')
1087
1088 def test_register_archive_format(self):
1089
1090 self.assertRaises(TypeError, register_archive_format, 'xxx', 1)
1091 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1092 1)
1093 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1094 [(1, 2), (1, 2, 3)])
1095
1096 register_archive_format('xxx', lambda: x, [(1, 2)], 'xxx file')
1097 formats = [name for name, params in get_archive_formats()]
1098 self.assertIn('xxx', formats)
1099
1100 unregister_archive_format('xxx')
1101 formats = [name for name, params in get_archive_formats()]
1102 self.assertNotIn('xxx', formats)
1103
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001104 def _compare_dirs(self, dir1, dir2):
1105 # check that dir1 and dir2 are equivalent,
1106 # return the diff
1107 diff = []
1108 for root, dirs, files in os.walk(dir1):
1109 for file_ in files:
1110 path = os.path.join(root, file_)
1111 target_path = os.path.join(dir2, os.path.split(path)[-1])
1112 if not os.path.exists(target_path):
1113 diff.append(file_)
1114 return diff
1115
Ezio Melotti975077a2011-05-19 22:03:22 +03001116 @requires_zlib
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001117 def test_unpack_archive(self):
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001118 formats = ['tar', 'gztar', 'zip']
1119 if BZ2_SUPPORTED:
1120 formats.append('bztar')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001121
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001122 for format in formats:
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001123 tmpdir = self.mkdtemp()
1124 base_dir, root_dir, base_name = self._create_files()
1125 tmpdir2 = self.mkdtemp()
1126 filename = make_archive(base_name, format, root_dir, base_dir)
1127
1128 # let's try to unpack it now
1129 unpack_archive(filename, tmpdir2)
1130 diff = self._compare_dirs(tmpdir, tmpdir2)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001131 self.assertEqual(diff, [])
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001132
Nick Coghlanabf202d2011-03-16 13:52:20 -04001133 # and again, this time with the format specified
1134 tmpdir3 = self.mkdtemp()
1135 unpack_archive(filename, tmpdir3, format=format)
1136 diff = self._compare_dirs(tmpdir, tmpdir3)
1137 self.assertEqual(diff, [])
1138 self.assertRaises(shutil.ReadError, unpack_archive, TESTFN)
1139 self.assertRaises(ValueError, unpack_archive, TESTFN, format='xxx')
1140
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001141 def test_unpack_registery(self):
1142
1143 formats = get_unpack_formats()
1144
1145 def _boo(filename, extract_dir, extra):
Ezio Melottib3aedd42010-11-20 19:04:17 +00001146 self.assertEqual(extra, 1)
1147 self.assertEqual(filename, 'stuff.boo')
1148 self.assertEqual(extract_dir, 'xx')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001149
1150 register_unpack_format('Boo', ['.boo', '.b2'], _boo, [('extra', 1)])
1151 unpack_archive('stuff.boo', 'xx')
1152
1153 # trying to register a .boo unpacker again
1154 self.assertRaises(RegistryError, register_unpack_format, 'Boo2',
1155 ['.boo'], _boo)
1156
1157 # should work now
1158 unregister_unpack_format('Boo')
1159 register_unpack_format('Boo2', ['.boo'], _boo)
1160 self.assertIn(('Boo2', ['.boo'], ''), get_unpack_formats())
1161 self.assertNotIn(('Boo', ['.boo'], ''), get_unpack_formats())
1162
1163 # let's leave a clean state
1164 unregister_unpack_format('Boo2')
Ezio Melottib3aedd42010-11-20 19:04:17 +00001165 self.assertEqual(get_unpack_formats(), formats)
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001166
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001167 @unittest.skipUnless(hasattr(shutil, 'disk_usage'),
1168 "disk_usage not available on this platform")
1169 def test_disk_usage(self):
1170 usage = shutil.disk_usage(os.getcwd())
Éric Araujo2ee61882011-07-02 16:45:45 +02001171 self.assertGreater(usage.total, 0)
1172 self.assertGreater(usage.used, 0)
1173 self.assertGreaterEqual(usage.free, 0)
1174 self.assertGreaterEqual(usage.total, usage.used)
1175 self.assertGreater(usage.total, usage.free)
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001176
Sandro Tosid902a142011-08-22 23:28:27 +02001177 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1178 @unittest.skipUnless(hasattr(os, 'chown'), 'requires os.chown')
1179 def test_chown(self):
1180
1181 # cleaned-up automatically by TestShutil.tearDown method
1182 dirname = self.mkdtemp()
1183 filename = tempfile.mktemp(dir=dirname)
1184 write_file(filename, 'testing chown function')
1185
1186 with self.assertRaises(ValueError):
1187 shutil.chown(filename)
1188
1189 with self.assertRaises(LookupError):
1190 shutil.chown(filename, user='non-exising username')
1191
1192 with self.assertRaises(LookupError):
1193 shutil.chown(filename, group='non-exising groupname')
1194
1195 with self.assertRaises(TypeError):
1196 shutil.chown(filename, b'spam')
1197
1198 with self.assertRaises(TypeError):
1199 shutil.chown(filename, 3.14)
1200
1201 uid = os.getuid()
1202 gid = os.getgid()
1203
1204 def check_chown(path, uid=None, gid=None):
1205 s = os.stat(filename)
1206 if uid is not None:
1207 self.assertEqual(uid, s.st_uid)
1208 if gid is not None:
1209 self.assertEqual(gid, s.st_gid)
1210
1211 shutil.chown(filename, uid, gid)
1212 check_chown(filename, uid, gid)
1213 shutil.chown(filename, uid)
1214 check_chown(filename, uid)
1215 shutil.chown(filename, user=uid)
1216 check_chown(filename, uid)
1217 shutil.chown(filename, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001218 check_chown(filename, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001219
1220 shutil.chown(dirname, uid, gid)
1221 check_chown(dirname, uid, gid)
1222 shutil.chown(dirname, uid)
1223 check_chown(dirname, uid)
1224 shutil.chown(dirname, user=uid)
1225 check_chown(dirname, uid)
1226 shutil.chown(dirname, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001227 check_chown(dirname, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001228
1229 user = pwd.getpwuid(uid)[0]
1230 group = grp.getgrgid(gid)[0]
1231 shutil.chown(filename, user, group)
1232 check_chown(filename, uid, gid)
1233 shutil.chown(dirname, user, group)
1234 check_chown(dirname, uid, gid)
1235
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001236 def test_copy_return_value(self):
1237 # copy and copy2 both return their destination path.
1238 for fn in (shutil.copy, shutil.copy2):
1239 src_dir = self.mkdtemp()
1240 dst_dir = self.mkdtemp()
1241 src = os.path.join(src_dir, 'foo')
1242 write_file(src, 'foo')
1243 rv = fn(src, dst_dir)
1244 self.assertEqual(rv, os.path.join(dst_dir, 'foo'))
1245 rv = fn(src, os.path.join(dst_dir, 'bar'))
1246 self.assertEqual(rv, os.path.join(dst_dir, 'bar'))
1247
1248 def test_copyfile_return_value(self):
1249 # copytree returns its destination path.
1250 src_dir = self.mkdtemp()
1251 dst_dir = self.mkdtemp()
1252 dst_file = os.path.join(dst_dir, 'bar')
1253 src_file = os.path.join(src_dir, 'foo')
1254 write_file(src_file, 'foo')
1255 rv = shutil.copyfile(src_file, dst_file)
1256 self.assertTrue(os.path.exists(rv))
1257 self.assertEqual(read_file(src_file), read_file(dst_file))
1258
Hynek Schlawack48653762012-10-07 12:49:58 +02001259 def test_copyfile_same_file(self):
1260 # copyfile() should raise SameFileError if the source and destination
1261 # are the same.
1262 src_dir = self.mkdtemp()
1263 src_file = os.path.join(src_dir, 'foo')
1264 write_file(src_file, 'foo')
1265 self.assertRaises(SameFileError, shutil.copyfile, src_file, src_file)
Hynek Schlawack27ddb572012-10-28 13:59:27 +01001266 # But Error should work too, to stay backward compatible.
1267 self.assertRaises(Error, shutil.copyfile, src_file, src_file)
Hynek Schlawack48653762012-10-07 12:49:58 +02001268
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001269 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):
1283 self.temp_dir = tempfile.mkdtemp()
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,
1288 suffix=".exe")
1289 os.chmod(self.temp_file.name, stat.S_IXUSR)
1290 self.addCleanup(self.temp_file.close)
1291 self.dir, self.file = os.path.split(self.temp_file.name)
1292
1293 def test_basic(self):
1294 # Given an EXE in a directory, it should be returned.
1295 rv = shutil.which(self.file, path=self.dir)
1296 self.assertEqual(rv, self.temp_file.name)
1297
1298 def test_full_path_short_circuit(self):
1299 # When given the fully qualified path to an executable that exists,
1300 # it should be returned.
1301 rv = shutil.which(self.temp_file.name, path=self.temp_dir)
1302 self.assertEqual(self.temp_file.name, rv)
1303
1304 def test_non_matching_mode(self):
1305 # Set the file read-only and ask for writeable files.
1306 os.chmod(self.temp_file.name, stat.S_IREAD)
1307 rv = shutil.which(self.file, path=self.dir, mode=os.W_OK)
1308 self.assertIsNone(rv)
1309
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001310 def test_relative(self):
1311 old_cwd = os.getcwd()
1312 base_dir, tail_dir = os.path.split(self.dir)
1313 os.chdir(base_dir)
1314 try:
1315 rv = shutil.which(self.file, path=tail_dir)
1316 self.assertEqual(rv, os.path.join(tail_dir, self.file))
1317 finally:
1318 os.chdir(old_cwd)
1319
Brian Curtinc57a3452012-06-22 16:00:30 -05001320 def test_nonexistent_file(self):
1321 # Return None when no matching executable file is found on the path.
1322 rv = shutil.which("foo.exe", path=self.dir)
1323 self.assertIsNone(rv)
1324
1325 @unittest.skipUnless(sys.platform == "win32",
1326 "pathext check is Windows-only")
1327 def test_pathext_checking(self):
1328 # Ask for the file without the ".exe" extension, then ensure that
1329 # it gets found properly with the extension.
1330 rv = shutil.which(self.temp_file.name[:-4], path=self.dir)
1331 self.assertEqual(self.temp_file.name, rv)
1332
1333
Christian Heimesada8c3b2008-03-18 18:26:33 +00001334class TestMove(unittest.TestCase):
1335
1336 def setUp(self):
1337 filename = "foo"
1338 self.src_dir = tempfile.mkdtemp()
1339 self.dst_dir = tempfile.mkdtemp()
1340 self.src_file = os.path.join(self.src_dir, filename)
1341 self.dst_file = os.path.join(self.dst_dir, filename)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001342 with open(self.src_file, "wb") as f:
1343 f.write(b"spam")
1344
1345 def tearDown(self):
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001346 for d in (self.src_dir, self.dst_dir):
Christian Heimesada8c3b2008-03-18 18:26:33 +00001347 try:
1348 if d:
1349 shutil.rmtree(d)
1350 except:
1351 pass
1352
1353 def _check_move_file(self, src, dst, real_dst):
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001354 with open(src, "rb") as f:
1355 contents = f.read()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001356 shutil.move(src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001357 with open(real_dst, "rb") as f:
1358 self.assertEqual(contents, f.read())
Christian Heimesada8c3b2008-03-18 18:26:33 +00001359 self.assertFalse(os.path.exists(src))
1360
1361 def _check_move_dir(self, src, dst, real_dst):
1362 contents = sorted(os.listdir(src))
1363 shutil.move(src, dst)
1364 self.assertEqual(contents, sorted(os.listdir(real_dst)))
1365 self.assertFalse(os.path.exists(src))
1366
1367 def test_move_file(self):
1368 # Move a file to another location on the same filesystem.
1369 self._check_move_file(self.src_file, self.dst_file, self.dst_file)
1370
1371 def test_move_file_to_dir(self):
1372 # Move a file inside an existing dir on the same filesystem.
1373 self._check_move_file(self.src_file, self.dst_dir, self.dst_file)
1374
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001375 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001376 def test_move_file_other_fs(self):
1377 # Move a file to an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001378 self.test_move_file()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001379
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001380 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001381 def test_move_file_to_dir_other_fs(self):
1382 # Move a file to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001383 self.test_move_file_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001384
1385 def test_move_dir(self):
1386 # Move a dir to another location on the same filesystem.
1387 dst_dir = tempfile.mktemp()
1388 try:
1389 self._check_move_dir(self.src_dir, dst_dir, dst_dir)
1390 finally:
1391 try:
1392 shutil.rmtree(dst_dir)
1393 except:
1394 pass
1395
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001396 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001397 def test_move_dir_other_fs(self):
1398 # Move a dir to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001399 self.test_move_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001400
1401 def test_move_dir_to_dir(self):
1402 # Move a dir inside an existing dir on the same filesystem.
1403 self._check_move_dir(self.src_dir, self.dst_dir,
1404 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1405
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001406 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001407 def test_move_dir_to_dir_other_fs(self):
1408 # Move a dir inside an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001409 self.test_move_dir_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001410
1411 def test_existing_file_inside_dest_dir(self):
1412 # A file with the same name inside the destination dir already exists.
1413 with open(self.dst_file, "wb"):
1414 pass
1415 self.assertRaises(shutil.Error, shutil.move, self.src_file, self.dst_dir)
1416
1417 def test_dont_move_dir_in_itself(self):
1418 # Moving a dir inside itself raises an Error.
1419 dst = os.path.join(self.src_dir, "bar")
1420 self.assertRaises(shutil.Error, shutil.move, self.src_dir, dst)
1421
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001422 def test_destinsrc_false_negative(self):
1423 os.mkdir(TESTFN)
1424 try:
1425 for src, dst in [('srcdir', 'srcdir/dest')]:
1426 src = os.path.join(TESTFN, src)
1427 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001428 self.assertTrue(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001429 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001430 'dst (%s) is not in src (%s)' % (dst, src))
1431 finally:
1432 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001433
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001434 def test_destinsrc_false_positive(self):
1435 os.mkdir(TESTFN)
1436 try:
1437 for src, dst in [('srcdir', 'src/dest'), ('srcdir', 'srcdir.new')]:
1438 src = os.path.join(TESTFN, src)
1439 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001440 self.assertFalse(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001441 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001442 'dst (%s) is in src (%s)' % (dst, src))
1443 finally:
1444 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimes9bd667a2008-01-20 15:14:11 +00001445
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +01001446 @support.skip_unless_symlink
1447 @mock_rename
1448 def test_move_file_symlink(self):
1449 dst = os.path.join(self.src_dir, 'bar')
1450 os.symlink(self.src_file, dst)
1451 shutil.move(dst, self.dst_file)
1452 self.assertTrue(os.path.islink(self.dst_file))
1453 self.assertTrue(os.path.samefile(self.src_file, self.dst_file))
1454
1455 @support.skip_unless_symlink
1456 @mock_rename
1457 def test_move_file_symlink_to_dir(self):
1458 filename = "bar"
1459 dst = os.path.join(self.src_dir, filename)
1460 os.symlink(self.src_file, dst)
1461 shutil.move(dst, self.dst_dir)
1462 final_link = os.path.join(self.dst_dir, filename)
1463 self.assertTrue(os.path.islink(final_link))
1464 self.assertTrue(os.path.samefile(self.src_file, final_link))
1465
1466 @support.skip_unless_symlink
1467 @mock_rename
1468 def test_move_dangling_symlink(self):
1469 src = os.path.join(self.src_dir, 'baz')
1470 dst = os.path.join(self.src_dir, 'bar')
1471 os.symlink(src, dst)
1472 dst_link = os.path.join(self.dst_dir, 'quux')
1473 shutil.move(dst, dst_link)
1474 self.assertTrue(os.path.islink(dst_link))
1475 self.assertEqual(os.path.realpath(src), os.path.realpath(dst_link))
1476
1477 @support.skip_unless_symlink
1478 @mock_rename
1479 def test_move_dir_symlink(self):
1480 src = os.path.join(self.src_dir, 'baz')
1481 dst = os.path.join(self.src_dir, 'bar')
1482 os.mkdir(src)
1483 os.symlink(src, dst)
1484 dst_link = os.path.join(self.dst_dir, 'quux')
1485 shutil.move(dst, dst_link)
1486 self.assertTrue(os.path.islink(dst_link))
1487 self.assertTrue(os.path.samefile(src, dst_link))
1488
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001489 def test_move_return_value(self):
1490 rv = shutil.move(self.src_file, self.dst_dir)
1491 self.assertEqual(rv,
1492 os.path.join(self.dst_dir, os.path.basename(self.src_file)))
1493
1494 def test_move_as_rename_return_value(self):
1495 rv = shutil.move(self.src_file, os.path.join(self.dst_dir, 'bar'))
1496 self.assertEqual(rv, os.path.join(self.dst_dir, 'bar'))
1497
Tarek Ziadé5340db32010-04-19 22:30:51 +00001498
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001499class TestCopyFile(unittest.TestCase):
1500
1501 _delete = False
1502
1503 class Faux(object):
1504 _entered = False
1505 _exited_with = None
1506 _raised = False
1507 def __init__(self, raise_in_exit=False, suppress_at_exit=True):
1508 self._raise_in_exit = raise_in_exit
1509 self._suppress_at_exit = suppress_at_exit
1510 def read(self, *args):
1511 return ''
1512 def __enter__(self):
1513 self._entered = True
1514 def __exit__(self, exc_type, exc_val, exc_tb):
1515 self._exited_with = exc_type, exc_val, exc_tb
1516 if self._raise_in_exit:
1517 self._raised = True
1518 raise IOError("Cannot close")
1519 return self._suppress_at_exit
1520
1521 def tearDown(self):
1522 if self._delete:
1523 del shutil.open
1524
1525 def _set_shutil_open(self, func):
1526 shutil.open = func
1527 self._delete = True
1528
1529 def test_w_source_open_fails(self):
1530 def _open(filename, mode='r'):
1531 if filename == 'srcfile':
1532 raise IOError('Cannot open "srcfile"')
1533 assert 0 # shouldn't reach here.
1534
1535 self._set_shutil_open(_open)
1536
1537 self.assertRaises(IOError, shutil.copyfile, 'srcfile', 'destfile')
1538
1539 def test_w_dest_open_fails(self):
1540
1541 srcfile = self.Faux()
1542
1543 def _open(filename, mode='r'):
1544 if filename == 'srcfile':
1545 return srcfile
1546 if filename == 'destfile':
1547 raise IOError('Cannot open "destfile"')
1548 assert 0 # shouldn't reach here.
1549
1550 self._set_shutil_open(_open)
1551
1552 shutil.copyfile('srcfile', 'destfile')
1553 self.assertTrue(srcfile._entered)
1554 self.assertTrue(srcfile._exited_with[0] is IOError)
1555 self.assertEqual(srcfile._exited_with[1].args,
1556 ('Cannot open "destfile"',))
1557
1558 def test_w_dest_close_fails(self):
1559
1560 srcfile = self.Faux()
1561 destfile = self.Faux(True)
1562
1563 def _open(filename, mode='r'):
1564 if filename == 'srcfile':
1565 return srcfile
1566 if filename == 'destfile':
1567 return destfile
1568 assert 0 # shouldn't reach here.
1569
1570 self._set_shutil_open(_open)
1571
1572 shutil.copyfile('srcfile', 'destfile')
1573 self.assertTrue(srcfile._entered)
1574 self.assertTrue(destfile._entered)
1575 self.assertTrue(destfile._raised)
1576 self.assertTrue(srcfile._exited_with[0] is IOError)
1577 self.assertEqual(srcfile._exited_with[1].args,
1578 ('Cannot close',))
1579
1580 def test_w_source_close_fails(self):
1581
1582 srcfile = self.Faux(True)
1583 destfile = self.Faux()
1584
1585 def _open(filename, mode='r'):
1586 if filename == 'srcfile':
1587 return srcfile
1588 if filename == 'destfile':
1589 return destfile
1590 assert 0 # shouldn't reach here.
1591
1592 self._set_shutil_open(_open)
1593
1594 self.assertRaises(IOError,
1595 shutil.copyfile, 'srcfile', 'destfile')
1596 self.assertTrue(srcfile._entered)
1597 self.assertTrue(destfile._entered)
1598 self.assertFalse(destfile._raised)
1599 self.assertTrue(srcfile._exited_with[0] is None)
1600 self.assertTrue(srcfile._raised)
1601
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001602 def test_move_dir_caseinsensitive(self):
1603 # Renames a folder to the same name
1604 # but a different case.
1605
1606 self.src_dir = tempfile.mkdtemp()
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001607 self.addCleanup(shutil.rmtree, self.src_dir, True)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001608 dst_dir = os.path.join(
1609 os.path.dirname(self.src_dir),
1610 os.path.basename(self.src_dir).upper())
1611 self.assertNotEqual(self.src_dir, dst_dir)
1612
1613 try:
1614 shutil.move(self.src_dir, dst_dir)
1615 self.assertTrue(os.path.isdir(dst_dir))
1616 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +02001617 os.rmdir(dst_dir)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001618
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001619class TermsizeTests(unittest.TestCase):
1620 def test_does_not_crash(self):
1621 """Check if get_terminal_size() returns a meaningful value.
1622
1623 There's no easy portable way to actually check the size of the
1624 terminal, so let's check if it returns something sensible instead.
1625 """
1626 size = shutil.get_terminal_size()
Antoine Pitroucfade362012-02-08 23:48:59 +01001627 self.assertGreaterEqual(size.columns, 0)
1628 self.assertGreaterEqual(size.lines, 0)
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001629
1630 def test_os_environ_first(self):
1631 "Check if environment variables have precedence"
1632
1633 with support.EnvironmentVarGuard() as env:
1634 env['COLUMNS'] = '777'
1635 size = shutil.get_terminal_size()
1636 self.assertEqual(size.columns, 777)
1637
1638 with support.EnvironmentVarGuard() as env:
1639 env['LINES'] = '888'
1640 size = shutil.get_terminal_size()
1641 self.assertEqual(size.lines, 888)
1642
1643 @unittest.skipUnless(os.isatty(sys.__stdout__.fileno()), "not on tty")
1644 def test_stty_match(self):
1645 """Check if stty returns the same results ignoring env
1646
1647 This test will fail if stdin and stdout are connected to
1648 different terminals with different sizes. Nevertheless, such
1649 situations should be pretty rare.
1650 """
1651 try:
1652 size = subprocess.check_output(['stty', 'size']).decode().split()
1653 except (FileNotFoundError, subprocess.CalledProcessError):
1654 self.skipTest("stty invocation failed")
1655 expected = (int(size[1]), int(size[0])) # reversed order
1656
1657 with support.EnvironmentVarGuard() as env:
1658 del env['LINES']
1659 del env['COLUMNS']
1660 actual = shutil.get_terminal_size()
1661
1662 self.assertEqual(expected, actual)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001663
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001664
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001665def test_main():
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001666 support.run_unittest(TestShutil, TestMove, TestCopyFile,
Brian Curtinc57a3452012-06-22 16:00:30 -05001667 TermsizeTests, TestWhich)
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001668
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001669if __name__ == '__main__':
Walter Dörwald21d3a322003-05-01 17:45:56 +00001670 test_main()