From 0fc3079c2030a43aa3897992e9d07498a1a78f54 Mon Sep 17 00:00:00 2001 From: Janet Taylor Date: Tue, 21 Nov 2023 11:00:06 -0500 Subject: [PATCH] #3662 remove hardcoded decimal point --- CHANGELOG.md | 1 + src/textual/widgets/_input.py | 3 ++- tests/input/test_input_restrict.py | 33 ++++++++++++++++++++++++++---- 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e1da5c856..cd8ad90991 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Loading indicators and app notifications overlapped in the wrong order https://github.com/Textualize/textual/issues/3677 - Widgets being loaded are disabled and have their scrolling explicitly disabled too https://github.com/Textualize/textual/issues/3677 - Method render on a widget could be called before mounting said widget https://github.com/Textualize/textual/issues/2914 +- Input type number only accepting decimal point of locale-specific decimals https://github.com/Textualize/textual/issues/3662 ### Added diff --git a/src/textual/widgets/_input.py b/src/textual/widgets/_input.py index 0b5dceef08..37fa4640df 100644 --- a/src/textual/widgets/_input.py +++ b/src/textual/widgets/_input.py @@ -1,5 +1,6 @@ from __future__ import annotations +import locale import re from dataclasses import dataclass from typing import ClassVar, Iterable @@ -32,7 +33,7 @@ _RESTRICT_TYPES = { "integer": r"[-+]?\d*", - "number": r"[-+]?\d*\.?\d*[eE]?[-+]?\d*", + "number": rf"[-+]?\d*[\.{locale.localeconv().get('decimal_point')}]?\d*[eE]?[-+]?\d*", "text": None, } InputType = Literal["integer", "number", "text"] diff --git a/tests/input/test_input_restrict.py b/tests/input/test_input_restrict.py index 12100811ac..5164836cd6 100644 --- a/tests/input/test_input_restrict.py +++ b/tests/input/test_input_restrict.py @@ -1,15 +1,18 @@ +import importlib +import locale import re import pytest from textual.app import App, ComposeResult -from textual.widgets import Input -from textual.widgets._input import _RESTRICT_TYPES +from textual.widgets import Input, _input def test_input_number_type(): """Test number type regex.""" - number = _RESTRICT_TYPES["number"] + locale._override_localeconv = {"decimal_point": "."} + importlib.reload(_input) + number = _input._RESTRICT_TYPES["number"] assert re.fullmatch(number, "0") assert re.fullmatch(number, "0.") assert re.fullmatch(number, ".") @@ -27,9 +30,31 @@ def test_input_number_type(): assert not re.fullmatch(number, "nan") +def test_input_number_type_non_period_decimal_point(): + """Test number type regex for locales with different decimal points.""" + locale._override_localeconv = {"decimal_point": ","} + importlib.reload(_input) + number = _input._RESTRICT_TYPES["number"] + assert re.fullmatch(number, "0") + assert re.fullmatch(number, "0,") + assert re.fullmatch(number, ",") + assert re.fullmatch(number, ",0") + assert re.fullmatch(number, "1,1") + assert re.fullmatch(number, "1e1") + assert re.fullmatch(number, "1,2e") + assert re.fullmatch(number, "1,2e10") + assert re.fullmatch(number, "1,2E10") + assert re.fullmatch(number, "1,2e-") + assert re.fullmatch(number, "1,2e-10") + assert not re.fullmatch(number, "1,2e10e") + assert not re.fullmatch(number, "1f2") + assert not re.fullmatch(number, "inf") + assert not re.fullmatch(number, "nan") + + def test_input_integer_type(): """Test input type regex""" - integer = _RESTRICT_TYPES["integer"] + integer = _input._RESTRICT_TYPES["integer"] assert re.fullmatch(integer, "0") assert re.fullmatch(integer, "1") assert re.fullmatch(integer, "10")