put consts into python submodules
authorAlexander Mordvintsev <Alexander.Mordvintsev@transas.com>
Tue, 19 Aug 2014 09:35:46 +0000 (13:35 +0400)
committerAlexander Mordvintsev <Alexander.Mordvintsev@transas.com>
Tue, 19 Aug 2014 12:40:09 +0000 (16:40 +0400)
maintain set of visited namespaces in CppHeaderParser
WARNING: REMOVED const name conversion (SomeConstName -> SOME_CONST_NAME), discussion needed

modules/python/common.cmake
modules/python/src2/cv2.cpp
modules/python/src2/gen2.py
modules/python/src2/hdr_parser.py

index f19474e..ea8d0c8 100644 (file)
@@ -50,7 +50,6 @@ set(cv2_generated_hdrs
     "${CMAKE_CURRENT_BINARY_DIR}/pyopencv_generated_funcs.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_ns_reg.h")
 
 file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/headers.txt" "${opencv_hdrs}")
index 3948d04..d71abba 100644 (file)
@@ -1201,7 +1201,13 @@ static PyMethodDef methods[] = {
 /************************************************************************/
 /* Module init */
 
-static void init_submodule(PyObject * root, const char * name, PyMethodDef * methods)
+struct ConstDef
+{
+    const char * name;
+    long val;
+};
+
+static void init_submodule(PyObject * root, const char * name, PyMethodDef * methods, ConstDef * consts)
 {
   // traverse and create nested submodules
   std::string s = name;
@@ -1233,6 +1239,11 @@ static void init_submodule(PyObject * root, const char * name, PyMethodDef * met
     PyDict_SetItemString(d, m->ml_name, method_obj);
     Py_DECREF(method_obj);
   }
+  for (ConstDef * c = consts; c->name != NULL; ++c)
+  {
+    PyDict_SetItemString(d, c->name, PyInt_FromLong(c->val));
+  }
+
 }
 
 #include "pyopencv_generated_ns_reg.h"
@@ -1323,7 +1334,6 @@ void initcv2()
   PUBLISH(CV_64FC3);
   PUBLISH(CV_64FC4);
 
-#include "pyopencv_generated_const_reg.h"
 #if PY_MAJOR_VERSION >= 3
     return m;
 #endif
index ca4e1fb..0c1ff64 100755 (executable)
@@ -341,16 +341,6 @@ class ClassInfo(object):
         return code
 
 
-class ConstInfo(object):
-    def __init__(self, name, val):
-        self.cname = name.replace(".", "::")
-        self.name = re.sub(r"^cv\.", "", name).replace(".", "_")
-        if self.name.startswith("Cv"):
-            self.name = self.name[2:]
-        self.name = re.sub(r"([a-z])([A-Z])", r"\1_\2", self.name)
-        self.name = self.name.upper()
-        self.value = val
-
 def handle_ptr(tp):
     if tp.startswith('Ptr_'):
         tp = 'Ptr<' + "::".join(tp.split('_')[1:]) + '>'
@@ -749,7 +739,6 @@ class PythonWrapperGenerator(object):
         self.code_types = StringIO()
         self.code_funcs = StringIO()
         self.code_type_reg = StringIO()
-        self.code_const_reg = StringIO()
         self.code_ns_reg = StringIO()
         self.class_idx = 0
 
@@ -766,23 +755,31 @@ class PythonWrapperGenerator(object):
         if classinfo.bases and not classinfo.isalgorithm:
             classinfo.isalgorithm = self.classes[classinfo.bases[0].replace("::", "_")].isalgorithm
 
-    def add_const(self, name, decl):
-        constinfo = ConstInfo(name, decl[1])
+    def split_decl_name(self, name):
+        chunks = name.split('.')
+        namespace = chunks[:-1]
+        classes = []
+        while namespace and '.'.join(namespace) not in self.parser.namespaces:
+            classes.insert(0, namespace.pop())
+        return namespace, classes, chunks[-1]
 
-        if constinfo.name in self.consts:
+
+    def add_const(self, name, decl):
+        cname = name.replace('.','::')
+        namespace, classes, name = self.split_decl_name(name)
+        namespace = '.'.join(namespace)
+        name = '_'.join(classes+[name])
+        ns = self.namespaces.setdefault(namespace, Namespace())
+        if name in ns.consts:
             print("Generator error: constant %s (cname=%s) already exists" \
-                % (constinfo.name, constinfo.cname))
+                % (name, cname))
             sys.exit(-1)
-        self.consts[constinfo.name] = constinfo
+        ns.consts[name] = cname
 
     def add_func(self, decl):
-        chunks = decl[0].split('.')
-        name = chunks[-1]
-        cname = '::'.join(chunks)
-        namespace = chunks[:-1]
-        classes = []
-        while normalize_class_name('.'.join(namespace)) in self.classes:
-            classes.insert(0, namespace.pop())
+        namespace, classes, barename = self.split_decl_name(decl[0])
+        cname = "::".join(namespace+classes+[barename])
+        name = barename
         classname = ''
         bareclassname = ''
         if classes:
@@ -804,7 +801,7 @@ class PythonWrapperGenerator(object):
             name = "_".join(classes[:-1]+[name])
 
         if classname and not isconstructor:
-            cname = chunks[-1]
+            cname = barename
             func_map = self.classes[classname].methods
         else:
             func_map = self.namespaces.setdefault(namespace, Namespace()).funcs
@@ -812,22 +809,27 @@ class PythonWrapperGenerator(object):
         func = func_map.setdefault(name, FuncInfo(classname, name, cname, isconstructor, namespace))
         func.add_variant(decl)
 
-    def gen_const_reg(self, constinfo):
-        self.code_const_reg.write("PUBLISH2(%s,%s);\n" % (constinfo.name, constinfo.cname))
 
     def gen_namespace(self, ns_name):
+        ns = self.namespaces[ns_name]
         wname = normalize_class_name(ns_name)
+
         self.code_ns_reg.write('static PyMethodDef methods_%s[] = {\n'%wname)
-        funclist = sorted(self.namespaces[ns_name].funcs.items())
-        for name, func in funclist:
+        for name, func in sorted(ns.funcs.items()):
             self.code_ns_reg.write(func.get_tab_entry())
         self.code_ns_reg.write('    {NULL, NULL}\n};\n\n')
 
+        self.code_ns_reg.write('static ConstDef consts_%s[] = {\n'%wname)
+        for name, cname in sorted(ns.consts.items()):
+            self.code_ns_reg.write('    {"%s", %s},\n'%(name, cname))
+        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.namespaces):
-            wname = normalize_class_name(ns_name)
-            self.code_ns_reg.write('  init_submodule(root, MODULESTR"%s", methods_%s);\n' % (ns_name[2:], wname))
+            if ns_name.split('.')[0] == 'cv':
+                wname = normalize_class_name(ns_name)
+                self.code_ns_reg.write('  init_submodule(root, MODULESTR"%s", methods_%s, consts_%s);\n' % (ns_name[2:], wname, wname))
         self.code_ns_reg.write('};\n')
 
 
@@ -838,11 +840,11 @@ class PythonWrapperGenerator(object):
 
     def gen(self, srcfiles, output_path):
         self.clear()
-        parser = hdr_parser.CppHeaderParser()
+        self.parser = hdr_parser.CppHeaderParser()
 
         # step 1: scan the headers and build more descriptive maps of classes, consts, functions
         for hdr in srcfiles:
-            decls = parser.parse(hdr)
+            decls = self.parser.parse(hdr)
             if len(decls) == 0:
                 continue
             self.code_include.write( '#include "{}"\n'.format(hdr[hdr.rindex('opencv2/'):]) )
@@ -888,6 +890,8 @@ class PythonWrapperGenerator(object):
 
         # 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()):
                 code = func.gen_code(self.classes)
                 self.code_funcs.write(code)
@@ -903,7 +907,6 @@ class PythonWrapperGenerator(object):
         # 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)
-        self.save(output_path, "pyopencv_generated_const_reg.h", self.code_const_reg)
         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)
index de33aeb..5f989d6 100755 (executable)
@@ -38,6 +38,8 @@ class CppHeaderParser(object):
         self.PUBLIC_SECTION = 3
         self.CLASS_DECL = 4
 
+        self.namespaces = set()
+
     def batch_replace(self, s, pairs):
         for before, after in pairs:
             s = s.replace(before, after)
@@ -833,6 +835,9 @@ class CppHeaderParser(object):
                                 decls.append(d)
                         else:
                             decls.append(decl)
+                    if stmt_type == "namespace":
+                        chunks = [block[1] for block in self.block_stack if block[0] == 'namespace'] + [name]
+                        self.namespaces.add('.'.join(chunks))
                 else:
                     stmt_type, name, parse_flag = "block", "", False
 
@@ -877,3 +882,5 @@ if __name__ == '__main__':
         #decls += parser.parse(hname, wmode=False)
     parser.print_decls(decls)
     print(len(decls))
+    print("namespaces:", " ".join(sorted(parser.namespaces)))
+