The Python "to_dict" method fails when generated from JSON schema with properties of type "number" which are assigned an integer value
douggish opened this issue · 0 comments
Consider the example JSON schema:
{
"id": "http://json-schema.org/geo",
"$schema": "http://json-schema.org/draft-06/schema#",
"description": "A geographical coordinate",
"type": "object",
"properties": {
"latitude": {
"type": "number"
},
"longitude": {
"type": "number"
}
}
}
Quicktype generates the following Python code:
from dataclasses import dataclass
from typing import Optional, Any, TypeVar, Type, cast
T = TypeVar("T")
def from_float(x: Any) -> float:
assert isinstance(x, (float, int)) and not isinstance(x, bool)
return float(x)
def from_none(x: Any) -> Any:
assert x is None
return x
def from_union(fs, x):
for f in fs:
try:
return f(x)
except:
pass
assert False
def to_float(x: Any) -> float:
assert isinstance(x, float)
return x
def to_class(c: Type[T], x: Any) -> dict:
assert isinstance(x, c)
return cast(Any, x).to_dict()
@dataclass
class Coordinate:
"""A geographical coordinate"""
latitude: Optional[float] = None
longitude: Optional[float] = None
@staticmethod
def from_dict(obj: Any) -> 'Coordinate':
assert isinstance(obj, dict)
latitude = from_union([from_float, from_none], obj.get("latitude"))
longitude = from_union([from_float, from_none], obj.get("longitude"))
return Coordinate(latitude, longitude)
def to_dict(self) -> dict:
result: dict = {}
if self.latitude is not None:
result["latitude"] = from_union([to_float, from_none], self.latitude)
if self.longitude is not None:
result["longitude"] = from_union([to_float, from_none], self.longitude)
return result
def coordinate_from_dict(s: Any) -> Coordinate:
return Coordinate.from_dict(s)
def coordinate_to_dict(x: Coordinate) -> Any:
return to_class(Coordinate, x)
The problem is that if you create an instance of Coordinate
with literal integer parameters and then call to_dict()
:
coordinate = Coordinate(10, 20)
print(coordinate.to_dict())
then you get an AssertionError:
Traceback (most recent call last):
File "/tmp/sessions/4a8af4124d815246/main.py", line 71, in <module>
print(coordinate.to_dict())
File "/tmp/sessions/4a8af4124d815246/main.py", line 53, in to_dict
result["latitude"] = from_union([to_float, from_none], self.latitude)
File "/tmp/sessions/4a8af4124d815246/main.py", line 24, in from_union
assert False
AssertionError
This should be expected to work since JSON schema spec defines the number
type like this:
The number type is used for any numeric type, either integers or floating point numbers.
Also, note that in Python the "float" type hint also deems an int as acceptable:
Rather than requiring that users write import numbers and then use numbers.Float etc., this PEP proposes a straightforward shortcut that is almost as effective: when an argument is annotated as having type float, an argument of type int is acceptable