Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

1 Commit
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

ylmz

A lightweight, zero-dependency ASGI web framework kernel β€” FastAPI-like API, minimal footprint.

Python License

ylmz is a pure-Python ASGI web framework that delivers the developer experience of FastAPI β€” type-safe request/response handling, automatic OpenAPI docs, dependency injection, and rich data validation β€” all without mandatory third-party dependencies.


✨ Features

Category Highlights
Routing @app.get/post/put/delete/patch/websocket β€” path params {id} with type coercion {id:int}
Type System BaseModel with Field(ge/le/gt/lt/min_length/max_length/pattern/alias), @validator, model_dump[_json], model_validate
Rich Types str int float bool Decimal datetime date time UUID Enum Optional[T] Union[A,B] list[T] dict[K,V] nested models
Dependency Injection Depends() with automatic sub-dependency resolution and per-request caching
Parameter Descriptors Path() Query() Body() Header() Cookie() β€” explicit source + constraints
Background Tasks BackgroundTasks.add_task() β€” fire-and-forget after response
Lifespan @app.on_event("startup"/"shutdown") + app.state
Middleware Class-based middleware chain + built-in cors_middleware_factory()
Exception Handling HTTPException, custom @app.exception_handler()
OpenAPI Docs setup_docs(app) β†’ auto-generated /docs (Swagger) + /redoc
WebSocket Native WebSocket with send_text/send_json/send_bytes/receive/close
File Upload UploadFile with read() / save()
Status Codes status.OK, status.CREATED, status.NOT_FOUND … β€” named constants
Zero Deps Core framework has zero mandatory dependencies β€” just uvicorn to run

πŸš€ Quick Start

Installation

pip install -e .            # framework only
pip install -e ".[dev]"     # + uvicorn, pytest, httpx

Hello World

from ylmz import Ylmz

app = Ylmz()

@app.get("/")
async def root():
    return {"hello": "world"}
PYTHONPATH=. uvicorn hello:app --reload

Open http://localhost:8000/docs for interactive Swagger UI.


πŸ“– Usage Guide

Routing

@app.get("/items/{item_id:int}")
async def get_item(item_id: int):
    return {"item_id": item_id}

@app.get("/search")
async def search(q: str = "", page: int = 1):
    return {"q": q, "page": page}

Data Models

from enum import Enum
from datetime import datetime
from ylmz import BaseModel, Field, validator

class Category(str, Enum):
    ELECTRONICS = "electronics"
    BOOKS = "books"

class Item(BaseModel):
    name: str = Field(min_length=1, max_length=100, description="Item name")
    price: float = Field(ge=0)
    category: Category
    tags: list[str] | None = None
    created_at: datetime | None = None

    @validator("name")
    def normalize(cls, v):
        return v.strip()

# Automatic validation
item = Item(name="  Widget  ", price=9.99, category="electronics")
assert item.name == "Widget"
print(item.model_dump_json())  # β†’ JSON string

POST with Body

@app.post("/items", status_code=201)
async def create_item(item: Item):
    # item is already validated
    return {"created": item.model_dump()}

Dependency Injection

from ylmz import Depends

async def get_db():
    return {"connected": True}

@app.get("/data")
async def read_data(db=Depends(get_db)):
    return {"db": db}

# Sub-dependencies work automatically:
async def get_repo(db=Depends(get_db)):
    return f"repo({db['connected']})"

@app.get("/repo")
async def read_repo(repo=Depends(get_repo)):
    return {"repo": repo}

Parameter Descriptors

from ylmz import Path, Query, Body, Header, Cookie

@app.get("/items/{item_id}")
async def get_item(
    item_id: int = Path(description="The item ID"),
    verbose: bool = Query(default=False),
):
    ...

@app.post("/items")
async def create(item: Item = Body(description="Item data")):
    ...

@app.get("/whoami")
async def whoami(user_agent: str = Header()):
    return {"ua": user_agent}

Background Tasks

from ylmz import BackgroundTasks

@app.post("/send-email")
async def send(background_tasks: BackgroundTasks):
    background_tasks.add_task(send_email_async, to="user@example.com")
    return {"queued": True}

Lifespan Events

@app.on_event("startup")
async def startup():
    app.state.db = await init_db()

@app.on_event("shutdown")
async def shutdown():
    await app.state.db.close()

Custom Exception Handlers

class RateLimitExceeded(Exception):
    pass

@app.exception_handler(RateLimitExceeded)
async def handle_rate_limit(request, exc):
    return JSONResponse(
        {"error": "rate_limited", "retry_after": 60},
        status_code=429,
    )

WebSocket

from ylmz import WebSocket

@app.websocket("/ws")
async def ws_endpoint(ws: WebSocket):
    await ws.accept()
    while True:
        msg = await ws.receive()
        if msg["type"] == "websocket.disconnect":
            break
        await ws.send_text(f"Echo: {msg['text']}")

Sub Routers

from ylmz import Router

admin = Router(prefix="/admin")

@admin.get("/health")
async def health():
    return {"status": "ok"}

app.include_router(admin)  # β†’ /admin/health

File Upload

from ylmz import UploadFile

@app.post("/upload")
async def upload(file: UploadFile):
    content = await file.read()
    await file.save(f"./uploads/{file.filename}")
    return {"filename": file.filename, "size": file.size}

OpenAPI Docs

from ylmz import setup_docs

app = Ylmz(title="My API")
setup_docs(app)
# Now available: /docs (Swagger) /redoc /openapi.json

Middleware & CORS

from ylmz.middleware import cors_middleware_factory

app.add_middleware(
    cors_middleware_factory(
        allow_origins=["http://localhost:3000"],
        allow_methods=["GET", "POST"],
        allow_headers=["*"],
    )
)

Status Codes

from ylmz import status
raise HTTPException(status.NOT_FOUND, "Item not found")

πŸ“ Project Structure

ylmz-python/
β”œβ”€β”€ ylmz/                    # framework source (zero mandatory deps)
β”‚   β”œβ”€β”€ app.py               # Ylmz ASGI application
β”‚   β”œβ”€β”€ routing.py           # route matching + parameter resolution
β”‚   β”œβ”€β”€ types.py             # BaseModel type system
β”‚   β”œβ”€β”€ depends.py           # dependency injection
β”‚   β”œβ”€β”€ params.py            # Path/Query/Body/Header/Cookie
β”‚   β”œβ”€β”€ response.py          # JSON/HTML/Plain/Streaming responses
β”‚   β”œβ”€β”€ request.py           # Request object
β”‚   β”œβ”€β”€ middleware.py         # middleware + CORS
β”‚   β”œβ”€β”€ background.py         # BackgroundTasks
β”‚   β”œβ”€β”€ websocket.py         # WebSocket support
β”‚   β”œβ”€β”€ uploads.py           # UploadFile
β”‚   β”œβ”€β”€ exceptions.py        # HTTPException
β”‚   β”œβ”€β”€ status.py            # named status codes
β”‚   └── openapi.py           # OpenAPI 3.0 + Swagger/ReDoc
β”œβ”€β”€ examples/
β”‚   └── basic.py             # full-featured demo app
└── tests/                   # 88 tests across 3 files

πŸ§ͺ Running Tests

PYTHONPATH=. python3 -m pytest tests/ -v

πŸ†š vs FastAPI

ylmz is designed as a from-scratch alternative to FastAPI with zero mandatory dependencies:

ylmz FastAPI
Core dependencies 0 Pydantic + Starlette
Framework source ~2000 lines ~50,000+ lines
Type validation Built-in BaseModel Pydantic
OpenAPI docs Built-in CDN-based Built-in
Startup time instant slower (heavy imports)
Python version 3.9+ 3.8+

πŸ“„ License

MIT

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages