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.6.6.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.6.6-py3-none-any.whl (235.7 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: genro_asgi-0.6.6.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.6.6.tar.gz
Algorithm Hash digest
SHA256 d5339858e34f143d1a6cbe875c56fa95ffbe8fe1f08ea95452e2be1e683da41d
MD5 f45ca49f96d9615be01cdb473d036a1d
BLAKE2b-256 26a66200429b3b8bba5627bf944dec8ea6a5e52bd09d2918826de70479d9e16e

See more details on using hashes here.

Provenance

The following attestation bundles were made for genro_asgi-0.6.6.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.6.6-py3-none-any.whl.

File metadata

  • Download URL: genro_asgi-0.6.6-py3-none-any.whl
  • Upload date:
  • Size: 235.7 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.6.6-py3-none-any.whl
Algorithm Hash digest
SHA256 d015462699128c73a4ef26a44481721234f7a036abf73da30461788b947d9c9b
MD5 703fbebe36664c53dab77af40cfe0b51
BLAKE2b-256 d4b0928f507274cae32454903e2321ca108e6d174356fa18072230ed9fda3167

See more details on using hashes here.

Provenance

The following attestation bundles were made for genro_asgi-0.6.6-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