Skip to content

Instantly share code, notes, and snippets.

@dmontagu
Created June 15, 2019 06:33
Show Gist options
  • Save dmontagu/18bba9f3b748e525319e909a508a45a4 to your computer and use it in GitHub Desktop.
Save dmontagu/18bba9f3b748e525319e909a508a45a4 to your computer and use it in GitHub Desktop.
Inherit from APIModel instead of BaseModel to get from_orm functionality
from typing import Any, Dict, Set, Type, TypeVar
from pydantic import BaseConfig, BaseModel, ConfigError, DictError, validate_model
from pydantic.utils import change_exception
Model = TypeVar("Model", bound=BaseModel)
class APIModel(BaseModel):
class Config(BaseConfig):
orm_mode = True
@classmethod
def validate(cls: Type["Model"], value: Any) -> "Model":
if isinstance(value, dict):
return cls(**value)
elif isinstance(value, cls):
return value.copy()
elif cls.__config__.orm_mode:
return cls.from_orm(value)
else:
with change_exception(DictError, TypeError, ValueError):
return cls(**dict(value))
@classmethod
def from_orm(cls: Type["Model"], obj: Any) -> "Model":
if not cls.__config__.orm_mode:
raise ConfigError("You must have the config attribute orm_mode=True to use from_orm")
obj = cls._decompose_class(obj)
m = cls.__new__(cls)
values, fields_set, _ = validate_model(m, obj)
object.__setattr__(m, "__values__", values)
object.__setattr__(m, "__fields_set__", fields_set)
return m
@classmethod
def _decompose_class(cls: Type["Model"], obj: Any) -> "GetterDict":
return GetterDict(obj)
class GetterDict:
"""
Hack to make object's smell just enough like dicts for validate_model.
"""
__slots__ = ("_obj",)
def __init__(self, obj: Any):
self._obj = obj
def get(self, item: Any, default: Any) -> Any:
return getattr(self._obj, item, default)
def keys(self) -> Set[Any]:
"""
We don't want to get any other attributes of obj if the model didn't explicitly ask for them
"""
return set()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment