Skip to content

Commit

Permalink
fix: nested ORM from nested dictionaries (#3182)
Browse files Browse the repository at this point in the history
closes #3181
  • Loading branch information
PrettyWood committed Dec 19, 2021
1 parent 5ad73d0 commit 93faefb
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 6 deletions.
8 changes: 5 additions & 3 deletions pydantic/main.py
Expand Up @@ -669,10 +669,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 @@ -682,6 +682,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
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'}})

0 comments on commit 93faefb

Please sign in to comment.