[Python-checkins] r80831 - in python/branches/release26-maint: Lib/shutil.py Lib/test/test_shutil.py Misc/NEWS

tarek.ziade python-checkins at python.org
Thu May 6 00:21:13 CEST 2010


Author: tarek.ziade
Date: Thu May  6 00:21:13 2010
New Revision: 80831

Log:
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
........


Modified:
   python/branches/release26-maint/   (props changed)
   python/branches/release26-maint/Lib/shutil.py
   python/branches/release26-maint/Lib/test/test_shutil.py
   python/branches/release26-maint/Misc/NEWS

Modified: python/branches/release26-maint/Lib/shutil.py
==============================================================================
--- python/branches/release26-maint/Lib/shutil.py	(original)
+++ python/branches/release26-maint/Lib/shutil.py	Thu May  6 00:21:13 2010
@@ -45,19 +45,11 @@
 def copyfile(src, dst):
     """Copy data from src to dst"""
     if _samefile(src, dst):
-        raise Error, "`%s` and `%s` are the same file" % (src, dst)
+        raise Error("`%s` and `%s` are the same file" % (src, dst))
 
-    fsrc = None
-    fdst = None
-    try:
-        fsrc = open(src, 'rb')
-        fdst = open(dst, 'wb')
-        copyfileobj(fsrc, fdst)
-    finally:
-        if fdst:
-            fdst.close()
-        if fsrc:
-            fsrc.close()
+    with open(src, 'rb') as fsrc:
+        with open(dst, 'wb') as fdst:
+            copyfileobj(fsrc, fdst)
 
 def copymode(src, dst):
     """Copy mode bits from src to dst"""

Modified: python/branches/release26-maint/Lib/test/test_shutil.py
==============================================================================
--- python/branches/release26-maint/Lib/test/test_shutil.py	(original)
+++ python/branches/release26-maint/Lib/test/test_shutil.py	Thu May  6 00:21:13 2010
@@ -367,8 +367,113 @@
         finally:
             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.failUnless(srcfile._entered)
+        self.failUnless(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.failUnless(srcfile._entered)
+        self.failUnless(destfile._entered)
+        self.failUnless(destfile._raised)
+        self.failUnless(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.failUnless(srcfile._entered)
+        self.failUnless(destfile._entered)
+        self.failIf(destfile._raised)
+        self.failUnless(srcfile._exited_with[0] is None)
+        self.failUnless(srcfile._raised)
+
+
 def test_main():
-    test_support.run_unittest(TestShutil, TestMove)
+    test_support.run_unittest(TestShutil, TestMove, TestCopyFile)
 
 if __name__ == '__main__':
     test_main()

Modified: python/branches/release26-maint/Misc/NEWS
==============================================================================
--- python/branches/release26-maint/Misc/NEWS	(original)
+++ python/branches/release26-maint/Misc/NEWS	Thu May  6 00:21:13 2010
@@ -33,6 +33,9 @@
 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
   parent and any children created using ``os.fork`` on MacOS X 10.6.
 


More information about the Python-checkins mailing list