纯异步 Python Web 框架,仅依赖 Python 标准库
Project description
PystdAPI - 纯异步 Python Web 框架
PystdAPI 是一个基于 ASGI 标准的高性能异步 Web 框架,仅依赖 Python 标准库,设计简洁、易于使用且功能强大。
✨ 特性
- 🚀 纯异步:基于 Python asyncio,支持高并发处理
- 📦 零依赖:仅使用 Python 标准库,无需安装额外包
- 🏗️ 模块化设计:清晰的架构,易于扩展和维护
- 🔌 插件系统:灵活的插件机制,可扩展框架功能
- 🛡️ 中间件支持:完整的中间件系统,支持请求/响应处理
- 📝 模板引擎:内置简单模板系统,支持变量替换、条件判断和循环
- 🔧 命令行工具:提供项目创建、服务器管理等命令行功能
- 📡 ASGI 兼容:完全兼容 ASGI 3.0 标准
📦 安装
方式一:使用 pip(推荐)
pip install pystdapi
方式二:直接使用源码
# 克隆或下载源码
git clone https://gitee.com/wangweiyong/pystdapi.git
cd pystdapi
# 将 pystdapi 目录复制到你的项目中
cp -r pystdapi /path/to/your/project/
或者直接安装最新开发版:
pip install git+https://gitee.com/wangweiyong/pystdapi.git
🚀 快速开始
基础示例
创建一个简单的 Web 应用:
#!/usr/bin/env python3
from pystdapi import PystdAPI
app = PystdAPI(name="myapp", debug=True)
@app.get("/")
async def index(request):
return {"message": "Hello, PystdAPI!"}
@app.get("/hello/<name>")
async def hello(request, name):
return {"message": f"Hello, {name}!"}
@app.post("/api/data")
async def create_data(request):
data = await request.json()
return {"received": data, "status": "created"}
if __name__ == "__main__":
app.run(host="127.0.0.1", port=8000)
运行应用
python app.py
访问 http://127.0.0.1:8000 查看应用。
📚 核心概念
1. 应用对象
from pystdapi import PystdAPI, create_app
# 创建应用实例
app = PystdAPI(name="myapp", debug=True)
# 或者使用快捷函数
app = create_app(name="myapp", debug=True)
2. 路由系统
支持多种 HTTP 方法和路由参数:
# 基本路由
@app.get("/")
async def index(request):
return "首页"
@app.post("/users")
async def create_user(request):
data = await request.json()
return {"id": 1, **data}
# 路由参数
@app.get("/users/<user_id:int>")
async def get_user(request, user_id):
return {"id": user_id, "name": "Alice"}
@app.get("/files/<path:filepath>")
async def get_file(request, filepath):
return {"file": filepath}
# 路由装饰器快捷方式
@app.route("/about", method="GET")
async def about(request):
return "关于我们"
3. 请求对象
@app.post("/api/submit")
async def submit(request):
# 获取请求信息
method = request.method
path = request.path
headers = request.headers
# 获取请求体
body = await request.body() # 原始字节
text = await request.text() # 文本
json_data = await request.json() # JSON 数据
form_data = await request.form() # 表单数据
# 获取查询参数
query_param = request.query.get("page", ["1"])[0]
# 获取 Cookie
session_id = request.get_cookie("session_id")
return {"method": method, "path": path}
4. 响应对象
from pystdapi import Response, text_response, json_response, html_response, redirect_response
@app.get("/responses")
async def responses(request):
# 返回文本响应
return "Hello World"
# 返回 JSON 响应
return {"status": "ok", "data": [1, 2, 3]}
# 返回 HTML 响应
return "<h1>Hello</h1>"
# 返回自定义响应
return Response("Custom", status=201, headers={"X-Custom": "value"})
# 使用快捷函数
return text_response("Text response")
return json_response({"key": "value"})
return html_response("<h1>HTML</h1>")
return redirect_response("/new-location")
5. 中间件
from pystdapi.middleware import (
cors_middleware,
logging_middleware,
error_middleware,
static_files_middleware
)
# 添加 CORS 中间件
app.add_middleware(cors_middleware(
allow_origins=["*"],
allow_methods=["GET", "POST", "PUT", "DELETE"],
allow_headers=["*"]
))
# 添加日志中间件
app.add_middleware(logging_middleware(format="verbose"))
# 添加错误处理中间件
app.add_middleware(error_middleware(debug=True))
# 添加静态文件中间件
app.add_middleware(static_files_middleware(
directory="./static",
url_prefix="/static"
))
# 自定义中间件
async def custom_middleware(app):
async def middleware(scope, receive, send):
# 请求前处理
print(f"Request: {scope.get('method')} {scope.get('path')}")
# 调用下一个中间件或应用
await app(scope, receive, send)
# 请求后处理
print("Request completed")
return middleware
app.add_middleware(custom_middleware)
6. 插件系统
from pystdapi.plugins import (
json_plugin,
template_plugin,
session_plugin,
auth_plugin,
cors_plugin
)
# 添加 JSON 插件(自动解析 JSON 请求/响应)
app.add_plugin(json_plugin())
# 添加模板插件
from pystdapi.templates import SimpleTemplate
app.add_plugin(template_plugin(
template_adapter=SimpleTemplate,
search_path="./templates",
cache=True
))
# 使用模板
@app.get("/template")
async def template_demo(request):
return {
"template": "index.html",
"title": "页面标题",
"users": ["Alice", "Bob", "Charlie"]
}
7. 钩子函数
# 请求前钩子
@app.hook("before_request")
async def before_request_hook(request):
request.start_time = time.time()
print(f"开始处理请求: {request.method} {request.path}")
# 请求后钩子
@app.hook("after_request")
async def after_request_hook(request):
duration = time.time() - request.start_time
print(f"请求处理完成,耗时: {duration:.3f}s")
# 响应前钩子
@app.hook("before_response")
async def before_response_hook(request, response):
response.set_header("X-Response-Time", str(time.time() - request.start_time))
# 响应后钩子
@app.hook("after_response")
async def after_response_hook(request, response):
print(f"响应已发送: {response.status}")
8. 错误处理
# 自定义错误处理器
@app.error_handler(404)
async def not_found_handler(error, request):
return {"error": "页面未找到", "path": request.path}, 404
@app.error_handler(500)
async def server_error_handler(error, request):
return {"error": "服务器内部错误"}, 500
# 抛出 HTTP 错误
from pystdapi.exceptions import HTTPError
@app.get("/protected")
async def protected(request):
if not request.get_header("Authorization"):
raise HTTPError(401, "需要认证")
return {"message": "访问成功"}
🛠️ 命令行工具
PystdAPI 提供了命令行工具来简化开发流程:
# 创建新项目
pystdapi new myproject
pystdapi new myapi --template api
pystdapi new myfull --template full
# 运行开发服务器
pystdapi run
pystdapi run --port 8080 --debug --reload
# 显示版本信息
pystdapi version
项目模板
- basic: 基础项目模板
- api: API 项目模板(包含 RESTful API 示例)
- full: 完整项目模板(包含模板、静态文件等)
📁 项目结构
一个典型的 PystdAPI 项目结构:
myproject/
├── app.py # 主应用文件
├── requirements.txt # 依赖文件
├── README.md # 项目说明
├── api/ # API 模块
│ ├── __init__.py
│ └── users.py # 用户 API
├── templates/ # 模板目录
│ ├── base.html
│ └── index.html
└── static/ # 静态文件
├── css/
│ └── style.css
└── js/
└── app.js
🔌 插件开发
创建自定义插件:
from pystdapi.plugins import Plugin
class MyPlugin(Plugin):
name = 'myplugin'
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.config = kwargs
def setup(self, app):
"""插件初始化"""
app.myplugin_config = self.config
def apply(self, callback, route):
"""应用到路由"""
def wrapper(request, *args, **kwargs):
# 插件逻辑
request.plugin_data = "来自插件的数据"
return callback(request, *args, **kwargs)
return wrapper
# 使用插件
app.add_plugin(MyPlugin(key="value"))
🧪 测试
单元测试示例
由于 PystdAPI 是一个 ASGI 应用,你可以使用标准的 ASGI 测试工具进行测试:
import pytest
from pystdapi import PystdAPI
import asyncio
app = PystdAPI()
@app.get("/test")
async def test_endpoint(request):
return {"status": "ok"}
# 使用 asyncio 测试
async def test_app():
# 模拟 ASGI 请求
scope = {
"type": "http",
"method": "GET",
"path": "/test",
"headers": [],
}
# 收集响应
responses = []
async def receive():
return {"type": "http.request", "body": b"", "more_body": False}
async def send(message):
responses.append(message)
# 调用应用
await app(scope, receive, send)
# 验证响应
assert len(responses) == 2 # response.start 和 response.body
assert responses[0]["type"] == "http.response.start"
assert responses[0]["status"] == 200
assert responses[1]["type"] == "http.response.body"
# 运行测试
def test_sync():
asyncio.run(test_app())
# 或者使用 pytest-asyncio
@pytest.mark.asyncio
async def test_with_pytest():
await test_app()
使用第三方测试库
你也可以使用第三方 ASGI 测试库:
# 安装: pip install httpx
import httpx
import asyncio
from pystdapi import PystdAPI
app = PystdAPI()
@app.get("/api/test")
async def api_test(request):
return {"status": "ok", "data": [1, 2, 3]}
async def test_with_httpx():
# 启动测试服务器
import uvicorn
from uvicorn.config import Config
from uvicorn.server import Server
config = Config(app=app, host="127.0.0.1", port=8888, log_level="error")
server = Server(config=config)
# 在后台启动服务器
server_task = asyncio.create_task(server.serve())
await asyncio.sleep(0.5) # 等待服务器启动
try:
# 使用 httpx 测试
async with httpx.AsyncClient(base_url="http://127.0.0.1:8888") as client:
response = await client.get("/api/test")
assert response.status_code == 200
assert response.json() == {"status": "ok", "data": [1, 2, 3]}
finally:
# 停止服务器
server.should_exit = True
await server_task
📖 API 参考
主要类和方法
PystdAPI 类
__init__(name="pystdapi", debug=False): 初始化应用route(rule, method="GET", **options): 路由装饰器get(rule, **options): GET 路由装饰器post(rule, **options): POST 路由装饰器put(rule, **options): PUT 路由装饰器delete(rule, **options): DELETE 路由装饰器patch(rule, **options): PATCH 路由装饰器add_middleware(middleware): 添加中间件add_plugin(plugin): 添加插件hook(name): 钩子装饰器error_handler(code): 错误处理装饰器run(host="127.0.0.1", port=8000, **options): 运行服务器url_for(route_name, **kwargs): 构建 URL
Request 类
method: HTTP 方法path: 请求路径headers: 请求头query: 查询参数body(): 获取请求体(异步)text(): 获取请求体文本(异步)json(): 获取 JSON 数据(异步)form(): 获取表单数据(异步)get_header(name, default=None): 获取请求头get_cookie(name, default=None): 获取 Cookie
Response 类
__init__(body="", status=200, headers=None, **kwargs): 初始化响应text(text, status=200, **kwargs): 创建文本响应(类方法)html(html, status=200, **kwargs): 创建 HTML 响应(类方法)json(data, status=200, **kwargs): 创建 JSON 响应(类方法)redirect(url, status=302): 创建重定向响应(类方法)set_header(name, value): 设置响应头set_cookie(key, value, **options): 设置 Cookiedelete_cookie(key, **options): 删除 Cookie
🚀 部署
使用 Uvicorn
# 安装 ASGI 服务器
pip install uvicorn
# 运行应用
uvicorn app:app --host 0.0.0.0 --port 8000 --workers 4
📄 许可证
本项目采用 MIT 许可证。详见 LICENSE 文件。
🤝 贡献
欢迎提交 Issue 和 Pull Request!
- Fork 项目
- 创建功能分支 (
git checkout -b feature/amazing-feature) - 提交更改 (
git commit -m 'Add amazing feature') - 推送到分支 (
git push origin feature/amazing-feature) - 创建 Pull Request
PystdAPI - 让异步 Web 开发更简单! 🚀
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 pystdapi-0.1.0.tar.gz.
File metadata
- Download URL: pystdapi-0.1.0.tar.gz
- Upload date:
- Size: 41.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.8.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fe22dc584b44a8be9ac71d02218c1ecd321eb1d9781c26f9a4e553a216fcdc14
|
|
| MD5 |
f5a93faa8defbb0a362a805f6afa0752
|
|
| BLAKE2b-256 |
6e4e1467589d08bbcb603506caed437cf560dd82f379c8e011ba7a2b61b700be
|
File details
Details for the file pystdapi-0.1.0-py3-none-any.whl.
File metadata
- Download URL: pystdapi-0.1.0-py3-none-any.whl
- Upload date:
- Size: 42.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.8.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
24eec0105a83b219e4d641124e1c79004329a8b723fbc76c3487313d54c4fb63
|
|
| MD5 |
8886cb9820ede2cc758e85911735f5b9
|
|
| BLAKE2b-256 |
f7e90d51f413d94864ed04650d16389028a8b875645c29654f8324d873273e95
|