Commit 640f13ec authored by Stefan Behnel's avatar Stefan Behnel

make cfunc wrapper function support kwargs if the defining module wants it and...

make cfunc wrapper function support kwargs if the defining module wants it and give it a docstring that shows the argument names
parent 4bdb3cf4
......@@ -2661,22 +2661,25 @@ class CFuncType(CType):
return False
if arg.type.is_extension_type or arg.type.is_builtin_type:
env.use_utility_code(UtilityCode.load_cached("ExtTypeTest", "ObjectHandling.c"))
class Arg:
def __init__(self, ix, type):
class Arg(object):
def __init__(self, ix, arg):
self.ix = ix
self.name = 'ARG%s' % ix
self.type = type
self.name = arg.name or 'ARG%s' % ix
self.type = arg.type
self.type_name = 'TYPE%s' % ix
self.type_cname = type.declaration_code("")
self.type_cname = self.type.declaration_code("")
if self.type.is_extension_type or self.type.is_builtin_type:
self.type_convert = '<%s>' % self.type_name
elif type.is_pyobject:
elif self.type.is_pyobject:
self.type_convert = ''
else:
self.type_convert = '%s_to_py' % self.type_name
def declare_type_def(self):
if self.type.is_extension_type or self.type.is_builtin_type or not self.type.is_pyobject:
return 'ctypedef void* %s "%s"' % (self.type_name, self.type_cname)
def declare_type_convert(self):
if self.type.is_extension_type or self.type.is_builtin_type:
return 'cdef PyTypeObject* %s_TYPE "%s"' % (self.type_name, self.type.typeptr_cname)
......@@ -2684,6 +2687,7 @@ class CFuncType(CType):
return ''
else:
return 'cdef %s %s "%s"(object) except *' % (self.type_name, self.type_convert, self.type.from_py_function)
def check_type(self):
if self.type.is_extension_type or self.type.is_builtin_type:
return '__Pyx_TypeTest(<PyObject*>%s, %s_TYPE)' % (self.name, self.type_name)
......@@ -2710,14 +2714,16 @@ class CFuncType(CType):
context = {
'cname': self.to_py_function,
'args': [Arg(ix, arg.type) for ix, arg in enumerate(self.args)],
'args': [Arg(ix, arg) for ix, arg in enumerate(self.args)],
'return_type': return_type,
'declare_return_type': declare_return_type,
'declare_return_type_convert': declare_return_type_convert,
'maybe_return': maybe_return,
'except_clause': except_clause,
}
env.use_utility_code(CythonUtilityCode.load("cfunc.to_py", "CFuncConvert.pyx", context=context))
env.use_utility_code(CythonUtilityCode.load(
"cfunc.to_py", "CFuncConvert.pyx",
context=context, compiler_directives=dict(env.directives)))
return True
......
......@@ -23,9 +23,12 @@ from . import UtilNodes
class StringParseContext(Main.Context):
def __init__(self, name, include_directories=None):
if include_directories is None: include_directories = []
Main.Context.__init__(self, include_directories, {},
def __init__(self, name, include_directories=None, compiler_directives=None):
if include_directories is None:
include_directories = []
if compiler_directives is None:
compiler_directives = {}
Main.Context.__init__(self, include_directories, compiler_directives,
create_testscope=False)
self.module_name = name
......
......@@ -71,7 +71,7 @@ class CythonUtilityCode(Code.UtilityCodeBase):
is_cython_utility = True
def __init__(self, impl, name="__pyxutil", prefix="", requires=None,
file=None, from_scope=None, context=None):
file=None, from_scope=None, context=None, compiler_directives=None):
# 1) We need to delay the parsing/processing, so that all modules can be
# imported without import loops
# 2) The same utility code object can be used for multiple source files;
......@@ -86,6 +86,7 @@ class CythonUtilityCode(Code.UtilityCodeBase):
self.prefix = prefix
self.requires = requires or []
self.from_scope = from_scope
self.compiler_directives = compiler_directives
def get_tree(self, entries_only=False, cython_scope=None):
from .AnalysedTreeTransforms import AutoTestDictTransform
......@@ -95,7 +96,8 @@ class CythonUtilityCode(Code.UtilityCodeBase):
excludes = [AutoTestDictTransform]
from . import Pipeline, ParseTreeTransforms
context = CythonUtilityCodeContext(self.name)
context = CythonUtilityCodeContext(
self.name, compiler_directives=self.compiler_directives)
context.prefix = self.prefix
context.cython_scope = cython_scope
#context = StringParseContext(self.name)
......
......@@ -12,10 +12,11 @@ cdef extern from *:
{{declare_return_type_convert}}
@cname("{{cname}}")
cdef object {{cname}}({{return_type}} (*f)({{', '.join(arg.type_name for arg in args)}}) {{except_clause}}):
def wrap({{', '.join(arg.name for arg in args)}}):
cdef object {{cname}}({{return_type}} (*f)({{ ', '.join(arg.type_name for arg in args) }}) {{except_clause}}):
def wrap({{ ', '.join(arg.name for arg in args) }}):
"""wrap({{', '.join(arg.name for arg in args)}})"""
{{for arg in args}}
{{arg.check_type()}}
{{endfor}}
{{maybe_return}} (f({{', '.join('%s(%s)' % (arg.type_convert, arg.name) for arg in args)}}))
{{maybe_return}}(f({{ ', '.join('%s(%s)' % (arg.type_convert, arg.name) for arg in args) }}))
return wrap
# mode: run
# cython: always_allow_keywords=True
from libc.math cimport sqrt
cdef void empty_cfunc():
......@@ -26,11 +30,26 @@ def call_square_c(x):
return py_func(x)
def return_square_c():
"""
>>> square_c = return_square_c()
>>> square_c(5)
25.0
>>> square_c(x=4)
16.0
>>> square_c.__doc__ # FIXME: try to make original C function name available
'wrap(x)'
"""
return square_c
def return_libc_sqrt():
"""
>>> sqrt = return_libc_sqrt()
>>> sqrt(9)
3.0
>>> sqrt(x=9)
3.0
"""
return sqrt
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment