neva-fastapi
The FastAPI integration for the Neva
framework. It marries FastAPI to neva's dishka-based dependency-injection
container so that route handlers resolve injected services, while keeping all
HTTP concerns out of the framework-agnostic python-neva core.
Most consumers pull this in transitively via the python-neva[fastapi] extra
rather than depending on it directly.
What it provides
Everything is re-exported from neva.fastapi:
App— a subclass offastapi.FastAPIthat owns aneva.arch.Application(the DI container) and drives it: builds the container, reads app metadata from neva config (app.*), wires neva providers'lifespan()hooks, and installs per-request DI scoping middleware.APIRouter— a subclass offastapi.APIRouterthat forcesroute_class=DishkaRouteso injection works inside handlers.Inject— a re-export ofdishka.FromDishka. Annotate handler params asInject[SomeService].Injectonly works on this package'sAPIRouter(orApp's routes) — a vanillafastapi.APIRouterlacksDishkaRouteand injection silently won't happen.route_template—(scope) -> str | None, the matched route's path template with router prefixes and mount points applied ("/api/v1/users/{id}"), orNonewhen nothing matched. A pure function over the ASGI scope, so it works with a vanillafastapi.APIRoutertoo. Written forneva-asgi[otel]'s tracing middleware, which takes it as an injected callable — a tracer needs the template rather than the resolved path, or every request becomes its own operation and no endpoint can be aggregated. This package depends on no OpenTelemetry to provide it, not even optionally.HttpAppConfig— aTypedDictnaming theapp.*config keys this package reads, so a type checker catches the typos that aResult-based lookup with a default would otherwise swallow.
neva is a namespace package (no top-level neva/__init__.py); this repo
owns neva/fastapi/ and shares the neva.* namespace with python-neva.
Application metadata
The OpenAPI document's title and version, the debug flag and the three
documentation URLs come from the app config namespace rather than the
constructor:
# src/config/app.py
config = {
"title": "Billing",
"version": "2.1.0",
"docs_url": "/documentation",
}
HttpAppConfig declares those six keys — title, debug, version,
openapi_url, docs_url, redoc_url — and nothing else. The app namespace
is shared, and each package declares only what it reads: the core owns key,
previous_keys and providers. A TypedDict is closed, so annotate a real
config/app.py with a shape that inherits from each package's:
from neva.arch import AppConfig
from neva.fastapi import HttpAppConfig
class ServiceAppConfig(HttpAppConfig, AppConfig): ...
config: ServiceAppConfig = {"title": "Billing", "providers": [...]}
Annotating with HttpAppConfig alone rejects providers; that is the
ownership rule working, not a defect. Unset keys fall back to
Neva Application, 0.1.0, debug off, /openapi.json, /docs and /redoc.
Testing helpers
neva.fastapi.testing.HttpTestCase is a neva.testing.TestCase whose
application is the one your App owns, booted through the App's own
lifespan, with an http_client fixture over it.
from neva.fastapi.testing import HttpTestCase
class TestActors(HttpTestCase):
@override
@classmethod
def create_app(cls, config_path: Path) -> App:
app = App(config_path=config_path)
_ = app.register(ActorProvider)
app.include_router(router)
return app
async def test_it_lists(self, http_client: AsyncClient) -> None:
assert (await http_client.get("/actors")).status_code == 200
Register providers and include routers in create_app: it runs before the boot,
and Application.register refuses once the application is booted.
The webapp / http_client fixtures and the neva.fastapi.fixtures plugin were
removed in 2.0.0. webapp was a synchronous fixture, so nothing ever entered the
app's lifespan — it handed back an unbooted app with no state.dishka_container
and no provider hooks run.
Develop
uv sync # install/refresh deps
poe lint # ruff check
poe fmt # ruff format
poe tc # pyrefly check
poe test # pytest
poe test-cov # pytest --cov=neva --cov-report=term-missing
asyncio_mode = "auto" is set, so async tests need no @pytest.mark.asyncio.
Contributing
Commits follow Conventional Commits
with gitmoji prefixes, enforced by
cz_gitmoji. Commitizen is
a dev dependency — run cz commit for the guided wizard, or format manually as
:gitmoji: type(scope): subject.
Releases are cut per-repo with commitizen from the repo root:
cz bump # bump version in pyproject, write CHANGELOG, tag v<version>
git push --follow-tags origin main
uv build && uv publish # build + publish the wheel/sdist
cz bump derives the level from the commits since the last tag, updates
CHANGELOG.md, and runs scripts/retag-with-changelog.sh to rewrite the new
tag with the rendered changelog as its annotation.
Metadata
Release files for neva-fastapi 2.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| neva_fastapi-2.1.0.tar.gz | 125.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| neva_fastapi-2.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 147.3 kB
Release files / neva_fastapi-2.1.0.tar.gz
| Download URL | neva_fastapi-2.1.0.tar.gz |
|---|---|
| Size | 125.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
eeccfe6283325c6fddc114e2c66304e2442d8206599b28668ec44e10a4bfed08
|
|
BLAKE2b-256 checksum How to use checksums |
5da264b1f07b16d8b94a7f7c9084415bae2c40b295f83053697c6d4b578f2987
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.8.22
|
Release files / neva_fastapi-2.1.0-py3-none-any.whl
| Download URL | neva_fastapi-2.1.0-py3-none-any.whl |
|---|---|
| Size | 21.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
5ea9bb0d36ef9b5e199db89bb5998dd9966461a274b2cf3e6645860076c2b84d
|
|
BLAKE2b-256 checksum How to use checksums |
1b0b13d0020d95b6fe932b9b4a152851231dd18b00e34acbc8a7f2bdc544ae82
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.8.22
|