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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5f888a074c0457bc746346785d20b152719f5677fe88f75b98aaf2087680dd0e
|
|
| MD5 |
fd6b3c92c9d82c95485a5f9e87b97cc5
|
|
| BLAKE2b-256 |
1485942a254a5f3949a8f9476149e7d3a9946c81da036bf8dfef65bec7b63adb
|
Provenance
The following attestation bundles were made for muscles_asgi-1.0.0.tar.gz:
Publisher:
release.yml on butkoden/muscles-asgi
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
muscles_asgi-1.0.0.tar.gz -
Subject digest:
5f888a074c0457bc746346785d20b152719f5677fe88f75b98aaf2087680dd0e - Sigstore transparency entry: 2258778476
- Sigstore integration time:
-
Permalink:
butkoden/muscles-asgi@7d5f961daf5f374bc67af70b1e95d03e9706a4d2 -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/butkoden
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@7d5f961daf5f374bc67af70b1e95d03e9706a4d2 -
Trigger Event:
release
-
Statement type:
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d175d65e72b371b10d301a0bedb66e61fa34c66e5900701ec00eb535a29e3311
|
|
| MD5 |
724472a7e248164a72531e1150152225
|
|
| BLAKE2b-256 |
c1c9c469fc3046c299983b8f9e8b05cb752e8271e6af994c7ebcc7673a293b02
|
Provenance
The following attestation bundles were made for muscles_asgi-1.0.0-py3-none-any.whl:
Publisher:
release.yml on butkoden/muscles-asgi
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
muscles_asgi-1.0.0-py3-none-any.whl -
Subject digest:
d175d65e72b371b10d301a0bedb66e61fa34c66e5900701ec00eb535a29e3311 - Sigstore transparency entry: 2258778559
- Sigstore integration time:
-
Permalink:
butkoden/muscles-asgi@7d5f961daf5f374bc67af70b1e95d03e9706a4d2 -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/butkoden
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@7d5f961daf5f374bc67af70b1e95d03e9706a4d2 -
Trigger Event:
release
-
Statement type: