Skip to content

Instantly share code, notes, and snippets.

@rodrigoddc
Created April 26, 2023 01:27
Show Gist options
  • Select an option

  • Save rodrigoddc/a8d6b1e617427513f7c1f85e746872e8 to your computer and use it in GitHub Desktop.

Select an option

Save rodrigoddc/a8d6b1e617427513f7c1f85e746872e8 to your computer and use it in GitHub Desktop.
SQLAlchemy ORM models + Pydantic with custom composite Field
from uuid import UUID
from pydantic.class_validators import validator
from pydantic.main import BaseModel
from pydantic.types import UUID4
from sqlalchemy import Column, String, Uuid
from sqlalchemy.orm import declarative_base
Base = declarative_base()
class ContactModel(Base):
__tablename__ = "contacts"
id = Column(Uuid, primary_key=True)
email = Column(String, nullable=False)
class Email(BaseModel):
value: str
class Config:
orm_mode = True
class Id(BaseModel):
value: UUID4
class Config:
orm_mode = True
def default_parser(value: str | dict) -> dict:
if isinstance(value, str) and not value:
raise ValueError("value cannot be empty")
if isinstance(value, str) or isinstance(value, UUID):
return {'value': value}
return value
class Contact(BaseModel):
id: Id
email: Email
class Config:
orm_mode = True
json_encoders = {
Id: lambda v: str(v.value),
Email: lambda v: v.value,
}
_parse_id = validator("id", pre=True, allow_reuse=True)(default_parser)
_parse_email = validator("email", pre=True, allow_reuse=True)(default_parser)
def dict(self, *args, **kwargs):
base_dict = super().dict(*args, **kwargs)
for field, value in base_dict.items():
if isinstance(value, dict) and 'value' in value:
base_dict[field] = value['value']
return base_dict
import pytest
from uuid import UUID
from pydantic.error_wrappers import ValidationError
from main import Email, Contact, ContactModel, Id
def test_email_schema():
email = Email(value='[email protected]')
assert email.value == '[email protected]'
def test_contact_schema_id_as_dict():
contact = Contact(
**{
'id': {'value': 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'},
'email': {'value': '[email protected]'}
}
)
assert contact.id == Id(value=UUID('a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'))
assert contact.email.value == '[email protected]'
def test_contact_schema_id_as_str():
contact = Contact(
**{
'id': 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11',
'email': {'value': '[email protected]'}
}
)
assert contact.id == Id(value=UUID('a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'))
assert contact.email.value == '[email protected]'
def test_contact_schema_email_as_dict():
contact = Contact(
**{
'id': 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11',
'email': {'value': '[email protected]'}
}
)
assert contact.id == Id(value=UUID('a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'))
assert contact.email.value == '[email protected]'
def test_contact_schema_email_as_str():
contact = Contact(
**{
'id': Id(value=UUID('a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11')),
'email': '[email protected]'
}
)
assert contact.id == Id(value=UUID('a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'))
assert contact.email.value == '[email protected]'
def test_contact_schema_dict_representation():
contact = Contact(
id=Id(value=UUID('a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11')),
email='[email protected]'
)
assert contact.dict() == {
'id': UUID('a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'),
'email': '[email protected]'
}
def test_contact_schema_json_representation():
contact = Contact(
id=Id(value=UUID('a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11')),
email='[email protected]'
)
assert contact.json(models_as_dict=False) == '{"id": "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11", "email": "[email protected]"}'
assert contact.json() == '{"id": {"value": "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11"}, "email": {"value": "[email protected]"}}'
def test_contact_schema_raises_when_id_empty_string():
with pytest.raises(ValidationError) as e:
contact = Contact(
id='',
email='[email protected]'
)
assert 'value cannot be empty' in str(e.value)
def test_contact_schema_raises_when_email_empty_string():
with pytest.raises(ValidationError) as e:
contact = Contact(
id=Id(value=UUID('a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11')),
email=''
)
assert 'value cannot be empty' in str(e.value)
def test_contact_schema_from_model():
model = ContactModel(
id=UUID('a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'),
email='[email protected]'
)
contact = Contact.from_orm(model)
assert contact.id == Id(value=UUID('a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'))
assert contact.email.value == '[email protected]'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment