From d549b3c164b7871acb9c80631c3d3f1c34449061 Mon Sep 17 00:00:00 2001 From: eeshsaxena Date: Thu, 13 Aug 2026 18:08:02 +0530 Subject: [PATCH] Accept uppercase E exponent after a leading-zero mantissa A float like `0E2` is valid TOML, since both `e` and `E` are allowed exponent markers. The "no leading zeros" guard exempted the mantissa only for lowercase `0e`, so `0E2` (and `0E+2`, `+0E2`, etc.) were rejected as an invalid number while `0e2` parsed fine. Add `0E` to the exempted prefixes. --- tests/test_parser.py | 11 +++++++++++ tomlkit/parser.py | 5 ++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/tests/test_parser.py b/tests/test_parser.py index bf378122..44d5cd6c 100644 --- a/tests/test_parser.py +++ b/tests/test_parser.py @@ -8,6 +8,7 @@ from tomlkit.exceptions import InvalidUnicodeValueError from tomlkit.exceptions import ParseError from tomlkit.exceptions import UnexpectedCharError +from tomlkit.items import Float from tomlkit.items import Integer from tomlkit.items import StringType from tomlkit.parser import Parser @@ -235,3 +236,13 @@ def test_parser_rejects_overlong_decimal_integer() -> None: # the value just under the limit is still a normal integer value = Parser("a = " + "9" * 4300).parse()["a"] assert isinstance(value, Integer) + + +def test_parser_accepts_uppercase_exponent_after_leading_zero() -> None: + # Both "e" and "E" are valid exponent markers. A leading-zero mantissa was + # only exempted from the "no leading zeros" rule for lowercase "0e", so + # "0E2" and its signed forms were wrongly rejected as an invalid number. + for raw in ("0E2", "0E+2", "0E-2", "+0E2", "-0E2"): + value = Parser(f"a = {raw}").parse()["a"] + assert isinstance(value, Float) + assert value == float(raw) diff --git a/tomlkit/parser.py b/tomlkit/parser.py index c97a08d4..8c7b1a64 100644 --- a/tomlkit/parser.py +++ b/tomlkit/parser.py @@ -749,7 +749,10 @@ def _parse_number(self, raw: str, trivia: Trivia) -> Item | None: raw = raw[1:] if len(raw) > 1 and ( - (raw.startswith("0") and not raw.startswith(("0.", "0o", "0x", "0b", "0e"))) + ( + raw.startswith("0") + and not raw.startswith(("0.", "0o", "0x", "0b", "0e", "0E")) + ) or (sign and raw.startswith(".")) ): return None