mirror of
https://github.com/opencv/opencv.git
synced 2025-06-07 17:44:04 +08:00
Improve Python binding generator with mappable types and phantom headers
This commit is contained in:
parent
f1ca05c822
commit
b5eb65e53e
@ -305,6 +305,9 @@ Cv64suf;
|
|||||||
#define CV_PROP_RW
|
#define CV_PROP_RW
|
||||||
#define CV_WRAP
|
#define CV_WRAP
|
||||||
#define CV_WRAP_AS(synonym)
|
#define CV_WRAP_AS(synonym)
|
||||||
|
#define CV_WRAP_MAPPABLE(mappable)
|
||||||
|
#define CV_WRAP_PHANTOM(phantom_header)
|
||||||
|
#define CV_WRAP_DEFAULT(val)
|
||||||
|
|
||||||
/****************************************************************************************\
|
/****************************************************************************************\
|
||||||
* Matrix type (Mat) *
|
* Matrix type (Mat) *
|
||||||
|
@ -81,16 +81,25 @@ template<> bool pyopencv_to(PyObject* src, ${cname}& dst, const char* name)
|
|||||||
{
|
{
|
||||||
if(!src || src == Py_None)
|
if(!src || src == Py_None)
|
||||||
return true;
|
return true;
|
||||||
if(!PyObject_TypeCheck(src, &pyopencv_${name}_Type))
|
if(PyObject_TypeCheck(src, &pyopencv_${name}_Type))
|
||||||
{
|
{
|
||||||
failmsg("Expected ${cname} for argument '%%s'", name);
|
dst = ((pyopencv_${name}_t*)src)->v;
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
dst = ((pyopencv_${name}_t*)src)->v;
|
failmsg("Expected ${cname} for argument '%%s'", name);
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
""" % head_init_str)
|
""" % 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("""
|
gen_template_type_decl = Template("""
|
||||||
struct pyopencv_${name}_t
|
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)
|
if(!src || src == Py_None)
|
||||||
return true;
|
return true;
|
||||||
if(!PyObject_TypeCheck(src, &pyopencv_${name}_Type))
|
if(PyObject_TypeCheck(src, &pyopencv_${name}_Type))
|
||||||
{
|
{
|
||||||
failmsg("Expected ${cname} for argument '%%s'", name);
|
dst = ((pyopencv_${name}_t*)src)->v.dynamicCast<${cname}>();
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
dst = ((pyopencv_${name}_t*)src)->v.dynamicCast<${cname}>();
|
${mappable_code}
|
||||||
return true;
|
failmsg("Expected ${cname} for argument '%%s'", name);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
""" % head_init_str)
|
""" % head_init_str)
|
||||||
@ -267,6 +277,7 @@ class ClassInfo(object):
|
|||||||
self.isalgorithm = False
|
self.isalgorithm = False
|
||||||
self.methods = {}
|
self.methods = {}
|
||||||
self.props = []
|
self.props = []
|
||||||
|
self.mappables = []
|
||||||
self.consts = {}
|
self.consts = {}
|
||||||
self.base = None
|
self.base = None
|
||||||
self.constructor = None
|
self.constructor = None
|
||||||
@ -412,10 +423,11 @@ class ArgInfo(object):
|
|||||||
|
|
||||||
|
|
||||||
class FuncVariant(object):
|
class FuncVariant(object):
|
||||||
def __init__(self, classname, name, decl, isconstructor):
|
def __init__(self, classname, name, decl, isconstructor, isphantom=False):
|
||||||
self.classname = classname
|
self.classname = classname
|
||||||
self.name = self.wname = name
|
self.name = self.wname = name
|
||||||
self.isconstructor = isconstructor
|
self.isconstructor = isconstructor
|
||||||
|
self.isphantom = isphantom
|
||||||
|
|
||||||
self.docstring = decl[5]
|
self.docstring = decl[5]
|
||||||
|
|
||||||
@ -531,8 +543,8 @@ class FuncInfo(object):
|
|||||||
self.isclassmethod = isclassmethod
|
self.isclassmethod = isclassmethod
|
||||||
self.variants = []
|
self.variants = []
|
||||||
|
|
||||||
def add_variant(self, decl):
|
def add_variant(self, decl, isphantom=False):
|
||||||
self.variants.append(FuncVariant(self.classname, self.name, decl, self.isconstructor))
|
self.variants.append(FuncVariant(self.classname, self.name, decl, self.isconstructor, isphantom))
|
||||||
|
|
||||||
def get_wrapper_name(self):
|
def get_wrapper_name(self):
|
||||||
name = self.name
|
name = self.name
|
||||||
@ -640,6 +652,9 @@ class FuncInfo(object):
|
|||||||
all_cargs = []
|
all_cargs = []
|
||||||
parse_arglist = []
|
parse_arglist = []
|
||||||
|
|
||||||
|
if v.isphantom and ismethod and not self.isclassmethod:
|
||||||
|
code_args += "_self_"
|
||||||
|
|
||||||
# declare all the C function arguments,
|
# declare all the C function arguments,
|
||||||
# add necessary conversions from Python objects to code_cvt_list,
|
# add necessary conversions from Python objects to code_cvt_list,
|
||||||
# form the function/method call,
|
# form the function/method call,
|
||||||
@ -717,6 +732,8 @@ class FuncInfo(object):
|
|||||||
|
|
||||||
code_prelude = templ_prelude.substitute(name=selfinfo.name, cname=selfinfo.cname)
|
code_prelude = templ_prelude.substitute(name=selfinfo.name, cname=selfinfo.cname)
|
||||||
code_fcall = templ.substitute(name=selfinfo.name, cname=selfinfo.cname, args=code_args)
|
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:
|
else:
|
||||||
code_prelude = ""
|
code_prelude = ""
|
||||||
code_fcall = ""
|
code_fcall = ""
|
||||||
@ -913,11 +930,21 @@ class PythonWrapperGenerator(object):
|
|||||||
|
|
||||||
isconstructor = name == bareclassname
|
isconstructor = name == bareclassname
|
||||||
isclassmethod = False
|
isclassmethod = False
|
||||||
|
isphantom = False
|
||||||
|
mappable = None
|
||||||
for m in decl[2]:
|
for m in decl[2]:
|
||||||
if m == "/S":
|
if m == "/S":
|
||||||
isclassmethod = True
|
isclassmethod = True
|
||||||
|
elif m == "/phantom":
|
||||||
|
isphantom = True
|
||||||
|
cname = cname.replace("::", "_")
|
||||||
elif m.startswith("="):
|
elif m.startswith("="):
|
||||||
name = m[1:]
|
name = m[1:]
|
||||||
|
elif m.startswith("/mappable="):
|
||||||
|
mappable = m[10:]
|
||||||
|
self.classes[classname].mappables.append(mappable)
|
||||||
|
return
|
||||||
|
|
||||||
if isconstructor:
|
if isconstructor:
|
||||||
name = "_".join(classes[:-1]+[name])
|
name = "_".join(classes[:-1]+[name])
|
||||||
|
|
||||||
@ -925,13 +952,13 @@ class PythonWrapperGenerator(object):
|
|||||||
# Add it as a method to the class
|
# Add it as a method to the class
|
||||||
func_map = self.classes[classname].methods
|
func_map = self.classes[classname].methods
|
||||||
func = func_map.setdefault(name, FuncInfo(classname, name, cname, isconstructor, namespace, isclassmethod))
|
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
|
# Add it as global function
|
||||||
g_name = "_".join(classes+[name])
|
g_name = "_".join(classes+[name])
|
||||||
func_map = self.namespaces.setdefault(namespace, Namespace()).funcs
|
func_map = self.namespaces.setdefault(namespace, Namespace()).funcs
|
||||||
func = func_map.setdefault(g_name, FuncInfo("", g_name, cname, isconstructor, namespace, False))
|
func = func_map.setdefault(g_name, FuncInfo("", g_name, cname, isconstructor, namespace, False))
|
||||||
func.add_variant(decl)
|
func.add_variant(decl, isphantom)
|
||||||
else:
|
else:
|
||||||
if classname and not isconstructor:
|
if classname and not isconstructor:
|
||||||
cname = barename
|
cname = barename
|
||||||
@ -940,7 +967,7 @@ class PythonWrapperGenerator(object):
|
|||||||
func_map = self.namespaces.setdefault(namespace, Namespace()).funcs
|
func_map = self.namespaces.setdefault(namespace, Namespace()).funcs
|
||||||
|
|
||||||
func = func_map.setdefault(name, FuncInfo(classname, name, cname, isconstructor, namespace, isclassmethod))
|
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:
|
if classname and isconstructor:
|
||||||
self.classes[classname].constructor = func
|
self.classes[classname].constructor = func
|
||||||
@ -1056,8 +1083,11 @@ class PythonWrapperGenerator(object):
|
|||||||
templ = gen_template_simple_type_decl
|
templ = gen_template_simple_type_decl
|
||||||
else:
|
else:
|
||||||
templ = gen_template_type_decl
|
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,
|
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.
|
# register classes in the same order as they have been declared.
|
||||||
# this way, base classes will be registered in Python before their derivatives.
|
# this way, base classes will be registered in Python before their derivatives.
|
||||||
|
@ -6,6 +6,7 @@ import os, sys, re, string, io
|
|||||||
# the list only for debugging. The real list, used in the real OpenCV build, is specified in CMakeLists.txt
|
# the list only for debugging. The real list, used in the real OpenCV build, is specified in CMakeLists.txt
|
||||||
opencv_hdr_list = [
|
opencv_hdr_list = [
|
||||||
"../../core/include/opencv2/core.hpp",
|
"../../core/include/opencv2/core.hpp",
|
||||||
|
"../../core/include/opencv2/core/mat.hpp",
|
||||||
"../../core/include/opencv2/core/ocl.hpp",
|
"../../core/include/opencv2/core/ocl.hpp",
|
||||||
"../../flann/include/opencv2/flann/miniflann.hpp",
|
"../../flann/include/opencv2/flann/miniflann.hpp",
|
||||||
"../../ml/include/opencv2/ml.hpp",
|
"../../ml/include/opencv2/ml.hpp",
|
||||||
@ -376,8 +377,6 @@ class CppHeaderParser(object):
|
|||||||
decl[2].append("/A")
|
decl[2].append("/A")
|
||||||
if bool(re.match(r".*\)\s*const(\s*=\s*0)?", decl_str)):
|
if bool(re.match(r".*\)\s*const(\s*=\s*0)?", decl_str)):
|
||||||
decl[2].append("/C")
|
decl[2].append("/C")
|
||||||
if "virtual" in decl_str:
|
|
||||||
print(decl_str)
|
|
||||||
return decl
|
return decl
|
||||||
|
|
||||||
def parse_func_decl(self, decl_str, mat="Mat", docstring=""):
|
def parse_func_decl(self, decl_str, mat="Mat", docstring=""):
|
||||||
@ -393,8 +392,7 @@ class CppHeaderParser(object):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
if self.wrap_mode:
|
if self.wrap_mode:
|
||||||
if not (("CV_EXPORTS_AS" in decl_str) or ("CV_EXPORTS_W" in decl_str) or \
|
if not (("CV_EXPORTS_AS" in decl_str) or ("CV_EXPORTS_W" in decl_str) or ("CV_WRAP" in decl_str)):
|
||||||
("CV_WRAP" in decl_str) or ("CV_WRAP_AS" in decl_str)):
|
|
||||||
return []
|
return []
|
||||||
|
|
||||||
# ignore old API in the documentation check (for now)
|
# ignore old API in the documentation check (for now)
|
||||||
@ -414,6 +412,16 @@ class CppHeaderParser(object):
|
|||||||
arg, npos3 = self.get_macro_arg(decl_str, npos)
|
arg, npos3 = self.get_macro_arg(decl_str, npos)
|
||||||
func_modlist.append("="+arg)
|
func_modlist.append("="+arg)
|
||||||
decl_str = decl_str[:npos] + decl_str[npos3+1:]
|
decl_str = decl_str[:npos] + decl_str[npos3+1:]
|
||||||
|
npos = decl_str.find("CV_WRAP_PHANTOM")
|
||||||
|
if npos >= 0:
|
||||||
|
decl_str, _ = self.get_macro_arg(decl_str, npos)
|
||||||
|
func_modlist.append("/phantom")
|
||||||
|
npos = decl_str.find("CV_WRAP_MAPPABLE")
|
||||||
|
if npos >= 0:
|
||||||
|
mappable, npos3 = self.get_macro_arg(decl_str, npos)
|
||||||
|
func_modlist.append("/mappable="+mappable)
|
||||||
|
classname = top[1]
|
||||||
|
return ['.'.join([classname, classname]), None, func_modlist, [], None, None]
|
||||||
|
|
||||||
virtual_method = False
|
virtual_method = False
|
||||||
pure_virtual_method = False
|
pure_virtual_method = False
|
||||||
@ -527,8 +535,6 @@ class CppHeaderParser(object):
|
|||||||
t, npos = self.find_next_token(decl_str, ["(", ")", ",", "<", ">"], npos)
|
t, npos = self.find_next_token(decl_str, ["(", ")", ",", "<", ">"], npos)
|
||||||
if not t:
|
if not t:
|
||||||
print("Error: no closing ')' at %d" % (self.lineno,))
|
print("Error: no closing ')' at %d" % (self.lineno,))
|
||||||
print(decl_str)
|
|
||||||
print(decl_str[arg_start:])
|
|
||||||
sys.exit(-1)
|
sys.exit(-1)
|
||||||
if t == "<":
|
if t == "<":
|
||||||
angle_balance += 1
|
angle_balance += 1
|
||||||
|
Loading…
Reference in New Issue
Block a user