]> granicus.if.org Git - python/commitdiff
Issue #1706039: Support continued reading from a file even after
authorMartin v. Löwis <martin@v.loewis.de>
Sat, 13 Dec 2008 15:36:49 +0000 (15:36 +0000)
committerMartin v. Löwis <martin@v.loewis.de>
Sat, 13 Dec 2008 15:36:49 +0000 (15:36 +0000)
EOF was hit.

Lib/test/test_file.py
Misc/NEWS
Objects/fileobject.c

index ba6ea47edf7c8ab19d73c81104d112fcccc74880..830871098e1d12f718684ee44f9450f6f55babf5 100644 (file)
@@ -355,6 +355,48 @@ class StdoutTests(unittest.TestCase):
         finally:
             sys.stdout = save_stdout
 
+    def testReadAfterEOF(self):
+        # Regression test for SF bug #1523853.
+        # Verify read works after hitting EOF
+
+        # Prepare the testfile
+        teststring = "spam"
+        bag = open(TESTFN, "w")
+        bag.write(teststring)
+        bag.close()
+
+        # And buf for readinto
+        buf = array("c", " "*len(teststring))
+
+        # Test for appropriate errors mixing read* and iteration
+        methods = [("readline", ()), ("read",()), ("readlines", ()),
+                   ("readinto", (buf,))]
+
+        for attr in 'r', 'rU':
+            for methodname, args in methods:
+                f = open(TESTFN, "rU")
+                f.seek(0, 2)
+                meth = getattr(f, methodname)
+                meth(*args) # hits EOF
+                try:
+                    # Writing the same file with another file descriptor
+                    append = open(TESTFN, "a+")
+                    append.write(teststring)
+                    append.flush()
+                    append.close()
+                    try:
+                        meth = getattr(f, methodname)
+                        if methodname == 'readlines':
+                            self.failUnlessEqual(meth(*args), [teststring])
+                        elif methodname == 'readinto':
+                            meth(*args)
+                            self.failUnlessEqual(buf.tostring(), teststring)
+                        else:
+                            self.failUnlessEqual(meth(*args), teststring)
+                    except ValueError:
+                        self.fail("read* failed after hitting EOF")
+                finally:
+                    f.close()
 
 def test_main():
     # Historically, these tests have been sloppy about removing TESTFN.
index fa5ceb6fc45ed5e3fdb7d718977b5ac88c869b7e..18af6d09f4d7c7c2067afb4179dbd7921050ec67 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -12,6 +12,9 @@ What's New in Python 2.5.3?
 Core and builtins
 -----------------
 
+- Issue #1706039: Support continued reading from a file even after 
+  EOF was hit.
+
 - Issue #1683: prevent forking from interfering in threading storage.
 
 - Issue #4597: Fixed several opcodes that weren't always propagating
index 565bf5ca2f78c23f3adc256d9cb2f935a47aa941..5b76b0d0cc6673333cc4be5937ba71af791f870f 100644 (file)
@@ -861,16 +861,16 @@ file_read(PyFileObject *f, PyObject *args)
                          buffersize - bytesread, f->f_fp, (PyObject *)f);
                Py_END_ALLOW_THREADS
                if (chunksize == 0) {
-                       if (!ferror(f->f_fp))
+                       if (!PyErr_ExceptionMatches(PyExc_IOError))
                                break;
-                       clearerr(f->f_fp);
                        /* When in non-blocking mode, data shouldn't
                         * be discarded if a blocking signal was
                         * received. That will also happen if
                         * chunksize != 0, but bytesread < buffersize. */
-                       if (bytesread > 0 && BLOCKED_ERRNO(errno))
+                       if (bytesread > 0 && BLOCKED_ERRNO(errno)) {
+                               PyErr_Clear();
                                break;
-                       PyErr_SetFromErrno(PyExc_IOError);
+                       }
                        Py_DECREF(v);
                        return NULL;
                }
@@ -917,10 +917,8 @@ file_readinto(PyFileObject *f, PyObject *args)
                                                (PyObject *)f);
                Py_END_ALLOW_THREADS
                if (nnow == 0) {
-                       if (!ferror(f->f_fp))
+                       if (!PyErr_ExceptionMatches(PyExc_IOError))
                                break;
-                       PyErr_SetFromErrno(PyExc_IOError);
-                       clearerr(f->f_fp);
                        return NULL;
                }
                ndone += nnow;
@@ -1412,10 +1410,8 @@ file_readlines(PyFileObject *f, PyObject *args)
                }
                if (nread == 0) {
                        sizehint = 0;
-                       if (!ferror(f->f_fp))
+                       if (!PyErr_ExceptionMatches(PyExc_IOError))
                                break;
-                       PyErr_SetFromErrno(PyExc_IOError);
-                       clearerr(f->f_fp);
                  error:
                        Py_DECREF(list);
                        list = NULL;
@@ -1863,9 +1859,7 @@ readahead(PyFileObject *f, int bufsize)
                f->f_buf, bufsize, f->f_fp, (PyObject *)f);
        Py_END_ALLOW_THREADS
        if (chunksize == 0) {
-               if (ferror(f->f_fp)) {
-                       PyErr_SetFromErrno(PyExc_IOError);
-                       clearerr(f->f_fp);
+               if (PyErr_ExceptionMatches(PyExc_IOError)) {
                        drop_readahead(f);
                        return -1;
                }
@@ -2416,6 +2410,7 @@ Py_UniversalNewlineFread(char *buf, size_t n,
        char *dst = buf;
        PyFileObject *f = (PyFileObject *)fobj;
        int newlinetypes, skipnextlf;
+       size_t nread;
 
        assert(buf != NULL);
        assert(stream != NULL);
@@ -2424,22 +2419,35 @@ Py_UniversalNewlineFread(char *buf, size_t n,
                errno = ENXIO;  /* What can you do... */
                return 0;
        }
-       if (!f->f_univ_newline)
-               return fread(buf, 1, n, stream);
+       if (!f->f_univ_newline) {
+               nread = fread(buf, 1, n, stream);
+               if (nread == 0) {
+                       if (ferror(stream))
+                               PyErr_SetFromErrno(PyExc_IOError);
+                       clearerr(stream);
+               }
+               return nread;
+       }
        newlinetypes = f->f_newlinetypes;
        skipnextlf = f->f_skipnextlf;
        /* Invariant:  n is the number of bytes remaining to be filled
         * in the buffer.
         */
        while (n) {
-               size_t nread;
                int shortread;
                char *src = dst;
 
                nread = fread(dst, 1, n, stream);
                assert(nread <= n);
-               if (nread == 0)
+               if (nread == 0) {
+                       if (ferror(stream)) {
+                               clearerr(stream);
+                               PyErr_SetFromErrno(PyExc_IOError);
+                               return 0;
+                       }
+                       clearerr(stream);
                        break;
+               }
 
                n -= nread; /* assuming 1 byte out for each in; will adjust */
                shortread = n != 0;     /* true iff EOF or error */