Skip to content

Instantly share code, notes, and snippets.

@SamWarden
Last active February 5, 2023 15:21
Show Gist options
  • Save SamWarden/00025424b8025c1b2cddb12b035a6604 to your computer and use it in GitHub Desktop.
Save SamWarden/00025424b8025c1b2cddb12b035a6604 to your computer and use it in GitHub Desktop.
Tests for dataclass_factory
from typing import Any, Callable, TypeVar
from dataclass_factory import Loader, Mediator, Request
from dataclass_factory._internal.provider import LoaderProvider, LoaderRequest
from dataclass_factory._internal.provider.request_filtering import ExactOriginRC
TModel = TypeVar("TModel")
TData = TypeVar("TData")
class Converter(LoaderProvider):
def __init__(self, from_cls: type[TData], to_cls: type[TModel], loader: Callable[[TData], TModel]):
self._from_cls = from_cls
self._to_cls = to_cls
self._loader = loader
self._request_checker = ExactOriginRC(to_cls)
def _check_request(self, mediator: Mediator, request: Request) -> None:
self._request_checker.check_request(mediator, request)
def _provide_loader(self, mediator: Mediator, request: LoaderRequest) -> Loader:
next_loader = mediator.provide_from_next()
def model_to_model_loader(data):
if not isinstance(data, self._from_cls):
_loader = next_loader
else:
_loader = self._loader
return _loader(data)
return model_to_model_loader
from dataclasses import dataclass
import pytest
from dataclass_factory import Retort
from dataclass_factory._internal.load_error import TypeLoadError
from tests.integration.converter import Converter
@dataclass
class User:
id: int
username: str
@dataclass
class Order:
id: int
owner_id: int
@dataclass
class DTO:
pass
@dataclass
class UserDTO(DTO):
user_id: str
username: str
@dataclass
class OrderDTO(DTO):
order_id: int
owner_id: int
@dataclass
class OrderOwner(User):
orders: list[Order]
@dataclass
class OrderOwnerDTO(UserDTO):
orders: list[OrderDTO]
DTOs = OrderDTO | UserDTO | OrderOwnerDTO
@dataclass
class UserModel:
user_id: int
username: str
# Converters
def convert_user_entity_to_dto(user: User) -> UserDTO:
return UserDTO(
user_id=str(user.id),
username=user.username,
)
def convert_order_entity_to_dto(order: Order) -> OrderDTO:
return OrderDTO(
order_id=order.id,
owner_id=order.owner_id,
)
def convert_order_owner_entity_to_dto(order_owner: OrderOwner) -> OrderOwnerDTO:
return OrderOwnerDTO(
user_id=str(order_owner.id),
username=order_owner.username,
orders=[
OrderDTO(order_id=order.id, owner_id=order.owner_id)
for order in order_owner.orders
],
)
def convert_user_model_to_dto(user: UserModel) -> UserDTO:
return UserDTO(
user_id=str(user.user_id),
username=user.username,
)
# Tests
def test_convert_entity_to_dto():
retort = Retort(recipe=(
Converter(User, UserDTO, convert_user_entity_to_dto),
))
assert retort.load(User(1, "Jon"), UserDTO) == UserDTO("1", "Jon")
def test_raise_error_on_wrong_entity_conversion():
retort = Retort(recipe=(
Converter(User, UserDTO, convert_user_entity_to_dto),
))
with pytest.raises(TypeLoadError):
retort.load(Order(1, 100), UserDTO)
def test_convert_entity_to_unknown_dto():
retort = Retort(recipe=(
Converter(User, UserDTO, convert_user_entity_to_dto),
Converter(Order, OrderDTO, convert_order_entity_to_dto),
))
assert retort.load(User(1, "Jon"), UserDTO) == UserDTO("1", "Jon")
assert retort.load(Order(1, 100), OrderDTO) == OrderDTO(1, 100)
assert retort.load(User(1, "Jon"), DTOs) == UserDTO("1", "Jon")
assert retort.load(Order(1, 100), DTOs) == OrderDTO(1, 100)
def test_convert_sequence_entities_to_list_dtos():
retort = Retort(recipe=(
Converter(User, UserDTO, convert_user_entity_to_dto),
Converter(Order, OrderDTO, convert_order_entity_to_dto),
))
assert retort.load([User(1, "Jon"), Order(1, 100)], list[DTOs]) == [UserDTO("1", "Jon"), OrderDTO(1, 100)]
assert retort.load((User(1, "Jon"), Order(1, 100)), list[DTOs]) == [UserDTO("1", "Jon"), OrderDTO(1, 100)]
@pytest.mark.skip("Convert to tuple of dataclasses not working now")
def test_convert_sequence_entities_to_tuple_dtos():
retort = Retort(recipe=(
Converter(User, UserDTO, convert_user_entity_to_dto),
Converter(Order, OrderDTO, convert_order_entity_to_dto),
))
assert retort.load((User(1, "Jon"), Order(1, 100)), tuple[UserDTO, OrderDTO]) == (UserDTO("1", "Jon"), OrderDTO(1, 100))
assert retort.load((User(1, "Jon"), Order(1, 100)), tuple[DTOs, DTOs]) == (UserDTO("1", "Jon"), OrderDTO(1, 100))
assert retort.load((User(1, "Jon"), Order(1, 100)), tuple[DTOs, ...]) == (UserDTO("1", "Jon"), OrderDTO(1, 100))
def test_convert_order_owner_entity_to_dto():
retort = Retort(recipe=(
Converter(User, UserDTO, convert_user_entity_to_dto),
Converter(Order, OrderDTO, convert_order_entity_to_dto),
Converter(OrderOwner, OrderOwnerDTO, convert_order_owner_entity_to_dto),
))
assert retort.load(
OrderOwner(1, "Jon", [Order(1, 100), Order(2, 200)]),
OrderOwnerDTO,
) == OrderOwnerDTO("1", "Jon", [OrderDTO(1, 100), OrderDTO(2, 200)])
def test_convert_model_to_dto():
retort = Retort(recipe=(
Converter(User, UserDTO, convert_user_entity_to_dto),
Converter(UserModel, UserDTO, convert_user_model_to_dto),
))
assert retort.load(User(1, "Jon"), UserDTO) == UserDTO("1", "Jon")
assert retort.load(UserModel(1, "Jon"), UserDTO) == UserDTO("1", "Jon")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment