Platform shared library – DDD/Hexagonal building blocks for Python services
Project description
mp-commons
Platform shared library for Python microservices.
mp-commons delivers the "senior engineer pillars" as importable building
blocks so every service starts from a solid foundation without re-inventing
the wheel:
- DDD / Hexagonal Architecture — Entities, Value Objects, Aggregates, Domain Events, Repositories, Unit of Work
- CQRS — Command / Query buses with an in-process default
- Resilience — Retry (exponential + jitter), Circuit Breaker, Bulkhead, Timeouts
- Outbox / Inbox / Idempotency — at-least-once delivery with duplicate suppression
- Observability — structured logging, metrics, tracing (all via ports)
- Security — Principal, Policy Engine, PII redaction, OIDC/Keycloak adapter
- 12-factor Config — env-var loader, Kubernetes secrets, Vault
- Contract Testing — OpenAPI / AsyncAPI compatibility assertions
- Testing Support — in-memory fakes, pytest fixtures, chaos injection
Installation
# Core only (no third-party runtime deps)
pip install mp-commons
# With specific adapters
pip install "mp-commons[fastapi,sqlalchemy,redis,otel]"
# Everything
pip install "mp-commons[all-adapters]"
Available extras: fastapi, sqlalchemy, redis, kafka, nats,
rabbitmq, httpx, keycloak, vault, otel, pydantic, structlog,
tenacity, crypto, dotenv.
Quick Start
1. Define a Domain
from dataclasses import dataclass
from mp_commons.kernel.ddd import AggregateRoot, DomainEvent, Invariant
from mp_commons.kernel.types import EntityId
@dataclass(frozen=True)
class OrderPlaced(DomainEvent):
order_id: str
event_type: str = "order.placed"
@dataclass
class Order(AggregateRoot):
customer_id: str
total_cents: int
def place(self) -> None:
Invariant.require(self.total_cents > 0, "Total must be positive")
self._raise_event(OrderPlaced(order_id=str(self.id)))
2. Write a Use Case with CQRS
from mp_commons.application.cqrs import Command, CommandHandler, InProcessCommandBus
class PlaceOrderCommand(Command):
def __init__(self, customer_id: str, total_cents: int) -> None:
self.customer_id = customer_id
self.total_cents = total_cents
class PlaceOrderHandler(CommandHandler[PlaceOrderCommand]):
async def handle(self, cmd: PlaceOrderCommand) -> None:
order = Order(id=EntityId.generate(), customer_id=cmd.customer_id, total_cents=cmd.total_cents)
order.place()
bus = InProcessCommandBus()
bus.register(PlaceOrderCommand, PlaceOrderHandler())
await bus.dispatch(PlaceOrderCommand("cust-1", 1999))
3. Add Resilience
from mp_commons.resilience.retry import RetryPolicy, ExponentialBackoff, FullJitter
from mp_commons.resilience.circuit_breaker import CircuitBreaker, CircuitBreakerPolicy
retry = RetryPolicy(max_attempts=3, backoff=ExponentialBackoff(base=0.1), jitter=FullJitter())
cb = CircuitBreaker("payments", CircuitBreakerPolicy(failure_threshold=5))
result = await retry.execute_async(lambda: cb.call(call_payment_service))
4. Structured Logging with Correlation
from mp_commons.observability.logging import JsonLoggerFactory
from mp_commons.observability.correlation import CorrelationContext, RequestContext
JsonLoggerFactory.configure(service="orders-service", environment="production")
ctx = RequestContext.new(tenant_id=TenantId("acme"))
CorrelationContext.set(ctx)
import structlog
log = structlog.get_logger()
log.info("order_placed", order_id="ord-1")
5. FastAPI Integration
from fastapi import FastAPI
from mp_commons.adapters.fastapi import (
FastAPICorrelationIdMiddleware,
FastAPIExceptionMapper,
FastAPIHealthRouter,
)
app = FastAPI()
app.add_middleware(FastAPICorrelationIdMiddleware)
FastAPIExceptionMapper.register(app)
app.include_router(FastAPIHealthRouter())
6. Testing with Fakes
from mp_commons.testing.fakes import FakeClock, InMemoryMessageBus, FakePolicyEngine
from mp_commons.kernel.security import PolicyDecision
clock = FakeClock()
bus = InMemoryMessageBus()
policy = FakePolicyEngine(default=PolicyDecision.ALLOW)
await bus.publish(some_message)
assert len(bus.of_topic("orders")) == 1
clock.advance(hours=2)
Module Map
mp_commons/
├── kernel/ # Zero external deps — pure Python
│ ├── errors/ # Error hierarchy
│ ├── types/ # EntityId, Money, Email, Result, Option, …
│ ├── ddd/ # Entity, Aggregate, ValueObject, DomainEvent, Specification, …
│ ├── messaging/ # Message, Outbox, Inbox, Idempotency ports
│ ├── contracts/ # CompatibilityMode, ContractRegistry port
│ ├── time/ # Clock protocol, SystemClock, FrozenClock
│ └── security/ # Principal, PolicyEngine, CryptoProvider, PIIRedactor
├── application/ # Use-case layer
│ ├── cqrs/ # Command/Query buses
│ ├── pipeline/ # Middleware pipeline + 9 built-in middlewares
│ ├── pagination/ # Page, PageRequest, Cursor
│ ├── rate_limit/ # RateLimiter port
│ ├── feature_flags/ # FeatureFlagProvider port
│ └── uow/ # TransactionManager, @transactional
├── resilience/
│ ├── retry/ # RetryPolicy, backoff & jitter strategies
│ ├── circuit_breaker/
│ ├── bulkhead/
│ └── timeouts/
├── observability/
│ ├── correlation/ # RequestContext, CorrelationContext (ContextVar)
│ ├── logging/ # Logger port, SensitiveFieldsFilter, JsonLoggerFactory
│ ├── metrics/ # Counter/Histogram/Gauge ports, NoopMetrics
│ └── tracing/ # Tracer/Span ports, NoopTracer
├── config/
│ ├── settings/ # Settings dataclass, EnvSettingsLoader, DotenvSettingsLoader
│ ├── secrets/ # SecretStore port, KubernetesSecretStore
│ └── validation/ # ConfigError, MissingRequiredSettingError
├── adapters/ # Concrete implementations (all lazy-imported)
│ ├── fastapi/
│ ├── sqlalchemy/
│ ├── redis/
│ ├── kafka/
│ ├── nats/
│ ├── rabbitmq/
│ ├── opentelemetry/
│ ├── http/ # httpx-based HTTP client with retry & circuit-breaker
│ ├── keycloak/ # OIDC token verification
│ └── vault/ # HashiCorp Vault secrets
└── testing/
├── fakes/ # In-memory doubles for all kernel ports
├── fixtures/ # pytest fixtures
├── contracts/ # OpenAPI/AsyncAPI contract test helpers
├── generators/ # Domain object factories
└── chaos/ # Latency & failure injection
Architecture Principles
- No framework leakage —
kernel.*imports stdlib only. See ADR-0001. - Ports & Adapters — every infrastructure concern is a Protocol/ABC
in the kernel; concrete implementations live in
adapters/. - Optional extras — no adapter is a hard dependency.
- Idiomatic Python 3.12+ —
typealiases,match, dataclasses,asyncio-native.
Development
uv sync --extra dev # install dev deps
pytest # run tests
ruff check src tests # lint
mypy src # type-check
pre-commit run --all-files
Contributing
- Fork and create a feature branch.
- Write tests first.
- Ensure
pytest,ruff, andmypyall pass. - Update
CHANGELOG.md. - Open a PR — CI must be green.
License
MIT — see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mp_commons-0.2.0.tar.gz.
File metadata
- Download URL: mp_commons-0.2.0.tar.gz
- Upload date:
- Size: 602.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6d83170c196831b2a6cced50f0d752129366a87de0cfb8e7bc28a74c0b929ed6
|
|
| MD5 |
f6da14243e37c204a3616d31442e2471
|
|
| BLAKE2b-256 |
7e58f68efbfba5584bb8b11c878ef4c455a03a5cb64e8e9a2ecd07ae75fe0d89
|
Provenance
The following attestation bundles were made for mp_commons-0.2.0.tar.gz:
Publisher:
ci.yml on marcusPrado02/python-commons
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mp_commons-0.2.0.tar.gz -
Subject digest:
6d83170c196831b2a6cced50f0d752129366a87de0cfb8e7bc28a74c0b929ed6 - Sigstore transparency entry: 1228860710
- Sigstore integration time:
-
Permalink:
marcusPrado02/python-commons@8ac4e3fb96353fed2358513d9ef3b638bfb41c6e -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/marcusPrado02
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@8ac4e3fb96353fed2358513d9ef3b638bfb41c6e -
Trigger Event:
push
-
Statement type:
File details
Details for the file mp_commons-0.2.0-py3-none-any.whl.
File metadata
- Download URL: mp_commons-0.2.0-py3-none-any.whl
- Upload date:
- Size: 357.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e506cfb6e92b30a98b1ed213a202ab34065d7c2a66de1e48a0d4d3c4f1b2f835
|
|
| MD5 |
dab8816d89dd123557c516c9d4b007ca
|
|
| BLAKE2b-256 |
481185077a7aa88da86b0cb3c372ae9925bda1d29c3162929d4da1fdf81fe0e5
|
Provenance
The following attestation bundles were made for mp_commons-0.2.0-py3-none-any.whl:
Publisher:
ci.yml on marcusPrado02/python-commons
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mp_commons-0.2.0-py3-none-any.whl -
Subject digest:
e506cfb6e92b30a98b1ed213a202ab34065d7c2a66de1e48a0d4d3c4f1b2f835 - Sigstore transparency entry: 1228860762
- Sigstore integration time:
-
Permalink:
marcusPrado02/python-commons@8ac4e3fb96353fed2358513d9ef3b638bfb41c6e -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/marcusPrado02
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@8ac4e3fb96353fed2358513d9ef3b638bfb41c6e -
Trigger Event:
push
-
Statement type: