developmentseed / geojson-pydantic

Pydantic data models for the GeoJSON spec
https://developmentseed.org/geojson-pydantic/
MIT License
232 stars 35 forks source link

Unable to use field_serializer with fields allowed to be only a Point #156

Open void-rooster opened 8 months ago

void-rooster commented 8 months ago

We have to provide coordinates with 6 digits of precision and use a field serializer to do so. Curiously, we can use the serializer on fields allowed to be either a Point or a Polygon, but not with fields allowed to be only a Point.

This produces a SchemaError:

from pydantic import BaseModel, field_serializer
from geojson_pydantic import Point

class Test(BaseModel):
    point: Point
    @field_serializer("point")
    def six_digits_precision(self, pt: Point) -> Point:
        rounded_coords = [round(coord, 6) for coord in pt.coordinates]
        return Point(type="Point", coordinates=rounded_coords)

traceback:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/kpenner/mambaforge/envs/pydantic/lib/python3.12/site-packages/pydantic/_internal/_model_construction.py", line 183, in __new__
    complete_model_class(
  File "/home/kpenner/mambaforge/envs/pydantic/lib/python3.12/site-packages/pydantic/_internal/_model_construction.py", line 535, in complete_model_class
    cls.__pydantic_validator__ = create_schema_validator(
                                 ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/kpenner/mambaforge/envs/pydantic/lib/python3.12/site-packages/pydantic/plugin/_schema_validator.py", line 49, in create_schema_validator
    return SchemaValidator(schema, config)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
pydantic_core._pydantic_core.SchemaError: Definitions error: definition `geojson_pydantic.geometries.Point:94014434282928` was never filled

without the field serializer, or with the field serializer and different treatment for coordinate extraction based on Point vs Polygon, it succeeds.

vincentsarago commented 6 months ago

Maybe related to https://github.com/pydantic/pydantic/issues/8984 🤷

vincentsarago commented 6 months ago

add the same time you could do something like

from pydantic import field_serializer
from geojson_pydantic import Point
from geojson_pydantic.types import Position

class MyPoint(Point):

    @field_serializer("coordinates")
    def six_digits_precision(self, coords: Position) -> Position:
        rounded_coords = [round(coord, 6) for coord in coords]
        return tuple(rounded_coords)

MyPoint(type="Point", coordinates=(0.000000000001,0)).model_dump(exclude_none=True)
>> {'type': 'Point', 'coordinates': (0.0, 0.0)}