← 文章 / 编程开发
Simon Willison 3小时前 · 2026-09-01 15:39:59 · 2 阅读

介绍 Wrapture:面向测试与追踪的 Python 包装工具

Introducing wrapture。Graham Dumpleton 的新项目。他因开发 wrapt、mod_wsgi 以及 New Relic 的 Python agent 而知名。他介绍说,Wrapture 借鉴了 wrapt 的 monkeypatch 思路,并将其扩展到测试和 tracing 场景。

Wrapture(完整文档)可以轻松包装任意函数或方法,从而追踪所有访问,或将其重写为返回其他值。

它既可以作为 unittest.mock 的替代方案,也可以用于为现有项目实现 tracing:

如何在不干扰被观察程序的前提下,为自己无法控制的代码附加观测能力,并记录其中流转的数据,这是我一直在思考的问题。

Wrapture 支持 OpenTelemetry,甚至提供了完全基于配置的机制,可以为现有 Python 项目添加 tracing,配置如下:

capture = "summary"

[[observe]]
target = "domain:Calculator"
name = ["outer", "inner"]

[[sink]]
type = "jsonlines"
path = "trace.jsonl"

这个项目还非常年轻——诞生至今只有几周——但开局相当亮眼。

有意思的是,这也是 Graham 首次尝试完全由 agent 驱动的大型项目:

Wrapture 中的每一行代码和文档,都是 AI assistant 在我的指导下完成的。我想坦率说明这一点,也同样想明确它不是什么。这不是所谓的 vibe coding:不是靠一次性提示词生成一堆代码,再因为缺乏判断能力而只能听天由命。Vibe coding 落得坏名声并非没有原因。从一开始,我就对 Wrapture 进行了精心设计。我在 Python 的这个领域深耕已久,非常清楚最终成果应当是什么样;AI 只是实现设计的工具,而不是设计的来源。

在后续文章 Unit testing with wrapture 中,Graham 展示了这个新库支持的测试模式:

def test_stub_with_wrapture():
    with wrapture.binding(
        Gateway, "charge"
    ).on_call.returns({
        "id": "stub", "amount": 0}
    ):
        assert OrderService().place(
            500
        )["id"] == "stub"

下面这个例子也很简洁:先调用原方法,再修改它的返回值:

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(...)。)

原始来源: Simon Willison

评论 (0)