diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py index 967018ea453..f0b38b6f7a9 100644 --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -232,6 +232,17 @@ class IOTest(unittest.TestCase): else: self.fail("1/0 didn't raise an exception") + # issue 5008 + def test_append_mode_tell(self): + with io.open(test_support.TESTFN, "wb") as f: + f.write(b"xxx") + with io.open(test_support.TESTFN, "ab", buffering=0) as f: + self.assertEqual(f.tell(), 3) + with io.open(test_support.TESTFN, "ab") as f: + self.assertEqual(f.tell(), 3) + with io.open(test_support.TESTFN, "a") as f: + self.assert_(f.tell() > 0) + def test_destructor(self): record = [] class MyFileIO(io.FileIO): diff --git a/Misc/NEWS b/Misc/NEWS index 30c3a0f7e30..ca5eef1dcb1 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -76,6 +76,11 @@ Core and Builtins Library ------- +- Issue #5008: When a file is opened in append mode with the new IO library, + do an explicit seek to the end of file (so that e.g. tell() returns the + file size rather than 0). This is consistent with the behaviour of the + traditional 2.x file object. + - Issue #3997: zipfiles generated with more than 65536 files could not be opened with other applications. diff --git a/Modules/_fileio.c b/Modules/_fileio.c index 0f09ecd8a3b..fbe4189a8da 100644 --- a/Modules/_fileio.c +++ b/Modules/_fileio.c @@ -41,6 +41,9 @@ PyTypeObject PyFileIO_Type; #define PyFileIO_Check(op) (PyObject_TypeCheck((op), &PyFileIO_Type)) +static PyObject * +portable_lseek(int fd, PyObject *posobj, int whence); + /* Returns 0 on success, errno (which is < 0) on failure. */ static int internal_close(PyFileIOObject *self) @@ -296,6 +299,16 @@ fileio_init(PyObject *oself, PyObject *args, PyObject *kwds) goto error; } + if (append) { + /* For consistent behaviour, we explicitly seek to the + end of file (otherwise, it might be done only on the + first write()). */ + PyObject *pos = portable_lseek(self->fd, NULL, 2); + if (pos == NULL) + goto error; + Py_DECREF(pos); + } + goto done; error: