2026-09-11 · 原文发布日
wrapture:测试与追踪两用的Python猴子补丁库
Simon Willison推荐Graham Dumpleton的新库wrapture:同一套猴子补丁机制既能像unittest.mock那样做单测替身,又能做New Relic式的调用追踪,支持按调用次数切换行为、补丁属性字典生成器、把调用录成时间线树、统计单次与聚合耗时,并可导出OpenTelemetry。亮点是零代码模式:不改Python文件,用独立TOML配置即可对Flask、Django、FastAPI、requests、sqlalchemy等一大批组件插桩,作者还配了JupyterLab互动教程,目前仍是alpha但已可用。
原文要点
Graham Dumpleton的新库wrapture用同一套猴子补丁机制同时服务单测替身(类似unittest.mock)与New Relic式调用追踪。功能包括:按调用次数切换补丁行为、补丁属性/字典/生成器、把方法调用录成时间线并处理展示为树、统计单次与跨多次调用的聚合耗时、导出OpenTelemetry。零代码模式用独立TOML文件配置即可插桩,不改Python代码;配套wrapture-instrumenation包覆盖aiohttp、django、fastapi、flask、grpc、httpx、requests、sqlalchemy、sqlite3、starlette、urllib3、uvicorn等组件。作者配有JupyterLab互动教程。库目前为alpha。
这次做成什么
做出一个低风险上手练习:不改任何业务代码,用独立TOML配置对一个Flask练习应用做调用追踪,再把同一套补丁机制用于单测替身与慢代码定位,验证wrapture‘测试+观测两用’的卖点。
准备什么
- Python 3环境,已安装wrapture(alpha版,建议在虚拟环境中安装)
- 一个用于练习的Flask小应用(可用下文示例自建,不用真实生产项目)
- 基本了解猴子补丁概念;所有练习在隔离测试项目中进行
具体怎么做
搭建练习用Flask应用
在虚拟环境中新建目录,写一个最小Flask应用:一个路由里调用一次requests请求外部接口(练习时可改为本地假接口)并查询一次sqlite3。这个应用全程不改代码,后续追踪完全靠外部配置生效,用来验证零代码模式。
用TOML配置零代码追踪
在项目里新建独立TOML配置文件,声明要插桩的目标模块(如flask路由函数、requests.request、sqlite3游标方法)和追踪输出方式。原文确认wrapture支持‘用单独TOML文件配置、完全不修改Python代码’,但TOML的具体字段写法需按作者官方教程核对,本文配置为示意结构,不要直接当作可运行语法。启动应用时按wrapture文档要求加载该配置,然后访问几次路由。
查看调用时间线与耗时
用wrapture的记录能力把方法调用整理成时间线树,观察一次请求里flask路由→requests调用→sqlite3查询的嵌套顺序;再用耗时统计功能分别看单次调用耗时和多次调用的聚合耗时,找出占比最高的环节,体验‘找慢代码’的用法。
把同一机制用作单测替身
在测试文件中用wrapture给requests.request打补丁,按调用次数切换行为:第一次返回假成功响应,第二次返回超时异常,验证业务代码的重试逻辑;再用补丁属性/字典的能力替换一个配置字典,覆盖原先要改环境才能测的分支。
可直接复制的材料
零代码追踪TOML配置(示意结构)
原文确认支持独立TOML零代码配置,但未给出字段细节;本配置为本站方案,真实字段以wrapture官方教程为准。
# 本站设计的示意结构,字段名需对照wrapture官方教程核对后再用
[[instrument]]
target = "requests.request"
action = "trace"
[[instrument]]
target = "sqlite3.Cursor.execute"
action = "trace"
[output]
format = "timeline"
timing = "aggregated"练习用Flask应用骨架
本站独立编写的练习应用,仅用于隔离环境试验追踪,不含真实凭据。
from flask import Flask
import sqlite3
app = Flask(__name__)
@app.route("/demo")
def demo():
conn = sqlite3.connect(":memory:")
cur = conn.cursor()
cur.execute("CREATE TABLE t (x INTEGER)")
cur.execute("INSERT INTO t VALUES (1)")
cur.execute("SELECT COUNT(*) FROM t")
n = cur.fetchone()[0]
return {"rows": n}
if __name__ == "__main__":
app.run(port=5001)输入与输出示例
本站虚构演示,数字为示意参考值,非实测结果,不构成本工具的性能承诺。
输入
对练习应用的/demo路由连续访问5次,然后用wrapture的聚合耗时统计查看各环节耗时占比。对应输出
聚合统计示意:demo视图函数总耗时约120ms/5次;其中sqlite3相关调用约15ms(占12%),路由框架开销约105ms(占88%)。时间线树显示每次调用均为flask路由→CREATE TABLE→INSERT→SELECT的顺序。慢点定位结论:本练习中瓶颈不在SQL。做完检查这些
- 练习应用代码零改动,追踪效果完全由外部TOML配置生效
- 时间线树能呈现一次请求内多个函数调用的先后与嵌套关系
- 耗时统计同时给出单次与多次聚合两个视角,且聚合口径与访问次数对应
- 单测中补丁按第1次、第2次调用返回了不同行为,重试分支被覆盖到
容易卡住的地方
- wrapture仍是alpha软件,API和TOML字段可能变动,升级前重读官方教程
- wrapture-instrumenation是单独包,覆盖fastapi、django、requests等组件,需单独安装核对
- 猴子补丁在并发或已导入模块上的生效时机可能踩坑,先在隔离小项目验证再推广
- 作者配的是JupyterLab互动教程,跟随练习需要本地能跑JupyterLab环境
- 本文TOML为示意结构,直接照抄字段名可能无法被alpha版识别
本站借助AI整理来源事实,独立编写中文操作指南与示例。示例不代表实际运行结果;来源效果尚未由本站独立复现。付费模板与模型、服务费用分别计算。
- 原文标题
- Graham Dumpleton's new monkey patching package wrapture is shaping up to be an indispensable tool for Python developers. I'm not sure why I'
- 原作者
- Simon Willison
- 原始发布日期
- 2026-09-11
- 来源
- https://simonwillison.net/2026/Sep/11/wrapture/