Skip to main content

A minimal, stable ASGI foundation - framework-agnostic toolkit for building high-performance web services

Project description

Genro ASGI

A minimal ASGI server and application toolkit for building web services with routing, authentication, sessions, and middleware — configured by a Python config.py builder recipe.

PyPI version Python Support License Documentation

What it does

  • Serves web applications mounted on URL prefixes (/api/, /shop/, etc.) with config-driven loading
  • Authenticates requests via bearer tokens, basic auth, or JWT — O(1) credential lookup, lazy auth for zero overhead on unprotected routes
  • Manages sessions with in-memory store, cookie-based reconnection, and user avatars (identity + tags + extensible Bag data)
  • Applies middleware at two levels: global (CORS, errors, auth) and per-app (session, cache) with independent chains
  • Routes requests via genro-routes with decorator-based routing and auth tag filtering
  • Serves static files with StaticRouter and hierarchical resource loading with fallback chains
  • Handles WebSocket with the WSX extension protocol for structured request/response messaging
  • Exposes MCP endpoints via McpApplication for AI tool integration (Streamable HTTP transport)
  • Configures plugins at runtime via the plugin_config web UI (mounted under /_sys/plugin_config/) with persistence to JSON

Installation

pip install genro-asgi            # core
pip install genro-asgi[json]      # + orjson for fast JSON
pip install genro-asgi[dev]       # + test/lint tools

Quick Start

The server boots from a config.py whose ServerConfiguration (a subclass of AsgiConfigBuilder) is rendered onto it. The recipe builds the server tree with the builder API; application classes are imported and passed as objects.

from genro_asgi import AsgiServer

server = AsgiServer("config.py")  # the config.py directory is the server dir
server.run()                      # starts uvicorn on the configured host/port

config.py:

from genro_asgi.config import AsgiConfigBuilder
from shop_app import Application as Shop          # your AsgiApplication subclass


class ServerConfiguration(AsgiConfigBuilder):
    def main(self, root):
        root.server(host="127.0.0.1", port=8000)
        root.middleware(cors=True, auth=True)     # one bool kwarg per middleware
        root.authMiddleware(
            bearer={"api_key": {"token": "sk_live_abc123", "tags": "api,read"}}
        )
        apps = root.applications(default="shop")   # "shop" is served on the empty mount
        apps.application(code="shop", app_class=Shop,
                         middleware={"session": True})
        root.openapi(title="Shop API", version="1.0.0")

Each app derives its URL mount from its code (or "" when it is the collection default), unless it declares an explicit mount. The server demultiplexes on the first path segment; each app does its own routing.

Architecture at a glance

The server is an instance with its own state — no global variables. Every component is an isolated instance connected via semantic parent-child references.

Request flow:

uvicorn → AsgiServer → global middleware (errors → cors → auth)
  → Dispatcher → per-app middleware (session, cache, ...)
    → handler(**query) → Response → ASGI send

Core components

Component Purpose
AsgiServer ASGI entry point, loads config, mounts apps, composes BasicAuthMixin
Dispatcher Resolves handler via router, applies per-app middleware chains
BasicAuthMixin Server-side auth: server.authenticate(scope), server.verify_credentials()
SessionMiddleware Per-app session lifecycle: cookie extraction, reconnection, Set-Cookie
Session / Avatar Session with meta + Bag data + Avatar (identity, tags, extensible data)
MemorySessionStore In-memory session store with dump/restore for persistence
AsgiApplication Base class for mountable applications
McpApplication MCP Streamable HTTP transport for AI tools
StaticRouter Filesystem-backed static file serving
LocalStorage Filesystem storage with mount system

Middleware

Middleware Name Order Default
ErrorMiddleware errors 100 on
LoggingMiddleware logging 200 off
CORSMiddleware cors 300 off
AuthMiddleware auth 400 off
SessionMiddleware session 450 off
CacheMiddleware cache 900 off
CompressionMiddleware compression 900 off

Scope is not a property of a middleware class: a middleware runs globally when the server's middleware(...) section names it, and per-app when an application's own middleware config names it. The same class can serve in either chain; Order sorts each chain independently.

Documentation

Full documentation: https://genro-asgi.readthedocs.io

Development

git clone https://github.com/genropy/genro-asgi.git
cd genro-asgi
pip install -e .[dev]

pytest                    # run tests
ruff check .              # lint
mypy src                  # type check

License

Copyright 2025-2026 Softwell S.r.l.

Licensed under the Apache License 2.0. See NOTICE for additional attribution.

Links

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

genro_asgi-0.7.0.tar.gz (1.6 MB view details)

Uploaded Source

Built Distribution

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

genro_asgi-0.7.0-py3-none-any.whl (242.2 kB view details)

Uploaded Python 3

File details

Details for the file genro_asgi-0.7.0.tar.gz.

File metadata

  • Download URL: genro_asgi-0.7.0.tar.gz
  • Upload date:
  • Size: 1.6 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for genro_asgi-0.7.0.tar.gz
Algorithm Hash digest
SHA256 40ea3458a1662d62a6d19abf416c45c3b0d8093798c51b71caaedb5fa8a65943
MD5 60893a4f1720236bd85186dc0670d978
BLAKE2b-256 7c8957462c7e0014348690eb8ea30b7a89f48e80b8e70c94a41c723a32d9cdd8

See more details on using hashes here.

Provenance

The following attestation bundles were made for genro_asgi-0.7.0.tar.gz:

Publisher: publish.yml on genropy/genro-asgi

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file genro_asgi-0.7.0-py3-none-any.whl.

File metadata

  • Download URL: genro_asgi-0.7.0-py3-none-any.whl
  • Upload date:
  • Size: 242.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for genro_asgi-0.7.0-py3-none-any.whl
Algorithm Hash digest
SHA256 f7be3c43f8e084b03655df61e3cd5755c64984034fb8bfb6bdb6ec2e7b520e95
MD5 3d01a67d20ecbe6a054f1386751aae4e
BLAKE2b-256 f9be6a23416bcebfc889075c41136735969abccf2bf737dd889323129ac221b3

See more details on using hashes here.

Provenance

The following attestation bundles were made for genro_asgi-0.7.0-py3-none-any.whl:

Publisher: publish.yml on genropy/genro-asgi

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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