From 5ad7f9910f23d1d6248c3142b1b65849051767bf Mon Sep 17 00:00:00 2001 From: Alexander Mordvintsev Date: Fri, 15 Aug 2014 20:44:32 +0400 Subject: [PATCH] function namespaces partially work --- modules/python/common.cmake | 3 ++- modules/python/src2/cv2.cpp | 36 ++++++++++++++++++++++++++++++ modules/python/src2/gen2.py | 53 +++++++++++++++++++++++++++------------------ 3 files changed, 70 insertions(+), 22 deletions(-) diff --git a/modules/python/common.cmake b/modules/python/common.cmake index b9b3377..05cff74 100644 --- a/modules/python/common.cmake +++ b/modules/python/common.cmake @@ -51,7 +51,8 @@ set(cv2_generated_hdrs "${CMAKE_CURRENT_BINARY_DIR}/pyopencv_generated_func_tab.h" "${CMAKE_CURRENT_BINARY_DIR}/pyopencv_generated_types.h" "${CMAKE_CURRENT_BINARY_DIR}/pyopencv_generated_type_reg.h" - "${CMAKE_CURRENT_BINARY_DIR}/pyopencv_generated_const_reg.h") + "${CMAKE_CURRENT_BINARY_DIR}/pyopencv_generated_const_reg.h" + "${CMAKE_CURRENT_BINARY_DIR}/pyopencv_generated_ns_reg.h") file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/headers.txt" "${opencv_hdrs}") add_custom_command( diff --git a/modules/python/src2/cv2.cpp b/modules/python/src2/cv2.cpp index 0bd914a..f5df883 100644 --- a/modules/python/src2/cv2.cpp +++ b/modules/python/src2/cv2.cpp @@ -1205,6 +1205,40 @@ static PyMethodDef methods[] = { /************************************************************************/ /* Module init */ +static void init_submodule(PyObject * root, const char * name, PyMethodDef * methods) +{ + std::string s = name; + size_t i = s.find('.')+1; // assume, that name is cv2.... + while (i < s.length()) + { + size_t j = s.find('.', i); + if (j == std::string::npos) + j = s.length(); + std::string short_name = s.substr(i, j-i); + std::string full_name = s.substr(0, j); + i = j+1; + + PyObject * d = PyModule_GetDict(root); + PyObject * submod = PyDict_GetItemString(d, short_name.c_str()); + if (submod == NULL) + { + submod = PyImport_AddModule(full_name.c_str()); + PyDict_SetItemString(d, short_name.c_str(), submod); + } + root = submod; + } + + PyObject * d = PyModule_GetDict(root); + for (PyMethodDef * m = methods; m->ml_name != NULL; ++m) + { + PyObject * method_obj = PyCFunction_NewEx(m, NULL, NULL); + PyDict_SetItemString(d, m->ml_name, method_obj); + Py_DECREF(method_obj); + } +} + +#include "pyopencv_generated_ns_reg.h" + static int to_ok(PyTypeObject *to) { to->tp_alloc = PyType_GenericAlloc; @@ -1242,6 +1276,8 @@ void initcv2() #else PyObject* m = Py_InitModule(MODULESTR, methods); #endif + init_submodules(m); // from "pyopencv_generated_ns_reg.h" + PyObject* d = PyModule_GetDict(m); PyDict_SetItemString(d, "__version__", PyString_FromString(CV_VERSION)); diff --git a/modules/python/src2/gen2.py b/modules/python/src2/gen2.py index 4ddcb8e..5926cec 100755 --- a/modules/python/src2/gen2.py +++ b/modules/python/src2/gen2.py @@ -398,11 +398,6 @@ class FuncVariant(object): self.classname = classname self.name = self.wname = name self.isconstructor = isconstructor - if self.isconstructor: - if self.wname.startswith("Cv"): - self.wname = self.wname[2:] - else: - self.wname = self.classname self.rettype = handle_ptr(decl[1]) if self.rettype == "void": @@ -505,11 +500,12 @@ class FuncVariant(object): class FuncInfo(object): - def __init__(self, classname, name, cname, isconstructor): + def __init__(self, classname, name, cname, isconstructor, namespace): self.classname = classname self.name = name self.cname = cname self.isconstructor = isconstructor + self.namespace = namespace self.variants = [] def add_variant(self, decl): @@ -560,6 +556,7 @@ class FuncInfo(object): def gen_code(self, all_classes): proto = self.get_wrapper_prototype() code = "%s\n{\n" % (proto,) + code += " using namespace %s;\n\n" % self.namespace.replace('.', '::') selfinfo = ClassInfo("") ismethod = self.classname != "" and not self.isconstructor @@ -782,6 +779,9 @@ class PythonWrapperGenerator(object): if classname in self.classes: bareclassname = chunks[-2] namespace = '.'.join(chunks[:-2]) + if normalize_class_name(namespace) in self.classes: + print('Note: skipping "%s" (nested classes are currently not supported)'%decl[0]) + return else: classname = '' bareclassname = '' @@ -795,14 +795,15 @@ class PythonWrapperGenerator(object): name = m[1:] if isclassmethod: name = bareclassname+"_"+name - classname = bareclassname = '' + classname = '' - if classname: - func_map = classinfo = self.classes[classname].methods + if classname and not isconstructor: + cname = chunks[-1] + func_map = self.classes[classname].methods else: func_map = self.ns_funcs.setdefault(namespace, {}) - func = func_map.setdefault(name, FuncInfo(classname, name, cname, isconstructor)) + func = func_map.setdefault(name, FuncInfo(classname, name, cname, isconstructor, namespace)) func.add_variant(decl) def gen_const_reg(self, constinfo): @@ -816,6 +817,16 @@ class PythonWrapperGenerator(object): self.code_ns_reg.write(func.get_tab_entry()) self.code_ns_reg.write(' {NULL, NULL}\n};\n\n') + def gen_namespaces_reg(self): + self.code_ns_reg.write('static void init_submodules(PyObject * root) \n{\n') + for ns_name in sorted(self.ns_funcs): + if ns_name == 'cv': + continue + wname = normalize_class_name(ns_name) + self.code_ns_reg.write(' init_submodule(root, MODULESTR"%s", methods_%s);\n' % (ns_name[2:], wname)) + self.code_ns_reg.write('};\n') + + def save(self, path, name, buf): f = open(path + "/" + name, "wt") f.write(buf.getvalue()) @@ -872,12 +883,17 @@ class PythonWrapperGenerator(object): self.code_type_reg.write("MKTYPE2(%s);\n" % (classinfo.name,) ) # step 3: generate the code for all the global functions - funclist = list(self.ns_funcs['cv'].items()) - funclist.sort() - for name, func in funclist: - code = func.gen_code(self.classes) - self.code_funcs.write(code) - self.code_func_tab.write(func.get_tab_entry()) + for ns in self.ns_funcs: + funclist = self.ns_funcs[ns].items() + funclist.sort() + for name, func in funclist: + code = func.gen_code(self.classes) + self.code_funcs.write(code) + if ns == 'cv': + self.code_func_tab.write(func.get_tab_entry()) + if ns != 'cv': + self.gen_namespace(ns) + self.gen_namespaces_reg() # step 4: generate the code for constants constlist = list(self.consts.items()) @@ -885,11 +901,6 @@ class PythonWrapperGenerator(object): for name, constinfo in constlist: self.gen_const_reg(constinfo) - # step 5: generate the code for namespaces - for ns in sorted(self.ns_funcs): - if ns != 'cv': - self.gen_namespace(ns) - # That's it. Now save all the files self.save(output_path, "pyopencv_generated_include.h", self.code_include) self.save(output_path, "pyopencv_generated_funcs.h", self.code_funcs) -- 2.7.4