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

Uploaded Python 3

File details

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

File metadata

  • Download URL: genro_asgi-0.6.5.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.5.tar.gz
Algorithm Hash digest
SHA256 18441e4d33b2650c956fd9e5f05ca5facec97d49c9308d03fa7bb4f49f66920f
MD5 8c26c6e330aaee5fa131e13a68a190ce
BLAKE2b-256 54728d6e3292256bf3a8431efe4a41f33fe75ff34ed32c9cf4f4c708506e7f7a

See more details on using hashes here.

Provenance

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

File metadata

  • Download URL: genro_asgi-0.6.5-py3-none-any.whl
  • Upload date:
  • Size: 235.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.6.5-py3-none-any.whl
Algorithm Hash digest
SHA256 2bd63b3cb637e227bfb311ebaa93d91b903edb377a4ce7cf7135f17298bdced7
MD5 1c2a9afbb10d83a41a0aa9569ce4a9ab
BLAKE2b-256 f08a695432b3f23090dc0990977312e8b2b9153b6841949c9f39d1d52e2ff1e3

See more details on using hashes here.

Provenance

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