Skip to main content

Adding entities

Entities form the domain model of the application.

An entity can be an object with methods, or it can be a set of data structures and functions. It should be a regular class, a dataclass, or a value object (if all the properties are the same, two objects are identical). Entities hold data (state) and logic reusable for various applications.

from dataclasses import asdict, dataclass, fields


@dataclass(frozen=True)
class TodoItem:
id: str
user_id: str
title: str
is_completed: bool = False

def to_dict(self) -> dict[str, str | bool]:
return asdict(self)

@classmethod
def from_dict(cls, dict_: dict[str, str | bool]) -> "TodoItem":
class_fields = {f.name for f in fields(cls)}
if "_id" in dict_:
dict_["id"] = dict_.pop("_id")
data = {k: v for k, v in dict_.items() if k in class_fields}
return TodoItem(**data) # type:ignore
info

Entities must not depend on anything, except possibly other entities.

Entities should be the most stable code within your application.

Entities should not be affected by any change external to them.

Testing entities

import uuid

from features.todo.entities.todo_item import TodoItem


def test_todo_item_init():
id = str(uuid.uuid4())
todo = TodoItem(id=id, title="title 1", is_completed=False, user_id="xyz")
assert todo.id == id
assert todo.title == "title 1"
assert not todo.is_completed


def test_todo_item_from_dict():
id = str(uuid.uuid4())
init_dict = {"id": id, "title": "title 1", "is_completed": False, "user_id": "xyz"}
todo = TodoItem.from_dict(init_dict)

assert todo.id == id
assert todo.title == "title 1"
assert not todo.is_completed


def test_todo_item_comparison():
id = str(uuid.uuid4())
init_dict = {"id": id, "title": "title 1", "is_completed": False, "user_id": "xyz"}
todo1 = TodoItem.from_dict(init_dict)
todo2 = TodoItem.from_dict(init_dict)

assert todo1 == todo2