Nested models with extendable classes not working
Closed this issue · 3 comments
First, thanks for your work on the extendable libs!
I have tried to do some extendable pydantic schemas with nested model but I have some strange behaviors.
Examples :
from pydantic import BaseModel
from extendable_pydantic import ExtendableModelMeta
from extendable import context, registry
from typing import Optional
class Location(BaseModel, metaclass=ExtendableModelMeta):
lat: float = 0.1
lng: float = 10.1
class ExtendedLocation(Location, extends=Location):
name: str
class Time(BaseModel, metaclass=ExtendableModelMeta):
hour: int
class Event(BaseModel, metaclass=ExtendableModelMeta):
location: Location
time: Optional[Time] = None
_registry = registry.ExtendableClassesRegistry()
context.extendable_registry.set(_registry)
_registry.init_registry()
data = {"location": {"lat": 12.3, "lng": 13.2, "name": "My Loc"}}
event = Event(**data)
This code give me the error :
time
Field required [type=missing, input_value={'location': {'lat': 12.3...13.2, 'name': 'My Loc'}}, input_type=dict]
For further information visit https://errors.pydantic.dev/2.1.2/v/missing
I think it should not, because I did specify a default Value for the nested model Time
on Event
Class. So this field should be optional and not raise an error.
If I remove the metaclass from my main Event
class, the problem does not appear, so this code don't give me any error (which seems correct) :
from pydantic import BaseModel
from extendable_pydantic import ExtendableModelMeta
from extendable import context, registry
from typing import Optional
class Location(BaseModel, metaclass=ExtendableModelMeta):
lat: float = 0.1
lng: float = 10.1
class ExtendedLocation(Location, extends=Location):
name: str
class Time(BaseModel):
hour: int
class Event(BaseModel):
location: Location
time: Optional[Time] = None
_registry = registry.ExtendableClassesRegistry()
context.extendable_registry.set(_registry)
_registry.init_registry()
data = {"location": {"lat": 12.3, "lng": 13.2, "name": "My Loc"}}
event = Event(**data)
I quite surprised because the only change is not setting the Event
class as extendable, I guess it should not change the validation behavior.
Also, removing the extendable attribute from Event
class seems to break the extendability of the Location
class.
I mean, the ExtendedLocation
class does not seem to extend Location
any more, see if we remove the mandatory field name
from the data :
from pydantic import BaseModel
from extendable_pydantic import ExtendableModelMeta
from extendable import context, registry
from typing import Optional
class Location(BaseModel, metaclass=ExtendableModelMeta):
lat: float = 0.1
lng: float = 10.1
class ExtendedLocation(Location, extends=Location):
name: str
class Time(BaseModel):
hour: int
class Event(BaseModel):
location: Location
time: Optional[Time] = None
_registry = registry.ExtendableClassesRegistry()
context.extendable_registry.set(_registry)
_registry.init_registry()
data = {"location": {"lat": 12.3, "lng": 13.2}}
event = Event(**data)
This should give a missing error of field name from Location class but it does not.
Here are the version of lib used :
extendable==1.2.0
extendable_pydantic==1.1.0
pydantic==2.0.2
python 3.10
@florian-dacosta @hparfr I'll take a look as soon as I've some time. It's strange since I've tests on these specific cases.
@florian-dacosta @hparfr #16 fix your problem.
Regarding your last code snippet
from pydantic import BaseModel
from extendable_pydantic import ExtendableModelMeta
from extendable import context, registry
from typing import Optional
class Location(BaseModel, metaclass=ExtendableModelMeta):
lat: float = 0.1
lng: float = 10.1
class ExtendedLocation(Location, extends=Location):
name: str
class Time(BaseModel):
hour: int
class Event(BaseModel):
location: Location
time: Optional[Time] = None
_registry = registry.ExtendableClassesRegistry()
context.extendable_registry.set(_registry)
_registry.init_registry()
data = {"location": {"lat": 12.3, "lng": 13.2}}
event = Event(**data)
This must not give a missing error for the field name
from Location class. The Event
is not extendable. Therefore, even if a nested class is extendable, the type definition must be the one defined at writing time and we will never try to resolve nested types.