Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: nested ORM from nested dictionaries #3182

Merged
merged 1 commit into from Dec 19, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 5 additions & 3 deletions pydantic/main.py
Expand Up @@ -656,10 +656,10 @@ def validate(cls: Type['Model'], value: Any) -> 'Model':

value = cls._enforce_dict_if_root(value)

if cls.__config__.orm_mode:
return cls.from_orm(value)
elif isinstance(value, dict):
if isinstance(value, dict):
return cls(**value)
elif cls.__config__.orm_mode:
return cls.from_orm(value)
else:
try:
value_as_dict = dict(value)
Expand All @@ -669,6 +669,8 @@ def validate(cls: Type['Model'], value: Any) -> 'Model':

@classmethod
def _decompose_class(cls: Type['Model'], obj: Any) -> GetterDict:
if isinstance(obj, GetterDict):
return obj
return cls.__config__.getter_dict(obj)

@classmethod
Expand Down
27 changes: 24 additions & 3 deletions tests/test_orm_mode.py
@@ -1,3 +1,4 @@
from types import SimpleNamespace
from typing import Any, Dict, List

import pytest
Expand Down Expand Up @@ -305,15 +306,14 @@ class Config:


def test_recursive_parsing():
from types import SimpleNamespace

class Getter(GetterDict):
# try to read the modified property name
# either as an attribute or as a key
def get(self, key, default):
key = key + key
try:
return self._obj[key]
v = self._obj[key]
return Getter(v) if isinstance(v, dict) else v
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nuno-andre Would it make sense to you?

except TypeError:
return getattr(self._obj, key, default)
except KeyError:
Expand All @@ -337,3 +337,24 @@ class ModelB(Model):
# test recursive parsing with dict keys
obj = dict(bb=dict(aa=1))
assert ModelB.from_orm(obj) == ModelB(b=ModelA(a=1))


def test_nested_orm():
class User(BaseModel):
first_name: str
last_name: str

class Config:
orm_mode = True

class State(BaseModel):
user: User

class Config:
orm_mode = True

# Pass an "orm instance"
State.from_orm(SimpleNamespace(user=SimpleNamespace(first_name='John', last_name='Appleseed')))

# Pass dictionary data directly
State(**{'user': {'first_name': 'John', 'last_name': 'Appleseed'}})