`Path.write_text` does not check whether LF is preceded by CR before converting it to CRLF on windows, resulting in CRCRLF
Bug report
Bug description:
from pathlib import Path
path = Path("foo.txt")
path.write_text("foo\r\nbar")
print(path.read_bytes()) # b'foo\r\r\nbar'
i know i can workaround this behavior by passing newline="" to write_text or using write_bytes instead, but this should not be necessary. it should check whether the text is already using CRLF.
(sidenote: windows has supported LF for many years now. the automatic conversion many tools do by default is not only no longer necessary, but nowadays causes far more problems than it solves IMO. https://old.reddit.com/r/git/comments/7mg1q1/gits_crlf_handling_is_the_source_of_all_modern/)
CPython versions tested on:
3.14
Operating systems tested on:
Windows
pathlib.Path is just forwarding to the standard Python I/O stack and not adding any new behaviors here (source code, I/O Docs: https://docs.python.org/3/library/io.html#io.TextIOWrapper). The newline behavior has been around since the beginning of Python 3 and changing the default here would likely break existing programs.
this seems like an obvious bug to me though, regardless of whether fixing it would be a breaking change. does this mean a PEP would be required to change the behavior?
CPython follows a backwards compatibility policy outlined in PEP-387. That also has a section on how to propose and make backwards incompatible changes.
I’d like to propose a small documentation clarification for Path.write_text() on Windows:
When writing text containing CRLF sequences (\r\n), Python’s text mode automatically translates \n to \r\n. If the text already contains CRLF, this can lead to duplication (\r\n → \r\r\n):
from pathlib import Path
path = Path("foo.txt")
path.write_text("foo\r\nbar")
print(path.read_bytes()) # b'foo\r\r\nbar'
I understand and acknowledge the problem--I've actually had to debug this exact thing, as \r\r\n between lines of code somehow completely messed up line numbers in tracebacks on Windows :-)
However, I don't think there's anything we can do to address this at the moment, so I'll close.
The Path.write_text documentation refers to the open built-in, and open (as well as TextIOWrapper) very clearly documents this behavior.
Maybe try to raise this issue at https://discuss.python.org/? Maybe suggest a rule to Ruff or other linters to detect uses of os.linesep / \r\n in arguments to Path.write_text() / open(..., "w").write()?