Metadata-Version: 2.4
Name: oclarcdo
Version: 0.2.0
Summary: DDD-oriented domain primitives and abstractions for any Python stack (framework-agnostic).
Project-URL: Homepage, https://github.com/o-shabi/odex-clarc-domain-python
Project-URL: Documentation, https://github.com/o-shabi/odex-clarc-domain-python#readme
Project-URL: Repository, https://github.com/o-shabi/odex-clarc-domain-python
Project-URL: Issues, https://github.com/o-shabi/odex-clarc-domain-python/issues
Project-URL: Changelog, https://github.com/o-shabi/odex-clarc-domain-python/blob/main/CHANGELOG.md
Author: Asen O'Shabi
License-Expression: MIT
License-File: LICENSE
Keywords: aggregates,clarc,clean-architecture,ddd,domain-events,python,specification
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries
Classifier: Typing :: Typed
Requires-Python: >=3.12
Description-Content-Type: text/markdown

# oclarcdo

[![PyPI](https://img.shields.io/pypi/v/oclarcdo)](https://pypi.org/project/oclarcdo/)
[![Python](https://img.shields.io/pypi/pyversions/oclarcdo)](https://pypi.org/project/oclarcdo/)
[![CI](https://github.com/o-shabi/odex-clarc-domain-python/actions/workflows/ci.yml/badge.svg)](https://github.com/o-shabi/odex-clarc-domain-python/actions/workflows/ci.yml)
[![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)

Reusable **domain-layer** building blocks for **Python**: aggregates, domain events, specifications, guard policies, persistence-oriented repository protocols, and transaction abstractions. **No web framework or ORM dependency**—use from FastAPI, Django, CLI tools, or any host.

This package is the Python equivalent of [**Odex.AspNetCore.Clarc.Domain**](https://www.nuget.org/packages/Odex.AspNetCore.Clarc.Domain) on .NET.

---

## Installation

```bash
pip install oclarcdo
```

With [uv](https://docs.astral.sh/uv/):

```bash
uv add oclarcdo
```

Pin a version for reproducible builds:

```bash
pip install oclarcdo==0.2.0
```

---

## Requirements

| Item | Version |
|------|---------|
| **Python** | 3.12+ |
| **Runtime dependencies** | None |

---

## How it fits in CLARC / clean architecture

| Layer | Responsibility | Typical CLARC package |
|-------|----------------|------------------------|
| **Domain** | Entities, value objects, domain services, invariants, aggregate events (raised, not dispatched) | **This package** |
| **Application** | Use cases, commands/queries, handlers, orchestration | Your application layer |
| **Infrastructure** | Persistence, external APIs, event dispatch, DI | Your infrastructure layer |

**Repository protocols** accept callables for predicates so implementations can filter in memory or translate to SQL (for example with SQLAlchemy). Wiring DI, ORMs, outboxes, and mediators stays in **Application** and **Infrastructure**.

---

## Capabilities

| Area | Types (summary) |
|------|------------------|
| **Aggregates** | `BaseAggregate` — identity, audit timestamps, in-memory domain events. `StatefulAggregate` — activation and soft-delete flags. |
| **Events** | `AggregateEventProtocol`, `AggregateEvent` — correlation id and `occurred_on`; collect with `_add_event`, read with `list_events`, clear after dispatch. |
| **Specifications** | `Specification` with `and_` / `or_` / `not_`; `to_predicate()` for repositories and in-memory checks. |
| **Policies** | `PolicyProtocol`, `BasePolicy` — `require_not_null`, `require_not_null_nor_empty`, `require_null_or_empty`, `require_true` / `require_false`, etc. |
| **Repositories** | `BaseRepositoryProtocol` — `save_changes_async`, `execute_in_transaction_async`. `AggregateRepositoryProtocol` — async reads/writes, attach helpers. |
| **Services** | `BaseService`, `AggregateService` — transaction and save delegation. |
| **Transactions** | `TransactionContextProtocol` — cooperative rollback signalling. |
| **Exceptions** | `DomainException`, `PolicyViolationException`, `EntityNotFoundException`, `ConcurrencyException`, `InvalidEntityStateException` with `ExceptionType`. |
| **Value objects / DTO markers** | `BaseValueObject`, `BaseRequest`, `BaseResponse`, `PagedRequest`, `PagedResponse`, `BaseData`. |

---

## Examples

### Aggregate and policy

```python
from uuid import UUID, uuid4

from oclarcdo import AggregateEvent, BasePolicy, StatefulAggregate


class ProductRenamed(AggregateEvent):
    product_id: UUID
    new_name: str


class Product(StatefulAggregate[UUID]):
    def __init__(self, name: str) -> None:
        super().__init__()
        self.id = uuid4()
        self.name = name

    def rename(self, new_name: str) -> None:
        BasePolicy[str]().require_not_null_nor_empty(new_name)
        self.name = new_name
        self.mark_modified()
        self._add_event(ProductRenamed(product_id=self.id, new_name=new_name))
```

### Specification

```python
from oclarcdo import Specification


class ActiveUsersSpec(Specification[User]):
    def to_predicate(self):
        return lambda u: u.is_active


spec = ActiveUsersSpec().and_(UserNameContainsSpec("alex"))
await repository.list_async(spec.to_predicate())
```

### Application service

```python
from oclarcdo import AggregateService


class ProductService(AggregateService):
    def __init__(self, products: AggregateRepositoryProtocol[Product, UUID]) -> None:
        super().__init__(products)
        self._products = products

    async def create_async(self, name: str) -> Product:
        product = Product(name)
        await self._products.add_async(product)
        await self.save_repository_changes_async()
        return product
```

---

## Development

See [CONTRIBUTING.md](CONTRIBUTING.md).

```bash
git clone https://github.com/o-shabi/odex-clarc-domain-python.git
cd odex-clarc-domain-python
uv sync --all-groups
uv run pytest
uv run ruff check .
uv run mypy
```

---

## License

MIT — Copyright (c) Asen O'Shabi. See [LICENSE](LICENSE).

---

## Links

| Resource | URL |
|----------|-----|
| PyPI | https://pypi.org/project/oclarcdo/ |
| .NET (NuGet) counterpart | https://www.nuget.org/packages/Odex.AspNetCore.Clarc.Domain |
| Changelog | https://github.com/o-shabi/odex-clarc-domain-python/blob/main/CHANGELOG.md |
| Source / issues | https://github.com/o-shabi/odex-clarc-domain-python |
