mirror of
https://github.com/opencv/opencv.git
synced 2025-06-07 17:44:04 +08:00
Merge pull request #8934 from lewisjb:python-classes
* Refactor Python Classes
This commit is contained in:
parent
42fbbfecc6
commit
1caca2112b
@ -1609,14 +1609,20 @@ void initcv2()
|
||||
return;
|
||||
#endif
|
||||
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
Py_INCREF(&cv2_UMatWrapperType);
|
||||
#define PUBLISH_OBJECT(name, type) Py_INCREF(&type);\
|
||||
PyModule_AddObject(m, name, (PyObject *)&type);
|
||||
#else
|
||||
// Unrolled Py_INCREF(&cv2_UMatWrapperType) without (PyObject*) cast
|
||||
// due to "warning: dereferencing type-punned pointer will break strict-aliasing rules"
|
||||
_Py_INC_REFTOTAL _Py_REF_DEBUG_COMMA (&cv2_UMatWrapperType)->ob_refcnt++;
|
||||
// Unrolled Py_INCREF(&type) without (PyObject*) cast
|
||||
// due to "warning: dereferencing type-punned pointer will break strict-aliasing rules"
|
||||
#define PUBLISH_OBJECT(name, type) _Py_INC_REFTOTAL _Py_REF_DEBUG_COMMA (&type)->ob_refcnt++;\
|
||||
PyModule_AddObject(m, name, (PyObject *)&type);
|
||||
#endif
|
||||
PyModule_AddObject(m, "UMat", (PyObject *)&cv2_UMatWrapperType);
|
||||
|
||||
PUBLISH_OBJECT("UMat", cv2_UMatWrapperType);
|
||||
|
||||
#include "pyopencv_generated_type_publish.h"
|
||||
|
||||
#define PUBLISH(I) PyDict_SetItemString(d, #I, PyInt_FromLong(I))
|
||||
//#define PUBLISHU(I) PyDict_SetItemString(d, #I, PyLong_FromUnsignedLong(I))
|
||||
|
@ -25,14 +25,12 @@ gen_template_check_self_algo = Template(""" $cname* _self_ = NULL;
|
||||
return failmsgp("Incorrect type of self (must be '${name}' or its derivative)");
|
||||
""")
|
||||
|
||||
gen_template_call_constructor_prelude = Template("""self = PyObject_NEW(pyopencv_${name}_t, &pyopencv_${name}_Type);
|
||||
new (&(self->v)) Ptr<$cname>(); // init Ptr with placement new
|
||||
gen_template_call_constructor_prelude = Template("""new (&(self->v)) Ptr<$cname>(); // init Ptr with placement new
|
||||
if(self) """)
|
||||
|
||||
gen_template_call_constructor = Template("""self->v.reset(new ${cname}${args})""")
|
||||
|
||||
gen_template_simple_call_constructor_prelude = Template("""self = PyObject_NEW(pyopencv_${name}_t, &pyopencv_${name}_Type);
|
||||
if(self) """)
|
||||
gen_template_simple_call_constructor_prelude = Template("""if(self) """)
|
||||
|
||||
gen_template_simple_call_constructor = Template("""new (&(self->v)) ${cname}${args}""")
|
||||
|
||||
@ -189,6 +187,7 @@ static void pyopencv_${name}_specials(void)
|
||||
pyopencv_${name}_Type.tp_dealloc = pyopencv_${name}_dealloc;
|
||||
pyopencv_${name}_Type.tp_repr = pyopencv_${name}_repr;
|
||||
pyopencv_${name}_Type.tp_getset = pyopencv_${name}_getseters;
|
||||
pyopencv_${name}_Type.tp_init = (initproc)${constructor};
|
||||
pyopencv_${name}_Type.tp_methods = pyopencv_${name}_methods;${extra_specials}
|
||||
}
|
||||
""")
|
||||
@ -280,6 +279,7 @@ class ClassInfo(object):
|
||||
self.props = []
|
||||
self.consts = {}
|
||||
self.base = None
|
||||
self.constructor = None
|
||||
customname = False
|
||||
|
||||
if decl:
|
||||
@ -353,6 +353,9 @@ class ClassInfo(object):
|
||||
sorted_methods = list(self.methods.items())
|
||||
sorted_methods.sort()
|
||||
|
||||
if self.constructor is not None:
|
||||
methods_code.write(self.constructor.gen_code(all_classes))
|
||||
|
||||
for mname, m in sorted_methods:
|
||||
methods_code.write(m.gen_code(all_classes))
|
||||
methods_inits.write(m.get_tab_entry())
|
||||
@ -361,10 +364,14 @@ class ClassInfo(object):
|
||||
if self.base and self.base in all_classes:
|
||||
baseptr = "&pyopencv_" + all_classes[self.base].name + "_Type"
|
||||
|
||||
constructor_name = "0"
|
||||
if self.constructor is not None:
|
||||
constructor_name = self.constructor.get_wrapper_name()
|
||||
|
||||
code = gen_template_type_impl.substitute(name=self.name, wname=self.wname, cname=self.cname,
|
||||
getset_code=getset_code.getvalue(), getset_inits=getset_inits.getvalue(),
|
||||
methods_code=methods_code.getvalue(), methods_inits=methods_inits.getvalue(),
|
||||
baseptr=baseptr, extra_specials="")
|
||||
baseptr=baseptr, constructor=constructor_name, extra_specials="")
|
||||
|
||||
return code
|
||||
|
||||
@ -521,12 +528,13 @@ class FuncVariant(object):
|
||||
|
||||
|
||||
class FuncInfo(object):
|
||||
def __init__(self, classname, name, cname, isconstructor, namespace):
|
||||
def __init__(self, classname, name, cname, isconstructor, namespace, isclassmethod):
|
||||
self.classname = classname
|
||||
self.name = name
|
||||
self.cname = cname
|
||||
self.isconstructor = isconstructor
|
||||
self.namespace = namespace
|
||||
self.isclassmethod = isclassmethod
|
||||
self.variants = []
|
||||
|
||||
def add_variant(self, decl):
|
||||
@ -540,11 +548,19 @@ class FuncInfo(object):
|
||||
name = "getelem"
|
||||
else:
|
||||
classname = ""
|
||||
|
||||
if self.isclassmethod:
|
||||
name += "_cls"
|
||||
|
||||
return "pyopencv_" + self.namespace.replace('.','_') + '_' + classname + name
|
||||
|
||||
def get_wrapper_prototype(self):
|
||||
def get_wrapper_prototype(self, all_classes):
|
||||
full_fname = self.get_wrapper_name()
|
||||
if self.classname and not self.isconstructor:
|
||||
if self.isconstructor:
|
||||
return "static int {fn_name}(pyopencv_{type_name}_t* self, PyObject* args, PyObject* kw)".format(
|
||||
fn_name=full_fname, type_name=all_classes[self.classname].name)
|
||||
|
||||
if self.classname:
|
||||
self_arg = "self"
|
||||
else:
|
||||
self_arg = ""
|
||||
@ -591,12 +607,16 @@ class FuncInfo(object):
|
||||
# Convert unicode chars to xml representation, but keep as string instead of bytes
|
||||
full_docstring = full_docstring.encode('ascii', errors='xmlcharrefreplace').decode()
|
||||
|
||||
return Template(' {"$py_funcname", (PyCFunction)$wrap_funcname, METH_VARARGS | METH_KEYWORDS, "$py_docstring"},\n'
|
||||
flags = ["METH_VARARGS", "METH_KEYWORDS"]
|
||||
if self.isclassmethod:
|
||||
flags.append("METH_CLASS")
|
||||
|
||||
return Template(' {"$py_funcname", (PyCFunction)$wrap_funcname, $flags, "$py_docstring"},\n'
|
||||
).substitute(py_funcname = self.variants[0].wname, wrap_funcname=self.get_wrapper_name(),
|
||||
py_docstring = full_docstring)
|
||||
flags = " | ".join(flags), py_docstring = full_docstring)
|
||||
|
||||
def gen_code(self, all_classes):
|
||||
proto = self.get_wrapper_prototype()
|
||||
proto = self.get_wrapper_prototype(all_classes)
|
||||
code = "%s\n{\n" % (proto,)
|
||||
code += " using namespace %s;\n\n" % self.namespace.replace('.', '::')
|
||||
|
||||
@ -609,7 +629,9 @@ class FuncInfo(object):
|
||||
selfinfo = all_classes[self.classname]
|
||||
if not self.isconstructor:
|
||||
amp = "&" if selfinfo.issimple else ""
|
||||
if selfinfo.isalgorithm:
|
||||
if self.isclassmethod:
|
||||
pass
|
||||
elif selfinfo.isalgorithm:
|
||||
code += gen_template_check_self_algo.substitute(name=selfinfo.name, cname=selfinfo.cname, amp=amp)
|
||||
else:
|
||||
get = "" if selfinfo.issimple else ".get()"
|
||||
@ -692,7 +714,6 @@ class FuncInfo(object):
|
||||
code_args += ")"
|
||||
|
||||
if self.isconstructor:
|
||||
code_decl += " pyopencv_%s_t* self = 0;\n" % selfinfo.name
|
||||
if selfinfo.issimple:
|
||||
templ_prelude = gen_template_simple_call_constructor_prelude
|
||||
templ = gen_template_simple_call_constructor
|
||||
@ -708,7 +729,7 @@ class FuncInfo(object):
|
||||
if v.rettype:
|
||||
code_decl += " " + v.rettype + " retval;\n"
|
||||
code_fcall += "retval = "
|
||||
if ismethod:
|
||||
if ismethod and not self.isclassmethod:
|
||||
code_fcall += "_self_->" + self.cname
|
||||
else:
|
||||
code_fcall += self.cname
|
||||
@ -750,7 +771,7 @@ class FuncInfo(object):
|
||||
code_ret = "Py_RETURN_NONE"
|
||||
elif len(v.py_outlist) == 1:
|
||||
if self.isconstructor:
|
||||
code_ret = "return (PyObject*)self"
|
||||
code_ret = "return 0"
|
||||
else:
|
||||
aname, argno = v.py_outlist[0]
|
||||
code_ret = "return pyopencv_from(%s)" % (aname,)
|
||||
@ -773,7 +794,11 @@ class FuncInfo(object):
|
||||
else:
|
||||
# try to execute each signature
|
||||
code += " PyErr_Clear();\n\n".join([" {\n" + v + " }\n" for v in all_code_variants])
|
||||
code += "\n return NULL;\n}\n\n"
|
||||
|
||||
def_ret = "NULL"
|
||||
if self.isconstructor:
|
||||
def_ret = "-1"
|
||||
code += "\n return %s;\n}\n\n" % def_ret
|
||||
return code
|
||||
|
||||
|
||||
@ -796,6 +821,7 @@ class PythonWrapperGenerator(object):
|
||||
self.code_funcs = StringIO()
|
||||
self.code_type_reg = StringIO()
|
||||
self.code_ns_reg = StringIO()
|
||||
self.code_type_publish = StringIO()
|
||||
self.class_idx = 0
|
||||
|
||||
def add_class(self, stype, name, decl):
|
||||
@ -848,20 +874,32 @@ class PythonWrapperGenerator(object):
|
||||
isclassmethod = True
|
||||
elif m.startswith("="):
|
||||
name = m[1:]
|
||||
if isclassmethod:
|
||||
name = "_".join(classes+[name])
|
||||
classname = ''
|
||||
elif isconstructor:
|
||||
if isconstructor:
|
||||
name = "_".join(classes[:-1]+[name])
|
||||
|
||||
if classname and not isconstructor:
|
||||
cname = barename
|
||||
if isclassmethod:
|
||||
# Add it as a method to the class
|
||||
func_map = self.classes[classname].methods
|
||||
else:
|
||||
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 = func_map.setdefault(name, FuncInfo(classname, name, cname, isconstructor, namespace))
|
||||
func.add_variant(decl)
|
||||
# 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)
|
||||
else:
|
||||
if classname and not isconstructor:
|
||||
cname = barename
|
||||
func_map = self.classes[classname].methods
|
||||
else:
|
||||
func_map = self.namespaces.setdefault(namespace, Namespace()).funcs
|
||||
|
||||
func = func_map.setdefault(name, FuncInfo(classname, name, cname, isconstructor, namespace, isclassmethod))
|
||||
func.add_variant(decl)
|
||||
|
||||
if classname and isconstructor:
|
||||
self.classes[classname].constructor = func
|
||||
|
||||
|
||||
def gen_namespace(self, ns_name):
|
||||
@ -870,6 +908,8 @@ class PythonWrapperGenerator(object):
|
||||
|
||||
self.code_ns_reg.write('static PyMethodDef methods_%s[] = {\n'%wname)
|
||||
for name, func in sorted(ns.funcs.items()):
|
||||
if func.isconstructor:
|
||||
continue
|
||||
self.code_ns_reg.write(func.get_tab_entry())
|
||||
self.code_ns_reg.write(' {NULL, NULL}\n};\n\n')
|
||||
|
||||
@ -960,12 +1000,15 @@ class PythonWrapperGenerator(object):
|
||||
self.code_types.write(code)
|
||||
if not classinfo.ismap:
|
||||
self.code_type_reg.write("MKTYPE2(%s);\n" % (classinfo.name,) )
|
||||
self.code_type_publish.write("PUBLISH_OBJECT(\"{name}\", pyopencv_{name}_Type);\n".format(name=classinfo.name))
|
||||
|
||||
# step 3: generate the code for all the global functions
|
||||
for ns_name, ns in sorted(self.namespaces.items()):
|
||||
if ns_name.split('.')[0] != 'cv':
|
||||
continue
|
||||
for name, func in sorted(ns.funcs.items()):
|
||||
if func.isconstructor:
|
||||
continue
|
||||
code = func.gen_code(self.classes)
|
||||
self.code_funcs.write(code)
|
||||
self.gen_namespace(ns_name)
|
||||
@ -983,6 +1026,7 @@ class PythonWrapperGenerator(object):
|
||||
self.save(output_path, "pyopencv_generated_types.h", self.code_types)
|
||||
self.save(output_path, "pyopencv_generated_type_reg.h", self.code_type_reg)
|
||||
self.save(output_path, "pyopencv_generated_ns_reg.h", self.code_ns_reg)
|
||||
self.save(output_path, "pyopencv_generated_type_publish.h", self.code_type_publish)
|
||||
|
||||
if __name__ == "__main__":
|
||||
srcfiles = hdr_parser.opencv_hdr_list
|
||||
|
Loading…
Reference in New Issue
Block a user