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.1.tar.gz (196.4 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.1-py3-none-any.whl (207.1 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: muscles_asgi-1.0.1.tar.gz
  • Upload date:
  • Size: 196.4 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.1.tar.gz
Algorithm Hash digest
SHA256 24c2c74b030d6934a5c278a50d37be12772c15844f9b3f2bf6e3ae9695a322b4
MD5 1629ca20ad347831915358a586400a49
BLAKE2b-256 fa7b4fecd7a2a7bcc557b1ddd1a8f55194e1ecc9246d55098ce3b4bd2a0b1507

See more details on using hashes here.

Provenance

The following attestation bundles were made for muscles_asgi-1.0.1.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.1-py3-none-any.whl.

File metadata

  • Download URL: muscles_asgi-1.0.1-py3-none-any.whl
  • Upload date:
  • Size: 207.1 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.1-py3-none-any.whl
Algorithm Hash digest
SHA256 8458096e928428ce01335226de05b71be84560a5c8bfc2769b1dd4812513e2ab
MD5 1b1f982ac9e4233f1f91d5d5c665bf0d
BLAKE2b-256 71ab69751ff776169d4868b7a273e43b8ea494e1c8c5667c503441d88158f28d

See more details on using hashes here.

Provenance

The following attestation bundles were made for muscles_asgi-1.0.1-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