+import cython
from tornado import gen
import pythonmodule
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)
backports_abc.patch()
from tornado.testing import AsyncTestCase, gen_test
+from tornado.util import ArgReplacer
+import unittest
import cythonapp
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], {}))
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.