Skip to main content

Classic Domain

Основывается на книге Эрика Эванса "Domain Driven Design: tackling complexity in the heart of software".

Предоставляет базовый примитив для описания языка предметной области - Criteria (Критерий).

Критерий нужен для описания выборки объектов. Есть два пути использования - через определение класса, и через декоратор.

Установка

pip install classic-domain

Критерии-классы

Представим себе, что у нас класс, олицетворяющий понятие из предметной области - задачу:

Также, представим себе, что в предметной области задача называется открытой, если нет времени завершения и просроченной, если больше работа не завершена больше какого-то количества дней.

Также представим, что нам необходимо получать из некоторого хранилища задачи, соответствующие этим критериям.

Задачу можно описать обычным датаклассом, а состояния задач - критериями. У критериев можно определить метод is_satisfied_by, которые будут определять, подходит ли объект под этот критерий или нет:

from datetime import datetime
from dataclasses import dataclass
from typing import Optional

from classic.domain import Criteria


@dataclass
class Task:
    created_at: datetime
    finished_at: Optional[datetime] = None


@dataclass
class Open(Criteria[Task]):
    """Критерий для открытых задач"""

    def is_satisfied_by(self, candidate: Task) -> bool:
        return candidate.finished_at is None

    
@dataclass
class Obsolete(Criteria[Task]):
    """Критерий для просроченных задач"""
    days_to_work: int

    def is_satisfied_by(self, candidate: Task) -> bool:
        return (
            candidate.finished_at is not None and
            (candidate.created_at - candidate.finished_at).days > self.days_to_work
        )

Затем описанные критерии можно использовать в разных сценариях.

Прямое использование

from datetime import datetime

some_task = Task(created_at=datetime(2025, 1, 1))
is_open = Open()

is_open.is_satisfied_by(some_task)
# True

Булева алгебра

Критерии можно связать логическими условиями:

from datetime import datetime

some_task = Task(created_at=datetime(2025, 1, 1))
some_crit = Open() | Obsolete(3)

some_crit.is_satisfied_by(some_task)
# True

Фильтрация

У критерия метод __call__ определен как алиас для is_satisfied_by. Это придает лаконичности при использовании критерия для фильтрации списка:

from datetime import datetime

tasks = [
    Task(created_at=datetime(2025, 1, 1)),
    Task(created_at=datetime(2025, 1, 1),
         finished_at=datetime(2025, 1, 5)),
    Task(created_at=datetime(2025, 1, 1),
         finished_at=datetime(2025, 1, 2)),
] 
some_crit = Open() | Obsolete(3)

filtered_tasks = filter(some_crit, tasks)
# True

Критерии-методы

Критерии можно определить как методы у класса (например, у самой сущности), используя декоратор criteria:

from datetime import datetime
from dataclasses import dataclass
from typing import Optional

from classic.domain import criteria


@dataclass
class Task:
    created_at: datetime
    finished_at: Optional[datetime] = None
    
    @criteria
    def open(self) -> bool:
        return self.finished_at is None
    
    @criteria
    def obsolete(self, days_to_work: int) -> bool:
        return (
            self.finished_at is not None and
            (self.created_at - self.finished_at).days > days_to_work
        )

У таких критериев есть две группы сценариев использования, использование на инстансах, и использование на классах.

Далее будут примеры с инстансами, аналогичные примерам выше.

Прямое использование

from datetime import datetime

some_task = Task(created_at=datetime(2025, 1, 1))

some_task.open()
# True

Булева алгебра:

from datetime import datetime

some_task = Task(created_at=datetime(2025, 1, 1))

some_task.open() or some_task.obsolete()
# True

Обратите внимание, что булева алгебра используется с and, 'or' и not.

Критерии-методы с классами

Критериев-методы можно использовать без инстансов, обращаясь к классам. При таком применении не произойдет проверки критерия. Полученный объект-критерий предоставляет собой отложенное условие:

from datetime import datetime

is_open = Task.open()  # Отложенная проверка

some_task = Task(created_at=datetime(2025, 1, 1))

is_open.is_satisfied_by(some_task)
# True

Фильтрация

Отложенные критерии также можно использовать для фильтрации списка:

from datetime import datetime

some_crit = Task.open() | Task.obsolete()

tasks = [
    Task(created_at=datetime(2025, 1, 1)),
    Task(created_at=datetime(2025, 1, 1),
         finished_at=datetime(2025, 1, 5)),
    Task(created_at=datetime(2025, 1, 1),
         finished_at=datetime(2025, 1, 2)),
]

filtered_tasks = filter(some_crit, tasks)
# True

Критерии-функции

Также можно использовать декоратор criteria на обычных функциях. Все свойства таких критериев абсолютно аналогичны варианту с методами:

from datetime import datetime
from dataclasses import dataclass
from typing import Optional

from classic.domain import criteria


@dataclass
class Task:
    created_at: datetime
    finished_at: Optional[datetime] = None
    

@criteria
def task_open(task: Task) -> bool:
    return task.finished_at is None


@criteria
def task_is_obsolete(task: Task, days_to_work: int) -> bool:
    return (
        task.finished_at is not None and
        (task.created_at - task.finished_at).days > days_to_work
    )

Выборки в БД

Также, критерии можно использовать для построения запросов к БД.

Этот раздел будет заполнен позднее, по мере готовности classic-db-tools

Metadata

Release files for classic-domain 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for classic-domain 0.2.0
File Size Uploaded Provenance
classic_domain-0.2.0.tar.gz 9.5 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for classic-domain 0.2.0
File Interpreter ABI Platform
classic_domain-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 17.7 kB

Release files / classic_domain-0.2.0.tar.gz

Download URL classic_domain-0.2.0.tar.gz
Size 9.5 kB
Tags Source
SHA-256 checksum
How to use checksums
8c490abc2f5c6605f3a334108f87d57ab79203408cb8ccf33d340a156fded984
BLAKE2b-256 checksum
How to use checksums
29896ad54b2a4d4cb2c76452e99d7782c88eb69cf56ae8bfd063bbe20be0432c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Mar 9, 2026.

Transparency log

Release files / classic_domain-0.2.0-py3-none-any.whl

Download URL classic_domain-0.2.0-py3-none-any.whl
Size 8.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
408785e9c8d4ce573417767e09797b75eaa6683b34554d33f67dcccf884942ea
BLAKE2b-256 checksum
How to use checksums
126329f0d523a6a286ab992fa99d20c4f7365dd63b499282f5635ce12e3fe40a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Mar 9, 2026.

Transparency log

Security for classic-domain 0.2.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for classic_domain-0.2.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Mar 9, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page