Грэм Дамплтон представил проект wrapture, доступный как альфа-пререлиз на PyPI. Публикация объясняет, как один механизм обёртывания реального кода применяется для monkey patching, модульного тестирования и трассировки.

wrapture оборачивает, а не подменяет вызываемый объект. Реальный код по умолчанию продолжает работать, а обёртка может наблюдать вызов, менять его или вернуть ответ вместо него.

Запись вызовов сохраняет аргументы, нормализованные по реальным сигнатурам, настоящие возвращаемые значения и фактическую вложенность вызовов. Для трассировки цели и sink можно задать в wrapture.toml без добавления кода в приложение.

Автор не позиционирует wrapture как готовый production APM или замену OpenTelemetry. Проект экспортирует данные в OpenTelemetry.

Проверка утверждений:

  • Грэм Дамплтон представил wrapture в материале типа announcement: публикация объясняет, как один механизм обёртывания реального кода используется для monkey patching, модульного тестирования и трассировки. (подтверждено первоисточником: доказательство; «That is the whole mechanism. What makes it interesting is that it serves three purposes which are usually handled by three different tools.»)
  • Основной принцип wrapture — оборачивать, а не подменять вызываемый объект: по умолчанию реальный код продолжает исполняться, а обёртка может наблюдать вызов, менять его или вернуть ответ вместо него. (подтверждено первоисточником: доказательство; «The one idea everything in wrapture sits on is to wrap rather than replace. A binding names a location in code, a method of a class or a function in a module, and when applied installs a wrapt wrapper around the real callable. Unless you tell it otherwise the wrapper is transparent. The real code runs, with wrapture in a position to watch the call, change it, or answer it instead.»)
  • Запись вызовов сохраняет нормализованные по реальным сигнатурам аргументы, настоящие возвращаемые значения и фактическую вложенность вызовов. (подтверждено первоисточником: доказательство; «That is the call graph as it actually ran. The arguments are normalised against the real signatures (so charge(500) and charge(amount=500) look the same), the return values are the real ones, and the nesting comes from what really called what.»)
  • Слой monkey patching добавляет жизненный цикл binding с apply, remove и suspend, групповое применение и сценарное изменение поведения через returns, raises и преобразования аргументов или результата. (подтверждено первоисточником: доказательство; «The first is plain monkey patching. wrapt’s wrap_object() has always been able to patch a target, but it leaves the bookkeeping to you. wrapture adds a lifecycle and a vocabulary over the top of it. A binding declares a target without touching it, apply() installs the patch, remove() restores the original, suspend() makes it inert in place, and a group of bindings applies and removes as one unit. Behaviour is configured on the binding, with returns() , raises() , transforms_args() , transforms_result() and a few others, and can be scripted to change over time, so “succeed twice, then time out” is three lines rather than a hand-written counter.»)
  • Для тестов wrapture предоставляет строгие stub() и mock(Spec), которые пишут события в общую ленту, проверяют сигнатуры и не создают атрибуты при первом обращении; опциональный pytest-плагин ищет оставшиеся активными патчи и прикладывает записи к отчётам об ошибках. (подтверждено первоисточником: доказательство; «When a test must supply a stand-in, because the code under test receives a collaborator rather than importing it, wrapture provides stub() for a callable and mock(Spec) for a whole object, and these record onto the same tape as everything else. Both are strict: signatures are checked and nothing is invented on first touch. There is deliberately no spec-less Mock() equivalent, and the comparison with unittest.mock in the documentation explains why, alongside a mapping of each mock idiom to its wrapture counterpart. An opt-in pytest plugin sweeps each test for patches left applied and attaches recordings to failure reports.»)
  • Для ad-hoc трассировки приложения, включая не подлежащее изменению или повторному развёртыванию, цели и sink можно задать в wrapture.toml без добавления кода в приложение. (подтверждено первоисточником: доказательство; «The third use is ad-hoc tracing of a running application, including one you cannot modify or redeploy. Take the bindings, drop the test around them, and the only remaining question is where the events go. A sink answers that. In practice this is done with a wrapture.toml file naming the targets and the sink, and no code at all.»)
  • Слой трассировки поддерживает вывод событий в JSON Lines, подсчёт, fan-out, sampling и filtering, а расширение wrapture[otel] экспортирует события в OTLP как spans, metrics и коррелированные logs; W3C trace id и traceparent позволяют объединить наблюдаемые сервисы в распределённую трассу. (подтверждено первоисточником: доказательство; «The printer is the simplest sink. Others stream events to disk as JSON lines, count without retaining, and compose with fan-out, sampling and filtering. Sitting on top of the tracing layer is OpenTelemetry export : with the wrapture[otel] extra installed, one [otel] table in the config sends the same events to any OTLP backend as spans, metrics and correlated logs. Every tree of events carries a W3C trace id, and the id arrives and leaves in traceparent headers, so two services both observed by wrapture join up as one distributed trace without either of them calling an OpenTelemetry API.»)
  • Автор ограничивает позиционирование проекта: wrapture не заменяет инструменты для выдуманных объектов, не является готовым production APM и экспортирует данные в OpenTelemetry, а не конкурирует с ним. (подтверждено первоисточником: доказательство; «It is not a fabrication tool, and unittest.mock remains the right thing for invented objects. It is not a production APM, although it is a toolkit that APM-like things could be built on. And it is not an OpenTelemetry competitor; it emits to OpenTelemetry rather than trying to replace it.»)
  • Сопутствующий пакет wrapture-instrumentation содержит готовую инструментацию для Flask и Jinja2; она включается записью [[instrument]] в wrapture.toml, а отсутствующие в окружении пакеты остаются неактивными. (подтверждено первоисточником: доказательство; «The companion wrapture-instrumentation package provides ready-made instrumentation, with Flask and Jinja2 covered so far. Each records a request or a template render as one structured tree, and enabling one is an [[instrument]] entry in wrapture.toml naming the target. Installing the package brings in wrapture and nothing else; the instrumentation for a package you do not have is inert.»)
  • По словам Дамплтона, весь код и документацию wrapture написал ИИ-ассистент под его руководством, тогда как он задавал направление, принимал архитектурные решения и рецензировал результат. (подтверждено первоисточником: доказательство; «Throughout, the division of labour was consistent. The AI wrote the code, the tests and the prose. I set the direction, made the design calls, reviewed what came back, and sent plenty of it back.»)
  • Разработка от первого коммита до одиннадцатой alpha-версии заняла чуть больше двух недель; за это время проект набрал более 1000 тестов и более 150 страниц документации. (подтверждено первоисточником: доказательство; «The first commit was in the middle of August and the current release is the eleventh alpha, so this all happened in a bit over two weeks. In that time it accumulated over 1000 tests and over 150 pages of documentation.»)
  • wrapture распространяется как alpha-пререлиз на PyPI, требует Python 3.12+ и wrapt 2.4.0+, а API для трёх описанных сценариев автор считает завершённым и не ожидает его поломки до 1.0.0. (подтверждено первоисточником: доказательство; «wrapture is in alpha, with pre-releases on PyPI . Until 1.0.0 is final a plain pip install wrapture picks up the latest pre-release, so there is no need to pin a version. It requires Python 3.12 or later and wrapt 2.4.0 or later. The API is complete for the three uses described above and I am not expecting it to break, so code written against it today should carry forward to 1.0.0.»)

Первоисточники:

оценка 58.6 · тип announcement · ревизия 1 · истории st-1ml11i8