Metadata-Version: 2.4
Name: spikard
Version: 0.13.0
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Web Environment
Classifier: Framework :: AsyncIO
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Natural Language :: English
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Programming Language :: Rust
Classifier: Topic :: Internet :: WWW/HTTP
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
Classifier: Topic :: Internet :: WWW/HTTP :: HTTP Servers
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Stubs Only
Requires-Dist: cloudpickle>=3.1.2
Requires-Dist: granian>=2.7.2
Requires-Dist: grpcio>=1.78
Requires-Dist: httpx>=0.28.1
Requires-Dist: httpx-sse>=0.4.3
Requires-Dist: msgspec>=0.19
Requires-Dist: typing-extensions>=4
Requires-Dist: uvloop>=0.22 ; sys_platform != 'win32'
Requires-Dist: websockets>=16
Requires-Dist: uvloop>=0.22 ; sys_platform != 'win32' and extra == 'uvloop'
Provides-Extra: uvloop
Summary: High-performance Python web framework with a Rust core. Build REST APIs, WebSockets, and SSE services with FastAPI/Litestar-style decorators backed by Axum and Tower-HTTP. 2.8x faster than FastAPI.
Keywords: api,async,axum,fastapi,framework,http,litestar,msgspec,performance,rest,rust,sse,tower,validation,web,websocket
Home-Page: https://github.com/Goldziher/spikard
Author-email: Na'aman Hirschfeld <nhirschfeld@gmail.com>
License: MIT
Requires-Python: >=3.10
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
Project-URL: Bug Tracker, https://github.com/Goldziher/spikard/issues
Project-URL: Changelog, https://github.com/Goldziher/spikard/releases
Project-URL: Discord, https://discord.gg/pXxagNK2zN
Project-URL: Documentation, https://github.com/Goldziher/spikard/blob/main/packages/python/README.md
Project-URL: Homepage, https://github.com/Goldziher/spikard
Project-URL: Repository, https://github.com/Goldziher/spikard

<!-- GENERATED FILE — DO NOT EDIT DIRECTLY. Run: task readme:generate -->

# Spikard Python

<div align="center" style="display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; margin: 20px 0;">
  <a href="https://spikard.dev">
    <img src="https://img.shields.io/badge/docs-spikard.dev-007ec6" alt="Documentation">
  </a>
  <a href="https://crates.io/crates/spikard">
    <img src="https://img.shields.io/crates/v/spikard.svg?color=007ec6" alt="Crates.io">
  </a>
  <a href="https://pypi.org/project/spikard/">
    <img src="https://img.shields.io/pypi/v/spikard.svg?color=007ec6" alt="PyPI">
  </a>
  <a href="https://www.npmjs.com/package/@spikard/node">
    <img src="https://img.shields.io/npm/v/@spikard/node.svg?color=007ec6" alt="npm">
  </a>
  <a href="https://rubygems.org/gems/spikard">
    <img src="https://img.shields.io/gem/v/spikard.svg?color=007ec6" alt="RubyGems">
  </a>
  <a href="https://packagist.org/packages/spikard/spikard">
    <img src="https://img.shields.io/packagist/v/spikard/spikard.svg?color=007ec6" alt="Packagist">
  </a>
  <a href="https://hex.pm/packages/spikard">
    <img src="https://img.shields.io/hexpm/v/spikard.svg?color=007ec6" alt="Hex.pm">
  </a>
  <a href="https://github.com/Goldziher/spikard/blob/main/LICENSE">
    <img src="https://img.shields.io/badge/license-MIT-007ec6" alt="License">
  </a>
</div>

High-performance Python web framework backed by a Rust core. Build REST APIs, WebSockets, and SSE services with FastAPI/Litestar-style decorators powered by Tokio, Hyper, and Tower middleware.

## Features
- **Multiple route styles:** FastAPI-style (`@app.get()`) or Litestar-style (`@get()`)
- **Automatic validation:** msgspec (default), Pydantic v2, dataclasses, TypedDict, NamedTuple
- **Request/response streaming:** WebSockets, Server-Sent Events, multipart uploads
- **Middleware stack:** Compression, rate limiting, request IDs, authentication, CORS
- **Async-first:** Full async/await with `pyo3_async_runtimes`
- **OpenAPI generation:** Automatic type introspection and documentation
- **Dependency injection:** Configurable container with singleton and factory support

## Installation

```bash
pip install spikard
```

Pre-built wheels available for macOS, Linux, Windows. Building from source requires Rust 1.75+.

**Development:**
```bash
cd packages/python && uv sync
```

**Requirements:** Python 3.10+

## Quick Start

```python
from spikard import Spikard
from spikard.config import ServerConfig
from msgspec import Struct

class User(Struct):
    id: int
    name: str
    email: str

app = Spikard()

@app.get("/users/{user_id}")
async def get_user(user_id: int) -> User:
    return User(id=user_id, name="Alice", email="alice@example.com")

@app.post("/users")
async def create_user(user: User) -> User:
    # Automatic validation via msgspec
    return user

if __name__ == "__main__":
    app.run(config=ServerConfig(port=8000))
```

## Core Concepts

**Route Decorators:**
```python
from spikard import Spikard, get, post

app = Spikard()

@app.get("/users/{user_id}")
async def get_user(user_id: int):
    return {"id": user_id}

@post("/users")  # Standalone decorator style
async def create_user(user: User):
    return user
# Note: standalone decorators require app.include_router(get_default_router()) before app.run()
```

**Validation with msgspec (recommended):**
```python
from msgspec import Struct

class User(Struct):
    name: str
    email: str

@app.post("/users")
async def create_user(user: User):
    return user  # Automatic validation
```

**Dependency Injection:**
```python
from spikard.di import Provide

class DatabasePool:
    async def fetch(self, sql: str) -> list: ...

def create_pool() -> DatabasePool:
    return DatabasePool()

app.provide(DatabasePool, Provide(create_pool, singleton=True))

@app.get("/data")
async def get_data(pool: DatabasePool) -> dict:
    return {"data": await pool.fetch("SELECT * FROM items")}
```

**WebSockets:**
```python
from spikard import websocket

@app.websocket("/ws")
async def chat_endpoint(message: dict) -> dict | None:
    return {"echo": message}
```

**Server-Sent Events:**
```python
from spikard import sse

@sse("/events")
async def stream():
    for i in range(10):
        yield {"count": i}
```

**Lifecycle Hooks:**
```python
@app.pre_validation
async def check_auth(request):
    if not request.headers.get("authorization"):
        return Response({"error": "Unauthorized"}, 401)
    return request
```
## Configuration

```python
from spikard import Spikard, ServerConfig, CompressionConfig, RateLimitConfig, JwtConfig

config = ServerConfig(
    host="0.0.0.0",
    port=8080,
    workers=4,
    compression=CompressionConfig(gzip=True, brotli=True),
    rate_limit=RateLimitConfig(per_second=100, burst=200),
    jwt=JwtConfig(secret="key", algorithm="HS256")
)

app = Spikard(config=config)
```

See the documentation for all options.

## Performance

Benchmarked across 34 workloads at 100 concurrency ([methodology](../../docs/benchmarks/methodology.md)):

| Framework | Avg RPS | P50 (ms) | P99 (ms) |
|-----------|--------:|----------:|----------:|
| **spikard** | 12,623 | 5.55 | 38.39 |
| litestar | 8,032 | 14.62 | 19.18 |
| fastapi | 6,418 | 16.43 | 21.72 |
| robyn | 6,012 | 16.85 | 24.18 |

Spikard is **1.6x faster than Litestar (throughput-based; see full results for latency breakdown), 2.0x faster than FastAPI, and 2.1x faster than Robyn (also Rust-backed)**.

Key optimizations:
- Zero-copy PyO3 type conversion (no JSON round-trips)
- Rust-powered HTTP server (Tokio + Hyper)
- GIL-friendly async design with `pyo3_async_runtimes`

## Testing

```python
from spikard.testing import TestClient

async def test_users():
    async with TestClient(app) as client:
        response = await client.get("/users/123")
        assert response.status_code == 200
        assert response.json()["id"] == 123
```

`TestClient` uses in-process Rust testing for speed. `LiveTestClient` starts a real subprocess server for WebSocket/SSE tests.

See the main documentation for WebSocket and SSE testing.

## Examples

Runnable examples with dependency injection and database integration:
- [Python examples](../../examples/python/)
- [GraphQL schema support](../../examples/schemas/social.graphql)
- [OpenAPI code generation](../../examples/schemas/todo-api.openapi.yaml)

See [examples/README.md](../../examples/README.md) for all languages and code generation.

## Documentation

Full documentation at [spikard.dev](https://spikard.dev). See also [CONTRIBUTING.md](../../CONTRIBUTING.md).

## Other Languages

- **Rust:** [Crates.io](https://crates.io/crates/spikard)
- **Python:** [PyPI](https://pypi.org/project/spikard/)
- **TypeScript:** [npm (@spikard/node)](https://www.npmjs.com/package/@spikard/node)
- **Ruby:** [RubyGems](https://rubygems.org/gems/spikard)
- **PHP:** [Packagist](https://packagist.org/packages/spikard/spikard)
- **Elixir:** [Hex.pm](https://hex.pm/packages/spikard)

## License

MIT - See [LICENSE](../../LICENSE) for details

