A pythonic web framework
Project description
lessweb
Lessweb is a ready-to-use, production-grade Python web framework with the following goals:
- Ready-to-use: Easily parse configuration files, set up logging with ease, and dynamically override configuration items using environ variables.
- Production-grade: Built on the aiohttp ecosystem and boasting powerful IOC capabilities.
- Pythonic: Supports the latest Python versions and syntax.
📦 Installation
To install the latest version of lessweb for Python ≥ 3.10, run:
pip install lessweb
Dependencies
⚡ Quick Start Example
Save the following to main.py:
from typing import Annotated
from lessweb import Bridge
from lessweb.annotation import Get
async def hello(*, who: str = 'world') -> Annotated[dict, Get('/')]:
return {'message': f'Hello, {who}!'}
def main():
bridge = Bridge()
bridge.scan(hello)
bridge.run_app()
if __name__ == '__main__':
main()
Run your app:
python main.py
Now open your browser at http://localhost:8080
Output:
{"message": "Hello, world!"}
Or try http://127.0.0.1:8080?who=John:
{"message": "Hello, John!"}
📚 Official Documentation
- Quick Start: https://lessweb.castdict.com/quickstart/
- IOC / Dependency Injection: https://lessweb.castdict.com/ioc/
- Reference Manual: https://lessweb.castdict.com/reference/
📘 Lessweb Framework Guide
Below is a summarized version of the Quick Start and IOC (Dependency Injection) documentation.
🧭 Endpoint Basics
An endpoint in lessweb is an async function bound to a specific HTTP route (URL). Endpoints can automatically receive parameters from query strings, path variables, or the request body.
Example:
from typing import Annotated
from aiohttp.web import Request
from lessweb import Bridge
from lessweb.annotation import Get, Post
async def get_pet_detail(request: Request) -> Annotated[dict, Get('/pet/{pet_id}')]:
return {'pet_id': request.match_info['pet_id']}
async def create_pet(request: Request) -> Annotated[dict, Post('/pet')]:
pet = await request.json()
return pet
if __name__ == '__main__':
bridge = Bridge()
bridge.scan(get_pet_detail, create_pet)
bridge.run_app()
You can also scan an entire package:
bridge.scan('myapp.endpoint')
Dynamic Path Parameters
Supports regex-based path matching:
async def get_pet_detail(request: Request) -> Annotated[dict, Get('/pet/{pet_id:[0-9]+}')]:
...
🧩 Request Parameter Injection
Lessweb automatically injects request data into endpoint parameters:
- keyword-only parameters (
*, name: str) → path/query parameters - positional-only parameters (
data: Model, /) → JSON body - normal parameters (
request: Request) → context objects or services
Example:
from pydantic import BaseModel
from lessweb.annotation import Get, Post
from typing import Annotated
class Pet(BaseModel):
pet_id: int
name: str
async def get_pet_detail(*, pet_id: int) -> Annotated[dict, Get('/pet/{pet_id}')]:
return {'pet_id': pet_id}
async def create_pet(pet: Pet, /) -> Annotated[dict, Post('/pet')]:
return pet
Supported types include:
str,int,float,bool,listdatetime,date,timeenum,Literal,Union,NewTypepydantic.BaseModel
💡 JSON Responses
Endpoints can directly return JSON-compatible data:
async def get_pet_list() -> Annotated[dict, Get('/pet')]:
return [{'pet_id': 1, 'name': 'Kitty'}]
Or use helper functions for advanced responses:
from lessweb import rest_response, rest_error
from aiohttp.web import HTTPBadRequest
async def get_pet_list() -> Annotated[dict, Get('/pet')]:
return rest_response([{'name': 'Kitty'}], headers={'X-TOKEN': 'abc123'})
async def bad_request() -> Annotated[dict, Get('/error')]:
raise rest_error(HTTPBadRequest, {'code': -1, 'message': 'Invalid request'})
⚙️ JSON Serialization
Based on orjson with support for:
- dataclasses
- datetime / date / time (RFC 3339)
- enum
- numpy types
- uuid
- pydantic models
Configurable in config.toml:
[lessweb]
orjson_option = 'APPEND_NEWLINE,INDENT_2,UTC_Z'
🧠 Dependency Injection (IOC)
Lessweb’s IOC system auto-injects dependencies based on parameter types, similar to Spring Boot.
Lifecycle Levels
| Type | Scope | Description |
|---|---|---|
| Module | Process-level singleton | e.g. DB connection pool |
| Middleware | Request-level wrapper | Pre/post processing |
| Service | Request-level singleton | Business logic |
| Bean | Request-level factory result | Complex object creation |
Example: Modules
class Mysql(Module):
async def on_startup(self, app):
self.pool = await aiomysql.create_pool(...)
class RedisModule(Module):
async def on_startup(self, app):
self.redis_client = redis.Redis(...)
Example: Middleware
class MysqlConn(Middleware):
def __init__(self, mysql: Mysql):
self.mysql = mysql
async def on_request(self, request, handler):
async with self.mysql.pool.acquire() as conn:
self.conn = conn
return await handler(request)
Example: Services and Beans
class TaskService(Service):
def __init__(self, dao: Commondao, redis: redis.Redis):
self.dao = dao
self.redis = redis
def commondao_bean(mysqlConn: MysqlConn) -> Commondao:
return Commondao(mysqlConn.conn, mysqlConn.cur)
def redis_bean(redis_module: RedisModule) -> redis.Redis:
return redis_module.redis_client
Register all in main.py:
def main():
bridge = Bridge()
bridge.beans(commondao_bean, redis_bean)
bridge.middlewares(MysqlConn)
bridge.scan('src')
bridge.run_app()
✅ Best Practices
- Use Middleware for request pre/post hooks (e.g. auth, logging)
- Use Service for business logic
- Keep Module dependencies only between other Modules
- Let Beans create reusable request-scoped objects
📄 License
Lessweb is offered under the Apache 2.0 License.
🧭 Source Code
GitHub Repository: 👉 https://github.com/lessweb/lessweb
Project details
Release history Release notifications | RSS feed
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 lessweb-2.2.0.tar.gz.
File metadata
- Download URL: lessweb-2.2.0.tar.gz
- Upload date:
- Size: 47.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.11.8
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1bff733630e4f5186659bab59d66466eeefd53511cc2ff495f75e19c2774686d
|
|
| MD5 |
e2ff0fabdf4630915fbde5c1dd1e3a46
|
|
| BLAKE2b-256 |
d6d9f78a80d32f6a23df0a6cf4d9359e2ae6f7882e3f6cd4701287422961a344
|
File details
Details for the file lessweb-2.2.0-py3-none-any.whl.
File metadata
- Download URL: lessweb-2.2.0-py3-none-any.whl
- Upload date:
- Size: 22.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.11.8
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a04c937cb5590b1817fc0dc57ce30589bad75fe2d5b1fbc0ec261da078d78aa7
|
|
| MD5 |
c7f296fd24c018fdafddfaff8df024dd
|
|
| BLAKE2b-256 |
65097661e29330b29e98b74c479e1c750a082550e1fa40fb12dd529915787ae1
|