Quality Report
Protean is built with a strong emphasis on code quality, test coverage, and long-term maintainability. This page documents the engineering practices and metrics behind the framework.
At a Glance
| Metric | Value |
|---|---|
| Tests | 20,712 |
| Test-to-Code Ratio | 2.7:1 |
| Linting Violations | 0 (Ruff) |
| Avg Cyclomatic Complexity | 3.38 (A grade) |
| Maintainability Index | A rank (95% of files) |
| Python Versions | 3.11, 3.12, 3.13, 3.14, and the 3.15 prerelease |
| CI Backing Services | PostgreSQL, Redis, Elasticsearch, MessageDB, MSSQL, MySQL, MariaDB, SQLite |
| Releases | 55 |
| Project Age | Since July 2018 |
| License | Apache 2.0 |
Test Suite
Protean has a comprehensive test suite covering domain logic, application services, infrastructure adapters, and integration scenarios. The current counts are in the breakdown below. This page is the single source of truth for these numbers; other pages quote round figures and link here.
Refresh them with one command:
uv run python scripts/metrics.py
tests/test_metrics_are_single_sourced.py keeps the policy honest: it fails if
any other page states an exact count. The counts change with every PR, so the
test does not check their values. Instead, it checks that the counts have only
one place to change.
Test Breakdown
| Metric | Count |
|---|---|
| Total Tests | 20,712 |
| Test Functions | 18,246 |
| Test Classes | 3,338 |
| Pytest Fixtures | 1,461 |
| Parametrized Tests | 543 |
Core vs. Integration
| Category | Tests | Share |
|---|---|---|
| Core tests (in-memory, no infrastructure) | 18,788 | 91% |
| Adapter/integration tests | 1,924 | 9% |
Core tests run entirely in-memory with no external dependencies, making
them fast and reliable for local development. Integration tests exercise
real databases and message brokers. A test counts as an integration test
when it carries one of the backing-service markers listed in
scripts/metrics.py, the same markers as the table below.
Infrastructure Coverage
Every merge to main is tested against real backing services:
| Technology | Marked Tests |
|---|---|
| Redis | 574 |
| Database (generic) | 452 |
| Event Store | 316 |
| Elasticsearch | 177 |
| PostgreSQL | 145 |
| SQLite | 132 |
| MySQL | 65 |
| MessageDB | 60 |
| MSSQL | 34 |
A test with more than one marker counts once in each row.
Branch coverage is enabled, and results are reported to Codecov on every CI run.
Code Quality
Linting
Protean uses Ruff for both linting and formatting. The codebase has zero linting violations. Pre-commit hooks enforce this on every commit:
ruff check --fix(linting with auto-fix)ruff format(consistent formatting)
Cyclomatic Complexity
Measured with Radon:
| Metric | Value |
|---|---|
| Average complexity | 3.38 |
| Blocks at A grade (1-5, simple) | 1,820 (84%) |
| Total blocks analyzed | 2,167 |
An average complexity under 5 indicates straightforward, easy-to-follow code paths throughout the framework.
Cognitive Complexity
Cognitive complexity measures how hard a function is to read. It counts
branches and loops, and charges more for each level of nesting.
complexipy computes it for every
function in src/, tests/ and scripts/, and fails the check on a function
above 15. The limit and the paths live in [tool.complexipy] in
pyproject.toml. The Lint (ruff) job in CI and the pre-commit hook both run
the check.
Some functions were already above the limit when the check arrived.
complexipy-snapshot.json at the repository root lists each of them with its
complexity at that time, and the check passes them. The check treats the
snapshot like this:
- A listed function that grows more complex fails the check.
- A new function above 15 fails the check. A listed function that is renamed or moved to another file counts as new, so it fails too.
- A listed function that becomes less complex gets its lower value in the snapshot, and one split down to a complexity of 15 or less drops out of it. Every passing run rewrites the file, so you commit the rewritten file with your change. CI fails when the committed snapshot differs from the rewritten one.
The check counts a function marked # noqa: complexipy or
# complexipy: ignore like any other. When a function fails the check, split
it along what it does. Leave the limit and the snapshot as they are.
Maintainability Index
| Rank | Files | Share |
|---|---|---|
| A (very maintainable, 20-100) | 146 | 95% |
| B (moderate, 10-19) | 6 | 4% |
| C (low, 0-9) | 1 | 1% |
Average Maintainability Index: 63.28 (on a scale of 0-100).
95% of source files score in the highest maintainability tier.
Codebase Structure
Size
| Area | Python Files | Lines of Code | Documentation Lines |
|---|---|---|---|
Source (src/protean/) |
153 | 48,347 | 5,907 |
Tests (tests/) |
810 | 145,248 | 13,505 |
| Total | 963 | 193,595 | 19,412 |
Architecture
Protean's source is organized into 10 top-level packages:
| Package | Purpose |
|---|---|
core/ |
Domain elements (aggregates, entities, value objects, commands, events, handlers, services, repositories) |
adapters/ |
Infrastructure implementations (database, broker, event store, cache) |
port/ |
Port interfaces that adapters implement |
fields/ |
Field system for domain element attributes |
domain/ |
Domain class and element registration |
server/ |
Async message processing engine |
cli/ |
Command-line tools |
ext/ |
Extensions (e.g., mypy plugin) |
utils/ |
Shared utilities (outbox, eventing, mixins) |
template/ |
Project scaffolding templates |
Domain Elements and Adapters
| Category | Count |
|---|---|
| Domain element types | 19 (Aggregate, Entity, Value Object, Command, Event, Domain Service, Command Handler, Event Handler, Query Handler, Application Service, Subscriber, Projection, Projector, Repository, Database Model, and more) |
| Port interfaces | 5 (Provider, Broker, Event Store, Cache, DAO) |
| Adapter implementations | 10 (Memory, SQLAlchemy, Elasticsearch, Redis Stream, Redis PubSub, Inline, MessageDB, and more) |
CI/CD Pipeline
Test Matrix
Protean tests across five Python versions and seven backing services, split between per-PR CI and a nightly run:
- 5 Python versions: 3.11, 3.12, 3.13, 3.14, and the 3.15 prerelease
- 7 backing services (started as Docker containers for the adapter suite):
- PostgreSQL 16
- Redis 7
- Elasticsearch 8.7.0
- MessageDB 1.3.1
- MSSQL Server 2022
- MySQL 8.4
- MariaDB 11.4
Each pull request runs the in-memory core suite on every stable version. It
also runs the PostgreSQL and Redis adapters, plus any adapter the pull request
changes. A push to main adds the full adapter suite on the newest stable
Python, and the nightly run exercises the full adapter suite across all five
versions. The stable versions gate every merge; the 3.15 prerelease leg runs
nightly as a non-blocking early-warning check while 3.15 is a prerelease.
Pipeline Steps
Each pull request runs these gates, all in CI so none can be bypassed by a
missing pre-commit hook, a --no-verify, or a web edit:
- Lint:
ruff check,ruff format --checkand the cognitive complexity check, the same checks as the pre-commit hook. - Type check:
mypy --strictoversrc/protean. - Test suite: the in-memory core suite (
protean test) on every stable Python version, and theAdapterscheck: PostgreSQL and Redis always, plus each adapter whose files the pull request changes (tests/adapters.toml). A push tomainruns the full adapter suite (protean test -c FULL) on the newest stable Python, and the nightly run extends it to every version. - Coverage: Codecov requires 96% of a pull request's changed lines to be
covered (
codecov/patch). The overall floor of 94% (coverage report --fail-under=94) is enforced on every push tomain, the only run that sees every adapter. - Security scanning: CodeQL (SAST) and a dependency-review check on any changed dependencies.
Documentation is deployed on merge to main.
Documentation
Documentation is built with MkDocs Material
and automatically deployed to docs.proteanhq.com
on every merge to main.
Dependencies
Protean maintains a lean dependency footprint:
| Category | Count |
|---|---|
| Required runtime dependencies | 16 |
| Optional extras (adapters) | 8 groups |
| Dev dependencies | 7 |
| Test dependencies | 8 |
All database and message broker drivers are optional extras, so the core framework installs only what's needed for in-memory development. Infrastructure dependencies are added when you're ready to deploy:
pip install protean[postgresql] # Adds SQLAlchemy + psycopg 3
pip install protean[redis] # Adds redis-py
pip install protean[elasticsearch] # Adds the elasticsearch client
Project History
| Metric | Value |
|---|---|
| First commit | July 15, 2018 |
| Total commits | 1,619 |
| Commits since Jan 2024 | 647 |
| Contributors | 14 |
| Published releases | 46 |
| Current version | 0.14.2 |
| Latest releases | v0.14.0, v0.14.1, v0.14.2 |
Tools and Practices
| Practice | Tool |
|---|---|
| Linting & formatting | Ruff (pre-commit + CI) |
| Type checking | mypy (with custom Protean plugin) |
| Test framework | pytest (with pytest-asyncio) |
| Coverage | coverage.py + Codecov |
| Complexity analysis | Radon, complexipy (pre-commit + CI) |
| Dependency management | uv |
| Multi-version testing | Nox |
| CI/CD | GitHub Actions |
| Documentation | MkDocs Material |
scripts/metrics.py produced the Test Suite figures, last updated in October 2026. These figures are the total, the Test Breakdown, the test-to-code ratio, and the Core vs. Integration and Infrastructure Coverage tables. Code Quality and Codebase Structure are from March 2026.