Skip to content

Commit 1c4baac

Browse files
Fixes for ser_json_inf_nan inference (#1251)
1 parent e26e857 commit 1c4baac

File tree

2 files changed

+57
-3
lines changed

2 files changed

+57
-3
lines changed

src/serializers/infer.rs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -401,7 +401,14 @@ pub(crate) fn infer_serialize_known<S: Serializer>(
401401
ObType::None => serializer.serialize_none(),
402402
ObType::Int | ObType::IntSubclass => serialize!(Int),
403403
ObType::Bool => serialize!(bool),
404-
ObType::Float | ObType::FloatSubclass => serialize!(f64),
404+
ObType::Float | ObType::FloatSubclass => {
405+
let v = value.extract::<f64>().map_err(py_err_se_err)?;
406+
if (v.is_nan() || v.is_infinite()) && extra.config.inf_nan_mode == InfNanMode::Null {
407+
serializer.serialize_none()
408+
} else {
409+
serializer.serialize_f64(v)
410+
}
411+
}
405412
ObType::Decimal => value.to_string().serialize(serializer),
406413
ObType::Str | ObType::StrSubclass => {
407414
let py_str = value.downcast::<PyString>().map_err(py_err_se_err)?;
@@ -575,8 +582,14 @@ pub(crate) fn infer_json_key_known<'a>(
575582
) -> PyResult<Cow<'a, str>> {
576583
match ob_type {
577584
ObType::None => super::type_serializers::simple::none_json_key(),
578-
ObType::Int | ObType::IntSubclass | ObType::Float | ObType::FloatSubclass => {
579-
super::type_serializers::simple::to_str_json_key(key)
585+
ObType::Int | ObType::IntSubclass => super::type_serializers::simple::to_str_json_key(key),
586+
ObType::Float | ObType::FloatSubclass => {
587+
let v = key.extract::<f64>()?;
588+
if (v.is_nan() || v.is_infinite()) && extra.config.inf_nan_mode == InfNanMode::Null {
589+
super::type_serializers::simple::none_json_key()
590+
} else {
591+
super::type_serializers::simple::to_str_json_key(key)
592+
}
580593
}
581594
ObType::Decimal => Ok(Cow::Owned(key.to_string())),
582595
ObType::Bool => super::type_serializers::simple::bool_json_key(key),

tests/serializers/test_any.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from datetime import date, datetime, time, timedelta, timezone
88
from decimal import Decimal
99
from enum import Enum
10+
from math import inf, isinf, isnan, nan
1011
from pathlib import Path
1112
from typing import ClassVar
1213

@@ -603,3 +604,43 @@ def test_numpy_float(any_serializer):
603604
any_serializer.to_python(numpy.float16(1.0), mode='json')
604605
with pytest.raises(PydanticSerializationError, match=r"Unable to serialize unknown type: <class 'numpy\.float16'>"):
605606
any_serializer.to_json(numpy.float16(1.0))
607+
608+
609+
def test_ser_json_inf_nan_with_any() -> None:
610+
s = SchemaSerializer(core_schema.any_schema(), core_schema.CoreConfig(ser_json_inf_nan='constants'))
611+
assert isinf(s.to_python(inf))
612+
assert isinf(s.to_python(inf, mode='json'))
613+
assert s.to_json(inf) == b'Infinity'
614+
assert isnan(s.to_python(nan))
615+
assert isnan(s.to_python(nan, mode='json'))
616+
assert s.to_json(nan) == b'NaN'
617+
618+
s = SchemaSerializer(core_schema.any_schema(), core_schema.CoreConfig(ser_json_inf_nan='null'))
619+
assert isinf(s.to_python(inf))
620+
assert s.to_python(inf, mode='json') is None
621+
assert s.to_json(inf) == b'null'
622+
assert isnan(s.to_python(nan))
623+
assert s.to_python(nan, mode='json') is None
624+
assert s.to_json(nan) == b'null'
625+
626+
627+
def test_ser_json_inf_nan_with_list_of_any() -> None:
628+
s = SchemaSerializer(
629+
core_schema.list_schema(core_schema.any_schema()), core_schema.CoreConfig(ser_json_inf_nan='constants')
630+
)
631+
assert isinf(s.to_python([inf])[0])
632+
assert isinf(s.to_python([inf], mode='json')[0])
633+
assert s.to_json([inf]) == b'[Infinity]'
634+
assert isnan(s.to_python([nan])[0])
635+
assert isnan(s.to_python([nan], mode='json')[0])
636+
assert s.to_json([nan]) == b'[NaN]'
637+
638+
s = SchemaSerializer(
639+
core_schema.list_schema(core_schema.any_schema()), core_schema.CoreConfig(ser_json_inf_nan='null')
640+
)
641+
assert isinf(s.to_python([inf])[0])
642+
assert s.to_python([inf], mode='json')[0] is None
643+
assert s.to_json([inf]) == b'[null]'
644+
assert isnan(s.to_python([nan])[0])
645+
assert s.to_python([nan], mode='json')[0] is None
646+
assert s.to_json([nan]) == b'[null]'

0 commit comments

Comments
 (0)