Repository: meltano/sdk (python)

Issue:
bug: ValueError: Out of range float values are not JSON compliant
### Singer SDK Version

0.34.1

### Is this a regression?

- [ ] Yes

### Python Version

3.9

### Bug scope

Taps (catalog, state, etc.)

### Operating System

MacOS

### Description

I get `ValueError: Out of range float values are not JSON compliant`  when trying to sync Amazon Document DB collection. 

The probably reason is that `simple_json.dumps()` has `allow_nan=False` default, while standard `dumps()` function from standard `json` library has `allow_nan=True`. 

As there is no way to pass configuration from outside could we add this functionality? I can introduce relevant fix. 

### Code

_No response_

Pull request:
fix: Encode `nan`, `inf` and `-inf` values as `null` in Singer stream
Changes the behavior of JSON serialization for Singer output to convert `nan`, `inf` and `-inf` values to `null` in compliance with the ECMA-262 specification.

## Implementation details

- `simplejson` supports this with the `ignore_nan=True`[^1] parameter.
- `msgspec` already does this by default[^2].

## Related

- Closes #2213

[^1]: https://simplejson.readthedocs.io/en/latest/#simplejson.dumps
[^2]: https://jcristharif.com/msgspec/supported-types.html#float

## Summary by Sourcery

Modify JSON serialization in Singer output to convert special float values (`nan`, `inf`, `-inf`) to `null`

Bug Fixes:
- Ensure proper handling of special float values in JSON serialization

Tests:
- Add test case to verify `nan` values are encoded as `null`

<!-- readthedocs-preview meltano-sdk start -->
----
📚 Documentation preview 📚: https://meltano-sdk--3019.org.readthedocs.build/en/3019/

<!-- readthedocs-preview meltano-sdk end -->

Patch:
diff --git a/singer_sdk/singerlib/json.py b/singer_sdk/singerlib/json.py
index 1c9855e3..2a4e60f5 100644
--- a/singer_sdk/singerlib/json.py
+++ b/singer_sdk/singerlib/json.py
@@ -59,5 +59,6 @@ def serialize_json(obj: object, **kwargs: t.Any) -> str:
         use_decimal=True,
         default=_default_encoding,
         separators=(",", ":"),
+        ignore_nan=True,
         **kwargs,
     )


Test patch:
diff --git a/tests/singerlib/encoding/test_simple.py b/tests/singerlib/encoding/test_simple.py
index 7ce7f5bd..098c7276 100644
--- a/tests/singerlib/encoding/test_simple.py
+++ b/tests/singerlib/encoding/test_simple.py
@@ -104,3 +104,18 @@ def test_write_message():
     assert out.getvalue() == (
         '{"type":"RECORD","stream":"test","record":{"id":1,"name":"test"}}\n'
     )
+
+
+@pytest.mark.parametrize("float_value", [float("nan"), float("inf"), float("-inf")])
+def test_encode_nan_values(float_value):
+    writer = SimpleSingerWriter()
+    message = RecordMessage(
+        stream="test",
+        record={"id": 1, "name": float_value},
+    )
+    with redirect_stdout(io.StringIO()) as out:
+        writer.write_message(message)
+
+    assert out.getvalue() == (
+        '{"type":"RECORD","stream":"test","record":{"id":1,"name":null}}\n'
+    )