blob: f2548dc4432884fb6577415e3ae71dac6fd742b7 [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
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)
Serhiy Storchaka41ad77c2014-08-07 19:38:37 +0300119 win = (os.name == 'nt')
120 with self.assertWarns(DeprecationWarning) if win else ExitStack():
121 shutil.rmtree(victim)
Hynek Schlawack3b527782012-06-25 13:27:31 +0200122
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200123 @support.skip_unless_symlink
124 def test_rmtree_fails_on_symlink(self):
125 tmp = self.mkdtemp()
126 dir_ = os.path.join(tmp, 'dir')
127 os.mkdir(dir_)
128 link = os.path.join(tmp, 'link')
129 os.symlink(dir_, link)
130 self.assertRaises(OSError, shutil.rmtree, link)
131 self.assertTrue(os.path.exists(dir_))
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100132 self.assertTrue(os.path.lexists(link))
133 errors = []
134 def onerror(*args):
135 errors.append(args)
136 shutil.rmtree(link, onerror=onerror)
137 self.assertEqual(len(errors), 1)
138 self.assertIs(errors[0][0], os.path.islink)
139 self.assertEqual(errors[0][1], link)
140 self.assertIsInstance(errors[0][2][1], OSError)
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200141
142 @support.skip_unless_symlink
143 def test_rmtree_works_on_symlinks(self):
144 tmp = self.mkdtemp()
145 dir1 = os.path.join(tmp, 'dir1')
146 dir2 = os.path.join(dir1, 'dir2')
147 dir3 = os.path.join(tmp, 'dir3')
148 for d in dir1, dir2, dir3:
149 os.mkdir(d)
150 file1 = os.path.join(tmp, 'file1')
151 write_file(file1, 'foo')
152 link1 = os.path.join(dir1, 'link1')
153 os.symlink(dir2, link1)
154 link2 = os.path.join(dir1, 'link2')
155 os.symlink(dir3, link2)
156 link3 = os.path.join(dir1, 'link3')
157 os.symlink(file1, link3)
158 # make sure symlinks are removed but not followed
159 shutil.rmtree(dir1)
160 self.assertFalse(os.path.exists(dir1))
161 self.assertTrue(os.path.exists(dir3))
162 self.assertTrue(os.path.exists(file1))
163
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000164 def test_rmtree_errors(self):
165 # filename is guaranteed not to exist
166 filename = tempfile.mktemp()
Hynek Schlawackb5501102012-12-10 09:11:25 +0100167 self.assertRaises(FileNotFoundError, shutil.rmtree, filename)
168 # test that ignore_errors option is honored
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100169 shutil.rmtree(filename, ignore_errors=True)
170
171 # existing file
172 tmpdir = self.mkdtemp()
Hynek Schlawackb5501102012-12-10 09:11:25 +0100173 write_file((tmpdir, "tstfile"), "")
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100174 filename = os.path.join(tmpdir, "tstfile")
Hynek Schlawackb5501102012-12-10 09:11:25 +0100175 with self.assertRaises(NotADirectoryError) as cm:
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100176 shutil.rmtree(filename)
Hynek Schlawack87f9b462012-12-10 16:29:57 +0100177 # The reason for this rather odd construct is that Windows sprinkles
178 # a \*.* at the end of file names. But only sometimes on some buildbots
179 possible_args = [filename, os.path.join(filename, '*.*')]
180 self.assertIn(cm.exception.filename, possible_args)
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100181 self.assertTrue(os.path.exists(filename))
Hynek Schlawackb5501102012-12-10 09:11:25 +0100182 # test that ignore_errors option is honored
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100183 shutil.rmtree(filename, ignore_errors=True)
184 self.assertTrue(os.path.exists(filename))
185 errors = []
186 def onerror(*args):
187 errors.append(args)
188 shutil.rmtree(filename, onerror=onerror)
189 self.assertEqual(len(errors), 2)
190 self.assertIs(errors[0][0], os.listdir)
191 self.assertEqual(errors[0][1], filename)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100192 self.assertIsInstance(errors[0][2][1], NotADirectoryError)
Hynek Schlawack87f9b462012-12-10 16:29:57 +0100193 self.assertIn(errors[0][2][1].filename, possible_args)
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100194 self.assertIs(errors[1][0], os.rmdir)
195 self.assertEqual(errors[1][1], filename)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100196 self.assertIsInstance(errors[1][2][1], NotADirectoryError)
Hynek Schlawack87f9b462012-12-10 16:29:57 +0100197 self.assertIn(errors[1][2][1].filename, possible_args)
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000198
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000199
Serhiy Storchaka43767632013-11-03 21:31:38 +0200200 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod()')
201 @unittest.skipIf(sys.platform[:6] == 'cygwin',
202 "This test can't be run on Cygwin (issue #1071513).")
203 @unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0,
204 "This test can't be run reliably as root (issue #1076467).")
205 def test_on_error(self):
206 self.errorState = 0
207 os.mkdir(TESTFN)
208 self.addCleanup(shutil.rmtree, TESTFN)
Antoine Pitrou2f8a75c2012-06-23 21:28:15 +0200209
Serhiy Storchaka43767632013-11-03 21:31:38 +0200210 self.child_file_path = os.path.join(TESTFN, 'a')
211 self.child_dir_path = os.path.join(TESTFN, 'b')
212 support.create_empty_file(self.child_file_path)
213 os.mkdir(self.child_dir_path)
214 old_dir_mode = os.stat(TESTFN).st_mode
215 old_child_file_mode = os.stat(self.child_file_path).st_mode
216 old_child_dir_mode = os.stat(self.child_dir_path).st_mode
217 # Make unwritable.
218 new_mode = stat.S_IREAD|stat.S_IEXEC
219 os.chmod(self.child_file_path, new_mode)
220 os.chmod(self.child_dir_path, new_mode)
221 os.chmod(TESTFN, new_mode)
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000222
Serhiy Storchaka43767632013-11-03 21:31:38 +0200223 self.addCleanup(os.chmod, TESTFN, old_dir_mode)
224 self.addCleanup(os.chmod, self.child_file_path, old_child_file_mode)
225 self.addCleanup(os.chmod, self.child_dir_path, old_child_dir_mode)
Antoine Pitrou2f8a75c2012-06-23 21:28:15 +0200226
Serhiy Storchaka43767632013-11-03 21:31:38 +0200227 shutil.rmtree(TESTFN, onerror=self.check_args_to_onerror)
228 # Test whether onerror has actually been called.
229 self.assertEqual(self.errorState, 3,
230 "Expected call to onerror function did not happen.")
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000231
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000232 def check_args_to_onerror(self, func, arg, exc):
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000233 # test_rmtree_errors deliberately runs rmtree
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200234 # on a directory that is chmod 500, which will fail.
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000235 # This function is run when shutil.rmtree fails.
236 # 99.9% of the time it initially fails to remove
237 # a file in the directory, so the first time through
238 # func is os.remove.
239 # However, some Linux machines running ZFS on
240 # FUSE experienced a failure earlier in the process
241 # at os.listdir. The first failure may legally
242 # be either.
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200243 if self.errorState < 2:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200244 if func is os.unlink:
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200245 self.assertEqual(arg, self.child_file_path)
246 elif func is os.rmdir:
247 self.assertEqual(arg, self.child_dir_path)
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000248 else:
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200249 self.assertIs(func, os.listdir)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200250 self.assertIn(arg, [TESTFN, self.child_dir_path])
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000251 self.assertTrue(issubclass(exc[0], OSError))
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200252 self.errorState += 1
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000253 else:
254 self.assertEqual(func, os.rmdir)
255 self.assertEqual(arg, TESTFN)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000256 self.assertTrue(issubclass(exc[0], OSError))
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200257 self.errorState = 3
258
259 def test_rmtree_does_not_choke_on_failing_lstat(self):
260 try:
261 orig_lstat = os.lstat
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200262 def raiser(fn, *args, **kwargs):
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200263 if fn != TESTFN:
264 raise OSError()
265 else:
266 return orig_lstat(fn)
267 os.lstat = raiser
268
269 os.mkdir(TESTFN)
270 write_file((TESTFN, 'foo'), 'foo')
271 shutil.rmtree(TESTFN)
272 finally:
273 os.lstat = orig_lstat
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000274
Antoine Pitrou78091e62011-12-29 18:54:15 +0100275 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
276 @support.skip_unless_symlink
277 def test_copymode_follow_symlinks(self):
278 tmp_dir = self.mkdtemp()
279 src = os.path.join(tmp_dir, 'foo')
280 dst = os.path.join(tmp_dir, 'bar')
281 src_link = os.path.join(tmp_dir, 'baz')
282 dst_link = os.path.join(tmp_dir, 'quux')
283 write_file(src, 'foo')
284 write_file(dst, 'foo')
285 os.symlink(src, src_link)
286 os.symlink(dst, dst_link)
287 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
288 # file to file
289 os.chmod(dst, stat.S_IRWXO)
290 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
291 shutil.copymode(src, dst)
292 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
Antoine Pitrou3f48ac92014-01-01 02:50:45 +0100293 # On Windows, os.chmod does not follow symlinks (issue #15411)
294 if os.name != 'nt':
295 # follow src link
296 os.chmod(dst, stat.S_IRWXO)
297 shutil.copymode(src_link, dst)
298 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
299 # follow dst link
300 os.chmod(dst, stat.S_IRWXO)
301 shutil.copymode(src, dst_link)
302 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
303 # follow both links
304 os.chmod(dst, stat.S_IRWXO)
305 shutil.copymode(src_link, dst_link)
306 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100307
308 @unittest.skipUnless(hasattr(os, 'lchmod'), 'requires os.lchmod')
309 @support.skip_unless_symlink
310 def test_copymode_symlink_to_symlink(self):
311 tmp_dir = self.mkdtemp()
312 src = os.path.join(tmp_dir, 'foo')
313 dst = os.path.join(tmp_dir, 'bar')
314 src_link = os.path.join(tmp_dir, 'baz')
315 dst_link = os.path.join(tmp_dir, 'quux')
316 write_file(src, 'foo')
317 write_file(dst, 'foo')
318 os.symlink(src, src_link)
319 os.symlink(dst, dst_link)
320 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
321 os.chmod(dst, stat.S_IRWXU)
322 os.lchmod(src_link, stat.S_IRWXO|stat.S_IRWXG)
323 # link to link
324 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700325 shutil.copymode(src_link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100326 self.assertEqual(os.lstat(src_link).st_mode,
327 os.lstat(dst_link).st_mode)
328 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
329 # src link - use chmod
330 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700331 shutil.copymode(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100332 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
333 # dst link - use chmod
334 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700335 shutil.copymode(src, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100336 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
337
338 @unittest.skipIf(hasattr(os, 'lchmod'), 'requires os.lchmod to be missing')
339 @support.skip_unless_symlink
340 def test_copymode_symlink_to_symlink_wo_lchmod(self):
341 tmp_dir = self.mkdtemp()
342 src = os.path.join(tmp_dir, 'foo')
343 dst = os.path.join(tmp_dir, 'bar')
344 src_link = os.path.join(tmp_dir, 'baz')
345 dst_link = os.path.join(tmp_dir, 'quux')
346 write_file(src, 'foo')
347 write_file(dst, 'foo')
348 os.symlink(src, src_link)
349 os.symlink(dst, dst_link)
Larry Hastingsb4038062012-07-15 10:57:38 -0700350 shutil.copymode(src_link, dst_link, follow_symlinks=False) # silent fail
Antoine Pitrou78091e62011-12-29 18:54:15 +0100351
352 @support.skip_unless_symlink
353 def test_copystat_symlinks(self):
354 tmp_dir = self.mkdtemp()
355 src = os.path.join(tmp_dir, 'foo')
356 dst = os.path.join(tmp_dir, 'bar')
357 src_link = os.path.join(tmp_dir, 'baz')
358 dst_link = os.path.join(tmp_dir, 'qux')
359 write_file(src, 'foo')
360 src_stat = os.stat(src)
361 os.utime(src, (src_stat.st_atime,
362 src_stat.st_mtime - 42.0)) # ensure different mtimes
363 write_file(dst, 'bar')
364 self.assertNotEqual(os.stat(src).st_mtime, os.stat(dst).st_mtime)
365 os.symlink(src, src_link)
366 os.symlink(dst, dst_link)
367 if hasattr(os, 'lchmod'):
368 os.lchmod(src_link, stat.S_IRWXO)
369 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
370 os.lchflags(src_link, stat.UF_NODUMP)
371 src_link_stat = os.lstat(src_link)
372 # follow
373 if hasattr(os, 'lchmod'):
Larry Hastingsb4038062012-07-15 10:57:38 -0700374 shutil.copystat(src_link, dst_link, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100375 self.assertNotEqual(src_link_stat.st_mode, os.stat(dst).st_mode)
376 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700377 shutil.copystat(src_link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100378 dst_link_stat = os.lstat(dst_link)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700379 if os.utime in os.supports_follow_symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100380 for attr in 'st_atime', 'st_mtime':
381 # The modification times may be truncated in the new file.
382 self.assertLessEqual(getattr(src_link_stat, attr),
383 getattr(dst_link_stat, attr) + 1)
384 if hasattr(os, 'lchmod'):
385 self.assertEqual(src_link_stat.st_mode, dst_link_stat.st_mode)
386 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
387 self.assertEqual(src_link_stat.st_flags, dst_link_stat.st_flags)
388 # tell to follow but dst is not a link
Larry Hastingsb4038062012-07-15 10:57:38 -0700389 shutil.copystat(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100390 self.assertTrue(abs(os.stat(src).st_mtime - os.stat(dst).st_mtime) <
391 00000.1)
392
Ned Deilybaf75712012-05-10 17:05:19 -0700393 @unittest.skipUnless(hasattr(os, 'chflags') and
394 hasattr(errno, 'EOPNOTSUPP') and
395 hasattr(errno, 'ENOTSUP'),
396 "requires os.chflags, EOPNOTSUPP & ENOTSUP")
397 def test_copystat_handles_harmless_chflags_errors(self):
398 tmpdir = self.mkdtemp()
399 file1 = os.path.join(tmpdir, 'file1')
400 file2 = os.path.join(tmpdir, 'file2')
401 write_file(file1, 'xxx')
402 write_file(file2, 'xxx')
403
404 def make_chflags_raiser(err):
405 ex = OSError()
406
Larry Hastings90867a52012-06-22 17:01:41 -0700407 def _chflags_raiser(path, flags, *, follow_symlinks=True):
Ned Deilybaf75712012-05-10 17:05:19 -0700408 ex.errno = err
409 raise ex
410 return _chflags_raiser
411 old_chflags = os.chflags
412 try:
413 for err in errno.EOPNOTSUPP, errno.ENOTSUP:
414 os.chflags = make_chflags_raiser(err)
415 shutil.copystat(file1, file2)
416 # assert others errors break it
417 os.chflags = make_chflags_raiser(errno.EOPNOTSUPP + errno.ENOTSUP)
418 self.assertRaises(OSError, shutil.copystat, file1, file2)
419 finally:
420 os.chflags = old_chflags
421
Antoine Pitrou424246f2012-05-12 19:02:01 +0200422 @support.skip_unless_xattr
423 def test_copyxattr(self):
424 tmp_dir = self.mkdtemp()
425 src = os.path.join(tmp_dir, 'foo')
426 write_file(src, 'foo')
427 dst = os.path.join(tmp_dir, 'bar')
428 write_file(dst, 'bar')
429
430 # no xattr == no problem
431 shutil._copyxattr(src, dst)
432 # common case
433 os.setxattr(src, 'user.foo', b'42')
434 os.setxattr(src, 'user.bar', b'43')
435 shutil._copyxattr(src, dst)
Gregory P. Smith1093bf22014-01-17 12:01:22 -0800436 self.assertEqual(sorted(os.listxattr(src)), sorted(os.listxattr(dst)))
Antoine Pitrou424246f2012-05-12 19:02:01 +0200437 self.assertEqual(
438 os.getxattr(src, 'user.foo'),
439 os.getxattr(dst, 'user.foo'))
440 # check errors don't affect other attrs
441 os.remove(dst)
442 write_file(dst, 'bar')
443 os_error = OSError(errno.EPERM, 'EPERM')
444
Larry Hastings9cf065c2012-06-22 16:30:09 -0700445 def _raise_on_user_foo(fname, attr, val, **kwargs):
Antoine Pitrou424246f2012-05-12 19:02:01 +0200446 if attr == 'user.foo':
447 raise os_error
448 else:
Larry Hastings9cf065c2012-06-22 16:30:09 -0700449 orig_setxattr(fname, attr, val, **kwargs)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200450 try:
451 orig_setxattr = os.setxattr
452 os.setxattr = _raise_on_user_foo
453 shutil._copyxattr(src, dst)
Antoine Pitrou61597d32012-05-12 23:37:35 +0200454 self.assertIn('user.bar', os.listxattr(dst))
Antoine Pitrou424246f2012-05-12 19:02:01 +0200455 finally:
456 os.setxattr = orig_setxattr
Hynek Schlawack0beab052013-02-05 08:22:44 +0100457 # the source filesystem not supporting xattrs should be ok, too.
458 def _raise_on_src(fname, *, follow_symlinks=True):
459 if fname == src:
460 raise OSError(errno.ENOTSUP, 'Operation not supported')
461 return orig_listxattr(fname, follow_symlinks=follow_symlinks)
462 try:
463 orig_listxattr = os.listxattr
464 os.listxattr = _raise_on_src
465 shutil._copyxattr(src, dst)
466 finally:
467 os.listxattr = orig_listxattr
Antoine Pitrou424246f2012-05-12 19:02:01 +0200468
Larry Hastingsad5ae042012-07-14 17:55:11 -0700469 # test that shutil.copystat copies xattrs
470 src = os.path.join(tmp_dir, 'the_original')
471 write_file(src, src)
472 os.setxattr(src, 'user.the_value', b'fiddly')
473 dst = os.path.join(tmp_dir, 'the_copy')
474 write_file(dst, dst)
475 shutil.copystat(src, dst)
Hynek Schlawackc2d481f2012-07-16 17:11:10 +0200476 self.assertEqual(os.getxattr(dst, 'user.the_value'), b'fiddly')
Larry Hastingsad5ae042012-07-14 17:55:11 -0700477
Antoine Pitrou424246f2012-05-12 19:02:01 +0200478 @support.skip_unless_symlink
479 @support.skip_unless_xattr
480 @unittest.skipUnless(hasattr(os, 'geteuid') and os.geteuid() == 0,
481 'root privileges required')
482 def test_copyxattr_symlinks(self):
483 # On Linux, it's only possible to access non-user xattr for symlinks;
484 # which in turn require root privileges. This test should be expanded
485 # as soon as other platforms gain support for extended attributes.
486 tmp_dir = self.mkdtemp()
487 src = os.path.join(tmp_dir, 'foo')
488 src_link = os.path.join(tmp_dir, 'baz')
489 write_file(src, 'foo')
490 os.symlink(src, src_link)
491 os.setxattr(src, 'trusted.foo', b'42')
Larry Hastings9cf065c2012-06-22 16:30:09 -0700492 os.setxattr(src_link, 'trusted.foo', b'43', follow_symlinks=False)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200493 dst = os.path.join(tmp_dir, 'bar')
494 dst_link = os.path.join(tmp_dir, 'qux')
495 write_file(dst, 'bar')
496 os.symlink(dst, dst_link)
Larry Hastingsb4038062012-07-15 10:57:38 -0700497 shutil._copyxattr(src_link, dst_link, follow_symlinks=False)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700498 self.assertEqual(os.getxattr(dst_link, 'trusted.foo', follow_symlinks=False), b'43')
Antoine Pitrou424246f2012-05-12 19:02:01 +0200499 self.assertRaises(OSError, os.getxattr, dst, 'trusted.foo')
Larry Hastingsb4038062012-07-15 10:57:38 -0700500 shutil._copyxattr(src_link, dst, follow_symlinks=False)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200501 self.assertEqual(os.getxattr(dst, 'trusted.foo'), b'43')
502
Antoine Pitrou78091e62011-12-29 18:54:15 +0100503 @support.skip_unless_symlink
504 def test_copy_symlinks(self):
505 tmp_dir = self.mkdtemp()
506 src = os.path.join(tmp_dir, 'foo')
507 dst = os.path.join(tmp_dir, 'bar')
508 src_link = os.path.join(tmp_dir, 'baz')
509 write_file(src, 'foo')
510 os.symlink(src, src_link)
511 if hasattr(os, 'lchmod'):
512 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
513 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700514 shutil.copy(src_link, dst, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100515 self.assertFalse(os.path.islink(dst))
516 self.assertEqual(read_file(src), read_file(dst))
517 os.remove(dst)
518 # follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700519 shutil.copy(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100520 self.assertTrue(os.path.islink(dst))
521 self.assertEqual(os.readlink(dst), os.readlink(src_link))
522 if hasattr(os, 'lchmod'):
523 self.assertEqual(os.lstat(src_link).st_mode,
524 os.lstat(dst).st_mode)
525
526 @support.skip_unless_symlink
527 def test_copy2_symlinks(self):
528 tmp_dir = self.mkdtemp()
529 src = os.path.join(tmp_dir, 'foo')
530 dst = os.path.join(tmp_dir, 'bar')
531 src_link = os.path.join(tmp_dir, 'baz')
532 write_file(src, 'foo')
533 os.symlink(src, src_link)
534 if hasattr(os, 'lchmod'):
535 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
536 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
537 os.lchflags(src_link, stat.UF_NODUMP)
538 src_stat = os.stat(src)
539 src_link_stat = os.lstat(src_link)
540 # follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700541 shutil.copy2(src_link, dst, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100542 self.assertFalse(os.path.islink(dst))
543 self.assertEqual(read_file(src), read_file(dst))
544 os.remove(dst)
545 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700546 shutil.copy2(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100547 self.assertTrue(os.path.islink(dst))
548 self.assertEqual(os.readlink(dst), os.readlink(src_link))
549 dst_stat = os.lstat(dst)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700550 if os.utime in os.supports_follow_symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100551 for attr in 'st_atime', 'st_mtime':
552 # The modification times may be truncated in the new file.
553 self.assertLessEqual(getattr(src_link_stat, attr),
554 getattr(dst_stat, attr) + 1)
555 if hasattr(os, 'lchmod'):
556 self.assertEqual(src_link_stat.st_mode, dst_stat.st_mode)
557 self.assertNotEqual(src_stat.st_mode, dst_stat.st_mode)
558 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
559 self.assertEqual(src_link_stat.st_flags, dst_stat.st_flags)
560
Antoine Pitrou424246f2012-05-12 19:02:01 +0200561 @support.skip_unless_xattr
562 def test_copy2_xattr(self):
563 tmp_dir = self.mkdtemp()
564 src = os.path.join(tmp_dir, 'foo')
565 dst = os.path.join(tmp_dir, 'bar')
566 write_file(src, 'foo')
567 os.setxattr(src, 'user.foo', b'42')
568 shutil.copy2(src, dst)
569 self.assertEqual(
570 os.getxattr(src, 'user.foo'),
571 os.getxattr(dst, 'user.foo'))
572 os.remove(dst)
573
Antoine Pitrou78091e62011-12-29 18:54:15 +0100574 @support.skip_unless_symlink
575 def test_copyfile_symlinks(self):
576 tmp_dir = self.mkdtemp()
577 src = os.path.join(tmp_dir, 'src')
578 dst = os.path.join(tmp_dir, 'dst')
579 dst_link = os.path.join(tmp_dir, 'dst_link')
580 link = os.path.join(tmp_dir, 'link')
581 write_file(src, 'foo')
582 os.symlink(src, link)
583 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700584 shutil.copyfile(link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100585 self.assertTrue(os.path.islink(dst_link))
586 self.assertEqual(os.readlink(link), os.readlink(dst_link))
587 # follow
588 shutil.copyfile(link, dst)
589 self.assertFalse(os.path.islink(dst))
590
Hynek Schlawack2100b422012-06-23 20:28:32 +0200591 def test_rmtree_uses_safe_fd_version_if_available(self):
Hynek Schlawackd0f6e0a2012-06-29 08:28:20 +0200592 _use_fd_functions = ({os.open, os.stat, os.unlink, os.rmdir} <=
593 os.supports_dir_fd and
594 os.listdir in os.supports_fd and
595 os.stat in os.supports_follow_symlinks)
596 if _use_fd_functions:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200597 self.assertTrue(shutil._use_fd_functions)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000598 self.assertTrue(shutil.rmtree.avoids_symlink_attacks)
Hynek Schlawack2100b422012-06-23 20:28:32 +0200599 tmp_dir = self.mkdtemp()
600 d = os.path.join(tmp_dir, 'a')
601 os.mkdir(d)
602 try:
603 real_rmtree = shutil._rmtree_safe_fd
604 class Called(Exception): pass
605 def _raiser(*args, **kwargs):
606 raise Called
607 shutil._rmtree_safe_fd = _raiser
608 self.assertRaises(Called, shutil.rmtree, d)
609 finally:
610 shutil._rmtree_safe_fd = real_rmtree
611 else:
612 self.assertFalse(shutil._use_fd_functions)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000613 self.assertFalse(shutil.rmtree.avoids_symlink_attacks)
Hynek Schlawack2100b422012-06-23 20:28:32 +0200614
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000615 def test_rmtree_dont_delete_file(self):
616 # When called on a file instead of a directory, don't delete it.
617 handle, path = tempfile.mkstemp()
Victor Stinnerbf816222011-06-30 23:25:47 +0200618 os.close(handle)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200619 self.assertRaises(NotADirectoryError, shutil.rmtree, path)
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000620 os.remove(path)
621
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000622 def test_copytree_simple(self):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000623 src_dir = tempfile.mkdtemp()
624 dst_dir = os.path.join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200625 self.addCleanup(shutil.rmtree, src_dir)
626 self.addCleanup(shutil.rmtree, os.path.dirname(dst_dir))
627 write_file((src_dir, 'test.txt'), '123')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000628 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200629 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000630
Éric Araujoa7e33a12011-08-12 19:51:35 +0200631 shutil.copytree(src_dir, dst_dir)
632 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test.txt')))
633 self.assertTrue(os.path.isdir(os.path.join(dst_dir, 'test_dir')))
634 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test_dir',
635 'test.txt')))
636 actual = read_file((dst_dir, 'test.txt'))
637 self.assertEqual(actual, '123')
638 actual = read_file((dst_dir, 'test_dir', 'test.txt'))
639 self.assertEqual(actual, '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000640
Antoine Pitrou78091e62011-12-29 18:54:15 +0100641 @support.skip_unless_symlink
642 def test_copytree_symlinks(self):
643 tmp_dir = self.mkdtemp()
644 src_dir = os.path.join(tmp_dir, 'src')
645 dst_dir = os.path.join(tmp_dir, 'dst')
646 sub_dir = os.path.join(src_dir, 'sub')
647 os.mkdir(src_dir)
648 os.mkdir(sub_dir)
649 write_file((src_dir, 'file.txt'), 'foo')
650 src_link = os.path.join(sub_dir, 'link')
651 dst_link = os.path.join(dst_dir, 'sub/link')
652 os.symlink(os.path.join(src_dir, 'file.txt'),
653 src_link)
654 if hasattr(os, 'lchmod'):
655 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
656 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
657 os.lchflags(src_link, stat.UF_NODUMP)
658 src_stat = os.lstat(src_link)
659 shutil.copytree(src_dir, dst_dir, symlinks=True)
660 self.assertTrue(os.path.islink(os.path.join(dst_dir, 'sub', 'link')))
661 self.assertEqual(os.readlink(os.path.join(dst_dir, 'sub', 'link')),
662 os.path.join(src_dir, 'file.txt'))
663 dst_stat = os.lstat(dst_link)
664 if hasattr(os, 'lchmod'):
665 self.assertEqual(dst_stat.st_mode, src_stat.st_mode)
666 if hasattr(os, 'lchflags'):
667 self.assertEqual(dst_stat.st_flags, src_stat.st_flags)
668
Georg Brandl2ee470f2008-07-16 12:55:28 +0000669 def test_copytree_with_exclude(self):
Georg Brandl2ee470f2008-07-16 12:55:28 +0000670 # creating data
671 join = os.path.join
672 exists = os.path.exists
673 src_dir = tempfile.mkdtemp()
Georg Brandl2ee470f2008-07-16 12:55:28 +0000674 try:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000675 dst_dir = join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200676 write_file((src_dir, 'test.txt'), '123')
677 write_file((src_dir, 'test.tmp'), '123')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000678 os.mkdir(join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200679 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000680 os.mkdir(join(src_dir, 'test_dir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200681 write_file((src_dir, 'test_dir2', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000682 os.mkdir(join(src_dir, 'test_dir2', 'subdir'))
683 os.mkdir(join(src_dir, 'test_dir2', 'subdir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200684 write_file((src_dir, 'test_dir2', 'subdir', 'test.txt'), '456')
685 write_file((src_dir, 'test_dir2', 'subdir2', 'test.py'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000686
687 # testing glob-like patterns
688 try:
689 patterns = shutil.ignore_patterns('*.tmp', 'test_dir2')
690 shutil.copytree(src_dir, dst_dir, ignore=patterns)
691 # checking the result: some elements should not be copied
692 self.assertTrue(exists(join(dst_dir, 'test.txt')))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200693 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
694 self.assertFalse(exists(join(dst_dir, 'test_dir2')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000695 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200696 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000697 try:
698 patterns = shutil.ignore_patterns('*.tmp', 'subdir*')
699 shutil.copytree(src_dir, dst_dir, ignore=patterns)
700 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200701 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
702 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2')))
703 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000704 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200705 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000706
707 # testing callable-style
708 try:
709 def _filter(src, names):
710 res = []
711 for name in names:
712 path = os.path.join(src, name)
713
714 if (os.path.isdir(path) and
715 path.split()[-1] == 'subdir'):
716 res.append(name)
717 elif os.path.splitext(path)[-1] in ('.py'):
718 res.append(name)
719 return res
720
721 shutil.copytree(src_dir, dst_dir, ignore=_filter)
722
723 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200724 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2',
725 'test.py')))
726 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000727
728 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200729 shutil.rmtree(dst_dir)
Georg Brandl2ee470f2008-07-16 12:55:28 +0000730 finally:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000731 shutil.rmtree(src_dir)
732 shutil.rmtree(os.path.dirname(dst_dir))
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000733
Antoine Pitrouac601602013-08-16 19:35:02 +0200734 def test_copytree_retains_permissions(self):
735 tmp_dir = tempfile.mkdtemp()
736 src_dir = os.path.join(tmp_dir, 'source')
737 os.mkdir(src_dir)
738 dst_dir = os.path.join(tmp_dir, 'destination')
739 self.addCleanup(shutil.rmtree, tmp_dir)
740
741 os.chmod(src_dir, 0o777)
742 write_file((src_dir, 'permissive.txt'), '123')
743 os.chmod(os.path.join(src_dir, 'permissive.txt'), 0o777)
744 write_file((src_dir, 'restrictive.txt'), '456')
745 os.chmod(os.path.join(src_dir, 'restrictive.txt'), 0o600)
746 restrictive_subdir = tempfile.mkdtemp(dir=src_dir)
747 os.chmod(restrictive_subdir, 0o600)
748
749 shutil.copytree(src_dir, dst_dir)
Brett Cannon9c7eb552013-08-23 14:38:11 -0400750 self.assertEqual(os.stat(src_dir).st_mode, os.stat(dst_dir).st_mode)
751 self.assertEqual(os.stat(os.path.join(src_dir, 'permissive.txt')).st_mode,
Antoine Pitrouac601602013-08-16 19:35:02 +0200752 os.stat(os.path.join(dst_dir, 'permissive.txt')).st_mode)
Brett Cannon9c7eb552013-08-23 14:38:11 -0400753 self.assertEqual(os.stat(os.path.join(src_dir, 'restrictive.txt')).st_mode,
Antoine Pitrouac601602013-08-16 19:35:02 +0200754 os.stat(os.path.join(dst_dir, 'restrictive.txt')).st_mode)
755 restrictive_subdir_dst = os.path.join(dst_dir,
756 os.path.split(restrictive_subdir)[1])
Brett Cannon9c7eb552013-08-23 14:38:11 -0400757 self.assertEqual(os.stat(restrictive_subdir).st_mode,
Antoine Pitrouac601602013-08-16 19:35:02 +0200758 os.stat(restrictive_subdir_dst).st_mode)
759
Berker Peksag884afd92014-12-10 02:50:32 +0200760 @unittest.mock.patch('os.chmod')
761 def test_copytree_winerror(self, mock_patch):
762 # When copying to VFAT, copystat() raises OSError. On Windows, the
763 # exception object has a meaningful 'winerror' attribute, but not
764 # on other operating systems. Do not assume 'winerror' is set.
765 src_dir = tempfile.mkdtemp()
766 dst_dir = os.path.join(tempfile.mkdtemp(), 'destination')
767 self.addCleanup(shutil.rmtree, src_dir)
768 self.addCleanup(shutil.rmtree, os.path.dirname(dst_dir))
769
770 mock_patch.side_effect = PermissionError('ka-boom')
771 with self.assertRaises(shutil.Error):
772 shutil.copytree(src_dir, dst_dir)
773
Zachary Ware9fe6d862013-12-08 00:20:35 -0600774 @unittest.skipIf(os.name == 'nt', 'temporarily disabled on Windows')
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000775 @unittest.skipUnless(hasattr(os, 'link'), 'requires os.link')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000776 def test_dont_copy_file_onto_link_to_itself(self):
777 # bug 851123.
778 os.mkdir(TESTFN)
779 src = os.path.join(TESTFN, 'cheese')
780 dst = os.path.join(TESTFN, 'shop')
781 try:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000782 with open(src, 'w') as f:
783 f.write('cheddar')
784 os.link(src, dst)
Hynek Schlawack48653762012-10-07 12:49:58 +0200785 self.assertRaises(shutil.SameFileError, shutil.copyfile, src, dst)
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000786 with open(src, 'r') as f:
787 self.assertEqual(f.read(), 'cheddar')
788 os.remove(dst)
789 finally:
790 shutil.rmtree(TESTFN, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000791
Brian Curtin3b4499c2010-12-28 14:31:47 +0000792 @support.skip_unless_symlink
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000793 def test_dont_copy_file_onto_symlink_to_itself(self):
794 # bug 851123.
795 os.mkdir(TESTFN)
796 src = os.path.join(TESTFN, 'cheese')
797 dst = os.path.join(TESTFN, 'shop')
798 try:
799 with open(src, 'w') as f:
800 f.write('cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000801 # Using `src` here would mean we end up with a symlink pointing
802 # to TESTFN/TESTFN/cheese, while it should point at
803 # TESTFN/cheese.
804 os.symlink('cheese', dst)
Hynek Schlawack48653762012-10-07 12:49:58 +0200805 self.assertRaises(shutil.SameFileError, shutil.copyfile, src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +0000806 with open(src, 'r') as f:
807 self.assertEqual(f.read(), 'cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000808 os.remove(dst)
809 finally:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000810 shutil.rmtree(TESTFN, ignore_errors=True)
Johannes Gijsbers68128712004-08-14 13:57:08 +0000811
Brian Curtin3b4499c2010-12-28 14:31:47 +0000812 @support.skip_unless_symlink
Brian Curtind40e6f72010-07-08 21:39:08 +0000813 def test_rmtree_on_symlink(self):
814 # bug 1669.
815 os.mkdir(TESTFN)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000816 try:
Brian Curtind40e6f72010-07-08 21:39:08 +0000817 src = os.path.join(TESTFN, 'cheese')
818 dst = os.path.join(TESTFN, 'shop')
819 os.mkdir(src)
820 os.symlink(src, dst)
821 self.assertRaises(OSError, shutil.rmtree, dst)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200822 shutil.rmtree(dst, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000823 finally:
Brian Curtind40e6f72010-07-08 21:39:08 +0000824 shutil.rmtree(TESTFN, ignore_errors=True)
825
Serhiy Storchaka43767632013-11-03 21:31:38 +0200826 # Issue #3002: copyfile and copytree block indefinitely on named pipes
827 @unittest.skipUnless(hasattr(os, "mkfifo"), 'requires os.mkfifo()')
828 def test_copyfile_named_pipe(self):
829 os.mkfifo(TESTFN)
830 try:
831 self.assertRaises(shutil.SpecialFileError,
832 shutil.copyfile, TESTFN, TESTFN2)
833 self.assertRaises(shutil.SpecialFileError,
834 shutil.copyfile, __file__, TESTFN)
835 finally:
836 os.remove(TESTFN)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000837
Serhiy Storchaka43767632013-11-03 21:31:38 +0200838 @unittest.skipUnless(hasattr(os, "mkfifo"), 'requires os.mkfifo()')
839 @support.skip_unless_symlink
840 def test_copytree_named_pipe(self):
841 os.mkdir(TESTFN)
842 try:
843 subdir = os.path.join(TESTFN, "subdir")
844 os.mkdir(subdir)
845 pipe = os.path.join(subdir, "mypipe")
846 os.mkfifo(pipe)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000847 try:
Serhiy Storchaka43767632013-11-03 21:31:38 +0200848 shutil.copytree(TESTFN, TESTFN2)
849 except shutil.Error as e:
850 errors = e.args[0]
851 self.assertEqual(len(errors), 1)
852 src, dst, error_msg = errors[0]
853 self.assertEqual("`%s` is a named pipe" % pipe, error_msg)
854 else:
855 self.fail("shutil.Error should have been raised")
856 finally:
857 shutil.rmtree(TESTFN, ignore_errors=True)
858 shutil.rmtree(TESTFN2, ignore_errors=True)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000859
Tarek Ziadé5340db32010-04-19 22:30:51 +0000860 def test_copytree_special_func(self):
861
862 src_dir = self.mkdtemp()
863 dst_dir = os.path.join(self.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200864 write_file((src_dir, 'test.txt'), '123')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000865 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200866 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000867
868 copied = []
869 def _copy(src, dst):
870 copied.append((src, dst))
871
872 shutil.copytree(src_dir, dst_dir, copy_function=_copy)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000873 self.assertEqual(len(copied), 2)
Tarek Ziadé5340db32010-04-19 22:30:51 +0000874
Brian Curtin3b4499c2010-12-28 14:31:47 +0000875 @support.skip_unless_symlink
Tarek Ziadéfb437512010-04-20 08:57:33 +0000876 def test_copytree_dangling_symlinks(self):
877
878 # a dangling symlink raises an error at the end
879 src_dir = self.mkdtemp()
880 dst_dir = os.path.join(self.mkdtemp(), 'destination')
881 os.symlink('IDONTEXIST', os.path.join(src_dir, 'test.txt'))
882 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200883 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadéfb437512010-04-20 08:57:33 +0000884 self.assertRaises(Error, shutil.copytree, src_dir, dst_dir)
885
886 # a dangling symlink is ignored with the proper flag
887 dst_dir = os.path.join(self.mkdtemp(), 'destination2')
888 shutil.copytree(src_dir, dst_dir, ignore_dangling_symlinks=True)
889 self.assertNotIn('test.txt', os.listdir(dst_dir))
890
891 # a dangling symlink is copied if symlinks=True
892 dst_dir = os.path.join(self.mkdtemp(), 'destination3')
893 shutil.copytree(src_dir, dst_dir, symlinks=True)
894 self.assertIn('test.txt', os.listdir(dst_dir))
895
Berker Peksag5a294d82015-07-25 14:53:48 +0300896 @support.skip_unless_symlink
897 def test_copytree_symlink_dir(self):
898 src_dir = self.mkdtemp()
899 dst_dir = os.path.join(self.mkdtemp(), 'destination')
900 os.mkdir(os.path.join(src_dir, 'real_dir'))
901 with open(os.path.join(src_dir, 'real_dir', 'test.txt'), 'w'):
902 pass
903 os.symlink(os.path.join(src_dir, 'real_dir'),
904 os.path.join(src_dir, 'link_to_dir'),
905 target_is_directory=True)
906
907 shutil.copytree(src_dir, dst_dir, symlinks=False)
908 self.assertFalse(os.path.islink(os.path.join(dst_dir, 'link_to_dir')))
909 self.assertIn('test.txt', os.listdir(os.path.join(dst_dir, 'link_to_dir')))
910
911 dst_dir = os.path.join(self.mkdtemp(), 'destination2')
912 shutil.copytree(src_dir, dst_dir, symlinks=True)
913 self.assertTrue(os.path.islink(os.path.join(dst_dir, 'link_to_dir')))
914 self.assertIn('test.txt', os.listdir(os.path.join(dst_dir, 'link_to_dir')))
915
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400916 def _copy_file(self, method):
917 fname = 'test.txt'
918 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200919 write_file((tmpdir, fname), 'xxx')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400920 file1 = os.path.join(tmpdir, fname)
921 tmpdir2 = self.mkdtemp()
922 method(file1, tmpdir2)
923 file2 = os.path.join(tmpdir2, fname)
924 return (file1, file2)
925
926 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
927 def test_copy(self):
928 # Ensure that the copied file exists and has the same mode bits.
929 file1, file2 = self._copy_file(shutil.copy)
930 self.assertTrue(os.path.exists(file2))
931 self.assertEqual(os.stat(file1).st_mode, os.stat(file2).st_mode)
932
933 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
Senthil Kumaran0c2dba52011-07-03 18:21:38 -0700934 @unittest.skipUnless(hasattr(os, 'utime'), 'requires os.utime')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400935 def test_copy2(self):
936 # Ensure that the copied file exists and has the same mode and
937 # modification time bits.
938 file1, file2 = self._copy_file(shutil.copy2)
939 self.assertTrue(os.path.exists(file2))
940 file1_stat = os.stat(file1)
941 file2_stat = os.stat(file2)
942 self.assertEqual(file1_stat.st_mode, file2_stat.st_mode)
943 for attr in 'st_atime', 'st_mtime':
944 # The modification times may be truncated in the new file.
945 self.assertLessEqual(getattr(file1_stat, attr),
946 getattr(file2_stat, attr) + 1)
947 if hasattr(os, 'chflags') and hasattr(file1_stat, 'st_flags'):
948 self.assertEqual(getattr(file1_stat, 'st_flags'),
949 getattr(file2_stat, 'st_flags'))
950
Ezio Melotti975077a2011-05-19 22:03:22 +0300951 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000952 def test_make_tarball(self):
953 # creating something to tar
954 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200955 write_file((tmpdir, 'file1'), 'xxx')
956 write_file((tmpdir, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000957 os.mkdir(os.path.join(tmpdir, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200958 write_file((tmpdir, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000959
960 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400961 # force shutil to create the directory
962 os.rmdir(tmpdir2)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000963 unittest.skipUnless(splitdrive(tmpdir)[0] == splitdrive(tmpdir2)[0],
964 "source and target should be on same drive")
965
966 base_name = os.path.join(tmpdir2, 'archive')
967
968 # working with relative paths to avoid tar warnings
Serhiy Storchaka2a23adf2015-09-06 14:13:25 +0300969 with support.change_cwd(tmpdir):
Tarek Ziadé396fad72010-02-23 05:30:31 +0000970 _make_tarball(splitdrive(base_name)[1], '.')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000971
972 # check if the compressed tarball was created
973 tarball = base_name + '.tar.gz'
974 self.assertTrue(os.path.exists(tarball))
975
976 # trying an uncompressed one
977 base_name = os.path.join(tmpdir2, 'archive')
Serhiy Storchaka2a23adf2015-09-06 14:13:25 +0300978 with support.change_cwd(tmpdir):
Tarek Ziadé396fad72010-02-23 05:30:31 +0000979 _make_tarball(splitdrive(base_name)[1], '.', compress=None)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000980 tarball = base_name + '.tar'
981 self.assertTrue(os.path.exists(tarball))
982
983 def _tarinfo(self, path):
984 tar = tarfile.open(path)
985 try:
986 names = tar.getnames()
987 names.sort()
988 return tuple(names)
989 finally:
990 tar.close()
991
992 def _create_files(self):
993 # creating something to tar
994 tmpdir = self.mkdtemp()
995 dist = os.path.join(tmpdir, 'dist')
996 os.mkdir(dist)
Éric Araujoa7e33a12011-08-12 19:51:35 +0200997 write_file((dist, 'file1'), 'xxx')
998 write_file((dist, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000999 os.mkdir(os.path.join(dist, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +02001000 write_file((dist, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +00001001 os.mkdir(os.path.join(dist, 'sub2'))
1002 tmpdir2 = self.mkdtemp()
1003 base_name = os.path.join(tmpdir2, 'archive')
1004 return tmpdir, tmpdir2, base_name
1005
Ezio Melotti975077a2011-05-19 22:03:22 +03001006 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001007 @unittest.skipUnless(find_executable('tar') and find_executable('gzip'),
1008 'Need the tar command to run')
1009 def test_tarfile_vs_tar(self):
1010 tmpdir, tmpdir2, base_name = self._create_files()
Serhiy Storchaka2a23adf2015-09-06 14:13:25 +03001011 with support.change_cwd(tmpdir):
Tarek Ziadé396fad72010-02-23 05:30:31 +00001012 _make_tarball(base_name, 'dist')
Tarek Ziadé396fad72010-02-23 05:30:31 +00001013
1014 # check if the compressed tarball was created
1015 tarball = base_name + '.tar.gz'
1016 self.assertTrue(os.path.exists(tarball))
1017
1018 # now create another tarball using `tar`
1019 tarball2 = os.path.join(tmpdir, 'archive2.tar.gz')
1020 tar_cmd = ['tar', '-cf', 'archive2.tar', 'dist']
1021 gzip_cmd = ['gzip', '-f9', 'archive2.tar']
Serhiy Storchaka2a23adf2015-09-06 14:13:25 +03001022 with support.change_cwd(tmpdir):
Tarek Ziadé396fad72010-02-23 05:30:31 +00001023 with captured_stdout() as s:
1024 spawn(tar_cmd)
1025 spawn(gzip_cmd)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001026
1027 self.assertTrue(os.path.exists(tarball2))
1028 # let's compare both tarballs
Ezio Melottib3aedd42010-11-20 19:04:17 +00001029 self.assertEqual(self._tarinfo(tarball), self._tarinfo(tarball2))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001030
1031 # trying an uncompressed one
1032 base_name = os.path.join(tmpdir2, 'archive')
Serhiy Storchaka2a23adf2015-09-06 14:13:25 +03001033 with support.change_cwd(tmpdir):
Tarek Ziadé396fad72010-02-23 05:30:31 +00001034 _make_tarball(base_name, 'dist', compress=None)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001035 tarball = base_name + '.tar'
1036 self.assertTrue(os.path.exists(tarball))
1037
1038 # now for a dry_run
1039 base_name = os.path.join(tmpdir2, 'archive')
Serhiy Storchaka2a23adf2015-09-06 14:13:25 +03001040 with support.change_cwd(tmpdir):
Tarek Ziadé396fad72010-02-23 05:30:31 +00001041 _make_tarball(base_name, 'dist', compress=None, dry_run=True)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001042 tarball = base_name + '.tar'
1043 self.assertTrue(os.path.exists(tarball))
1044
Ezio Melotti975077a2011-05-19 22:03:22 +03001045 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001046 @unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run')
1047 def test_make_zipfile(self):
1048 # creating something to tar
1049 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +02001050 write_file((tmpdir, 'file1'), 'xxx')
1051 write_file((tmpdir, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +00001052
1053 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001054 # force shutil to create the directory
1055 os.rmdir(tmpdir2)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001056 base_name = os.path.join(tmpdir2, 'archive')
1057 _make_zipfile(base_name, tmpdir)
1058
1059 # check if the compressed tarball was created
1060 tarball = base_name + '.zip'
Éric Araujo1c505492010-11-06 02:12:51 +00001061 self.assertTrue(os.path.exists(tarball))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001062
1063
1064 def test_make_archive(self):
1065 tmpdir = self.mkdtemp()
1066 base_name = os.path.join(tmpdir, 'archive')
1067 self.assertRaises(ValueError, make_archive, base_name, 'xxx')
1068
Ezio Melotti975077a2011-05-19 22:03:22 +03001069 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001070 def test_make_archive_owner_group(self):
1071 # testing make_archive with owner and group, with various combinations
1072 # this works even if there's not gid/uid support
1073 if UID_GID_SUPPORT:
1074 group = grp.getgrgid(0)[0]
1075 owner = pwd.getpwuid(0)[0]
1076 else:
1077 group = owner = 'root'
1078
1079 base_dir, root_dir, base_name = self._create_files()
1080 base_name = os.path.join(self.mkdtemp() , 'archive')
1081 res = make_archive(base_name, 'zip', root_dir, base_dir, owner=owner,
1082 group=group)
1083 self.assertTrue(os.path.exists(res))
1084
1085 res = make_archive(base_name, 'zip', root_dir, base_dir)
1086 self.assertTrue(os.path.exists(res))
1087
1088 res = make_archive(base_name, 'tar', root_dir, base_dir,
1089 owner=owner, group=group)
1090 self.assertTrue(os.path.exists(res))
1091
1092 res = make_archive(base_name, 'tar', root_dir, base_dir,
1093 owner='kjhkjhkjg', group='oihohoh')
1094 self.assertTrue(os.path.exists(res))
1095
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001096
Ezio Melotti975077a2011-05-19 22:03:22 +03001097 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001098 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1099 def test_tarfile_root_owner(self):
1100 tmpdir, tmpdir2, base_name = self._create_files()
Tarek Ziadé396fad72010-02-23 05:30:31 +00001101 group = grp.getgrgid(0)[0]
1102 owner = pwd.getpwuid(0)[0]
Serhiy Storchaka2a23adf2015-09-06 14:13:25 +03001103 with support.change_cwd(tmpdir):
Tarek Ziadé396fad72010-02-23 05:30:31 +00001104 archive_name = _make_tarball(base_name, 'dist', compress=None,
1105 owner=owner, group=group)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001106
1107 # check if the compressed tarball was created
1108 self.assertTrue(os.path.exists(archive_name))
1109
1110 # now checks the rights
1111 archive = tarfile.open(archive_name)
1112 try:
1113 for member in archive.getmembers():
Ezio Melottib3aedd42010-11-20 19:04:17 +00001114 self.assertEqual(member.uid, 0)
1115 self.assertEqual(member.gid, 0)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001116 finally:
1117 archive.close()
1118
1119 def test_make_archive_cwd(self):
1120 current_dir = os.getcwd()
1121 def _breaks(*args, **kw):
1122 raise RuntimeError()
1123
1124 register_archive_format('xxx', _breaks, [], 'xxx file')
1125 try:
1126 try:
1127 make_archive('xxx', 'xxx', root_dir=self.mkdtemp())
1128 except Exception:
1129 pass
Ezio Melottib3aedd42010-11-20 19:04:17 +00001130 self.assertEqual(os.getcwd(), current_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001131 finally:
1132 unregister_archive_format('xxx')
1133
Serhiy Storchaka9a4fc192014-11-28 00:48:46 +02001134 def test_make_tarfile_in_curdir(self):
1135 # Issue #21280
1136 root_dir = self.mkdtemp()
1137 with support.change_cwd(root_dir):
1138 self.assertEqual(make_archive('test', 'tar'), 'test.tar')
1139 self.assertTrue(os.path.isfile('test.tar'))
1140
1141 @requires_zlib
1142 def test_make_zipfile_in_curdir(self):
1143 # Issue #21280
1144 root_dir = self.mkdtemp()
1145 with support.change_cwd(root_dir):
1146 self.assertEqual(make_archive('test', 'zip'), 'test.zip')
1147 self.assertTrue(os.path.isfile('test.zip'))
1148
Tarek Ziadé396fad72010-02-23 05:30:31 +00001149 def test_register_archive_format(self):
1150
1151 self.assertRaises(TypeError, register_archive_format, 'xxx', 1)
1152 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1153 1)
1154 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1155 [(1, 2), (1, 2, 3)])
1156
1157 register_archive_format('xxx', lambda: x, [(1, 2)], 'xxx file')
1158 formats = [name for name, params in get_archive_formats()]
1159 self.assertIn('xxx', formats)
1160
1161 unregister_archive_format('xxx')
1162 formats = [name for name, params in get_archive_formats()]
1163 self.assertNotIn('xxx', formats)
1164
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001165 def _compare_dirs(self, dir1, dir2):
1166 # check that dir1 and dir2 are equivalent,
1167 # return the diff
1168 diff = []
1169 for root, dirs, files in os.walk(dir1):
1170 for file_ in files:
1171 path = os.path.join(root, file_)
1172 target_path = os.path.join(dir2, os.path.split(path)[-1])
1173 if not os.path.exists(target_path):
1174 diff.append(file_)
1175 return diff
1176
Ezio Melotti975077a2011-05-19 22:03:22 +03001177 @requires_zlib
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001178 def test_unpack_archive(self):
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001179 formats = ['tar', 'gztar', 'zip']
1180 if BZ2_SUPPORTED:
1181 formats.append('bztar')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001182
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001183 for format in formats:
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001184 tmpdir = self.mkdtemp()
1185 base_dir, root_dir, base_name = self._create_files()
1186 tmpdir2 = self.mkdtemp()
1187 filename = make_archive(base_name, format, root_dir, base_dir)
1188
1189 # let's try to unpack it now
1190 unpack_archive(filename, tmpdir2)
1191 diff = self._compare_dirs(tmpdir, tmpdir2)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001192 self.assertEqual(diff, [])
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001193
Nick Coghlanabf202d2011-03-16 13:52:20 -04001194 # and again, this time with the format specified
1195 tmpdir3 = self.mkdtemp()
1196 unpack_archive(filename, tmpdir3, format=format)
1197 diff = self._compare_dirs(tmpdir, tmpdir3)
1198 self.assertEqual(diff, [])
1199 self.assertRaises(shutil.ReadError, unpack_archive, TESTFN)
1200 self.assertRaises(ValueError, unpack_archive, TESTFN, format='xxx')
1201
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001202 def test_unpack_registery(self):
1203
1204 formats = get_unpack_formats()
1205
1206 def _boo(filename, extract_dir, extra):
Ezio Melottib3aedd42010-11-20 19:04:17 +00001207 self.assertEqual(extra, 1)
1208 self.assertEqual(filename, 'stuff.boo')
1209 self.assertEqual(extract_dir, 'xx')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001210
1211 register_unpack_format('Boo', ['.boo', '.b2'], _boo, [('extra', 1)])
1212 unpack_archive('stuff.boo', 'xx')
1213
1214 # trying to register a .boo unpacker again
1215 self.assertRaises(RegistryError, register_unpack_format, 'Boo2',
1216 ['.boo'], _boo)
1217
1218 # should work now
1219 unregister_unpack_format('Boo')
1220 register_unpack_format('Boo2', ['.boo'], _boo)
1221 self.assertIn(('Boo2', ['.boo'], ''), get_unpack_formats())
1222 self.assertNotIn(('Boo', ['.boo'], ''), get_unpack_formats())
1223
1224 # let's leave a clean state
1225 unregister_unpack_format('Boo2')
Ezio Melottib3aedd42010-11-20 19:04:17 +00001226 self.assertEqual(get_unpack_formats(), formats)
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001227
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001228 @unittest.skipUnless(hasattr(shutil, 'disk_usage'),
1229 "disk_usage not available on this platform")
1230 def test_disk_usage(self):
1231 usage = shutil.disk_usage(os.getcwd())
Éric Araujo2ee61882011-07-02 16:45:45 +02001232 self.assertGreater(usage.total, 0)
1233 self.assertGreater(usage.used, 0)
1234 self.assertGreaterEqual(usage.free, 0)
1235 self.assertGreaterEqual(usage.total, usage.used)
1236 self.assertGreater(usage.total, usage.free)
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001237
Sandro Tosid902a142011-08-22 23:28:27 +02001238 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1239 @unittest.skipUnless(hasattr(os, 'chown'), 'requires os.chown')
1240 def test_chown(self):
1241
1242 # cleaned-up automatically by TestShutil.tearDown method
1243 dirname = self.mkdtemp()
1244 filename = tempfile.mktemp(dir=dirname)
1245 write_file(filename, 'testing chown function')
1246
1247 with self.assertRaises(ValueError):
1248 shutil.chown(filename)
1249
1250 with self.assertRaises(LookupError):
1251 shutil.chown(filename, user='non-exising username')
1252
1253 with self.assertRaises(LookupError):
1254 shutil.chown(filename, group='non-exising groupname')
1255
1256 with self.assertRaises(TypeError):
1257 shutil.chown(filename, b'spam')
1258
1259 with self.assertRaises(TypeError):
1260 shutil.chown(filename, 3.14)
1261
1262 uid = os.getuid()
1263 gid = os.getgid()
1264
1265 def check_chown(path, uid=None, gid=None):
1266 s = os.stat(filename)
1267 if uid is not None:
1268 self.assertEqual(uid, s.st_uid)
1269 if gid is not None:
1270 self.assertEqual(gid, s.st_gid)
1271
1272 shutil.chown(filename, uid, gid)
1273 check_chown(filename, uid, gid)
1274 shutil.chown(filename, uid)
1275 check_chown(filename, uid)
1276 shutil.chown(filename, user=uid)
1277 check_chown(filename, uid)
1278 shutil.chown(filename, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001279 check_chown(filename, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001280
1281 shutil.chown(dirname, uid, gid)
1282 check_chown(dirname, uid, gid)
1283 shutil.chown(dirname, uid)
1284 check_chown(dirname, uid)
1285 shutil.chown(dirname, user=uid)
1286 check_chown(dirname, uid)
1287 shutil.chown(dirname, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001288 check_chown(dirname, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001289
1290 user = pwd.getpwuid(uid)[0]
1291 group = grp.getgrgid(gid)[0]
1292 shutil.chown(filename, user, group)
1293 check_chown(filename, uid, gid)
1294 shutil.chown(dirname, user, group)
1295 check_chown(dirname, uid, gid)
1296
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001297 def test_copy_return_value(self):
1298 # copy and copy2 both return their destination path.
1299 for fn in (shutil.copy, shutil.copy2):
1300 src_dir = self.mkdtemp()
1301 dst_dir = self.mkdtemp()
1302 src = os.path.join(src_dir, 'foo')
1303 write_file(src, 'foo')
1304 rv = fn(src, dst_dir)
1305 self.assertEqual(rv, os.path.join(dst_dir, 'foo'))
1306 rv = fn(src, os.path.join(dst_dir, 'bar'))
1307 self.assertEqual(rv, os.path.join(dst_dir, 'bar'))
1308
1309 def test_copyfile_return_value(self):
1310 # copytree returns its destination path.
1311 src_dir = self.mkdtemp()
1312 dst_dir = self.mkdtemp()
1313 dst_file = os.path.join(dst_dir, 'bar')
1314 src_file = os.path.join(src_dir, 'foo')
1315 write_file(src_file, 'foo')
1316 rv = shutil.copyfile(src_file, dst_file)
1317 self.assertTrue(os.path.exists(rv))
1318 self.assertEqual(read_file(src_file), read_file(dst_file))
1319
Hynek Schlawack48653762012-10-07 12:49:58 +02001320 def test_copyfile_same_file(self):
1321 # copyfile() should raise SameFileError if the source and destination
1322 # are the same.
1323 src_dir = self.mkdtemp()
1324 src_file = os.path.join(src_dir, 'foo')
1325 write_file(src_file, 'foo')
1326 self.assertRaises(SameFileError, shutil.copyfile, src_file, src_file)
Hynek Schlawack27ddb572012-10-28 13:59:27 +01001327 # But Error should work too, to stay backward compatible.
1328 self.assertRaises(Error, shutil.copyfile, src_file, src_file)
Hynek Schlawack48653762012-10-07 12:49:58 +02001329
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001330 def test_copytree_return_value(self):
1331 # copytree returns its destination path.
1332 src_dir = self.mkdtemp()
1333 dst_dir = src_dir + "dest"
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001334 self.addCleanup(shutil.rmtree, dst_dir, True)
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001335 src = os.path.join(src_dir, 'foo')
1336 write_file(src, 'foo')
1337 rv = shutil.copytree(src_dir, dst_dir)
1338 self.assertEqual(['foo'], os.listdir(rv))
1339
Christian Heimes9bd667a2008-01-20 15:14:11 +00001340
Brian Curtinc57a3452012-06-22 16:00:30 -05001341class TestWhich(unittest.TestCase):
1342
1343 def setUp(self):
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001344 self.temp_dir = tempfile.mkdtemp(prefix="Tmp")
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001345 self.addCleanup(shutil.rmtree, self.temp_dir, True)
Brian Curtinc57a3452012-06-22 16:00:30 -05001346 # Give the temp_file an ".exe" suffix for all.
1347 # It's needed on Windows and not harmful on other platforms.
1348 self.temp_file = tempfile.NamedTemporaryFile(dir=self.temp_dir,
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001349 prefix="Tmp",
1350 suffix=".Exe")
Brian Curtinc57a3452012-06-22 16:00:30 -05001351 os.chmod(self.temp_file.name, stat.S_IXUSR)
1352 self.addCleanup(self.temp_file.close)
1353 self.dir, self.file = os.path.split(self.temp_file.name)
1354
1355 def test_basic(self):
1356 # Given an EXE in a directory, it should be returned.
1357 rv = shutil.which(self.file, path=self.dir)
1358 self.assertEqual(rv, self.temp_file.name)
1359
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001360 def test_absolute_cmd(self):
Brian Curtinc57a3452012-06-22 16:00:30 -05001361 # When given the fully qualified path to an executable that exists,
1362 # it should be returned.
1363 rv = shutil.which(self.temp_file.name, path=self.temp_dir)
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001364 self.assertEqual(rv, self.temp_file.name)
1365
1366 def test_relative_cmd(self):
1367 # When given the relative path with a directory part to an executable
1368 # that exists, it should be returned.
1369 base_dir, tail_dir = os.path.split(self.dir)
1370 relpath = os.path.join(tail_dir, self.file)
Nick Coghlan55175962013-07-28 22:11:50 +10001371 with support.change_cwd(path=base_dir):
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001372 rv = shutil.which(relpath, path=self.temp_dir)
1373 self.assertEqual(rv, relpath)
1374 # But it shouldn't be searched in PATH directories (issue #16957).
Nick Coghlan55175962013-07-28 22:11:50 +10001375 with support.change_cwd(path=self.dir):
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001376 rv = shutil.which(relpath, path=base_dir)
1377 self.assertIsNone(rv)
1378
1379 def test_cwd(self):
1380 # Issue #16957
1381 base_dir = os.path.dirname(self.dir)
Nick Coghlan55175962013-07-28 22:11:50 +10001382 with support.change_cwd(path=self.dir):
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001383 rv = shutil.which(self.file, path=base_dir)
1384 if sys.platform == "win32":
1385 # Windows: current directory implicitly on PATH
1386 self.assertEqual(rv, os.path.join(os.curdir, self.file))
1387 else:
1388 # Other platforms: shouldn't match in the current directory.
1389 self.assertIsNone(rv)
Brian Curtinc57a3452012-06-22 16:00:30 -05001390
Serhiy Storchaka12516e22013-05-28 15:50:15 +03001391 @unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0,
1392 'non-root user required')
Brian Curtinc57a3452012-06-22 16:00:30 -05001393 def test_non_matching_mode(self):
1394 # Set the file read-only and ask for writeable files.
1395 os.chmod(self.temp_file.name, stat.S_IREAD)
Serhiy Storchaka12516e22013-05-28 15:50:15 +03001396 if os.access(self.temp_file.name, os.W_OK):
1397 self.skipTest("can't set the file read-only")
Brian Curtinc57a3452012-06-22 16:00:30 -05001398 rv = shutil.which(self.file, path=self.dir, mode=os.W_OK)
1399 self.assertIsNone(rv)
1400
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001401 def test_relative_path(self):
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001402 base_dir, tail_dir = os.path.split(self.dir)
Nick Coghlan55175962013-07-28 22:11:50 +10001403 with support.change_cwd(path=base_dir):
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001404 rv = shutil.which(self.file, path=tail_dir)
1405 self.assertEqual(rv, os.path.join(tail_dir, self.file))
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001406
Brian Curtinc57a3452012-06-22 16:00:30 -05001407 def test_nonexistent_file(self):
1408 # Return None when no matching executable file is found on the path.
1409 rv = shutil.which("foo.exe", path=self.dir)
1410 self.assertIsNone(rv)
1411
1412 @unittest.skipUnless(sys.platform == "win32",
1413 "pathext check is Windows-only")
1414 def test_pathext_checking(self):
1415 # Ask for the file without the ".exe" extension, then ensure that
1416 # it gets found properly with the extension.
Serhiy Storchakad70127a2013-01-24 20:03:49 +02001417 rv = shutil.which(self.file[:-4], path=self.dir)
Serhiy Storchaka80c88f42013-01-22 10:31:36 +02001418 self.assertEqual(rv, self.temp_file.name[:-4] + ".EXE")
Brian Curtinc57a3452012-06-22 16:00:30 -05001419
Barry Warsaw618738b2013-04-16 11:05:03 -04001420 def test_environ_path(self):
1421 with support.EnvironmentVarGuard() as env:
Victor Stinner1d006a22013-12-16 23:39:40 +01001422 env['PATH'] = self.dir
Barry Warsaw618738b2013-04-16 11:05:03 -04001423 rv = shutil.which(self.file)
1424 self.assertEqual(rv, self.temp_file.name)
1425
1426 def test_empty_path(self):
1427 base_dir = os.path.dirname(self.dir)
Nick Coghlan55175962013-07-28 22:11:50 +10001428 with support.change_cwd(path=self.dir), \
Barry Warsaw618738b2013-04-16 11:05:03 -04001429 support.EnvironmentVarGuard() as env:
Victor Stinner1d006a22013-12-16 23:39:40 +01001430 env['PATH'] = self.dir
Barry Warsaw618738b2013-04-16 11:05:03 -04001431 rv = shutil.which(self.file, path='')
1432 self.assertIsNone(rv)
1433
1434 def test_empty_path_no_PATH(self):
1435 with support.EnvironmentVarGuard() as env:
1436 env.pop('PATH', None)
1437 rv = shutil.which(self.file)
1438 self.assertIsNone(rv)
1439
Brian Curtinc57a3452012-06-22 16:00:30 -05001440
Christian Heimesada8c3b2008-03-18 18:26:33 +00001441class TestMove(unittest.TestCase):
1442
1443 def setUp(self):
1444 filename = "foo"
1445 self.src_dir = tempfile.mkdtemp()
1446 self.dst_dir = tempfile.mkdtemp()
1447 self.src_file = os.path.join(self.src_dir, filename)
1448 self.dst_file = os.path.join(self.dst_dir, filename)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001449 with open(self.src_file, "wb") as f:
1450 f.write(b"spam")
1451
1452 def tearDown(self):
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001453 for d in (self.src_dir, self.dst_dir):
Christian Heimesada8c3b2008-03-18 18:26:33 +00001454 try:
1455 if d:
1456 shutil.rmtree(d)
1457 except:
1458 pass
1459
1460 def _check_move_file(self, src, dst, real_dst):
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001461 with open(src, "rb") as f:
1462 contents = f.read()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001463 shutil.move(src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001464 with open(real_dst, "rb") as f:
1465 self.assertEqual(contents, f.read())
Christian Heimesada8c3b2008-03-18 18:26:33 +00001466 self.assertFalse(os.path.exists(src))
1467
1468 def _check_move_dir(self, src, dst, real_dst):
1469 contents = sorted(os.listdir(src))
1470 shutil.move(src, dst)
1471 self.assertEqual(contents, sorted(os.listdir(real_dst)))
1472 self.assertFalse(os.path.exists(src))
1473
1474 def test_move_file(self):
1475 # Move a file to another location on the same filesystem.
1476 self._check_move_file(self.src_file, self.dst_file, self.dst_file)
1477
1478 def test_move_file_to_dir(self):
1479 # Move a file inside an existing dir on the same filesystem.
1480 self._check_move_file(self.src_file, self.dst_dir, self.dst_file)
1481
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001482 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001483 def test_move_file_other_fs(self):
1484 # Move a file to an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001485 self.test_move_file()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001486
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001487 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001488 def test_move_file_to_dir_other_fs(self):
1489 # Move a file to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001490 self.test_move_file_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001491
1492 def test_move_dir(self):
1493 # Move a dir to another location on the same filesystem.
1494 dst_dir = tempfile.mktemp()
1495 try:
1496 self._check_move_dir(self.src_dir, dst_dir, dst_dir)
1497 finally:
1498 try:
1499 shutil.rmtree(dst_dir)
1500 except:
1501 pass
1502
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001503 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001504 def test_move_dir_other_fs(self):
1505 # Move a dir to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001506 self.test_move_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001507
1508 def test_move_dir_to_dir(self):
1509 # Move a dir inside an existing dir on the same filesystem.
1510 self._check_move_dir(self.src_dir, self.dst_dir,
1511 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1512
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001513 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001514 def test_move_dir_to_dir_other_fs(self):
1515 # Move a dir inside an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001516 self.test_move_dir_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001517
Serhiy Storchaka3a308b92014-02-11 10:30:59 +02001518 def test_move_dir_sep_to_dir(self):
1519 self._check_move_dir(self.src_dir + os.path.sep, self.dst_dir,
1520 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1521
1522 @unittest.skipUnless(os.path.altsep, 'requires os.path.altsep')
1523 def test_move_dir_altsep_to_dir(self):
1524 self._check_move_dir(self.src_dir + os.path.altsep, self.dst_dir,
1525 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1526
Christian Heimesada8c3b2008-03-18 18:26:33 +00001527 def test_existing_file_inside_dest_dir(self):
1528 # A file with the same name inside the destination dir already exists.
1529 with open(self.dst_file, "wb"):
1530 pass
1531 self.assertRaises(shutil.Error, shutil.move, self.src_file, self.dst_dir)
1532
1533 def test_dont_move_dir_in_itself(self):
1534 # Moving a dir inside itself raises an Error.
1535 dst = os.path.join(self.src_dir, "bar")
1536 self.assertRaises(shutil.Error, shutil.move, self.src_dir, dst)
1537
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001538 def test_destinsrc_false_negative(self):
1539 os.mkdir(TESTFN)
1540 try:
1541 for src, dst in [('srcdir', 'srcdir/dest')]:
1542 src = os.path.join(TESTFN, src)
1543 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001544 self.assertTrue(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001545 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001546 'dst (%s) is not in src (%s)' % (dst, src))
1547 finally:
1548 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001549
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001550 def test_destinsrc_false_positive(self):
1551 os.mkdir(TESTFN)
1552 try:
1553 for src, dst in [('srcdir', 'src/dest'), ('srcdir', 'srcdir.new')]:
1554 src = os.path.join(TESTFN, src)
1555 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001556 self.assertFalse(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001557 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001558 'dst (%s) is in src (%s)' % (dst, src))
1559 finally:
1560 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimes9bd667a2008-01-20 15:14:11 +00001561
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +01001562 @support.skip_unless_symlink
1563 @mock_rename
1564 def test_move_file_symlink(self):
1565 dst = os.path.join(self.src_dir, 'bar')
1566 os.symlink(self.src_file, dst)
1567 shutil.move(dst, self.dst_file)
1568 self.assertTrue(os.path.islink(self.dst_file))
1569 self.assertTrue(os.path.samefile(self.src_file, self.dst_file))
1570
1571 @support.skip_unless_symlink
1572 @mock_rename
1573 def test_move_file_symlink_to_dir(self):
1574 filename = "bar"
1575 dst = os.path.join(self.src_dir, filename)
1576 os.symlink(self.src_file, dst)
1577 shutil.move(dst, self.dst_dir)
1578 final_link = os.path.join(self.dst_dir, filename)
1579 self.assertTrue(os.path.islink(final_link))
1580 self.assertTrue(os.path.samefile(self.src_file, final_link))
1581
1582 @support.skip_unless_symlink
1583 @mock_rename
1584 def test_move_dangling_symlink(self):
1585 src = os.path.join(self.src_dir, 'baz')
1586 dst = os.path.join(self.src_dir, 'bar')
1587 os.symlink(src, dst)
1588 dst_link = os.path.join(self.dst_dir, 'quux')
1589 shutil.move(dst, dst_link)
1590 self.assertTrue(os.path.islink(dst_link))
Antoine Pitrou3f48ac92014-01-01 02:50:45 +01001591 # On Windows, os.path.realpath does not follow symlinks (issue #9949)
1592 if os.name == 'nt':
1593 self.assertEqual(os.path.realpath(src), os.readlink(dst_link))
1594 else:
1595 self.assertEqual(os.path.realpath(src), os.path.realpath(dst_link))
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +01001596
1597 @support.skip_unless_symlink
1598 @mock_rename
1599 def test_move_dir_symlink(self):
1600 src = os.path.join(self.src_dir, 'baz')
1601 dst = os.path.join(self.src_dir, 'bar')
1602 os.mkdir(src)
1603 os.symlink(src, dst)
1604 dst_link = os.path.join(self.dst_dir, 'quux')
1605 shutil.move(dst, dst_link)
1606 self.assertTrue(os.path.islink(dst_link))
1607 self.assertTrue(os.path.samefile(src, dst_link))
1608
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001609 def test_move_return_value(self):
1610 rv = shutil.move(self.src_file, self.dst_dir)
1611 self.assertEqual(rv,
1612 os.path.join(self.dst_dir, os.path.basename(self.src_file)))
1613
1614 def test_move_as_rename_return_value(self):
1615 rv = shutil.move(self.src_file, os.path.join(self.dst_dir, 'bar'))
1616 self.assertEqual(rv, os.path.join(self.dst_dir, 'bar'))
1617
Tarek Ziadé5340db32010-04-19 22:30:51 +00001618
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001619class TestCopyFile(unittest.TestCase):
1620
1621 _delete = False
1622
1623 class Faux(object):
1624 _entered = False
1625 _exited_with = None
1626 _raised = False
1627 def __init__(self, raise_in_exit=False, suppress_at_exit=True):
1628 self._raise_in_exit = raise_in_exit
1629 self._suppress_at_exit = suppress_at_exit
1630 def read(self, *args):
1631 return ''
1632 def __enter__(self):
1633 self._entered = True
1634 def __exit__(self, exc_type, exc_val, exc_tb):
1635 self._exited_with = exc_type, exc_val, exc_tb
1636 if self._raise_in_exit:
1637 self._raised = True
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001638 raise OSError("Cannot close")
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001639 return self._suppress_at_exit
1640
1641 def tearDown(self):
1642 if self._delete:
1643 del shutil.open
1644
1645 def _set_shutil_open(self, func):
1646 shutil.open = func
1647 self._delete = True
1648
1649 def test_w_source_open_fails(self):
1650 def _open(filename, mode='r'):
1651 if filename == 'srcfile':
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001652 raise OSError('Cannot open "srcfile"')
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001653 assert 0 # shouldn't reach here.
1654
1655 self._set_shutil_open(_open)
1656
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001657 self.assertRaises(OSError, shutil.copyfile, 'srcfile', 'destfile')
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001658
1659 def test_w_dest_open_fails(self):
1660
1661 srcfile = self.Faux()
1662
1663 def _open(filename, mode='r'):
1664 if filename == 'srcfile':
1665 return srcfile
1666 if filename == 'destfile':
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001667 raise OSError('Cannot open "destfile"')
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001668 assert 0 # shouldn't reach here.
1669
1670 self._set_shutil_open(_open)
1671
1672 shutil.copyfile('srcfile', 'destfile')
1673 self.assertTrue(srcfile._entered)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001674 self.assertTrue(srcfile._exited_with[0] is OSError)
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001675 self.assertEqual(srcfile._exited_with[1].args,
1676 ('Cannot open "destfile"',))
1677
1678 def test_w_dest_close_fails(self):
1679
1680 srcfile = self.Faux()
1681 destfile = self.Faux(True)
1682
1683 def _open(filename, mode='r'):
1684 if filename == 'srcfile':
1685 return srcfile
1686 if filename == 'destfile':
1687 return destfile
1688 assert 0 # shouldn't reach here.
1689
1690 self._set_shutil_open(_open)
1691
1692 shutil.copyfile('srcfile', 'destfile')
1693 self.assertTrue(srcfile._entered)
1694 self.assertTrue(destfile._entered)
1695 self.assertTrue(destfile._raised)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001696 self.assertTrue(srcfile._exited_with[0] is OSError)
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001697 self.assertEqual(srcfile._exited_with[1].args,
1698 ('Cannot close',))
1699
1700 def test_w_source_close_fails(self):
1701
1702 srcfile = self.Faux(True)
1703 destfile = self.Faux()
1704
1705 def _open(filename, mode='r'):
1706 if filename == 'srcfile':
1707 return srcfile
1708 if filename == 'destfile':
1709 return destfile
1710 assert 0 # shouldn't reach here.
1711
1712 self._set_shutil_open(_open)
1713
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001714 self.assertRaises(OSError,
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001715 shutil.copyfile, 'srcfile', 'destfile')
1716 self.assertTrue(srcfile._entered)
1717 self.assertTrue(destfile._entered)
1718 self.assertFalse(destfile._raised)
1719 self.assertTrue(srcfile._exited_with[0] is None)
1720 self.assertTrue(srcfile._raised)
1721
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001722 def test_move_dir_caseinsensitive(self):
1723 # Renames a folder to the same name
1724 # but a different case.
1725
1726 self.src_dir = tempfile.mkdtemp()
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001727 self.addCleanup(shutil.rmtree, self.src_dir, True)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001728 dst_dir = os.path.join(
1729 os.path.dirname(self.src_dir),
1730 os.path.basename(self.src_dir).upper())
1731 self.assertNotEqual(self.src_dir, dst_dir)
1732
1733 try:
1734 shutil.move(self.src_dir, dst_dir)
1735 self.assertTrue(os.path.isdir(dst_dir))
1736 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +02001737 os.rmdir(dst_dir)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001738
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001739class TermsizeTests(unittest.TestCase):
1740 def test_does_not_crash(self):
1741 """Check if get_terminal_size() returns a meaningful value.
1742
1743 There's no easy portable way to actually check the size of the
1744 terminal, so let's check if it returns something sensible instead.
1745 """
1746 size = shutil.get_terminal_size()
Antoine Pitroucfade362012-02-08 23:48:59 +01001747 self.assertGreaterEqual(size.columns, 0)
1748 self.assertGreaterEqual(size.lines, 0)
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001749
1750 def test_os_environ_first(self):
1751 "Check if environment variables have precedence"
1752
1753 with support.EnvironmentVarGuard() as env:
1754 env['COLUMNS'] = '777'
1755 size = shutil.get_terminal_size()
1756 self.assertEqual(size.columns, 777)
1757
1758 with support.EnvironmentVarGuard() as env:
1759 env['LINES'] = '888'
1760 size = shutil.get_terminal_size()
1761 self.assertEqual(size.lines, 888)
1762
1763 @unittest.skipUnless(os.isatty(sys.__stdout__.fileno()), "not on tty")
1764 def test_stty_match(self):
1765 """Check if stty returns the same results ignoring env
1766
1767 This test will fail if stdin and stdout are connected to
1768 different terminals with different sizes. Nevertheless, such
1769 situations should be pretty rare.
1770 """
1771 try:
1772 size = subprocess.check_output(['stty', 'size']).decode().split()
1773 except (FileNotFoundError, subprocess.CalledProcessError):
1774 self.skipTest("stty invocation failed")
1775 expected = (int(size[1]), int(size[0])) # reversed order
1776
1777 with support.EnvironmentVarGuard() as env:
1778 del env['LINES']
1779 del env['COLUMNS']
1780 actual = shutil.get_terminal_size()
1781
1782 self.assertEqual(expected, actual)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001783
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001784
Berker Peksag8083cd62014-11-01 11:04:06 +02001785class PublicAPITests(unittest.TestCase):
1786 """Ensures that the correct values are exposed in the public API."""
1787
1788 def test_module_all_attribute(self):
1789 self.assertTrue(hasattr(shutil, '__all__'))
1790 target_api = ['copyfileobj', 'copyfile', 'copymode', 'copystat',
1791 'copy', 'copy2', 'copytree', 'move', 'rmtree', 'Error',
1792 'SpecialFileError', 'ExecError', 'make_archive',
1793 'get_archive_formats', 'register_archive_format',
1794 'unregister_archive_format', 'get_unpack_formats',
1795 'register_unpack_format', 'unregister_unpack_format',
1796 'unpack_archive', 'ignore_patterns', 'chown', 'which',
1797 'get_terminal_size', 'SameFileError']
1798 if hasattr(os, 'statvfs') or os.name == 'nt':
1799 target_api.append('disk_usage')
1800 self.assertEqual(set(shutil.__all__), set(target_api))
1801
1802
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001803if __name__ == '__main__':
Brett Cannon3e9a9ae2013-06-12 21:25:59 -04001804 unittest.main()