datamodel-code-generator
datamodel-code-generator copied to clipboard
`multipleOf` and `number` translations yield unstable Pydantic models.
Describe the bug
Pydantic has an underlying bug when using multiple_of with float, and is covered here. To my knowledge, Decimal is more stable in this regard.
To Reproduce
Here is a small program to showcase the instability of float vs. Decimal.
from decimal import Decimal
import pydantic
from pydantic import BaseModel, Field
class A(BaseModel):
a: float = Field(multiple_of=0.1)
class B(BaseModel):
a: Decimal = Field(multiple_of=0.1)
def test_class(cls):
error_value = None
for i in range(100):
v = (i - 50) / 10
try:
cls(a=v)
except pydantic.ValidationError:
error_value = v
break
if error_value:
print(f"Got validation error with value: {error_value}")
else:
print("No validation errors")
def main():
print("Testing float with `multiple_of``")
test_class(A)
print("Testing Decimal with `multiple_of`")
test_class(B)
if __name__ == "__main__":
main()
Example schema:
...
Energy: {type: number, format: realenergy, multipleOf: 0.1, minimum: -9.99999999E7,
maximum: 9.99999999E7, example: 1200.7}
...
Will map to:
class Energy(RootModel[confloat(ge=-99999999.9, le=99999999.9, multiple_of=0.1)]):
root: confloat(ge=-99999999.9, le=99999999.9, multiple_of=0.1) = Field(
...,
examples=[1200.7],
)
I think it would be more sane to map to Decimal as soon as multipleOf is a requirement.
This would be a breaking change though, no?
Yes, it would. It is unfortunately non-trivial how to progress from here.
I'd also be interested in having the ability to translate multipleOf float as Decimal. Maybe it could take the form of an option?