Execute function with FastAPI features.
Project description
fastexec
Version: 0.6.0 License: MIT
Execute functions with FastAPI features—dependency injection, validation, response models, and more—without running a full server.
Summary
fastexec lets you build and execute function pipelines using the same patterns as FastAPI: dependency injection via Depends(), Pydantic validation via type hints, response model filtering, and layered state management. No HTTP server required.
Use cases:
- Offline execution of FastAPI-style endpoints (batch jobs, scripts, CLI tools)
- Testing route logic and dependency chains without spinning up a server
- Workflow orchestration with typed, validated pipelines
Installation
Requires Python 3.11+.
pip install fastexec
Quick Start
import asyncio
import fastapi
from fastexec import FastExec, Pipeline
# Define a pipeline (like FastAPI's APIRouter)
pipeline = Pipeline()
@pipeline.register("/greet")
async def greet(name: str = fastapi.Query("World")):
return {"message": f"Hello, {name}!"}
# Create the app (like FastAPI())
app = FastExec()
app.include_pipeline(pipeline)
# Execute
async def main():
result = await app.exec("/greet", query_params={"name": "Alice"})
print(result) # {'message': 'Hello, Alice!'}
asyncio.run(main())
Core Concepts
FastExec (App) and Pipeline (Router)
FastExec is the application object (analogous to FastAPI()). Pipeline is a route group (analogous to APIRouter).
from fastexec import FastExec, Pipeline
users = Pipeline()
orders = Pipeline()
@users.register("/list")
async def list_users():
return [{"id": 1, "name": "Alice"}]
@orders.register("/list")
async def list_orders():
return [{"id": 101, "total": 42.0}]
app = FastExec()
app.include_pipeline(users, prefix="/users")
app.include_pipeline(orders, prefix="/orders")
# Dispatch by path
await app.exec("/users/list") # -> [{"id": 1, "name": "Alice"}]
await app.exec("/orders/list") # -> [{"id": 101, "total": 42.0}]
Dependency Injection
Three layers of dependencies cascade: app → pipeline → endpoint. All use FastAPI's Depends().
import fastapi
from fastexec import FastExec, Pipeline
async def app_auth(request: fastapi.Request):
"""App-level dependency — runs for every endpoint."""
token = request.headers.get("authorization")
if not token:
raise fastapi.HTTPException(status_code=401, detail="Unauthorized")
async def pipeline_logger():
"""Pipeline-level dependency — runs for endpoints in this pipeline."""
print("Pipeline executing")
async def get_user_id(user_id: int = fastapi.Query(...)):
return user_id
pipeline = Pipeline(dependencies=[fastapi.Depends(pipeline_logger)])
@pipeline.register("/profile")
async def profile(uid: int = fastapi.Depends(get_user_id)):
return {"user_id": uid}
app = FastExec(dependencies=[fastapi.Depends(app_auth)])
app.include_pipeline(pipeline, prefix="/users")
result = await app.exec(
"/users/profile",
query_params={"user_id": 42},
headers={"authorization": "Bearer token"},
)
# result == {"user_id": 42}
State Management
App-level state is set via FastExec(state=...) and accessed through request.app.state. Per-request state is passed via exec(state=...) and accessed through request.state.
app = FastExec(state={"db_url": "postgres://localhost/mydb"})
pipeline = Pipeline()
@pipeline.register("/info")
async def info(request: fastapi.Request):
return {
"db": request.app.state.db_url,
"session": request.state.session_id,
}
app.include_pipeline(pipeline)
result = await app.exec("/info", state={"session_id": "abc123"})
# result == {"db": "postgres://localhost/mydb", "session": "abc123"}
Auto Validation via Type Hints
Like FastAPI, type annotations drive runtime validation. Pydantic models as parameter types auto-parse the request body; return type annotations auto-filter the response.
import pydantic
class UserCreate(pydantic.BaseModel):
name: str
email: str
class UserResponse(pydantic.BaseModel):
name: str
email: str
pipeline = Pipeline()
@pipeline.register("/create")
async def create_user(user: UserCreate) -> UserResponse:
# Return extra fields — they'll be stripped by the return type
return {"name": user.name, "email": user.email, "internal_id": 999}
app = FastExec()
app.include_pipeline(pipeline, prefix="/users")
result = await app.exec("/users/create", body={"name": "Alice", "email": "alice@example.com"})
# result == {"name": "Alice", "email": "alice@example.com"}
# "internal_id" is filtered out by the UserResponse return type
Response Model and Status Code
Explicit response_model and status_code can be set on register():
pipeline.register("/create", create_user, response_model=UserResponse, status_code=201)
Nested Pipelines
Pipelines can include other pipelines, just like FastAPI's nested routers:
child = Pipeline()
@child.register("/detail")
async def detail():
return {"detail": "nested"}
parent = Pipeline()
parent.include_pipeline(child, prefix="/child")
app = FastExec()
app.include_pipeline(parent, prefix="/parent")
await app.exec("/parent/child/detail") # -> {"detail": "nested"}
Examples
See the tests/ folder for comprehensive examples covering all features.
Contributing
- Fork this repo.
- Create a feature branch and make changes.
- Install dev requirements:
poetry install -E all --with dev
- Run Tests:
make pytest - Open a Pull Request.
License
fastexec is distributed under the terms of the MIT License.
Project details
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 fastexec-0.6.0.tar.gz.
File metadata
- Download URL: fastexec-0.6.0.tar.gz
- Upload date:
- Size: 6.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/2.3.2 CPython/3.12.13 Darwin/25.3.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9b8fd5711bb921d63e34d5c542bc9e24f77e5018a2f7d99fca9dcb4af1d94f8d
|
|
| MD5 |
693ec8fd029d47ce3b42e74cc1100dfd
|
|
| BLAKE2b-256 |
2a5caa326f99ea99227092826a1f18b307a7555f96ca8750d21aa98c4e58739a
|
File details
Details for the file fastexec-0.6.0-py3-none-any.whl.
File metadata
- Download URL: fastexec-0.6.0-py3-none-any.whl
- Upload date:
- Size: 7.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/2.3.2 CPython/3.12.13 Darwin/25.3.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
02ad1ceda4d3ed158fd55a90d79f1244893d85822c2655423546e8ea56650409
|
|
| MD5 |
f6857cfd0f244353d2ee680479cdb513
|
|
| BLAKE2b-256 |
7a720f875c21817374a99ede95e4295c2730bf74dcc6bfbd4d075e1f95879893
|