NENE2 Python — minimal API framework following NENE2's design philosophy
Project description
nene2-python
A Python reference framework implementing the NENE2 design philosophy — clean architecture, security-first, and AI-readable code.
Features
- FastAPI + Pydantic v2 — modern Python API stack with automatic OpenAPI docs
- Clean Architecture — UseCase / Domain layer fully decoupled from HTTP and DB
mypy --strict— equivalent to PHPStan level 8 type safety- ruff — lint and format in one tool (replaces flake8, isort, black, bandit)
- RFC 9457 Problem Details — uniform error responses across all endpoints
- Bearer Token / API Key auth — zero-config
LocalTokenVerifier - MCP support — expose UseCases as AI agent tools via
LocalMcpServer - SQLAlchemy Core — parameterised SQL without ORM overhead
- Security middleware — CSP, X-Frame-Options, rate limiting, request size limit, CORS
- structlog — structured JSON logging with request ID correlation
Installation
pip install nene2-python
# or
uv add nene2-python
Requires Python 3.12+.
Quick Start
from fastapi import FastAPI
from nene2.config import AppSettings
from nene2.middleware import (
ErrorHandlerMiddleware,
RequestIdMiddleware,
SecurityHeadersMiddleware,
ThrottleMiddleware,
)
cfg = AppSettings()
app = FastAPI()
app.add_middleware(ErrorHandlerMiddleware, debug=cfg.app_debug)
app.add_middleware(SecurityHeadersMiddleware)
app.add_middleware(RequestIdMiddleware)
app.add_middleware(ThrottleMiddleware, limit=cfg.throttle_limit, window=cfg.throttle_window)
Define a domain
from dataclasses import dataclass
from abc import ABC, abstractmethod
@dataclass(frozen=True, slots=True)
class Note:
id: int
title: str
body: str
class NoteRepositoryInterface(ABC):
@abstractmethod
def find_by_id(self, note_id: int) -> Note | None: ...
@dataclass(frozen=True, slots=True)
class GetNoteInput:
note_id: int
class GetNoteUseCase:
def __init__(self, repository: NoteRepositoryInterface) -> None:
self._repository = repository
def execute(self, input_: GetNoteInput) -> Note:
note = self._repository.find_by_id(input_.note_id)
if note is None:
raise NoteNotFoundException(input_.note_id)
return note
Wire to HTTP
from fastapi import APIRouter
from fastapi.responses import JSONResponse
from nene2.http import problem_details_response
router = APIRouter(prefix="/notes", tags=["notes"])
@router.get("/{note_id}")
async def get_note(note_id: int) -> JSONResponse:
note = get_use_case.execute(GetNoteInput(note_id))
return JSONResponse({"id": note.id, "title": note.title, "body": note.body})
See the full working example in src/example/.
Development Commands
uv sync # install dependencies
uv run pytest # run tests (coverage enforced at 80%)
uv run mypy src/ # type check
uv run ruff check src/ tests/ # lint
uv run ruff format src/ tests/ # format
uv run uvicorn src.example.app:app --reload --port 8080 # dev server
Full CI check (equivalent to GitHub Actions):
uv run pytest && \
uv run mypy src/ && \
uv run ruff check src/ tests/ && \
uv run ruff format --check src/ tests/ && \
uv run pip-audit
Framework Modules
| Module | Purpose |
|---|---|
nene2.http |
PaginationQueryParser, PaginationResponse, problem_details_response() |
nene2.middleware |
ErrorHandlerMiddleware, SecurityHeadersMiddleware, RequestIdMiddleware, RequestLoggingMiddleware, RequestSizeLimitMiddleware, ThrottleMiddleware |
nene2.auth |
BearerTokenMiddleware, ApiKeyAuthMiddleware, LocalTokenVerifier, TokenVerifierProtocol |
nene2.database |
SqlAlchemyQueryExecutor, SqlAlchemyTransactionManager, DatabaseHealthCheck |
nene2.config |
AppSettings (pydantic-settings, reads from env / .env) |
nene2.validation |
ValidationException, ValidationError |
nene2.mcp |
LocalMcpServer, HttpxMcpClient |
nene2.log |
setup_logging() (structlog, JSON in production) |
nene2.use_case |
UseCaseProtocol[I, O], AsyncUseCaseProtocol[I, O] |
PHP NENE2 Correspondence
| PHP | Python |
|---|---|
readonly class |
dataclass(frozen=True, slots=True) |
PHPStan level 8 |
mypy --strict |
PHP-CS-Fixer |
ruff format |
composer check |
uv run pytest && mypy && ruff check && ruff format --check && pip-audit |
ValidationException |
nene2.validation.ValidationException |
PaginationQueryParser |
nene2.http.PaginationQueryParser |
ErrorHandlerMiddleware |
nene2.middleware.ErrorHandlerMiddleware |
LocalMcpServer |
nene2.mcp.LocalMcpServer |
Related
- NENE2 (PHP) — PHP reference implementation
- Documentation — full docs (Diátaxis structure)
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 nene2_python-1.8.3.tar.gz.
File metadata
- Download URL: nene2_python-1.8.3.tar.gz
- Upload date:
- Size: 300.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.15 {"installer":{"name":"uv","version":"0.11.15","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d8c903e66f575771a4e53a94a4b86178db4eca6f0132acf4f215d12f255bef0f
|
|
| MD5 |
9405d64492127866cb82ea0a045de2d0
|
|
| BLAKE2b-256 |
671cd19a300919a58d535148f67b13be734ec03626c97bd1f21425012eecfb4e
|
File details
Details for the file nene2_python-1.8.3-py3-none-any.whl.
File metadata
- Download URL: nene2_python-1.8.3-py3-none-any.whl
- Upload date:
- Size: 33.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.15 {"installer":{"name":"uv","version":"0.11.15","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
750037f59cfffbbca71ec3e26df5a182161f23ad4cae1c13c94c5e6ba8c79e5e
|
|
| MD5 |
ed166fb0f090f349f8feada26aa347c4
|
|
| BLAKE2b-256 |
a0b7f2469ac1beba5bcea0d9f0cb2b82cb7077099adfba69240629ea3fbe3f6d
|