Merged revisions 80833 via svnmerge from

svn+ssh://pythondev@svn.python.org/python/branches/py3k

................
  r80833 | tarek.ziade | 2010-05-06 00:27:31 +0200 (Thu, 06 May 2010) | 9 lines

  Merged revisions 80830 via svnmerge from
  svn+ssh://pythondev@svn.python.org/python/trunk

  ........
    r80830 | tarek.ziade | 2010-05-06 00:15:31 +0200 (Thu, 06 May 2010) | 1 line

    Fixed #4265: shutil.copyfile() was leaking file descriptors when disk fills
  ........
................
This commit is contained in:
Tarek Ziadé 2010-05-05 22:39:31 +00:00
parent bc5f75cca2
commit 9623980d01
3 changed files with 112 additions and 10 deletions

View File

@ -63,15 +63,10 @@ def copyfile(src, dst):
# XXX What about other special files? (sockets, devices...) # XXX What about other special files? (sockets, devices...)
if stat.S_ISFIFO(st.st_mode): if stat.S_ISFIFO(st.st_mode):
raise SpecialFileError("`%s` is a named pipe" % fn) raise SpecialFileError("`%s` is a named pipe" % fn)
try:
fsrc = open(src, 'rb') with open(src, 'rb') as fsrc:
fdst = open(dst, 'wb') with open(dst, 'wb') as fdst:
copyfileobj(fsrc, fdst) copyfileobj(fsrc, fdst)
finally:
if fdst:
fdst.close()
if fsrc:
fsrc.close()
def copymode(src, dst): def copymode(src, dst):
"""Copy mode bits from src to dst""" """Copy mode bits from src to dst"""

View File

@ -415,8 +415,112 @@ class TestMove(unittest.TestCase):
finally: finally:
shutil.rmtree(TESTFN, ignore_errors=True) shutil.rmtree(TESTFN, ignore_errors=True)
class TestCopyFile(unittest.TestCase):
_delete = False
class Faux(object):
_entered = False
_exited_with = None
_raised = False
def __init__(self, raise_in_exit=False, suppress_at_exit=True):
self._raise_in_exit = raise_in_exit
self._suppress_at_exit = suppress_at_exit
def read(self, *args):
return ''
def __enter__(self):
self._entered = True
def __exit__(self, exc_type, exc_val, exc_tb):
self._exited_with = exc_type, exc_val, exc_tb
if self._raise_in_exit:
self._raised = True
raise IOError("Cannot close")
return self._suppress_at_exit
def tearDown(self):
if self._delete:
del shutil.open
def _set_shutil_open(self, func):
shutil.open = func
self._delete = True
def test_w_source_open_fails(self):
def _open(filename, mode='r'):
if filename == 'srcfile':
raise IOError('Cannot open "srcfile"')
assert 0 # shouldn't reach here.
self._set_shutil_open(_open)
self.assertRaises(IOError, shutil.copyfile, 'srcfile', 'destfile')
def test_w_dest_open_fails(self):
srcfile = self.Faux()
def _open(filename, mode='r'):
if filename == 'srcfile':
return srcfile
if filename == 'destfile':
raise IOError('Cannot open "destfile"')
assert 0 # shouldn't reach here.
self._set_shutil_open(_open)
shutil.copyfile('srcfile', 'destfile')
self.assertTrue(srcfile._entered)
self.assertTrue(srcfile._exited_with[0] is IOError)
self.assertEqual(srcfile._exited_with[1].args,
('Cannot open "destfile"',))
def test_w_dest_close_fails(self):
srcfile = self.Faux()
destfile = self.Faux(True)
def _open(filename, mode='r'):
if filename == 'srcfile':
return srcfile
if filename == 'destfile':
return destfile
assert 0 # shouldn't reach here.
self._set_shutil_open(_open)
shutil.copyfile('srcfile', 'destfile')
self.assertTrue(srcfile._entered)
self.assertTrue(destfile._entered)
self.assertTrue(destfile._raised)
self.assertTrue(srcfile._exited_with[0] is IOError)
self.assertEqual(srcfile._exited_with[1].args,
('Cannot close',))
def test_w_source_close_fails(self):
srcfile = self.Faux(True)
destfile = self.Faux()
def _open(filename, mode='r'):
if filename == 'srcfile':
return srcfile
if filename == 'destfile':
return destfile
assert 0 # shouldn't reach here.
self._set_shutil_open(_open)
self.assertRaises(IOError,
shutil.copyfile, 'srcfile', 'destfile')
self.assertTrue(srcfile._entered)
self.assertTrue(destfile._entered)
self.assertFalse(destfile._raised)
self.assertTrue(srcfile._exited_with[0] is None)
self.assertTrue(srcfile._raised)
def test_main(): def test_main():
support.run_unittest(TestShutil, TestMove) support.run_unittest(TestShutil, TestMove, TestCopyFile)
if __name__ == '__main__': if __name__ == '__main__':
test_main() test_main()

View File

@ -40,6 +40,9 @@ Core and Builtins
Library Library
------- -------
- Issue #4265: shutil.copyfile() was leaking file descriptors when disk fills.
Patch by Tres Seaver.
- Issue #8621: uuid.uuid4() returned the same sequence of values in the - Issue #8621: uuid.uuid4() returned the same sequence of values in the
parent and any children created using ``os.fork`` on MacOS X 10.6. parent and any children created using ``os.fork`` on MacOS X 10.6.