blob: 5b4e7e76699abfc22886a61855b033d363adb787 [file] [log] [blame]
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001# Copyright (C) 2003 Python Software Foundation
2
3import unittest
Berker Peksag884afd92014-12-10 02:50:32 +02004import unittest.mock
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00005import shutil
6import tempfile
Johannes Gijsbers8e6f2de2004-11-23 09:27:27 +00007import sys
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +00008import stat
Brett Cannon1c3fa182004-06-19 21:11:35 +00009import os
10import os.path
Antoine Pitrouc041ab62012-01-02 19:18:02 +010011import errno
Nick Coghlan8ed3cf32011-03-16 14:05:35 -040012import functools
Antoine Pitroubcf2b592012-02-08 23:28:36 +010013import subprocess
Serhiy Storchaka41ad77c2014-08-07 19:38:37 +030014from contextlib import ExitStack
Tarek Ziadé396fad72010-02-23 05:30:31 +000015from os.path import splitdrive
16from distutils.spawn import find_executable, spawn
Serhiy Storchaka527ef072015-09-06 18:33:19 +030017from shutil import (make_archive,
Tarek Ziadé396fad72010-02-23 05:30:31 +000018 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
Serhiy Storchaka527ef072015-09-06 18:33:19 +030089def rlistdir(path):
90 res = []
91 for name in sorted(os.listdir(path)):
92 p = os.path.join(path, name)
93 if os.path.isdir(p) and not os.path.islink(p):
94 res.append(name + '/')
95 for n in rlistdir(p):
96 res.append(name + '/' + n)
97 else:
98 res.append(name)
99 return res
100
Éric Araujoa7e33a12011-08-12 19:51:35 +0200101
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000102class TestShutil(unittest.TestCase):
Tarek Ziadé396fad72010-02-23 05:30:31 +0000103
104 def setUp(self):
105 super(TestShutil, self).setUp()
106 self.tempdirs = []
107
108 def tearDown(self):
109 super(TestShutil, self).tearDown()
110 while self.tempdirs:
111 d = self.tempdirs.pop()
112 shutil.rmtree(d, os.name in ('nt', 'cygwin'))
113
Tarek Ziadé396fad72010-02-23 05:30:31 +0000114
115 def mkdtemp(self):
116 """Create a temporary directory that will be cleaned up.
117
118 Returns the path of the directory.
119 """
120 d = tempfile.mkdtemp()
121 self.tempdirs.append(d)
122 return d
Tarek Ziadé5340db32010-04-19 22:30:51 +0000123
Hynek Schlawack3b527782012-06-25 13:27:31 +0200124 def test_rmtree_works_on_bytes(self):
125 tmp = self.mkdtemp()
126 victim = os.path.join(tmp, 'killme')
127 os.mkdir(victim)
128 write_file(os.path.join(victim, 'somefile'), 'foo')
129 victim = os.fsencode(victim)
130 self.assertIsInstance(victim, bytes)
Serhiy Storchaka41ad77c2014-08-07 19:38:37 +0300131 win = (os.name == 'nt')
132 with self.assertWarns(DeprecationWarning) if win else ExitStack():
133 shutil.rmtree(victim)
Hynek Schlawack3b527782012-06-25 13:27:31 +0200134
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200135 @support.skip_unless_symlink
136 def test_rmtree_fails_on_symlink(self):
137 tmp = self.mkdtemp()
138 dir_ = os.path.join(tmp, 'dir')
139 os.mkdir(dir_)
140 link = os.path.join(tmp, 'link')
141 os.symlink(dir_, link)
142 self.assertRaises(OSError, shutil.rmtree, link)
143 self.assertTrue(os.path.exists(dir_))
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100144 self.assertTrue(os.path.lexists(link))
145 errors = []
146 def onerror(*args):
147 errors.append(args)
148 shutil.rmtree(link, onerror=onerror)
149 self.assertEqual(len(errors), 1)
150 self.assertIs(errors[0][0], os.path.islink)
151 self.assertEqual(errors[0][1], link)
152 self.assertIsInstance(errors[0][2][1], OSError)
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200153
154 @support.skip_unless_symlink
155 def test_rmtree_works_on_symlinks(self):
156 tmp = self.mkdtemp()
157 dir1 = os.path.join(tmp, 'dir1')
158 dir2 = os.path.join(dir1, 'dir2')
159 dir3 = os.path.join(tmp, 'dir3')
160 for d in dir1, dir2, dir3:
161 os.mkdir(d)
162 file1 = os.path.join(tmp, 'file1')
163 write_file(file1, 'foo')
164 link1 = os.path.join(dir1, 'link1')
165 os.symlink(dir2, link1)
166 link2 = os.path.join(dir1, 'link2')
167 os.symlink(dir3, link2)
168 link3 = os.path.join(dir1, 'link3')
169 os.symlink(file1, link3)
170 # make sure symlinks are removed but not followed
171 shutil.rmtree(dir1)
172 self.assertFalse(os.path.exists(dir1))
173 self.assertTrue(os.path.exists(dir3))
174 self.assertTrue(os.path.exists(file1))
175
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000176 def test_rmtree_errors(self):
177 # filename is guaranteed not to exist
178 filename = tempfile.mktemp()
Hynek Schlawackb5501102012-12-10 09:11:25 +0100179 self.assertRaises(FileNotFoundError, shutil.rmtree, filename)
180 # test that ignore_errors option is honored
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100181 shutil.rmtree(filename, ignore_errors=True)
182
183 # existing file
184 tmpdir = self.mkdtemp()
Hynek Schlawackb5501102012-12-10 09:11:25 +0100185 write_file((tmpdir, "tstfile"), "")
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100186 filename = os.path.join(tmpdir, "tstfile")
Hynek Schlawackb5501102012-12-10 09:11:25 +0100187 with self.assertRaises(NotADirectoryError) as cm:
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100188 shutil.rmtree(filename)
Hynek Schlawack87f9b462012-12-10 16:29:57 +0100189 # The reason for this rather odd construct is that Windows sprinkles
190 # a \*.* at the end of file names. But only sometimes on some buildbots
191 possible_args = [filename, os.path.join(filename, '*.*')]
192 self.assertIn(cm.exception.filename, possible_args)
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100193 self.assertTrue(os.path.exists(filename))
Hynek Schlawackb5501102012-12-10 09:11:25 +0100194 # test that ignore_errors option is honored
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100195 shutil.rmtree(filename, ignore_errors=True)
196 self.assertTrue(os.path.exists(filename))
197 errors = []
198 def onerror(*args):
199 errors.append(args)
200 shutil.rmtree(filename, onerror=onerror)
201 self.assertEqual(len(errors), 2)
202 self.assertIs(errors[0][0], os.listdir)
203 self.assertEqual(errors[0][1], filename)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100204 self.assertIsInstance(errors[0][2][1], NotADirectoryError)
Hynek Schlawack87f9b462012-12-10 16:29:57 +0100205 self.assertIn(errors[0][2][1].filename, possible_args)
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100206 self.assertIs(errors[1][0], os.rmdir)
207 self.assertEqual(errors[1][1], filename)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100208 self.assertIsInstance(errors[1][2][1], NotADirectoryError)
Hynek Schlawack87f9b462012-12-10 16:29:57 +0100209 self.assertIn(errors[1][2][1].filename, possible_args)
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000210
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000211
Serhiy Storchaka43767632013-11-03 21:31:38 +0200212 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod()')
213 @unittest.skipIf(sys.platform[:6] == 'cygwin',
214 "This test can't be run on Cygwin (issue #1071513).")
215 @unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0,
216 "This test can't be run reliably as root (issue #1076467).")
217 def test_on_error(self):
218 self.errorState = 0
219 os.mkdir(TESTFN)
220 self.addCleanup(shutil.rmtree, TESTFN)
Antoine Pitrou2f8a75c2012-06-23 21:28:15 +0200221
Serhiy Storchaka43767632013-11-03 21:31:38 +0200222 self.child_file_path = os.path.join(TESTFN, 'a')
223 self.child_dir_path = os.path.join(TESTFN, 'b')
224 support.create_empty_file(self.child_file_path)
225 os.mkdir(self.child_dir_path)
226 old_dir_mode = os.stat(TESTFN).st_mode
227 old_child_file_mode = os.stat(self.child_file_path).st_mode
228 old_child_dir_mode = os.stat(self.child_dir_path).st_mode
229 # Make unwritable.
230 new_mode = stat.S_IREAD|stat.S_IEXEC
231 os.chmod(self.child_file_path, new_mode)
232 os.chmod(self.child_dir_path, new_mode)
233 os.chmod(TESTFN, new_mode)
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000234
Serhiy Storchaka43767632013-11-03 21:31:38 +0200235 self.addCleanup(os.chmod, TESTFN, old_dir_mode)
236 self.addCleanup(os.chmod, self.child_file_path, old_child_file_mode)
237 self.addCleanup(os.chmod, self.child_dir_path, old_child_dir_mode)
Antoine Pitrou2f8a75c2012-06-23 21:28:15 +0200238
Serhiy Storchaka43767632013-11-03 21:31:38 +0200239 shutil.rmtree(TESTFN, onerror=self.check_args_to_onerror)
240 # Test whether onerror has actually been called.
241 self.assertEqual(self.errorState, 3,
242 "Expected call to onerror function did not happen.")
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000243
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000244 def check_args_to_onerror(self, func, arg, exc):
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000245 # test_rmtree_errors deliberately runs rmtree
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200246 # on a directory that is chmod 500, which will fail.
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000247 # This function is run when shutil.rmtree fails.
248 # 99.9% of the time it initially fails to remove
249 # a file in the directory, so the first time through
250 # func is os.remove.
251 # However, some Linux machines running ZFS on
252 # FUSE experienced a failure earlier in the process
253 # at os.listdir. The first failure may legally
254 # be either.
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200255 if self.errorState < 2:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200256 if func is os.unlink:
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200257 self.assertEqual(arg, self.child_file_path)
258 elif func is os.rmdir:
259 self.assertEqual(arg, self.child_dir_path)
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000260 else:
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200261 self.assertIs(func, os.listdir)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200262 self.assertIn(arg, [TESTFN, self.child_dir_path])
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000263 self.assertTrue(issubclass(exc[0], OSError))
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200264 self.errorState += 1
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000265 else:
266 self.assertEqual(func, os.rmdir)
267 self.assertEqual(arg, TESTFN)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000268 self.assertTrue(issubclass(exc[0], OSError))
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200269 self.errorState = 3
270
271 def test_rmtree_does_not_choke_on_failing_lstat(self):
272 try:
273 orig_lstat = os.lstat
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200274 def raiser(fn, *args, **kwargs):
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200275 if fn != TESTFN:
276 raise OSError()
277 else:
278 return orig_lstat(fn)
279 os.lstat = raiser
280
281 os.mkdir(TESTFN)
282 write_file((TESTFN, 'foo'), 'foo')
283 shutil.rmtree(TESTFN)
284 finally:
285 os.lstat = orig_lstat
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000286
Antoine Pitrou78091e62011-12-29 18:54:15 +0100287 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
288 @support.skip_unless_symlink
289 def test_copymode_follow_symlinks(self):
290 tmp_dir = self.mkdtemp()
291 src = os.path.join(tmp_dir, 'foo')
292 dst = os.path.join(tmp_dir, 'bar')
293 src_link = os.path.join(tmp_dir, 'baz')
294 dst_link = os.path.join(tmp_dir, 'quux')
295 write_file(src, 'foo')
296 write_file(dst, 'foo')
297 os.symlink(src, src_link)
298 os.symlink(dst, dst_link)
299 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
300 # file to file
301 os.chmod(dst, stat.S_IRWXO)
302 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
303 shutil.copymode(src, dst)
304 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
Antoine Pitrou3f48ac92014-01-01 02:50:45 +0100305 # On Windows, os.chmod does not follow symlinks (issue #15411)
306 if os.name != 'nt':
307 # follow src link
308 os.chmod(dst, stat.S_IRWXO)
309 shutil.copymode(src_link, dst)
310 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
311 # follow dst link
312 os.chmod(dst, stat.S_IRWXO)
313 shutil.copymode(src, dst_link)
314 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
315 # follow both links
316 os.chmod(dst, stat.S_IRWXO)
317 shutil.copymode(src_link, dst_link)
318 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100319
320 @unittest.skipUnless(hasattr(os, 'lchmod'), 'requires os.lchmod')
321 @support.skip_unless_symlink
322 def test_copymode_symlink_to_symlink(self):
323 tmp_dir = self.mkdtemp()
324 src = os.path.join(tmp_dir, 'foo')
325 dst = os.path.join(tmp_dir, 'bar')
326 src_link = os.path.join(tmp_dir, 'baz')
327 dst_link = os.path.join(tmp_dir, 'quux')
328 write_file(src, 'foo')
329 write_file(dst, 'foo')
330 os.symlink(src, src_link)
331 os.symlink(dst, dst_link)
332 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
333 os.chmod(dst, stat.S_IRWXU)
334 os.lchmod(src_link, stat.S_IRWXO|stat.S_IRWXG)
335 # link to link
336 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700337 shutil.copymode(src_link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100338 self.assertEqual(os.lstat(src_link).st_mode,
339 os.lstat(dst_link).st_mode)
340 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
341 # src link - use chmod
342 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700343 shutil.copymode(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100344 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
345 # dst link - use chmod
346 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700347 shutil.copymode(src, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100348 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
349
350 @unittest.skipIf(hasattr(os, 'lchmod'), 'requires os.lchmod to be missing')
351 @support.skip_unless_symlink
352 def test_copymode_symlink_to_symlink_wo_lchmod(self):
353 tmp_dir = self.mkdtemp()
354 src = os.path.join(tmp_dir, 'foo')
355 dst = os.path.join(tmp_dir, 'bar')
356 src_link = os.path.join(tmp_dir, 'baz')
357 dst_link = os.path.join(tmp_dir, 'quux')
358 write_file(src, 'foo')
359 write_file(dst, 'foo')
360 os.symlink(src, src_link)
361 os.symlink(dst, dst_link)
Larry Hastingsb4038062012-07-15 10:57:38 -0700362 shutil.copymode(src_link, dst_link, follow_symlinks=False) # silent fail
Antoine Pitrou78091e62011-12-29 18:54:15 +0100363
364 @support.skip_unless_symlink
365 def test_copystat_symlinks(self):
366 tmp_dir = self.mkdtemp()
367 src = os.path.join(tmp_dir, 'foo')
368 dst = os.path.join(tmp_dir, 'bar')
369 src_link = os.path.join(tmp_dir, 'baz')
370 dst_link = os.path.join(tmp_dir, 'qux')
371 write_file(src, 'foo')
372 src_stat = os.stat(src)
373 os.utime(src, (src_stat.st_atime,
374 src_stat.st_mtime - 42.0)) # ensure different mtimes
375 write_file(dst, 'bar')
376 self.assertNotEqual(os.stat(src).st_mtime, os.stat(dst).st_mtime)
377 os.symlink(src, src_link)
378 os.symlink(dst, dst_link)
379 if hasattr(os, 'lchmod'):
380 os.lchmod(src_link, stat.S_IRWXO)
381 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
382 os.lchflags(src_link, stat.UF_NODUMP)
383 src_link_stat = os.lstat(src_link)
384 # follow
385 if hasattr(os, 'lchmod'):
Larry Hastingsb4038062012-07-15 10:57:38 -0700386 shutil.copystat(src_link, dst_link, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100387 self.assertNotEqual(src_link_stat.st_mode, os.stat(dst).st_mode)
388 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700389 shutil.copystat(src_link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100390 dst_link_stat = os.lstat(dst_link)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700391 if os.utime in os.supports_follow_symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100392 for attr in 'st_atime', 'st_mtime':
393 # The modification times may be truncated in the new file.
394 self.assertLessEqual(getattr(src_link_stat, attr),
395 getattr(dst_link_stat, attr) + 1)
396 if hasattr(os, 'lchmod'):
397 self.assertEqual(src_link_stat.st_mode, dst_link_stat.st_mode)
398 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
399 self.assertEqual(src_link_stat.st_flags, dst_link_stat.st_flags)
400 # tell to follow but dst is not a link
Larry Hastingsb4038062012-07-15 10:57:38 -0700401 shutil.copystat(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100402 self.assertTrue(abs(os.stat(src).st_mtime - os.stat(dst).st_mtime) <
403 00000.1)
404
Ned Deilybaf75712012-05-10 17:05:19 -0700405 @unittest.skipUnless(hasattr(os, 'chflags') and
406 hasattr(errno, 'EOPNOTSUPP') and
407 hasattr(errno, 'ENOTSUP'),
408 "requires os.chflags, EOPNOTSUPP & ENOTSUP")
409 def test_copystat_handles_harmless_chflags_errors(self):
410 tmpdir = self.mkdtemp()
411 file1 = os.path.join(tmpdir, 'file1')
412 file2 = os.path.join(tmpdir, 'file2')
413 write_file(file1, 'xxx')
414 write_file(file2, 'xxx')
415
416 def make_chflags_raiser(err):
417 ex = OSError()
418
Larry Hastings90867a52012-06-22 17:01:41 -0700419 def _chflags_raiser(path, flags, *, follow_symlinks=True):
Ned Deilybaf75712012-05-10 17:05:19 -0700420 ex.errno = err
421 raise ex
422 return _chflags_raiser
423 old_chflags = os.chflags
424 try:
425 for err in errno.EOPNOTSUPP, errno.ENOTSUP:
426 os.chflags = make_chflags_raiser(err)
427 shutil.copystat(file1, file2)
428 # assert others errors break it
429 os.chflags = make_chflags_raiser(errno.EOPNOTSUPP + errno.ENOTSUP)
430 self.assertRaises(OSError, shutil.copystat, file1, file2)
431 finally:
432 os.chflags = old_chflags
433
Antoine Pitrou424246f2012-05-12 19:02:01 +0200434 @support.skip_unless_xattr
435 def test_copyxattr(self):
436 tmp_dir = self.mkdtemp()
437 src = os.path.join(tmp_dir, 'foo')
438 write_file(src, 'foo')
439 dst = os.path.join(tmp_dir, 'bar')
440 write_file(dst, 'bar')
441
442 # no xattr == no problem
443 shutil._copyxattr(src, dst)
444 # common case
445 os.setxattr(src, 'user.foo', b'42')
446 os.setxattr(src, 'user.bar', b'43')
447 shutil._copyxattr(src, dst)
Gregory P. Smith1093bf22014-01-17 12:01:22 -0800448 self.assertEqual(sorted(os.listxattr(src)), sorted(os.listxattr(dst)))
Antoine Pitrou424246f2012-05-12 19:02:01 +0200449 self.assertEqual(
450 os.getxattr(src, 'user.foo'),
451 os.getxattr(dst, 'user.foo'))
452 # check errors don't affect other attrs
453 os.remove(dst)
454 write_file(dst, 'bar')
455 os_error = OSError(errno.EPERM, 'EPERM')
456
Larry Hastings9cf065c2012-06-22 16:30:09 -0700457 def _raise_on_user_foo(fname, attr, val, **kwargs):
Antoine Pitrou424246f2012-05-12 19:02:01 +0200458 if attr == 'user.foo':
459 raise os_error
460 else:
Larry Hastings9cf065c2012-06-22 16:30:09 -0700461 orig_setxattr(fname, attr, val, **kwargs)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200462 try:
463 orig_setxattr = os.setxattr
464 os.setxattr = _raise_on_user_foo
465 shutil._copyxattr(src, dst)
Antoine Pitrou61597d32012-05-12 23:37:35 +0200466 self.assertIn('user.bar', os.listxattr(dst))
Antoine Pitrou424246f2012-05-12 19:02:01 +0200467 finally:
468 os.setxattr = orig_setxattr
Hynek Schlawack0beab052013-02-05 08:22:44 +0100469 # the source filesystem not supporting xattrs should be ok, too.
470 def _raise_on_src(fname, *, follow_symlinks=True):
471 if fname == src:
472 raise OSError(errno.ENOTSUP, 'Operation not supported')
473 return orig_listxattr(fname, follow_symlinks=follow_symlinks)
474 try:
475 orig_listxattr = os.listxattr
476 os.listxattr = _raise_on_src
477 shutil._copyxattr(src, dst)
478 finally:
479 os.listxattr = orig_listxattr
Antoine Pitrou424246f2012-05-12 19:02:01 +0200480
Larry Hastingsad5ae042012-07-14 17:55:11 -0700481 # test that shutil.copystat copies xattrs
482 src = os.path.join(tmp_dir, 'the_original')
483 write_file(src, src)
484 os.setxattr(src, 'user.the_value', b'fiddly')
485 dst = os.path.join(tmp_dir, 'the_copy')
486 write_file(dst, dst)
487 shutil.copystat(src, dst)
Hynek Schlawackc2d481f2012-07-16 17:11:10 +0200488 self.assertEqual(os.getxattr(dst, 'user.the_value'), b'fiddly')
Larry Hastingsad5ae042012-07-14 17:55:11 -0700489
Antoine Pitrou424246f2012-05-12 19:02:01 +0200490 @support.skip_unless_symlink
491 @support.skip_unless_xattr
492 @unittest.skipUnless(hasattr(os, 'geteuid') and os.geteuid() == 0,
493 'root privileges required')
494 def test_copyxattr_symlinks(self):
495 # On Linux, it's only possible to access non-user xattr for symlinks;
496 # which in turn require root privileges. This test should be expanded
497 # as soon as other platforms gain support for extended attributes.
498 tmp_dir = self.mkdtemp()
499 src = os.path.join(tmp_dir, 'foo')
500 src_link = os.path.join(tmp_dir, 'baz')
501 write_file(src, 'foo')
502 os.symlink(src, src_link)
503 os.setxattr(src, 'trusted.foo', b'42')
Larry Hastings9cf065c2012-06-22 16:30:09 -0700504 os.setxattr(src_link, 'trusted.foo', b'43', follow_symlinks=False)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200505 dst = os.path.join(tmp_dir, 'bar')
506 dst_link = os.path.join(tmp_dir, 'qux')
507 write_file(dst, 'bar')
508 os.symlink(dst, dst_link)
Larry Hastingsb4038062012-07-15 10:57:38 -0700509 shutil._copyxattr(src_link, dst_link, follow_symlinks=False)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700510 self.assertEqual(os.getxattr(dst_link, 'trusted.foo', follow_symlinks=False), b'43')
Antoine Pitrou424246f2012-05-12 19:02:01 +0200511 self.assertRaises(OSError, os.getxattr, dst, 'trusted.foo')
Larry Hastingsb4038062012-07-15 10:57:38 -0700512 shutil._copyxattr(src_link, dst, follow_symlinks=False)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200513 self.assertEqual(os.getxattr(dst, 'trusted.foo'), b'43')
514
Antoine Pitrou78091e62011-12-29 18:54:15 +0100515 @support.skip_unless_symlink
516 def test_copy_symlinks(self):
517 tmp_dir = self.mkdtemp()
518 src = os.path.join(tmp_dir, 'foo')
519 dst = os.path.join(tmp_dir, 'bar')
520 src_link = os.path.join(tmp_dir, 'baz')
521 write_file(src, 'foo')
522 os.symlink(src, src_link)
523 if hasattr(os, 'lchmod'):
524 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
525 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700526 shutil.copy(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 # follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700531 shutil.copy(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 if hasattr(os, 'lchmod'):
535 self.assertEqual(os.lstat(src_link).st_mode,
536 os.lstat(dst).st_mode)
537
538 @support.skip_unless_symlink
539 def test_copy2_symlinks(self):
540 tmp_dir = self.mkdtemp()
541 src = os.path.join(tmp_dir, 'foo')
542 dst = os.path.join(tmp_dir, 'bar')
543 src_link = os.path.join(tmp_dir, 'baz')
544 write_file(src, 'foo')
545 os.symlink(src, src_link)
546 if hasattr(os, 'lchmod'):
547 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
548 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
549 os.lchflags(src_link, stat.UF_NODUMP)
550 src_stat = os.stat(src)
551 src_link_stat = os.lstat(src_link)
552 # follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700553 shutil.copy2(src_link, dst, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100554 self.assertFalse(os.path.islink(dst))
555 self.assertEqual(read_file(src), read_file(dst))
556 os.remove(dst)
557 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700558 shutil.copy2(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100559 self.assertTrue(os.path.islink(dst))
560 self.assertEqual(os.readlink(dst), os.readlink(src_link))
561 dst_stat = os.lstat(dst)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700562 if os.utime in os.supports_follow_symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100563 for attr in 'st_atime', 'st_mtime':
564 # The modification times may be truncated in the new file.
565 self.assertLessEqual(getattr(src_link_stat, attr),
566 getattr(dst_stat, attr) + 1)
567 if hasattr(os, 'lchmod'):
568 self.assertEqual(src_link_stat.st_mode, dst_stat.st_mode)
569 self.assertNotEqual(src_stat.st_mode, dst_stat.st_mode)
570 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
571 self.assertEqual(src_link_stat.st_flags, dst_stat.st_flags)
572
Antoine Pitrou424246f2012-05-12 19:02:01 +0200573 @support.skip_unless_xattr
574 def test_copy2_xattr(self):
575 tmp_dir = self.mkdtemp()
576 src = os.path.join(tmp_dir, 'foo')
577 dst = os.path.join(tmp_dir, 'bar')
578 write_file(src, 'foo')
579 os.setxattr(src, 'user.foo', b'42')
580 shutil.copy2(src, dst)
581 self.assertEqual(
582 os.getxattr(src, 'user.foo'),
583 os.getxattr(dst, 'user.foo'))
584 os.remove(dst)
585
Antoine Pitrou78091e62011-12-29 18:54:15 +0100586 @support.skip_unless_symlink
587 def test_copyfile_symlinks(self):
588 tmp_dir = self.mkdtemp()
589 src = os.path.join(tmp_dir, 'src')
590 dst = os.path.join(tmp_dir, 'dst')
591 dst_link = os.path.join(tmp_dir, 'dst_link')
592 link = os.path.join(tmp_dir, 'link')
593 write_file(src, 'foo')
594 os.symlink(src, link)
595 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700596 shutil.copyfile(link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100597 self.assertTrue(os.path.islink(dst_link))
598 self.assertEqual(os.readlink(link), os.readlink(dst_link))
599 # follow
600 shutil.copyfile(link, dst)
601 self.assertFalse(os.path.islink(dst))
602
Hynek Schlawack2100b422012-06-23 20:28:32 +0200603 def test_rmtree_uses_safe_fd_version_if_available(self):
Hynek Schlawackd0f6e0a2012-06-29 08:28:20 +0200604 _use_fd_functions = ({os.open, os.stat, os.unlink, os.rmdir} <=
605 os.supports_dir_fd and
606 os.listdir in os.supports_fd and
607 os.stat in os.supports_follow_symlinks)
608 if _use_fd_functions:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200609 self.assertTrue(shutil._use_fd_functions)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000610 self.assertTrue(shutil.rmtree.avoids_symlink_attacks)
Hynek Schlawack2100b422012-06-23 20:28:32 +0200611 tmp_dir = self.mkdtemp()
612 d = os.path.join(tmp_dir, 'a')
613 os.mkdir(d)
614 try:
615 real_rmtree = shutil._rmtree_safe_fd
616 class Called(Exception): pass
617 def _raiser(*args, **kwargs):
618 raise Called
619 shutil._rmtree_safe_fd = _raiser
620 self.assertRaises(Called, shutil.rmtree, d)
621 finally:
622 shutil._rmtree_safe_fd = real_rmtree
623 else:
624 self.assertFalse(shutil._use_fd_functions)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000625 self.assertFalse(shutil.rmtree.avoids_symlink_attacks)
Hynek Schlawack2100b422012-06-23 20:28:32 +0200626
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000627 def test_rmtree_dont_delete_file(self):
628 # When called on a file instead of a directory, don't delete it.
629 handle, path = tempfile.mkstemp()
Victor Stinnerbf816222011-06-30 23:25:47 +0200630 os.close(handle)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200631 self.assertRaises(NotADirectoryError, shutil.rmtree, path)
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000632 os.remove(path)
633
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000634 def test_copytree_simple(self):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000635 src_dir = tempfile.mkdtemp()
636 dst_dir = os.path.join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200637 self.addCleanup(shutil.rmtree, src_dir)
638 self.addCleanup(shutil.rmtree, os.path.dirname(dst_dir))
639 write_file((src_dir, 'test.txt'), '123')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000640 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200641 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000642
Éric Araujoa7e33a12011-08-12 19:51:35 +0200643 shutil.copytree(src_dir, dst_dir)
644 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test.txt')))
645 self.assertTrue(os.path.isdir(os.path.join(dst_dir, 'test_dir')))
646 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test_dir',
647 'test.txt')))
648 actual = read_file((dst_dir, 'test.txt'))
649 self.assertEqual(actual, '123')
650 actual = read_file((dst_dir, 'test_dir', 'test.txt'))
651 self.assertEqual(actual, '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000652
Antoine Pitrou78091e62011-12-29 18:54:15 +0100653 @support.skip_unless_symlink
654 def test_copytree_symlinks(self):
655 tmp_dir = self.mkdtemp()
656 src_dir = os.path.join(tmp_dir, 'src')
657 dst_dir = os.path.join(tmp_dir, 'dst')
658 sub_dir = os.path.join(src_dir, 'sub')
659 os.mkdir(src_dir)
660 os.mkdir(sub_dir)
661 write_file((src_dir, 'file.txt'), 'foo')
662 src_link = os.path.join(sub_dir, 'link')
663 dst_link = os.path.join(dst_dir, 'sub/link')
664 os.symlink(os.path.join(src_dir, 'file.txt'),
665 src_link)
666 if hasattr(os, 'lchmod'):
667 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
668 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
669 os.lchflags(src_link, stat.UF_NODUMP)
670 src_stat = os.lstat(src_link)
671 shutil.copytree(src_dir, dst_dir, symlinks=True)
672 self.assertTrue(os.path.islink(os.path.join(dst_dir, 'sub', 'link')))
673 self.assertEqual(os.readlink(os.path.join(dst_dir, 'sub', 'link')),
674 os.path.join(src_dir, 'file.txt'))
675 dst_stat = os.lstat(dst_link)
676 if hasattr(os, 'lchmod'):
677 self.assertEqual(dst_stat.st_mode, src_stat.st_mode)
678 if hasattr(os, 'lchflags'):
679 self.assertEqual(dst_stat.st_flags, src_stat.st_flags)
680
Georg Brandl2ee470f2008-07-16 12:55:28 +0000681 def test_copytree_with_exclude(self):
Georg Brandl2ee470f2008-07-16 12:55:28 +0000682 # creating data
683 join = os.path.join
684 exists = os.path.exists
685 src_dir = tempfile.mkdtemp()
Georg Brandl2ee470f2008-07-16 12:55:28 +0000686 try:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000687 dst_dir = join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200688 write_file((src_dir, 'test.txt'), '123')
689 write_file((src_dir, 'test.tmp'), '123')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000690 os.mkdir(join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200691 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000692 os.mkdir(join(src_dir, 'test_dir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200693 write_file((src_dir, 'test_dir2', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000694 os.mkdir(join(src_dir, 'test_dir2', 'subdir'))
695 os.mkdir(join(src_dir, 'test_dir2', 'subdir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200696 write_file((src_dir, 'test_dir2', 'subdir', 'test.txt'), '456')
697 write_file((src_dir, 'test_dir2', 'subdir2', 'test.py'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000698
699 # testing glob-like patterns
700 try:
701 patterns = shutil.ignore_patterns('*.tmp', 'test_dir2')
702 shutil.copytree(src_dir, dst_dir, ignore=patterns)
703 # checking the result: some elements should not be copied
704 self.assertTrue(exists(join(dst_dir, 'test.txt')))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200705 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
706 self.assertFalse(exists(join(dst_dir, 'test_dir2')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000707 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200708 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000709 try:
710 patterns = shutil.ignore_patterns('*.tmp', 'subdir*')
711 shutil.copytree(src_dir, dst_dir, ignore=patterns)
712 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200713 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
714 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2')))
715 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000716 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200717 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000718
719 # testing callable-style
720 try:
721 def _filter(src, names):
722 res = []
723 for name in names:
724 path = os.path.join(src, name)
725
726 if (os.path.isdir(path) and
727 path.split()[-1] == 'subdir'):
728 res.append(name)
729 elif os.path.splitext(path)[-1] in ('.py'):
730 res.append(name)
731 return res
732
733 shutil.copytree(src_dir, dst_dir, ignore=_filter)
734
735 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200736 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2',
737 'test.py')))
738 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000739
740 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200741 shutil.rmtree(dst_dir)
Georg Brandl2ee470f2008-07-16 12:55:28 +0000742 finally:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000743 shutil.rmtree(src_dir)
744 shutil.rmtree(os.path.dirname(dst_dir))
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000745
Antoine Pitrouac601602013-08-16 19:35:02 +0200746 def test_copytree_retains_permissions(self):
747 tmp_dir = tempfile.mkdtemp()
748 src_dir = os.path.join(tmp_dir, 'source')
749 os.mkdir(src_dir)
750 dst_dir = os.path.join(tmp_dir, 'destination')
751 self.addCleanup(shutil.rmtree, tmp_dir)
752
753 os.chmod(src_dir, 0o777)
754 write_file((src_dir, 'permissive.txt'), '123')
755 os.chmod(os.path.join(src_dir, 'permissive.txt'), 0o777)
756 write_file((src_dir, 'restrictive.txt'), '456')
757 os.chmod(os.path.join(src_dir, 'restrictive.txt'), 0o600)
758 restrictive_subdir = tempfile.mkdtemp(dir=src_dir)
759 os.chmod(restrictive_subdir, 0o600)
760
761 shutil.copytree(src_dir, dst_dir)
Brett Cannon9c7eb552013-08-23 14:38:11 -0400762 self.assertEqual(os.stat(src_dir).st_mode, os.stat(dst_dir).st_mode)
763 self.assertEqual(os.stat(os.path.join(src_dir, 'permissive.txt')).st_mode,
Antoine Pitrouac601602013-08-16 19:35:02 +0200764 os.stat(os.path.join(dst_dir, 'permissive.txt')).st_mode)
Brett Cannon9c7eb552013-08-23 14:38:11 -0400765 self.assertEqual(os.stat(os.path.join(src_dir, 'restrictive.txt')).st_mode,
Antoine Pitrouac601602013-08-16 19:35:02 +0200766 os.stat(os.path.join(dst_dir, 'restrictive.txt')).st_mode)
767 restrictive_subdir_dst = os.path.join(dst_dir,
768 os.path.split(restrictive_subdir)[1])
Brett Cannon9c7eb552013-08-23 14:38:11 -0400769 self.assertEqual(os.stat(restrictive_subdir).st_mode,
Antoine Pitrouac601602013-08-16 19:35:02 +0200770 os.stat(restrictive_subdir_dst).st_mode)
771
Berker Peksag884afd92014-12-10 02:50:32 +0200772 @unittest.mock.patch('os.chmod')
773 def test_copytree_winerror(self, mock_patch):
774 # When copying to VFAT, copystat() raises OSError. On Windows, the
775 # exception object has a meaningful 'winerror' attribute, but not
776 # on other operating systems. Do not assume 'winerror' is set.
777 src_dir = tempfile.mkdtemp()
778 dst_dir = os.path.join(tempfile.mkdtemp(), 'destination')
779 self.addCleanup(shutil.rmtree, src_dir)
780 self.addCleanup(shutil.rmtree, os.path.dirname(dst_dir))
781
782 mock_patch.side_effect = PermissionError('ka-boom')
783 with self.assertRaises(shutil.Error):
784 shutil.copytree(src_dir, dst_dir)
785
Zachary Ware9fe6d862013-12-08 00:20:35 -0600786 @unittest.skipIf(os.name == 'nt', 'temporarily disabled on Windows')
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000787 @unittest.skipUnless(hasattr(os, 'link'), 'requires os.link')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000788 def test_dont_copy_file_onto_link_to_itself(self):
789 # bug 851123.
790 os.mkdir(TESTFN)
791 src = os.path.join(TESTFN, 'cheese')
792 dst = os.path.join(TESTFN, 'shop')
793 try:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000794 with open(src, 'w') as f:
795 f.write('cheddar')
796 os.link(src, dst)
Hynek Schlawack48653762012-10-07 12:49:58 +0200797 self.assertRaises(shutil.SameFileError, shutil.copyfile, src, dst)
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000798 with open(src, 'r') as f:
799 self.assertEqual(f.read(), 'cheddar')
800 os.remove(dst)
801 finally:
802 shutil.rmtree(TESTFN, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000803
Brian Curtin3b4499c2010-12-28 14:31:47 +0000804 @support.skip_unless_symlink
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000805 def test_dont_copy_file_onto_symlink_to_itself(self):
806 # bug 851123.
807 os.mkdir(TESTFN)
808 src = os.path.join(TESTFN, 'cheese')
809 dst = os.path.join(TESTFN, 'shop')
810 try:
811 with open(src, 'w') as f:
812 f.write('cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000813 # Using `src` here would mean we end up with a symlink pointing
814 # to TESTFN/TESTFN/cheese, while it should point at
815 # TESTFN/cheese.
816 os.symlink('cheese', dst)
Hynek Schlawack48653762012-10-07 12:49:58 +0200817 self.assertRaises(shutil.SameFileError, shutil.copyfile, src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +0000818 with open(src, 'r') as f:
819 self.assertEqual(f.read(), 'cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000820 os.remove(dst)
821 finally:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000822 shutil.rmtree(TESTFN, ignore_errors=True)
Johannes Gijsbers68128712004-08-14 13:57:08 +0000823
Brian Curtin3b4499c2010-12-28 14:31:47 +0000824 @support.skip_unless_symlink
Brian Curtind40e6f72010-07-08 21:39:08 +0000825 def test_rmtree_on_symlink(self):
826 # bug 1669.
827 os.mkdir(TESTFN)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000828 try:
Brian Curtind40e6f72010-07-08 21:39:08 +0000829 src = os.path.join(TESTFN, 'cheese')
830 dst = os.path.join(TESTFN, 'shop')
831 os.mkdir(src)
832 os.symlink(src, dst)
833 self.assertRaises(OSError, shutil.rmtree, dst)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200834 shutil.rmtree(dst, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000835 finally:
Brian Curtind40e6f72010-07-08 21:39:08 +0000836 shutil.rmtree(TESTFN, ignore_errors=True)
837
Serhiy Storchaka43767632013-11-03 21:31:38 +0200838 # Issue #3002: copyfile and copytree block indefinitely on named pipes
839 @unittest.skipUnless(hasattr(os, "mkfifo"), 'requires os.mkfifo()')
840 def test_copyfile_named_pipe(self):
841 os.mkfifo(TESTFN)
842 try:
843 self.assertRaises(shutil.SpecialFileError,
844 shutil.copyfile, TESTFN, TESTFN2)
845 self.assertRaises(shutil.SpecialFileError,
846 shutil.copyfile, __file__, TESTFN)
847 finally:
848 os.remove(TESTFN)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000849
Serhiy Storchaka43767632013-11-03 21:31:38 +0200850 @unittest.skipUnless(hasattr(os, "mkfifo"), 'requires os.mkfifo()')
851 @support.skip_unless_symlink
852 def test_copytree_named_pipe(self):
853 os.mkdir(TESTFN)
854 try:
855 subdir = os.path.join(TESTFN, "subdir")
856 os.mkdir(subdir)
857 pipe = os.path.join(subdir, "mypipe")
858 os.mkfifo(pipe)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000859 try:
Serhiy Storchaka43767632013-11-03 21:31:38 +0200860 shutil.copytree(TESTFN, TESTFN2)
861 except shutil.Error as e:
862 errors = e.args[0]
863 self.assertEqual(len(errors), 1)
864 src, dst, error_msg = errors[0]
865 self.assertEqual("`%s` is a named pipe" % pipe, error_msg)
866 else:
867 self.fail("shutil.Error should have been raised")
868 finally:
869 shutil.rmtree(TESTFN, ignore_errors=True)
870 shutil.rmtree(TESTFN2, ignore_errors=True)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000871
Tarek Ziadé5340db32010-04-19 22:30:51 +0000872 def test_copytree_special_func(self):
873
874 src_dir = self.mkdtemp()
875 dst_dir = os.path.join(self.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200876 write_file((src_dir, 'test.txt'), '123')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000877 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200878 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000879
880 copied = []
881 def _copy(src, dst):
882 copied.append((src, dst))
883
884 shutil.copytree(src_dir, dst_dir, copy_function=_copy)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000885 self.assertEqual(len(copied), 2)
Tarek Ziadé5340db32010-04-19 22:30:51 +0000886
Brian Curtin3b4499c2010-12-28 14:31:47 +0000887 @support.skip_unless_symlink
Tarek Ziadéfb437512010-04-20 08:57:33 +0000888 def test_copytree_dangling_symlinks(self):
889
890 # a dangling symlink raises an error at the end
891 src_dir = self.mkdtemp()
892 dst_dir = os.path.join(self.mkdtemp(), 'destination')
893 os.symlink('IDONTEXIST', os.path.join(src_dir, 'test.txt'))
894 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200895 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadéfb437512010-04-20 08:57:33 +0000896 self.assertRaises(Error, shutil.copytree, src_dir, dst_dir)
897
898 # a dangling symlink is ignored with the proper flag
899 dst_dir = os.path.join(self.mkdtemp(), 'destination2')
900 shutil.copytree(src_dir, dst_dir, ignore_dangling_symlinks=True)
901 self.assertNotIn('test.txt', os.listdir(dst_dir))
902
903 # a dangling symlink is copied if symlinks=True
904 dst_dir = os.path.join(self.mkdtemp(), 'destination3')
905 shutil.copytree(src_dir, dst_dir, symlinks=True)
906 self.assertIn('test.txt', os.listdir(dst_dir))
907
Berker Peksag5a294d82015-07-25 14:53:48 +0300908 @support.skip_unless_symlink
909 def test_copytree_symlink_dir(self):
910 src_dir = self.mkdtemp()
911 dst_dir = os.path.join(self.mkdtemp(), 'destination')
912 os.mkdir(os.path.join(src_dir, 'real_dir'))
913 with open(os.path.join(src_dir, 'real_dir', 'test.txt'), 'w'):
914 pass
915 os.symlink(os.path.join(src_dir, 'real_dir'),
916 os.path.join(src_dir, 'link_to_dir'),
917 target_is_directory=True)
918
919 shutil.copytree(src_dir, dst_dir, symlinks=False)
920 self.assertFalse(os.path.islink(os.path.join(dst_dir, 'link_to_dir')))
921 self.assertIn('test.txt', os.listdir(os.path.join(dst_dir, 'link_to_dir')))
922
923 dst_dir = os.path.join(self.mkdtemp(), 'destination2')
924 shutil.copytree(src_dir, dst_dir, symlinks=True)
925 self.assertTrue(os.path.islink(os.path.join(dst_dir, 'link_to_dir')))
926 self.assertIn('test.txt', os.listdir(os.path.join(dst_dir, 'link_to_dir')))
927
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400928 def _copy_file(self, method):
929 fname = 'test.txt'
930 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200931 write_file((tmpdir, fname), 'xxx')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400932 file1 = os.path.join(tmpdir, fname)
933 tmpdir2 = self.mkdtemp()
934 method(file1, tmpdir2)
935 file2 = os.path.join(tmpdir2, fname)
936 return (file1, file2)
937
938 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
939 def test_copy(self):
940 # Ensure that the copied file exists and has the same mode bits.
941 file1, file2 = self._copy_file(shutil.copy)
942 self.assertTrue(os.path.exists(file2))
943 self.assertEqual(os.stat(file1).st_mode, os.stat(file2).st_mode)
944
945 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
Senthil Kumaran0c2dba52011-07-03 18:21:38 -0700946 @unittest.skipUnless(hasattr(os, 'utime'), 'requires os.utime')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400947 def test_copy2(self):
948 # Ensure that the copied file exists and has the same mode and
949 # modification time bits.
950 file1, file2 = self._copy_file(shutil.copy2)
951 self.assertTrue(os.path.exists(file2))
952 file1_stat = os.stat(file1)
953 file2_stat = os.stat(file2)
954 self.assertEqual(file1_stat.st_mode, file2_stat.st_mode)
955 for attr in 'st_atime', 'st_mtime':
956 # The modification times may be truncated in the new file.
957 self.assertLessEqual(getattr(file1_stat, attr),
958 getattr(file2_stat, attr) + 1)
959 if hasattr(os, 'chflags') and hasattr(file1_stat, 'st_flags'):
960 self.assertEqual(getattr(file1_stat, 'st_flags'),
961 getattr(file2_stat, 'st_flags'))
962
Ezio Melotti975077a2011-05-19 22:03:22 +0300963 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000964 def test_make_tarball(self):
965 # creating something to tar
Serhiy Storchaka527ef072015-09-06 18:33:19 +0300966 root_dir, base_dir = self._create_files('')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000967
968 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400969 # force shutil to create the directory
970 os.rmdir(tmpdir2)
Serhiy Storchakaeba8fee2015-09-07 19:58:23 +0300971 # working with relative paths
972 work_dir = os.path.dirname(tmpdir2)
973 rel_base_name = os.path.join(os.path.basename(tmpdir2), 'archive')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000974
Serhiy Storchakaeba8fee2015-09-07 19:58:23 +0300975 with support.change_cwd(work_dir):
Serhiy Storchaka5558d4f2015-09-08 09:59:02 +0300976 base_name = os.path.abspath(rel_base_name)
Serhiy Storchakaeba8fee2015-09-07 19:58:23 +0300977 tarball = make_archive(rel_base_name, 'gztar', root_dir, '.')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000978
979 # check if the compressed tarball was created
Serhiy Storchakaa091a822015-09-07 13:55:25 +0300980 self.assertEqual(tarball, base_name + '.tar.gz')
Serhiy Storchaka527ef072015-09-06 18:33:19 +0300981 self.assertTrue(os.path.isfile(tarball))
982 self.assertTrue(tarfile.is_tarfile(tarball))
983 with tarfile.open(tarball, 'r:gz') as tf:
984 self.assertCountEqual(tf.getnames(),
985 ['.', './sub', './sub2',
986 './file1', './file2', './sub/file3'])
Tarek Ziadé396fad72010-02-23 05:30:31 +0000987
988 # trying an uncompressed one
Serhiy Storchakaeba8fee2015-09-07 19:58:23 +0300989 with support.change_cwd(work_dir):
990 tarball = make_archive(rel_base_name, 'tar', root_dir, '.')
Serhiy Storchakaa091a822015-09-07 13:55:25 +0300991 self.assertEqual(tarball, base_name + '.tar')
Serhiy Storchaka527ef072015-09-06 18:33:19 +0300992 self.assertTrue(os.path.isfile(tarball))
993 self.assertTrue(tarfile.is_tarfile(tarball))
994 with tarfile.open(tarball, 'r') as tf:
995 self.assertCountEqual(tf.getnames(),
996 ['.', './sub', './sub2',
997 './file1', './file2', './sub/file3'])
Tarek Ziadé396fad72010-02-23 05:30:31 +0000998
999 def _tarinfo(self, path):
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001000 with tarfile.open(path) as tar:
Tarek Ziadé396fad72010-02-23 05:30:31 +00001001 names = tar.getnames()
1002 names.sort()
1003 return tuple(names)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001004
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001005 def _create_files(self, base_dir='dist'):
Tarek Ziadé396fad72010-02-23 05:30:31 +00001006 # creating something to tar
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001007 root_dir = self.mkdtemp()
1008 dist = os.path.join(root_dir, base_dir)
1009 os.makedirs(dist, exist_ok=True)
Éric Araujoa7e33a12011-08-12 19:51:35 +02001010 write_file((dist, 'file1'), 'xxx')
1011 write_file((dist, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +00001012 os.mkdir(os.path.join(dist, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +02001013 write_file((dist, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +00001014 os.mkdir(os.path.join(dist, 'sub2'))
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001015 if base_dir:
1016 write_file((root_dir, 'outer'), 'xxx')
1017 return root_dir, base_dir
Tarek Ziadé396fad72010-02-23 05:30:31 +00001018
Ezio Melotti975077a2011-05-19 22:03:22 +03001019 @requires_zlib
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001020 @unittest.skipUnless(find_executable('tar'),
Tarek Ziadé396fad72010-02-23 05:30:31 +00001021 'Need the tar command to run')
1022 def test_tarfile_vs_tar(self):
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001023 root_dir, base_dir = self._create_files()
1024 base_name = os.path.join(self.mkdtemp(), 'archive')
Serhiy Storchakaa091a822015-09-07 13:55:25 +03001025 tarball = make_archive(base_name, 'gztar', root_dir, base_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001026
1027 # check if the compressed tarball was created
Serhiy Storchakaa091a822015-09-07 13:55:25 +03001028 self.assertEqual(tarball, base_name + '.tar.gz')
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001029 self.assertTrue(os.path.isfile(tarball))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001030
1031 # now create another tarball using `tar`
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001032 tarball2 = os.path.join(root_dir, 'archive2.tar')
1033 tar_cmd = ['tar', '-cf', 'archive2.tar', base_dir]
1034 with support.change_cwd(root_dir), captured_stdout():
1035 spawn(tar_cmd)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001036
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001037 self.assertTrue(os.path.isfile(tarball2))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001038 # let's compare both tarballs
Ezio Melottib3aedd42010-11-20 19:04:17 +00001039 self.assertEqual(self._tarinfo(tarball), self._tarinfo(tarball2))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001040
1041 # trying an uncompressed one
Serhiy Storchakaa091a822015-09-07 13:55:25 +03001042 tarball = make_archive(base_name, 'tar', root_dir, base_dir)
1043 self.assertEqual(tarball, base_name + '.tar')
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001044 self.assertTrue(os.path.isfile(tarball))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001045
1046 # now for a dry_run
Serhiy Storchakaa091a822015-09-07 13:55:25 +03001047 tarball = make_archive(base_name, 'tar', root_dir, base_dir,
1048 dry_run=True)
1049 self.assertEqual(tarball, base_name + '.tar')
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001050 self.assertTrue(os.path.isfile(tarball))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001051
Ezio Melotti975077a2011-05-19 22:03:22 +03001052 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001053 @unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run')
1054 def test_make_zipfile(self):
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001055 # creating something to zip
1056 root_dir, base_dir = self._create_files()
Serhiy Storchakaeba8fee2015-09-07 19:58:23 +03001057
1058 tmpdir2 = self.mkdtemp()
1059 # force shutil to create the directory
1060 os.rmdir(tmpdir2)
1061 # working with relative paths
1062 work_dir = os.path.dirname(tmpdir2)
1063 rel_base_name = os.path.join(os.path.basename(tmpdir2), 'archive')
Serhiy Storchakaeba8fee2015-09-07 19:58:23 +03001064
1065 with support.change_cwd(work_dir):
Serhiy Storchaka5558d4f2015-09-08 09:59:02 +03001066 base_name = os.path.abspath(rel_base_name)
Serhiy Storchaka2504cec2015-09-08 05:47:23 +03001067 res = make_archive(rel_base_name, 'zip', root_dir, base_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001068
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001069 self.assertEqual(res, base_name + '.zip')
1070 self.assertTrue(os.path.isfile(res))
1071 self.assertTrue(zipfile.is_zipfile(res))
1072 with zipfile.ZipFile(res) as zf:
1073 self.assertCountEqual(zf.namelist(),
Serhiy Storchaka2504cec2015-09-08 05:47:23 +03001074 ['dist/', 'dist/sub/', 'dist/sub2/',
1075 'dist/file1', 'dist/file2', 'dist/sub/file3'])
Tarek Ziadé396fad72010-02-23 05:30:31 +00001076
Serhiy Storchaka2504cec2015-09-08 05:47:23 +03001077 @requires_zlib
1078 @unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run')
1079 @unittest.skipUnless(find_executable('zip'),
1080 'Need the zip command to run')
1081 def test_zipfile_vs_zip(self):
1082 root_dir, base_dir = self._create_files()
1083 base_name = os.path.join(self.mkdtemp(), 'archive')
1084 archive = make_archive(base_name, 'zip', root_dir, base_dir)
1085
1086 # check if ZIP file was created
1087 self.assertEqual(archive, base_name + '.zip')
1088 self.assertTrue(os.path.isfile(archive))
1089
1090 # now create another ZIP file using `zip`
1091 archive2 = os.path.join(root_dir, 'archive2.zip')
1092 zip_cmd = ['zip', '-q', '-r', 'archive2.zip', base_dir]
1093 with support.change_cwd(root_dir):
1094 spawn(zip_cmd)
1095
1096 self.assertTrue(os.path.isfile(archive2))
1097 # let's compare both ZIP files
1098 with zipfile.ZipFile(archive) as zf:
1099 names = zf.namelist()
1100 with zipfile.ZipFile(archive2) as zf:
1101 names2 = zf.namelist()
1102 self.assertEqual(sorted(names), sorted(names2))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001103
1104 def test_make_archive(self):
1105 tmpdir = self.mkdtemp()
1106 base_name = os.path.join(tmpdir, 'archive')
1107 self.assertRaises(ValueError, make_archive, base_name, 'xxx')
1108
Ezio Melotti975077a2011-05-19 22:03:22 +03001109 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001110 def test_make_archive_owner_group(self):
1111 # testing make_archive with owner and group, with various combinations
1112 # this works even if there's not gid/uid support
1113 if UID_GID_SUPPORT:
1114 group = grp.getgrgid(0)[0]
1115 owner = pwd.getpwuid(0)[0]
1116 else:
1117 group = owner = 'root'
1118
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001119 root_dir, base_dir = self._create_files()
1120 base_name = os.path.join(self.mkdtemp(), 'archive')
Tarek Ziadé396fad72010-02-23 05:30:31 +00001121 res = make_archive(base_name, 'zip', root_dir, base_dir, owner=owner,
1122 group=group)
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001123 self.assertTrue(os.path.isfile(res))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001124
1125 res = make_archive(base_name, 'zip', root_dir, base_dir)
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001126 self.assertTrue(os.path.isfile(res))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001127
1128 res = make_archive(base_name, 'tar', root_dir, base_dir,
1129 owner=owner, group=group)
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001130 self.assertTrue(os.path.isfile(res))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001131
1132 res = make_archive(base_name, 'tar', root_dir, base_dir,
1133 owner='kjhkjhkjg', group='oihohoh')
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001134 self.assertTrue(os.path.isfile(res))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001135
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001136
Ezio Melotti975077a2011-05-19 22:03:22 +03001137 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001138 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1139 def test_tarfile_root_owner(self):
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001140 root_dir, base_dir = self._create_files()
1141 base_name = os.path.join(self.mkdtemp(), 'archive')
Tarek Ziadé396fad72010-02-23 05:30:31 +00001142 group = grp.getgrgid(0)[0]
1143 owner = pwd.getpwuid(0)[0]
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001144 with support.change_cwd(root_dir):
1145 archive_name = make_archive(base_name, 'gztar', root_dir, 'dist',
1146 owner=owner, group=group)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001147
1148 # check if the compressed tarball was created
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001149 self.assertTrue(os.path.isfile(archive_name))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001150
1151 # now checks the rights
1152 archive = tarfile.open(archive_name)
1153 try:
1154 for member in archive.getmembers():
Ezio Melottib3aedd42010-11-20 19:04:17 +00001155 self.assertEqual(member.uid, 0)
1156 self.assertEqual(member.gid, 0)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001157 finally:
1158 archive.close()
1159
1160 def test_make_archive_cwd(self):
1161 current_dir = os.getcwd()
1162 def _breaks(*args, **kw):
1163 raise RuntimeError()
1164
1165 register_archive_format('xxx', _breaks, [], 'xxx file')
1166 try:
1167 try:
1168 make_archive('xxx', 'xxx', root_dir=self.mkdtemp())
1169 except Exception:
1170 pass
Ezio Melottib3aedd42010-11-20 19:04:17 +00001171 self.assertEqual(os.getcwd(), current_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001172 finally:
1173 unregister_archive_format('xxx')
1174
Serhiy Storchaka9a4fc192014-11-28 00:48:46 +02001175 def test_make_tarfile_in_curdir(self):
1176 # Issue #21280
1177 root_dir = self.mkdtemp()
1178 with support.change_cwd(root_dir):
1179 self.assertEqual(make_archive('test', 'tar'), 'test.tar')
1180 self.assertTrue(os.path.isfile('test.tar'))
1181
1182 @requires_zlib
1183 def test_make_zipfile_in_curdir(self):
1184 # Issue #21280
1185 root_dir = self.mkdtemp()
1186 with support.change_cwd(root_dir):
1187 self.assertEqual(make_archive('test', 'zip'), 'test.zip')
1188 self.assertTrue(os.path.isfile('test.zip'))
1189
Tarek Ziadé396fad72010-02-23 05:30:31 +00001190 def test_register_archive_format(self):
1191
1192 self.assertRaises(TypeError, register_archive_format, 'xxx', 1)
1193 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1194 1)
1195 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1196 [(1, 2), (1, 2, 3)])
1197
1198 register_archive_format('xxx', lambda: x, [(1, 2)], 'xxx file')
1199 formats = [name for name, params in get_archive_formats()]
1200 self.assertIn('xxx', formats)
1201
1202 unregister_archive_format('xxx')
1203 formats = [name for name, params in get_archive_formats()]
1204 self.assertNotIn('xxx', formats)
1205
Ezio Melotti975077a2011-05-19 22:03:22 +03001206 @requires_zlib
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001207 def test_unpack_archive(self):
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001208 formats = ['tar', 'gztar', 'zip']
1209 if BZ2_SUPPORTED:
1210 formats.append('bztar')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001211
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001212 root_dir, base_dir = self._create_files()
Serhiy Storchaka2504cec2015-09-08 05:47:23 +03001213 expected = rlistdir(root_dir)
1214 expected.remove('outer')
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001215 for format in formats:
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001216 base_name = os.path.join(self.mkdtemp(), 'archive')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001217 filename = make_archive(base_name, format, root_dir, base_dir)
1218
1219 # let's try to unpack it now
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001220 tmpdir2 = self.mkdtemp()
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001221 unpack_archive(filename, tmpdir2)
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001222 self.assertEqual(rlistdir(tmpdir2), expected)
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001223
Nick Coghlanabf202d2011-03-16 13:52:20 -04001224 # and again, this time with the format specified
1225 tmpdir3 = self.mkdtemp()
1226 unpack_archive(filename, tmpdir3, format=format)
Serhiy Storchaka527ef072015-09-06 18:33:19 +03001227 self.assertEqual(rlistdir(tmpdir3), expected)
Nick Coghlanabf202d2011-03-16 13:52:20 -04001228 self.assertRaises(shutil.ReadError, unpack_archive, TESTFN)
1229 self.assertRaises(ValueError, unpack_archive, TESTFN, format='xxx')
1230
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001231 def test_unpack_registery(self):
1232
1233 formats = get_unpack_formats()
1234
1235 def _boo(filename, extract_dir, extra):
Ezio Melottib3aedd42010-11-20 19:04:17 +00001236 self.assertEqual(extra, 1)
1237 self.assertEqual(filename, 'stuff.boo')
1238 self.assertEqual(extract_dir, 'xx')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001239
1240 register_unpack_format('Boo', ['.boo', '.b2'], _boo, [('extra', 1)])
1241 unpack_archive('stuff.boo', 'xx')
1242
1243 # trying to register a .boo unpacker again
1244 self.assertRaises(RegistryError, register_unpack_format, 'Boo2',
1245 ['.boo'], _boo)
1246
1247 # should work now
1248 unregister_unpack_format('Boo')
1249 register_unpack_format('Boo2', ['.boo'], _boo)
1250 self.assertIn(('Boo2', ['.boo'], ''), get_unpack_formats())
1251 self.assertNotIn(('Boo', ['.boo'], ''), get_unpack_formats())
1252
1253 # let's leave a clean state
1254 unregister_unpack_format('Boo2')
Ezio Melottib3aedd42010-11-20 19:04:17 +00001255 self.assertEqual(get_unpack_formats(), formats)
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001256
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001257 @unittest.skipUnless(hasattr(shutil, 'disk_usage'),
1258 "disk_usage not available on this platform")
1259 def test_disk_usage(self):
1260 usage = shutil.disk_usage(os.getcwd())
Éric Araujo2ee61882011-07-02 16:45:45 +02001261 self.assertGreater(usage.total, 0)
1262 self.assertGreater(usage.used, 0)
1263 self.assertGreaterEqual(usage.free, 0)
1264 self.assertGreaterEqual(usage.total, usage.used)
1265 self.assertGreater(usage.total, usage.free)
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001266
Sandro Tosid902a142011-08-22 23:28:27 +02001267 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1268 @unittest.skipUnless(hasattr(os, 'chown'), 'requires os.chown')
1269 def test_chown(self):
1270
1271 # cleaned-up automatically by TestShutil.tearDown method
1272 dirname = self.mkdtemp()
1273 filename = tempfile.mktemp(dir=dirname)
1274 write_file(filename, 'testing chown function')
1275
1276 with self.assertRaises(ValueError):
1277 shutil.chown(filename)
1278
1279 with self.assertRaises(LookupError):
1280 shutil.chown(filename, user='non-exising username')
1281
1282 with self.assertRaises(LookupError):
1283 shutil.chown(filename, group='non-exising groupname')
1284
1285 with self.assertRaises(TypeError):
1286 shutil.chown(filename, b'spam')
1287
1288 with self.assertRaises(TypeError):
1289 shutil.chown(filename, 3.14)
1290
1291 uid = os.getuid()
1292 gid = os.getgid()
1293
1294 def check_chown(path, uid=None, gid=None):
1295 s = os.stat(filename)
1296 if uid is not None:
1297 self.assertEqual(uid, s.st_uid)
1298 if gid is not None:
1299 self.assertEqual(gid, s.st_gid)
1300
1301 shutil.chown(filename, uid, gid)
1302 check_chown(filename, uid, gid)
1303 shutil.chown(filename, uid)
1304 check_chown(filename, uid)
1305 shutil.chown(filename, user=uid)
1306 check_chown(filename, uid)
1307 shutil.chown(filename, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001308 check_chown(filename, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001309
1310 shutil.chown(dirname, uid, gid)
1311 check_chown(dirname, uid, gid)
1312 shutil.chown(dirname, uid)
1313 check_chown(dirname, uid)
1314 shutil.chown(dirname, user=uid)
1315 check_chown(dirname, uid)
1316 shutil.chown(dirname, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001317 check_chown(dirname, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001318
1319 user = pwd.getpwuid(uid)[0]
1320 group = grp.getgrgid(gid)[0]
1321 shutil.chown(filename, user, group)
1322 check_chown(filename, uid, gid)
1323 shutil.chown(dirname, user, group)
1324 check_chown(dirname, uid, gid)
1325
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001326 def test_copy_return_value(self):
1327 # copy and copy2 both return their destination path.
1328 for fn in (shutil.copy, shutil.copy2):
1329 src_dir = self.mkdtemp()
1330 dst_dir = self.mkdtemp()
1331 src = os.path.join(src_dir, 'foo')
1332 write_file(src, 'foo')
1333 rv = fn(src, dst_dir)
1334 self.assertEqual(rv, os.path.join(dst_dir, 'foo'))
1335 rv = fn(src, os.path.join(dst_dir, 'bar'))
1336 self.assertEqual(rv, os.path.join(dst_dir, 'bar'))
1337
1338 def test_copyfile_return_value(self):
1339 # copytree returns its destination path.
1340 src_dir = self.mkdtemp()
1341 dst_dir = self.mkdtemp()
1342 dst_file = os.path.join(dst_dir, 'bar')
1343 src_file = os.path.join(src_dir, 'foo')
1344 write_file(src_file, 'foo')
1345 rv = shutil.copyfile(src_file, dst_file)
1346 self.assertTrue(os.path.exists(rv))
1347 self.assertEqual(read_file(src_file), read_file(dst_file))
1348
Hynek Schlawack48653762012-10-07 12:49:58 +02001349 def test_copyfile_same_file(self):
1350 # copyfile() should raise SameFileError if the source and destination
1351 # are the same.
1352 src_dir = self.mkdtemp()
1353 src_file = os.path.join(src_dir, 'foo')
1354 write_file(src_file, 'foo')
1355 self.assertRaises(SameFileError, shutil.copyfile, src_file, src_file)
Hynek Schlawack27ddb572012-10-28 13:59:27 +01001356 # But Error should work too, to stay backward compatible.
1357 self.assertRaises(Error, shutil.copyfile, src_file, src_file)
Hynek Schlawack48653762012-10-07 12:49:58 +02001358
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001359 def test_copytree_return_value(self):
1360 # copytree returns its destination path.
1361 src_dir = self.mkdtemp()
1362 dst_dir = src_dir + "dest"
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001363 self.addCleanup(shutil.rmtree, dst_dir, True)
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001364 src = os.path.join(src_dir, 'foo')
1365 write_file(src, 'foo')
1366 rv = shutil.copytree(src_dir, dst_dir)
1367 self.assertEqual(['foo'], os.listdir(rv))
1368
Christian Heimes9bd667a2008-01-20 15:14:11 +00001369
Brian Curtinc57a3452012-06-22 16:00:30 -05001370class TestWhich(unittest.TestCase):
1371
1372 def setUp(self):
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001373 self.temp_dir = tempfile.mkdtemp(prefix="Tmp")
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001374 self.addCleanup(shutil.rmtree, self.temp_dir, True)
Brian Curtinc57a3452012-06-22 16:00:30 -05001375 # Give the temp_file an ".exe" suffix for all.
1376 # It's needed on Windows and not harmful on other platforms.
1377 self.temp_file = tempfile.NamedTemporaryFile(dir=self.temp_dir,
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001378 prefix="Tmp",
1379 suffix=".Exe")
Brian Curtinc57a3452012-06-22 16:00:30 -05001380 os.chmod(self.temp_file.name, stat.S_IXUSR)
1381 self.addCleanup(self.temp_file.close)
1382 self.dir, self.file = os.path.split(self.temp_file.name)
1383
1384 def test_basic(self):
1385 # Given an EXE in a directory, it should be returned.
1386 rv = shutil.which(self.file, path=self.dir)
1387 self.assertEqual(rv, self.temp_file.name)
1388
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001389 def test_absolute_cmd(self):
Brian Curtinc57a3452012-06-22 16:00:30 -05001390 # When given the fully qualified path to an executable that exists,
1391 # it should be returned.
1392 rv = shutil.which(self.temp_file.name, path=self.temp_dir)
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001393 self.assertEqual(rv, self.temp_file.name)
1394
1395 def test_relative_cmd(self):
1396 # When given the relative path with a directory part to an executable
1397 # that exists, it should be returned.
1398 base_dir, tail_dir = os.path.split(self.dir)
1399 relpath = os.path.join(tail_dir, self.file)
Nick Coghlan55175962013-07-28 22:11:50 +10001400 with support.change_cwd(path=base_dir):
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001401 rv = shutil.which(relpath, path=self.temp_dir)
1402 self.assertEqual(rv, relpath)
1403 # But it shouldn't be searched in PATH directories (issue #16957).
Nick Coghlan55175962013-07-28 22:11:50 +10001404 with support.change_cwd(path=self.dir):
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001405 rv = shutil.which(relpath, path=base_dir)
1406 self.assertIsNone(rv)
1407
1408 def test_cwd(self):
1409 # Issue #16957
1410 base_dir = os.path.dirname(self.dir)
Nick Coghlan55175962013-07-28 22:11:50 +10001411 with support.change_cwd(path=self.dir):
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001412 rv = shutil.which(self.file, path=base_dir)
1413 if sys.platform == "win32":
1414 # Windows: current directory implicitly on PATH
1415 self.assertEqual(rv, os.path.join(os.curdir, self.file))
1416 else:
1417 # Other platforms: shouldn't match in the current directory.
1418 self.assertIsNone(rv)
Brian Curtinc57a3452012-06-22 16:00:30 -05001419
Serhiy Storchaka12516e22013-05-28 15:50:15 +03001420 @unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0,
1421 'non-root user required')
Brian Curtinc57a3452012-06-22 16:00:30 -05001422 def test_non_matching_mode(self):
1423 # Set the file read-only and ask for writeable files.
1424 os.chmod(self.temp_file.name, stat.S_IREAD)
Serhiy Storchaka12516e22013-05-28 15:50:15 +03001425 if os.access(self.temp_file.name, os.W_OK):
1426 self.skipTest("can't set the file read-only")
Brian Curtinc57a3452012-06-22 16:00:30 -05001427 rv = shutil.which(self.file, path=self.dir, mode=os.W_OK)
1428 self.assertIsNone(rv)
1429
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001430 def test_relative_path(self):
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001431 base_dir, tail_dir = os.path.split(self.dir)
Nick Coghlan55175962013-07-28 22:11:50 +10001432 with support.change_cwd(path=base_dir):
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001433 rv = shutil.which(self.file, path=tail_dir)
1434 self.assertEqual(rv, os.path.join(tail_dir, self.file))
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001435
Brian Curtinc57a3452012-06-22 16:00:30 -05001436 def test_nonexistent_file(self):
1437 # Return None when no matching executable file is found on the path.
1438 rv = shutil.which("foo.exe", path=self.dir)
1439 self.assertIsNone(rv)
1440
1441 @unittest.skipUnless(sys.platform == "win32",
1442 "pathext check is Windows-only")
1443 def test_pathext_checking(self):
1444 # Ask for the file without the ".exe" extension, then ensure that
1445 # it gets found properly with the extension.
Serhiy Storchakad70127a2013-01-24 20:03:49 +02001446 rv = shutil.which(self.file[:-4], path=self.dir)
Serhiy Storchaka80c88f42013-01-22 10:31:36 +02001447 self.assertEqual(rv, self.temp_file.name[:-4] + ".EXE")
Brian Curtinc57a3452012-06-22 16:00:30 -05001448
Barry Warsaw618738b2013-04-16 11:05:03 -04001449 def test_environ_path(self):
1450 with support.EnvironmentVarGuard() as env:
Victor Stinner1d006a22013-12-16 23:39:40 +01001451 env['PATH'] = self.dir
Barry Warsaw618738b2013-04-16 11:05:03 -04001452 rv = shutil.which(self.file)
1453 self.assertEqual(rv, self.temp_file.name)
1454
1455 def test_empty_path(self):
1456 base_dir = os.path.dirname(self.dir)
Nick Coghlan55175962013-07-28 22:11:50 +10001457 with support.change_cwd(path=self.dir), \
Barry Warsaw618738b2013-04-16 11:05:03 -04001458 support.EnvironmentVarGuard() as env:
Victor Stinner1d006a22013-12-16 23:39:40 +01001459 env['PATH'] = self.dir
Barry Warsaw618738b2013-04-16 11:05:03 -04001460 rv = shutil.which(self.file, path='')
1461 self.assertIsNone(rv)
1462
1463 def test_empty_path_no_PATH(self):
1464 with support.EnvironmentVarGuard() as env:
1465 env.pop('PATH', None)
1466 rv = shutil.which(self.file)
1467 self.assertIsNone(rv)
1468
Brian Curtinc57a3452012-06-22 16:00:30 -05001469
Christian Heimesada8c3b2008-03-18 18:26:33 +00001470class TestMove(unittest.TestCase):
1471
1472 def setUp(self):
1473 filename = "foo"
1474 self.src_dir = tempfile.mkdtemp()
1475 self.dst_dir = tempfile.mkdtemp()
1476 self.src_file = os.path.join(self.src_dir, filename)
1477 self.dst_file = os.path.join(self.dst_dir, filename)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001478 with open(self.src_file, "wb") as f:
1479 f.write(b"spam")
1480
1481 def tearDown(self):
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001482 for d in (self.src_dir, self.dst_dir):
Christian Heimesada8c3b2008-03-18 18:26:33 +00001483 try:
1484 if d:
1485 shutil.rmtree(d)
1486 except:
1487 pass
1488
1489 def _check_move_file(self, src, dst, real_dst):
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001490 with open(src, "rb") as f:
1491 contents = f.read()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001492 shutil.move(src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001493 with open(real_dst, "rb") as f:
1494 self.assertEqual(contents, f.read())
Christian Heimesada8c3b2008-03-18 18:26:33 +00001495 self.assertFalse(os.path.exists(src))
1496
1497 def _check_move_dir(self, src, dst, real_dst):
1498 contents = sorted(os.listdir(src))
1499 shutil.move(src, dst)
1500 self.assertEqual(contents, sorted(os.listdir(real_dst)))
1501 self.assertFalse(os.path.exists(src))
1502
1503 def test_move_file(self):
1504 # Move a file to another location on the same filesystem.
1505 self._check_move_file(self.src_file, self.dst_file, self.dst_file)
1506
1507 def test_move_file_to_dir(self):
1508 # Move a file inside an existing dir on the same filesystem.
1509 self._check_move_file(self.src_file, self.dst_dir, self.dst_file)
1510
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001511 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001512 def test_move_file_other_fs(self):
1513 # Move a file to an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001514 self.test_move_file()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001515
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001516 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001517 def test_move_file_to_dir_other_fs(self):
1518 # Move a file to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001519 self.test_move_file_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001520
1521 def test_move_dir(self):
1522 # Move a dir to another location on the same filesystem.
1523 dst_dir = tempfile.mktemp()
1524 try:
1525 self._check_move_dir(self.src_dir, dst_dir, dst_dir)
1526 finally:
1527 try:
1528 shutil.rmtree(dst_dir)
1529 except:
1530 pass
1531
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001532 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001533 def test_move_dir_other_fs(self):
1534 # Move a dir to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001535 self.test_move_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001536
1537 def test_move_dir_to_dir(self):
1538 # Move a dir inside an existing dir on the same filesystem.
1539 self._check_move_dir(self.src_dir, self.dst_dir,
1540 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1541
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001542 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001543 def test_move_dir_to_dir_other_fs(self):
1544 # Move a dir inside an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001545 self.test_move_dir_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001546
Serhiy Storchaka3a308b92014-02-11 10:30:59 +02001547 def test_move_dir_sep_to_dir(self):
1548 self._check_move_dir(self.src_dir + os.path.sep, self.dst_dir,
1549 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1550
1551 @unittest.skipUnless(os.path.altsep, 'requires os.path.altsep')
1552 def test_move_dir_altsep_to_dir(self):
1553 self._check_move_dir(self.src_dir + os.path.altsep, self.dst_dir,
1554 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1555
Christian Heimesada8c3b2008-03-18 18:26:33 +00001556 def test_existing_file_inside_dest_dir(self):
1557 # A file with the same name inside the destination dir already exists.
1558 with open(self.dst_file, "wb"):
1559 pass
1560 self.assertRaises(shutil.Error, shutil.move, self.src_file, self.dst_dir)
1561
1562 def test_dont_move_dir_in_itself(self):
1563 # Moving a dir inside itself raises an Error.
1564 dst = os.path.join(self.src_dir, "bar")
1565 self.assertRaises(shutil.Error, shutil.move, self.src_dir, dst)
1566
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001567 def test_destinsrc_false_negative(self):
1568 os.mkdir(TESTFN)
1569 try:
1570 for src, dst in [('srcdir', 'srcdir/dest')]:
1571 src = os.path.join(TESTFN, src)
1572 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001573 self.assertTrue(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001574 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001575 'dst (%s) is not in src (%s)' % (dst, src))
1576 finally:
1577 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001578
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001579 def test_destinsrc_false_positive(self):
1580 os.mkdir(TESTFN)
1581 try:
1582 for src, dst in [('srcdir', 'src/dest'), ('srcdir', 'srcdir.new')]:
1583 src = os.path.join(TESTFN, src)
1584 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001585 self.assertFalse(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001586 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001587 'dst (%s) is in src (%s)' % (dst, src))
1588 finally:
1589 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimes9bd667a2008-01-20 15:14:11 +00001590
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +01001591 @support.skip_unless_symlink
1592 @mock_rename
1593 def test_move_file_symlink(self):
1594 dst = os.path.join(self.src_dir, 'bar')
1595 os.symlink(self.src_file, dst)
1596 shutil.move(dst, self.dst_file)
1597 self.assertTrue(os.path.islink(self.dst_file))
1598 self.assertTrue(os.path.samefile(self.src_file, self.dst_file))
1599
1600 @support.skip_unless_symlink
1601 @mock_rename
1602 def test_move_file_symlink_to_dir(self):
1603 filename = "bar"
1604 dst = os.path.join(self.src_dir, filename)
1605 os.symlink(self.src_file, dst)
1606 shutil.move(dst, self.dst_dir)
1607 final_link = os.path.join(self.dst_dir, filename)
1608 self.assertTrue(os.path.islink(final_link))
1609 self.assertTrue(os.path.samefile(self.src_file, final_link))
1610
1611 @support.skip_unless_symlink
1612 @mock_rename
1613 def test_move_dangling_symlink(self):
1614 src = os.path.join(self.src_dir, 'baz')
1615 dst = os.path.join(self.src_dir, 'bar')
1616 os.symlink(src, dst)
1617 dst_link = os.path.join(self.dst_dir, 'quux')
1618 shutil.move(dst, dst_link)
1619 self.assertTrue(os.path.islink(dst_link))
Antoine Pitrou3f48ac92014-01-01 02:50:45 +01001620 # On Windows, os.path.realpath does not follow symlinks (issue #9949)
1621 if os.name == 'nt':
1622 self.assertEqual(os.path.realpath(src), os.readlink(dst_link))
1623 else:
1624 self.assertEqual(os.path.realpath(src), os.path.realpath(dst_link))
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +01001625
1626 @support.skip_unless_symlink
1627 @mock_rename
1628 def test_move_dir_symlink(self):
1629 src = os.path.join(self.src_dir, 'baz')
1630 dst = os.path.join(self.src_dir, 'bar')
1631 os.mkdir(src)
1632 os.symlink(src, dst)
1633 dst_link = os.path.join(self.dst_dir, 'quux')
1634 shutil.move(dst, dst_link)
1635 self.assertTrue(os.path.islink(dst_link))
1636 self.assertTrue(os.path.samefile(src, dst_link))
1637
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001638 def test_move_return_value(self):
1639 rv = shutil.move(self.src_file, self.dst_dir)
1640 self.assertEqual(rv,
1641 os.path.join(self.dst_dir, os.path.basename(self.src_file)))
1642
1643 def test_move_as_rename_return_value(self):
1644 rv = shutil.move(self.src_file, os.path.join(self.dst_dir, 'bar'))
1645 self.assertEqual(rv, os.path.join(self.dst_dir, 'bar'))
1646
Tarek Ziadé5340db32010-04-19 22:30:51 +00001647
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001648class TestCopyFile(unittest.TestCase):
1649
1650 _delete = False
1651
1652 class Faux(object):
1653 _entered = False
1654 _exited_with = None
1655 _raised = False
1656 def __init__(self, raise_in_exit=False, suppress_at_exit=True):
1657 self._raise_in_exit = raise_in_exit
1658 self._suppress_at_exit = suppress_at_exit
1659 def read(self, *args):
1660 return ''
1661 def __enter__(self):
1662 self._entered = True
1663 def __exit__(self, exc_type, exc_val, exc_tb):
1664 self._exited_with = exc_type, exc_val, exc_tb
1665 if self._raise_in_exit:
1666 self._raised = True
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001667 raise OSError("Cannot close")
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001668 return self._suppress_at_exit
1669
1670 def tearDown(self):
1671 if self._delete:
1672 del shutil.open
1673
1674 def _set_shutil_open(self, func):
1675 shutil.open = func
1676 self._delete = True
1677
1678 def test_w_source_open_fails(self):
1679 def _open(filename, mode='r'):
1680 if filename == 'srcfile':
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001681 raise OSError('Cannot open "srcfile"')
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001682 assert 0 # shouldn't reach here.
1683
1684 self._set_shutil_open(_open)
1685
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001686 self.assertRaises(OSError, shutil.copyfile, 'srcfile', 'destfile')
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001687
1688 def test_w_dest_open_fails(self):
1689
1690 srcfile = self.Faux()
1691
1692 def _open(filename, mode='r'):
1693 if filename == 'srcfile':
1694 return srcfile
1695 if filename == 'destfile':
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001696 raise OSError('Cannot open "destfile"')
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001697 assert 0 # shouldn't reach here.
1698
1699 self._set_shutil_open(_open)
1700
1701 shutil.copyfile('srcfile', 'destfile')
1702 self.assertTrue(srcfile._entered)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001703 self.assertTrue(srcfile._exited_with[0] is OSError)
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001704 self.assertEqual(srcfile._exited_with[1].args,
1705 ('Cannot open "destfile"',))
1706
1707 def test_w_dest_close_fails(self):
1708
1709 srcfile = self.Faux()
1710 destfile = self.Faux(True)
1711
1712 def _open(filename, mode='r'):
1713 if filename == 'srcfile':
1714 return srcfile
1715 if filename == 'destfile':
1716 return destfile
1717 assert 0 # shouldn't reach here.
1718
1719 self._set_shutil_open(_open)
1720
1721 shutil.copyfile('srcfile', 'destfile')
1722 self.assertTrue(srcfile._entered)
1723 self.assertTrue(destfile._entered)
1724 self.assertTrue(destfile._raised)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001725 self.assertTrue(srcfile._exited_with[0] is OSError)
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001726 self.assertEqual(srcfile._exited_with[1].args,
1727 ('Cannot close',))
1728
1729 def test_w_source_close_fails(self):
1730
1731 srcfile = self.Faux(True)
1732 destfile = self.Faux()
1733
1734 def _open(filename, mode='r'):
1735 if filename == 'srcfile':
1736 return srcfile
1737 if filename == 'destfile':
1738 return destfile
1739 assert 0 # shouldn't reach here.
1740
1741 self._set_shutil_open(_open)
1742
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001743 self.assertRaises(OSError,
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001744 shutil.copyfile, 'srcfile', 'destfile')
1745 self.assertTrue(srcfile._entered)
1746 self.assertTrue(destfile._entered)
1747 self.assertFalse(destfile._raised)
1748 self.assertTrue(srcfile._exited_with[0] is None)
1749 self.assertTrue(srcfile._raised)
1750
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001751 def test_move_dir_caseinsensitive(self):
1752 # Renames a folder to the same name
1753 # but a different case.
1754
1755 self.src_dir = tempfile.mkdtemp()
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001756 self.addCleanup(shutil.rmtree, self.src_dir, True)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001757 dst_dir = os.path.join(
1758 os.path.dirname(self.src_dir),
1759 os.path.basename(self.src_dir).upper())
1760 self.assertNotEqual(self.src_dir, dst_dir)
1761
1762 try:
1763 shutil.move(self.src_dir, dst_dir)
1764 self.assertTrue(os.path.isdir(dst_dir))
1765 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +02001766 os.rmdir(dst_dir)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001767
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001768class TermsizeTests(unittest.TestCase):
1769 def test_does_not_crash(self):
1770 """Check if get_terminal_size() returns a meaningful value.
1771
1772 There's no easy portable way to actually check the size of the
1773 terminal, so let's check if it returns something sensible instead.
1774 """
1775 size = shutil.get_terminal_size()
Antoine Pitroucfade362012-02-08 23:48:59 +01001776 self.assertGreaterEqual(size.columns, 0)
1777 self.assertGreaterEqual(size.lines, 0)
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001778
1779 def test_os_environ_first(self):
1780 "Check if environment variables have precedence"
1781
1782 with support.EnvironmentVarGuard() as env:
1783 env['COLUMNS'] = '777'
1784 size = shutil.get_terminal_size()
1785 self.assertEqual(size.columns, 777)
1786
1787 with support.EnvironmentVarGuard() as env:
1788 env['LINES'] = '888'
1789 size = shutil.get_terminal_size()
1790 self.assertEqual(size.lines, 888)
1791
1792 @unittest.skipUnless(os.isatty(sys.__stdout__.fileno()), "not on tty")
1793 def test_stty_match(self):
1794 """Check if stty returns the same results ignoring env
1795
1796 This test will fail if stdin and stdout are connected to
1797 different terminals with different sizes. Nevertheless, such
1798 situations should be pretty rare.
1799 """
1800 try:
1801 size = subprocess.check_output(['stty', 'size']).decode().split()
1802 except (FileNotFoundError, subprocess.CalledProcessError):
1803 self.skipTest("stty invocation failed")
1804 expected = (int(size[1]), int(size[0])) # reversed order
1805
1806 with support.EnvironmentVarGuard() as env:
1807 del env['LINES']
1808 del env['COLUMNS']
1809 actual = shutil.get_terminal_size()
1810
1811 self.assertEqual(expected, actual)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001812
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001813
Berker Peksag8083cd62014-11-01 11:04:06 +02001814class PublicAPITests(unittest.TestCase):
1815 """Ensures that the correct values are exposed in the public API."""
1816
1817 def test_module_all_attribute(self):
1818 self.assertTrue(hasattr(shutil, '__all__'))
1819 target_api = ['copyfileobj', 'copyfile', 'copymode', 'copystat',
1820 'copy', 'copy2', 'copytree', 'move', 'rmtree', 'Error',
1821 'SpecialFileError', 'ExecError', 'make_archive',
1822 'get_archive_formats', 'register_archive_format',
1823 'unregister_archive_format', 'get_unpack_formats',
1824 'register_unpack_format', 'unregister_unpack_format',
1825 'unpack_archive', 'ignore_patterns', 'chown', 'which',
1826 'get_terminal_size', 'SameFileError']
1827 if hasattr(os, 'statvfs') or os.name == 'nt':
1828 target_api.append('disk_usage')
1829 self.assertEqual(set(shutil.__all__), set(target_api))
1830
1831
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001832if __name__ == '__main__':
Brett Cannon3e9a9ae2013-06-12 21:25:59 -04001833 unittest.main()