Improve Python binding generator with mappable types and phantom headers

This commit is contained in:
Hamdi Sahloul
2018-08-19 02:34:47 +09:00
parent f1ca05c822
commit b5eb65e53e
3 changed files with 62 additions and 23 deletions
+47 -17
View File
@@ -81,16 +81,25 @@ template<> bool pyopencv_to(PyObject* src, ${cname}& dst, const char* name)
{
if(!src || src == Py_None)
return true;
if(!PyObject_TypeCheck(src, &pyopencv_${name}_Type))
if(PyObject_TypeCheck(src, &pyopencv_${name}_Type))
{
failmsg("Expected ${cname} for argument '%%s'", name);
return false;
dst = ((pyopencv_${name}_t*)src)->v;
return true;
}
dst = ((pyopencv_${name}_t*)src)->v;
return true;
failmsg("Expected ${cname} for argument '%%s'", name);
return false;
}
""" % head_init_str)
gen_template_mappable = Template("""
{
${mappable} _src;
if (pyopencv_to(src, _src, name))
{
return cv_mappable_to(_src, dst);
}
}
""")
gen_template_type_decl = Template("""
struct pyopencv_${name}_t
@@ -124,13 +133,14 @@ template<> bool pyopencv_to(PyObject* src, Ptr<${cname}>& dst, const char* name)
{
if(!src || src == Py_None)
return true;
if(!PyObject_TypeCheck(src, &pyopencv_${name}_Type))
if(PyObject_TypeCheck(src, &pyopencv_${name}_Type))
{
failmsg("Expected ${cname} for argument '%%s'", name);
return false;
dst = ((pyopencv_${name}_t*)src)->v.dynamicCast<${cname}>();
return true;
}
dst = ((pyopencv_${name}_t*)src)->v.dynamicCast<${cname}>();
return true;
${mappable_code}
failmsg("Expected ${cname} for argument '%%s'", name);
return false;
}
""" % head_init_str)
@@ -267,6 +277,7 @@ class ClassInfo(object):
self.isalgorithm = False
self.methods = {}
self.props = []
self.mappables = []
self.consts = {}
self.base = None
self.constructor = None
@@ -412,10 +423,11 @@ class ArgInfo(object):
class FuncVariant(object):
def __init__(self, classname, name, decl, isconstructor):
def __init__(self, classname, name, decl, isconstructor, isphantom=False):
self.classname = classname
self.name = self.wname = name
self.isconstructor = isconstructor
self.isphantom = isphantom
self.docstring = decl[5]
@@ -531,8 +543,8 @@ class FuncInfo(object):
self.isclassmethod = isclassmethod
self.variants = []
def add_variant(self, decl):
self.variants.append(FuncVariant(self.classname, self.name, decl, self.isconstructor))
def add_variant(self, decl, isphantom=False):
self.variants.append(FuncVariant(self.classname, self.name, decl, self.isconstructor, isphantom))
def get_wrapper_name(self):
name = self.name
@@ -640,6 +652,9 @@ class FuncInfo(object):
all_cargs = []
parse_arglist = []
if v.isphantom and ismethod and not self.isclassmethod:
code_args += "_self_"
# declare all the C function arguments,
# add necessary conversions from Python objects to code_cvt_list,
# form the function/method call,
@@ -717,6 +732,8 @@ class FuncInfo(object):
code_prelude = templ_prelude.substitute(name=selfinfo.name, cname=selfinfo.cname)
code_fcall = templ.substitute(name=selfinfo.name, cname=selfinfo.cname, args=code_args)
if v.isphantom:
code_fcall = code_fcall.replace("new " + selfinfo.cname, self.cname.replace("::", "_"))
else:
code_prelude = ""
code_fcall = ""
@@ -913,11 +930,21 @@ class PythonWrapperGenerator(object):
isconstructor = name == bareclassname
isclassmethod = False
isphantom = False
mappable = None
for m in decl[2]:
if m == "/S":
isclassmethod = True
elif m == "/phantom":
isphantom = True
cname = cname.replace("::", "_")
elif m.startswith("="):
name = m[1:]
elif m.startswith("/mappable="):
mappable = m[10:]
self.classes[classname].mappables.append(mappable)
return
if isconstructor:
name = "_".join(classes[:-1]+[name])
@@ -925,13 +952,13 @@ class PythonWrapperGenerator(object):
# Add it as a method to the class
func_map = self.classes[classname].methods
func = func_map.setdefault(name, FuncInfo(classname, name, cname, isconstructor, namespace, isclassmethod))
func.add_variant(decl)
func.add_variant(decl, isphantom)
# Add it as global function
g_name = "_".join(classes+[name])
func_map = self.namespaces.setdefault(namespace, Namespace()).funcs
func = func_map.setdefault(g_name, FuncInfo("", g_name, cname, isconstructor, namespace, False))
func.add_variant(decl)
func.add_variant(decl, isphantom)
else:
if classname and not isconstructor:
cname = barename
@@ -940,7 +967,7 @@ class PythonWrapperGenerator(object):
func_map = self.namespaces.setdefault(namespace, Namespace()).funcs
func = func_map.setdefault(name, FuncInfo(classname, name, cname, isconstructor, namespace, isclassmethod))
func.add_variant(decl)
func.add_variant(decl, isphantom)
if classname and isconstructor:
self.classes[classname].constructor = func
@@ -1056,8 +1083,11 @@ class PythonWrapperGenerator(object):
templ = gen_template_simple_type_decl
else:
templ = gen_template_type_decl
mappable_code = "\n".join([
gen_template_mappable.substitute(cname=classinfo.cname, mappable=mappable)
for mappable in classinfo.mappables])
self.code_types.write(templ.substitute(name=name, wname=classinfo.wname, cname=classinfo.cname, sname=classinfo.sname,
cname1=("cv::Algorithm" if classinfo.isalgorithm else classinfo.cname)))
cname1=("cv::Algorithm" if classinfo.isalgorithm else classinfo.cname), mappable_code=mappable_code))
# register classes in the same order as they have been declared.
# this way, base classes will be registered in Python before their derivatives.