Make ArgReplacer compatible with cython-compiled functions.
This requires a directive in the cython code to make the signature introspectable.
This commit is contained in:
parent
3463036d75
commit
4ccfe8925d
|
@ -1,3 +1,4 @@
|
|||
import cython
|
||||
from tornado import gen
|
||||
import pythonmodule
|
||||
|
||||
|
@ -13,3 +14,9 @@ def decorated_coroutine():
|
|||
if x != "hello":
|
||||
raise ValueError("expected hello, got %r" % x)
|
||||
return "goodbye"
|
||||
|
||||
# The binding directive is necessary for compatibility with
|
||||
# ArgReplacer (and therefore return_future).
|
||||
@cython.binding(True)
|
||||
def function_with_args(one, two, three):
|
||||
return (one, two, three)
|
||||
|
|
|
@ -6,6 +6,8 @@ else:
|
|||
backports_abc.patch()
|
||||
|
||||
from tornado.testing import AsyncTestCase, gen_test
|
||||
from tornado.util import ArgReplacer
|
||||
import unittest
|
||||
|
||||
import cythonapp
|
||||
|
||||
|
@ -20,3 +22,13 @@ class CythonCoroutineTest(AsyncTestCase):
|
|||
def test_decorated_coroutine(self):
|
||||
x = yield cythonapp.decorated_coroutine()
|
||||
self.assertEqual(x, "goodbye")
|
||||
|
||||
|
||||
class CythonArgReplacerTest(unittest.TestCase):
|
||||
def test_arg_replacer(self):
|
||||
replacer = ArgReplacer(cythonapp.function_with_args, 'two')
|
||||
args = (1, 'old', 3)
|
||||
kwargs = {}
|
||||
self.assertEqual(replacer.get_old_value(args, kwargs), 'old')
|
||||
self.assertEqual(replacer.replace('new', args, kwargs),
|
||||
('old', [1, 'new', 3], {}))
|
||||
|
|
|
@ -290,11 +290,25 @@ class ArgReplacer(object):
|
|||
def __init__(self, func, name):
|
||||
self.name = name
|
||||
try:
|
||||
self.arg_pos = getargspec(func).args.index(self.name)
|
||||
self.arg_pos = self._getargnames(func).index(name)
|
||||
except ValueError:
|
||||
# Not a positional parameter
|
||||
self.arg_pos = None
|
||||
|
||||
def _getargnames(self, func):
|
||||
try:
|
||||
return getargspec(func).args
|
||||
except TypeError:
|
||||
if hasattr(func, 'func_code'):
|
||||
# Cython-generated code has all the attributes needed
|
||||
# by inspect.getargspec (when the
|
||||
# @cython.binding(True) directive is used), but the
|
||||
# inspect module only works with ordinary functions.
|
||||
# Inline the portion of getargspec that we need here.
|
||||
code = func.func_code
|
||||
return code.co_varnames[:code.co_argcount]
|
||||
raise
|
||||
|
||||
def get_old_value(self, args, kwargs, default=None):
|
||||
"""Returns the old value of the named argument without replacing it.
|
||||
|
||||
|
|
Loading…
Reference in New Issue