diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py index 489e5605f65..6265258493d 100644 --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -233,6 +233,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(support.TESTFN, "wb") as f: + f.write(b"xxx") + with io.open(support.TESTFN, "ab", buffering=0) as f: + self.assertEqual(f.tell(), 3) + with io.open(support.TESTFN, "ab") as f: + self.assertEqual(f.tell(), 3) + with io.open(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 35506cb6f33..b92048c2c6d 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -137,6 +137,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 #5013: Fixed a bug in FileHandler which occurred when the delay parameter was set. diff --git a/Modules/_fileio.c b/Modules/_fileio.c index 5b840c000a8..7a71837d7bb 100644 --- a/Modules/_fileio.c +++ b/Modules/_fileio.c @@ -55,6 +55,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, -1 with exception set on failure. */ static int internal_close(PyFileIOObject *self) @@ -315,6 +318,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: