art049 / odmantic

Sync and Async ODM (Object Document Mapper) for MongoDB based on python type hints
http://art049.github.io/odmantic
ISC License
1.07k stars 93 forks source link

`model_validate_doc` consider `field(default=...)` but not `field(default_factory=...)` #507

Open d3cryptofc opened 3 weeks ago

d3cryptofc commented 3 weeks ago

Bug

When defining fields with a default parameter, the model_validate_doc function works as it should, but when using default_factory the function treats it as a mandatory field.

Current Behavior

from typing import Dict

from bson import ObjectId
from odmantic Model, Field

class Person(Model):
  phones: Dict = Field(default_factory=list)
In [1]: Person.model_validate_doc(dict(_id=ObjectId()))
---------------------------------------------------------------------------
DocumentParsingError                      Traceback (most recent call last)
Cell In[134], line 1
----> 1 Person.model_validate_doc(dict(_id=ObjectId()))

File .venv/lib/python3.12/site-packages/odmantic/model.py:805, in _BaseODMModel.model_validate_doc(cls, raw_doc)
    803 errors, obj = cls._parse_doc_to_obj(raw_doc)
    804 if len(errors) > 0:
--> 805     raise DocumentParsingError(
    806         errors=errors,
    807         model=cls,
    808     )
    809 try:
    810     instance = cls.model_validate(obj)
DocumentParsingError: 1 validation error for Person
phones
  Key 'phones' not found in document [type=odmantic::key_not_found_in_document, input_value={'_id': ObjectId('6723d87aee92661091c3c8bc')}, input_type=dict]

Expected behavior

In [1]: Person.model_validate_doc(dict(_id=ObjectId()))
Out[1]: Person(phones=[])

Environment

             pydantic version: 2.9.2
        pydantic-core version: 2.23.4
          pydantic-core build: profile=release pgo=false
                 install path: /home/lelzin/Projects/tests/git/odmantic/.venv/lib/python3.8/site-packages/pydantic
               python version: 3.8.17 (default, Jul  8 2023, 21:39:49)  [GCC 13.1.1 20230429]
                     platform: Linux-6.6.50-2-lts-x86_64-with-glibc2.34
             related packages: mypy-1.4.1 fastapi-0.115.4 typing_extensions-4.12.2
                       commit: unknown
d3cryptofc commented 3 weeks ago

I discovered that unlike pydantic.Field, odmantic.Field accepts non-literals in the default parameter, so default_factory becomes useless. But I'll leave the issue open in case anyone wants to work on it, even if it means adding a warning.