blob: a41d88b0df42eeac469fe2fd7cdbb916cbb1b726 [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
Serhiy Storchaka11213772014-08-06 18:50:19 +030036try:
37 import lzma
38 LZMA_SUPPORTED = True
39except ImportError:
40 LZMA_SUPPORTED = False
41
Antoine Pitrou7fff0962009-05-01 21:09:44 +000042TESTFN2 = TESTFN + "2"
Barry Warsaw7fc2cca2003-01-24 17:34:13 +000043
Tarek Ziadé396fad72010-02-23 05:30:31 +000044try:
45 import grp
46 import pwd
47 UID_GID_SUPPORT = True
48except ImportError:
49 UID_GID_SUPPORT = False
50
51try:
Tarek Ziadé396fad72010-02-23 05:30:31 +000052 import zipfile
53 ZIP_SUPPORT = True
54except ImportError:
55 ZIP_SUPPORT = find_executable('zip')
56
Nick Coghlan8ed3cf32011-03-16 14:05:35 -040057def _fake_rename(*args, **kwargs):
58 # Pretend the destination path is on a different filesystem.
Antoine Pitrouc041ab62012-01-02 19:18:02 +010059 raise OSError(getattr(errno, 'EXDEV', 18), "Invalid cross-device link")
Nick Coghlan8ed3cf32011-03-16 14:05:35 -040060
61def mock_rename(func):
62 @functools.wraps(func)
63 def wrap(*args, **kwargs):
64 try:
65 builtin_rename = os.rename
66 os.rename = _fake_rename
67 return func(*args, **kwargs)
68 finally:
69 os.rename = builtin_rename
70 return wrap
71
Éric Araujoa7e33a12011-08-12 19:51:35 +020072def write_file(path, content, binary=False):
73 """Write *content* to a file located at *path*.
74
75 If *path* is a tuple instead of a string, os.path.join will be used to
76 make a path. If *binary* is true, the file will be opened in binary
77 mode.
78 """
79 if isinstance(path, tuple):
80 path = os.path.join(*path)
81 with open(path, 'wb' if binary else 'w') as fp:
82 fp.write(content)
83
84def read_file(path, binary=False):
85 """Return contents from a file located at *path*.
86
87 If *path* is a tuple instead of a string, os.path.join will be used to
88 make a path. If *binary* is true, the file will be opened in binary
89 mode.
90 """
91 if isinstance(path, tuple):
92 path = os.path.join(*path)
93 with open(path, 'rb' if binary else 'r') as fp:
94 return fp.read()
95
96
Barry Warsaw7fc2cca2003-01-24 17:34:13 +000097class TestShutil(unittest.TestCase):
Tarek Ziadé396fad72010-02-23 05:30:31 +000098
99 def setUp(self):
100 super(TestShutil, self).setUp()
101 self.tempdirs = []
102
103 def tearDown(self):
104 super(TestShutil, self).tearDown()
105 while self.tempdirs:
106 d = self.tempdirs.pop()
107 shutil.rmtree(d, os.name in ('nt', 'cygwin'))
108
Tarek Ziadé396fad72010-02-23 05:30:31 +0000109
110 def mkdtemp(self):
111 """Create a temporary directory that will be cleaned up.
112
113 Returns the path of the directory.
114 """
115 d = tempfile.mkdtemp()
116 self.tempdirs.append(d)
117 return d
Tarek Ziadé5340db32010-04-19 22:30:51 +0000118
Hynek Schlawack3b527782012-06-25 13:27:31 +0200119 def test_rmtree_works_on_bytes(self):
120 tmp = self.mkdtemp()
121 victim = os.path.join(tmp, 'killme')
122 os.mkdir(victim)
123 write_file(os.path.join(victim, 'somefile'), 'foo')
124 victim = os.fsencode(victim)
125 self.assertIsInstance(victim, bytes)
Serhiy Storchaka41ad77c2014-08-07 19:38:37 +0300126 win = (os.name == 'nt')
127 with self.assertWarns(DeprecationWarning) if win else ExitStack():
128 shutil.rmtree(victim)
Hynek Schlawack3b527782012-06-25 13:27:31 +0200129
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200130 @support.skip_unless_symlink
131 def test_rmtree_fails_on_symlink(self):
132 tmp = self.mkdtemp()
133 dir_ = os.path.join(tmp, 'dir')
134 os.mkdir(dir_)
135 link = os.path.join(tmp, 'link')
136 os.symlink(dir_, link)
137 self.assertRaises(OSError, shutil.rmtree, link)
138 self.assertTrue(os.path.exists(dir_))
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100139 self.assertTrue(os.path.lexists(link))
140 errors = []
141 def onerror(*args):
142 errors.append(args)
143 shutil.rmtree(link, onerror=onerror)
144 self.assertEqual(len(errors), 1)
145 self.assertIs(errors[0][0], os.path.islink)
146 self.assertEqual(errors[0][1], link)
147 self.assertIsInstance(errors[0][2][1], OSError)
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200148
149 @support.skip_unless_symlink
150 def test_rmtree_works_on_symlinks(self):
151 tmp = self.mkdtemp()
152 dir1 = os.path.join(tmp, 'dir1')
153 dir2 = os.path.join(dir1, 'dir2')
154 dir3 = os.path.join(tmp, 'dir3')
155 for d in dir1, dir2, dir3:
156 os.mkdir(d)
157 file1 = os.path.join(tmp, 'file1')
158 write_file(file1, 'foo')
159 link1 = os.path.join(dir1, 'link1')
160 os.symlink(dir2, link1)
161 link2 = os.path.join(dir1, 'link2')
162 os.symlink(dir3, link2)
163 link3 = os.path.join(dir1, 'link3')
164 os.symlink(file1, link3)
165 # make sure symlinks are removed but not followed
166 shutil.rmtree(dir1)
167 self.assertFalse(os.path.exists(dir1))
168 self.assertTrue(os.path.exists(dir3))
169 self.assertTrue(os.path.exists(file1))
170
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000171 def test_rmtree_errors(self):
172 # filename is guaranteed not to exist
173 filename = tempfile.mktemp()
Hynek Schlawackb5501102012-12-10 09:11:25 +0100174 self.assertRaises(FileNotFoundError, shutil.rmtree, filename)
175 # test that ignore_errors option is honored
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100176 shutil.rmtree(filename, ignore_errors=True)
177
178 # existing file
179 tmpdir = self.mkdtemp()
Hynek Schlawackb5501102012-12-10 09:11:25 +0100180 write_file((tmpdir, "tstfile"), "")
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100181 filename = os.path.join(tmpdir, "tstfile")
Hynek Schlawackb5501102012-12-10 09:11:25 +0100182 with self.assertRaises(NotADirectoryError) as cm:
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100183 shutil.rmtree(filename)
Hynek Schlawack87f9b462012-12-10 16:29:57 +0100184 # The reason for this rather odd construct is that Windows sprinkles
185 # a \*.* at the end of file names. But only sometimes on some buildbots
186 possible_args = [filename, os.path.join(filename, '*.*')]
187 self.assertIn(cm.exception.filename, possible_args)
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100188 self.assertTrue(os.path.exists(filename))
Hynek Schlawackb5501102012-12-10 09:11:25 +0100189 # test that ignore_errors option is honored
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100190 shutil.rmtree(filename, ignore_errors=True)
191 self.assertTrue(os.path.exists(filename))
192 errors = []
193 def onerror(*args):
194 errors.append(args)
195 shutil.rmtree(filename, onerror=onerror)
196 self.assertEqual(len(errors), 2)
197 self.assertIs(errors[0][0], os.listdir)
198 self.assertEqual(errors[0][1], filename)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100199 self.assertIsInstance(errors[0][2][1], NotADirectoryError)
Hynek Schlawack87f9b462012-12-10 16:29:57 +0100200 self.assertIn(errors[0][2][1].filename, possible_args)
Hynek Schlawackd16eacb2012-12-10 09:00:09 +0100201 self.assertIs(errors[1][0], os.rmdir)
202 self.assertEqual(errors[1][1], filename)
Hynek Schlawackb5501102012-12-10 09:11:25 +0100203 self.assertIsInstance(errors[1][2][1], NotADirectoryError)
Hynek Schlawack87f9b462012-12-10 16:29:57 +0100204 self.assertIn(errors[1][2][1].filename, possible_args)
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000205
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000206
Serhiy Storchaka43767632013-11-03 21:31:38 +0200207 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod()')
208 @unittest.skipIf(sys.platform[:6] == 'cygwin',
209 "This test can't be run on Cygwin (issue #1071513).")
210 @unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0,
211 "This test can't be run reliably as root (issue #1076467).")
212 def test_on_error(self):
213 self.errorState = 0
214 os.mkdir(TESTFN)
215 self.addCleanup(shutil.rmtree, TESTFN)
Antoine Pitrou2f8a75c2012-06-23 21:28:15 +0200216
Serhiy Storchaka43767632013-11-03 21:31:38 +0200217 self.child_file_path = os.path.join(TESTFN, 'a')
218 self.child_dir_path = os.path.join(TESTFN, 'b')
219 support.create_empty_file(self.child_file_path)
220 os.mkdir(self.child_dir_path)
221 old_dir_mode = os.stat(TESTFN).st_mode
222 old_child_file_mode = os.stat(self.child_file_path).st_mode
223 old_child_dir_mode = os.stat(self.child_dir_path).st_mode
224 # Make unwritable.
225 new_mode = stat.S_IREAD|stat.S_IEXEC
226 os.chmod(self.child_file_path, new_mode)
227 os.chmod(self.child_dir_path, new_mode)
228 os.chmod(TESTFN, new_mode)
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000229
Serhiy Storchaka43767632013-11-03 21:31:38 +0200230 self.addCleanup(os.chmod, TESTFN, old_dir_mode)
231 self.addCleanup(os.chmod, self.child_file_path, old_child_file_mode)
232 self.addCleanup(os.chmod, self.child_dir_path, old_child_dir_mode)
Antoine Pitrou2f8a75c2012-06-23 21:28:15 +0200233
Serhiy Storchaka43767632013-11-03 21:31:38 +0200234 shutil.rmtree(TESTFN, onerror=self.check_args_to_onerror)
235 # Test whether onerror has actually been called.
236 self.assertEqual(self.errorState, 3,
237 "Expected call to onerror function did not happen.")
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000238
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000239 def check_args_to_onerror(self, func, arg, exc):
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000240 # test_rmtree_errors deliberately runs rmtree
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200241 # on a directory that is chmod 500, which will fail.
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000242 # This function is run when shutil.rmtree fails.
243 # 99.9% of the time it initially fails to remove
244 # a file in the directory, so the first time through
245 # func is os.remove.
246 # However, some Linux machines running ZFS on
247 # FUSE experienced a failure earlier in the process
248 # at os.listdir. The first failure may legally
249 # be either.
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200250 if self.errorState < 2:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200251 if func is os.unlink:
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200252 self.assertEqual(arg, self.child_file_path)
253 elif func is os.rmdir:
254 self.assertEqual(arg, self.child_dir_path)
Benjamin Peterson25c95f12009-05-08 20:42:26 +0000255 else:
Antoine Pitrou4f6e3f72012-06-23 22:05:11 +0200256 self.assertIs(func, os.listdir)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200257 self.assertIn(arg, [TESTFN, self.child_dir_path])
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000258 self.assertTrue(issubclass(exc[0], OSError))
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200259 self.errorState += 1
Johannes Gijsbersef5ffc42004-10-31 12:05:31 +0000260 else:
261 self.assertEqual(func, os.rmdir)
262 self.assertEqual(arg, TESTFN)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +0000263 self.assertTrue(issubclass(exc[0], OSError))
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200264 self.errorState = 3
265
266 def test_rmtree_does_not_choke_on_failing_lstat(self):
267 try:
268 orig_lstat = os.lstat
Hynek Schlawacka75cd1c2012-06-28 12:07:29 +0200269 def raiser(fn, *args, **kwargs):
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200270 if fn != TESTFN:
271 raise OSError()
272 else:
273 return orig_lstat(fn)
274 os.lstat = raiser
275
276 os.mkdir(TESTFN)
277 write_file((TESTFN, 'foo'), 'foo')
278 shutil.rmtree(TESTFN)
279 finally:
280 os.lstat = orig_lstat
Barry Warsaw7fc2cca2003-01-24 17:34:13 +0000281
Antoine Pitrou78091e62011-12-29 18:54:15 +0100282 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
283 @support.skip_unless_symlink
284 def test_copymode_follow_symlinks(self):
285 tmp_dir = self.mkdtemp()
286 src = os.path.join(tmp_dir, 'foo')
287 dst = os.path.join(tmp_dir, 'bar')
288 src_link = os.path.join(tmp_dir, 'baz')
289 dst_link = os.path.join(tmp_dir, 'quux')
290 write_file(src, 'foo')
291 write_file(dst, 'foo')
292 os.symlink(src, src_link)
293 os.symlink(dst, dst_link)
294 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
295 # file to file
296 os.chmod(dst, stat.S_IRWXO)
297 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
298 shutil.copymode(src, dst)
299 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
Antoine Pitrou3f48ac92014-01-01 02:50:45 +0100300 # On Windows, os.chmod does not follow symlinks (issue #15411)
301 if os.name != 'nt':
302 # follow src link
303 os.chmod(dst, stat.S_IRWXO)
304 shutil.copymode(src_link, dst)
305 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
306 # follow dst link
307 os.chmod(dst, stat.S_IRWXO)
308 shutil.copymode(src, dst_link)
309 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
310 # follow both links
311 os.chmod(dst, stat.S_IRWXO)
312 shutil.copymode(src_link, dst_link)
313 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100314
315 @unittest.skipUnless(hasattr(os, 'lchmod'), 'requires os.lchmod')
316 @support.skip_unless_symlink
317 def test_copymode_symlink_to_symlink(self):
318 tmp_dir = self.mkdtemp()
319 src = os.path.join(tmp_dir, 'foo')
320 dst = os.path.join(tmp_dir, 'bar')
321 src_link = os.path.join(tmp_dir, 'baz')
322 dst_link = os.path.join(tmp_dir, 'quux')
323 write_file(src, 'foo')
324 write_file(dst, 'foo')
325 os.symlink(src, src_link)
326 os.symlink(dst, dst_link)
327 os.chmod(src, stat.S_IRWXU|stat.S_IRWXG)
328 os.chmod(dst, stat.S_IRWXU)
329 os.lchmod(src_link, stat.S_IRWXO|stat.S_IRWXG)
330 # link to link
331 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700332 shutil.copymode(src_link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100333 self.assertEqual(os.lstat(src_link).st_mode,
334 os.lstat(dst_link).st_mode)
335 self.assertNotEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
336 # src link - use chmod
337 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700338 shutil.copymode(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100339 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
340 # dst link - use chmod
341 os.lchmod(dst_link, stat.S_IRWXO)
Larry Hastingsb4038062012-07-15 10:57:38 -0700342 shutil.copymode(src, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100343 self.assertEqual(os.stat(src).st_mode, os.stat(dst).st_mode)
344
345 @unittest.skipIf(hasattr(os, 'lchmod'), 'requires os.lchmod to be missing')
346 @support.skip_unless_symlink
347 def test_copymode_symlink_to_symlink_wo_lchmod(self):
348 tmp_dir = self.mkdtemp()
349 src = os.path.join(tmp_dir, 'foo')
350 dst = os.path.join(tmp_dir, 'bar')
351 src_link = os.path.join(tmp_dir, 'baz')
352 dst_link = os.path.join(tmp_dir, 'quux')
353 write_file(src, 'foo')
354 write_file(dst, 'foo')
355 os.symlink(src, src_link)
356 os.symlink(dst, dst_link)
Larry Hastingsb4038062012-07-15 10:57:38 -0700357 shutil.copymode(src_link, dst_link, follow_symlinks=False) # silent fail
Antoine Pitrou78091e62011-12-29 18:54:15 +0100358
359 @support.skip_unless_symlink
360 def test_copystat_symlinks(self):
361 tmp_dir = self.mkdtemp()
362 src = os.path.join(tmp_dir, 'foo')
363 dst = os.path.join(tmp_dir, 'bar')
364 src_link = os.path.join(tmp_dir, 'baz')
365 dst_link = os.path.join(tmp_dir, 'qux')
366 write_file(src, 'foo')
367 src_stat = os.stat(src)
368 os.utime(src, (src_stat.st_atime,
369 src_stat.st_mtime - 42.0)) # ensure different mtimes
370 write_file(dst, 'bar')
371 self.assertNotEqual(os.stat(src).st_mtime, os.stat(dst).st_mtime)
372 os.symlink(src, src_link)
373 os.symlink(dst, dst_link)
374 if hasattr(os, 'lchmod'):
375 os.lchmod(src_link, stat.S_IRWXO)
376 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
377 os.lchflags(src_link, stat.UF_NODUMP)
378 src_link_stat = os.lstat(src_link)
379 # follow
380 if hasattr(os, 'lchmod'):
Larry Hastingsb4038062012-07-15 10:57:38 -0700381 shutil.copystat(src_link, dst_link, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100382 self.assertNotEqual(src_link_stat.st_mode, os.stat(dst).st_mode)
383 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700384 shutil.copystat(src_link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100385 dst_link_stat = os.lstat(dst_link)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700386 if os.utime in os.supports_follow_symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100387 for attr in 'st_atime', 'st_mtime':
388 # The modification times may be truncated in the new file.
389 self.assertLessEqual(getattr(src_link_stat, attr),
390 getattr(dst_link_stat, attr) + 1)
391 if hasattr(os, 'lchmod'):
392 self.assertEqual(src_link_stat.st_mode, dst_link_stat.st_mode)
393 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
394 self.assertEqual(src_link_stat.st_flags, dst_link_stat.st_flags)
395 # tell to follow but dst is not a link
Larry Hastingsb4038062012-07-15 10:57:38 -0700396 shutil.copystat(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100397 self.assertTrue(abs(os.stat(src).st_mtime - os.stat(dst).st_mtime) <
398 00000.1)
399
Ned Deilybaf75712012-05-10 17:05:19 -0700400 @unittest.skipUnless(hasattr(os, 'chflags') and
401 hasattr(errno, 'EOPNOTSUPP') and
402 hasattr(errno, 'ENOTSUP'),
403 "requires os.chflags, EOPNOTSUPP & ENOTSUP")
404 def test_copystat_handles_harmless_chflags_errors(self):
405 tmpdir = self.mkdtemp()
406 file1 = os.path.join(tmpdir, 'file1')
407 file2 = os.path.join(tmpdir, 'file2')
408 write_file(file1, 'xxx')
409 write_file(file2, 'xxx')
410
411 def make_chflags_raiser(err):
412 ex = OSError()
413
Larry Hastings90867a52012-06-22 17:01:41 -0700414 def _chflags_raiser(path, flags, *, follow_symlinks=True):
Ned Deilybaf75712012-05-10 17:05:19 -0700415 ex.errno = err
416 raise ex
417 return _chflags_raiser
418 old_chflags = os.chflags
419 try:
420 for err in errno.EOPNOTSUPP, errno.ENOTSUP:
421 os.chflags = make_chflags_raiser(err)
422 shutil.copystat(file1, file2)
423 # assert others errors break it
424 os.chflags = make_chflags_raiser(errno.EOPNOTSUPP + errno.ENOTSUP)
425 self.assertRaises(OSError, shutil.copystat, file1, file2)
426 finally:
427 os.chflags = old_chflags
428
Antoine Pitrou424246f2012-05-12 19:02:01 +0200429 @support.skip_unless_xattr
430 def test_copyxattr(self):
431 tmp_dir = self.mkdtemp()
432 src = os.path.join(tmp_dir, 'foo')
433 write_file(src, 'foo')
434 dst = os.path.join(tmp_dir, 'bar')
435 write_file(dst, 'bar')
436
437 # no xattr == no problem
438 shutil._copyxattr(src, dst)
439 # common case
440 os.setxattr(src, 'user.foo', b'42')
441 os.setxattr(src, 'user.bar', b'43')
442 shutil._copyxattr(src, dst)
Gregory P. Smith1093bf22014-01-17 12:01:22 -0800443 self.assertEqual(sorted(os.listxattr(src)), sorted(os.listxattr(dst)))
Antoine Pitrou424246f2012-05-12 19:02:01 +0200444 self.assertEqual(
445 os.getxattr(src, 'user.foo'),
446 os.getxattr(dst, 'user.foo'))
447 # check errors don't affect other attrs
448 os.remove(dst)
449 write_file(dst, 'bar')
450 os_error = OSError(errno.EPERM, 'EPERM')
451
Larry Hastings9cf065c2012-06-22 16:30:09 -0700452 def _raise_on_user_foo(fname, attr, val, **kwargs):
Antoine Pitrou424246f2012-05-12 19:02:01 +0200453 if attr == 'user.foo':
454 raise os_error
455 else:
Larry Hastings9cf065c2012-06-22 16:30:09 -0700456 orig_setxattr(fname, attr, val, **kwargs)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200457 try:
458 orig_setxattr = os.setxattr
459 os.setxattr = _raise_on_user_foo
460 shutil._copyxattr(src, dst)
Antoine Pitrou61597d32012-05-12 23:37:35 +0200461 self.assertIn('user.bar', os.listxattr(dst))
Antoine Pitrou424246f2012-05-12 19:02:01 +0200462 finally:
463 os.setxattr = orig_setxattr
Hynek Schlawack0beab052013-02-05 08:22:44 +0100464 # the source filesystem not supporting xattrs should be ok, too.
465 def _raise_on_src(fname, *, follow_symlinks=True):
466 if fname == src:
467 raise OSError(errno.ENOTSUP, 'Operation not supported')
468 return orig_listxattr(fname, follow_symlinks=follow_symlinks)
469 try:
470 orig_listxattr = os.listxattr
471 os.listxattr = _raise_on_src
472 shutil._copyxattr(src, dst)
473 finally:
474 os.listxattr = orig_listxattr
Antoine Pitrou424246f2012-05-12 19:02:01 +0200475
Larry Hastingsad5ae042012-07-14 17:55:11 -0700476 # test that shutil.copystat copies xattrs
477 src = os.path.join(tmp_dir, 'the_original')
478 write_file(src, src)
479 os.setxattr(src, 'user.the_value', b'fiddly')
480 dst = os.path.join(tmp_dir, 'the_copy')
481 write_file(dst, dst)
482 shutil.copystat(src, dst)
Hynek Schlawackc2d481f2012-07-16 17:11:10 +0200483 self.assertEqual(os.getxattr(dst, 'user.the_value'), b'fiddly')
Larry Hastingsad5ae042012-07-14 17:55:11 -0700484
Antoine Pitrou424246f2012-05-12 19:02:01 +0200485 @support.skip_unless_symlink
486 @support.skip_unless_xattr
487 @unittest.skipUnless(hasattr(os, 'geteuid') and os.geteuid() == 0,
488 'root privileges required')
489 def test_copyxattr_symlinks(self):
490 # On Linux, it's only possible to access non-user xattr for symlinks;
491 # which in turn require root privileges. This test should be expanded
492 # as soon as other platforms gain support for extended attributes.
493 tmp_dir = self.mkdtemp()
494 src = os.path.join(tmp_dir, 'foo')
495 src_link = os.path.join(tmp_dir, 'baz')
496 write_file(src, 'foo')
497 os.symlink(src, src_link)
498 os.setxattr(src, 'trusted.foo', b'42')
Larry Hastings9cf065c2012-06-22 16:30:09 -0700499 os.setxattr(src_link, 'trusted.foo', b'43', follow_symlinks=False)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200500 dst = os.path.join(tmp_dir, 'bar')
501 dst_link = os.path.join(tmp_dir, 'qux')
502 write_file(dst, 'bar')
503 os.symlink(dst, dst_link)
Larry Hastingsb4038062012-07-15 10:57:38 -0700504 shutil._copyxattr(src_link, dst_link, follow_symlinks=False)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700505 self.assertEqual(os.getxattr(dst_link, 'trusted.foo', follow_symlinks=False), b'43')
Antoine Pitrou424246f2012-05-12 19:02:01 +0200506 self.assertRaises(OSError, os.getxattr, dst, 'trusted.foo')
Larry Hastingsb4038062012-07-15 10:57:38 -0700507 shutil._copyxattr(src_link, dst, follow_symlinks=False)
Antoine Pitrou424246f2012-05-12 19:02:01 +0200508 self.assertEqual(os.getxattr(dst, 'trusted.foo'), b'43')
509
Antoine Pitrou78091e62011-12-29 18:54:15 +0100510 @support.skip_unless_symlink
511 def test_copy_symlinks(self):
512 tmp_dir = self.mkdtemp()
513 src = os.path.join(tmp_dir, 'foo')
514 dst = os.path.join(tmp_dir, 'bar')
515 src_link = os.path.join(tmp_dir, 'baz')
516 write_file(src, 'foo')
517 os.symlink(src, src_link)
518 if hasattr(os, 'lchmod'):
519 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
520 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700521 shutil.copy(src_link, dst, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100522 self.assertFalse(os.path.islink(dst))
523 self.assertEqual(read_file(src), read_file(dst))
524 os.remove(dst)
525 # follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700526 shutil.copy(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100527 self.assertTrue(os.path.islink(dst))
528 self.assertEqual(os.readlink(dst), os.readlink(src_link))
529 if hasattr(os, 'lchmod'):
530 self.assertEqual(os.lstat(src_link).st_mode,
531 os.lstat(dst).st_mode)
532
533 @support.skip_unless_symlink
534 def test_copy2_symlinks(self):
535 tmp_dir = self.mkdtemp()
536 src = os.path.join(tmp_dir, 'foo')
537 dst = os.path.join(tmp_dir, 'bar')
538 src_link = os.path.join(tmp_dir, 'baz')
539 write_file(src, 'foo')
540 os.symlink(src, src_link)
541 if hasattr(os, 'lchmod'):
542 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
543 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
544 os.lchflags(src_link, stat.UF_NODUMP)
545 src_stat = os.stat(src)
546 src_link_stat = os.lstat(src_link)
547 # follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700548 shutil.copy2(src_link, dst, follow_symlinks=True)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100549 self.assertFalse(os.path.islink(dst))
550 self.assertEqual(read_file(src), read_file(dst))
551 os.remove(dst)
552 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700553 shutil.copy2(src_link, dst, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100554 self.assertTrue(os.path.islink(dst))
555 self.assertEqual(os.readlink(dst), os.readlink(src_link))
556 dst_stat = os.lstat(dst)
Larry Hastings9cf065c2012-06-22 16:30:09 -0700557 if os.utime in os.supports_follow_symlinks:
Antoine Pitrou78091e62011-12-29 18:54:15 +0100558 for attr in 'st_atime', 'st_mtime':
559 # The modification times may be truncated in the new file.
560 self.assertLessEqual(getattr(src_link_stat, attr),
561 getattr(dst_stat, attr) + 1)
562 if hasattr(os, 'lchmod'):
563 self.assertEqual(src_link_stat.st_mode, dst_stat.st_mode)
564 self.assertNotEqual(src_stat.st_mode, dst_stat.st_mode)
565 if hasattr(os, 'lchflags') and hasattr(src_link_stat, 'st_flags'):
566 self.assertEqual(src_link_stat.st_flags, dst_stat.st_flags)
567
Antoine Pitrou424246f2012-05-12 19:02:01 +0200568 @support.skip_unless_xattr
569 def test_copy2_xattr(self):
570 tmp_dir = self.mkdtemp()
571 src = os.path.join(tmp_dir, 'foo')
572 dst = os.path.join(tmp_dir, 'bar')
573 write_file(src, 'foo')
574 os.setxattr(src, 'user.foo', b'42')
575 shutil.copy2(src, dst)
576 self.assertEqual(
577 os.getxattr(src, 'user.foo'),
578 os.getxattr(dst, 'user.foo'))
579 os.remove(dst)
580
Antoine Pitrou78091e62011-12-29 18:54:15 +0100581 @support.skip_unless_symlink
582 def test_copyfile_symlinks(self):
583 tmp_dir = self.mkdtemp()
584 src = os.path.join(tmp_dir, 'src')
585 dst = os.path.join(tmp_dir, 'dst')
586 dst_link = os.path.join(tmp_dir, 'dst_link')
587 link = os.path.join(tmp_dir, 'link')
588 write_file(src, 'foo')
589 os.symlink(src, link)
590 # don't follow
Larry Hastingsb4038062012-07-15 10:57:38 -0700591 shutil.copyfile(link, dst_link, follow_symlinks=False)
Antoine Pitrou78091e62011-12-29 18:54:15 +0100592 self.assertTrue(os.path.islink(dst_link))
593 self.assertEqual(os.readlink(link), os.readlink(dst_link))
594 # follow
595 shutil.copyfile(link, dst)
596 self.assertFalse(os.path.islink(dst))
597
Hynek Schlawack2100b422012-06-23 20:28:32 +0200598 def test_rmtree_uses_safe_fd_version_if_available(self):
Hynek Schlawackd0f6e0a2012-06-29 08:28:20 +0200599 _use_fd_functions = ({os.open, os.stat, os.unlink, os.rmdir} <=
600 os.supports_dir_fd and
601 os.listdir in os.supports_fd and
602 os.stat in os.supports_follow_symlinks)
603 if _use_fd_functions:
Hynek Schlawack2100b422012-06-23 20:28:32 +0200604 self.assertTrue(shutil._use_fd_functions)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000605 self.assertTrue(shutil.rmtree.avoids_symlink_attacks)
Hynek Schlawack2100b422012-06-23 20:28:32 +0200606 tmp_dir = self.mkdtemp()
607 d = os.path.join(tmp_dir, 'a')
608 os.mkdir(d)
609 try:
610 real_rmtree = shutil._rmtree_safe_fd
611 class Called(Exception): pass
612 def _raiser(*args, **kwargs):
613 raise Called
614 shutil._rmtree_safe_fd = _raiser
615 self.assertRaises(Called, shutil.rmtree, d)
616 finally:
617 shutil._rmtree_safe_fd = real_rmtree
618 else:
619 self.assertFalse(shutil._use_fd_functions)
Nick Coghlan5b0eca12012-06-24 16:43:06 +1000620 self.assertFalse(shutil.rmtree.avoids_symlink_attacks)
Hynek Schlawack2100b422012-06-23 20:28:32 +0200621
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000622 def test_rmtree_dont_delete_file(self):
623 # When called on a file instead of a directory, don't delete it.
624 handle, path = tempfile.mkstemp()
Victor Stinnerbf816222011-06-30 23:25:47 +0200625 os.close(handle)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200626 self.assertRaises(NotADirectoryError, shutil.rmtree, path)
Johannes Gijsbersd60e92a2004-09-11 21:26:21 +0000627 os.remove(path)
628
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000629 def test_copytree_simple(self):
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000630 src_dir = tempfile.mkdtemp()
631 dst_dir = os.path.join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200632 self.addCleanup(shutil.rmtree, src_dir)
633 self.addCleanup(shutil.rmtree, os.path.dirname(dst_dir))
634 write_file((src_dir, 'test.txt'), '123')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000635 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200636 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000637
Éric Araujoa7e33a12011-08-12 19:51:35 +0200638 shutil.copytree(src_dir, dst_dir)
639 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test.txt')))
640 self.assertTrue(os.path.isdir(os.path.join(dst_dir, 'test_dir')))
641 self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test_dir',
642 'test.txt')))
643 actual = read_file((dst_dir, 'test.txt'))
644 self.assertEqual(actual, '123')
645 actual = read_file((dst_dir, 'test_dir', 'test.txt'))
646 self.assertEqual(actual, '456')
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000647
Antoine Pitrou78091e62011-12-29 18:54:15 +0100648 @support.skip_unless_symlink
649 def test_copytree_symlinks(self):
650 tmp_dir = self.mkdtemp()
651 src_dir = os.path.join(tmp_dir, 'src')
652 dst_dir = os.path.join(tmp_dir, 'dst')
653 sub_dir = os.path.join(src_dir, 'sub')
654 os.mkdir(src_dir)
655 os.mkdir(sub_dir)
656 write_file((src_dir, 'file.txt'), 'foo')
657 src_link = os.path.join(sub_dir, 'link')
658 dst_link = os.path.join(dst_dir, 'sub/link')
659 os.symlink(os.path.join(src_dir, 'file.txt'),
660 src_link)
661 if hasattr(os, 'lchmod'):
662 os.lchmod(src_link, stat.S_IRWXU | stat.S_IRWXO)
663 if hasattr(os, 'lchflags') and hasattr(stat, 'UF_NODUMP'):
664 os.lchflags(src_link, stat.UF_NODUMP)
665 src_stat = os.lstat(src_link)
666 shutil.copytree(src_dir, dst_dir, symlinks=True)
667 self.assertTrue(os.path.islink(os.path.join(dst_dir, 'sub', 'link')))
668 self.assertEqual(os.readlink(os.path.join(dst_dir, 'sub', 'link')),
669 os.path.join(src_dir, 'file.txt'))
670 dst_stat = os.lstat(dst_link)
671 if hasattr(os, 'lchmod'):
672 self.assertEqual(dst_stat.st_mode, src_stat.st_mode)
673 if hasattr(os, 'lchflags'):
674 self.assertEqual(dst_stat.st_flags, src_stat.st_flags)
675
Georg Brandl2ee470f2008-07-16 12:55:28 +0000676 def test_copytree_with_exclude(self):
Georg Brandl2ee470f2008-07-16 12:55:28 +0000677 # creating data
678 join = os.path.join
679 exists = os.path.exists
680 src_dir = tempfile.mkdtemp()
Georg Brandl2ee470f2008-07-16 12:55:28 +0000681 try:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000682 dst_dir = join(tempfile.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200683 write_file((src_dir, 'test.txt'), '123')
684 write_file((src_dir, 'test.tmp'), '123')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000685 os.mkdir(join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200686 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000687 os.mkdir(join(src_dir, 'test_dir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200688 write_file((src_dir, 'test_dir2', 'test.txt'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000689 os.mkdir(join(src_dir, 'test_dir2', 'subdir'))
690 os.mkdir(join(src_dir, 'test_dir2', 'subdir2'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200691 write_file((src_dir, 'test_dir2', 'subdir', 'test.txt'), '456')
692 write_file((src_dir, 'test_dir2', 'subdir2', 'test.py'), '456')
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000693
694 # testing glob-like patterns
695 try:
696 patterns = shutil.ignore_patterns('*.tmp', 'test_dir2')
697 shutil.copytree(src_dir, dst_dir, ignore=patterns)
698 # checking the result: some elements should not be copied
699 self.assertTrue(exists(join(dst_dir, 'test.txt')))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200700 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
701 self.assertFalse(exists(join(dst_dir, 'test_dir2')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000702 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200703 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000704 try:
705 patterns = shutil.ignore_patterns('*.tmp', 'subdir*')
706 shutil.copytree(src_dir, dst_dir, ignore=patterns)
707 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200708 self.assertFalse(exists(join(dst_dir, 'test.tmp')))
709 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2')))
710 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000711 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200712 shutil.rmtree(dst_dir)
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000713
714 # testing callable-style
715 try:
716 def _filter(src, names):
717 res = []
718 for name in names:
719 path = os.path.join(src, name)
720
721 if (os.path.isdir(path) and
722 path.split()[-1] == 'subdir'):
723 res.append(name)
724 elif os.path.splitext(path)[-1] in ('.py'):
725 res.append(name)
726 return res
727
728 shutil.copytree(src_dir, dst_dir, ignore=_filter)
729
730 # checking the result: some elements should not be copied
Éric Araujoa7e33a12011-08-12 19:51:35 +0200731 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir2',
732 'test.py')))
733 self.assertFalse(exists(join(dst_dir, 'test_dir2', 'subdir')))
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000734
735 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +0200736 shutil.rmtree(dst_dir)
Georg Brandl2ee470f2008-07-16 12:55:28 +0000737 finally:
Antoine Pitrou97c81ef2009-11-04 00:57:15 +0000738 shutil.rmtree(src_dir)
739 shutil.rmtree(os.path.dirname(dst_dir))
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000740
Antoine Pitrouac601602013-08-16 19:35:02 +0200741 def test_copytree_retains_permissions(self):
742 tmp_dir = tempfile.mkdtemp()
743 src_dir = os.path.join(tmp_dir, 'source')
744 os.mkdir(src_dir)
745 dst_dir = os.path.join(tmp_dir, 'destination')
746 self.addCleanup(shutil.rmtree, tmp_dir)
747
748 os.chmod(src_dir, 0o777)
749 write_file((src_dir, 'permissive.txt'), '123')
750 os.chmod(os.path.join(src_dir, 'permissive.txt'), 0o777)
751 write_file((src_dir, 'restrictive.txt'), '456')
752 os.chmod(os.path.join(src_dir, 'restrictive.txt'), 0o600)
753 restrictive_subdir = tempfile.mkdtemp(dir=src_dir)
754 os.chmod(restrictive_subdir, 0o600)
755
756 shutil.copytree(src_dir, dst_dir)
Brett Cannon9c7eb552013-08-23 14:38:11 -0400757 self.assertEqual(os.stat(src_dir).st_mode, os.stat(dst_dir).st_mode)
758 self.assertEqual(os.stat(os.path.join(src_dir, 'permissive.txt')).st_mode,
Antoine Pitrouac601602013-08-16 19:35:02 +0200759 os.stat(os.path.join(dst_dir, 'permissive.txt')).st_mode)
Brett Cannon9c7eb552013-08-23 14:38:11 -0400760 self.assertEqual(os.stat(os.path.join(src_dir, 'restrictive.txt')).st_mode,
Antoine Pitrouac601602013-08-16 19:35:02 +0200761 os.stat(os.path.join(dst_dir, 'restrictive.txt')).st_mode)
762 restrictive_subdir_dst = os.path.join(dst_dir,
763 os.path.split(restrictive_subdir)[1])
Brett Cannon9c7eb552013-08-23 14:38:11 -0400764 self.assertEqual(os.stat(restrictive_subdir).st_mode,
Antoine Pitrouac601602013-08-16 19:35:02 +0200765 os.stat(restrictive_subdir_dst).st_mode)
766
Zachary Ware9fe6d862013-12-08 00:20:35 -0600767 @unittest.skipIf(os.name == 'nt', 'temporarily disabled on Windows')
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000768 @unittest.skipUnless(hasattr(os, 'link'), 'requires os.link')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000769 def test_dont_copy_file_onto_link_to_itself(self):
770 # bug 851123.
771 os.mkdir(TESTFN)
772 src = os.path.join(TESTFN, 'cheese')
773 dst = os.path.join(TESTFN, 'shop')
774 try:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000775 with open(src, 'w') as f:
776 f.write('cheddar')
777 os.link(src, dst)
Hynek Schlawack48653762012-10-07 12:49:58 +0200778 self.assertRaises(shutil.SameFileError, shutil.copyfile, src, dst)
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000779 with open(src, 'r') as f:
780 self.assertEqual(f.read(), 'cheddar')
781 os.remove(dst)
782 finally:
783 shutil.rmtree(TESTFN, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000784
Brian Curtin3b4499c2010-12-28 14:31:47 +0000785 @support.skip_unless_symlink
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000786 def test_dont_copy_file_onto_symlink_to_itself(self):
787 # bug 851123.
788 os.mkdir(TESTFN)
789 src = os.path.join(TESTFN, 'cheese')
790 dst = os.path.join(TESTFN, 'shop')
791 try:
792 with open(src, 'w') as f:
793 f.write('cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000794 # Using `src` here would mean we end up with a symlink pointing
795 # to TESTFN/TESTFN/cheese, while it should point at
796 # TESTFN/cheese.
797 os.symlink('cheese', dst)
Hynek Schlawack48653762012-10-07 12:49:58 +0200798 self.assertRaises(shutil.SameFileError, shutil.copyfile, src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +0000799 with open(src, 'r') as f:
800 self.assertEqual(f.read(), 'cheddar')
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000801 os.remove(dst)
802 finally:
Hirokazu Yamamoto26681452010-12-05 02:04:16 +0000803 shutil.rmtree(TESTFN, ignore_errors=True)
Johannes Gijsbers68128712004-08-14 13:57:08 +0000804
Brian Curtin3b4499c2010-12-28 14:31:47 +0000805 @support.skip_unless_symlink
Brian Curtind40e6f72010-07-08 21:39:08 +0000806 def test_rmtree_on_symlink(self):
807 # bug 1669.
808 os.mkdir(TESTFN)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000809 try:
Brian Curtind40e6f72010-07-08 21:39:08 +0000810 src = os.path.join(TESTFN, 'cheese')
811 dst = os.path.join(TESTFN, 'shop')
812 os.mkdir(src)
813 os.symlink(src, dst)
814 self.assertRaises(OSError, shutil.rmtree, dst)
Hynek Schlawack67be92b2012-06-23 17:58:42 +0200815 shutil.rmtree(dst, ignore_errors=True)
Tarek Ziadé51a6f722010-04-23 13:03:09 +0000816 finally:
Brian Curtind40e6f72010-07-08 21:39:08 +0000817 shutil.rmtree(TESTFN, ignore_errors=True)
818
Serhiy Storchaka43767632013-11-03 21:31:38 +0200819 # Issue #3002: copyfile and copytree block indefinitely on named pipes
820 @unittest.skipUnless(hasattr(os, "mkfifo"), 'requires os.mkfifo()')
821 def test_copyfile_named_pipe(self):
822 os.mkfifo(TESTFN)
823 try:
824 self.assertRaises(shutil.SpecialFileError,
825 shutil.copyfile, TESTFN, TESTFN2)
826 self.assertRaises(shutil.SpecialFileError,
827 shutil.copyfile, __file__, TESTFN)
828 finally:
829 os.remove(TESTFN)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000830
Serhiy Storchaka43767632013-11-03 21:31:38 +0200831 @unittest.skipUnless(hasattr(os, "mkfifo"), 'requires os.mkfifo()')
832 @support.skip_unless_symlink
833 def test_copytree_named_pipe(self):
834 os.mkdir(TESTFN)
835 try:
836 subdir = os.path.join(TESTFN, "subdir")
837 os.mkdir(subdir)
838 pipe = os.path.join(subdir, "mypipe")
839 os.mkfifo(pipe)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000840 try:
Serhiy Storchaka43767632013-11-03 21:31:38 +0200841 shutil.copytree(TESTFN, TESTFN2)
842 except shutil.Error as e:
843 errors = e.args[0]
844 self.assertEqual(len(errors), 1)
845 src, dst, error_msg = errors[0]
846 self.assertEqual("`%s` is a named pipe" % pipe, error_msg)
847 else:
848 self.fail("shutil.Error should have been raised")
849 finally:
850 shutil.rmtree(TESTFN, ignore_errors=True)
851 shutil.rmtree(TESTFN2, ignore_errors=True)
Antoine Pitrou7fff0962009-05-01 21:09:44 +0000852
Tarek Ziadé5340db32010-04-19 22:30:51 +0000853 def test_copytree_special_func(self):
854
855 src_dir = self.mkdtemp()
856 dst_dir = os.path.join(self.mkdtemp(), 'destination')
Éric Araujoa7e33a12011-08-12 19:51:35 +0200857 write_file((src_dir, 'test.txt'), '123')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000858 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200859 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadé5340db32010-04-19 22:30:51 +0000860
861 copied = []
862 def _copy(src, dst):
863 copied.append((src, dst))
864
865 shutil.copytree(src_dir, dst_dir, copy_function=_copy)
Ezio Melottib3aedd42010-11-20 19:04:17 +0000866 self.assertEqual(len(copied), 2)
Tarek Ziadé5340db32010-04-19 22:30:51 +0000867
Brian Curtin3b4499c2010-12-28 14:31:47 +0000868 @support.skip_unless_symlink
Tarek Ziadéfb437512010-04-20 08:57:33 +0000869 def test_copytree_dangling_symlinks(self):
870
871 # a dangling symlink raises an error at the end
872 src_dir = self.mkdtemp()
873 dst_dir = os.path.join(self.mkdtemp(), 'destination')
874 os.symlink('IDONTEXIST', os.path.join(src_dir, 'test.txt'))
875 os.mkdir(os.path.join(src_dir, 'test_dir'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200876 write_file((src_dir, 'test_dir', 'test.txt'), '456')
Tarek Ziadéfb437512010-04-20 08:57:33 +0000877 self.assertRaises(Error, shutil.copytree, src_dir, dst_dir)
878
879 # a dangling symlink is ignored with the proper flag
880 dst_dir = os.path.join(self.mkdtemp(), 'destination2')
881 shutil.copytree(src_dir, dst_dir, ignore_dangling_symlinks=True)
882 self.assertNotIn('test.txt', os.listdir(dst_dir))
883
884 # a dangling symlink is copied if symlinks=True
885 dst_dir = os.path.join(self.mkdtemp(), 'destination3')
886 shutil.copytree(src_dir, dst_dir, symlinks=True)
887 self.assertIn('test.txt', os.listdir(dst_dir))
888
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400889 def _copy_file(self, method):
890 fname = 'test.txt'
891 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200892 write_file((tmpdir, fname), 'xxx')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400893 file1 = os.path.join(tmpdir, fname)
894 tmpdir2 = self.mkdtemp()
895 method(file1, tmpdir2)
896 file2 = os.path.join(tmpdir2, fname)
897 return (file1, file2)
898
899 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
900 def test_copy(self):
901 # Ensure that the copied file exists and has the same mode bits.
902 file1, file2 = self._copy_file(shutil.copy)
903 self.assertTrue(os.path.exists(file2))
904 self.assertEqual(os.stat(file1).st_mode, os.stat(file2).st_mode)
905
906 @unittest.skipUnless(hasattr(os, 'chmod'), 'requires os.chmod')
Senthil Kumaran0c2dba52011-07-03 18:21:38 -0700907 @unittest.skipUnless(hasattr(os, 'utime'), 'requires os.utime')
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400908 def test_copy2(self):
909 # Ensure that the copied file exists and has the same mode and
910 # modification time bits.
911 file1, file2 = self._copy_file(shutil.copy2)
912 self.assertTrue(os.path.exists(file2))
913 file1_stat = os.stat(file1)
914 file2_stat = os.stat(file2)
915 self.assertEqual(file1_stat.st_mode, file2_stat.st_mode)
916 for attr in 'st_atime', 'st_mtime':
917 # The modification times may be truncated in the new file.
918 self.assertLessEqual(getattr(file1_stat, attr),
919 getattr(file2_stat, attr) + 1)
920 if hasattr(os, 'chflags') and hasattr(file1_stat, 'st_flags'):
921 self.assertEqual(getattr(file1_stat, 'st_flags'),
922 getattr(file2_stat, 'st_flags'))
923
Ezio Melotti975077a2011-05-19 22:03:22 +0300924 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000925 def test_make_tarball(self):
926 # creating something to tar
927 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +0200928 write_file((tmpdir, 'file1'), 'xxx')
929 write_file((tmpdir, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000930 os.mkdir(os.path.join(tmpdir, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200931 write_file((tmpdir, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000932
933 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -0400934 # force shutil to create the directory
935 os.rmdir(tmpdir2)
Tarek Ziadé396fad72010-02-23 05:30:31 +0000936 unittest.skipUnless(splitdrive(tmpdir)[0] == splitdrive(tmpdir2)[0],
937 "source and target should be on same drive")
938
939 base_name = os.path.join(tmpdir2, 'archive')
940
941 # working with relative paths to avoid tar warnings
942 old_dir = os.getcwd()
943 os.chdir(tmpdir)
944 try:
945 _make_tarball(splitdrive(base_name)[1], '.')
946 finally:
947 os.chdir(old_dir)
948
949 # check if the compressed tarball was created
950 tarball = base_name + '.tar.gz'
951 self.assertTrue(os.path.exists(tarball))
952
953 # trying an uncompressed one
954 base_name = os.path.join(tmpdir2, 'archive')
955 old_dir = os.getcwd()
956 os.chdir(tmpdir)
957 try:
958 _make_tarball(splitdrive(base_name)[1], '.', compress=None)
959 finally:
960 os.chdir(old_dir)
961 tarball = base_name + '.tar'
962 self.assertTrue(os.path.exists(tarball))
963
964 def _tarinfo(self, path):
965 tar = tarfile.open(path)
966 try:
967 names = tar.getnames()
968 names.sort()
969 return tuple(names)
970 finally:
971 tar.close()
972
973 def _create_files(self):
974 # creating something to tar
975 tmpdir = self.mkdtemp()
976 dist = os.path.join(tmpdir, 'dist')
977 os.mkdir(dist)
Éric Araujoa7e33a12011-08-12 19:51:35 +0200978 write_file((dist, 'file1'), 'xxx')
979 write_file((dist, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000980 os.mkdir(os.path.join(dist, 'sub'))
Éric Araujoa7e33a12011-08-12 19:51:35 +0200981 write_file((dist, 'sub', 'file3'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +0000982 os.mkdir(os.path.join(dist, 'sub2'))
983 tmpdir2 = self.mkdtemp()
984 base_name = os.path.join(tmpdir2, 'archive')
985 return tmpdir, tmpdir2, base_name
986
Ezio Melotti975077a2011-05-19 22:03:22 +0300987 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +0000988 @unittest.skipUnless(find_executable('tar') and find_executable('gzip'),
989 'Need the tar command to run')
990 def test_tarfile_vs_tar(self):
991 tmpdir, tmpdir2, base_name = self._create_files()
992 old_dir = os.getcwd()
993 os.chdir(tmpdir)
994 try:
995 _make_tarball(base_name, 'dist')
996 finally:
997 os.chdir(old_dir)
998
999 # check if the compressed tarball was created
1000 tarball = base_name + '.tar.gz'
1001 self.assertTrue(os.path.exists(tarball))
1002
1003 # now create another tarball using `tar`
1004 tarball2 = os.path.join(tmpdir, 'archive2.tar.gz')
1005 tar_cmd = ['tar', '-cf', 'archive2.tar', 'dist']
1006 gzip_cmd = ['gzip', '-f9', 'archive2.tar']
1007 old_dir = os.getcwd()
1008 os.chdir(tmpdir)
1009 try:
1010 with captured_stdout() as s:
1011 spawn(tar_cmd)
1012 spawn(gzip_cmd)
1013 finally:
1014 os.chdir(old_dir)
1015
1016 self.assertTrue(os.path.exists(tarball2))
1017 # let's compare both tarballs
Ezio Melottib3aedd42010-11-20 19:04:17 +00001018 self.assertEqual(self._tarinfo(tarball), self._tarinfo(tarball2))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001019
1020 # trying an uncompressed one
1021 base_name = os.path.join(tmpdir2, 'archive')
1022 old_dir = os.getcwd()
1023 os.chdir(tmpdir)
1024 try:
1025 _make_tarball(base_name, 'dist', compress=None)
1026 finally:
1027 os.chdir(old_dir)
1028 tarball = base_name + '.tar'
1029 self.assertTrue(os.path.exists(tarball))
1030
1031 # now for a dry_run
1032 base_name = os.path.join(tmpdir2, 'archive')
1033 old_dir = os.getcwd()
1034 os.chdir(tmpdir)
1035 try:
1036 _make_tarball(base_name, 'dist', compress=None, dry_run=True)
1037 finally:
1038 os.chdir(old_dir)
1039 tarball = base_name + '.tar'
1040 self.assertTrue(os.path.exists(tarball))
1041
Ezio Melotti975077a2011-05-19 22:03:22 +03001042 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001043 @unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run')
1044 def test_make_zipfile(self):
1045 # creating something to tar
1046 tmpdir = self.mkdtemp()
Éric Araujoa7e33a12011-08-12 19:51:35 +02001047 write_file((tmpdir, 'file1'), 'xxx')
1048 write_file((tmpdir, 'file2'), 'xxx')
Tarek Ziadé396fad72010-02-23 05:30:31 +00001049
1050 tmpdir2 = self.mkdtemp()
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001051 # force shutil to create the directory
1052 os.rmdir(tmpdir2)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001053 base_name = os.path.join(tmpdir2, 'archive')
1054 _make_zipfile(base_name, tmpdir)
1055
1056 # check if the compressed tarball was created
1057 tarball = base_name + '.zip'
Éric Araujo1c505492010-11-06 02:12:51 +00001058 self.assertTrue(os.path.exists(tarball))
Tarek Ziadé396fad72010-02-23 05:30:31 +00001059
1060
1061 def test_make_archive(self):
1062 tmpdir = self.mkdtemp()
1063 base_name = os.path.join(tmpdir, 'archive')
1064 self.assertRaises(ValueError, make_archive, base_name, 'xxx')
1065
Ezio Melotti975077a2011-05-19 22:03:22 +03001066 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001067 def test_make_archive_owner_group(self):
1068 # testing make_archive with owner and group, with various combinations
1069 # this works even if there's not gid/uid support
1070 if UID_GID_SUPPORT:
1071 group = grp.getgrgid(0)[0]
1072 owner = pwd.getpwuid(0)[0]
1073 else:
1074 group = owner = 'root'
1075
1076 base_dir, root_dir, base_name = self._create_files()
1077 base_name = os.path.join(self.mkdtemp() , 'archive')
1078 res = make_archive(base_name, 'zip', root_dir, base_dir, owner=owner,
1079 group=group)
1080 self.assertTrue(os.path.exists(res))
1081
1082 res = make_archive(base_name, 'zip', root_dir, base_dir)
1083 self.assertTrue(os.path.exists(res))
1084
1085 res = make_archive(base_name, 'tar', root_dir, base_dir,
1086 owner=owner, group=group)
1087 self.assertTrue(os.path.exists(res))
1088
1089 res = make_archive(base_name, 'tar', root_dir, base_dir,
1090 owner='kjhkjhkjg', group='oihohoh')
1091 self.assertTrue(os.path.exists(res))
1092
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001093
Ezio Melotti975077a2011-05-19 22:03:22 +03001094 @requires_zlib
Tarek Ziadé396fad72010-02-23 05:30:31 +00001095 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1096 def test_tarfile_root_owner(self):
1097 tmpdir, tmpdir2, base_name = self._create_files()
1098 old_dir = os.getcwd()
1099 os.chdir(tmpdir)
1100 group = grp.getgrgid(0)[0]
1101 owner = pwd.getpwuid(0)[0]
1102 try:
1103 archive_name = _make_tarball(base_name, 'dist', compress=None,
1104 owner=owner, group=group)
1105 finally:
1106 os.chdir(old_dir)
1107
1108 # check if the compressed tarball was created
1109 self.assertTrue(os.path.exists(archive_name))
1110
1111 # now checks the rights
1112 archive = tarfile.open(archive_name)
1113 try:
1114 for member in archive.getmembers():
Ezio Melottib3aedd42010-11-20 19:04:17 +00001115 self.assertEqual(member.uid, 0)
1116 self.assertEqual(member.gid, 0)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001117 finally:
1118 archive.close()
1119
1120 def test_make_archive_cwd(self):
1121 current_dir = os.getcwd()
1122 def _breaks(*args, **kw):
1123 raise RuntimeError()
1124
1125 register_archive_format('xxx', _breaks, [], 'xxx file')
1126 try:
1127 try:
1128 make_archive('xxx', 'xxx', root_dir=self.mkdtemp())
1129 except Exception:
1130 pass
Ezio Melottib3aedd42010-11-20 19:04:17 +00001131 self.assertEqual(os.getcwd(), current_dir)
Tarek Ziadé396fad72010-02-23 05:30:31 +00001132 finally:
1133 unregister_archive_format('xxx')
1134
1135 def test_register_archive_format(self):
1136
1137 self.assertRaises(TypeError, register_archive_format, 'xxx', 1)
1138 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1139 1)
1140 self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x,
1141 [(1, 2), (1, 2, 3)])
1142
1143 register_archive_format('xxx', lambda: x, [(1, 2)], 'xxx file')
1144 formats = [name for name, params in get_archive_formats()]
1145 self.assertIn('xxx', formats)
1146
1147 unregister_archive_format('xxx')
1148 formats = [name for name, params in get_archive_formats()]
1149 self.assertNotIn('xxx', formats)
1150
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001151 def _compare_dirs(self, dir1, dir2):
1152 # check that dir1 and dir2 are equivalent,
1153 # return the diff
1154 diff = []
1155 for root, dirs, files in os.walk(dir1):
1156 for file_ in files:
1157 path = os.path.join(root, file_)
1158 target_path = os.path.join(dir2, os.path.split(path)[-1])
1159 if not os.path.exists(target_path):
1160 diff.append(file_)
1161 return diff
1162
Ezio Melotti975077a2011-05-19 22:03:22 +03001163 @requires_zlib
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001164 def test_unpack_archive(self):
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001165 formats = ['tar', 'gztar', 'zip']
1166 if BZ2_SUPPORTED:
1167 formats.append('bztar')
Serhiy Storchaka11213772014-08-06 18:50:19 +03001168 if LZMA_SUPPORTED:
1169 formats.append('xztar')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001170
Tarek Ziadéffa155a2010-04-29 13:34:35 +00001171 for format in formats:
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001172 tmpdir = self.mkdtemp()
1173 base_dir, root_dir, base_name = self._create_files()
1174 tmpdir2 = self.mkdtemp()
1175 filename = make_archive(base_name, format, root_dir, base_dir)
1176
1177 # let's try to unpack it now
1178 unpack_archive(filename, tmpdir2)
1179 diff = self._compare_dirs(tmpdir, tmpdir2)
Ezio Melottib3aedd42010-11-20 19:04:17 +00001180 self.assertEqual(diff, [])
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001181
Nick Coghlanabf202d2011-03-16 13:52:20 -04001182 # and again, this time with the format specified
1183 tmpdir3 = self.mkdtemp()
1184 unpack_archive(filename, tmpdir3, format=format)
1185 diff = self._compare_dirs(tmpdir, tmpdir3)
1186 self.assertEqual(diff, [])
1187 self.assertRaises(shutil.ReadError, unpack_archive, TESTFN)
1188 self.assertRaises(ValueError, unpack_archive, TESTFN, format='xxx')
1189
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001190 def test_unpack_registery(self):
1191
1192 formats = get_unpack_formats()
1193
1194 def _boo(filename, extract_dir, extra):
Ezio Melottib3aedd42010-11-20 19:04:17 +00001195 self.assertEqual(extra, 1)
1196 self.assertEqual(filename, 'stuff.boo')
1197 self.assertEqual(extract_dir, 'xx')
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001198
1199 register_unpack_format('Boo', ['.boo', '.b2'], _boo, [('extra', 1)])
1200 unpack_archive('stuff.boo', 'xx')
1201
1202 # trying to register a .boo unpacker again
1203 self.assertRaises(RegistryError, register_unpack_format, 'Boo2',
1204 ['.boo'], _boo)
1205
1206 # should work now
1207 unregister_unpack_format('Boo')
1208 register_unpack_format('Boo2', ['.boo'], _boo)
1209 self.assertIn(('Boo2', ['.boo'], ''), get_unpack_formats())
1210 self.assertNotIn(('Boo', ['.boo'], ''), get_unpack_formats())
1211
1212 # let's leave a clean state
1213 unregister_unpack_format('Boo2')
Ezio Melottib3aedd42010-11-20 19:04:17 +00001214 self.assertEqual(get_unpack_formats(), formats)
Tarek Ziadé6ac91722010-04-28 17:51:36 +00001215
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001216 @unittest.skipUnless(hasattr(shutil, 'disk_usage'),
1217 "disk_usage not available on this platform")
1218 def test_disk_usage(self):
1219 usage = shutil.disk_usage(os.getcwd())
Éric Araujo2ee61882011-07-02 16:45:45 +02001220 self.assertGreater(usage.total, 0)
1221 self.assertGreater(usage.used, 0)
1222 self.assertGreaterEqual(usage.free, 0)
1223 self.assertGreaterEqual(usage.total, usage.used)
1224 self.assertGreater(usage.total, usage.free)
Giampaolo Rodola'210e7ca2011-07-01 13:55:36 +02001225
Sandro Tosid902a142011-08-22 23:28:27 +02001226 @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support")
1227 @unittest.skipUnless(hasattr(os, 'chown'), 'requires os.chown')
1228 def test_chown(self):
1229
1230 # cleaned-up automatically by TestShutil.tearDown method
1231 dirname = self.mkdtemp()
1232 filename = tempfile.mktemp(dir=dirname)
1233 write_file(filename, 'testing chown function')
1234
1235 with self.assertRaises(ValueError):
1236 shutil.chown(filename)
1237
1238 with self.assertRaises(LookupError):
1239 shutil.chown(filename, user='non-exising username')
1240
1241 with self.assertRaises(LookupError):
1242 shutil.chown(filename, group='non-exising groupname')
1243
1244 with self.assertRaises(TypeError):
1245 shutil.chown(filename, b'spam')
1246
1247 with self.assertRaises(TypeError):
1248 shutil.chown(filename, 3.14)
1249
1250 uid = os.getuid()
1251 gid = os.getgid()
1252
1253 def check_chown(path, uid=None, gid=None):
1254 s = os.stat(filename)
1255 if uid is not None:
1256 self.assertEqual(uid, s.st_uid)
1257 if gid is not None:
1258 self.assertEqual(gid, s.st_gid)
1259
1260 shutil.chown(filename, uid, gid)
1261 check_chown(filename, uid, gid)
1262 shutil.chown(filename, uid)
1263 check_chown(filename, uid)
1264 shutil.chown(filename, user=uid)
1265 check_chown(filename, uid)
1266 shutil.chown(filename, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001267 check_chown(filename, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001268
1269 shutil.chown(dirname, uid, gid)
1270 check_chown(dirname, uid, gid)
1271 shutil.chown(dirname, uid)
1272 check_chown(dirname, uid)
1273 shutil.chown(dirname, user=uid)
1274 check_chown(dirname, uid)
1275 shutil.chown(dirname, group=gid)
Sandro Tosi91f948a2011-08-22 23:55:39 +02001276 check_chown(dirname, gid=gid)
Sandro Tosid902a142011-08-22 23:28:27 +02001277
1278 user = pwd.getpwuid(uid)[0]
1279 group = grp.getgrgid(gid)[0]
1280 shutil.chown(filename, user, group)
1281 check_chown(filename, uid, gid)
1282 shutil.chown(dirname, user, group)
1283 check_chown(dirname, uid, gid)
1284
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001285 def test_copy_return_value(self):
1286 # copy and copy2 both return their destination path.
1287 for fn in (shutil.copy, shutil.copy2):
1288 src_dir = self.mkdtemp()
1289 dst_dir = self.mkdtemp()
1290 src = os.path.join(src_dir, 'foo')
1291 write_file(src, 'foo')
1292 rv = fn(src, dst_dir)
1293 self.assertEqual(rv, os.path.join(dst_dir, 'foo'))
1294 rv = fn(src, os.path.join(dst_dir, 'bar'))
1295 self.assertEqual(rv, os.path.join(dst_dir, 'bar'))
1296
1297 def test_copyfile_return_value(self):
1298 # copytree returns its destination path.
1299 src_dir = self.mkdtemp()
1300 dst_dir = self.mkdtemp()
1301 dst_file = os.path.join(dst_dir, 'bar')
1302 src_file = os.path.join(src_dir, 'foo')
1303 write_file(src_file, 'foo')
1304 rv = shutil.copyfile(src_file, dst_file)
1305 self.assertTrue(os.path.exists(rv))
1306 self.assertEqual(read_file(src_file), read_file(dst_file))
1307
Hynek Schlawack48653762012-10-07 12:49:58 +02001308 def test_copyfile_same_file(self):
1309 # copyfile() should raise SameFileError if the source and destination
1310 # are the same.
1311 src_dir = self.mkdtemp()
1312 src_file = os.path.join(src_dir, 'foo')
1313 write_file(src_file, 'foo')
1314 self.assertRaises(SameFileError, shutil.copyfile, src_file, src_file)
Hynek Schlawack27ddb572012-10-28 13:59:27 +01001315 # But Error should work too, to stay backward compatible.
1316 self.assertRaises(Error, shutil.copyfile, src_file, src_file)
Hynek Schlawack48653762012-10-07 12:49:58 +02001317
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001318 def test_copytree_return_value(self):
1319 # copytree returns its destination path.
1320 src_dir = self.mkdtemp()
1321 dst_dir = src_dir + "dest"
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001322 self.addCleanup(shutil.rmtree, dst_dir, True)
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001323 src = os.path.join(src_dir, 'foo')
1324 write_file(src, 'foo')
1325 rv = shutil.copytree(src_dir, dst_dir)
1326 self.assertEqual(['foo'], os.listdir(rv))
1327
Christian Heimes9bd667a2008-01-20 15:14:11 +00001328
Brian Curtinc57a3452012-06-22 16:00:30 -05001329class TestWhich(unittest.TestCase):
1330
1331 def setUp(self):
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001332 self.temp_dir = tempfile.mkdtemp(prefix="Tmp")
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001333 self.addCleanup(shutil.rmtree, self.temp_dir, True)
Brian Curtinc57a3452012-06-22 16:00:30 -05001334 # Give the temp_file an ".exe" suffix for all.
1335 # It's needed on Windows and not harmful on other platforms.
1336 self.temp_file = tempfile.NamedTemporaryFile(dir=self.temp_dir,
Serhiy Storchaka014791f2013-01-21 15:00:27 +02001337 prefix="Tmp",
1338 suffix=".Exe")
Brian Curtinc57a3452012-06-22 16:00:30 -05001339 os.chmod(self.temp_file.name, stat.S_IXUSR)
1340 self.addCleanup(self.temp_file.close)
1341 self.dir, self.file = os.path.split(self.temp_file.name)
1342
1343 def test_basic(self):
1344 # Given an EXE in a directory, it should be returned.
1345 rv = shutil.which(self.file, path=self.dir)
1346 self.assertEqual(rv, self.temp_file.name)
1347
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001348 def test_absolute_cmd(self):
Brian Curtinc57a3452012-06-22 16:00:30 -05001349 # When given the fully qualified path to an executable that exists,
1350 # it should be returned.
1351 rv = shutil.which(self.temp_file.name, path=self.temp_dir)
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001352 self.assertEqual(rv, self.temp_file.name)
1353
1354 def test_relative_cmd(self):
1355 # When given the relative path with a directory part to an executable
1356 # that exists, it should be returned.
1357 base_dir, tail_dir = os.path.split(self.dir)
1358 relpath = os.path.join(tail_dir, self.file)
Nick Coghlan55175962013-07-28 22:11:50 +10001359 with support.change_cwd(path=base_dir):
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001360 rv = shutil.which(relpath, path=self.temp_dir)
1361 self.assertEqual(rv, relpath)
1362 # But it shouldn't be searched in PATH directories (issue #16957).
Nick Coghlan55175962013-07-28 22:11:50 +10001363 with support.change_cwd(path=self.dir):
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001364 rv = shutil.which(relpath, path=base_dir)
1365 self.assertIsNone(rv)
1366
1367 def test_cwd(self):
1368 # Issue #16957
1369 base_dir = os.path.dirname(self.dir)
Nick Coghlan55175962013-07-28 22:11:50 +10001370 with support.change_cwd(path=self.dir):
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001371 rv = shutil.which(self.file, path=base_dir)
1372 if sys.platform == "win32":
1373 # Windows: current directory implicitly on PATH
1374 self.assertEqual(rv, os.path.join(os.curdir, self.file))
1375 else:
1376 # Other platforms: shouldn't match in the current directory.
1377 self.assertIsNone(rv)
Brian Curtinc57a3452012-06-22 16:00:30 -05001378
Serhiy Storchaka12516e22013-05-28 15:50:15 +03001379 @unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0,
1380 'non-root user required')
Brian Curtinc57a3452012-06-22 16:00:30 -05001381 def test_non_matching_mode(self):
1382 # Set the file read-only and ask for writeable files.
1383 os.chmod(self.temp_file.name, stat.S_IREAD)
Serhiy Storchaka12516e22013-05-28 15:50:15 +03001384 if os.access(self.temp_file.name, os.W_OK):
1385 self.skipTest("can't set the file read-only")
Brian Curtinc57a3452012-06-22 16:00:30 -05001386 rv = shutil.which(self.file, path=self.dir, mode=os.W_OK)
1387 self.assertIsNone(rv)
1388
Serhiy Storchaka8bea2002013-01-23 10:44:21 +02001389 def test_relative_path(self):
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001390 base_dir, tail_dir = os.path.split(self.dir)
Nick Coghlan55175962013-07-28 22:11:50 +10001391 with support.change_cwd(path=base_dir):
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001392 rv = shutil.which(self.file, path=tail_dir)
1393 self.assertEqual(rv, os.path.join(tail_dir, self.file))
Antoine Pitrou07c24d12012-06-22 23:33:05 +02001394
Brian Curtinc57a3452012-06-22 16:00:30 -05001395 def test_nonexistent_file(self):
1396 # Return None when no matching executable file is found on the path.
1397 rv = shutil.which("foo.exe", path=self.dir)
1398 self.assertIsNone(rv)
1399
1400 @unittest.skipUnless(sys.platform == "win32",
1401 "pathext check is Windows-only")
1402 def test_pathext_checking(self):
1403 # Ask for the file without the ".exe" extension, then ensure that
1404 # it gets found properly with the extension.
Serhiy Storchakad70127a2013-01-24 20:03:49 +02001405 rv = shutil.which(self.file[:-4], path=self.dir)
Serhiy Storchaka80c88f42013-01-22 10:31:36 +02001406 self.assertEqual(rv, self.temp_file.name[:-4] + ".EXE")
Brian Curtinc57a3452012-06-22 16:00:30 -05001407
Barry Warsaw618738b2013-04-16 11:05:03 -04001408 def test_environ_path(self):
1409 with 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)
1412 self.assertEqual(rv, self.temp_file.name)
1413
1414 def test_empty_path(self):
1415 base_dir = os.path.dirname(self.dir)
Nick Coghlan55175962013-07-28 22:11:50 +10001416 with support.change_cwd(path=self.dir), \
Barry Warsaw618738b2013-04-16 11:05:03 -04001417 support.EnvironmentVarGuard() as env:
Victor Stinner1d006a22013-12-16 23:39:40 +01001418 env['PATH'] = self.dir
Barry Warsaw618738b2013-04-16 11:05:03 -04001419 rv = shutil.which(self.file, path='')
1420 self.assertIsNone(rv)
1421
1422 def test_empty_path_no_PATH(self):
1423 with support.EnvironmentVarGuard() as env:
1424 env.pop('PATH', None)
1425 rv = shutil.which(self.file)
1426 self.assertIsNone(rv)
1427
Brian Curtinc57a3452012-06-22 16:00:30 -05001428
Christian Heimesada8c3b2008-03-18 18:26:33 +00001429class TestMove(unittest.TestCase):
1430
1431 def setUp(self):
1432 filename = "foo"
1433 self.src_dir = tempfile.mkdtemp()
1434 self.dst_dir = tempfile.mkdtemp()
1435 self.src_file = os.path.join(self.src_dir, filename)
1436 self.dst_file = os.path.join(self.dst_dir, filename)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001437 with open(self.src_file, "wb") as f:
1438 f.write(b"spam")
1439
1440 def tearDown(self):
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001441 for d in (self.src_dir, self.dst_dir):
Christian Heimesada8c3b2008-03-18 18:26:33 +00001442 try:
1443 if d:
1444 shutil.rmtree(d)
1445 except:
1446 pass
1447
1448 def _check_move_file(self, src, dst, real_dst):
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001449 with open(src, "rb") as f:
1450 contents = f.read()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001451 shutil.move(src, dst)
Antoine Pitrou92f60ed2010-10-14 22:11:44 +00001452 with open(real_dst, "rb") as f:
1453 self.assertEqual(contents, f.read())
Christian Heimesada8c3b2008-03-18 18:26:33 +00001454 self.assertFalse(os.path.exists(src))
1455
1456 def _check_move_dir(self, src, dst, real_dst):
1457 contents = sorted(os.listdir(src))
1458 shutil.move(src, dst)
1459 self.assertEqual(contents, sorted(os.listdir(real_dst)))
1460 self.assertFalse(os.path.exists(src))
1461
1462 def test_move_file(self):
1463 # Move a file to another location on the same filesystem.
1464 self._check_move_file(self.src_file, self.dst_file, self.dst_file)
1465
1466 def test_move_file_to_dir(self):
1467 # Move a file inside an existing dir on the same filesystem.
1468 self._check_move_file(self.src_file, self.dst_dir, self.dst_file)
1469
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001470 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001471 def test_move_file_other_fs(self):
1472 # Move a file to an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001473 self.test_move_file()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001474
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001475 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001476 def test_move_file_to_dir_other_fs(self):
1477 # Move a file to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001478 self.test_move_file_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001479
1480 def test_move_dir(self):
1481 # Move a dir to another location on the same filesystem.
1482 dst_dir = tempfile.mktemp()
1483 try:
1484 self._check_move_dir(self.src_dir, dst_dir, dst_dir)
1485 finally:
1486 try:
1487 shutil.rmtree(dst_dir)
1488 except:
1489 pass
1490
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001491 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001492 def test_move_dir_other_fs(self):
1493 # Move a dir to another location on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001494 self.test_move_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001495
1496 def test_move_dir_to_dir(self):
1497 # Move a dir inside an existing dir on the same filesystem.
1498 self._check_move_dir(self.src_dir, self.dst_dir,
1499 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1500
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001501 @mock_rename
Christian Heimesada8c3b2008-03-18 18:26:33 +00001502 def test_move_dir_to_dir_other_fs(self):
1503 # Move a dir inside an existing dir on another filesystem.
Nick Coghlan8ed3cf32011-03-16 14:05:35 -04001504 self.test_move_dir_to_dir()
Christian Heimesada8c3b2008-03-18 18:26:33 +00001505
Serhiy Storchaka3a308b92014-02-11 10:30:59 +02001506 def test_move_dir_sep_to_dir(self):
1507 self._check_move_dir(self.src_dir + os.path.sep, self.dst_dir,
1508 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1509
1510 @unittest.skipUnless(os.path.altsep, 'requires os.path.altsep')
1511 def test_move_dir_altsep_to_dir(self):
1512 self._check_move_dir(self.src_dir + os.path.altsep, self.dst_dir,
1513 os.path.join(self.dst_dir, os.path.basename(self.src_dir)))
1514
Christian Heimesada8c3b2008-03-18 18:26:33 +00001515 def test_existing_file_inside_dest_dir(self):
1516 # A file with the same name inside the destination dir already exists.
1517 with open(self.dst_file, "wb"):
1518 pass
1519 self.assertRaises(shutil.Error, shutil.move, self.src_file, self.dst_dir)
1520
1521 def test_dont_move_dir_in_itself(self):
1522 # Moving a dir inside itself raises an Error.
1523 dst = os.path.join(self.src_dir, "bar")
1524 self.assertRaises(shutil.Error, shutil.move, self.src_dir, dst)
1525
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001526 def test_destinsrc_false_negative(self):
1527 os.mkdir(TESTFN)
1528 try:
1529 for src, dst in [('srcdir', 'srcdir/dest')]:
1530 src = os.path.join(TESTFN, src)
1531 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001532 self.assertTrue(shutil._destinsrc(src, dst),
Benjamin Peterson247a9b82009-02-20 04:09:19 +00001533 msg='_destinsrc() wrongly concluded that '
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001534 'dst (%s) is not in src (%s)' % (dst, src))
1535 finally:
1536 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimesada8c3b2008-03-18 18:26:33 +00001537
Antoine Pitrou0dcc3cd2009-01-29 20:26:59 +00001538 def test_destinsrc_false_positive(self):
1539 os.mkdir(TESTFN)
1540 try:
1541 for src, dst in [('srcdir', 'src/dest'), ('srcdir', 'srcdir.new')]:
1542 src = os.path.join(TESTFN, src)
1543 dst = os.path.join(TESTFN, dst)
Benjamin Petersonc9c0f202009-06-30 23:06:06 +00001544 self.assertFalse(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 in src (%s)' % (dst, src))
1547 finally:
1548 shutil.rmtree(TESTFN, ignore_errors=True)
Christian Heimes9bd667a2008-01-20 15:14:11 +00001549
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +01001550 @support.skip_unless_symlink
1551 @mock_rename
1552 def test_move_file_symlink(self):
1553 dst = os.path.join(self.src_dir, 'bar')
1554 os.symlink(self.src_file, dst)
1555 shutil.move(dst, self.dst_file)
1556 self.assertTrue(os.path.islink(self.dst_file))
1557 self.assertTrue(os.path.samefile(self.src_file, self.dst_file))
1558
1559 @support.skip_unless_symlink
1560 @mock_rename
1561 def test_move_file_symlink_to_dir(self):
1562 filename = "bar"
1563 dst = os.path.join(self.src_dir, filename)
1564 os.symlink(self.src_file, dst)
1565 shutil.move(dst, self.dst_dir)
1566 final_link = os.path.join(self.dst_dir, filename)
1567 self.assertTrue(os.path.islink(final_link))
1568 self.assertTrue(os.path.samefile(self.src_file, final_link))
1569
1570 @support.skip_unless_symlink
1571 @mock_rename
1572 def test_move_dangling_symlink(self):
1573 src = os.path.join(self.src_dir, 'baz')
1574 dst = os.path.join(self.src_dir, 'bar')
1575 os.symlink(src, dst)
1576 dst_link = os.path.join(self.dst_dir, 'quux')
1577 shutil.move(dst, dst_link)
1578 self.assertTrue(os.path.islink(dst_link))
Antoine Pitrou3f48ac92014-01-01 02:50:45 +01001579 # On Windows, os.path.realpath does not follow symlinks (issue #9949)
1580 if os.name == 'nt':
1581 self.assertEqual(os.path.realpath(src), os.readlink(dst_link))
1582 else:
1583 self.assertEqual(os.path.realpath(src), os.path.realpath(dst_link))
Antoine Pitrou0a08d7a2012-01-06 20:16:19 +01001584
1585 @support.skip_unless_symlink
1586 @mock_rename
1587 def test_move_dir_symlink(self):
1588 src = os.path.join(self.src_dir, 'baz')
1589 dst = os.path.join(self.src_dir, 'bar')
1590 os.mkdir(src)
1591 os.symlink(src, dst)
1592 dst_link = os.path.join(self.dst_dir, 'quux')
1593 shutil.move(dst, dst_link)
1594 self.assertTrue(os.path.islink(dst_link))
1595 self.assertTrue(os.path.samefile(src, dst_link))
1596
Brian Curtin0d0a1de2012-06-18 18:41:07 -05001597 def test_move_return_value(self):
1598 rv = shutil.move(self.src_file, self.dst_dir)
1599 self.assertEqual(rv,
1600 os.path.join(self.dst_dir, os.path.basename(self.src_file)))
1601
1602 def test_move_as_rename_return_value(self):
1603 rv = shutil.move(self.src_file, os.path.join(self.dst_dir, 'bar'))
1604 self.assertEqual(rv, os.path.join(self.dst_dir, 'bar'))
1605
R David Murray6ffface2014-06-11 14:40:13 -04001606 @mock_rename
1607 def test_move_file_special_function(self):
1608 moved = []
1609 def _copy(src, dst):
1610 moved.append((src, dst))
1611 shutil.move(self.src_file, self.dst_dir, copy_function=_copy)
1612 self.assertEqual(len(moved), 1)
1613
1614 @mock_rename
1615 def test_move_dir_special_function(self):
1616 moved = []
1617 def _copy(src, dst):
1618 moved.append((src, dst))
1619 support.create_empty_file(os.path.join(self.src_dir, 'child'))
1620 support.create_empty_file(os.path.join(self.src_dir, 'child1'))
1621 shutil.move(self.src_dir, self.dst_dir, copy_function=_copy)
1622 self.assertEqual(len(moved), 3)
1623
Tarek Ziadé5340db32010-04-19 22:30:51 +00001624
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001625class TestCopyFile(unittest.TestCase):
1626
1627 _delete = False
1628
1629 class Faux(object):
1630 _entered = False
1631 _exited_with = None
1632 _raised = False
1633 def __init__(self, raise_in_exit=False, suppress_at_exit=True):
1634 self._raise_in_exit = raise_in_exit
1635 self._suppress_at_exit = suppress_at_exit
1636 def read(self, *args):
1637 return ''
1638 def __enter__(self):
1639 self._entered = True
1640 def __exit__(self, exc_type, exc_val, exc_tb):
1641 self._exited_with = exc_type, exc_val, exc_tb
1642 if self._raise_in_exit:
1643 self._raised = True
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001644 raise OSError("Cannot close")
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001645 return self._suppress_at_exit
1646
1647 def tearDown(self):
1648 if self._delete:
1649 del shutil.open
1650
1651 def _set_shutil_open(self, func):
1652 shutil.open = func
1653 self._delete = True
1654
1655 def test_w_source_open_fails(self):
1656 def _open(filename, mode='r'):
1657 if filename == 'srcfile':
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001658 raise OSError('Cannot open "srcfile"')
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001659 assert 0 # shouldn't reach here.
1660
1661 self._set_shutil_open(_open)
1662
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001663 self.assertRaises(OSError, shutil.copyfile, 'srcfile', 'destfile')
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001664
1665 def test_w_dest_open_fails(self):
1666
1667 srcfile = self.Faux()
1668
1669 def _open(filename, mode='r'):
1670 if filename == 'srcfile':
1671 return srcfile
1672 if filename == 'destfile':
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001673 raise OSError('Cannot open "destfile"')
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001674 assert 0 # shouldn't reach here.
1675
1676 self._set_shutil_open(_open)
1677
1678 shutil.copyfile('srcfile', 'destfile')
1679 self.assertTrue(srcfile._entered)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001680 self.assertTrue(srcfile._exited_with[0] is OSError)
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001681 self.assertEqual(srcfile._exited_with[1].args,
1682 ('Cannot open "destfile"',))
1683
1684 def test_w_dest_close_fails(self):
1685
1686 srcfile = self.Faux()
1687 destfile = self.Faux(True)
1688
1689 def _open(filename, mode='r'):
1690 if filename == 'srcfile':
1691 return srcfile
1692 if filename == 'destfile':
1693 return destfile
1694 assert 0 # shouldn't reach here.
1695
1696 self._set_shutil_open(_open)
1697
1698 shutil.copyfile('srcfile', 'destfile')
1699 self.assertTrue(srcfile._entered)
1700 self.assertTrue(destfile._entered)
1701 self.assertTrue(destfile._raised)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001702 self.assertTrue(srcfile._exited_with[0] is OSError)
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001703 self.assertEqual(srcfile._exited_with[1].args,
1704 ('Cannot close',))
1705
1706 def test_w_source_close_fails(self):
1707
1708 srcfile = self.Faux(True)
1709 destfile = self.Faux()
1710
1711 def _open(filename, mode='r'):
1712 if filename == 'srcfile':
1713 return srcfile
1714 if filename == 'destfile':
1715 return destfile
1716 assert 0 # shouldn't reach here.
1717
1718 self._set_shutil_open(_open)
1719
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001720 self.assertRaises(OSError,
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001721 shutil.copyfile, 'srcfile', 'destfile')
1722 self.assertTrue(srcfile._entered)
1723 self.assertTrue(destfile._entered)
1724 self.assertFalse(destfile._raised)
1725 self.assertTrue(srcfile._exited_with[0] is None)
1726 self.assertTrue(srcfile._raised)
1727
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001728 def test_move_dir_caseinsensitive(self):
1729 # Renames a folder to the same name
1730 # but a different case.
1731
1732 self.src_dir = tempfile.mkdtemp()
Larry Hastings5b2f9c02012-06-25 23:50:01 -07001733 self.addCleanup(shutil.rmtree, self.src_dir, True)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001734 dst_dir = os.path.join(
1735 os.path.dirname(self.src_dir),
1736 os.path.basename(self.src_dir).upper())
1737 self.assertNotEqual(self.src_dir, dst_dir)
1738
1739 try:
1740 shutil.move(self.src_dir, dst_dir)
1741 self.assertTrue(os.path.isdir(dst_dir))
1742 finally:
Éric Araujoa7e33a12011-08-12 19:51:35 +02001743 os.rmdir(dst_dir)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001744
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001745class TermsizeTests(unittest.TestCase):
1746 def test_does_not_crash(self):
1747 """Check if get_terminal_size() returns a meaningful value.
1748
1749 There's no easy portable way to actually check the size of the
1750 terminal, so let's check if it returns something sensible instead.
1751 """
1752 size = shutil.get_terminal_size()
Antoine Pitroucfade362012-02-08 23:48:59 +01001753 self.assertGreaterEqual(size.columns, 0)
1754 self.assertGreaterEqual(size.lines, 0)
Antoine Pitroubcf2b592012-02-08 23:28:36 +01001755
1756 def test_os_environ_first(self):
1757 "Check if environment variables have precedence"
1758
1759 with support.EnvironmentVarGuard() as env:
1760 env['COLUMNS'] = '777'
1761 size = shutil.get_terminal_size()
1762 self.assertEqual(size.columns, 777)
1763
1764 with support.EnvironmentVarGuard() as env:
1765 env['LINES'] = '888'
1766 size = shutil.get_terminal_size()
1767 self.assertEqual(size.lines, 888)
1768
1769 @unittest.skipUnless(os.isatty(sys.__stdout__.fileno()), "not on tty")
1770 def test_stty_match(self):
1771 """Check if stty returns the same results ignoring env
1772
1773 This test will fail if stdin and stdout are connected to
1774 different terminals with different sizes. Nevertheless, such
1775 situations should be pretty rare.
1776 """
1777 try:
1778 size = subprocess.check_output(['stty', 'size']).decode().split()
1779 except (FileNotFoundError, subprocess.CalledProcessError):
1780 self.skipTest("stty invocation failed")
1781 expected = (int(size[1]), int(size[0])) # reversed order
1782
1783 with support.EnvironmentVarGuard() as env:
1784 del env['LINES']
1785 del env['COLUMNS']
1786 actual = shutil.get_terminal_size()
1787
1788 self.assertEqual(expected, actual)
Ronald Oussorenf51738b2011-05-06 10:23:04 +02001789
Tarek Ziadéae4d5c62010-05-05 22:27:31 +00001790
Barry Warsaw7fc2cca2003-01-24 17:34:13 +00001791if __name__ == '__main__':
Brett Cannon3e9a9ae2013-06-12 21:25:59 -04001792 unittest.main()