From c279c5918fbb4baaf335601919b91a4a47235ac1 Mon Sep 17 00:00:00 2001 From: Renchao Wu <42173584+widechaos@users.noreply.github.com> Date: Mon, 5 Oct 2026 10:06:55 +0400 Subject: [PATCH] Fix CRLF recovery after invalid dotenv statements --- src/dotenv/parser.py | 2 +- tests/test_parser.py | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/dotenv/parser.py b/src/dotenv/parser.py index d9d47583..b3b55070 100644 --- a/src/dotenv/parser.py +++ b/src/dotenv/parser.py @@ -29,7 +29,7 @@ def make_regex(string: str, extra_flags: int = 0) -> Pattern[str]: _unquoted_value = make_regex(r"([^\r\n]*)") _comment = make_regex(r"(?:[^\S\r\n]*#[^\r\n]*)?") _end_of_line = make_regex(r"[^\S\r\n]*(?:\r\n|\n|\r|$)") -_rest_of_line = make_regex(r"[^\r\n]*(?:\r|\n|\r\n)?") +_rest_of_line = make_regex(r"[^\r\n]*(?:\r\n|\n|\r)?") _double_quote_escapes = make_regex(r"\\[\\'\"abfnrtv]") _single_quote_escapes = make_regex(r"\\[\\']") diff --git a/tests/test_parser.py b/tests/test_parser.py index 667eae15..a385e481 100644 --- a/tests/test_parser.py +++ b/tests/test_parser.py @@ -721,3 +721,16 @@ def test_parse_stream(test_input, expected): result = parse_stream(io.StringIO(test_input)) assert list(result) == expected + + +@pytest.mark.parametrize("newline", ["\n", "\r", "\r\n"]) +def test_parse_stream_recovers_after_invalid_lines(newline): + lines = ["bad line", "NEXT=ok", "bad again", "LAST=yes"] + result = list(parse_stream(io.StringIO(newline.join(lines)))) + + assert result == [ + Binding(None, None, Original(lines[0] + newline, 1), True), + Binding("NEXT", "ok", Original(lines[1] + newline, 2), False), + Binding(None, None, Original(lines[2] + newline, 3), True), + Binding("LAST", "yes", Original(lines[3], 4), False), + ]