]> granicus.if.org Git - python/commitdiff
Merged revisions 60481,60485,60489-60492,60494-60496,60498-60499,60501-60503,60505...
authorChristian Heimes <christian@cheimes.de>
Sat, 9 Feb 2008 20:51:34 +0000 (20:51 +0000)
committerChristian Heimes <christian@cheimes.de>
Sat, 9 Feb 2008 20:51:34 +0000 (20:51 +0000)
svn+ssh://pythondev@svn.python.org/python/trunk

........
  r60679 | raymond.hettinger | 2008-02-09 02:18:42 +0100 (Sat, 09 Feb 2008) | 1 line

  Make ABC containers inherit as documented.
........
  r60684 | raymond.hettinger | 2008-02-09 04:34:52 +0100 (Sat, 09 Feb 2008) | 1 line

  Merge with r60683.
........
  r60687 | raymond.hettinger | 2008-02-09 05:37:49 +0100 (Sat, 09 Feb 2008) | 1 line

  Add -3 warnings that set.copy(), dict.copy(), and defaultdict.copy() will go away in Py3.x
........
  r60689 | raymond.hettinger | 2008-02-09 11:04:19 +0100 (Sat, 09 Feb 2008) | 1 line

  Metaclass declaration is inherited
........
  r60691 | raymond.hettinger | 2008-02-09 11:06:20 +0100 (Sat, 09 Feb 2008) | 1 line

  Temporarily disable this test. It's been broken for a week.
........
  r60695 | nick.coghlan | 2008-02-09 16:28:09 +0100 (Sat, 09 Feb 2008) | 1 line

  Issue 2021: Allow NamedTemporaryFile and SpooledTemporaryFile to be used as context managers. (The NamedTemporaryFile fix should be considered for backporting to 2.5)
........

Doc/library/tempfile.rst
Lib/io.py
Lib/tempfile.py
Lib/test/test_sys.py
Lib/test/test_tempfile.py
Modules/_collectionsmodule.c

index e38dbab1cbc97430df48519f5a03d920b13b0b8d..cc3318f252ae34ae245a4d77b1f4e682c1400604 100644 (file)
@@ -51,7 +51,8 @@ The module defines the following user-callable functions:
 
    The returned object is a true file object on POSIX platforms.  On other
    platforms, it is a file-like object whose :attr:`file` attribute is the
-   underlying true file object.
+   underlying true file object. This file-like object can be used in a :keyword:`with`
+   statement, just like a normal file.
 
 
 .. function:: NamedTemporaryFile([mode='w+b'[, bufsize=-1[, suffix[, prefix[, dir[, delete]]]]]])
@@ -64,7 +65,8 @@ The module defines the following user-callable functions:
    across platforms (it can be so used on Unix; it cannot on Windows NT or later).
    If *delete* is true (the default), the file is deleted as soon as it is closed.
    The returned object is always a file-like object whose :attr:`file` attribute
-   is the underlying true file object.
+   is the underlying true file object. This file-like object can be used in a :keyword:`with`
+   statement, just like a normal file.
 
 
 .. function:: SpooledTemporaryFile([max_size=0, [mode='w+b'[, bufsize=-1[, suffix[, prefix[, dir]]]]]])
@@ -79,7 +81,8 @@ The module defines the following user-callable functions:
 
    The returned object is a file-like object whose :attr:`_file` attribute
    is either a :class:`StringIO` object or a true file object, depending on
-   whether :func:`rollover` has been called.
+   whether :func:`rollover` has been called. This file-like object can be used in a
+   :keyword:`with` statement, just like a normal file.
 
 
 .. function:: mkstemp([suffix[, prefix[, dir[, text]]]])
index e427fe6969ab535239deef17a53652f8779a7866..01c31a9753cf79b1080128bb1045d6b8ac39fe56 100644 (file)
--- a/Lib/io.py
+++ b/Lib/io.py
@@ -365,6 +365,7 @@ class IOBase(metaclass=abc.ABCMeta):
 
     def __enter__(self) -> "IOBase":  # That's a forward reference
         """Context management protocol.  Returns self."""
+        self._checkClosed()
         return self
 
     def __exit__(self, *args) -> None:
index d725a9d0b64606544e90f58e5dbb75f8a5d29203..4f27f614a19312a607a30dd91891ac2198b89178 100644 (file)
@@ -363,6 +363,7 @@ def mktemp(suffix="", prefix=template, dir=None):
 
     raise IOError(_errno.EEXIST, "No usable temporary filename found")
 
+
 class _TemporaryFileWrapper:
     """Temporary file wrapper
 
@@ -378,17 +379,25 @@ class _TemporaryFileWrapper:
         self.delete = delete
 
     def __getattr__(self, name):
+        # Attribute lookups are delegated to the underlying file
+        # and cached for non-numeric results
+        # (i.e. methods are cached, closed and friends are not)
         file = self.__dict__['file']
         a = getattr(file, name)
-        if type(a) != type(0):
+        if not isinstance(a, int):
             setattr(self, name, a)
         return a
 
+    # The underlying __enter__ method returns the wrong object
+    # (self.file) so override it to return the wrapper
+    def __enter__(self):
+        self.file.__enter__()
+        return self
+
     # NT provides delete-on-close as a primitive, so we don't need
     # the wrapper to do anything special.  We still use it so that
     # file.name is useful (i.e. not "(fdopen)") with NamedTemporaryFile.
     if _os.name != 'nt':
-
         # Cache the unlinker so we don't get spurious errors at
         # shutdown when the module-level "os" is None'd out.  Note
         # that this must be referenced as self.unlink, because the
@@ -406,6 +415,14 @@ class _TemporaryFileWrapper:
         def __del__(self):
             self.close()
 
+        # Need to trap __exit__ as well to ensure the file gets
+        # deleted when used in a with statement
+        def __exit__(self, exc, value, tb):
+            result = self.file.__exit__(exc, value, tb)
+            self.close()
+            return result
+
+
 def NamedTemporaryFile(mode='w+b', buffering=-1, encoding=None,
                        newline=None, suffix="", prefix=template,
                        dir=None, delete=True):
@@ -523,6 +540,20 @@ class SpooledTemporaryFile:
 
         self._rolled = True
 
+    # The method caching trick from NamedTemporaryFile
+    # won't work here, because _file may change from a
+    # _StringIO instance to a real file. So we list
+    # all the methods directly.
+
+    # Context management protocol
+    def __enter__(self):
+        if self._file.closed:
+            raise ValueError("Cannot enter context with closed file")
+        return self
+
+    def __exit__(self, exc, value, tb):
+        self._file.close()
+
     # file protocol
     def __iter__(self):
         return self._file.__iter__()
index d8d74d06d694661ebcea8041f853a4a52028af03..7961837e53461433b5690be60251e61be68dd363 100644 (file)
@@ -336,17 +336,17 @@ class SysModuleTest(unittest.TestCase):
     def test_compact_freelists(self):
         sys._compact_freelists()
         r = sys._compact_freelists()
-        # freed blocks shouldn't change
-        self.assertEqual(r[0][2], 0)
-        # fill freelists
-        ints = list(range(10000))
-        floats = [float(i) for i in ints]
-        del ints
-        del floats
-        # should free more than 100 blocks
-        r = sys._compact_freelists()
-        self.assert_(r[0][1] > 100, r[0][1])
-        self.assert_(r[0][2] > 100, r[0][2])
+        ## freed blocks shouldn't change
+        #self.assertEqual(r[0][2], 0)
+        ## fill freelists
+        #ints = list(range(10000))
+        #floats = [float(i) for i in ints]
+        #del ints
+        #del floats
+        ## should free more than 100 blocks
+        #r = sys._compact_freelists()
+        #self.assert_(r[0][1] > 100, r[0][1])
+        #self.assert_(r[0][2] > 100, r[0][2])
 
 def test_main():
     test.test_support.run_unittest(SysModuleTest)
index 1e41f9ef29937919e22424bbe9fc9a45f94ed010..e88efebbd82dae2999799ccf98575887ebf8c2b9 100644 (file)
@@ -1,5 +1,4 @@
 # tempfile.py unit tests.
-
 import tempfile
 import os
 import sys
@@ -619,7 +618,6 @@ class test_NamedTemporaryFile(TC):
 
     def test_multiple_close(self):
         # A NamedTemporaryFile can be closed many times without error
-
         f = tempfile.NamedTemporaryFile()
         f.write(b'abc\n')
         f.close()
@@ -629,6 +627,16 @@ class test_NamedTemporaryFile(TC):
         except:
             self.failOnException("close")
 
+    def test_context_manager(self):
+        # A NamedTemporaryFile can be used as a context manager
+        with tempfile.NamedTemporaryFile() as f:
+            self.failUnless(os.path.exists(f.name))
+        self.failIf(os.path.exists(f.name))
+        def use_closed():
+            with f:
+                pass
+        self.failUnlessRaises(ValueError, use_closed)
+
     # How to test the mode and bufsize parameters?
 
 test_classes.append(test_NamedTemporaryFile)
@@ -707,10 +715,23 @@ class test_SpooledTemporaryFile(TC):
         self.failUnless(f.fileno() > 0)
         self.failUnless(f._rolled)
 
-    def test_multiple_close(self):
+    def test_multiple_close_before_rollover(self):
         # A SpooledTemporaryFile can be closed many times without error
         f = tempfile.SpooledTemporaryFile()
         f.write(b'abc\n')
+        self.failIf(f._rolled)
+        f.close()
+        try:
+            f.close()
+            f.close()
+        except:
+            self.failOnException("close")
+
+    def test_multiple_close_after_rollover(self):
+        # A SpooledTemporaryFile can be closed many times without error
+        f = tempfile.SpooledTemporaryFile(max_size=1)
+        f.write(b'abc\n')
+        self.failUnless(f._rolled)
         f.close()
         try:
             f.close()
@@ -759,6 +780,46 @@ class test_SpooledTemporaryFile(TC):
         self.assertEqual(f.read(), "\u039B\r\n" + ("\u039B" * 20) + "\r\n")
         self.failUnless(f._rolled)
 
+    def test_context_manager_before_rollover(self):
+        # A SpooledTemporaryFile can be used as a context manager
+        with tempfile.SpooledTemporaryFile(max_size=1) as f:
+            self.failIf(f._rolled)
+            self.failIf(f.closed)
+        self.failUnless(f.closed)
+        def use_closed():
+            with f:
+                pass
+        self.failUnlessRaises(ValueError, use_closed)
+
+    def test_context_manager_during_rollover(self):
+        # A SpooledTemporaryFile can be used as a context manager
+        with tempfile.SpooledTemporaryFile(max_size=1) as f:
+            self.failIf(f._rolled)
+            f.write(b'abc\n')
+            f.flush()
+            self.failUnless(f._rolled)
+            self.failIf(f.closed)
+        self.failUnless(f.closed)
+        def use_closed():
+            with f:
+                pass
+        self.failUnlessRaises(ValueError, use_closed)
+
+    def test_context_manager_after_rollover(self):
+        # A SpooledTemporaryFile can be used as a context manager
+        f = tempfile.SpooledTemporaryFile(max_size=1)
+        f.write(b'abc\n')
+        f.flush()
+        self.failUnless(f._rolled)
+        with f:
+            self.failIf(f.closed)
+        self.failUnless(f.closed)
+        def use_closed():
+            with f:
+                pass
+        self.failUnlessRaises(ValueError, use_closed)
+
+
 test_classes.append(test_SpooledTemporaryFile)
 
 
index 4bcc1fddfccb539939eebeb5b9a61ec29701a348..87d744dbee81e3e7c71a95d4fb19e88b324acfb4 100644 (file)
@@ -1127,7 +1127,7 @@ defdict_copy(defdictobject *dd)
 {
        /* This calls the object's class.  That only works for subclasses
           whose class constructor has the same signature.  Subclasses that
-          define a different constructor signature must override copy().
+          define a different constructor signature must override __copy__().
        */
        return PyObject_CallFunctionObjArgs((PyObject*)Py_TYPE(dd),
                                            dd->default_factory, dd, NULL);
@@ -1182,8 +1182,6 @@ defdict_reduce(defdictobject *dd)
 static PyMethodDef defdict_methods[] = {
        {"__missing__", (PyCFunction)defdict_missing, METH_O,
         defdict_missing_doc},
-       {"copy", (PyCFunction)defdict_copy, METH_NOARGS,
-        defdict_copy_doc},
        {"__copy__", (PyCFunction)defdict_copy, METH_NOARGS,
         defdict_copy_doc},
        {"__reduce__", (PyCFunction)defdict_reduce, METH_NOARGS,