Ejemplo n.º 1
0
    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
Ejemplo n.º 2
0
    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
Ejemplo n.º 3
0
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
Ejemplo n.º 5
0
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
Ejemplo n.º 6
0
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