This is an automated email from the ASF dual-hosted git repository.

ebenizzy pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/hamilton.git


The following commit(s) were added to refs/heads/main by this push:
     new 27349233 Serialize NaN and Infinity values as strings (#1322)
27349233 is described below

commit 27349233d4e17f2653355139f8e36718f25dd9ec
Author: Gavin Kistner <[email protected]>
AuthorDate: Mon Jul 14 21:48:03 2025 -0600

    Serialize NaN and Infinity values as strings (#1322)
    
    Float values that are "out of range" were previously serialized—to send to 
the
    tracker/Hamilton UI—in a way that produced invalid JSON (but value JS), 
which
    caused a runtime error trying to send values to the tracker.
    
    `math.nan`, `math.inf`, and `-math.inf` are serialized by `json.dumps()` to
    `NaN`, `Infinity`, and `-Infinity` values by default(NOT as strings).
    
    This commit uses `json.dumps(…, allow_nan=False)`, which raises a 
`ValueError`
    for such values, and in that case converts them to strings.
    
    The result is that Hamliton UI will show such values as **strings**
    `"nan"`, `"inf"`, and `"-inf"`.
    This could be confusing only to users who are also using such string values.
    
    Fixes #1310
    
    Co-authored-by: Gavin Kistner <[email protected]>
---
 ui/sdk/src/hamilton_sdk/tracking/utils.py |  4 ++--
 ui/sdk/tests/tracking/test_utils.py       | 25 +++++++++++++++++++++++++
 2 files changed, 27 insertions(+), 2 deletions(-)

diff --git a/ui/sdk/src/hamilton_sdk/tracking/utils.py 
b/ui/sdk/src/hamilton_sdk/tracking/utils.py
index b0e515d8..fefc3b11 100644
--- a/ui/sdk/src/hamilton_sdk/tracking/utils.py
+++ b/ui/sdk/src/hamilton_sdk/tracking/utils.py
@@ -58,11 +58,11 @@ def make_json_safe(item: Union[dict, list, str, float, int, 
bool]) -> Any:
         return make_json_safe(item.to_dict())
     else:
         try:
-            json.dumps(item)  # Check if item is json serializable
+            json.dumps(item, allow_nan=False)  # Check if item is json 
serializable
             if isinstance(item, str):
                 # escape null byte -- postgres doesn't like null bytes at 
least.
                 # we might need to escape more things; TBD.
                 return item.replace("\x00", "\\x00")
             return item
-        except TypeError:
+        except (TypeError, ValueError):
             return str(item)  # Convert item to string if not json serializable
diff --git a/ui/sdk/tests/tracking/test_utils.py 
b/ui/sdk/tests/tracking/test_utils.py
index eb85d52b..62cafb87 100644
--- a/ui/sdk/tests/tracking/test_utils.py
+++ b/ui/sdk/tests/tracking/test_utils.py
@@ -157,3 +157,28 @@ def test_make_json_safe_str_with_null_byte():
     assert isinstance(result, dict)
     assert isinstance(result["key2"], str)
     assert result["key2"] == "value\\x00"
+
+
+def test_make_json_safe_with_nan():
+    """Test that NaN and Infinity values are properly handled in 
make_json_safe"""
+    import math
+
+    # Test with a dictionary
+    input_dict = {"a": math.nan, "b": np.nan, "c": 1.0, "d": math.inf, "e": 
-math.inf}
+    result = utils.make_json_safe(input_dict)
+    assert isinstance(result, dict)
+    assert result["a"] == "nan"  # NaN should be represented as "nan"
+    assert result["b"] == "nan"  # …same for numpy.nan
+    assert result["c"] == 1.0  # Regular float should remain unchanged
+    assert result["d"] == "inf"  # Infinity should be represented as "inf"
+    assert result["e"] == "-inf"  # Negative infinity should be represented as 
"-inf"
+
+    # Test with a list
+    input_list = [math.nan, np.nan, 1.0, math.inf, -math.inf]
+    result = utils.make_json_safe(input_list)
+    assert isinstance(result, list)
+    assert result[0] == "nan"  # NaN should be represented as "nan"
+    assert result[1] == "nan"  # …same for numpy.nan
+    assert result[2] == 1.0  # Regular float should remain unchanged
+    assert result[3] == "inf"  # Infinity should be represented as "inf"
+    assert result[4] == "-inf"  # Negative infinity should be represented as 
"-inf"

Reply via email to