[Python-checkins] r67740 - in python/branches/release25-maint: Lib/test/test_file.py Misc/NEWS Objects/fileobject.c
martin.v.loewis
python-checkins at python.org
Sat Dec 13 16:36:49 CET 2008
Author: martin.v.loewis
Date: Sat Dec 13 16:36:49 2008
New Revision: 67740
Log:
Issue #1706039: Support continued reading from a file even after
EOF was hit.
Modified:
python/branches/release25-maint/Lib/test/test_file.py
python/branches/release25-maint/Misc/NEWS
python/branches/release25-maint/Objects/fileobject.c
Modified: python/branches/release25-maint/Lib/test/test_file.py
==============================================================================
--- python/branches/release25-maint/Lib/test/test_file.py (original)
+++ python/branches/release25-maint/Lib/test/test_file.py Sat Dec 13 16:36:49 2008
@@ -355,6 +355,48 @@
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.
Modified: python/branches/release25-maint/Misc/NEWS
==============================================================================
--- python/branches/release25-maint/Misc/NEWS (original)
+++ python/branches/release25-maint/Misc/NEWS Sat Dec 13 16:36:49 2008
@@ -12,6 +12,9 @@
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
Modified: python/branches/release25-maint/Objects/fileobject.c
==============================================================================
--- python/branches/release25-maint/Objects/fileobject.c (original)
+++ python/branches/release25-maint/Objects/fileobject.c Sat Dec 13 16:36:49 2008
@@ -861,16 +861,16 @@
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 @@
(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 @@
}
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 @@
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 @@
char *dst = buf;
PyFileObject *f = (PyFileObject *)fobj;
int newlinetypes, skipnextlf;
+ size_t nread;
assert(buf != NULL);
assert(stream != NULL);
@@ -2424,22 +2419,35 @@
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 */
More information about the Python-checkins
mailing list