diff --git a/path/__init__.py b/path/__init__.py index 33dd979..221b70e 100644 --- a/path/__init__.py +++ b/path/__init__.py @@ -900,8 +900,12 @@ def write_text( """ if linesep is not None: text = U_NEWLINE.sub(linesep, text) - bytes = text.encode(encoding or sys.getdefaultencoding(), errors) - self.write_bytes(bytes, append=append) + encoding = encoding or sys.getdefaultencoding() + if append: + with self.open('a', encoding=encoding, errors=errors, newline='') as f: + f.write(text) + else: + self.write_bytes(text.encode(encoding, errors)) def lines( self, diff --git a/tests/test_path.py b/tests/test_path.py index b424bb6..e0bc581 100644 --- a/tests/test_path.py +++ b/tests/test_path.py @@ -727,7 +727,7 @@ def test_patterns(self, tmpdir): self.assertList(d.walkfiles('*.tmp'), [e / 'x.tmp' for e in dirs]) self.assertList(d.walkdirs('*.tmp'), [d / 'xdir.tmp']) - encodings = 'UTF-8', 'UTF-16BE', 'UTF-16LE', 'UTF-16' + encodings = 'UTF-8', 'UTF-16BE', 'UTF-16LE', 'UTF-16', 'UTF-32', 'UTF-8-SIG' @pytest.mark.parametrize("encoding", encodings) def test_unicode(self, tmpdir, encoding): @@ -768,13 +768,6 @@ def test_unicode(self, tmpdir, encoding): assert p.lines(encoding) == expectedLines assert p.lines(encoding, retain=False) == stripped - # If this is UTF-16, that's enough. - # The rest of these will unfortunately fail because append=True - # mode causes an extra BOM to be written in the middle of the file. - # UTF-16 is the only encoding that has this problem. - if encoding == 'UTF-16': - return - # Write Unicode to file using path.write_text(). # This test doesn't work with a hanging line. cleanNoHanging = clean + '\n' @@ -782,7 +775,7 @@ def test_unicode(self, tmpdir, encoding): p.write_text(cleanNoHanging, encoding) p.write_text(cleanNoHanging, encoding, append=True) # Check the result. - expectedBytes = 2 * cleanNoHanging.replace('\n', os.linesep).encode(encoding) + expectedBytes = (2 * cleanNoHanging.replace('\n', os.linesep)).encode(encoding) expectedLinesNoHanging = expectedLines[:] expectedLinesNoHanging[-1] += '\n' assert p.bytes() == expectedBytes @@ -1398,3 +1391,14 @@ def test_ignore(self): def test_invalid_handler(self): with pytest.raises(ValueError): path.Handlers._resolve('raise') + + +@pytest.mark.parametrize('encoding', ['UTF-16', 'UTF-32', 'UTF-8-SIG']) +@pytest.mark.parametrize('exists', [False, True]) +def test_write_text_append_bom(tmp_path, encoding, exists): + target = Path(tmp_path) / 'text.txt' + if exists: + target.touch() + target.write_text('first', encoding=encoding, append=True) + target.write_text('second', encoding=encoding, append=True) + assert target.read_bytes() == 'firstsecond'.encode(encoding)