pydantic / pydantic-core

Core validation logic for pydantic written in rust
MIT License
1.42k stars 236 forks source link

`SchemaSerializer.to_json` behavior on `nan` values #1416

Closed sreeprasannar closed 2 months ago

sreeprasannar commented 2 months ago

Related to https://github.com/pydantic/pydantic/issues/10037

from pydantic_core import SchemaSerializer, core_schema
s = SchemaSerializer(core_schema.literal_schema([0.1]))
s.to_python(float("nan")) # outputs: nan
s.to_json(float("nan")) # outputs: b'null'

New to pydantic-core but the issue here points out that the behavior of model_dump_json() and model_dump(mode="json") should be the same -- if so, then should s.to_json(float("nan")) output b'NaN' instead of b'null'?

sreeprasannar commented 2 months ago

I checked here (and also tried this):

>>> json.loads('{"a": NaN, "b": "12345"}')
{'a': nan, 'b': '12345'}

so json can handle NaN so outputting NaN seems more in-line with the RFC

sreeprasannar commented 2 months ago

This seems like the most obvious place to make the change -- I haven't figured out how to work with Rust + Python together yet. But I believe this could help?

sreeprasannar commented 2 months ago

Looks like the default value for inf_nan_mode=InfNanMode::Null in this line

sreeprasannar commented 2 months ago

okay, more exploration and I think the simple way to get the NaN behaviour is by passing in a config for ser_json_inf_nan:

from pydantic_core import SchemaSerializer, core_schema, CoreConfig
s = SchemaSerializer(core_schema.float_schema(), config=CoreConfig(ser_json_inf_nan="constants"))
print(s.to_json(float("nan"))) # outputs: b'NaN'

Is this only available in pydantic-core or can it be passed in from pydantic as well?

sreeprasannar commented 2 months ago

turns out ConfigDict does exactly this (more info in this comment on the original issue)