From b13c6dc80c426aa115ebe60bce4724cf808a4ba5 Mon Sep 17 00:00:00 2001 From: harbinresearcher Date: Thu, 8 Oct 2026 10:59:04 +0800 Subject: [PATCH] Honor falsey AdapterFactory subclasses --- docs/changes.rst | 9 +++++++ src/wrapt/decorators.py | 2 +- tests/core/test_adapter.py | 53 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 1 deletion(-) diff --git a/docs/changes.rst b/docs/changes.rst index 9f50db19..88e56b76 100644 --- a/docs/changes.rst +++ b/docs/changes.rst @@ -1,6 +1,15 @@ Release Notes ============= +Unreleased +---------- + +**Bugs Fixed** + +* ``wrapt.decorator`` ignored an ``AdapterFactory`` whose boolean value was + false, leaving the original signature in place instead of invoking the + factory. These factories are now invoked regardless of their truth value. + Version 2.5.0 ------------- diff --git a/src/wrapt/decorators.py b/src/wrapt/decorators.py index f9290684..b6a139a6 100644 --- a/src/wrapt/decorators.py +++ b/src/wrapt/decorators.py @@ -177,7 +177,7 @@ def decorator(wrapper=None, /, *, enabled=None, adapter=None, proxy=FunctionWrap # time when we need it down below. def _build(wrapped, wrapper, enabled=None, adapter=None): - if adapter: + if isinstance(adapter, AdapterFactory) or adapter: if isinstance(adapter, AdapterFactory): adapter = adapter(wrapped) diff --git a/tests/core/test_adapter.py b/tests/core/test_adapter.py index 00c1f18d..33338d4d 100644 --- a/tests/core/test_adapter.py +++ b/tests/core/test_adapter.py @@ -208,6 +208,59 @@ def function(cls): self.assertEqual(inspect.getfullargspec(Class2.function), argspec) self.assertEqual(inspect.getfullargspec(instance2.function), argspec) + def test_falsey_adapter_factory(self): + class FalseyFactory(wrapt.AdapterFactory): + def __bool__(self): + return False + + def __call__(self, wrapped): + calls.append(wrapped) + argspec = inspect.getfullargspec(wrapped) + argspec.args.insert(0, "extra") + return argspec + + class EmptyFactory(wrapt.AdapterFactory): + def __len__(self): + return 0 + + __call__ = FalseyFactory.__call__ + + for factory_type in (FalseyFactory, EmptyFactory): + with self.subTest(factory=factory_type.__name__): + calls = [] + + @wrapt.decorator(adapter=factory_type()) + def wrapper(wrapped, instance, args, kwargs): + return wrapped(*args, **kwargs) + + def function(value): + return value + + decorated = wrapper(function) + self.assertEqual(calls, [function]) + self.assertEqual(str(inspect.signature(decorated)), "(extra, value)") + self.assertEqual( + inspect.getfullargspec(decorated).args, ["extra", "value"] + ) + self.assertEqual(decorated(7), 7) + + def test_falsey_adapter_disabled(self): + for adapter in (None, False, ""): + with self.subTest(adapter=adapter): + + @wrapt.decorator(adapter=adapter) + def wrapper(wrapped, instance, args, kwargs): + return wrapped(*args, **kwargs) + + def function(value): + return value + + decorated = wrapper(function) + self.assertEqual( + inspect.signature(decorated), inspect.signature(function) + ) + self.assertEqual(decorated(7), 7) + def test_adapter_factory(self): def factory(wrapped): argspec = inspect.getfullargspec(wrapped)