blob: c4306da5e4143a6910a87f34c0e89c5fb406334b [file] [log] [blame]
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001# Copyright (C) 2003 Python Software Foundation
2
3import unittest
4import shutil
5import tempfile
Johannes Gijsbers8e6f2de2004-11-23 09:27:27 +00006import sys
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +00007import stat
Brett Cannon1c3fa182004-06-19 21:11:35 +00008import os
9import os.path
Antoine Pitrouc041ab62012-01-02 19:18:02 +010010import errno
Nick Coghlan8ed3cf32011-03-16 14:05:35 -040011import functools
Antoine Pitroubcf2b592012-02-08 23:28:36 +010012import subprocess
Serhiy Storchaka41ad77c2014-08-07 19:38:37 +030013from contextlib import ExitStack
Benjamin Petersonee8712c2008-05-20 21:35:26 +000014from test import support
15from test.support import TESTFN
Tarek Ziadé396fad72010-02-23 05:30:31 +000016from os.path import splitdrive
17from distutils.spawn import find_executable, spawn
18from shutil import (_make_tarball, _make_zipfile, make_archive,
19 register_archive_format, unregister_archive_format,
Tarek Ziadé6ac91722010-04-28 17:51:36 +000020 get_archive_formats, Error, unpack_archive,
21 register_unpack_format, RegistryError,
Hynek Schlawack48653762012-10-07 12:49:58 +020022 unregister_unpack_format, get_unpack_formats,
23 SameFileError)
Tarek Ziadé396fad72010-02-23 05:30:31 +000024import tarfile
25import warnings
26
27from test import support
Ezio Melotti975077a2011-05-19 22:03:22 +030028from test.support import TESTFN, check_warnings, captured_stdout, requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +000029
Tarek Ziadéffa155a2010-04-29 13:34:35 +000030try:
31 import bz2
32 BZ2_SUPPORTED = True
33except ImportError:
34 BZ2_SUPPORTED = False
35
Antoine Pitrou7fff0962009-05-01 21:09:44 +000036TESTFN2 = TESTFN + "2"
Barry Warsaw7fc2cca2003-01-24 17:34:13 +000037
Tarek Ziadé396fad72010-02-23 05:30:31 +000038try:
39 import grp
40 import pwd
41 UID_GID_SUPPORT = True
42except ImportError:
43 UID_GID_SUPPORT = False
44
45try:
Tarek Ziadé396fad72010-02-23 05:30:31 +000046 import zipfile
47 ZIP_SUPPORT = True
48except ImportError:
49 ZIP_SUPPORT = find_executable('zip')
50
Nick Coghlan8ed3cf32011-03-16 14:05:35 -040051def _fake_rename(*args, **kwargs):
52 # Pretend the destination path is on a different filesystem.
Antoine Pitrouc041ab62012-01-02 19:18:02 +010053 raise OSError(getattr(errno, 'EXDEV', 18), "Invalid cross-device link")
Nick Coghlan8ed3cf32011-03-16 14:05:35 -040054
55def mock_rename(func):
56 @functools.wraps(func)
57 def wrap(*args, **kwargs):
58 try:
59 builtin_rename = os.rename
60 os.rename = _fake_rename
61 return func(*args, **kwargs)
62 finally:
63 os.rename = builtin_rename
64 return wrap
65
Éric Araujoa7e33a12011-08-12 19:51:35 +020066def write_file(path, content, binary=False):
67 """Write *content* to a file located at *path*.
68
69 If *path* is a tuple instead of a string, os.path.join will be used to
70 make a path. If *binary* is true, the file will be opened in binary
71 mode.
72 """
73 if isinstance(path, tuple):
74 path = os.path.join(*path)
75 with open(path, 'wb' if binary else 'w') as fp:
76 fp.write(content)
77
78def read_file(path, binary=False):
79 """Return contents from a file located at *path*.
80
81 If *path* is a tuple instead of a string, os.path.join will be used to
82 make a path. If *binary* is true, the file will be opened in binary
83 mode.
84 """
85 if isinstance(path, tuple):
86 path = os.path.join(*path)
87 with open(path, 'rb' if binary else 'r') as fp:
88 return fp.read()
89
90
Barry Warsaw7fc2cca2003-01-24 17:34:13 +000091class TestShutil(unittest.TestCase):
Tarek Ziadé396fad72010-02-23 05:30:31 +000092
93 def setUp(self):
94 super(TestShutil, self).setUp()
95 self.tempdirs = []
96
97 def tearDown(self):
98 super(TestShutil, self).tearDown()
99 while self.tempdirs:
100 d = self.tempdirs.pop()
101 shutil.rmtree(d, os.name in ('nt', 'cygwin'))
102
Tarek Ziadé396fad72010-02-23 05:30:31 +0000103
104 def mkdtemp(self):
105 """Create a temporary directory that will be cleaned up.
106
107 Returns the path of the directory.
108 """
109 d = tempfile.mkdtemp()
110 self.tempdirs.append(d)
111 return d
Tarek Ziadé5340db32010-04-19 22:30:51 +0000112
Hynek Schlawack3b527782012-06-25 13:27:31 +0200113 def test_rmtree_works_on_bytes(self):
114 tmp = self.mkdtemp()
115 victim = os.path.join(tmp, 'killme')
116 os.mkdir(victim)
117 write_file(os.path.join(victim, 'somefile'), 'foo')
118 victim = os.fsencode(victim)
119 self.assertIsInstance(victim, bytes)
Serhiy Storchaka41ad77c2014-08-07 19:38:37 +0300120 win = (os.name == 'nt')
121 with self.assertWarns(DeprecationWarning) if win else ExitStack():
122 shutil.rmtree(victim)
Hynek Schlawack3b527782012-06-25 13:27:31 +0200123
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200124 @support.skip_unless_symlink
125 def test_rmtree_fails_on_symlink(self):
126 tmp = self.mkdtemp()
127 dir_ = os.path.join(tmp, 'dir')
128 os.mkdir(dir_)
129 link = os.path.join(tmp, 'link')
130 os.symlink(dir_, link)
131 self.assertRaises(OSError, shutil.rmtree, link)
132 self.assertTrue(os.path.exists(dir_))
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100133 self.assertTrue(os.path.lexists(link))
134 errors = []
135 def onerror(*args):
136 errors.append(args)
137 shutil.rmtree(link, onerror=onerror)
138 self.assertEqual(len(errors), 1)
139 self.assertIs(errors[0][0], os.path.islink)
140 self.assertEqual(errors[0][1], link)
141 self.assertIsInstance(errors[0][2][1], OSError)
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200142
143 @support.skip_unless_symlink
144 def test_rmtree_works_on_symlinks(self):
145 tmp = self.mkdtemp()
146 dir1 = os.path.join(tmp, 'dir1')
147 dir2 = os.path.join(dir1, 'dir2')
148 dir3 = os.path.join(tmp, 'dir3')
149 for d in dir1, dir2, dir3:
150 os.mkdir(d)
151 file1 = os.path.join(tmp, 'file1')
152 write_file(file1, 'foo')
153 link1 = os.path.join(dir1, 'link1')
154 os.symlink(dir2, link1)
155 link2 = os.path.join(dir1, 'link2')
156 os.symlink(dir3, link2)
157 link3 = os.path.join(dir1, 'link3')
158 os.symlink(file1, link3)
159 # make sure symlinks are removed but not followed
160 shutil.rmtree(dir1)
161 self.assertFalse(os.path.exists(dir1))
162 self.assertTrue(os.path.exists(dir3))
163 self.assertTrue(os.path.exists(file1))
164
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000165 def test_rmtree_errors(self):
166 # filename is guaranteed not to exist
167 filename = tempfile.mktemp()
Hynek Schlawackb5501102012-12-10 09:11:25 +0100168 self.assertRaises(FileNotFoundError, shutil.rmtree, filename)
169 # test that ignore_errors option is honored
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100170 shutil.rmtree(filename, ignore_errors=True)
171
172 # existing file
173 tmpdir = self.mkdtemp()
Hynek Schlawackb5501102012-12-10 09:11:25 +0100174 write_file((tmpdir, "tstfile"), "")
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100175 filename = os.path.join(tmpdir, "tstfile")
Hynek Schlawackb5501102012-12-10 09:11:25 +0100176 with self.assertRaises(NotADirectoryError) as cm:
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100177 shutil.rmtree(filename)
Hynek Schlawack87f9b462012-12-10 16:29:57 +0100178 # The reason for this rather odd construct is that Windows sprinkles
179 # a \*.* at the end of file names. But only sometimes on some buildbots
180 possible_args = [filename, os.path.join(filename, '*.*')]
181 self.assertIn(cm.exception.filename, possible_args)
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100182 self.assertTrue(os.path.exists(filename))
Hynek Schlawackb5501102012-12-10 09:11:25 +0100183 # test that ignore_errors option is honored
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100184 shutil.rmtree(filename, ignore_errors=True)
185 self.assertTrue(os.path.exists(filename))
186 errors = []
187 def onerror(*args):
188 errors.append(args)
189 shutil.rmtree(filename, onerror=onerror)
190 self.assertEqual(len(errors), 2)
191 self.assertIs(errors[0][0], os.listdir)
192 self.assertEqual(errors[0][1], filename)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100193 self.assertIsInstance(errors[0][2][1], NotADirectoryError)
Hynek Schlawack87f9b462012-12-10 16:29:57 +0100194 self.assertIn(errors[0][2][1].filename, possible_args)
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100195 self.assertIs(errors[1][0], os.rmdir)
196 self.assertEqual(errors[1][1], filename)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100197 self.assertIsInstance(errors[1][2][1], NotADirectoryError)
Hynek Schlawack87f9b462012-12-10 16:29:57 +0100198 self.assertIn(errors[1][2][1].filename, possible_args)
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000199
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000200
Serhiy Storchaka43767632013-11-03 21:31:38 +0200201 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod()')
202 @unittest.skipIf(sys.platform[:6] == 'cygwin',
203 "This test can't be run on Cygwin (issue #1071513).")
204 @unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0,
205 "This test can't be run reliably as root (issue #1076467).")
206 def test_on_error(self):
207 self.errorState = 0
208 os.mkdir(TESTFN)
209 self.addCleanup(shutil.rmtree, TESTFN)
Antoine Pitrou2f8a75c2012-06-23 21:28:15 +0200210
Serhiy Storchaka43767632013-11-03 21:31:38 +0200211 self.child_file_path = os.path.join(TESTFN, 'a')
212 self.child_dir_path = os.path.join(TESTFN, 'b')
213 support.create_empty_file(self.child_file_path)
214 os.mkdir(self.child_dir_path)
215 old_dir_mode = os.stat(TESTFN).st_mode
216 old_child_file_mode = os.stat(self.child_file_path).st_mode
217 old_child_dir_mode = os.stat(self.child_dir_path).st_mode
218 # Make unwritable.
219 new_mode = stat.S_IREAD|stat.S_IEXEC
220 os.chmod(self.child_file_path, new_mode)
221 os.chmod(self.child_dir_path, new_mode)
222 os.chmod(TESTFN, new_mode)
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000223
Serhiy Storchaka43767632013-11-03 21:31:38 +0200224 self.addCleanup(os.chmod, TESTFN, old_dir_mode)
225 self.addCleanup(os.chmod, self.child_file_path, old_child_file_mode)
226 self.addCleanup(os.chmod, self.child_dir_path, old_child_dir_mode)
Antoine Pitrou2f8a75c2012-06-23 21:28:15 +0200227
Serhiy Storchaka43767632013-11-03 21:31:38 +0200228 shutil.rmtree(TESTFN, onerror=self.check_args_to_onerror)
229 # Test whether onerror has actually been called.
230 self.assertEqual(self.errorState, 3,
231 "Expected call to onerror function did not happen.")
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000232
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000233 def check_args_to_onerror(self, func, arg, exc):
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000234 # test_rmtree_errors deliberately runs rmtree
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200235 # on a directory that is chmod 500, which will fail.
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000236 # This function is run when shutil.rmtree fails.
237 # 99.9% of the time it initially fails to remove
238 # a file in the directory, so the first time through
239 # func is os.remove.
240 # However, some Linux machines running ZFS on
241 # FUSE experienced a failure earlier in the process
242 # at os.listdir. The first failure may legally
243 # be either.
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200244 if self.errorState < 2:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200245 if func is os.unlink:
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200246 self.assertEqual(arg, self.child_file_path)
247 elif func is os.rmdir:
248 self.assertEqual(arg, self.child_dir_path)
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000249 else:
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200250 self.assertIs(func, os.listdir)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200251 self.assertIn(arg, [TESTFN, self.child_dir_path])
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000252 self.assertTrue(issubclass(exc[0], OSError))
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200253 self.errorState += 1
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000254 else:
255 self.assertEqual(func, os.rmdir)
256 self.assertEqual(arg, TESTFN)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000257 self.assertTrue(issubclass(exc[0], OSError))
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200258 self.errorState = 3
259
260 def test_rmtree_does_not_choke_on_failing_lstat(self):
261 try:
262 orig_lstat = os.lstat
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200263 def raiser(fn, *args, **kwargs):
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200264 if fn != TESTFN:
265 raise OSError()
266 else:
267 return orig_lstat(fn)
268 os.lstat = raiser
269
270 os.mkdir(TESTFN)
271 write_file((TESTFN, 'foo'), 'foo')
272 shutil.rmtree(TESTFN)
273 finally:
274 os.lstat = orig_lstat
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000275
Antoine Pitrou78091e62011-12-29 18:54:15 +0100276 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
277 @support.skip_unless_symlink
278 def test_copymode_follow_symlinks(self):
279 tmp_dir = self.mkdtemp()
280 src = os.path.join(tmp_dir, 'foo')
281 dst = os.path.join(tmp_dir, 'bar')
282 src_link = os.path.join(tmp_dir, 'baz')
283 dst_link = os.path.join(tmp_dir, 'quux')
284 write_file(src, 'foo')
285 write_file(dst, 'foo')
286 os.symlink(src, src_link)
287 os.symlink(dst, dst_link)
288 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
289 # file to file
290 os.chmod(dst, stat.S_IRWXO)
291 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
292 shutil.copymode(src, dst)
293 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
Antoine Pitrou3f48ac92014-01-01 02:50:45 +0100294 # On Windows, os.chmod does not follow symlinks (issue #15411)
295 if os.name != 'nt':
296 # follow src link
297 os.chmod(dst, stat.S_IRWXO)
298 shutil.copymode(src_link, dst)
299 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
300 # follow dst link
301 os.chmod(dst, stat.S_IRWXO)
302 shutil.copymode(src, dst_link)
303 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
304 # follow both links
305 os.chmod(dst, stat.S_IRWXO)
306 shutil.copymode(src_link, dst_link)
307 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100308
309 @unittest.skipUnless(hasattr(os, 'lchmod'), 'requires os.lchmod')
310 @support.skip_unless_symlink
311 def test_copymode_symlink_to_symlink(self):
312 tmp_dir = self.mkdtemp()
313 src = os.path.join(tmp_dir, 'foo')
314 dst = os.path.join(tmp_dir, 'bar')
315 src_link = os.path.join(tmp_dir, 'baz')
316 dst_link = os.path.join(tmp_dir, 'quux')
317 write_file(src, 'foo')
318 write_file(dst, 'foo')
319 os.symlink(src, src_link)
320 os.symlink(dst, dst_link)
321 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
322 os.chmod(dst, stat.S_IRWXU)
323 os.lchmod(src_link, stat.S_IRWXO|stat.S_IRWXG)
324 # link to link
325 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700326 shutil.copymode(src_link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100327 self.assertEqual(os.lstat(src_link).st_mode,
328 os.lstat(dst_link).st_mode)
329 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
330 # src link - use chmod
331 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700332 shutil.copymode(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100333 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
334 # dst link - use chmod
335 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700336 shutil.copymode(src, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100337 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
338
339 @unittest.skipIf(hasattr(os, 'lchmod'), 'requires os.lchmod to be missing')
340 @support.skip_unless_symlink
341 def test_copymode_symlink_to_symlink_wo_lchmod(self):
342 tmp_dir = self.mkdtemp()
343 src = os.path.join(tmp_dir, 'foo')
344 dst = os.path.join(tmp_dir, 'bar')
345 src_link = os.path.join(tmp_dir, 'baz')
346 dst_link = os.path.join(tmp_dir, 'quux')
347 write_file(src, 'foo')
348 write_file(dst, 'foo')
349 os.symlink(src, src_link)
350 os.symlink(dst, dst_link)
Larry Hastingsb4038062012-07-15 10:57:38 -0700351 shutil.copymode(src_link, dst_link, follow_symlinks=False) # silent fail
Antoine Pitrou78091e62011-12-29 18:54:15 +0100352
353 @support.skip_unless_symlink
354 def test_copystat_symlinks(self):
355 tmp_dir = self.mkdtemp()
356 src = os.path.join(tmp_dir, 'foo')
357 dst = os.path.join(tmp_dir, 'bar')
358 src_link = os.path.join(tmp_dir, 'baz')
359 dst_link = os.path.join(tmp_dir, 'qux')
360 write_file(src, 'foo')
361 src_stat = os.stat(src)
362 os.utime(src, (src_stat.st_atime,
363 src_stat.st_mtime - 42.0)) # ensure different mtimes
364 write_file(dst, 'bar')
365 self.assertNotEqual(os.stat(src).st_mtime, os.stat(dst).st_mtime)
366 os.symlink(src, src_link)
367 os.symlink(dst, dst_link)
368 if hasattr(os, 'lchmod'):
369 os.lchmod(src_link, stat.S_IRWXO)
370 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
371 os.lchflags(src_link, stat.UF_NODUMP)
372 src_link_stat = os.lstat(src_link)
373 # follow
374 if hasattr(os, 'lchmod'):
Larry Hastingsb4038062012-07-15 10:57:38 -0700375 shutil.copystat(src_link, dst_link, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100376 self.assertNotEqual(src_link_stat.st_mode, os.stat(dst).st_mode)
377 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700378 shutil.copystat(src_link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100379 dst_link_stat = os.lstat(dst_link)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700380 if os.utime in os.supports_follow_symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100381 for attr in 'st_atime', 'st_mtime':
382 # The modification times may be truncated in the new file.
383 self.assertLessEqual(getattr(src_link_stat, attr),
384 getattr(dst_link_stat, attr) + 1)
385 if hasattr(os, 'lchmod'):
386 self.assertEqual(src_link_stat.st_mode, dst_link_stat.st_mode)
387 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
388 self.assertEqual(src_link_stat.st_flags, dst_link_stat.st_flags)
389 # tell to follow but dst is not a link
Larry Hastingsb4038062012-07-15 10:57:38 -0700390 shutil.copystat(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100391 self.assertTrue(abs(os.stat(src).st_mtime - os.stat(dst).st_mtime) <
392 00000.1)
393
Ned Deilybaf75712012-05-10 17:05:19 -0700394 @unittest.skipUnless(hasattr(os, 'chflags') and
395 hasattr(errno, 'EOPNOTSUPP') and
396 hasattr(errno, 'ENOTSUP'),
397 "requires os.chflags, EOPNOTSUPP & ENOTSUP")
398 def test_copystat_handles_harmless_chflags_errors(self):
399 tmpdir = self.mkdtemp()
400 file1 = os.path.join(tmpdir, 'file1')
401 file2 = os.path.join(tmpdir, 'file2')
402 write_file(file1, 'xxx')
403 write_file(file2, 'xxx')
404
405 def make_chflags_raiser(err):
406 ex = OSError()
407
Larry Hastings90867a52012-06-22 17:01:41 -0700408 def _chflags_raiser(path, flags, *, follow_symlinks=True):
Ned Deilybaf75712012-05-10 17:05:19 -0700409 ex.errno = err
410 raise ex
411 return _chflags_raiser
412 old_chflags = os.chflags
413 try:
414 for err in errno.EOPNOTSUPP, errno.ENOTSUP:
415 os.chflags = make_chflags_raiser(err)
416 shutil.copystat(file1, file2)
417 # assert others errors break it
418 os.chflags = make_chflags_raiser(errno.EOPNOTSUPP + errno.ENOTSUP)
419 self.assertRaises(OSError, shutil.copystat, file1, file2)
420 finally:
421 os.chflags = old_chflags
422
Antoine Pitrou424246f2012-05-12 19:02:01 +0200423 @support.skip_unless_xattr
424 def test_copyxattr(self):
425 tmp_dir = self.mkdtemp()
426 src = os.path.join(tmp_dir, 'foo')
427 write_file(src, 'foo')
428 dst = os.path.join(tmp_dir, 'bar')
429 write_file(dst, 'bar')
430
431 # no xattr == no problem
432 shutil._copyxattr(src, dst)
433 # common case
434 os.setxattr(src, 'user.foo', b'42')
435 os.setxattr(src, 'user.bar', b'43')
436 shutil._copyxattr(src, dst)
Gregory P. Smith1093bf22014-01-17 12:01:22 -0800437 self.assertEqual(sorted(os.listxattr(src)), sorted(os.listxattr(dst)))
Antoine Pitrou424246f2012-05-12 19:02:01 +0200438 self.assertEqual(
439 os.getxattr(src, 'user.foo'),
440 os.getxattr(dst, 'user.foo'))
441 # check errors don't affect other attrs
442 os.remove(dst)
443 write_file(dst, 'bar')
444 os_error = OSError(errno.EPERM, 'EPERM')
445
Larry Hastings9cf065c2012-06-22 16:30:09 -0700446 def _raise_on_user_foo(fname, attr, val, **kwargs):
Antoine Pitrou424246f2012-05-12 19:02:01 +0200447 if attr == 'user.foo':
448 raise os_error
449 else:
Larry Hastings9cf065c2012-06-22 16:30:09 -0700450 orig_setxattr(fname, attr, val, **kwargs)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200451 try:
452 orig_setxattr = os.setxattr
453 os.setxattr = _raise_on_user_foo
454 shutil._copyxattr(src, dst)
Antoine Pitrou61597d32012-05-12 23:37:35 +0200455 self.assertIn('user.bar', os.listxattr(dst))
Antoine Pitrou424246f2012-05-12 19:02:01 +0200456 finally:
457 os.setxattr = orig_setxattr
Hynek Schlawack0beab052013-02-05 08:22:44 +0100458 # the source filesystem not supporting xattrs should be ok, too.
459 def _raise_on_src(fname, *, follow_symlinks=True):
460 if fname == src:
461 raise OSError(errno.ENOTSUP, 'Operation not supported')
462 return orig_listxattr(fname, follow_symlinks=follow_symlinks)
463 try:
464 orig_listxattr = os.listxattr
465 os.listxattr = _raise_on_src
466 shutil._copyxattr(src, dst)
467 finally:
468 os.listxattr = orig_listxattr
Antoine Pitrou424246f2012-05-12 19:02:01 +0200469
Larry Hastingsad5ae042012-07-14 17:55:11 -0700470 # test that shutil.copystat copies xattrs
471 src = os.path.join(tmp_dir, 'the_original')
472 write_file(src, src)
473 os.setxattr(src, 'user.the_value', b'fiddly')
474 dst = os.path.join(tmp_dir, 'the_copy')
475 write_file(dst, dst)
476 shutil.copystat(src, dst)
Hynek Schlawackc2d481f2012-07-16 17:11:10 +0200477 self.assertEqual(os.getxattr(dst, 'user.the_value'), b'fiddly')
Larry Hastingsad5ae042012-07-14 17:55:11 -0700478
Antoine Pitrou424246f2012-05-12 19:02:01 +0200479 @support.skip_unless_symlink
480 @support.skip_unless_xattr
481 @unittest.skipUnless(hasattr(os, 'geteuid') and os.geteuid() == 0,
482 'root privileges required')
483 def test_copyxattr_symlinks(self):
484 # On Linux, it's only possible to access non-user xattr for symlinks;
485 # which in turn require root privileges. This test should be expanded
486 # as soon as other platforms gain support for extended attributes.
487 tmp_dir = self.mkdtemp()
488 src = os.path.join(tmp_dir, 'foo')
489 src_link = os.path.join(tmp_dir, 'baz')
490 write_file(src, 'foo')
491 os.symlink(src, src_link)
492 os.setxattr(src, 'trusted.foo', b'42')
Larry Hastings9cf065c2012-06-22 16:30:09 -0700493 os.setxattr(src_link, 'trusted.foo', b'43', follow_symlinks=False)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200494 dst = os.path.join(tmp_dir, 'bar')
495 dst_link = os.path.join(tmp_dir, 'qux')
496 write_file(dst, 'bar')
497 os.symlink(dst, dst_link)
Larry Hastingsb4038062012-07-15 10:57:38 -0700498 shutil._copyxattr(src_link, dst_link, follow_symlinks=False)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700499 self.assertEqual(os.getxattr(dst_link, 'trusted.foo', follow_symlinks=False), b'43')
Antoine Pitrou424246f2012-05-12 19:02:01 +0200500 self.assertRaises(OSError, os.getxattr, dst, 'trusted.foo')
Larry Hastingsb4038062012-07-15 10:57:38 -0700501 shutil._copyxattr(src_link, dst, follow_symlinks=False)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200502 self.assertEqual(os.getxattr(dst, 'trusted.foo'), b'43')
503
Antoine Pitrou78091e62011-12-29 18:54:15 +0100504 @support.skip_unless_symlink
505 def test_copy_symlinks(self):
506 tmp_dir = self.mkdtemp()
507 src = os.path.join(tmp_dir, 'foo')
508 dst = os.path.join(tmp_dir, 'bar')
509 src_link = os.path.join(tmp_dir, 'baz')
510 write_file(src, 'foo')
511 os.symlink(src, src_link)
512 if hasattr(os, 'lchmod'):
513 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
514 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700515 shutil.copy(src_link, dst, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100516 self.assertFalse(os.path.islink(dst))
517 self.assertEqual(read_file(src), read_file(dst))
518 os.remove(dst)
519 # follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700520 shutil.copy(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100521 self.assertTrue(os.path.islink(dst))
522 self.assertEqual(os.readlink(dst), os.readlink(src_link))
523 if hasattr(os, 'lchmod'):
524 self.assertEqual(os.lstat(src_link).st_mode,
525 os.lstat(dst).st_mode)
526
527 @support.skip_unless_symlink
528 def test_copy2_symlinks(self):
529 tmp_dir = self.mkdtemp()
530 src = os.path.join(tmp_dir, 'foo')
531 dst = os.path.join(tmp_dir, 'bar')
532 src_link = os.path.join(tmp_dir, 'baz')
533 write_file(src, 'foo')
534 os.symlink(src, src_link)
535 if hasattr(os, 'lchmod'):
536 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
537 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
538 os.lchflags(src_link, stat.UF_NODUMP)
539 src_stat = os.stat(src)
540 src_link_stat = os.lstat(src_link)
541 # follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700542 shutil.copy2(src_link, dst, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100543 self.assertFalse(os.path.islink(dst))
544 self.assertEqual(read_file(src), read_file(dst))
545 os.remove(dst)
546 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700547 shutil.copy2(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100548 self.assertTrue(os.path.islink(dst))
549 self.assertEqual(os.readlink(dst), os.readlink(src_link))
550 dst_stat = os.lstat(dst)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700551 if os.utime in os.supports_follow_symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100552 for attr in 'st_atime', 'st_mtime':
553 # The modification times may be truncated in the new file.
554 self.assertLessEqual(getattr(src_link_stat, attr),
555 getattr(dst_stat, attr) + 1)
556 if hasattr(os, 'lchmod'):
557 self.assertEqual(src_link_stat.st_mode, dst_stat.st_mode)
558 self.assertNotEqual(src_stat.st_mode, dst_stat.st_mode)
559 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
560 self.assertEqual(src_link_stat.st_flags, dst_stat.st_flags)
561
Antoine Pitrou424246f2012-05-12 19:02:01 +0200562 @support.skip_unless_xattr
563 def test_copy2_xattr(self):
564 tmp_dir = self.mkdtemp()
565 src = os.path.join(tmp_dir, 'foo')
566 dst = os.path.join(tmp_dir, 'bar')
567 write_file(src, 'foo')
568 os.setxattr(src, 'user.foo', b'42')
569 shutil.copy2(src, dst)
570 self.assertEqual(
571 os.getxattr(src, 'user.foo'),
572 os.getxattr(dst, 'user.foo'))
573 os.remove(dst)
574
Antoine Pitrou78091e62011-12-29 18:54:15 +0100575 @support.skip_unless_symlink
576 def test_copyfile_symlinks(self):
577 tmp_dir = self.mkdtemp()
578 src = os.path.join(tmp_dir, 'src')
579 dst = os.path.join(tmp_dir, 'dst')
580 dst_link = os.path.join(tmp_dir, 'dst_link')
581 link = os.path.join(tmp_dir, 'link')
582 write_file(src, 'foo')
583 os.symlink(src, link)
584 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700585 shutil.copyfile(link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100586 self.assertTrue(os.path.islink(dst_link))
587 self.assertEqual(os.readlink(link), os.readlink(dst_link))
588 # follow
589 shutil.copyfile(link, dst)
590 self.assertFalse(os.path.islink(dst))
591
Hynek Schlawack2100b422012-06-23 20:28:32 +0200592 def test_rmtree_uses_safe_fd_version_if_available(self):
Hynek Schlawackd0f6e0a2012-06-29 08:28:20 +0200593 _use_fd_functions = ({os.open, os.stat, os.unlink, os.rmdir} <=
594 os.supports_dir_fd and
595 os.listdir in os.supports_fd and
596 os.stat in os.supports_follow_symlinks)
597 if _use_fd_functions:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200598 self.assertTrue(shutil._use_fd_functions)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000599 self.assertTrue(shutil.rmtree.avoids_symlink_attacks)
Hynek Schlawack2100b422012-06-23 20:28:32 +0200600 tmp_dir = self.mkdtemp()
601 d = os.path.join(tmp_dir, 'a')
602 os.mkdir(d)
603 try:
604 real_rmtree = shutil._rmtree_safe_fd
605 class Called(Exception): pass
606 def _raiser(*args, **kwargs):
607 raise Called
608 shutil._rmtree_safe_fd = _raiser
609 self.assertRaises(Called, shutil.rmtree, d)
610 finally:
611 shutil._rmtree_safe_fd = real_rmtree
612 else:
613 self.assertFalse(shutil._use_fd_functions)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000614 self.assertFalse(shutil.rmtree.avoids_symlink_attacks)
Hynek Schlawack2100b422012-06-23 20:28:32 +0200615
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000616 def test_rmtree_dont_delete_file(self):
617 # When called on a file instead of a directory, don't delete it.
618 handle, path = tempfile.mkstemp()
Victor Stinnerbf816222011-06-30 23:25:47 +0200619 os.close(handle)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200620 self.assertRaises(NotADirectoryError, shutil.rmtree, path)
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000621 os.remove(path)
622
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000623 def test_copytree_simple(self):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000624 src_dir = tempfile.mkdtemp()
625 dst_dir = os.path.join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200626 self.addCleanup(shutil.rmtree, src_dir)
627 self.addCleanup(shutil.rmtree, os.path.dirname(dst_dir))
628 write_file((src_dir, 'test.txt'), '123')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000629 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200630 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000631
Éric Araujoa7e33a12011-08-12 19:51:35 +0200632 shutil.copytree(src_dir, dst_dir)
633 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test.txt')))
634 self.assertTrue(os.path.isdir(os.path.join(dst_dir, 'test_dir')))
635 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test_dir',
636 'test.txt')))
637 actual = read_file((dst_dir, 'test.txt'))
638 self.assertEqual(actual, '123')
639 actual = read_file((dst_dir, 'test_dir', 'test.txt'))
640 self.assertEqual(actual, '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000641
Antoine Pitrou78091e62011-12-29 18:54:15 +0100642 @support.skip_unless_symlink
643 def test_copytree_symlinks(self):
644 tmp_dir = self.mkdtemp()
645 src_dir = os.path.join(tmp_dir, 'src')
646 dst_dir = os.path.join(tmp_dir, 'dst')
647 sub_dir = os.path.join(src_dir, 'sub')
648 os.mkdir(src_dir)
649 os.mkdir(sub_dir)
650 write_file((src_dir, 'file.txt'), 'foo')
651 src_link = os.path.join(sub_dir, 'link')
652 dst_link = os.path.join(dst_dir, 'sub/link')
653 os.symlink(os.path.join(src_dir, 'file.txt'),
654 src_link)
655 if hasattr(os, 'lchmod'):
656 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
657 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
658 os.lchflags(src_link, stat.UF_NODUMP)
659 src_stat = os.lstat(src_link)
660 shutil.copytree(src_dir, dst_dir, symlinks=True)
661 self.assertTrue(os.path.islink(os.path.join(dst_dir, 'sub', 'link')))
662 self.assertEqual(os.readlink(os.path.join(dst_dir, 'sub', 'link')),
663 os.path.join(src_dir, 'file.txt'))
664 dst_stat = os.lstat(dst_link)
665 if hasattr(os, 'lchmod'):
666 self.assertEqual(dst_stat.st_mode, src_stat.st_mode)
667 if hasattr(os, 'lchflags'):
668 self.assertEqual(dst_stat.st_flags, src_stat.st_flags)
669
Georg Brandl2ee470f2008-07-16 12:55:28 +0000670 def test_copytree_with_exclude(self):
Georg Brandl2ee470f2008-07-16 12:55:28 +0000671 # creating data
672 join = os.path.join
673 exists = os.path.exists
674 src_dir = tempfile.mkdtemp()
Georg Brandl2ee470f2008-07-16 12:55:28 +0000675 try:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000676 dst_dir = join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200677 write_file((src_dir, 'test.txt'), '123')
678 write_file((src_dir, 'test.tmp'), '123')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000679 os.mkdir(join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200680 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000681 os.mkdir(join(src_dir, 'test_dir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200682 write_file((src_dir, 'test_dir2', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000683 os.mkdir(join(src_dir, 'test_dir2', 'subdir'))
684 os.mkdir(join(src_dir, 'test_dir2', 'subdir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200685 write_file((src_dir, 'test_dir2', 'subdir', 'test.txt'), '456')
686 write_file((src_dir, 'test_dir2', 'subdir2', 'test.py'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000687
688 # testing glob-like patterns
689 try:
690 patterns = shutil.ignore_patterns('*.tmp', 'test_dir2')
691 shutil.copytree(src_dir, dst_dir, ignore=patterns)
692 # checking the result: some elements should not be copied
693 self.assertTrue(exists(join(dst_dir, 'test.txt')))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200694 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
695 self.assertFalse(exists(join(dst_dir, 'test_dir2')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000696 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200697 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000698 try:
699 patterns = shutil.ignore_patterns('*.tmp', 'subdir*')
700 shutil.copytree(src_dir, dst_dir, ignore=patterns)
701 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200702 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
703 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2')))
704 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000705 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200706 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000707
708 # testing callable-style
709 try:
710 def _filter(src, names):
711 res = []
712 for name in names:
713 path = os.path.join(src, name)
714
715 if (os.path.isdir(path) and
716 path.split()[-1] == 'subdir'):
717 res.append(name)
718 elif os.path.splitext(path)[-1] in ('.py'):
719 res.append(name)
720 return res
721
722 shutil.copytree(src_dir, dst_dir, ignore=_filter)
723
724 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200725 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2',
726 'test.py')))
727 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000728
729 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200730 shutil.rmtree(dst_dir)
Georg Brandl2ee470f2008-07-16 12:55:28 +0000731 finally:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000732 shutil.rmtree(src_dir)
733 shutil.rmtree(os.path.dirname(dst_dir))
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000734
Antoine Pitrouac601602013-08-16 19:35:02 +0200735 def test_copytree_retains_permissions(self):
736 tmp_dir = tempfile.mkdtemp()
737 src_dir = os.path.join(tmp_dir, 'source')
738 os.mkdir(src_dir)
739 dst_dir = os.path.join(tmp_dir, 'destination')
740 self.addCleanup(shutil.rmtree, tmp_dir)
741
742 os.chmod(src_dir, 0o777)
743 write_file((src_dir, 'permissive.txt'), '123')
744 os.chmod(os.path.join(src_dir, 'permissive.txt'), 0o777)
745 write_file((src_dir, 'restrictive.txt'), '456')
746 os.chmod(os.path.join(src_dir, 'restrictive.txt'), 0o600)
747 restrictive_subdir = tempfile.mkdtemp(dir=src_dir)
748 os.chmod(restrictive_subdir, 0o600)
749
750 shutil.copytree(src_dir, dst_dir)
Brett Cannon9c7eb552013-08-23 14:38:11 -0400751 self.assertEqual(os.stat(src_dir).st_mode, os.stat(dst_dir).st_mode)
752 self.assertEqual(os.stat(os.path.join(src_dir, 'permissive.txt')).st_mode,
Antoine Pitrouac601602013-08-16 19:35:02 +0200753 os.stat(os.path.join(dst_dir, 'permissive.txt')).st_mode)
Brett Cannon9c7eb552013-08-23 14:38:11 -0400754 self.assertEqual(os.stat(os.path.join(src_dir, 'restrictive.txt')).st_mode,
Antoine Pitrouac601602013-08-16 19:35:02 +0200755 os.stat(os.path.join(dst_dir, 'restrictive.txt')).st_mode)
756 restrictive_subdir_dst = os.path.join(dst_dir,
757 os.path.split(restrictive_subdir)[1])
Brett Cannon9c7eb552013-08-23 14:38:11 -0400758 self.assertEqual(os.stat(restrictive_subdir).st_mode,
Antoine Pitrouac601602013-08-16 19:35:02 +0200759 os.stat(restrictive_subdir_dst).st_mode)
760
Zachary Ware9fe6d862013-12-08 00:20:35 -0600761 @unittest.skipIf(os.name == 'nt', 'temporarily disabled on Windows')
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000762 @unittest.skipUnless(hasattr(os, 'link'), 'requires os.link')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000763 def test_dont_copy_file_onto_link_to_itself(self):
764 # bug 851123.
765 os.mkdir(TESTFN)
766 src = os.path.join(TESTFN, 'cheese')
767 dst = os.path.join(TESTFN, 'shop')
768 try:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000769 with open(src, 'w') as f:
770 f.write('cheddar')
771 os.link(src, dst)
Hynek Schlawack48653762012-10-07 12:49:58 +0200772 self.assertRaises(shutil.SameFileError, shutil.copyfile, src, dst)
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000773 with open(src, 'r') as f:
774 self.assertEqual(f.read(), 'cheddar')
775 os.remove(dst)
776 finally:
777 shutil.rmtree(TESTFN, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000778
Brian Curtin3b4499c2010-12-28 14:31:47 +0000779 @support.skip_unless_symlink
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000780 def test_dont_copy_file_onto_symlink_to_itself(self):
781 # bug 851123.
782 os.mkdir(TESTFN)
783 src = os.path.join(TESTFN, 'cheese')
784 dst = os.path.join(TESTFN, 'shop')
785 try:
786 with open(src, 'w') as f:
787 f.write('cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000788 # Using `src` here would mean we end up with a symlink pointing
789 # to TESTFN/TESTFN/cheese, while it should point at
790 # TESTFN/cheese.
791 os.symlink('cheese', dst)
Hynek Schlawack48653762012-10-07 12:49:58 +0200792 self.assertRaises(shutil.SameFileError, shutil.copyfile, src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +0000793 with open(src, 'r') as f:
794 self.assertEqual(f.read(), 'cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000795 os.remove(dst)
796 finally:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000797 shutil.rmtree(TESTFN, ignore_errors=True)
Johannes Gijsbers68128712004-08-14 13:57:08 +0000798
Brian Curtin3b4499c2010-12-28 14:31:47 +0000799 @support.skip_unless_symlink
Brian Curtind40e6f72010-07-08 21:39:08 +0000800 def test_rmtree_on_symlink(self):
801 # bug 1669.
802 os.mkdir(TESTFN)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000803 try:
Brian Curtind40e6f72010-07-08 21:39:08 +0000804 src = os.path.join(TESTFN, 'cheese')
805 dst = os.path.join(TESTFN, 'shop')
806 os.mkdir(src)
807 os.symlink(src, dst)
808 self.assertRaises(OSError, shutil.rmtree, dst)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200809 shutil.rmtree(dst, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000810 finally:
Brian Curtind40e6f72010-07-08 21:39:08 +0000811 shutil.rmtree(TESTFN, ignore_errors=True)
812
Serhiy Storchaka43767632013-11-03 21:31:38 +0200813 # Issue #3002: copyfile and copytree block indefinitely on named pipes
814 @unittest.skipUnless(hasattr(os, "mkfifo"), 'requires os.mkfifo()')
815 def test_copyfile_named_pipe(self):
816 os.mkfifo(TESTFN)
817 try:
818 self.assertRaises(shutil.SpecialFileError,
819 shutil.copyfile, TESTFN, TESTFN2)
820 self.assertRaises(shutil.SpecialFileError,
821 shutil.copyfile, __file__, TESTFN)
822 finally:
823 os.remove(TESTFN)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000824
Serhiy Storchaka43767632013-11-03 21:31:38 +0200825 @unittest.skipUnless(hasattr(os, "mkfifo"), 'requires os.mkfifo()')
826 @support.skip_unless_symlink
827 def test_copytree_named_pipe(self):
828 os.mkdir(TESTFN)
829 try:
830 subdir = os.path.join(TESTFN, "subdir")
831 os.mkdir(subdir)
832 pipe = os.path.join(subdir, "mypipe")
833 os.mkfifo(pipe)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000834 try:
Serhiy Storchaka43767632013-11-03 21:31:38 +0200835 shutil.copytree(TESTFN, TESTFN2)
836 except shutil.Error as e:
837 errors = e.args[0]
838 self.assertEqual(len(errors), 1)
839 src, dst, error_msg = errors[0]
840 self.assertEqual("`%s` is a named pipe" % pipe, error_msg)
841 else:
842 self.fail("shutil.Error should have been raised")
843 finally:
844 shutil.rmtree(TESTFN, ignore_errors=True)
845 shutil.rmtree(TESTFN2, ignore_errors=True)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000846
Tarek Ziadé5340db32010-04-19 22:30:51 +0000847 def test_copytree_special_func(self):
848
849 src_dir = self.mkdtemp()
850 dst_dir = os.path.join(self.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200851 write_file((src_dir, 'test.txt'), '123')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000852 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200853 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000854
855 copied = []
856 def _copy(src, dst):
857 copied.append((src, dst))
858
859 shutil.copytree(src_dir, dst_dir, copy_function=_copy)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000860 self.assertEqual(len(copied), 2)
Tarek Ziadé5340db32010-04-19 22:30:51 +0000861
Brian Curtin3b4499c2010-12-28 14:31:47 +0000862 @support.skip_unless_symlink
Tarek Ziadéfb437512010-04-20 08:57:33 +0000863 def test_copytree_dangling_symlinks(self):
864
865 # a dangling symlink raises an error at the end
866 src_dir = self.mkdtemp()
867 dst_dir = os.path.join(self.mkdtemp(), 'destination')
868 os.symlink('IDONTEXIST', os.path.join(src_dir, 'test.txt'))
869 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200870 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadéfb437512010-04-20 08:57:33 +0000871 self.assertRaises(Error, shutil.copytree, src_dir, dst_dir)
872
873 # a dangling symlink is ignored with the proper flag
874 dst_dir = os.path.join(self.mkdtemp(), 'destination2')
875 shutil.copytree(src_dir, dst_dir, ignore_dangling_symlinks=True)
876 self.assertNotIn('test.txt', os.listdir(dst_dir))
877
878 # a dangling symlink is copied if symlinks=True
879 dst_dir = os.path.join(self.mkdtemp(), 'destination3')
880 shutil.copytree(src_dir, dst_dir, symlinks=True)
881 self.assertIn('test.txt', os.listdir(dst_dir))
882
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400883 def _copy_file(self, method):
884 fname = 'test.txt'
885 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200886 write_file((tmpdir, fname), 'xxx')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400887 file1 = os.path.join(tmpdir, fname)
888 tmpdir2 = self.mkdtemp()
889 method(file1, tmpdir2)
890 file2 = os.path.join(tmpdir2, fname)
891 return (file1, file2)
892
893 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
894 def test_copy(self):
895 # Ensure that the copied file exists and has the same mode bits.
896 file1, file2 = self._copy_file(shutil.copy)
897 self.assertTrue(os.path.exists(file2))
898 self.assertEqual(os.stat(file1).st_mode, os.stat(file2).st_mode)
899
900 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
Senthil Kumaran0c2dba52011-07-03 18:21:38 -0700901 @unittest.skipUnless(hasattr(os, 'utime'), 'requires os.utime')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400902 def test_copy2(self):
903 # Ensure that the copied file exists and has the same mode and
904 # modification time bits.
905 file1, file2 = self._copy_file(shutil.copy2)
906 self.assertTrue(os.path.exists(file2))
907 file1_stat = os.stat(file1)
908 file2_stat = os.stat(file2)
909 self.assertEqual(file1_stat.st_mode, file2_stat.st_mode)
910 for attr in 'st_atime', 'st_mtime':
911 # The modification times may be truncated in the new file.
912 self.assertLessEqual(getattr(file1_stat, attr),
913 getattr(file2_stat, attr) + 1)
914 if hasattr(os, 'chflags') and hasattr(file1_stat, 'st_flags'):
915 self.assertEqual(getattr(file1_stat, 'st_flags'),
916 getattr(file2_stat, 'st_flags'))
917
Ezio Melotti975077a2011-05-19 22:03:22 +0300918 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000919 def test_make_tarball(self):
920 # creating something to tar
921 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200922 write_file((tmpdir, 'file1'), 'xxx')
923 write_file((tmpdir, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000924 os.mkdir(os.path.join(tmpdir, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200925 write_file((tmpdir, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000926
927 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400928 # force shutil to create the directory
929 os.rmdir(tmpdir2)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000930 unittest.skipUnless(splitdrive(tmpdir)[0] == splitdrive(tmpdir2)[0],
931 "source and target should be on same drive")
932
933 base_name = os.path.join(tmpdir2, 'archive')
934
935 # working with relative paths to avoid tar warnings
936 old_dir = os.getcwd()
937 os.chdir(tmpdir)
938 try:
939 _make_tarball(splitdrive(base_name)[1], '.')
940 finally:
941 os.chdir(old_dir)
942
943 # check if the compressed tarball was created
944 tarball = base_name + '.tar.gz'
945 self.assertTrue(os.path.exists(tarball))
946
947 # trying an uncompressed one
948 base_name = os.path.join(tmpdir2, 'archive')
949 old_dir = os.getcwd()
950 os.chdir(tmpdir)
951 try:
952 _make_tarball(splitdrive(base_name)[1], '.', compress=None)
953 finally:
954 os.chdir(old_dir)
955 tarball = base_name + '.tar'
956 self.assertTrue(os.path.exists(tarball))
957
958 def _tarinfo(self, path):
959 tar = tarfile.open(path)
960 try:
961 names = tar.getnames()
962 names.sort()
963 return tuple(names)
964 finally:
965 tar.close()
966
967 def _create_files(self):
968 # creating something to tar
969 tmpdir = self.mkdtemp()
970 dist = os.path.join(tmpdir, 'dist')
971 os.mkdir(dist)
Éric Araujoa7e33a12011-08-12 19:51:35 +0200972 write_file((dist, 'file1'), 'xxx')
973 write_file((dist, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000974 os.mkdir(os.path.join(dist, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200975 write_file((dist, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000976 os.mkdir(os.path.join(dist, 'sub2'))
977 tmpdir2 = self.mkdtemp()
978 base_name = os.path.join(tmpdir2, 'archive')
979 return tmpdir, tmpdir2, base_name
980
Ezio Melotti975077a2011-05-19 22:03:22 +0300981 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000982 @unittest.skipUnless(find_executable('tar') and find_executable('gzip'),
983 'Need the tar command to run')
984 def test_tarfile_vs_tar(self):
985 tmpdir, tmpdir2, base_name = self._create_files()
986 old_dir = os.getcwd()
987 os.chdir(tmpdir)
988 try:
989 _make_tarball(base_name, 'dist')
990 finally:
991 os.chdir(old_dir)
992
993 # check if the compressed tarball was created
994 tarball = base_name + '.tar.gz'
995 self.assertTrue(os.path.exists(tarball))
996
997 # now create another tarball using `tar`
998 tarball2 = os.path.join(tmpdir, 'archive2.tar.gz')
999 tar_cmd = ['tar', '-cf', 'archive2.tar', 'dist']
1000 gzip_cmd = ['gzip', '-f9', 'archive2.tar']
1001 old_dir = os.getcwd()
1002 os.chdir(tmpdir)
1003 try:
1004 with captured_stdout() as s:
1005 spawn(tar_cmd)
1006 spawn(gzip_cmd)
1007 finally:
1008 os.chdir(old_dir)
1009
1010 self.assertTrue(os.path.exists(tarball2))
1011 # let's compare both tarballs
Ezio Melottib3aedd42010-11-20 19:04:17 +00001012 self.assertEqual(self._tarinfo(tarball), self._tarinfo(tarball2))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001013
1014 # trying an uncompressed one
1015 base_name = os.path.join(tmpdir2, 'archive')
1016 old_dir = os.getcwd()
1017 os.chdir(tmpdir)
1018 try:
1019 _make_tarball(base_name, 'dist', compress=None)
1020 finally:
1021 os.chdir(old_dir)
1022 tarball = base_name + '.tar'
1023 self.assertTrue(os.path.exists(tarball))
1024
1025 # now for a dry_run
1026 base_name = os.path.join(tmpdir2, 'archive')
1027 old_dir = os.getcwd()
1028 os.chdir(tmpdir)
1029 try:
1030 _make_tarball(base_name, 'dist', compress=None, dry_run=True)
1031 finally:
1032 os.chdir(old_dir)
1033 tarball = base_name + '.tar'
1034 self.assertTrue(os.path.exists(tarball))
1035
Ezio Melotti975077a2011-05-19 22:03:22 +03001036 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001037 @unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run')
1038 def test_make_zipfile(self):
1039 # creating something to tar
1040 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +02001041 write_file((tmpdir, 'file1'), 'xxx')
1042 write_file((tmpdir, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +00001043
1044 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001045 # force shutil to create the directory
1046 os.rmdir(tmpdir2)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001047 base_name = os.path.join(tmpdir2, 'archive')
1048 _make_zipfile(base_name, tmpdir)
1049
1050 # check if the compressed tarball was created
1051 tarball = base_name + '.zip'
Éric Araujo1c505492010-11-06 02:12:51 +00001052 self.assertTrue(os.path.exists(tarball))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001053
1054
1055 def test_make_archive(self):
1056 tmpdir = self.mkdtemp()
1057 base_name = os.path.join(tmpdir, 'archive')
1058 self.assertRaises(ValueError, make_archive, base_name, 'xxx')
1059
Ezio Melotti975077a2011-05-19 22:03:22 +03001060 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001061 def test_make_archive_owner_group(self):
1062 # testing make_archive with owner and group, with various combinations
1063 # this works even if there's not gid/uid support
1064 if UID_GID_SUPPORT:
1065 group = grp.getgrgid(0)[0]
1066 owner = pwd.getpwuid(0)[0]
1067 else:
1068 group = owner = 'root'
1069
1070 base_dir, root_dir, base_name = self._create_files()
1071 base_name = os.path.join(self.mkdtemp() , 'archive')
1072 res = make_archive(base_name, 'zip', root_dir, base_dir, owner=owner,
1073 group=group)
1074 self.assertTrue(os.path.exists(res))
1075
1076 res = make_archive(base_name, 'zip', root_dir, base_dir)
1077 self.assertTrue(os.path.exists(res))
1078
1079 res = make_archive(base_name, 'tar', root_dir, base_dir,
1080 owner=owner, group=group)
1081 self.assertTrue(os.path.exists(res))
1082
1083 res = make_archive(base_name, 'tar', root_dir, base_dir,
1084 owner='kjhkjhkjg', group='oihohoh')
1085 self.assertTrue(os.path.exists(res))
1086
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001087
Ezio Melotti975077a2011-05-19 22:03:22 +03001088 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001089 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1090 def test_tarfile_root_owner(self):
1091 tmpdir, tmpdir2, base_name = self._create_files()
1092 old_dir = os.getcwd()
1093 os.chdir(tmpdir)
1094 group = grp.getgrgid(0)[0]
1095 owner = pwd.getpwuid(0)[0]
1096 try:
1097 archive_name = _make_tarball(base_name, 'dist', compress=None,
1098 owner=owner, group=group)
1099 finally:
1100 os.chdir(old_dir)
1101
1102 # check if the compressed tarball was created
1103 self.assertTrue(os.path.exists(archive_name))
1104
1105 # now checks the rights
1106 archive = tarfile.open(archive_name)
1107 try:
1108 for member in archive.getmembers():
Ezio Melottib3aedd42010-11-20 19:04:17 +00001109 self.assertEqual(member.uid, 0)
1110 self.assertEqual(member.gid, 0)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001111 finally:
1112 archive.close()
1113
1114 def test_make_archive_cwd(self):
1115 current_dir = os.getcwd()
1116 def _breaks(*args, **kw):
1117 raise RuntimeError()
1118
1119 register_archive_format('xxx', _breaks, [], 'xxx file')
1120 try:
1121 try:
1122 make_archive('xxx', 'xxx', root_dir=self.mkdtemp())
1123 except Exception:
1124 pass
Ezio Melottib3aedd42010-11-20 19:04:17 +00001125 self.assertEqual(os.getcwd(), current_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001126 finally:
1127 unregister_archive_format('xxx')
1128
1129 def test_register_archive_format(self):
1130
1131 self.assertRaises(TypeError, register_archive_format, 'xxx', 1)
1132 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1133 1)
1134 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1135 [(1, 2), (1, 2, 3)])
1136
1137 register_archive_format('xxx', lambda: x, [(1, 2)], 'xxx file')
1138 formats = [name for name, params in get_archive_formats()]
1139 self.assertIn('xxx', formats)
1140
1141 unregister_archive_format('xxx')
1142 formats = [name for name, params in get_archive_formats()]
1143 self.assertNotIn('xxx', formats)
1144
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001145 def _compare_dirs(self, dir1, dir2):
1146 # check that dir1 and dir2 are equivalent,
1147 # return the diff
1148 diff = []
1149 for root, dirs, files in os.walk(dir1):
1150 for file_ in files:
1151 path = os.path.join(root, file_)
1152 target_path = os.path.join(dir2, os.path.split(path)[-1])
1153 if not os.path.exists(target_path):
1154 diff.append(file_)
1155 return diff
1156
Ezio Melotti975077a2011-05-19 22:03:22 +03001157 @requires_zlib
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001158 def test_unpack_archive(self):
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001159 formats = ['tar', 'gztar', 'zip']
1160 if BZ2_SUPPORTED:
1161 formats.append('bztar')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001162
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001163 for format in formats:
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001164 tmpdir = self.mkdtemp()
1165 base_dir, root_dir, base_name = self._create_files()
1166 tmpdir2 = self.mkdtemp()
1167 filename = make_archive(base_name, format, root_dir, base_dir)
1168
1169 # let's try to unpack it now
1170 unpack_archive(filename, tmpdir2)
1171 diff = self._compare_dirs(tmpdir, tmpdir2)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001172 self.assertEqual(diff, [])
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001173
Nick Coghlanabf202d2011-03-16 13:52:20 -04001174 # and again, this time with the format specified
1175 tmpdir3 = self.mkdtemp()
1176 unpack_archive(filename, tmpdir3, format=format)
1177 diff = self._compare_dirs(tmpdir, tmpdir3)
1178 self.assertEqual(diff, [])
1179 self.assertRaises(shutil.ReadError, unpack_archive, TESTFN)
1180 self.assertRaises(ValueError, unpack_archive, TESTFN, format='xxx')
1181
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001182 def test_unpack_registery(self):
1183
1184 formats = get_unpack_formats()
1185
1186 def _boo(filename, extract_dir, extra):
Ezio Melottib3aedd42010-11-20 19:04:17 +00001187 self.assertEqual(extra, 1)
1188 self.assertEqual(filename, 'stuff.boo')
1189 self.assertEqual(extract_dir, 'xx')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001190
1191 register_unpack_format('Boo', ['.boo', '.b2'], _boo, [('extra', 1)])
1192 unpack_archive('stuff.boo', 'xx')
1193
1194 # trying to register a .boo unpacker again
1195 self.assertRaises(RegistryError, register_unpack_format, 'Boo2',
1196 ['.boo'], _boo)
1197
1198 # should work now
1199 unregister_unpack_format('Boo')
1200 register_unpack_format('Boo2', ['.boo'], _boo)
1201 self.assertIn(('Boo2', ['.boo'], ''), get_unpack_formats())
1202 self.assertNotIn(('Boo', ['.boo'], ''), get_unpack_formats())
1203
1204 # let's leave a clean state
1205 unregister_unpack_format('Boo2')
Ezio Melottib3aedd42010-11-20 19:04:17 +00001206 self.assertEqual(get_unpack_formats(), formats)
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001207
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001208 @unittest.skipUnless(hasattr(shutil, 'disk_usage'),
1209 "disk_usage not available on this platform")
1210 def test_disk_usage(self):
1211 usage = shutil.disk_usage(os.getcwd())
Éric Araujo2ee61882011-07-02 16:45:45 +02001212 self.assertGreater(usage.total, 0)
1213 self.assertGreater(usage.used, 0)
1214 self.assertGreaterEqual(usage.free, 0)
1215 self.assertGreaterEqual(usage.total, usage.used)
1216 self.assertGreater(usage.total, usage.free)
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001217
Sandro Tosid902a142011-08-22 23:28:27 +02001218 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1219 @unittest.skipUnless(hasattr(os, 'chown'), 'requires os.chown')
1220 def test_chown(self):
1221
1222 # cleaned-up automatically by TestShutil.tearDown method
1223 dirname = self.mkdtemp()
1224 filename = tempfile.mktemp(dir=dirname)
1225 write_file(filename, 'testing chown function')
1226
1227 with self.assertRaises(ValueError):
1228 shutil.chown(filename)
1229
1230 with self.assertRaises(LookupError):
1231 shutil.chown(filename, user='non-exising username')
1232
1233 with self.assertRaises(LookupError):
1234 shutil.chown(filename, group='non-exising groupname')
1235
1236 with self.assertRaises(TypeError):
1237 shutil.chown(filename, b'spam')
1238
1239 with self.assertRaises(TypeError):
1240 shutil.chown(filename, 3.14)
1241
1242 uid = os.getuid()
1243 gid = os.getgid()
1244
1245 def check_chown(path, uid=None, gid=None):
1246 s = os.stat(filename)
1247 if uid is not None:
1248 self.assertEqual(uid, s.st_uid)
1249 if gid is not None:
1250 self.assertEqual(gid, s.st_gid)
1251
1252 shutil.chown(filename, uid, gid)
1253 check_chown(filename, uid, gid)
1254 shutil.chown(filename, uid)
1255 check_chown(filename, uid)
1256 shutil.chown(filename, user=uid)
1257 check_chown(filename, uid)
1258 shutil.chown(filename, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001259 check_chown(filename, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001260
1261 shutil.chown(dirname, uid, gid)
1262 check_chown(dirname, uid, gid)
1263 shutil.chown(dirname, uid)
1264 check_chown(dirname, uid)
1265 shutil.chown(dirname, user=uid)
1266 check_chown(dirname, uid)
1267 shutil.chown(dirname, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001268 check_chown(dirname, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001269
1270 user = pwd.getpwuid(uid)[0]
1271 group = grp.getgrgid(gid)[0]
1272 shutil.chown(filename, user, group)
1273 check_chown(filename, uid, gid)
1274 shutil.chown(dirname, user, group)
1275 check_chown(dirname, uid, gid)
1276
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001277 def test_copy_return_value(self):
1278 # copy and copy2 both return their destination path.
1279 for fn in (shutil.copy, shutil.copy2):
1280 src_dir = self.mkdtemp()
1281 dst_dir = self.mkdtemp()
1282 src = os.path.join(src_dir, 'foo')
1283 write_file(src, 'foo')
1284 rv = fn(src, dst_dir)
1285 self.assertEqual(rv, os.path.join(dst_dir, 'foo'))
1286 rv = fn(src, os.path.join(dst_dir, 'bar'))
1287 self.assertEqual(rv, os.path.join(dst_dir, 'bar'))
1288
1289 def test_copyfile_return_value(self):
1290 # copytree returns its destination path.
1291 src_dir = self.mkdtemp()
1292 dst_dir = self.mkdtemp()
1293 dst_file = os.path.join(dst_dir, 'bar')
1294 src_file = os.path.join(src_dir, 'foo')
1295 write_file(src_file, 'foo')
1296 rv = shutil.copyfile(src_file, dst_file)
1297 self.assertTrue(os.path.exists(rv))
1298 self.assertEqual(read_file(src_file), read_file(dst_file))
1299
Hynek Schlawack48653762012-10-07 12:49:58 +02001300 def test_copyfile_same_file(self):
1301 # copyfile() should raise SameFileError if the source and destination
1302 # are the same.
1303 src_dir = self.mkdtemp()
1304 src_file = os.path.join(src_dir, 'foo')
1305 write_file(src_file, 'foo')
1306 self.assertRaises(SameFileError, shutil.copyfile, src_file, src_file)
Hynek Schlawack27ddb572012-10-28 13:59:27 +01001307 # But Error should work too, to stay backward compatible.
1308 self.assertRaises(Error, shutil.copyfile, src_file, src_file)
Hynek Schlawack48653762012-10-07 12:49:58 +02001309
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001310 def test_copytree_return_value(self):
1311 # copytree returns its destination path.
1312 src_dir = self.mkdtemp()
1313 dst_dir = src_dir + "dest"
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001314 self.addCleanup(shutil.rmtree, dst_dir, True)
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001315 src = os.path.join(src_dir, 'foo')
1316 write_file(src, 'foo')
1317 rv = shutil.copytree(src_dir, dst_dir)
1318 self.assertEqual(['foo'], os.listdir(rv))
1319
Christian Heimes9bd667a2008-01-20 15:14:11 +00001320
Brian Curtinc57a3452012-06-22 16:00:30 -05001321class TestWhich(unittest.TestCase):
1322
1323 def setUp(self):
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001324 self.temp_dir = tempfile.mkdtemp(prefix="Tmp")
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001325 self.addCleanup(shutil.rmtree, self.temp_dir, True)
Brian Curtinc57a3452012-06-22 16:00:30 -05001326 # Give the temp_file an ".exe" suffix for all.
1327 # It's needed on Windows and not harmful on other platforms.
1328 self.temp_file = tempfile.NamedTemporaryFile(dir=self.temp_dir,
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001329 prefix="Tmp",
1330 suffix=".Exe")
Brian Curtinc57a3452012-06-22 16:00:30 -05001331 os.chmod(self.temp_file.name, stat.S_IXUSR)
1332 self.addCleanup(self.temp_file.close)
1333 self.dir, self.file = os.path.split(self.temp_file.name)
1334
1335 def test_basic(self):
1336 # Given an EXE in a directory, it should be returned.
1337 rv = shutil.which(self.file, path=self.dir)
1338 self.assertEqual(rv, self.temp_file.name)
1339
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001340 def test_absolute_cmd(self):
Brian Curtinc57a3452012-06-22 16:00:30 -05001341 # When given the fully qualified path to an executable that exists,
1342 # it should be returned.
1343 rv = shutil.which(self.temp_file.name, path=self.temp_dir)
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001344 self.assertEqual(rv, self.temp_file.name)
1345
1346 def test_relative_cmd(self):
1347 # When given the relative path with a directory part to an executable
1348 # that exists, it should be returned.
1349 base_dir, tail_dir = os.path.split(self.dir)
1350 relpath = os.path.join(tail_dir, self.file)
Nick Coghlan55175962013-07-28 22:11:50 +10001351 with support.change_cwd(path=base_dir):
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001352 rv = shutil.which(relpath, path=self.temp_dir)
1353 self.assertEqual(rv, relpath)
1354 # But it shouldn't be searched in PATH directories (issue #16957).
Nick Coghlan55175962013-07-28 22:11:50 +10001355 with support.change_cwd(path=self.dir):
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001356 rv = shutil.which(relpath, path=base_dir)
1357 self.assertIsNone(rv)
1358
1359 def test_cwd(self):
1360 # Issue #16957
1361 base_dir = os.path.dirname(self.dir)
Nick Coghlan55175962013-07-28 22:11:50 +10001362 with support.change_cwd(path=self.dir):
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001363 rv = shutil.which(self.file, path=base_dir)
1364 if sys.platform == "win32":
1365 # Windows: current directory implicitly on PATH
1366 self.assertEqual(rv, os.path.join(os.curdir, self.file))
1367 else:
1368 # Other platforms: shouldn't match in the current directory.
1369 self.assertIsNone(rv)
Brian Curtinc57a3452012-06-22 16:00:30 -05001370
Serhiy Storchaka12516e22013-05-28 15:50:15 +03001371 @unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0,
1372 'non-root user required')
Brian Curtinc57a3452012-06-22 16:00:30 -05001373 def test_non_matching_mode(self):
1374 # Set the file read-only and ask for writeable files.
1375 os.chmod(self.temp_file.name, stat.S_IREAD)
Serhiy Storchaka12516e22013-05-28 15:50:15 +03001376 if os.access(self.temp_file.name, os.W_OK):
1377 self.skipTest("can't set the file read-only")
Brian Curtinc57a3452012-06-22 16:00:30 -05001378 rv = shutil.which(self.file, path=self.dir, mode=os.W_OK)
1379 self.assertIsNone(rv)
1380
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001381 def test_relative_path(self):
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001382 base_dir, tail_dir = os.path.split(self.dir)
Nick Coghlan55175962013-07-28 22:11:50 +10001383 with support.change_cwd(path=base_dir):
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001384 rv = shutil.which(self.file, path=tail_dir)
1385 self.assertEqual(rv, os.path.join(tail_dir, self.file))
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001386
Brian Curtinc57a3452012-06-22 16:00:30 -05001387 def test_nonexistent_file(self):
1388 # Return None when no matching executable file is found on the path.
1389 rv = shutil.which("foo.exe", path=self.dir)
1390 self.assertIsNone(rv)
1391
1392 @unittest.skipUnless(sys.platform == "win32",
1393 "pathext check is Windows-only")
1394 def test_pathext_checking(self):
1395 # Ask for the file without the ".exe" extension, then ensure that
1396 # it gets found properly with the extension.
Serhiy Storchakad70127a2013-01-24 20:03:49 +02001397 rv = shutil.which(self.file[:-4], path=self.dir)
Serhiy Storchaka80c88f42013-01-22 10:31:36 +02001398 self.assertEqual(rv, self.temp_file.name[:-4] + ".EXE")
Brian Curtinc57a3452012-06-22 16:00:30 -05001399
Barry Warsaw618738b2013-04-16 11:05:03 -04001400 def test_environ_path(self):
1401 with support.EnvironmentVarGuard() as env:
Victor Stinner1d006a22013-12-16 23:39:40 +01001402 env['PATH'] = self.dir
Barry Warsaw618738b2013-04-16 11:05:03 -04001403 rv = shutil.which(self.file)
1404 self.assertEqual(rv, self.temp_file.name)
1405
1406 def test_empty_path(self):
1407 base_dir = os.path.dirname(self.dir)
Nick Coghlan55175962013-07-28 22:11:50 +10001408 with support.change_cwd(path=self.dir), \
Barry Warsaw618738b2013-04-16 11:05:03 -04001409 support.EnvironmentVarGuard() as env:
Victor Stinner1d006a22013-12-16 23:39:40 +01001410 env['PATH'] = self.dir
Barry Warsaw618738b2013-04-16 11:05:03 -04001411 rv = shutil.which(self.file, path='')
1412 self.assertIsNone(rv)
1413
1414 def test_empty_path_no_PATH(self):
1415 with support.EnvironmentVarGuard() as env:
1416 env.pop('PATH', None)
1417 rv = shutil.which(self.file)
1418 self.assertIsNone(rv)
1419
Brian Curtinc57a3452012-06-22 16:00:30 -05001420
Christian Heimesada8c3b2008-03-18 18:26:33 +00001421class TestMove(unittest.TestCase):
1422
1423 def setUp(self):
1424 filename = "foo"
1425 self.src_dir = tempfile.mkdtemp()
1426 self.dst_dir = tempfile.mkdtemp()
1427 self.src_file = os.path.join(self.src_dir, filename)
1428 self.dst_file = os.path.join(self.dst_dir, filename)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001429 with open(self.src_file, "wb") as f:
1430 f.write(b"spam")
1431
1432 def tearDown(self):
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001433 for d in (self.src_dir, self.dst_dir):
Christian Heimesada8c3b2008-03-18 18:26:33 +00001434 try:
1435 if d:
1436 shutil.rmtree(d)
1437 except:
1438 pass
1439
1440 def _check_move_file(self, src, dst, real_dst):
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001441 with open(src, "rb") as f:
1442 contents = f.read()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001443 shutil.move(src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001444 with open(real_dst, "rb") as f:
1445 self.assertEqual(contents, f.read())
Christian Heimesada8c3b2008-03-18 18:26:33 +00001446 self.assertFalse(os.path.exists(src))
1447
1448 def _check_move_dir(self, src, dst, real_dst):
1449 contents = sorted(os.listdir(src))
1450 shutil.move(src, dst)
1451 self.assertEqual(contents, sorted(os.listdir(real_dst)))
1452 self.assertFalse(os.path.exists(src))
1453
1454 def test_move_file(self):
1455 # Move a file to another location on the same filesystem.
1456 self._check_move_file(self.src_file, self.dst_file, self.dst_file)
1457
1458 def test_move_file_to_dir(self):
1459 # Move a file inside an existing dir on the same filesystem.
1460 self._check_move_file(self.src_file, self.dst_dir, self.dst_file)
1461
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001462 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001463 def test_move_file_other_fs(self):
1464 # Move a file to an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001465 self.test_move_file()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001466
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001467 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001468 def test_move_file_to_dir_other_fs(self):
1469 # Move a file to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001470 self.test_move_file_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001471
1472 def test_move_dir(self):
1473 # Move a dir to another location on the same filesystem.
1474 dst_dir = tempfile.mktemp()
1475 try:
1476 self._check_move_dir(self.src_dir, dst_dir, dst_dir)
1477 finally:
1478 try:
1479 shutil.rmtree(dst_dir)
1480 except:
1481 pass
1482
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001483 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001484 def test_move_dir_other_fs(self):
1485 # Move a dir to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001486 self.test_move_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001487
1488 def test_move_dir_to_dir(self):
1489 # Move a dir inside an existing dir on the same filesystem.
1490 self._check_move_dir(self.src_dir, self.dst_dir,
1491 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1492
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001493 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001494 def test_move_dir_to_dir_other_fs(self):
1495 # Move a dir inside an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001496 self.test_move_dir_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001497
Serhiy Storchaka3a308b92014-02-11 10:30:59 +02001498 def test_move_dir_sep_to_dir(self):
1499 self._check_move_dir(self.src_dir + os.path.sep, self.dst_dir,
1500 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1501
1502 @unittest.skipUnless(os.path.altsep, 'requires os.path.altsep')
1503 def test_move_dir_altsep_to_dir(self):
1504 self._check_move_dir(self.src_dir + os.path.altsep, self.dst_dir,
1505 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1506
Christian Heimesada8c3b2008-03-18 18:26:33 +00001507 def test_existing_file_inside_dest_dir(self):
1508 # A file with the same name inside the destination dir already exists.
1509 with open(self.dst_file, "wb"):
1510 pass
1511 self.assertRaises(shutil.Error, shutil.move, self.src_file, self.dst_dir)
1512
1513 def test_dont_move_dir_in_itself(self):
1514 # Moving a dir inside itself raises an Error.
1515 dst = os.path.join(self.src_dir, "bar")
1516 self.assertRaises(shutil.Error, shutil.move, self.src_dir, dst)
1517
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001518 def test_destinsrc_false_negative(self):
1519 os.mkdir(TESTFN)
1520 try:
1521 for src, dst in [('srcdir', 'srcdir/dest')]:
1522 src = os.path.join(TESTFN, src)
1523 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001524 self.assertTrue(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001525 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001526 'dst (%s) is not in src (%s)' % (dst, src))
1527 finally:
1528 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001529
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001530 def test_destinsrc_false_positive(self):
1531 os.mkdir(TESTFN)
1532 try:
1533 for src, dst in [('srcdir', 'src/dest'), ('srcdir', 'srcdir.new')]:
1534 src = os.path.join(TESTFN, src)
1535 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001536 self.assertFalse(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001537 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001538 'dst (%s) is in src (%s)' % (dst, src))
1539 finally:
1540 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimes9bd667a2008-01-20 15:14:11 +00001541
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +01001542 @support.skip_unless_symlink
1543 @mock_rename
1544 def test_move_file_symlink(self):
1545 dst = os.path.join(self.src_dir, 'bar')
1546 os.symlink(self.src_file, dst)
1547 shutil.move(dst, self.dst_file)
1548 self.assertTrue(os.path.islink(self.dst_file))
1549 self.assertTrue(os.path.samefile(self.src_file, self.dst_file))
1550
1551 @support.skip_unless_symlink
1552 @mock_rename
1553 def test_move_file_symlink_to_dir(self):
1554 filename = "bar"
1555 dst = os.path.join(self.src_dir, filename)
1556 os.symlink(self.src_file, dst)
1557 shutil.move(dst, self.dst_dir)
1558 final_link = os.path.join(self.dst_dir, filename)
1559 self.assertTrue(os.path.islink(final_link))
1560 self.assertTrue(os.path.samefile(self.src_file, final_link))
1561
1562 @support.skip_unless_symlink
1563 @mock_rename
1564 def test_move_dangling_symlink(self):
1565 src = os.path.join(self.src_dir, 'baz')
1566 dst = os.path.join(self.src_dir, 'bar')
1567 os.symlink(src, dst)
1568 dst_link = os.path.join(self.dst_dir, 'quux')
1569 shutil.move(dst, dst_link)
1570 self.assertTrue(os.path.islink(dst_link))
Antoine Pitrou3f48ac92014-01-01 02:50:45 +01001571 # On Windows, os.path.realpath does not follow symlinks (issue #9949)
1572 if os.name == 'nt':
1573 self.assertEqual(os.path.realpath(src), os.readlink(dst_link))
1574 else:
1575 self.assertEqual(os.path.realpath(src), os.path.realpath(dst_link))
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +01001576
1577 @support.skip_unless_symlink
1578 @mock_rename
1579 def test_move_dir_symlink(self):
1580 src = os.path.join(self.src_dir, 'baz')
1581 dst = os.path.join(self.src_dir, 'bar')
1582 os.mkdir(src)
1583 os.symlink(src, dst)
1584 dst_link = os.path.join(self.dst_dir, 'quux')
1585 shutil.move(dst, dst_link)
1586 self.assertTrue(os.path.islink(dst_link))
1587 self.assertTrue(os.path.samefile(src, dst_link))
1588
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001589 def test_move_return_value(self):
1590 rv = shutil.move(self.src_file, self.dst_dir)
1591 self.assertEqual(rv,
1592 os.path.join(self.dst_dir, os.path.basename(self.src_file)))
1593
1594 def test_move_as_rename_return_value(self):
1595 rv = shutil.move(self.src_file, os.path.join(self.dst_dir, 'bar'))
1596 self.assertEqual(rv, os.path.join(self.dst_dir, 'bar'))
1597
Tarek Ziadé5340db32010-04-19 22:30:51 +00001598
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001599class TestCopyFile(unittest.TestCase):
1600
1601 _delete = False
1602
1603 class Faux(object):
1604 _entered = False
1605 _exited_with = None
1606 _raised = False
1607 def __init__(self, raise_in_exit=False, suppress_at_exit=True):
1608 self._raise_in_exit = raise_in_exit
1609 self._suppress_at_exit = suppress_at_exit
1610 def read(self, *args):
1611 return ''
1612 def __enter__(self):
1613 self._entered = True
1614 def __exit__(self, exc_type, exc_val, exc_tb):
1615 self._exited_with = exc_type, exc_val, exc_tb
1616 if self._raise_in_exit:
1617 self._raised = True
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001618 raise OSError("Cannot close")
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001619 return self._suppress_at_exit
1620
1621 def tearDown(self):
1622 if self._delete:
1623 del shutil.open
1624
1625 def _set_shutil_open(self, func):
1626 shutil.open = func
1627 self._delete = True
1628
1629 def test_w_source_open_fails(self):
1630 def _open(filename, mode='r'):
1631 if filename == 'srcfile':
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001632 raise OSError('Cannot open "srcfile"')
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001633 assert 0 # shouldn't reach here.
1634
1635 self._set_shutil_open(_open)
1636
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001637 self.assertRaises(OSError, shutil.copyfile, 'srcfile', 'destfile')
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001638
1639 def test_w_dest_open_fails(self):
1640
1641 srcfile = self.Faux()
1642
1643 def _open(filename, mode='r'):
1644 if filename == 'srcfile':
1645 return srcfile
1646 if filename == 'destfile':
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001647 raise OSError('Cannot open "destfile"')
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001648 assert 0 # shouldn't reach here.
1649
1650 self._set_shutil_open(_open)
1651
1652 shutil.copyfile('srcfile', 'destfile')
1653 self.assertTrue(srcfile._entered)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001654 self.assertTrue(srcfile._exited_with[0] is OSError)
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001655 self.assertEqual(srcfile._exited_with[1].args,
1656 ('Cannot open "destfile"',))
1657
1658 def test_w_dest_close_fails(self):
1659
1660 srcfile = self.Faux()
1661 destfile = self.Faux(True)
1662
1663 def _open(filename, mode='r'):
1664 if filename == 'srcfile':
1665 return srcfile
1666 if filename == 'destfile':
1667 return destfile
1668 assert 0 # shouldn't reach here.
1669
1670 self._set_shutil_open(_open)
1671
1672 shutil.copyfile('srcfile', 'destfile')
1673 self.assertTrue(srcfile._entered)
1674 self.assertTrue(destfile._entered)
1675 self.assertTrue(destfile._raised)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001676 self.assertTrue(srcfile._exited_with[0] is OSError)
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001677 self.assertEqual(srcfile._exited_with[1].args,
1678 ('Cannot close',))
1679
1680 def test_w_source_close_fails(self):
1681
1682 srcfile = self.Faux(True)
1683 destfile = self.Faux()
1684
1685 def _open(filename, mode='r'):
1686 if filename == 'srcfile':
1687 return srcfile
1688 if filename == 'destfile':
1689 return destfile
1690 assert 0 # shouldn't reach here.
1691
1692 self._set_shutil_open(_open)
1693
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001694 self.assertRaises(OSError,
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001695 shutil.copyfile, 'srcfile', 'destfile')
1696 self.assertTrue(srcfile._entered)
1697 self.assertTrue(destfile._entered)
1698 self.assertFalse(destfile._raised)
1699 self.assertTrue(srcfile._exited_with[0] is None)
1700 self.assertTrue(srcfile._raised)
1701
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001702 def test_move_dir_caseinsensitive(self):
1703 # Renames a folder to the same name
1704 # but a different case.
1705
1706 self.src_dir = tempfile.mkdtemp()
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001707 self.addCleanup(shutil.rmtree, self.src_dir, True)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001708 dst_dir = os.path.join(
1709 os.path.dirname(self.src_dir),
1710 os.path.basename(self.src_dir).upper())
1711 self.assertNotEqual(self.src_dir, dst_dir)
1712
1713 try:
1714 shutil.move(self.src_dir, dst_dir)
1715 self.assertTrue(os.path.isdir(dst_dir))
1716 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +02001717 os.rmdir(dst_dir)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001718
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001719class TermsizeTests(unittest.TestCase):
1720 def test_does_not_crash(self):
1721 """Check if get_terminal_size() returns a meaningful value.
1722
1723 There's no easy portable way to actually check the size of the
1724 terminal, so let's check if it returns something sensible instead.
1725 """
1726 size = shutil.get_terminal_size()
Antoine Pitroucfade362012-02-08 23:48:59 +01001727 self.assertGreaterEqual(size.columns, 0)
1728 self.assertGreaterEqual(size.lines, 0)
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001729
1730 def test_os_environ_first(self):
1731 "Check if environment variables have precedence"
1732
1733 with support.EnvironmentVarGuard() as env:
1734 env['COLUMNS'] = '777'
1735 size = shutil.get_terminal_size()
1736 self.assertEqual(size.columns, 777)
1737
1738 with support.EnvironmentVarGuard() as env:
1739 env['LINES'] = '888'
1740 size = shutil.get_terminal_size()
1741 self.assertEqual(size.lines, 888)
1742
1743 @unittest.skipUnless(os.isatty(sys.__stdout__.fileno()), "not on tty")
1744 def test_stty_match(self):
1745 """Check if stty returns the same results ignoring env
1746
1747 This test will fail if stdin and stdout are connected to
1748 different terminals with different sizes. Nevertheless, such
1749 situations should be pretty rare.
1750 """
1751 try:
1752 size = subprocess.check_output(['stty', 'size']).decode().split()
1753 except (FileNotFoundError, subprocess.CalledProcessError):
1754 self.skipTest("stty invocation failed")
1755 expected = (int(size[1]), int(size[0])) # reversed order
1756
1757 with support.EnvironmentVarGuard() as env:
1758 del env['LINES']
1759 del env['COLUMNS']
1760 actual = shutil.get_terminal_size()
1761
1762 self.assertEqual(expected, actual)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001763
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001764
Berker Peksag8083cd62014-11-01 11:04:06 +02001765class PublicAPITests(unittest.TestCase):
1766 """Ensures that the correct values are exposed in the public API."""
1767
1768 def test_module_all_attribute(self):
1769 self.assertTrue(hasattr(shutil, '__all__'))
1770 target_api = ['copyfileobj', 'copyfile', 'copymode', 'copystat',
1771 'copy', 'copy2', 'copytree', 'move', 'rmtree', 'Error',
1772 'SpecialFileError', 'ExecError', 'make_archive',
1773 'get_archive_formats', 'register_archive_format',
1774 'unregister_archive_format', 'get_unpack_formats',
1775 'register_unpack_format', 'unregister_unpack_format',
1776 'unpack_archive', 'ignore_patterns', 'chown', 'which',
1777 'get_terminal_size', 'SameFileError']
1778 if hasattr(os, 'statvfs') or os.name == 'nt':
1779 target_api.append('disk_usage')
1780 self.assertEqual(set(shutil.__all__), set(target_api))
1781
1782
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001783if __name__ == '__main__':
Brett Cannon3e9a9ae2013-06-12 21:25:59 -04001784 unittest.main()