Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use inspect.Signature instead of inspect.formatargspec #203

Closed
wants to merge 2 commits into from
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
33 changes: 26 additions & 7 deletions src/wrapt/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,14 @@ def exec_(_code_, _globs_=None, _locs_=None):
del builtins

from functools import partial
from inspect import ismethod, isclass, formatargspec
from inspect import ismethod, isclass
from collections import namedtuple
from threading import Lock, RLock

try:
from inspect import signature
from inspect import signature, Signature, Parameter
except ImportError:
pass
from inspect import formatargspec

from .wrappers import (FunctionWrapper, BoundFunctionWrapper, ObjectProxy,
CallableObjectProxy)
Expand Down Expand Up @@ -166,6 +166,27 @@ def __call__(self, wrapped):

adapter_factory = DelegatedAdapterFactory

if PY2:
def _formatargspec(spec):
return formatargspec(*spec)
else:
def _formatargspec(spec):
params = []
for arg in spec.args:
params.append(Parameter(arg, Parameter.POSITIONAL_OR_KEYWORD))
if spec.defaults:
for i, d in enumerate(reversed(spec.defaults)):
idx = len(params) - 1 - i
params[idx] = params[idx].replace(default=d)
if spec.varargs:
params.append(Parameter(spec.varargs, Parameter.VAR_POSITIONAL))
if hasattr(spec, 'keywords') and spec.keywords:
params.append(Parameter(spec.keywords, Parameter.VAR_KEYWORD))
if hasattr(spec, 'varkw') and spec.varkw:
params.append(Parameter(spec.varkw, Parameter.VAR_KEYWORD))

return str(Signature(params))

# Decorator for creating other decorators. This decorator and the
# wrappers which they use are designed to properly preserve any name
# attributes, function signatures etc, in addition to the wrappers
Expand Down Expand Up @@ -211,8 +232,7 @@ def _build(wrapped, wrapper, enabled=None, adapter=None):

# Check if the signature argument specification has
# annotations. If it does then we need to remember
# it but also drop it when attempting to manufacture
# a standin adapter function. This is necessary else
# it. This is necessary else
# it will try and look up any types referenced in
# the annotations in the empty namespace we use,
# which will fail.
Expand All @@ -222,8 +242,7 @@ def _build(wrapped, wrapper, enabled=None, adapter=None):
if not isinstance(adapter, string_types):
if len(adapter) == 7:
annotations = adapter[-1]
adapter = adapter[:-1]
adapter = formatargspec(*adapter)
adapter = _formatargspec(adapter)

exec_('def adapter{}: pass'.format(adapter), ns, ns)
adapter = ns['adapter']
Expand Down
96 changes: 52 additions & 44 deletions tests/test_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
import unittest
import inspect
import imp
import sys
try:
from inspect import getargspec as getspec
except ImportError: # python 3.11 and above
from inspect import getfullargspec as getspec

import wrapt

Expand Down Expand Up @@ -72,15 +77,15 @@ def test_argspec(self):

def _adapter(arg1, arg2, arg3=None, *args, **kwargs): pass

function1a_argspec = inspect.getargspec(_adapter)
function1d_argspec = inspect.getargspec(function1d)
function1a_argspec = getspec(_adapter)
function1d_argspec = getspec(function1d)
self.assertEqual(function1a_argspec, function1d_argspec)

# Now bind the function to an instance. The argspec should
# still match.

bound_function1d = function1d.__get__(object(), object)
bound_function1d_argspec = inspect.getargspec(bound_function1d)
bound_function1d_argspec = getspec(bound_function1d)
self.assertEqual(function1a_argspec, bound_function1d_argspec)

def test_signature(self):
Expand All @@ -107,7 +112,7 @@ class TestDynamicAdapter(unittest.TestCase):
def test_dynamic_adapter_function(self):
def _adapter(arg1, arg2, arg3=None, *args, **kwargs): pass

argspec = inspect.getargspec(_adapter)
argspec = getspec(_adapter)

@wrapt.decorator(adapter=argspec)
def _wrapper_1(wrapped, instance, args, kwargs):
Expand All @@ -117,24 +122,25 @@ def _wrapper_1(wrapped, instance, args, kwargs):
def _function_1():
pass

self.assertEqual(inspect.getargspec(_function_1), argspec)
self.assertEqual(getspec(_function_1), argspec)

args = inspect.formatargspec(*argspec)
if sys.version_info < (3, 11):
args = inspect.formatargspec(*argspec)

@wrapt.decorator(adapter=args)
def _wrapper_2(wrapped, instance, args, kwargs):
return wrapped(*args, **kwargs)
@wrapt.decorator(adapter=args)
def _wrapper_2(wrapped, instance, args, kwargs):
return wrapped(*args, **kwargs)

@_wrapper_2
def _function_2():
pass
@_wrapper_2
def _function_2():
pass

self.assertEqual(inspect.getargspec(_function_2), argspec)
self.assertEqual(getspec(_function_2), argspec)

def test_dynamic_adapter_instancemethod(self):
def _adapter(self, arg1, arg2, arg3=None, *args, **kwargs): pass

argspec = inspect.getargspec(_adapter)
argspec = getspec(_adapter)

@wrapt.decorator(adapter=argspec)
def _wrapper_1(wrapped, instance, args, kwargs):
Expand All @@ -147,29 +153,30 @@ def function(self):

instance1 = Class1()

self.assertEqual(inspect.getargspec(Class1.function), argspec)
self.assertEqual(inspect.getargspec(instance1.function), argspec)
self.assertEqual(getspec(Class1.function), argspec)
self.assertEqual(getspec(instance1.function), argspec)

args = inspect.formatargspec(*argspec)
if sys.version_info < (3, 11):
args = inspect.formatargspec(*argspec)

@wrapt.decorator(adapter=args)
def _wrapper_2(wrapped, instance, args, kwargs):
return wrapped(*args, **kwargs)
@wrapt.decorator(adapter=args)
def _wrapper_2(wrapped, instance, args, kwargs):
return wrapped(*args, **kwargs)

class Class2(object):
@_wrapper_2
def function(self):
pass
class Class2(object):
@_wrapper_2
def function(self):
pass

instance2 = Class2()
instance2 = Class2()

self.assertEqual(inspect.getargspec(Class2.function), argspec)
self.assertEqual(inspect.getargspec(instance2.function), argspec)
self.assertEqual(getspec(Class2.function), argspec)
self.assertEqual(getspec(instance2.function), argspec)

def test_dynamic_adapter_classmethod(self):
def _adapter(cls, arg1, arg2, arg3=None, *args, **kwargs): pass

argspec = inspect.getargspec(_adapter)
argspec = getspec(_adapter)

@wrapt.decorator(adapter=argspec)
def _wrapper_1(wrapped, instance, args, kwargs):
Expand All @@ -183,29 +190,30 @@ def function(cls):

instance1 = Class1()

self.assertEqual(inspect.getargspec(Class1.function), argspec)
self.assertEqual(inspect.getargspec(instance1.function), argspec)
self.assertEqual(getspec(Class1.function), argspec)
self.assertEqual(getspec(instance1.function), argspec)

args = inspect.formatargspec(*argspec)
if sys.version_info < (3, 11):
args = inspect.formatargspec(*argspec)

@wrapt.decorator(adapter=args)
def _wrapper_2(wrapped, instance, args, kwargs):
return wrapped(*args, **kwargs)
@wrapt.decorator(adapter=args)
def _wrapper_2(wrapped, instance, args, kwargs):
return wrapped(*args, **kwargs)

class Class2(object):
@_wrapper_2
@classmethod
def function(self):
pass
class Class2(object):
@_wrapper_2
@classmethod
def function(self):
pass

instance2 = Class2()
instance2 = Class2()

self.assertEqual(inspect.getargspec(Class2.function), argspec)
self.assertEqual(inspect.getargspec(instance2.function), argspec)
self.assertEqual(getspec(Class2.function), argspec)
self.assertEqual(getspec(instance2.function), argspec)

def test_adapter_factory(self):
def factory(wrapped):
argspec = inspect.getargspec(wrapped)
argspec = getspec(wrapped)
argspec.args.insert(0, 'arg0')
return argspec

Expand All @@ -217,7 +225,7 @@ def _wrapper_1(wrapped, instance, args, kwargs):
def _function_1(arg1, arg2):
pass

argspec = inspect.getargspec(_function_1)
argspec = getspec(_function_1)

self.assertEqual(argspec.args, ['arg0', 'arg1', 'arg2'])

Expand Down