Files
paste-framework/docs/manual.md
T
2026-06-02 17:15:32 +08:00

16 KiB
Raw Blame History

┌─────────────────────────────────────────────────┐
│                                                 │
│     ██████╗  █████╗ ███████╗████████╗███████╗   │
│     ██╔══██╗██╔══██╗██╔════╝╚══██╔══╝██╔════╝   │
│     ██████╔╝███████║███████╗   ██║   █████╗     │
│     ██╔═══╝ ██╔══██║╚════██║   ██║   ██╔══╝     │
│     ██║     ██║  ██║███████║   ██║   ███████╗   │
│     ╚═╝     ╚═╝  ╚═╝╚══════╝   ╚═╝   ╚══════╝   │
│                                                 │
│      Python Api-first Scalable Task Engine      │
│                                                 │
└─────────────────────────────────────────────────┘

📘 PASTE 框架使用手册 v2.0.1

副本信息 文件:docs/PASTE框架使用手册.html 最后更新:2025-04-08 对应框架版本:2.0.1


一、框架概述

PASTE —— Python Api-first Scalable Task Engine

PASTE 是一个基于 Tornado 的生产级 Python 轻量框架,提供:

特性 说明
自动路由加载 定义 route_pattern = "/user" 即可自动注册 API,无需手动配置路由
RBAC 权限控制 动态规则引擎,规则以序列化类存储于数据库,支持时间/IP/自定义规则链
Swagger 自动生成 /docs 自动输出 Swagger UI,无需手写 YAML
异步任务池(带背压) run_background_task(coro) 安全管理并发任务,支持任务队列上限
JWT 无状态认证 集成 Token 签发/验证/刷新,@auth_token 装饰器一行开启
Redis Stream 消息队列 StreamActor 支持消费者组、消息 ACK、僵尸任务自动恢复
雪花 ID 生成器 内嵌线程安全实现,无需外部依赖,单机 1 万+ ID/秒
配置系统 点号路径风格:get_config("db.engine.engine"),单文件配置
工具库 字符串/字典/文件/分页/编码器/BaseX 编解码/图表/PDF/SVG/Excel

二、目录结构说明

paste-project/
│
├── paste/                       # 框架核心(禁止修改!)
│   ├── core/                    #   基础设施层
│   │   ├── config.py            #     点号路径配置加载器
│   │   ├── logging.py           #     日志系统(RotatingFile + 控制台)
│   │   └── aio_pool.py          #     异步任务池 + 背压
│   ├── db/                      #   数据库层
│   │   ├── engine.py            #     SQLAlchemy 引擎工厂
│   │   ├── redis.py             #     Redis 连接 + StreamActor
│   │   ├── basemodel.py         #     异步 ORM 基类
│   │   ├── basetable.py         #     表反射工具
│   │   ├── baseadapter.py       #     结果集适配器
│   │   └── gen_models.py        #     自动生成模型类
│   ├── web/                     #   Web 层
│   │   ├── application.py       #     Application(自动装载 Handler
│   │   ├── handler.py           #     RequestHandler 基类
│   │   ├── decorators.py        #     @route / @auth_token / @auth_permission
│   │   ├── swagger.py           #     Swagger UI 自动生成
│   │   ├── form.py              #     WTForms 集成
│   │   ├── param_aware_loader.py #    异步 UIModule 数据预加载
│   │   └── websocket.py         #     WebSocket 支持
│   ├── rbac/                    #   访问控制层
│   │   ├── rbac_user.py         #     用户类(权限继承)
│   │   ├── rbac_role.py         #     角色管理
│   │   ├── rbac_rule.py         #     规则引擎
│   │   ├── rbac_item.py         #     权限项层次结构
│   │   ├── rbac_assignment.py   #     用户-项分配
│   │   └── rbac_permission.py   #     权限查询
│   ├── security/                #   安全层
│   │   ├── token.py             #     JWT 编解码
│   │   └── shash.py             #     PBKDF2 密码哈希
│   ├── service/                 #   服务层
│   │   ├── server.py            #     进程管理
│   │   ├── daemonize.py         #     Unix 守护进程 + PID 文件
│   │   └── task_service.py      #     定时任务调度器
│   ├── chart/                   #   图表生成(可选依赖)
│   │   ├── bar.py / pie.py / line.py
│   ├── util/                    #   工具库
│   │   ├── ustr.py / udict.py / ufile.py
│   │   ├── pagination.py / snow_id.py / encoder.py
│   │   └── pdf.py / svg.py / xlsx.py
│
├── examples/                    # 即开即用的示例代码
│   ├── 01_hello_world/          #   最小化 Web 应用
│   ├── 02_background_task/      #   后台异步任务
│   ├── 03_redis_stream/         #   Redis Stream 发布/消费
│   ├── 04_tasks_service/        #   定时任务服务
│   └── 05_gen_models/           #   自动生成数据库模型
│
├── tests/                       # 测试套件
│   ├── unit/                    #   单元测试(Mock 模式)
│   └── integration/             #   集成测试(需数据库/Redis
│
├── pyproject.toml               # 项目元数据和依赖
├── README.md                    # 英文文档
├── CHANGELOG.md                 # 变更日志
├── CONTRIBUTING.md              # 贡献指南
├── LICENSE                      # MIT 许可证
└── .github/workflows/ci.yml     # CI 流水线

三、快速开始

3.1 安装

git clone https://github.com/wayne-zwf/paste.git
cd paste
pip install -e .

3.2 运行 HelloWorld 示例

cd examples/01_hello_world
python main.py

打开浏览器访问 http://localhost:9000/hello

3.3 创建新项目

建议的目录模版:

myapp/
├── main.py                 # 入口
├── config.json             # 配置
├── apps/                   # Handler 层
│   ├── __init__.py
│   ├── handler_user.py
│   └── handler_product.py
├── models/                 # 数据模型
│   └── db_models.py
└── service/                # 业务服务
    ├── __init__.py
    └── task_service.py

四、核心模块详解

4.1 配置系统 paste.core.config

所有配置集中在 config.json,通过点号路径读取:

from paste.core import config

db_url = config.get_config("db.engine.engine")
port = config.get_config("tornado.demo.port", 9000)  # 带默认值

配置结构:

{
  "tornado": {
    ...
  },
  "db": {
    "engine": {
      ...
    }
  },
  "redis": {
    "connection": "...",
    "streams": {
      ...
    }
  },
  "rbac": {
    "user_class": "...",
    "table": {
      ...
    }
  },
  "logger": {
    "default": {
      "basic": {
        ...
      }
    }
  }
}

4.2 自动路由装载 paste.web.application

Handler 只需定义 route_pattern,框架自动扫描注册:

# handler.py —— 无需手动添加路由
from paste.web.decorators import route
from paste.web.handler import RequestHandler


@route("/users")
class UserHandler(RequestHandler):
    async def get(self):
        self.response_ok(users=await get_all_users())
# main.py —— 自动装载处理器
from paste.web.application import Application

app = Application(
  handlers_pkg="apps",  # ← 自动扫描 apps 包下的所有 Handler
  **config.get_config("tornado.demo", {})
)

4.3 RBAC 权限系统 paste.rbac

三层架构:用户 → 角色 → 权限(规则)

# 1. 创建用户
await RbacUser.create(username="alice", password="secure123")

# 2. 分配权限
user = await RbacUser.find_by_username("alice")
await user.assign({"view_reports", "edit_profile"})

# 3. 自定义规则(以序列化类存储于数据库)
from paste.rbac.rbac_rule import RbacRule


class BusinessHoursRule(RbacRule):
    async def run(self, **kwargs) -> bool:
        hour = datetime.now().hour
        return 9 <= hour < 18

在 Handler 中一行开启:

@route("/admin/reports")
class ReportHandler(RequestHandler):
    @auth_token
    @auth_permission
    async def get(self):
        ...

4.4 Swagger 自动生成

使用 ApplicationSwagger 替代 Application

from paste.web.application import ApplicationSwagger

app = ApplicationSwagger(
    handlers_pkg="apps",
    swagger_title="My API",
    swagger_description="My API Description",
    swagger_api_version="1.0.0",
    **settings
)

访问 http://localhost:9000/docs 即可看到交互式 API 文档。

4.5 Redis StreamActor paste.db.redis

from paste.db.redis import StreamActor

# 创建执行器(从配置读取)
actor = StreamActor.new_actor("redis.streams.user_event")

# 发布消息
msg_id = await actor.publish({"user_id": "123", "event": "login"})


# 消费消息(阻塞式)
async def handler(data: dict):
    print(f"处理消息: {data}")
    return True  # ACK


await actor.run_forever(func=handler, is_delete=True)

4.6 任务池 + 背压 paste.core.aio_pool

from paste.core.logging import echo_log
from paste.core.aio_pool import run_background_task


async def heavy_task(data):
    result = await process(data)
    echo_log(f"任务完成: {result}")


# 提交任务(队列满时自动阻塞)
await run_background_task(heavy_task(some_data))

4.7 定时任务服务 paste.service.task_service

from paste.service.task_service import TaskService

ts = TaskService(service_name="数据同步服务", pid_file="/var/run/sync.pid")
ts.add_task(
    creator=ts.create_delay_task(),
    fn=sync_data,
    delay=300  # 每 5 分钟执行一次
)
ts.start_service()  # 控制台模式
# 或 ts.start()    # 守护进程模式

五、范例速查表

示例 路径 学习重点
HelloWorld examples/01_hello_world 最小化应用、自动路由、response_ok()
后台任务 examples/02_background_task aio_pool、后台协程、日志输出
Redis Stream examples/03_redis_stream StreamActor、发布/订阅、消息 ACK
定时任务 examples/04_tasks_service TaskService、守护进程、PID 管理
模型生成 examples/05_gen_models gen_models、表反射、自动生成 ORM

六、测试指南

# 安装测试依赖
pip install -e ".[test]"

# 运行单元测试(纯 Mock,无需外部服务)
pytest tests/unit -v

# 运行集成测试(需 MySQL + Redis
pytest tests/integration -v

# 全量测试 + 覆盖率报告
pytest --cov=paste --cov-report=term-missing

集成测试需要配置环境变量或 config.json

export PASTE_DB_URL="mysql+pymysql://root:pass@localhost:3306/paste_test"
export PASTE_REDIS_URL="redis://localhost:6379/15"

七、语义版本号规则

本项目遵循 SemVer 2.0

  • 主版本号 — 不兼容的 API 修改
  • 次版本号 — 向下兼容的功能新增(如新的 Handler 装饰器、新的 Stream 功能)
  • 修订号 — 向下兼容的问题修复(如 bug fix、性能优化)

八、发布检查清单

在推送至 GitHub 公开发布前,请确认以下事项:

  • README.md 中的徽章 URL、仓库地址已替换为真实值
  • pyproject.tomlauthorsHomepageRepository 已填写真实信息
  • CHANGELOG.md 已根据实际变更更新
  • .gitignore 已添加 !examples/*/config.json 放行示例配置
  • git 仓库已清理:bash clean_pycache.sh
  • .github/workflows/ci.yml 已完善(含 checkout、test、lint 步骤)
  • 单元测试全部通过:pytest tests/unit -v
  • 集成测试已通过(如有外部服务)
  • 所有示例至少手动运行一次验证
  • LICENSE 文件存在且内容正确

九、附录:常见问题

Q: 为什么我的 Handler 没有被自动装载? A: 检查三点:① 类上有 @route(...) 装饰器;② 类继承自 RequestHandler;③ main.pyApplication(handlers_pkg="你的包名") 的包名正确。

Q: 如何关闭 Swagger A: 使用 Application 而非 ApplicationSwagger,或不传 swagger_* 参数。

Q: RBAC 规则如何持久化? A: 规则类以 pickle 序列化后存入数据库 rbac_rule 表。建议仅内部使用,对外 API 应使用 JSON + 白名单方式。

Q: 如何扩展用户模型? A: 继承 RbacUser 并添加自定义字段;然后在 config.json 中通过 rbac.user_class 指向你的自定义类。

Q: 日志文件在哪里? A: 默认在 logs/ 目录下,文件名和格式由 config.jsonlogger.default.basic 配置控制。

Q: 为什么我的配置读取失败? A: 确保项目根目录存在 config.json 文件,且该文件未被 .gitignore 排除。使用 config.get_config("路径.字段", 默认值) 时可以设置安全默认值。


十、附录:示例配置文件参考(config.json 模版)

{
  "tornado": {
    "demo": {
      "autoreload": false,
      "handlers_pkg": "apps.demo",
      "port": 9000,
      "static_path": "static",
      "template_path": "templates",
      "swagger_title": "My API",
      "swagger_description": "My API Description",
      "swagger_api_version": "1.0.0",
      "swagger_contact": "admin@example.com"
    }
  },
  "db": {
    "engine": {
      "engine": "mysql+pymysql://root:password@localhost:3306/mydb",
      "async_engine": "mysql+aiomysql://root:password@localhost:3306/mydb",
      "engine_option": {
        "echo": false,
        "pool_size": 10,
        "pool_recycle": 3600
      }
    }
  },
  "redis": {
    "connection": "redis://localhost:6379/0",
    "streams": {
      "user_event": {
        "group": "user_event_group",
        "consumer": "processor_01"
      }
    }
  },
  "rbac": {
    "user_class": "myapp.models.MyRbacUser",
    "table": {
      "rule": "rbac_rule",
      "user": "rbac_user",
      "item": "rbac_item",
      "assignment": "rbac_assignment",
      "item_child": "rbac_item_child"
    }
  },
  "logger": {
    "default": {
      "basic": {
        "filename": "logs/app.log",
        "format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s",
        "level": 20
      },
      "name": "MyApp",
      "max_bytes": 10485760,
      "backup_count": 5
    },
    "task": {
      "basic": {
        "filename": "logs/task.log",
        "format": "%(asctime)s - %(levelname)s - %(message)s",
        "level": 20
      },
      "name": "TaskService",
      "filename": "logs/task_service.log",
      "max_bytes": 10485760,
      "backup_count": 3
    }
  }
}