def parse_multiple_files(pxdfiles, comp_name): def cimport(b, _, __): print "cimport", b.module_name, "as", b.as_name handlers = { CEnumDefNode: EnumDecl.parseTree, CppClassNode: CppClassDecl.parseTree, CTypeDefNode: CTypeDefDecl.parseTree, CVarDefNode: MethodOrAttributeDecl.parseTree, CImportStatNode: cimport, } found = False # Go through all files and all classes in those files, trying to find # the class whose C/C++ name matches the current compound name for pxdfile in pxdfiles: cython_file = parse_pxd_file(pxdfile) for klass in cython_file: if hasattr(klass[0], "cname"): if klass[0].cname == comp_name: found = True if found: break if found: break if not found: error_str = "Could not find a match for class %s in file %s" % (comp_name, pxdfile) raise PXDFileParseError(error_str) # Check if we really have a class, then initialize it if isinstance(klass[0], CppClassNode): cl = CppClassDecl.parseTree(klass[0], klass[1], klass[2]) else: print "Something is wrong, not a class" raise PXDFileParseError("wrong") cl.pxdfile = pxdfile for klass in cython_file: handler = handlers.get(type(klass[0])) res = handler(klass[0], klass[1], klass[2]) if res.annotations.has_key("wrap-attach"): if res.annotations["wrap-attach"] == cl.name: ## attach this to the above class cl.methods[res.name] = res return cl
def parse_multiple_files(pxdfiles, comp_name): def cimport(b, _, __): print "cimport", b.module_name, "as", b.as_name handlers = { CEnumDefNode: EnumDecl.parseTree, CppClassNode: CppClassDecl.parseTree, CTypeDefNode: CTypeDefDecl.parseTree, CVarDefNode: MethodOrAttributeDecl.parseTree, CImportStatNode: cimport, } found = False # Go through all files and all classes in those files, trying to find # the class whose C/C++ name matches the current compound name for pxdfile in pxdfiles: cython_file = parse_pxd_file(pxdfile) for klass in cython_file: if hasattr(klass[0], "cname"): if klass[0].cname == comp_name: found = True if found: break if found: break if not found: error_str = "Could not find a match for class %s in file %s" % ( comp_name, pxdfile) raise PXDFileParseError(error_str) # Check if we really have a class, then initialize it if isinstance(klass[0], CppClassNode): cl = CppClassDecl.parseTree(klass[0], klass[1], klass[2]) else: print "Something is wrong, not a class" raise PXDFileParseError("wrong") cl.pxdfile = pxdfile for klass in cython_file: handler = handlers.get(type(klass[0])) res = handler(klass[0], klass[1], klass[2]) if res.annotations.has_key("wrap-attach"): if res.annotations["wrap-attach"] == cl.name: ## attach this to the above class cl.methods[res.name] = res return cl
def handle_member_definition(mdef, pxd_class, cnt): """ Matches a doxygen member definition (mdef) to a Cython pxd file. """ tres = TestResult() protection = mdef.get_prot( ) # DoxProtectionKind: public, protected, private, package kind = mdef.get_kind( ) # DoxMemberKind: define property event variable typedef enum function signal prototype friend dcop slot if not protection in "public protected private package".split(" "): raise Exception("Error; something is wrong") if not kind in "define property event variable typedef enum function signal prototype friend dcop slot".split( " "): raise Exception("Error; something is wrong") if kind == "enum" and protection == "public": cnt.public_enums_total += 1 cython_file = parse_pxd_file(pxd_class.pxd_path) found = False for klass in cython_file: if hasattr(klass[0], "name") and klass[0].name == mdef.get_name(): found = True break if not found: tres.setPassed(False) tres.setMessage( "TODO: Found enum in C++ but not in pxd: %s %s %s" % (mdef.kind, mdef.prot, mdef.name)) cnt.public_enums_missing += 1 comp_name = mdef.parent_doxy_file.compound.get_compoundname() file_location = mdef.parent_doxy_file.getCompoundFileLocation() internal_file_name = "OpenMS" + file_location.split( "/include/OpenMS")[1] namespace = comp_name true_cppname = '"%s::%s"' % (comp_name, mdef.get_name()) enumr = "\n" enumr += 'cdef extern from "<%s>" namespace "%s":\n' % ( internal_file_name, namespace) enumr += " \n" enumr += ' cdef enum %s %s:\n' % (mdef.get_name(), true_cppname) for val in mdef.get_enumvalue(): enumr += " %s\n" % val.get_name() tres.setMessage(tres.getMessage() + enumr) elif len(klass[0].items) != len(mdef.get_enumvalue()): tres.setPassed(False) tres.setMessage( "TODO: Found enum in C++ with %s members but in Cython there are %s members: " % (len(mdef.get_enumvalue()), len(klass[0].items))) else: tres.setPassed(True) elif kind == "variable" and protection == "public": attrnames = [a.name for a in pxd_class.attributes] cnt.public_variables += 1 if not mdef.name in attrnames: tres.setPassed(False) tres.setMessage( "TODO: Found attribute in C++ but not in pxd: %s %s %s" % (mdef.kind, mdef.prot, mdef.name)) cnt.public_variables_missing += 1 else: tres.setPassed(True) elif kind == "function" and protection == "public": # Wrap of public member functions ... cnt.public_methods += 1 c_return_type = mdef.resolve_return_type() if mdef.name in pxd_class.methods: # Found match between C++ method and Python method py_methods = pxd_class.methods[mdef.name] if not isinstance(py_methods, list): py_methods = [py_methods] py_return_type = [str(d.result_type) for d in py_methods] if mdef.definition == mdef.name: # Constructor, no return type -> all is good assert len(c_return_type) == 0 tres.setPassed(True) elif "void" in py_return_type and not "void" in c_return_type: tres.setPassed(False) tres.setMessage( "TODO: Mismatch between C++ return type (%s) and Python return type (%s) in %s %s %s:" % (str(c_return_type), str(py_return_type), mdef.kind, mdef.prot, mdef.name)) else: tres.setPassed(True) else: cnt.public_methods_missing += 1 if mdef.name.find("~") != -1: # destructor cnt.public_methods_missing_nowrapping += 1 tres.setPassed(True) tres.setMessage("Cannot wrap destructor") elif (mdef.name.find("operator") != -1 or mdef.name.find("begin") != -1 or mdef.name.find("end") != -1): cnt.public_methods_missing_nowrapping += 1 tres.setPassed(True) tres.setMessage( "Cannot wrap method with iterator/operator %s" % mdef.name) else: tres.setPassed(False) tres.setMessage( " -- TODO missing function in PXD: %s nogil except +" % mdef.format_definition_for_cython()) else: # It is neither public function/enum/variable tres.setPassed(True) # Return the testresult return tres
def handle_member_definition(mdef, pxd_class, cnt): """ Matches a doxygen member definition (mdef) to a Cython pxd file. """ tres = TestResult() protection = mdef.get_prot() # DoxProtectionKind: public, protected, private, package kind = mdef.get_kind() # DoxMemberKind: define property event variable typedef enum function signal prototype friend dcop slot if not protection in "public protected private package".split(" "): raise Exception("Error; something is wrong") if not kind in "define property event variable typedef enum function signal prototype friend dcop slot".split(" "): raise Exception("Error; something is wrong") if kind == "enum" and protection == "public": cnt.public_enums_total += 1 cython_file = parse_pxd_file(pxd_class.pxd_path) found = False for klass in cython_file: if hasattr(klass[0], "name") and klass[0].name == mdef.get_name(): found = True break if not found: tres.setPassed(False) tres.setMessage("TODO: Found enum in C++ but not in pxd: %s %s %s" % (mdef.kind, mdef.prot, mdef.name)) cnt.public_enums_missing += 1 comp_name = mdef.parent_doxy_file.compound.get_compoundname() file_location = mdef.parent_doxy_file.getCompoundFileLocation() internal_file_name = "OpenMS" + file_location.split("/include/OpenMS")[1] namespace = comp_name true_cppname = '"%s::%s"' % (comp_name, mdef.get_name()) enumr = "\n" enumr += 'cdef extern from "<%s>" namespace "%s":\n' % (internal_file_name, namespace) enumr += " \n" enumr += ' cdef enum %s %s:\n' % (mdef.get_name(), true_cppname) for val in mdef.get_enumvalue(): enumr += " %s\n" % val.get_name() tres.setMessage(tres.getMessage() + enumr) elif len(klass[0].items) != len(mdef.get_enumvalue()): tres.setPassed(False) tres.setMessage("TODO: Found enum in C++ with %s members but in Cython there are %s members: " % ( len(mdef.get_enumvalue()), len(klass[0].items) ) ) else: tres.setPassed(True) elif kind == "variable" and protection == "public": attrnames = [a.name for a in pxd_class.attributes] cnt.public_variables += 1 if not mdef.name in attrnames: tres.setPassed(False) tres.setMessage("TODO: Found attribute in C++ but not in pxd: %s %s %s" % (mdef.kind, mdef.prot, mdef.name) ) cnt.public_variables_missing += 1 else: tres.setPassed(True) elif kind == "function" and protection == "public": # Wrap of public member functions ... cnt.public_methods += 1 c_return_type = mdef.resolve_return_type() if mdef.name in pxd_class.methods: # Found match between C++ method and Python method py_methods = pxd_class.methods[mdef.name] if not isinstance(py_methods, list): py_methods = [py_methods] py_return_type = [str(d.result_type) for d in py_methods] if mdef.definition == mdef.name: # Constructor, no return type -> all is good assert len(c_return_type) == 0 tres.setPassed(True) elif "void" in py_return_type and not "void" in c_return_type: tres.setPassed(False) tres.setMessage( "TODO: Mismatch between C++ return type (%s) and Python return type (%s) in %s %s %s:" % ( str(c_return_type), str(py_return_type), mdef.kind, mdef.prot, mdef.name) ) else: tres.setPassed(True) else: cnt.public_methods_missing += 1 if mdef.name.find("~") != -1: # destructor cnt.public_methods_missing_nowrapping += 1 tres.setPassed(True) tres.setMessage("Cannot wrap destructor") elif (mdef.name.find("operator") != -1 or mdef.name.find("begin") != -1 or mdef.name.find("end") != -1): cnt.public_methods_missing_nowrapping += 1 tres.setPassed(True) tres.setMessage("Cannot wrap method with iterator/operator %s" % mdef.name) else: tres.setPassed(False) tres.setMessage(" -- TODO missing function in PXD: %s nogil except +" % mdef.format_definition_for_cython()) else: # It is neither public function/enum/variable tres.setPassed(True) # Return the testresult return tres
def handle_member_definition(mdef, pxd_class, cnt): """ Matches a doxygen member definition (mdef) to a Cython pxd file. This tries to ensure that all C++ functions are wrapped and have an equivalent in the Python wrapper. Parameters ---------- mdef : breathe.parser.compound.memberdefTypeSub A doxygen entry pxd_class : autowrap.PXDParser.CppClassDecl A PXD class file as parsed by autowrap cnt : A count object to keep track of how many functions we wrapped """ pxd_class_methods_str = str([ str(m) for m in pxd_class.methods.keys()]) tres = TestResult() protection = mdef.get_prot() # DoxProtectionKind: public, protected, private, package kind = mdef.get_kind() # DoxMemberKind: define property event variable typedef enum function signal prototype friend dcop slot if not protection in "public protected private package".split(" "): raise Exception("Error; something is wrong") if not kind in "define property event variable typedef enum function signal prototype friend dcop slot".split(" "): raise Exception("Error; something is wrong") if kind == "enum" and protection == "public": cnt.public_enums_total += 1 cython_file = parse_pxd_file(pxd_class.pxd_path) found = False for klass in cython_file: if hasattr(klass[0], "name") and klass[0].name == mdef.get_name(): found = True break # Sometimes we rename things in pyOpenMS for sanity (and namespace consistency) sake # E.g. OpenMS::PercolatorOutfile::ScoreType becomes PercolatorOutfile_ScoreType # and we have to go back to the full cname. However, the doxygen name needs to be inferred if hasattr(klass[0], "cname") and klass[0].cname.endswith(mdef.get_name()): assumed_fullname = mdef.compoundname + "::" + mdef.get_name() if (assumed_fullname == klass[0].cname): found = True break else: print "Something went wrong, %s is not equal to %s" % (assumed_fullname, klass[0].cname) if not found: tres.setPassed(False) tres.setMessage("TODO: Found enum in C++ but not in pxd: %s %s %s" % (mdef.kind, mdef.prot, mdef.name)) cnt.public_enums_missing += 1 comp_name = mdef.parent_doxy_file.compound.get_compoundname() file_location = mdef.parent_doxy_file.getCompoundFileLocation() if (len(file_location.split("/include/OpenMS")) > 1): internal_file_name = "OpenMS" + file_location.split("/include/OpenMS")[1] elif (len(file_location.split("/OpenMS")) > 1): internal_file_name = "OpenMS" + file_location.split("/OpenMS")[1] namespace = comp_name true_cppname = '"%s::%s"' % (comp_name, mdef.get_name()) enumr = "\n" enumr += 'cdef extern from "<%s>" namespace "%s":\n' % (internal_file_name, namespace) enumr += " \n" enumr += ' cdef enum %s %s:\n' % (mdef.get_name(), true_cppname) for val in mdef.get_enumvalue(): enumr += " %s\n" % val.get_name() tres.setMessage(tres.getMessage() + enumr) elif len(klass[0].items) != len(mdef.get_enumvalue()): tres.setPassed(False) tres.setMessage("TODO: Found enum in C++ with %s members but in Cython there are %s members: " % ( len(mdef.get_enumvalue()), len(klass[0].items) ) ) else: tres.setPassed(True) elif kind == "variable" and protection == "public": attrnames = [a.name for a in pxd_class.attributes] cnt.public_variables += 1 if not mdef.name in attrnames: tres.setPassed(False) tres.setMessage("TODO: Found attribute in C++ but not in pxd: %s %s %s" % (mdef.kind, mdef.prot, mdef.name) ) cnt.public_variables_missing += 1 else: tres.setPassed(True) elif kind == "function" and protection == "public": # Wrap of public member functions ... cnt.public_methods += 1 c_return_type = mdef.resolve_return_type() if mdef.name in pxd_class.methods: # Found match between C++ method and Python method py_methods = pxd_class.methods[mdef.name] if not isinstance(py_methods, list): py_methods = [py_methods] py_return_type = [str(d.result_type) for d in py_methods] if mdef.definition == mdef.name: # Constructor, no return type -> all is good assert len(c_return_type) == 0 tres.setPassed(True) elif "void" in py_return_type and not "void" in c_return_type: tres.setPassed(False) tres.setMessage( "TODO: Mismatch between C++ return type (%s) and Python return type (%s) in %s %s %s:" % ( str(c_return_type), str(py_return_type), mdef.kind, mdef.prot, mdef.name) ) else: tres.setPassed(True) else: cnt.public_methods_missing += 1 if mdef.name.find("~") != -1: # destructor cnt.public_methods_missing_nowrapping += 1 tres.setPassed(True) tres.setMessage("Cannot wrap destructor") elif (mdef.name.find("operator") != -1 or mdef.name.find("begin") != -1 or mdef.name.find("end") != -1): cnt.public_methods_missing_nowrapping += 1 tres.setPassed(True) tres.setMessage("Cannot wrap method with iterator/operator %s" % mdef.name) else: tres.setPassed(False) tres.setMessage(" -- TODO missing function in PXD: %s nogil except +" % mdef.format_definition_for_cython()) else: # It is neither public function/enum/variable tres.setPassed(True) # Return the testresult return tres