Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions docs/changes.rst
Original file line number Diff line number Diff line change
@@ -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
-------------

Expand Down
2 changes: 1 addition & 1 deletion src/wrapt/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
53 changes: 53 additions & 0 deletions tests/core/test_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Loading