Skip to main content

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

  1. Fork this repo.
  2. Create a feature branch and make changes.
  3. Install dev requirements:
    poetry install -E all --with dev
    
  4. Run Tests:
    make pytest
    
  5. 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

fastexec-0.6.0.tar.gz (6.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

fastexec-0.6.0-py3-none-any.whl (7.8 kB view details)

Uploaded Python 3

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

Hashes for fastexec-0.6.0.tar.gz
Algorithm Hash digest
SHA256 9b8fd5711bb921d63e34d5c542bc9e24f77e5018a2f7d99fca9dcb4af1d94f8d
MD5 693ec8fd029d47ce3b42e74cc1100dfd
BLAKE2b-256 2a5caa326f99ea99227092826a1f18b307a7555f96ca8750d21aa98c4e58739a

See more details on using hashes here.

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

Hashes for fastexec-0.6.0-py3-none-any.whl
Algorithm Hash digest
SHA256 02ad1ceda4d3ed158fd55a90d79f1244893d85822c2655423546e8ea56650409
MD5 f6857cfd0f244353d2ee680479cdb513
BLAKE2b-256 7a720f875c21817374a99ede95e4295c2730bf74dcc6bfbd4d075e1f95879893

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page