| single |
# Cross
**Write once, run everywhere** - A universal web framework adapter for
Python that lets you write code once and use it across multiple web
frameworks.
## Installation
```bash
uv add cross-web
`
`python
from cross_web import Response
```
## Overview
Cross provides a unified interface for common web framework operations,
allowing you to write framework-agnostic code that can be easily adapted to
work with FastAPI, Flask, Django, and other popular Python web frameworks.
## Testing
This project is in early development!
Cross also ships framework-specific test clients under
`cross_web.testing.clients`.
Import a concrete client from its module:
```python
from cross_web.testing.clients.starlette import StarletteHttpClient
from cross_web.testing.clients.flask import FlaskHttpClient
from cross_web.testing.clients.django import DjangoHttpClient
```
Do not import client classes from `cross_web.testing.clients` directly. The
package only exports the shared base types so importing it does not pull
optional framework dependencies.
The shared testing API lives in `cross_web.testing`:
```python
from cross_web.testing import HttpClient, Response
```
Every concrete client exposes the same async interface:
- `await client.request(url, method, headers=None, **kwargs)`
- `await client.get(url, headers=None, **kwargs)`
- `await client.post(url, data=None, json=None, files=None, headers=None,
**kwargs)`
`Response` exposes:
- `response.status_code`
- `response.headers`
- `response.text`
- `response.json`
### Example
```python
import json
import pytest
from starlette.applications import Starlette
from starlette.requests import Request
from starlette.responses import JSONResponse
from starlette.routing import Route
from cross_web.request._starlette import StarletteRequestAdapter
from cross_web.testing.clients.starlette import StarletteHttpClient
async def echo(request: Request) -> JSONResponse:
adapter = StarletteRequestAdapter(request)
body = await adapter.get_body()
return JSONResponse(
{
"method": adapter.method,
"query": dict(adapter.query_params),
"body": json.loads(body.decode()),
}
)
app = Starlette(routes=[Route("/echo", echo, methods=["POST"])])
@pytest.mark.asyncio
async def test_echo() -> None:
client = StarletteHttpClient(app)
response = await client.post("/echo?debug=1", json={"hello": "world"})
assert response.status_code == 200
assert response.json == {
"method": "POST",
"query": {"debug": "1"},
"body": {"hello": "world"},
}
|