Best Python code snippet using Airtest
doxygen2rst.py
Source:doxygen2rst.py  
1from __future__ import print_function2import re, sys, os, time, glob, errno, tempfile, binascii, subprocess, shutil3from lxml import etree4from optparse import OptionParser5import textwrap6import string7VERSION = '0.1'8__all__ = ['DoxyGen2RST']9LINE_BREAKER = "\n"10MAX_COLUMN = 8011def is_valid_uuid(uuid_string):12    uuid4hex = re.compile('[0-9a-f]{32}\Z', re.I)13    return uuid4hex.match(uuid_string) != None14def get_page(refid):15    fields = refid.split("_")16    if(is_valid_uuid(fields[-1][-32:])):17        return ["_".join(fields[0:-1]), fields[-1]]18    return [refid, None]19def mkdir_p(path):20    try:21        os.makedirs(path)22    except OSError as exc: # Python >2.523        if exc.errno == errno.EEXIST and os.path.isdir(path):24            pass25        else:26            raise27def _glob(path, *exts):28    path = os.path.join(path, "*") if os.path.isdir(path) else path + "*"29    return [f for files in [glob.glob(path + ext) for ext in exts] for f in files]30class DoxyGen2RST(object):31    """32    Customize the Doxygen XML output into RST format, then it can33    be translated into all formats with the unified user interface.34    The Doxygen output itself is too verbose and not hard to be35    organized for a good documentation.36    """37    def __init__(self,38                 src,39                 dst,40                 missing_filename = "missing.rst",41                 is_github = False,42                 enable_uml = True,43                 github_ext = ""):44        self.doxy_output_dir = os.path.join(src, "_doxygen", "xml")45        self.output_dir = dst46        self.rst_dir = src47        self.enable_uml = enable_uml48        mkdir_p(dst)49        self.is_github = is_github50        if(is_github):51            self.page_ext = github_ext52            self.anchor_prefix = "wiki-"53        else:54            self.anchor_prefix = ""55            self.page_ext = ".html"56        self.filter = ["*.rst", "*.rest"]57        self.re_doxy = "<doxygen2rst\s(\S*)=(\S*)>(.*?)</doxygen2rst>"58        self.index_root = etree.parse(os.path.join(self.doxy_output_dir, "index.xml")).getroot()59        self.references = {}60        self.missed_types_structs = {}61        self.name_refid_map = {}62        self.build_references()63        self.page_references = {}64        self.missing_filename = missing_filename65        self.temp_uml_path = os.path.join(tempfile.gettempdir(), "uml_" + binascii.b2a_hex(os.urandom(15)))66        if os.path.exists(self.temp_uml_path):67            shutil.rmtree(self.temp_uml_path)68        os.mkdir(self.temp_uml_path)69    def _find_ref_id(self, kind, name):70        #print("_find_ref_id, %s - %s" %(kind, name))71        if(kind == "function"):72            for comp in self.index_root.iter("member"):73                if(comp.attrib["kind"].lower() == kind.lower() and74                   comp.findtext("name").lower() == name.lower()):75                    return (comp.attrib["refid"])76            pass77        else:78            for comp in self.index_root.iter("compound"):79                if(comp.attrib["kind"].lower() == kind.lower() and80                   comp.findtext("name").lower() == name.lower()):81                   return comp.attrib["refid"]82        return None83    def strip_title_ref(self, text):84        table = string.maketrans("","")85        retstr = text.translate(table, string.punctuation)86        words = retstr.split()87        retstr = "-".join(words)88        return retstr.lower()89    def build_references(self):90        for file in _glob(self.rst_dir, *self.filter):91            filename = os.path.basename(file)92            fin = open(file,'r')93            content = fin.read()94            it = re.finditer(self.re_doxy, content, re.DOTALL)95            for m in it:96                ref_id = self._find_ref_id(m.groups()[0], m.groups()[1])97                if(ref_id is None):98                    #print("Reference is NOT found for: %s=%s" % (m.groups()[0], m.groups()[1]))99                    continue100                page_name = os.path.splitext(filename)[0]101                title_ref = self.strip_title_ref(m.groups()[2])102                self.references[ref_id] = [m.groups()[0], m.groups()[1], page_name, filename, title_ref]103                self.name_refid_map[m.groups()[1]] = ref_id104            fin.close()105        #print(self.references)106    def call_plantuml(self):107        if(not self.enable_uml):108            return109        java_bin = os.path.join(os.environ['JAVA_HOME'], "bin", "java")110        output_path = os.path.abspath(os.path.join(self.output_dir, "images"))111        cmds = ["\"" + java_bin + "\"", "-jar", "plantuml.jar", self.temp_uml_path + "/", "-o", output_path]112        print(" ".join(cmds))113        os.system(" ".join(cmds))114        shutil.rmtree(self.temp_uml_path)115    def _build_uml(self, uml_name, content):116        uml_path = os.path.join(self.temp_uml_path, uml_name + ".txt")117        fuml = open(uml_path, "w+")118        fuml.write("@startuml\n")119        fuml.write(content)120        fuml.write("\n@enduml\n")121        fuml.close()122        return ".. image:: images/" + uml_name + ".png" + LINE_BREAKER123    def _build(self, m):124        retstr = ""125        if(m.groups()[0] == "uml"):126            retstr = self._build_uml(m.groups()[1], m.groups()[2])127        elif(m.groups()[0] == "link"):128            link = m.groups()[1] + self.page_ext129            retstr = ("`%s <%s>`_" % (m.groups()[2], link))130        else:131            if(m.groups()[0] != "function"):132                retstr +=  self._build_title(m.groups()[2])133            retstr += self.convert_doxy(m.groups()[0], m.groups()[1])134        return retstr135    def generate(self):136        for file in _glob(self.rst_dir, *self.filter):137            filename = os.path.basename(file)138            fin = open(file,'r')139            input_txt = fin.read()140            fin.close()141            output_txt = re.sub(self.re_doxy, self._build, input_txt, 0, re.DOTALL)142            output_txt  += self._build_page_ref_notes()143            fout = open(os.path.join(self.output_dir, filename), 'w+')144            fout.write(output_txt)145            fout.close()146            #print("%s --- %s" %( file, os.path.join(self.output_dir, filename)))147        self._build_missed_types_and_structs()148        self.call_plantuml()149    def make_para_title(self, title,  indent = 4):150        retstr = LINE_BREAKER151        if(title):152            retstr += "".ljust(indent, " ") + "| **" + title + "**" +  LINE_BREAKER153        return retstr154    def _build_title(self, title, flag = '=', ref = None):155        retstr = LINE_BREAKER156        if(ref):157            retstr += ".. _ref-" + ref + ":" + LINE_BREAKER + LINE_BREAKER158        retstr += title + LINE_BREAKER159        retstr += "".ljust(20, flag) + LINE_BREAKER160        retstr += LINE_BREAKER161        return retstr162    def _build_ref(self, node):163        text = node.text.strip()164        retstr = ""165        target = '`' + text + '`'166        retstr += target + "_ "167        if target in self.page_references:168            reflink = self.page_references[target]169            print("Link already added: %s == %s" % (reflink[0], node.attrib["refid"]))170            assert(reflink[0] == node.attrib["refid"])171            pass172        else:173            self.page_references[target] = (node.attrib["refid"], node.attrib["kindref"], text)174        return retstr175    def _build_code_block(self, node):176        retstr = "::" + LINE_BREAKER + LINE_BREAKER177        for codeline in node.iter("codeline"):178            retstr += "  "179            for phrases in codeline.iter("highlight"):180                if(phrases.text):181                    retstr += phrases.text.strip()182                for child in phrases:183                    if(child.text):184                        retstr += child.text.strip()185                    if(child.tag == "sp"):186                        retstr += " "187                    if(child.tag == "ref" and child.text):188                        #escape the reference in the code block189                        retstr += "" # self._build_ref(child)190                    if(child.tail):191                        retstr += child.tail.strip()192            retstr += LINE_BREAKER193        return retstr194    def _build_itemlist(self, node):195        retstr = ""196        for para in node:197            if(para.tag != "para"):198                continue199            if(para.text):200                retstr += para.text.strip()201            for child in para:202                if(child.tag == "ref" and child.text):203                    retstr += self._build_ref(child)204                if(child.tail):205                    retstr += child.tail.strip()206        return retstr207    def _build_itemizedlist(self, node):208        retstr = LINE_BREAKER209        if(node == None):210            return ""211        for item in node:212            if(item.tag != "listitem"):213                continue214            retstr += "    - " + self._build_itemlist(item)215            retstr += LINE_BREAKER216        return retstr217    def _build_verbatim(self, node):218        retstr = LINE_BREAKER219        if(node.text):220            lines = node.text.splitlines()221            print(lines[0])222            m = re.search("{plantuml}\s(\S*)", lines[0])223            if(m):224                uml_name = "uml_" + m.groups()[0]225                retstr += self._build_uml(uml_name, "\n".join(lines[1:]))226            else:227                retstr += "::" + LINE_BREAKER + LINE_BREAKER228                retstr += node.text229        return retstr230    def _build_para(self, para):231        retstr = ""232        no_new_line = False233        if(para.text):234            retstr += textwrap.fill(para.text.strip(), MAX_COLUMN) + LINE_BREAKER + LINE_BREAKER235        for child in para:236            no_new_line = False237            if(child.tag == "simplesect"):238                for child_para in child:239                    if(child.attrib["kind"] == "return"):240                        return_str = self._build_para(child_para)241                        retstr += "".ljust(4, " ") + "| Return:" + LINE_BREAKER242                        for line in return_str.splitlines():243                            retstr += "".ljust(4, " ") + "| " + line + LINE_BREAKER244                    elif(child_para.tag == "title" and child_para.text):245                        lf.make_para_title(child_para.text.strip(), 4)246                    elif(child_para.tag == "para"): #for @see247                        retstr += self._build_para(child_para)248                    elif(child_para.text):249                        retstr += "".ljust(4, " ") + "| " + child_para.text.strip() + LINE_BREAKER250            if(child.tag == "preformatted"):251                retstr += "::" + LINE_BREAKER + LINE_BREAKER252                if(child.text):253                    for line in child.text.splitlines():254                        retstr += "  " + line + LINE_BREAKER255            if(child.tag == "ref" and child.text):256                retstr = retstr.rstrip('\n')257                retstr += " " + self._build_ref(child)258                no_new_line = True259            if(child.tag == "programlisting"):260                retstr += self._build_code_block(child)261            if(child.tag == "itemizedlist"):262                retstr += self._build_itemizedlist(child)263            if(child.tag == "verbatim"):264                retstr += self._build_verbatim(child)265            if(not no_new_line):266                retstr += LINE_BREAKER267            if(child.tail):268                retstr += textwrap.fill(child.tail.strip(), MAX_COLUMN) + LINE_BREAKER + LINE_BREAKER269        return retstr270    def get_text(self, node):271        retstr = ""272        if(node == None):273            return ""274        for para in node:275            if(para.tag != "para"):276                continue277            retstr += self._build_para(para)278        return retstr279    def _find_text_ref(self, node):280        retstr = ""281        if(node.text):282            retstr += node.text.strip()283        for child in node:284            if(child.tag == "ref"):285                retstr += " " + self._build_ref(child) + " "286            if(child.tail):287                retstr += child.tail.strip()288        return retstr289    def _build_row_breaker(self, columns):290        retstr = "+"291        for column in columns:292            retstr += "".ljust(column, "-") + "+"293        return retstr + LINE_BREAKER294    def _wrap_cell(self, text, length = 30):295        newlines = []296        for line in text.splitlines():297            newlines.extend(textwrap.wrap(line, length))298        return newlines299    def _build_row(self, row, columns):300        retstr = ""301        row_lines = []302        max_line = 0303        for i in range(3):304            row_lines.append(row[i].splitlines())305            if(max_line < len(row_lines[i])):306                max_line = len(row_lines[i])307        for i in range(max_line):308            for j in range(3):309                retstr += "|"310                if(len(row_lines[j]) > i):311                    retstr += row_lines[j][i]312                    retstr += "".ljust(columns[j] - len(row_lines[j][i]), " ")313                else:314                    retstr += "".ljust(columns[j], " ")315            retstr += "|" + LINE_BREAKER316        return retstr317    def _build_table(self, rows):318        retstr = ""319        columns = [0, 0, 0]320        for row in rows:321            for i in range(3):322                for rowline in row[i].splitlines():323                    if(columns[i] < len(rowline) + 2):324                        columns[i] = len(rowline) + 2325        #columns[0] = 40 if(columns[0] > 40) else columns[0]326        #columns[1] = 40 if(columns[1] > 40) else columns[1]327        #columns[2] = MAX_COLUMN - columns[0] - columns[1]328        retstr += self._build_row_breaker(columns)329        for row in rows:330            retstr += self._build_row(row, columns)331            retstr += self._build_row_breaker(columns)332        return retstr;333    def build_param_list(self, params, paramdescs):334        retstr = ""335        param_descriptions = []336        for desc in paramdescs:337            param_descriptions.append(desc)338        rows = []339        rows.append(("Name", "Type", "Descritpion"))340        for param in params:341            declname = param.findtext("declname")342            paramdesc = None343            for desc in param_descriptions:344                paramname = desc.findtext("parameternamelist/parametername")345                if(paramname.lower() == declname.lower()):346                    paramdesc = desc.find("parameterdescription")347                    break348            decltype = self._find_text_ref(param.find("type"))349            rows.append((declname, decltype, self.get_text(paramdesc)))350        if(len(rows) > 1):351            retstr += self._build_table(rows)352        return retstr353    def _build_enum(self, member):354        enum_id = member.attrib["id"]355        file, tag = get_page(enum_id)356        retstr = self._build_title(member.findtext("name"), ref = tag)357        detail_node = self.get_desc_node(member)358        if(detail_node is not None):359            retstr += LINE_BREAKER360            retstr += self.get_text(detail_node)361        rows = []362        rows.append(("Name", "Initializer", "Descritpion"))363        for enumvalue in member.iter("enumvalue"):364            name = enumvalue.findtext("name")365            initializer = enumvalue.findtext("initializer")366            if(not initializer):367                initializer = ""368            desc = self.get_text(enumvalue.find("briefdescription"))369            desc += self.get_text(enumvalue.find("detaileddescription"))370            if(not desc):371                desc = ""372            rows.append((name, initializer, desc))373        if(len(rows) > 1):374            retstr += self._build_table(rows)375        return retstr376    def _build_struct(self, node):377        retstr = ""378        detail_node = self.get_desc_node(node)379        if(detail_node is not None):380            retstr += self.get_text(detail_node) + LINE_BREAKER381        rows = []382        rows.append(("Name", "Type", "Descritpion"))383        for member in node.iter("memberdef"):384            if(member.attrib["kind"] == "variable"):385                name = member.findtext("name")386                type = self._find_text_ref(member.find("type"))387                desc = self.get_text(member.find("briefdescription"))388                desc += self.get_text(member.find("detaileddescription"))389                desc += self.get_text(member.find("inbodydescription"))390                if(not desc):391                    desc = ""392                rows.append((name, type, desc))393        if(len(rows) > 1):394            retstr += self._build_table(rows)395        return retstr396    def _build_class(self, node):397        retstr = ""398        for member in node.iter("memberdef"):399            if(member.attrib["kind"] == "function"):400                retstr += self.build_function(member)401        return retstr402    def get_desc_node(self, member):403        detail_node = member.find("detaileddescription")404        brief_node = member.find("briefdescription")405        detail_txt = ""406        if(detail_node == None and brief_node == None):407            return None408        if(detail_node is not None):409            detail_txt = detail_node.findtext("para")410        if(not detail_txt and brief_node != None):411            detail_txt = brief_node.findtext("para")412            detail_node = brief_node413        return detail_node414    def build_function(self, member):415        retstr = ""416        desc_node = self.get_desc_node(member)417        if(desc_node is None):418            return ""419        detail_txt = desc_node.findtext("para")420        if(not detail_txt or detail_txt.strip() == "{ignore}"):421            return ""422        func_id = member.attrib["id"]423        page_id, ref_id = get_page(func_id)424        retstr += self._build_title(member.findtext("name"), '-', ref = ref_id)425        retstr += self.get_text(desc_node)426        retstr += LINE_BREAKER427        detail_node = member.find("detaileddescription")428        if(desc_node != detail_node):429            retstr += self.get_text(detail_node)430        retstr += self.build_param_list(member.iter("param"), detail_node.iter("parameteritem"))431        return retstr432    def _build_missed_types_and_structs(self):433        fout = open(os.path.join(self.output_dir, self.missing_filename), 'w+')434        fout.write(".. contents:: " + LINE_BREAKER)435        fout.write("    :local:"  + LINE_BREAKER)436        fout.write("    :depth: 2" + LINE_BREAKER + LINE_BREAKER)437        footnote = ""438        while (len(self.missed_types_structs) > 0):439            for key, value in self.missed_types_structs.iteritems():440                fout.write(self.covert_item(value[0], key, value[1]))441                #print(value)442            self.missed_types_structs = {}443            footnote += self._build_page_ref_notes()444        fout.write(footnote)445        fout.close()446    def _build_page_ref_notes(self):447        retstr = LINE_BREAKER448        #TODO449        for key, value in self.page_references.iteritems():450            page, tag = get_page(value[0])451            m = re.search("_8h_", page)452            if(m):453                continue;454            rstname = None455            anchor = value[2].lower()456            if not page in self.references:457                self.missed_types_structs[value[0]] = (page, tag)458                rstname = os.path.splitext(self.missing_filename)[0]459            else:460                rstname = self.references[page][2]461                anchor = self.references[page][4]462            #if(tag and not self.is_github):463            #    anchor = self.anchor_prefix + "ref-" + tag464            retstr += ".. _" + key + ": " + rstname + self.page_ext + "#" + anchor465            retstr += LINE_BREAKER + LINE_BREAKER466        self.page_references = {}467        return retstr468    def _build_item_by_id(self, node, id):469        retstr = ""470        for member in node.iter("memberdef"):471            if(member.attrib["id"] != id):472                continue473            if(member.attrib["kind"] == "enum"):474                retstr += self._build_enum(member)475        return retstr476    def covert_item(self, compound, id, tag):477        xml_path = os.path.join(self.doxy_output_dir, "%s.xml" % compound)478        print("covert_item: id=%s, name=%s" % (id, xml_path))479        obj_root = etree.parse(xml_path).getroot()480        retstr = ""481        compound = obj_root.find("compounddef")482        compound_kind = compound.attrib["kind"]483        if(not tag):484            retstr += self._build_title(compound.findtext("compoundname"))485            if(compound_kind == "class"):486                retstr += self._build_class(compound)487            elif(compound_kind == "struct"):488                retstr += self._build_struct(compound)489        else:490            retstr += self._build_item_by_id(compound, id)491        return retstr492    def _build_page(self, compound):493        retstr = ""494        retstr += self.get_text(compound.find("detaileddescription"))495        return retstr496    def _build_file(self, compound, type, ref_id, name):497        retstr = ""498        for member in compound.iter("memberdef"):499            if(member.attrib["kind"] == "function" and member.attrib["id"] == ref_id):500                retstr += self.build_function(member)501        return retstr502    def convert_doxy(self, type, name):503        #print(name)504        file = ref_id = self.name_refid_map[name]505        dst_kind = type506        if(type == "function"):507            file, tag = get_page(ref_id)508            dst_kind = "file"509        xml_path = os.path.join(self.doxy_output_dir, "%s.xml" % file)510        print("convert_doxy: type=%s, name=%s" % (type, xml_path))511        obj_root = etree.parse(xml_path).getroot()512        compound = obj_root.find("compounddef")513        compound_kind = compound.attrib["kind"]514        assert(dst_kind == compound_kind)515        retstr = ""516        if(compound_kind == "class"):517            retstr += self._build_class(compound)518        elif(compound_kind == "struct"):519            retstr += self._build_struct(compound)520        elif(compound_kind == "page"):521            retstr += self._build_page(compound)522        elif(compound_kind == "group"):523            retstr += self._build_page(compound)524        elif(compound_kind == "file"):525            retstr += self._build_file(compound, type, ref_id, name)526        return retstr527if __name__ == '__main__':528    import argparse529    parser = argparse.ArgumentParser()530    parser.add_argument("-g", "--github", action="store_true", help="Render the link in format of github wiki.")531    parser.add_argument("-e", "--ext", default="", help="extension for github wiki")532    parser.add_argument("-i", "--input", default="doxygen", help="Input file path of doxygen output and source rst file.")533    parser.add_argument("-o", "--output", default="wikipage", help="Output converted restructured text files to path.")534    parser.add_argument("-s", "--struct", default="TypesAndStructures.rest", help="Output of auto generated enum and structures.")535    parser.add_argument("-u", "--uml", action="store_true", help="Enable UML, you need to download plantuml.jar from Plantuml and put it to here. http://plantuml.sourceforge.net/")536    args = parser.parse_args()537    ext = ""538    if(len(args.ext) > 0):539        ext = ("." + args.ext)540    agent = DoxyGen2RST(args.input,541                        args.output,542                        args.struct,543                        is_github = True,544                        enable_uml = args.uml,545                        github_ext = ext)...Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!
