Skip to main content

quadkit

Quadkit

PyPI Python License

Async-first application framework for Python: dependency-injection container, application lifecycle, typed configuration, and the Result error model. This is the core package; everything else published from this repository builds on it.

For application developers — write providers and modules, bind contracts, and let one container boot them in order.

What's in the box:

  • DI container — singleton, scoped, and transient bindings, async factories, override support for tests; the graph resolves once, at boot.
  • Provider & module system — providers register bindings, boot resources, and shut them down in reverse order; modules compose providers into reusable units.
  • Typed configuration — application.yaml validated against dataclass models at boot (unknown keys fail fast), every key overridable via QK_* environment variables, profiles via QK_PROFILE.
  • The Result model — expected failures are values (Ok/Err), not exceptions; ResultPipeline chains them fluently while keeping the error type visible to mypy.
  • Structured logging — get_logger() gives every service a keyed, structlog-style logger out of the box.
  • Domain primitives — AggregateRoot, Entity, DomainEvent, AbstractUnitOfWork for DDD-style modelling without a framework tax.

The quadkit family

Package Role
quadkit-contracts zero-dependency protocols, types, exception hierarchy
quadkit the framework core — DI container, modules, config, logging, Result
quadkit-web ASGI layer — controllers, routing, middleware, OpenAPI docs
quadkit-cli project scaffolding and code generators
quadkit-testing in-process test beds, fakes, fixtures

Installation

uv add quadkit
# batteries-included web stack:
uv add "quadkit[web]"

Requires Python >= 3.11.

Minimal working example

import asyncio

from quadkit import Application
from quadkit.contracts.core.di import ContainerRegistrarProtocol
from quadkit.di.provider import Provider


class Settings:
    greeting = "hello, quadkit"


class SettingsProvider(Provider):
    async def register(self, container: ContainerRegistrarProtocol) -> None:
        container.singleton(Settings, instance=Settings())


async def main() -> None:
    app = Application()
    app.add_provider(SettingsProvider())
    await app.start()
    try:
        settings = await app.container.resolve(Settings)
        print(settings.greeting)
    finally:
        await app.stop()


asyncio.run(main())

For the web quickstart (a real endpoint in minutes), see the docs.

Expected failures are values

Result[T, E] keeps the happy path and the failure path in the type system — pipeline() chains fallible steps without try/except pyramids, and mypy sees the error type at every step:

from quadkit.result import Err, Ok, pipeline


def parse_port(raw: str):
    try:
        port = int(raw)
    except ValueError as exc:
        return Err(exc)
    if not 1 <= port <= 65535:
        return Err(ValueError(f"port out of range: {port}"))
    return Ok(port)


result = (
    pipeline("8080")  # infallible start
    .then(parse_port)  # Result[int, ValueError]
    .map(lambda port: f"listening on :{port}")
    .finalize()  # Result[str, ValueError]
)

In controllers, returning an Err renders as an RFC 7807 problem response automatically — see the error-handling guide.

Optional extras

Extra Contents
quadkit[web] quadkit-web[granian] — the full web stack
quadkit[test] pytest, pytest-asyncio, pytest-cov, pytest-mock
quadkit[security] cryptography (signing/token helpers)
quadkit[codegen] code generation toolchain
quadkit[docs] / [dev] documentation / development tooling

Public API entry points

from quadkit import Application, Result, Ok, Err
from quadkit.di.provider import Provider
from quadkit.di.container import Container
from quadkit.config import BaseConfig, ConfigLoader
from quadkit.logging import get_logger
from quadkit.domain import AggregateRoot, Entity, DomainEvent, AbstractUnitOfWork
from quadkit.contracts.core.di import (
    ContainerRegistrarProtocol,
    ContainerResolverProtocol,
)

Providers can also define an async boot() (acquire resources) and shutdown() (release them, in reverse registration order) — the container drives the whole lifecycle.

Concepts: contracts · dependency injection · modules · lifecycle · async model.

Configuration

application.yaml at the working directory, validated against typed config models at boot (unknown keys fail fast); application metadata lives at the root (name, version, description); every typed key overrides from the environment with QK_<SECTION>__<KEY>. Use QK_PROFILE to select a profile.

QK_QUADKIT__LOGGING__LEVEL=DEBUG   # fold into the root `logging` section
QK_PROFILE=production              # select a profile block

See configuration.

Error handling

Result[T, E] for expected domain failures; the quadkit-contracts exception hierarchy (QuadkitError → DomainError → NotFoundError, ValidationError, ConflictError, ...) for everything else. The web layer renders both as problem responses — see error handling.

Testing

Pair with quadkit-testing: AppTestBed.from_factory(create_app) boots your application in-process (with overrides={Contract: fake} for test doubles), no server required. See testing.

Security

Never put secrets in application.yaml — pass them through QK_* environment variables or a secret store. Unexpected exceptions never leak internals to clients. See secure configuration and report vulnerabilities privately per SECURITY.md.

Stability

Version 0.0.43 in the 0.x series, released in lockstep with the other four distributions; APIs may change between minor versions until 1.0 — pin an exact version (quadkit==0.0.43) or a tight range (>=0.0.43,<0.1.0). Full policy: stability and compatibility.

Apache-2.0 — see LICENSE. "Quadkit" and the Quadkit logo are trademarks of the project — see TRADEMARK.md.

Metadata

Release files for quadkit 0.0.43

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for quadkit 0.0.43
File Size Uploaded Provenance
quadkit-0.0.43.tar.gz 589.4 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for quadkit 0.0.43
File Interpreter ABI Platform
quadkit-0.0.43-py3-none-any.whl Python 3 none any Details

Total release size: 1.0 MB

Release files / quadkit-0.0.43.tar.gz

Download URL quadkit-0.0.43.tar.gz
Size 589.4 kB
Tags Source
SHA-256 checksum
How to use checksums
ae4ab75fa8ab5d049880c7c8e0809daeb8df7eed9ad793f1a183d62f5816d035
BLAKE2b-256 checksum
How to use checksums
2629513e611b0d4778e3bb69d6ff77460669b7622c66a947bfdce434dbef64c8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.8.14

Release files / quadkit-0.0.43-py3-none-any.whl

Download URL quadkit-0.0.43-py3-none-any.whl
Size 443.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
ac30b14df4991825b0af745b2330292863ba3c1576eabb9c174bb3f15eaf9a3f
BLAKE2b-256 checksum
How to use checksums
db1d08d5dea6235657fa84152294d48c40a03d16340ef51ba7ab582c2b392d17
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.8.14

Security for quadkit 0.0.43

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page