Fixed regression in python wrappers generator
authorAndrey Kamaev <no@email>
Thu, 31 May 2012 11:04:11 +0000 (11:04 +0000)
committerAndrey Kamaev <no@email>
Thu, 31 May 2012 11:04:11 +0000 (11:04 +0000)
modules/python/src2/gen2.py

index 830c378..a14cb1d 100644 (file)
@@ -211,15 +211,18 @@ class ClassInfo(object):
         self.props = []
         self.consts = {}
         customname = False
-        
+
         if decl:
             self.bases = decl[1].split()[1:]
             if len(self.bases) > 1:
                 print "Warning: class %s has more than 1 base class (not supported by Python C extensions)" % (self.name,)
-                print "Bases: ", self.bases
+                print "Bases: ", " ".join(self.bases)
                 print "Only the first base class will be used"
-                self.bases = self.bases[:1]
+                self.bases = [self.bases[0].strip(",")]
                 #return sys.exit(-1)
+            if self.bases and self.bases[0].startswith("cv::"):
+                self.bases[0] = self.bases[0][4:]
+            print self.bases, decl[1]
             for m in decl[2]:
                 if m.startswith("="):
                     self.wname = m[1:]
@@ -229,10 +232,10 @@ class ClassInfo(object):
                 elif m == "/Simple":
                     self.issimple = True
             self.props = [ClassProp(p) for p in decl[3]]
-        
+
         if not customname and self.wname.startswith("Cv"):
             self.wname = self.wname[2:]
-        
+
     def gen_map_code(self, all_classes):
         code = "static bool pyopencv_to(PyObject* src, %s& dst, const char* name)\n{\n    PyObject* tmp;\n    bool ok;\n" % (self.cname)
         code += "".join([gen_template_set_prop_from_map.substitute(propname=p.name,proptype=p.tp) for p in self.props])
@@ -241,21 +244,21 @@ class ClassInfo(object):
         else:
             code += "\n    return true;\n}\n"
         return code
-        
+
     def gen_code(self, all_classes):
         if self.ismap:
             return self.gen_map_code(all_classes)
-        
+
         getset_code = cStringIO.StringIO()
         getset_inits = cStringIO.StringIO()
-        
+
         sorted_props = [(p.name, p) for p in self.props]
         sorted_props.sort()
-        
+
         access_op = "->"
         if self.issimple:
             access_op = "."
-        
+
         for pname, p in sorted_props:
             getset_code.write(gen_template_get_prop.substitute(name=self.name, member=pname, membertype=p.tp, access=access_op))
             if p.readonly:
@@ -263,29 +266,29 @@ class ClassInfo(object):
             else:
                 getset_code.write(gen_template_set_prop.substitute(name=self.name, member=pname, membertype=p.tp, access=access_op))
                 getset_inits.write(gen_template_rw_prop_init.substitute(name=self.name, member=pname))
-                
+
         methods_code = cStringIO.StringIO()
         methods_inits = cStringIO.StringIO()
-        
+
         sorted_methods = self.methods.items()
         sorted_methods.sort()
-        
+
         for mname, m in sorted_methods:
             methods_code.write(m.gen_code(all_classes))
             methods_inits.write(m.get_tab_entry())
-        
+
         baseptr = "NULL"
         if self.bases and all_classes.has_key(self.bases[0]):
             baseptr = "&pyopencv_" + all_classes[self.bases[0]].name + "_Type"
-        
+
         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="")
-        
+
         return code
-            
-            
+
+
 class ConstInfo(object):
     def __init__(self, name, val):
         self.cname = name.replace(".", "::")
@@ -295,7 +298,7 @@ class ConstInfo(object):
         self.name = re.sub(r"([a-z])([A-Z])", r"\1_\2", self.name)
         self.name = self.name.upper()
         self.value = val
-     
+
 class ArgInfo(object):
     def __init__(self, arg_tuple):
         self.tp = arg_tuple[0]
@@ -323,7 +326,7 @@ class ArgInfo(object):
                 self.arraycvt = m[2:].strip()
         self.py_inputarg = False
         self.py_outputarg = False
-        
+
     def isbig(self):
         return self.tp == "Mat" or self.tp == "vector_Mat"# or self.tp.startswith("vector")
 
@@ -338,7 +341,7 @@ class FuncVariant(object):
                 self.wname = self.wname[2:]
             else:
                 self.wname = self.classname
-            
+
         self.rettype = decl[1]
         if self.rettype == "void":
             self.rettype = ""
@@ -355,28 +358,28 @@ class FuncVariant(object):
                     self.array_counters[c] = [ainfo.name]
             self.args.append(ainfo)
         self.init_pyproto()
-        
+
     def init_pyproto(self):
         # string representation of argument list, with '[', ']' symbols denoting optional arguments, e.g.
         # "src1, src2[, dst[, mask]]" for cv.add
         argstr = ""
-        
+
         # list of all input arguments of the Python function, with the argument numbers:
         #    [("src1", 0), ("src2", 1), ("dst", 2), ("mask", 3)]
         # we keep an argument number to find the respective argument quickly, because
         # some of the arguments of C function may not present in the Python function (such as array counters)
         # or even go in a different order ("heavy" output parameters of the C function
         # become the first optional input parameters of the Python function, and thus they are placed right after
-        # non-optional input parameters) 
+        # non-optional input parameters)
         arglist = []
-        
+
         # the list of "heavy" output parameters. Heavy parameters are the parameters
         # that can be expensive to allocate each time, such as vectors and matrices (see isbig).
         outarr_list = []
-        
+
         # the list of output parameters. Also includes input/output parameters.
         outlist = []
-        
+
         firstoptarg = 1000000
         argno = -1
         for a in self.args:
@@ -400,12 +403,12 @@ class FuncVariant(object):
                     arglist += outarr_list
                     outarr_list = []
                 arglist.append((a.name, argno))
-                
+
         if outarr_list:
             firstoptarg = min(firstoptarg, len(arglist))
             arglist += outarr_list
         firstoptarg = min(firstoptarg, len(arglist))
-        
+
         noptargs = len(arglist) - firstoptarg
         argnamelist = [aname for aname, argno in arglist]
         argstr = ", ".join(argnamelist[:firstoptarg])
@@ -425,7 +428,7 @@ class FuncVariant(object):
             outstr = ", ".join([o[0] for o in outlist])
         else:
             outstr = "None"
-            
+
         self.py_docstring = "%s(%s) -> %s" % (self.wname, argstr, outstr)
         self.py_noptargs = noptargs
         self.py_arglist = arglist
@@ -444,10 +447,10 @@ class FuncInfo(object):
         self.cname = cname
         self.isconstructor = isconstructor
         self.variants = []
-    
+
     def add_variant(self, decl):
         self.variants.append(FuncVariant(self.classname, self.name, decl, self.isconstructor))
-        
+
     def get_wrapper_name(self):
         name = self.name
         if self.classname:
@@ -457,7 +460,7 @@ class FuncInfo(object):
         else:
             classname = ""
         return "pyopencv_" + classname + name
-    
+
     def get_wrapper_prototype(self):
         full_fname = self.get_wrapper_name()
         if self.classname and not self.isconstructor:
@@ -465,7 +468,7 @@ class FuncInfo(object):
         else:
             self_arg = ""
         return "static PyObject* %s(PyObject* %s, PyObject* args, PyObject* kw)" % (full_fname, self_arg)
-    
+
     def get_tab_entry(self):
         docstring_list = []
         have_empty_constructor = False
@@ -485,11 +488,11 @@ class FuncInfo(object):
             p1 = s.find("(")
             p2 = s.rfind(")")
             docstring_list = [s[:p1+1] + "[" + s[p1+1:p2] + "]" + s[p2:]]
-            
+
         return Template('    {"$py_funcname", (PyCFunction)$wrap_funcname, METH_KEYWORDS, "$py_docstring"},\n'
                         ).substitute(py_funcname = self.variants[0].wname, wrap_funcname=self.get_wrapper_name(),
                                      py_docstring = "  or  ".join(docstring_list))
-        
+
     def gen_code(self, all_classes):
         proto = self.get_wrapper_prototype()
         code = "%s\n{\n" % (proto,)
@@ -560,9 +563,9 @@ class FuncInfo(object):
                         code_decl += "    PyObject* pyobj_%s = NULL;\n" % (a.name,)
                         parse_name = "pyobj_" + a.name
                         code_cvt_list.append("pyopencv_to(pyobj_%s, %s)" % (a.name, a.name))
-                
+
                 all_cargs.append([amapping, parse_name])
-                
+
                 defval = a.defval
                 if not defval:
                     defval = amapping[2]
@@ -630,7 +633,7 @@ class FuncInfo(object):
                     amapping = all_cargs[argno][0]
                     backcvt_arg_list.append("%s(%s)" % (amapping[2], aname))
                 code_ret = "return Py_BuildValue(\"(%s)\", %s)" % \
-                    (fmtspec, ", ".join(["pyopencv_from(" + aname + ")" for aname, argno in v.py_outlist]))                    
+                    (fmtspec, ", ".join(["pyopencv_from(" + aname + ")" for aname, argno in v.py_outlist]))
 
             all_code_variants.append(gen_template_func_body.substitute(code_decl=code_decl,
                 code_parse=code_parse, code_fcall=code_fcall, code_ret=code_ret))
@@ -642,13 +645,13 @@ class FuncInfo(object):
             # 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"
-        return code    
-  
-    
+        return code
+
+
 class PythonWrapperGenerator(object):
     def __init__(self):
         self.clear()
-        
+
     def clear(self):
         self.classes = {}
         self.funcs = {}
@@ -664,20 +667,20 @@ class PythonWrapperGenerator(object):
         classinfo = ClassInfo(name, decl)
         classinfo.decl_idx = self.class_idx
         self.class_idx += 1
-        
+
         if self.classes.has_key(classinfo.name):
             print "Generator error: class %s (cname=%s) already exists" \
                 % (classinfo.name, classinfo.cname)
-            sys.exit(-1) 
+            sys.exit(-1)
         self.classes[classinfo.name] = classinfo
-        
+
     def add_const(self, name, decl):
         constinfo = ConstInfo(name, decl[1])
-        
+
         if self.consts.has_key(constinfo.name):
             print "Generator error: constant %s (cname=%s) already exists" \
                 % (constinfo.name, constinfo.cname)
-            sys.exit(-1) 
+            sys.exit(-1)
         self.consts[constinfo.name] = constinfo
 
     def add_func(self, decl):
@@ -704,7 +707,7 @@ class PythonWrapperGenerator(object):
                 name = m[1:]
                 customname = True
         func_map = self.funcs
-        
+
         if not classname or isconstructor:
             pass
         elif isclassmethod:
@@ -718,24 +721,24 @@ class PythonWrapperGenerator(object):
                 print "Generator error: the class for method %s is missing" % (name,)
                 sys.exit(-1)
             func_map = classinfo.methods
-            
+
         func = func_map.get(name, FuncInfo(classname, name, cname, isconstructor))
         func.add_variant(decl)
         if len(func.variants) == 1:
             func_map[name] = func
-    
+
     def gen_const_reg(self, constinfo):
         self.code_const_reg.write("PUBLISH2(%s,%s);\n" % (constinfo.name, constinfo.cname))
-    
+
     def save(self, path, name, buf):
         f = open(path + "/" + name, "wt")
         f.write(buf.getvalue())
         f.close()
-            
+
     def gen(self, srcfiles, output_path):
         self.clear()
         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)
@@ -753,7 +756,7 @@ class PythonWrapperGenerator(object):
                 else:
                     # function
                     self.add_func(decl)
-        
+
         # step 2: generate code for the classes and their methods
         classlist = self.classes.items()
         classlist.sort()
@@ -766,18 +769,18 @@ class PythonWrapperGenerator(object):
                 else:
                     templ = gen_template_type_decl
                 self.code_types.write(templ.substitute(name=name, wname=classinfo.wname, cname=classinfo.cname))
-        
+
         # register classes in the same order as they have been declared.
         # this way, base classes will be registered in Python before their derivatives.
         classlist1 = [(classinfo.decl_idx, name, classinfo) for name, classinfo in classlist]
         classlist1.sort()
-        
+
         for decl_idx, name, classinfo in classlist1:
             code = classinfo.gen_code(self.classes)
             self.code_types.write(code)
             if not classinfo.ismap:
                 self.code_type_reg.write("MKTYPE2(%s);\n" % (classinfo.name,) )
-            
+
         # step 3: generate the code for all the global functions
         funclist = self.funcs.items()
         funclist.sort()
@@ -785,13 +788,13 @@ class PythonWrapperGenerator(object):
             code = func.gen_code(self.classes)
             self.code_funcs.write(code)
             self.code_func_tab.write(func.get_tab_entry())
-            
+
         # step 4: generate the code for constants
         constlist = self.consts.items()
         constlist.sort()
         for name, constinfo in constlist:
             self.gen_const_reg(constinfo)
-            
+
         # That's it. Now save all the files
         self.save(output_path, "pyopencv_generated_funcs.h", self.code_funcs)
         self.save(output_path, "pyopencv_generated_func_tab.h", self.code_func_tab)
@@ -809,5 +812,5 @@ if __name__ == "__main__":
     generator = PythonWrapperGenerator()
     generator.gen(srcfiles, dstdir)
 
-    
-    
+
+