Files
pydantic/tests/test_orm_mode.py
T
Samuel Colvin 3dfae21208 ORM mode: Add support for arbitrary class instances (#562)
* Support ORM objects to 'parse_obj', replace #520

* switch to GetterDict and orm_mode

* tweaks

* update docs

* split tests and add @tiangolo's suggestion

* split tests and add @tiangolo's suggestion

* fix coverage
2019-06-06 11:29:09 +01:00

169 lines
3.4 KiB
Python

from typing import List
import pytest
from pydantic import BaseModel, ConfigError, ValidationError
from pydantic.utils import GetterDict
def test_getdict():
class TestCls:
a = 1
b: int
def __init__(self):
self.c = 3
@property
def d(self):
return 4
def __getattr__(self, key):
if key == 'e':
return 5
else:
raise AttributeError()
t = TestCls()
gd = GetterDict(t)
assert gd.keys() == set()
assert gd.get('a', None) == 1
assert gd.get('b', None) is None
assert gd.get('b', 1234) == 1234
assert gd.get('c', None) == 3
assert gd.get('d', None) == 4
assert gd.get('e', None) == 5
assert gd.get('f', 'missing') == 'missing'
def test_orm_mode():
class PetCls:
def __init__(self, *, name: str, species: str):
self.name = name
self.species = species
class PersonCls:
def __init__(self, *, name: str, age: float = None, pets: List[PetCls]):
self.name = name
self.age = age
self.pets = pets
class Pet(BaseModel):
name: str
species: str
class Config:
orm_mode = True
class Person(BaseModel):
name: str
age: float = None
pets: List[Pet]
class Config:
orm_mode = True
bones = PetCls(name='Bones', species='dog')
orion = PetCls(name='Orion', species='cat')
anna = PersonCls(name='Anna', age=20, pets=[bones, orion])
anna_model = Person.from_orm(anna)
assert anna_model.dict() == {
'name': 'Anna',
'pets': [{'name': 'Bones', 'species': 'dog'}, {'name': 'Orion', 'species': 'cat'}],
'age': 20.0,
}
def test_not_orm_mode():
class Pet(BaseModel):
name: str
species: str
with pytest.raises(ConfigError):
Pet.from_orm(None)
def test_object_with_getattr():
class FooGetAttr:
def __getattr__(self, key: str):
if key == 'foo':
return 'Foo'
else:
raise AttributeError
class Model(BaseModel):
foo: str
bar: int = 1
class Config:
orm_mode = True
class ModelInvalid(BaseModel):
foo: str
bar: int
class Config:
orm_mode = True
foo = FooGetAttr()
model = Model.from_orm(foo)
assert model.foo == 'Foo'
assert model.bar == 1
assert model.dict(skip_defaults=True) == {'foo': 'Foo'}
with pytest.raises(ValidationError):
ModelInvalid.from_orm(foo)
def test_properties():
class XyProperty:
x = 4
@property
def y(self):
return '5'
class Model(BaseModel):
x: int
y: int
class Config:
orm_mode = True
model = Model.from_orm(XyProperty())
assert model.x == 4
assert model.y == 5
def test_extra_allow():
class TestCls:
x = 1
y = 2
class Model(BaseModel):
x: int
class Config:
orm_mode = True
extra = 'allow'
model = Model.from_orm(TestCls())
assert model.dict() == {'x': 1}
def test_extra_forbid():
class TestCls:
x = 1
y = 2
class Model(BaseModel):
x: int
class Config:
orm_mode = True
extra = 'forbid'
model = Model.from_orm(TestCls())
assert model.dict() == {'x': 1}