Skip to main content

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.

CI Python License: MIT


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

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

nene2_python-1.8.34.tar.gz (422.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

nene2_python-1.8.34-py3-none-any.whl (44.5 kB view details)

Uploaded Python 3

File details

Details for the file nene2_python-1.8.34.tar.gz.

File metadata

  • Download URL: nene2_python-1.8.34.tar.gz
  • Upload date:
  • Size: 422.5 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

Hashes for nene2_python-1.8.34.tar.gz
Algorithm Hash digest
SHA256 b6f6209f8cc66c15a4c3740ada3d9c102be94ecbe05da7d02318a2a7d4feec2a
MD5 4bd38759abf3e32859c8244379e20aaa
BLAKE2b-256 7ebf2d8a72a418f6af78ea10abddb6af1da44075ebeaa31d10146840b4e4cf6b

See more details on using hashes here.

File details

Details for the file nene2_python-1.8.34-py3-none-any.whl.

File metadata

  • Download URL: nene2_python-1.8.34-py3-none-any.whl
  • Upload date:
  • Size: 44.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

Hashes for nene2_python-1.8.34-py3-none-any.whl
Algorithm Hash digest
SHA256 74c6c8535208d01d5bd9c7f81cd59c92ea7efbc9ab498540901dbe51e480636d
MD5 f5d28c2678c1e76247c82bb2ccb81d87
BLAKE2b-256 9d18a19833b6568ad8c69dcf8336e940692fc31dc1fcf368ac0c9caf5bbe5719

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page