function namespaces partially work
authorAlexander Mordvintsev <Alexander.Mordvintsev@transas.com>
Fri, 15 Aug 2014 16:44:32 +0000 (20:44 +0400)
committerAlexander Mordvintsev <Alexander.Mordvintsev@transas.com>
Tue, 19 Aug 2014 12:40:07 +0000 (16:40 +0400)
modules/python/common.cmake
modules/python/src2/cv2.cpp
modules/python/src2/gen2.py

index b9b3377..05cff74 100644 (file)
@@ -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(
index 0bd914a..f5df883 100644 (file)
@@ -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.<name>...
+  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));
index 4ddcb8e..5926cec 100755 (executable)
@@ -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)