📄 generate_docstrings.py
字号:
name = first['name'].firstChild.data if name[:8] == 'operator': # Don't handle operators yet. return if self.include_function_definition: defn = first['definition'].firstChild.data else: defn = "" # Scip definition. Use the one produced with %feature("autodoc",1) instead self.add_text('\n') self.add_text('%feature("docstring") ') anc = node.parentNode.parentNode if cdef_kind in ('file', 'namespace'): ns_node = anc.getElementsByTagName('innernamespace') if not ns_node and cdef_kind == 'namespace': ns_node = anc.getElementsByTagName('compoundname') if ns_node: ns = ns_node[0].firstChild.data self.add_text(' %s::%s "\n%s'%(ns, name, defn)) else: self.add_text(' %s "\n%s'%(name, defn)) elif cdef_kind in ('class', 'struct'): # Get the full function name. anc_node = anc.getElementsByTagName('compoundname') cname = anc_node[0].firstChild.data self.add_text(' %s::%s "\n%s'%(cname, name, defn)) for n in node.childNodes: if n not in first.values(): self.parse(n) self.add_text(['";', '\n']) def do_definition(self, node): data = node.firstChild.data self.add_text('%s "\n%s'%(data, data)) def do_sectiondef(self, node): kind = node.attributes['kind'].value if kind in ('public-func', 'func'): self.generic_parse(node) def do_simplesect(self, node): kind = node.attributes['kind'].value if kind in ('date', 'rcs', 'version'): pass elif kind == 'warning': self.add_text(['\n', 'WARNING: ']) self.generic_parse(node) elif kind == 'see': self.add_text('\n') self.add_text('See: ') self.generic_parse(node) else: self.generic_parse(node) def do_argsstring(self, node): self.generic_parse(node, pad=1) def do_member(self, node): kind = node.attributes['kind'].value refid = node.attributes['refid'].value if kind == 'function' and refid[:9] == 'namespace': self.generic_parse(node) def do_doxygenindex(self, node): self.multi = 1 comps = node.getElementsByTagName('compound') for c in comps: refid = c.attributes['refid'].value fname = refid + '.xml' if not os.path.exists(fname): fname = os.path.join(self.my_dir, fname) print "parsing file: %s"%fname p = Doxy2SWIG(fname) p.generate() self.pieces.extend(self.clean_pieces(p.pieces)) def write(self, fname): o = my_open_write(fname) if self.multi: o.write("".join(self.pieces)) else: o.write("".join(self.clean_pieces(self.pieces))) o.close() def clean_pieces(self, pieces): """Cleans the list of strings given as `pieces`. It replaces multiple newlines by a maximum of 2 and returns a new list. It also wraps the paragraphs nicely. """ ret = [] count = 0 for i in pieces: if i == '\n': count = count + 1 else: if i == '";': if count: ret.append('\n') elif count > 2: ret.append('\n\n') elif count: ret.append('\n'*count) count = 0 ret.append(i) _data = "".join(ret) ret = [] for i in _data.split('\n\n'): if i == 'Parameters:': ret.extend(['Parameters:\n-----------', '\n\n']) elif i.find('// File:') > -1: # leave comments alone. ret.extend([i, '\n']) else: _tmp = textwrap.fill(i.strip()) _tmp = self.lead_spc.sub(r'\1"\2', _tmp) ret.extend([_tmp, '\n\n']) return retclass DocstringGenerator: def __init__(self, directory = os.curdir, header_files = "Use files in working directory", swig_directory = "swig", docstring_file_base = "Use working directory", doxygen_file = "doxyfile", xml_directory = "xml"): """ A class to generate docstrings from c/c++ header files, using doxygen. Provide a directory that is scanned for header files or provide the header files directly as a list of strings. """ # Set the name of the working directory if not os.path.isabs(directory): if directory == os.curdir: directory = os.path.abspath(os.curdir) else: directory = os.path.join(os.path.abspath(os.curdir),directory) self._directory = directory # Set the name of the header files, if not provided scan the working directory if header_files == "Use files in working directory": self._header_files = [ f for f in os.listdir(self._directory) if f.rfind(".h") != -1] else: self._header_files = header_files # Set the name of the directory where the generated interface file(s) are placed if os.path.isabs(swig_directory): self._swig_directory = swig_directory else: self._swig_directory = os.path.join(directory,swig_directory) # Set the name of the temporary doxyfile self._doxygen_file = os.path.join(directory, doxygen_file) # Set the name of the xml directory if os.path.isabs(xml_directory): self._xml_directory = xml_directory else: self._xml_directory = os.path.join(directory,xml_directory) # Set the name of the generated docstring file that should be %included in a swig # interface file before any %include "code" statements # The files name is: docstring_file_base + _docstrings.i if docstring_file_base == "Use working directory": # If the not provided then use current directory docstring_file_base = self._directory.split(os.path.sep)[-1] self._docstring_file = os.path.join(self._swig_directory,docstring_file_base + "_docstrings.i") def generate_doxygen_documentation(self): """ Generate xml documentation with doxygen. Doxygen needs to be installed. """ from subprocess import Popen header_files = " ".join(self._header_files) dfile = open(self._doxygen_file,'w') dfile.write("""INPUT = %sGENERATE_HTML = NOGENERATE_LATEX = NOGENERATE_XML = YESXML_OUTPUT = %s""" % (header_files,self._xml_directory)) dfile.close() generate_doxygen_code = Popen(['doxygen',dfile.name]) generate_doxygen_code.wait() def generate_interface_files_from_classes(self): """Only include class files when generating interface files""" class_files = [f for f in os.listdir(self._xml_directory) if f.find("class") != -1] dfile = open(self._docstring_file,"w") dfile.write("// An autogenerated docstringfile\n\n") dfile.close() for class_file in class_files: p = Doxy2SWIG(os.path.join(self._xml_directory,class_file)) p.generate() dfile = open(self._docstring_file,"a") p.write(dfile) def generate_interface_file_from_index(self): """Take index.xml and generates one interface file.""" p = Doxy2SWIG(os.path.join(self._xml_directory,"index.xml")) p.generate() dfile = open(self._docstring_file,"w") dfile.write("// An autogenerated docstringfile\n\n") #p.write(self._docstring_file) p.write(dfile) def clean(self): """Remove temporary xml directory and doxyfile.""" for f in os.listdir(self._xml_directory): os.remove(os.path.join(self._xml_directory,f)) os.removedirs(self._xml_directory) os.remove(self._doxygen_file) if 'html' in os.listdir(self._directory): html_dir = os.path.join(self._directory,"html") for f in os.listdir(html_dir): os.remove(os.path.join(html_dir,f)) os.removedirs(html_dir) if __name__ == '__main__': import sys if len(sys.argv) == 2: directory = sys.argv[1] g = DocstringGenerator(directory) else: g = DocstringGenerator() g.generate_doxygen_documentation() if "index.xml" in os.listdir(g._xml_directory): g.generate_interface_file_from_index() else: g.generate_interface_files_classes() g.clean()
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -