Index: Lib/_pyio.py =================================================================== --- Lib/_pyio.py (révision 70474) +++ Lib/_pyio.py (copie de travail) @@ -1390,6 +1390,12 @@ self._snapshot = None # info for reconstructing decoder state self._seekable = self._telling = self.buffer.seekable() + if self._seekable and self.writable(): + position = self.buffer.tell() + if position != 0: + self._encoder = self._get_encoder() + self._encoder.setstate(0) + # self._snapshot is either None, or a tuple (dec_flags, next_input) # where dec_flags is the second (integer) item of the decoder state # and next_input is the chunk of input bytes that comes next after the Index: Lib/test/test_io.py =================================================================== --- Lib/test/test_io.py (révision 70474) +++ Lib/test/test_io.py (copie de travail) @@ -1797,6 +1797,20 @@ self.assertEqual(buffer.seekable(), txt.seekable()) + def test_append_bom(self): + filename = support.TESTFN + for charset in ('utf-8-sig', 'utf16', 'utf-32'): + with self.open(filename, 'w', encoding=charset) as f: + f.write('aaa') + with self.open(filename, 'r', encoding=charset) as f: + self.assertEquals(f.read(), 'aaa') + + with self.open(filename, 'a', encoding=charset) as f: + f.write('xxx') + with self.open(filename, 'r', encoding=charset) as f: + self.assertEquals(f.read(), 'aaaxxx') + + class CTextIOWrapperTest(TextIOWrapperTest): def test_initialization(self): Index: Modules/_textio.c =================================================================== --- Modules/_textio.c (révision 70474) +++ Modules/_textio.c (copie de travail) @@ -754,6 +754,7 @@ char *newline = NULL; int line_buffering = 0; _PyIO_State *state = IO_STATE; + static PyObject *zero = NULL; PyObject *res; int r; @@ -963,9 +964,40 @@ Py_DECREF(res); self->ok = 1; + + if (self->seekable && self->encoder) { + PyObject *cookieObj; + int cmp; + + if (zero == NULL) { + zero = PyLong_FromLong(0L); + if (zero == NULL) + goto error; + } + + cookieObj = PyObject_CallMethod(buffer, "tell", NULL); + if (cookieObj == NULL) + goto error; + + cmp = PyObject_RichCompareBool(cookieObj, zero, Py_EQ); + Py_DECREF(cookieObj); + if (cmp < 0) { + goto error; + } + + if (cmp == 0) { + res = PyObject_CallMethod(self->encoder, "setstate", "O", zero); + if (res == NULL) + goto error; + Py_DECREF(res); + + self->encodefunc = NULL; + } + } return 0; error: + self->ok = 0; return -1; }