Experimental thread-aware ASGI framework and runtime prototype.
Project description
tasgi
tasgi means Thread ASGI. It is an experimental ASGI-compatible framework/runtime that keeps transport and protocol handling on the event loop while allowing handler execution on either the asyncio loop or a thread runtime.
Runtime design goal:
- the
tasgipackage itself depends only on the Python standard library - external tools like
coverage,build, andtwineare used only for CI, testing, and packaging
Status
tasgi is currently an alpha-stage project.
- public APIs are still settling
- auth APIs are still evolving
- router/module composition is still evolving
- native HTTP/2 support is still a prototype subset
Treat the current release line as experimental, not stable.
Install
From source:
pip install -e .
tasgi does not require Poetry at runtime. The project is packaged from pyproject.toml
using the standard PEP 517 build flow, so CI and publishing use pip, build, and twine
directly instead of a Poetry-specific workflow.
After packaging to TestPyPI, the intended trial install flow is:
pip install --index-url https://test.pypi.org/simple/ tasgi
Hello World
from tasgi import TasgiApp, TextResponse
app = TasgiApp(docs=True, debug=True)
@app.route.get("/")
async def home(request):
return TextResponse("hello from tasgi")
Run it:
tasgi
Or run the bundled demo app:
python3 examples/service_api/main.py
Router Usage
tasgi now treats app.route as the main HTTP registration surface.
from tasgi import JsonResponse, Router, TasgiApp
users = Router(tags=["users"])
@users.get("/users")
def list_users(request):
return ["alice", "bob"]
app = TasgiApp()
app.include_router(users, prefix="/api")
@app.route.get("/status")
async def status(request):
return JsonResponse({"ok": True})
Core Model
tasgi is layered like this:
socket/transport
-> ASGI boundary
-> tasgi runtime
-> tasgi framework
-> user handlers
Rules:
- network I/O stays on the event loop
- HTTP protocol handling stays on the event loop
- async handlers run on the asyncio loop
- sync handlers run in the tasgi thread runtime
- worker threads never write directly to sockets
Dual Execution Model
App-level execution policy is explicit:
from tasgi import ASYNC_EXECUTION, THREAD_EXECUTION, TasgiApp
app = TasgiApp(default_execution=THREAD_EXECUTION)
@app.route.get("/cpu")
def cpu(request):
...
@app.route.get("/status", execution=ASYNC_EXECUTION)
async def status(request):
...
Request And Response Types
Main public HTTP types:
TasgiAppRouterRequestResponseTextResponseJsonResponseStreamingResponse
Handlers may return Response objects directly, or return typed values when a response model is declared.
OpenAPI And Docs
Built-in docs can be enabled from app config:
from dataclasses import dataclass
from tasgi import TasgiApp
@dataclass
class EchoIn:
message: str
@dataclass
class EchoOut:
echoed: str
app = TasgiApp(
docs=True,
title="tasgi demo",
version="0.1.0a1",
)
@app.route.post("/echo", request_model=EchoIn, response_model=EchoOut)
def echo(request, body: EchoIn) -> EchoOut:
return EchoOut(echoed=body.message)
Default docs endpoints:
/openapi.json/docs
Auth
tasgi includes an experimental pluggable auth layer.
Built-in starters:
BearerTokenBackendAPIKeyBackendBasicAuthBackendRequireAuthenticatedRequireScopeRequireRole
Example:
from tasgi import BearerTokenBackend, Identity, RequireScope, TasgiApp
def validate_token(token: str):
if token == "demo-token":
return Identity(subject="alice", scopes=frozenset({"profile"}))
if token == "admin-token":
return Identity(subject="admin", scopes=frozenset({"admin"}))
return None
app = TasgiApp(auth_backend=BearerTokenBackend(validate_token), docs=True)
@app.route.get("/public", auth=False)
async def public_route(request):
return {"public": True}
@app.route.get("/me", auth=True)
async def me(request):
return {"subject": request.identity.subject}
@app.route.get("/admin", auth=RequireScope("admin"))
async def admin(request):
return {"subject": request.identity.subject}
Auth metadata is also reflected automatically in OpenAPI for built-in auth backends.
Demo App
The bundled service example includes:
- HTTP routes
- router/module composition
- OpenAPI + Swagger UI
- auth examples
- streaming responses
- WebSocket echo
- thread-executed sync handlers
Run:
python3 examples/service_api/main.py
There is also a cleaner modular composition example:
python3 examples/modular_api/main.py
Benchmarks
The benchmark suite exercises loopback TCP requests against a dedicated benchmark app.
Run:
python3 benchmarks/run_benchmarks.py
CI And Publishing
GitHub Actions workflows are set up for both validation and releases:
CIruns on every push and pull request- the primary CI target is free-threaded CPython
3.14t - standard compatibility tests also run on Python 3.14, 3.13, 3.12, and 3.11
- coverage is reported in CI using
coverage run -m unittest discover -s tests - package builds are verified in CI with
python -m buildandpython -m twine check --strict dist/*
Publishing is separated from CI:
Publishruns only on version tags likev0.1.0a1or on published GitHub Releases- release builds run on CPython
3.14t - PyPI upload is configured for Trusted Publishing via GitHub Actions
- before enabling real PyPI releases, do one TestPyPI dry run and confirm a clean install path
Local commands:
python3 -m unittest discover -s tests -v
python3 -m pip install coverage build twine
coverage run -m unittest discover -s tests
coverage report -m
python3 -m build
python3 -m twine check --strict dist/*
Current Limits
- HTTP/2 support is prototype-grade, not production-complete
- auth API is still settling
- route registration APIs changed recently and may still evolve
- no middleware ecosystem yet
- no dependency injection container beyond explicit lightweight helpers
- no production-hardening claims
License
tasgi is licensed under Apache-2.0. See LICENSE and NOTICE.
That keeps the project free to use, including in companies, while preserving the attribution notices when the software is redistributed.
Release Notes
This repository is currently prepared for an alpha-style release, not a stable release.
Before a public non-alpha release, the project still needs:
- final public API freeze
- repository/homepage URLs in package metadata
- a TestPyPI install-and-verify pass
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 tasgi-0.1.0a1.tar.gz.
File metadata
- Download URL: tasgi-0.1.0a1.tar.gz
- Upload date:
- Size: 72.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7ec12ab1489e769ee76b4f1037cc248a8106d933d7a57813c696e31576c225a8
|
|
| MD5 |
29e495032d704f6a526135035b82773c
|
|
| BLAKE2b-256 |
8fa75a78efdf6ce2086ea375980bf49c97d82b84ce2c5cbb40aaaec35c3ab8b1
|
Provenance
The following attestation bundles were made for tasgi-0.1.0a1.tar.gz:
Publisher:
publish.yml on VachaganGrigoryan/tasgi
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
tasgi-0.1.0a1.tar.gz -
Subject digest:
7ec12ab1489e769ee76b4f1037cc248a8106d933d7a57813c696e31576c225a8 - Sigstore transparency entry: 1124389013
- Sigstore integration time:
-
Permalink:
VachaganGrigoryan/tasgi@f45437f924c57d49a1c4ad906ca532ed47bc7deb -
Branch / Tag:
refs/tags/v0.1.0a1 - Owner: https://github.com/VachaganGrigoryan
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@f45437f924c57d49a1c4ad906ca532ed47bc7deb -
Trigger Event:
push
-
Statement type:
File details
Details for the file tasgi-0.1.0a1-py3-none-any.whl.
File metadata
- Download URL: tasgi-0.1.0a1-py3-none-any.whl
- Upload date:
- Size: 62.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
259f7854b48ebb7b6e2bd02b422e697ba52e060791935abad458a0f4de521870
|
|
| MD5 |
44bdcc5eb981d573a82301dcbfc083e2
|
|
| BLAKE2b-256 |
0bae3e9ab031691d815570c2c6921db5d9e0e7f0af4aee8629d83d9533ba7547
|
Provenance
The following attestation bundles were made for tasgi-0.1.0a1-py3-none-any.whl:
Publisher:
publish.yml on VachaganGrigoryan/tasgi
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
tasgi-0.1.0a1-py3-none-any.whl -
Subject digest:
259f7854b48ebb7b6e2bd02b422e697ba52e060791935abad458a0f4de521870 - Sigstore transparency entry: 1124389183
- Sigstore integration time:
-
Permalink:
VachaganGrigoryan/tasgi@f45437f924c57d49a1c4ad906ca532ed47bc7deb -
Branch / Tag:
refs/tags/v0.1.0a1 - Owner: https://github.com/VachaganGrigoryan
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@f45437f924c57d49a1c4ad906ca532ed47bc7deb -
Trigger Event:
push
-
Statement type: