Metadata-Version: 2.4
Name: asyncutilsx
Version: 0.2.0
Summary: ASGI wrapper for combining FastAPI and Socket.IO in one app
Author: Akshat kotpalliwar (IntegerAlex)
Maintainer: Akshat kotpalliwar (IntegerAlex)
License-Expression: LGPL-2.1-only
Project-URL: Repository, https://github.com/IntegerAlex/asyncplus
Project-URL: Documentation, https://github.com/IntegerAlex/asyncplus#readme
Project-URL: Changelog, https://github.com/IntegerAlex/asyncplus/blob/main/CHANGELOG.md
Keywords: asgi,fastapi,socket.io,websocket
Classifier: Development Status :: 4 - Beta
Classifier: Framework :: FastAPI
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Internet :: WWW/HTTP :: HTTP Servers
Requires-Python: >=3.12
Description-Content-Type: text/markdown
License-File: LICENSE
License-File: NOTICE
Requires-Dist: asgiref>=3.11.0
Requires-Dist: fastapi>=0.115.0
Requires-Dist: python-socketio>=5.11.0
Provides-Extra: dev
Requires-Dist: build>=1.4.0; extra == "dev"
Requires-Dist: hypothesis>=6.0; extra == "dev"
Requires-Dist: twine>=6.2.0; extra == "dev"
Requires-Dist: pytest>=8.0; extra == "dev"
Requires-Dist: pytest-asyncio>=0.24; extra == "dev"
Requires-Dist: httpx>=0.27; extra == "dev"
Dynamic: license-file

# asyncutilsx

[![CodSpeed](https://img.shields.io/endpoint?url=https://codspeed.io/badge.json)](https://codspeed.io/IntegerAlex/asyncutilsx?utm_source=badge)

ASGI wrapper for combining **FastAPI** and **Socket.IO** in one app.

**Author:** Akshat kotpalliwar (alias IntegerAlex)  
**SPDX-License-Identifier:** LGPL-2.1-only

Minimal and pure: one function, no side effects.

## Why asyncplus() / asyncutilsx?

**Scenario: real-time chat app with REST API**

```python
# ❌ With mount() — problematic
app = FastAPI()
app.mount("/socket.io", socket_app)
# - Auth middleware may break Socket.IO handshake
# - CORS middleware may interfere
# - Extra latency on every Socket.IO message

# ✅ With asyncplus — clean
asgi_app = asyncplus(app, sio)
# - Socket.IO gets raw ASGI requests
# - FastAPI gets HTTP requests
# - Each handles its own concerns
```

FastAPI’s `app.mount("/path", other_asgi)` works, but you must serve Socket.IO on a subpath and deal with that path everywhere (client, CORS, proxies). **asyncplus** gives you a **single ASGI app**: one entry point for the server (e.g. uvicorn), no mount path, same origin for API and Socket.IO. Plug and play—no middleware, no timeouts or circuit breakers added; you keep full control of the ASGI apps you pass in.

## Install

```bash
pip install asyncutilsx
```

## Usage

```python
from fastapi import FastAPI
from socketio import AsyncServer
from asyncutilsx import asyncplus

app = FastAPI()
sio = AsyncServer(async_mode="asgi")

@sio.event
async def connect(sid, environ):
    print("connect", sid)

asgi_app = asyncplus(app, sio)
# Run with: uvicorn asgi:asgi_app
```

- **HTTP** (except `/socket.io/*`) → FastAPI  
- **HTTP** `/socket.io/*` → Socket.IO (polling)  
- **WebSocket** → Socket.IO  

Optional: `asyncplus(app, sio, socketio_path="/custom/", debug_hook=..., socketio_fallback_on_error=False, timeout=30.0)`.

For custom routing (e.g. SSE, gRPC), use the pure `router(routes, default_app)` function: pass a sequence of `(predicate, app)` pairs; first match wins; `default_app` used when none match.

See [docs/user_guide.md](docs/user_guide.md) for common patterns and examples.  

## Development

```bash
pip install -e ".[dev]"
pytest
```

## Benchmarks

Performance benchmarks are continuously monitored with CodSpeed. To run benchmarks locally:

```bash
pytest benchmarks/ --codspeed
```

## License

LGPL-2.1-only
