From af21469a31f95b078fd7b2546461c96dff7eb28f Mon Sep 17 00:00:00 2001 From: Vansh8803 Date: Sun, 25 Oct 2026 22:20:58 +0530 Subject: [PATCH] fix: reject non-ASCII digits in numbers --- CHANGELOG.md | 4 ++++ tests/test_parser.py | 11 +++++++++++ tomlkit/parser.py | 6 ++++++ 3 files changed, 21 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f414f212..c489a4de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## [Unreleased] +### Fixed + +- Fix non-ASCII Unicode digits being accepted in numbers. `int()` and `float()` converted them, so `1` followed by U+0660 (ARABIC-INDIC DIGIT ZERO) parsed as `10`. Numbers are now required to be ASCII and otherwise raise `InvalidNumberError`. ([#686](https://github.com/python-poetry/tomlkit/pull/686)) + ## [0.15.2] - 2026-10-16 ### Changed diff --git a/tests/test_parser.py b/tests/test_parser.py index 36c0ae98..6d37127d 100644 --- a/tests/test_parser.py +++ b/tests/test_parser.py @@ -274,6 +274,17 @@ def test_parser_accepts_uppercase_exponent_after_leading_zero() -> None: assert value == float(raw) +def test_parser_rejects_non_ascii_digits_in_numbers() -> None: + # int() and float() accept non-ASCII Unicode digits, so a token ending in + # U+0660 (ARABIC-INDIC DIGIT ZERO) would otherwise be parsed as an ASCII + # number, e.g. "1" followed by that digit as 10. TOML allows ASCII only. + zero = chr(0x0660) # ARABIC-INDIC DIGIT ZERO + for raw in (f"1{zero}", f"1_0{zero}", f"1.{zero}", f"1e{zero}", f"+{zero}"): + parser = Parser(f"a = {raw}") + with pytest.raises(InvalidNumberError): + parser.parse() + + @pytest.mark.parametrize("sign", ["", "+", "-"]) @pytest.mark.parametrize( "raw", diff --git a/tomlkit/parser.py b/tomlkit/parser.py index dc08f928..0596d5d5 100644 --- a/tomlkit/parser.py +++ b/tomlkit/parser.py @@ -778,6 +778,12 @@ def _parse_number(self, raw: str, trivia: Trivia) -> Item | None: if "_" in clean: return None + # int() and float() also accept non-ASCII Unicode digits, so a token + # such as "1" followed by U+0660 (ARABIC-INDIC DIGIT ZERO) would be read + # as 10. TOML numbers are ASCII only. + if not clean.isascii(): + return None + # Special float values must be lowercase in the original token. if clean in ("inf", "nan") and raw != clean: return None