Skip to main content

Muscles ASGI runtime adapter for Web/API applications

Project description

Muscles ASGI

muscles-asgi is the ASGI runtime for Muscles. It mirrors the WSGI API model while using ASGI scopes/events for async-capable servers.

Installation

pip install muscles-asgi

Canonical ecosystem install matrix is documented in core: Muscles installation matrix.

Related Repositories

  • muscles - core contracts, routing, actions and canonical documentation.
  • muscles-wsgi - WSGI runtime with the same application model.
  • muscles-cli - CLI projection and developer commands.
  • muscles-sse - streaming projection for action results.
  • muscles-mcp - MCP projection that can bind to ASGI entrypoints.
  • muscles-benchmarks - ASGI regression and architecture checks.

Runtime

An app binds Context to AsgiStrategy:

from muscles import ApplicationMeta, Configurator, Context
from muscles.asgi import AsgiStrategy


class App(metaclass=ApplicationMeta):
    config = Configurator(obj={"main": {"HOST": "0.0.0.0", "PORT": "8080"}})
    context = Context(AsgiStrategy, params={})

    def run(self, *args):
        return self.context.execute(*args, shutup=True)

The ASGI package shares core schemas, route matching and OpenAPI generation with the other runtimes. It should not duplicate core itinerary code.

Schema Ownership

ASGI does not ship its own muscles.asgi.schema_ package. Framework schemas, columns, fields, request/response bodies, security objects and value objects belong to muscles.core.schema and should be imported from muscles:

from muscles import Column, JsonRequestBody, Model, String

REST API And Swagger

RestApi controllers/actions are projected into OpenAPI automatically. Generated paths include the external API prefix, so a mounted route such as /api/v1/bookings appears in Swagger exactly as clients must call it.

More detail: docs/openapi-and-routing.md. Backend pipeline features are documented in docs/backend-pipeline.md.

Application Inspection

Use mount_api(app, api) after declaring a RestApi to project ASGI routes into the core ApplicationRegistry. This makes routes visible to inspect_application(app) and CLI/doctor tooling without making the registry the HTTP dispatch source.

Call it after all controllers/actions are registered and before running inspection, doctor checks or generators. It is safe to call more than once: already projected routes are skipped. finalize_api(app, api) is an alias for projects that prefer a "declare, then finalize" bootstrap style. asgi_app(app) also calls mount_application_apis(app) once when the ASGI entrypoint is created, so APIs stored as attributes on the application are visible to runtime inspection without additional app-side adapters.

from muscles import inspect_application
from muscles.asgi import RestApi, finalize_api

app = App()
api = RestApi(name="Api", prefix="/api")

@api.init("/ping", method="get")
def ping(request):
    return {"ok": True}

finalize_api(app, api)
assert any(route["path"] == "/api/ping" for route in inspect_application(app)["routes"])

Request dispatch still uses the ASGI RestApi route tree. The projected routes are lightweight descriptors for tools that need to understand the application without knowing ASGI internals.

When the application has a neutral TelemetryProvider, ASGI records a muscles.server.dispatch span for matched routes with app, route, method and HTTP status attributes.

Action Bridge

ActionAsgiAdapter is an optional HTTP projection for Muscles actions. It keeps package-specific features out of ASGI routes: packages register normal core actions, and ASGI exposes only the actions explicitly allowed by the project.

from muscles.asgi import ActionAsgiAdapter

application = ActionAsgiAdapter.from_application(
    app,
    allowed_actions={"bookings.echo"},
)

The bridge accepts JSON POST /actions/<action-name> requests, executes through core ActionDispatcher(..., transport="http"), returns JSON for non-stream results, and returns application/problem+json for core action errors. Stream actions should be projected through muscles-sse.

Request Handling

Request parsing does not require cgi, multipart or python-magic at import time. Multipart form data uses the standard library path, and missing MIME detection falls back safely.

ASGI request execution is stateless on Context: request-specific data (scope, receive, send) is passed directly into context.execute(...) per request. The strategy keeps a persistent server lifecycle while request state stays isolated.

Development

Run tests with sibling packages on PYTHONPATH:

PYTHONPATH=../muscles/src:src python -m pytest -q

Production notes: docs/production.md.

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

muscles_asgi-1.0.0.tar.gz (196.2 kB view details)

Uploaded Source

Built Distribution

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

muscles_asgi-1.0.0-py3-none-any.whl (206.9 kB view details)

Uploaded Python 3

File details

Details for the file muscles_asgi-1.0.0.tar.gz.

File metadata

  • Download URL: muscles_asgi-1.0.0.tar.gz
  • Upload date:
  • Size: 196.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for muscles_asgi-1.0.0.tar.gz
Algorithm Hash digest
SHA256 5f888a074c0457bc746346785d20b152719f5677fe88f75b98aaf2087680dd0e
MD5 fd6b3c92c9d82c95485a5f9e87b97cc5
BLAKE2b-256 1485942a254a5f3949a8f9476149e7d3a9946c81da036bf8dfef65bec7b63adb

See more details on using hashes here.

Provenance

The following attestation bundles were made for muscles_asgi-1.0.0.tar.gz:

Publisher: release.yml on butkoden/muscles-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 muscles_asgi-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: muscles_asgi-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 206.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for muscles_asgi-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 d175d65e72b371b10d301a0bedb66e61fa34c66e5900701ec00eb535a29e3311
MD5 724472a7e248164a72531e1150152225
BLAKE2b-256 c1c9c469fc3046c299983b8f9e8b05cb752e8271e6af994c7ebcc7673a293b02

See more details on using hashes here.

Provenance

The following attestation bundles were made for muscles_asgi-1.0.0-py3-none-any.whl:

Publisher: release.yml on butkoden/muscles-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