サンプル
wrapt 2.2.2: Invoke wrapt universal decorators and monkey-patch wrappers with 4-arg signatures without double-binding instance or decorating patch hooks
検証済みサンプル — pypi wrapt 2.2.2: Invoke wrapt universal decorators and monkey-patch wrappers with 4-arg signatures without double-binding instance or decorating…
sha256:7a13d82fc8fc99b353d10c003fde6ab931c335ba8d42b8cf245f5a18f4524a1d
このネットワークが提供するのは一つだけです。ビルドされるサンプル。サンドボックスで実行し、署名済みの受領証を保管します。等級はつけず、何も保証しません — 同じコードがあなたの環境でビルドされるかは測定していません。
合格した契約受領証を提出した異なる署名鍵の数です。1 なら作者だけ、2 以上なら他の誰かもビルドしています。鍵は自己生成で背後に登録された身元がないため、数えているのは人ではなく鍵です。
MIT-0
実行証拠
宣言された環境と署名済みの実行を分けてあります。このサンプルが何をどこで実行したかをそのまま確認できます。
- 証拠の基準
- 署名済みコントラクト合格
- 検証レシート
- 3
- ビルドした署名鍵
- 3
宣言された環境
python linux x64 python python pip
検証実行環境
| 環境 | コントラクト | ステージ | 実行日 |
|---|---|---|---|
| python 3.12 · linux alpine/x64 · docker ed25519:d91480838ac982c9 | PASS | compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS CONTAINER_RUN · python@1 |
2026-08-16 |
| python 3.12 · linux alpine/x64 · docker ed25519:2175b912ea1c23b1 | PASS | compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS CONTAINER_RUN · python@1 |
2026-08-18 |
| python 3.12 · linux debian/x64 · docker ed25519:c1973797be207ac4 | PASS | compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS CONTAINER_RUN · python@1python:3.12-slim@sha256:09f7da3bc104… |
2026-09-08 |
ケース
HOW- ゴール
- Invoke wrapt universal decorators and monkey-patch wrappers with 4-arg signatures without double-binding instance or decorating patch hooks
- パッケージ
- シンボル
-
- wrapt.decorator
- wrapt.wrap_function_wrapper
- wrapt.adapter_factory
- wrapt.FunctionWrapper
- 環境
- python
- 作成日
- 2026-08-16T07:09:19Z
コントラクト
- assert wrapt decorator passes instance separately and strips self or cls from positional args
- assert wrapped is already bound so passing instance to wrapped(*args) raises TypeError
- assert passing a @wrapt.decorator function to wrap_function_wrapper silently returns FunctionWrapper instead of the target return value
- assert @wrapt.decorator rejects custom decorator keyword arguments and requires an outer factory function
- assert enabled=False returns the unwrapped function while enabled=callable dynamically evaluates per invocation
- assert @wrapt.adapter_factory customizes inspect.signature without changing underlying wrapper execution
ファイル
- NOTES.md
- csx.json
- requirements.txt
- src/__init__.py
- src/decorators.py
- test/contract.py
ソース
# Notes on wrapt Universal Decorator & Monkey-Patching Contracts
## Existing CSX Solutions Found
`search_known_solution` returned sample `sha256:61d02a30076981ae851aad530bd2d9dbce05537be4411337993c75500740cdd6` ("Subclass the right object proxy base in wrapt 2.x so iteration works"), which focuses on `BaseObjectProxy` vs `ObjectProxy` dunder iteration changes in wrapt 2.x.
We selected a different core area: the `@wrapt.decorator` 4-argument signature protocol `(wrapped, instance, args, kwargs)`, instance pre-binding, monkey-patching hooks in `wrapt.wrap_function_wrapper`, custom decorator argument factories, and signature adaptation.
## What a Competent Model Would Have Written Instead
- Competent models reaching for `@wrapt.decorator` often inspect `instance` and write `if instance: return wrapped(instance, *args, **kwargs)` (or assume `args[0]` contains `self`), apply `@wrapt.decorator` to the `wrapper` argument of `wrapt.wrap_function_wrapper`, or pass custom configuration directly as keyword arguments to `@wrapt.decorator(prefix=...)`.
## Failure Mode (Loud vs Silent)
- Double-passing `instance` to `wrapped(instance, *args, **kwargs)` fails loudly with `TypeError: ... takes N positional arguments but N+1 were given`, whereas applying `@wrapt.decorator` to a `wrap_function_wrapper` hook fails silently with a green build because calling the patched method returns a `wrapt.FunctionWrapper` instance (truthy in boolean checks) rather than executing the target function and returning its value.
{"case":{"caseId":"case:sha256:146f1ea397de419787dfe056ff9075ad18639932f410ab1b7361a80618d195e7","contract":["assert wrapt decorator passes instance separately and strips self or cls from positional args","assert wrapped is already bound so passing instance to wrapped(*args) raises TypeError","assert passing a @wrapt.decorator function to wrap_function_wrapper silently returns FunctionWrapper instead of the target return value","assert @wrapt.decorator rejects custom decorator keyword arguments and requires an outer factory function","assert enabled=False returns the unwrapped function while enabled=callable dynamically evaluates per invocation","assert @wrapt.adapter_factory customizes inspect.signature without changing underlying wrapper execution"],"goal":"Invoke wrapt universal decorators and monkey-patch wrappers with 4-arg signatures without double-binding instance or decorating patch hooks","kind":"HOW","packages":["pkg:pypi/wrapt@2.2.2"],"schemaVersion":1,"symbols":["wrapt.decorator","wrapt.wrap_function_wrapper","wrapt.adapter_factory","wrapt.FunctionWrapper"]},"contractCommand":["python","test/contract.py"],"environment":{"arch":"x64","ecosystem":"pypi","executionContext":"python","language":"python","os":"linux","packageManager":"pip","runtime":"python","schemaVersion":1},"license":"MIT-0","packages":["pkg:pypi/wrapt@2.2.2"],"schemaVersion":1,"symbols":["wrapt.decorator","wrapt.wrap_function_wrapper","wrapt.adapter_factory","wrapt.FunctionWrapper"],"verifierAdapter":"python@1"}
wrapt==2.2.2
# wrapt decorator patterns and monkeypatching contract source
"""Wrapt universal decorator patterns, binding rules, and monkeypatching adapters.
Wrapt's universal decorator protocol uses a 4-argument signature:
wrapper(wrapped, instance, args, kwargs)
Key behavioral rules:
1. `instance` separation: When decorating an instance method or class method,
`instance` receives `self` or `cls`, and `args` has `self`/`cls` stripped.
2. `wrapped` binding: `wrapped` is ALREADY bound to `instance`. Calling
`wrapped(*args, **kwargs)` is always required; passing `instance` explicitly
double-passes the target and raises a TypeError.
3. Decorators with arguments: `@wrapt.decorator` only accepts (wrapper, enabled,
adapter, proxy). Custom decorator arguments must use an outer factory function.
4. Monkey-patching: `wrapt.wrap_function_wrapper` expects a raw 4-arg callable,
NOT a `@wrapt.decorator` wrapped object. Passing a decorated wrapper silently
returns a FunctionWrapper instead of executing the wrapped target.
5. Signature adaptation: `@wrapt.adapter_factory` or `adapter=` customizes
the advertised signature reported by `inspect.signature`.
"""
import inspect
import wrapt
@wrapt.decorator
def universal_passthrough(wrapped, instance, args, kwargs):
"""A standard wrapt decorator that inspects instance and passes args cleanly."""
return wrapped(*args, **kwargs)
def prefix_decorator_factory(prefix="LOG"):
"""Correct pattern for a wrapt decorator with custom arguments."""
@wrapt.decorator
def wrapper(wrapped, instance, args, kwargs):
result = wrapped(*args, **kwargs)
return f"{prefix}: {result}"
return wrapper
def raw_patch_wrapper(wrapped, instance, args, kwargs):
"""Raw 4-argument callable intended for wrapt.wrap_function_wrapper."""
return wrapped(*args, **kwargs) * 2
@wrapt.decorator
def double_wrapped_patch(wrapped, instance, args, kwargs):
"""Common anti-pattern: applying @wrapt.decorator to a wrap_function_wrapper hook."""
return wrapped(*args, **kwargs) * 2
@wrapt.adapter_factory
def drop_first_arg_adapter(wrapped):
"""Adapter factory that provides a signature omitting the first parameter."""
sig = inspect.signature(wrapped)
params = list(sig.parameters.values())[1:]
new_sig = sig.replace(parameters=params)
def prototype(*args, **kwargs):
pass
prototype.__signature__ = new_sig
return prototype
@wrapt.decorator(adapter=drop_first_arg_adapter)
def inject_context_decorator(wrapped, instance, args, kwargs):
"""Decorator that injects a default context string as first argument."""
return wrapped("default_context", *args, **kwargs)
import inspect
import os
import sys
import types
import wrapt
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from src.decorators import (
double_wrapped_patch,
inject_context_decorator,
prefix_decorator_factory,
raw_patch_wrapper,
universal_passthrough,
)
# -----------------------------------------------------------------------------
# 1. Instance separation and argument stripping across call kinds
# -----------------------------------------------------------------------------
call_state = {}
@wrapt.decorator
def inspect_call(wrapped, instance, args, kwargs):
call_state["instance"] = instance
call_state["args"] = args
call_state["kwargs"] = kwargs
return wrapped(*args, **kwargs)
class Calculator:
def add(self, a, b):
return a + b
@classmethod
def multiply(cls, a, b):
return a * b
@staticmethod
def negate(a):
return -a
calc = Calculator()
# Standalone function
@inspect_call
def standalone_sub(a, b):
return a - b
assert standalone_sub(10, 3) == 7
assert call_state["instance"] is None
assert call_state["args"] == (10, 3)
# Instance method: instance is calc, args has self stripped!
dec_add = inspect_call(calc.add)
assert dec_add(10, 3) == 13
assert call_state["instance"] is calc
assert call_state["args"] == (10, 3) # self is NOT in args!
# Class method: instance is Calculator class, args has cls stripped!
dec_mul = inspect_call(Calculator.multiply)
assert dec_mul(4, 5) == 20
assert call_state["instance"] is Calculator
assert call_state["args"] == (4, 5) # cls is NOT in args!
# Static method: instance is None
dec_neg = inspect_call(Calculator.negate)
assert dec_neg(42) == -42
assert call_state["instance"] is None
assert call_state["args"] == (42,)
# -----------------------------------------------------------------------------
# 2. Trap: Calling wrapped(instance, *args) raises TypeError
# Naive models assume wrapped is unbound when instance is present and try to pass instance.
# -----------------------------------------------------------------------------
@wrapt.decorator
def naive_instance_passer(wrapped, instance, args, kwargs):
if instance is not None:
# NAIVE ERROR: wrapped is ALREADY bound to instance!
return wrapped(instance, *args, **kwargs)
return wrapped(*args, **kwargs)
bound_bad_add = naive_instance_passer(calc.add)
try:
bound_bad_add(10, 3)
raise AssertionError("Expected TypeError: wrapped is already bound")
except TypeError as err:
# Error message confirms double-passing instance:
# "Calculator.add() takes 3 positional arguments but 4 were given"
assert "takes" in str(err) and "positional argument" in str(err)
# -----------------------------------------------------------------------------
# 3. Trap: wrap_function_wrapper with @wrapt.decorator silently returns FunctionWrapper
# Passing a decorated wrapper instead of a raw 4-arg function corrupts return values without raising.
# -----------------------------------------------------------------------------
class TargetService:
def compute(self, x):
return x + 1
target_good = TargetService()
wrapt.wrap_function_wrapper(target_good, "compute", raw_patch_wrapper)
assert target_good.compute(5) == 12 # (5 + 1) * 2 = 12
target_bad = TargetService()
wrapt.wrap_function_wrapper(target_bad, "compute", double_wrapped_patch)
bad_result = target_bad.compute(5)
# SILENT TRAP: bad_result is NOT an int (12) -- it is a FunctionWrapper object!
assert isinstance(bad_result, wrapt.FunctionWrapper)
assert bad_result != 12
assert bool(bad_result) is True # Truthiness test would deceptively pass
# -----------------------------------------------------------------------------
# 4. Trap: Custom arguments to @wrapt.decorator vs factory function
# -----------------------------------------------------------------------------
# Direct custom keyword argument to @wrapt.decorator raises TypeError immediately
try:
@wrapt.decorator(prefix="CUSTOM")
def bad_direct_args(wrapped, instance, args, kwargs):
return wrapped(*args, **kwargs)
raise AssertionError("Expected TypeError on unknown kwarg to wrapt.decorator")
except TypeError as err:
assert "unexpected keyword argument 'prefix'" in str(err)
# Extra default parameter on wrapper called as factory raises IndexError
@wrapt.decorator
def flawed_factory_wrapper(wrapped, instance, args, kwargs, prefix="DEFAULT"):
return f"{prefix}: {wrapped(*args, **kwargs)}"
try:
@flawed_factory_wrapper(prefix="CUSTOM")
def doomed_target():
return "ok"
raise AssertionError("Expected IndexError when invoking wrapper with kwargs")
except IndexError as err:
assert "tuple index out of range" in str(err)
# Correct factory pattern works as expected
custom_dec = prefix_decorator_factory(prefix="VERIFIED")
@custom_dec
def greet(name):
return f"Hello {name}"
assert greet("Alice") == "VERIFIED: Hello Alice"
# -----------------------------------------------------------------------------
# 5. Dynamic enabled flag: boolean vs callable predicate
# -----------------------------------------------------------------------------
# Static enabled=False returns the unwrapped function directly (no wrapper created)
def plain_fn():
return "original"
@wrapt.decorator(enabled=False)
def inactive_wrapper(wrapped, instance, args, kwargs):
return "interceptor"
disabled_dec = inactive_wrapper(plain_fn)
assert disabled_dec is plain_fn
# Callable enabled predicate evaluates per call
feature_flag = True
@wrapt.decorator(enabled=lambda: feature_flag)
def toggled_dec(wrapped, instance, args, kwargs):
return f"INTERCEPTED: {wrapped(*args, **kwargs)}"
@toggled_dec
def query_value():
return "data"
assert query_value() == "INTERCEPTED: data"
feature_flag = False
assert query_value() == "data" # Bypasses wrapper body
# -----------------------------------------------------------------------------
# 6. Preserving and adapting signatures via wrapt.adapter_factory
# -----------------------------------------------------------------------------
# Default wrapt.decorator preserves the wrapped function's original signature
assert str(inspect.signature(standalone_sub)) == "(a, b)"
assert str(inspect.signature(greet)) == "(name)"
# Adapter factory modifies advertised inspect.signature
def endpoint_handler(ctx, x, y):
return f"{ctx}: {x + y}"
adapted_endpoint = inject_context_decorator(endpoint_handler)
# Advertised signature omits the injected 'ctx' parameter
assert str(inspect.signature(adapted_endpoint)) == "(x, y)"
# Invocation injects 'default_context' and passes x, y
assert adapted_endpoint(10, 20) == "default_context: 30"
print("CONTRACT PASS: wrapt universal decorator binding, monkeypatching, and adapter contracts verified")