From 2744c5151e61492aa65cc6b9f461fe1ab009339e Mon Sep 17 00:00:00 2001 From: Peter Nelson Subrata Date: Fri, 17 Apr 2026 18:12:10 +1000 Subject: [PATCH] fix: reject NaN values in FloatRange --- src/click/types.py | 16 ++++++++++++++++ tests/test_types.py | 18 ++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/src/click/types.py b/src/click/types.py index e71c1c21e4..126d8b65b3 100644 --- a/src/click/types.py +++ b/src/click/types.py @@ -648,6 +648,22 @@ def __init__( if (min_open or max_open) and clamp: raise TypeError("Clamping is not supported for open bounds.") + def convert( + self, value: t.Any, param: Parameter | None, ctx: Context | None + ) -> t.Any: + import math + + rv = super().convert(value, param, ctx) + + if math.isnan(rv): + self.fail( + _("{value} is not a valid number.").format(value=rv), + param, + ctx, + ) + + return rv + def _clamp(self, bound: float, dir: t.Literal[1, -1], open: bool) -> float: if not open: return bound diff --git a/tests/test_types.py b/tests/test_types.py index 75434f1042..fa376c4b7a 100644 --- a/tests/test_types.py +++ b/tests/test_types.py @@ -51,6 +51,24 @@ def test_range_fail(type, value, expect): assert expect in exc_info.value.message +@pytest.mark.parametrize( + ("type",), + [ + (click.FloatRange(0.0, 1.0),), + (click.FloatRange(0.5, 1.5),), + (click.FloatRange(max=1.5),), + (click.FloatRange(),), + (click.FloatRange(0.0, 1.0, clamp=True),), + (click.FloatRange(0.0, 1.0, min_open=True),), + ], +) +def test_float_range_rejects_nan(type): + """FloatRange should reject NaN values since NaN is not a valid number + and NaN comparisons are always False, bypassing range checks.""" + with pytest.raises(click.BadParameter, match="not a valid number"): + type.convert("nan", None, None) + + def test_float_range_no_clamp_open(): with pytest.raises(TypeError): click.FloatRange(0, 1, max_open=True, clamp=True)