From 23deac1f7c6b7042f7f2106afe564ef40304db99 Mon Sep 17 00:00:00 2001 From: Khaleel Al-Adhami Date: Tue, 17 Sep 2024 11:05:17 -0700 Subject: [PATCH 1/3] add special handling for infinity and nan --- reflex/vars/number.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/reflex/vars/number.py b/reflex/vars/number.py index 31778a25d8..3300769690 100644 --- a/reflex/vars/number.py +++ b/reflex/vars/number.py @@ -4,6 +4,7 @@ import dataclasses import json +import math import sys from typing import ( TYPE_CHECKING, @@ -1038,7 +1039,12 @@ def json(self) -> str: Returns: The JSON representation of the var. + + Raises: + ValueError: The JSON representation is invalid. """ + if math.isinf(self._var_value) or math.isnan(self._var_value): + raise ValueError(f"Invalid JSON representation for {self}") return json.dumps(self._var_value) def __hash__(self) -> int: @@ -1060,8 +1066,15 @@ def create(cls, value: float | int, _var_data: VarData | None = None): Returns: The number var. """ + if math.isinf(value): + js_expr = "Infinity" if value > 0 else "-Infinity" + elif math.isnan(value): + js_expr = "NaN" + else: + js_expr = str(value) + return cls( - _js_expr=str(value), + _js_expr=js_expr, _var_type=type(value), _var_data=_var_data, _var_value=value, From 86390eac2d5465edab9dfd00a246c343c35a9d7e Mon Sep 17 00:00:00 2001 From: Khaleel Al-Adhami Date: Wed, 18 Sep 2024 11:24:47 -0700 Subject: [PATCH 2/3] use custom exception --- reflex/utils/exceptions.py | 4 ++++ reflex/vars/number.py | 8 +++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/reflex/utils/exceptions.py b/reflex/utils/exceptions.py index 8a527e1130..95d68c3b8b 100644 --- a/reflex/utils/exceptions.py +++ b/reflex/utils/exceptions.py @@ -107,3 +107,7 @@ class EventHandlerShadowsBuiltInStateMethod(ReflexError, NameError): class GeneratedCodeHasNoFunctionDefs(ReflexError): """Raised when refactored code generated with flexgen has no functions defined.""" + + +class PrimitiveUnserializableToJSON(ReflexError, ValueError): + """Raised when a primitive type is unserializable to JSON. Usually with NaN and Infinity.""" diff --git a/reflex/vars/number.py b/reflex/vars/number.py index 3300769690..8b0e86301a 100644 --- a/reflex/vars/number.py +++ b/reflex/vars/number.py @@ -18,7 +18,7 @@ overload, ) -from reflex.utils.exceptions import VarTypeError +from reflex.utils.exceptions import PrimitiveUnserializableToJSON, VarTypeError from .base import ( CustomVarOperationReturn, @@ -1041,10 +1041,12 @@ def json(self) -> str: The JSON representation of the var. Raises: - ValueError: The JSON representation is invalid. + PrimitiveUnserializableToJSON: If the var is unserializable to JSON. """ if math.isinf(self._var_value) or math.isnan(self._var_value): - raise ValueError(f"Invalid JSON representation for {self}") + raise PrimitiveUnserializableToJSON( + f"No valid JSON representation for {self}" + ) return json.dumps(self._var_value) def __hash__(self) -> int: From c9733d265be4177ff88d5b1f28349e660bba805b Mon Sep 17 00:00:00 2001 From: Khaleel Al-Adhami Date: Wed, 18 Sep 2024 12:00:12 -0700 Subject: [PATCH 3/3] add test for inf and nan --- tests/test_var.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/test_var.py b/tests/test_var.py index e73407bb02..75a85bfc5b 100644 --- a/tests/test_var.py +++ b/tests/test_var.py @@ -9,6 +9,7 @@ from reflex.base import Base from reflex.constants.base import REFLEX_VAR_CLOSING_TAG, REFLEX_VAR_OPENING_TAG from reflex.state import BaseState +from reflex.utils.exceptions import PrimitiveUnserializableToJSON from reflex.utils.imports import ImportVar from reflex.vars import VarData from reflex.vars.base import ( @@ -974,6 +975,22 @@ def test_index_operation(): assert str(array_var[0].to(NumberVar) + 9) == "([1, 2, 3, 4, 5].at(0) + 9)" +@pytest.mark.parametrize( + "var, expected_js", + [ + (Var.create(float("inf")), "Infinity"), + (Var.create(-float("inf")), "-Infinity"), + (Var.create(float("nan")), "NaN"), + ], +) +def test_inf_and_nan(var, expected_js): + assert str(var) == expected_js + assert isinstance(var, NumberVar) + assert isinstance(var, LiteralVar) + with pytest.raises(PrimitiveUnserializableToJSON): + var.json() + + def test_array_operations(): array_var = LiteralArrayVar.create([1, 2, 3, 4, 5])