Wrapture 扩展 Python 猴子补丁
Simon Willison··作者 Simon Willison
关键信息
该库在某些测试场景下可作为 unittest.mock 的替代方案,并且支持 OpenTelemetry 导出。Dumpleton 说这个项目还很年轻,只有几周时间,同时还提供一种基于配置的追踪方式,可以针对特定类和方法进行观察。
资讯摘要
Graham Dumpleton 发布了 Wrapture,这是一个新的 Python 库,它把 wrapt 背后的猴子补丁思路进一步扩展,同时用于测试和链路追踪。Dumpleton 因 wrapt、mod_wsgi 以及 New Relic 的 Python agent 而广为人知。文章介绍说,Wrapture 可以包装任意函数或方法,从而让调用被追踪,或者被覆盖为返回不同的值。这个项目既可用于观察你并不控制的代码,也可以在某些测试场景下替代 unittest.mock。文章还强调了它对 OpenTelemetry 的支持,以及一种完全基于配置的方式,可以把追踪加入到现有的 Python 项目中。
示例配置使用 TOML 选择 Calculator 目标,指定要观察的方法名,并把追踪结果写入 JSON Lines 输出。Dumpleton 表示,这个项目只有几周大,但起步非常不错。与此同时,他也坦率说明,Wrapture 的代码和文档全部是在 AI 助手协助下完成的,但设计仍由他自己主导,而不是所谓的一键式“vibe coding”。后续文章还展示了测试用法,例如用 Wrapture 让 Gateway.charge 返回一个假的结果对象,从而在 OrderService 的测试中进行断言。
资讯正文
<p><strong><a href="https://grahamdumpleton.me/posts/2026/08/introducing-wrapture/">介绍 wrapture</a></strong></p>
来自 Graham Dumpleton 的新作——他因 wrapt、mod_wsgi 和 New Relic 的 Python agent 而为人熟知——他将 Wrapture 描述为把 wrapt 里的猴子补丁(monkeypatching)思路扩展到同时适用于测试和追踪。</p>
<p>Wrapture(<a href="https://wrapture.readthedocs.io/">完整文档在此</a>)可以轻松地包装任何函数或方法,使得所有访问都可以被追踪,或者被覆盖以返回不同的值。</p>
<p>它既可以作为 <code>unittest.mock</code> 的替代方案,也可以作为在现有项目上实现追踪的一种方式:</p>
<blockquote>
<p>把观测附加到你无法控制的代码上,记录流经其中的内容,并且在不干扰被观察程序的情况下做到这一点,这个问题我从未真正停止思考。</p>
</blockquote>
<p>Wrapture 包含 <a href="https://wrapture.readthedocs.io/en/latest/otel-export.html">OpenTelemetry 支持</a>,甚至还有一种完全基于配置的机制,可以为现有 Python 项目添加追踪,看起来像这样:</p>
<div class="highlight highlight-source-toml"><pre><span class="pl-smi">capture</span> = <span class="pl-s"><span class="pl-pds">"</span>summary<span class="pl-pds">"</span></span>
[[<span class="pl-en">observe</span>]]
<span class="pl-smi">target</span> = <span class="pl-s"><span class="pl-pds">"</span>domain:Calculator<span class="pl-pds">"</span></span>
<span class="pl-smi">name</span> = [<span class="pl-s"><span class="pl-pds">"</span>outer<span class="pl-pds">"</span></span>, <span class="pl-s"><span class="pl-pds">"</span>inner<span class="pl-pds">"</span></span>]
[[<span class="pl-en">sink</span>]]
<span class="pl-smi">type</span> = <span class="pl-s"><span class="pl-pds">"</span>jsonlines<span class="pl-pds">"</span></span>
<span class="pl-smi">path</span> = <span class="pl-s"><span class="pl-pds">"</span>trace.jsonl<span class="pl-pds">"</span></span></pre></div>
<p>这仍然是一个非常年轻的项目——只有几周大——但它开局非常有前景。</p>
<p>有意思的是,这也是 Graham 第一次尝试大规模、完全由 agent 驱动的项目:</p>
<blockquote>
<p>wrapture 中的每一行代码和文档,都是由一位在我指导下工作的 AI 助手写成的。我想对此直言不讳,也同样想明确说明它不是什么。这不是 vibe coding,不是用一次性提示词生成一大堆代码,然后驱动者因为缺乏判断返回结果的知识而只能祈祷一切顺利。vibe coding 确实配得上它糟糕的名声。我从一开始就认真地设计了 wrapture。我在 Python 的这个特定领域已经深耕很久,清楚地知道结果需要是什么样子,而 AI 只是实现它的手段,而不是设计的来源。</p>
</blockquote>
在一篇后续文章《使用 wrapture 进行单元测试》中,Graham 展示了这款新库支持的测试模式:
```python
def test_stub_with_wrapture():
with wrapture.binding(
Gateway, "charge"
).on_call.returns({
"id": "stub", "amount": 0})
assert OrderService().place(
500
)["id"] == "stub"
```
以及这个巧妙的测试示例:它会调用原始方法,然后修改其返回值:
```python
def test_pinned_result_with_wrapture():
charge = wrapture.binding(
Gateway, "charge"
charge.on_call.transforms_result(
lambda r: {**r, "id": "ch_TEST"}
with charge:
assert OrderService().place(
500
) == {
"id": "ch_TEST", "amount": 500
}
```
(在这两个示例中,`OrderService().place(...)` 方法都会调用 `Gateway().charge(...)`。)
来源与参考
收录于 2026-09-02