def index_items(item_type, items): return """ %s: .. toctree:: :maxdepth: 1 %s """ % (item_type, indent("\n".join(sorted(items)), 4))
def generate_cpp_module(module, documentation, classnames, output_dir): print indent("Generating documentation for %s ... " % module, 0) # Generate index file for this module module_index = templates.generate_module_index(module) index_filename = os.path.join(output_dir, "index.rst") open_write_close(index_filename, module_index) # Generate .rst for each header file in this module for (header, doc) in documentation: #print indent("Generating documentation for %s" % header, 2) rst_filename = os.path.join(output_dir, header.split(".")[0] + ".rst") header_rst = generate_header_rst_file(module, header, doc, classnames) open_write_close(rst_filename, header_rst) return
def write_class_doc(classname, parents, comment, function_documentation, classnames): output = [] base_indent = 0 if classname is not None: base_indent = 4 output += [".. cpp:class:: %s\n" % classname] if parents is not None: output += [indent("*Parent class(es)*\n", 4)] for parent in parents: output += [indent("* :cpp:class:`%s`\n" % parent, 8)] if comment is not None: comment = add_links(comment, classnames, ":cpp:class:") #NB output += [indent(comment, 4)] + ["\n"] else: output += ["\n"] for (signature, comment) in function_documentation: # Handle indentation of signature # Hm? if "\n" in signature: lines = signature.split("\n") signature = ("\n".join([lines[0]] + [(len(".. cpp.function::") + 1)*" " + l for l in lines[1:]])) # Add crosslinks in comment comment = add_links(comment, classnames, ":cpp:class:") output += [indent(".. cpp:function:: %s\n" % signature, base_indent)] output += [indent(comment, base_indent + 4), "\n"] text = "\n".join(output) return text
def write_class_doc(classname, parents, comment, function_documentation, classnames): output = [] base_indent = 0 if classname is not None: base_indent = 4 output += [".. cpp:class:: %s\n" % classname] if parents is not None: output += [indent("*Parent class(es)*\n", 4)] for parent in parents: output += [indent("* :cpp:class:`%s`\n" % parent, 8)] if comment is not None: comment = add_links(comment, classnames, ":cpp:class:") #NB output += [indent(comment, 4)] + ["\n"] else: output += ["\n"] for (signature, comment) in function_documentation: # Handle indentation of signature # Hm? if "\n" in signature: lines = signature.split("\n") signature = ("\n".join([lines[0]] + [(len(".. cpp.function::") + 1) * " " + l for l in lines[1:]])) # Add crosslinks in comment comment = add_links(comment, classnames, ":cpp:class:") output += [indent(".. cpp:function:: %s\n" % signature, base_indent)] output += [indent(comment, base_indent + 4), "\n"] text = "\n".join(output) return text
def replace_example(text, classname, signature): """Replace the C++ example code with the Python equivalent. Currently we can only handle one block/section of example code per function. """ # Check if we need to manipulate comment. if not "*Example*" in text: return text # Check if we have example code in the dictionary examplecode = ".. note::\n\n No example code available for this function." if not classname in codesnippets: output(" " * 6 + "No example code for class: '%s'" % classname) elif not signature in codesnippets[classname]: output(" " * 6 + "No example code for (class, function): ('%s', '%s')" % (classname, signature)) else: examplecode = codesnippets[classname][signature] # Remove leading and trailing new lines in example code. lines = examplecode.split("\n") while lines and not lines[0].strip(): del lines[0] while lines and not lines[-1].strip(): del lines[-1] examplecode = "\n".join(lines) # NOTE: KBO: We currently only handle 1 example block new_text = [] example = False indentation = 0 # Loop comment lines for l in text.split("\n"): # When we get to the lines containing the example, add the header and # codeblock. if not example and "*Example*" in l: example = True indentation = len(l) - len(l.lstrip()) new_text.append(l) new_text += indent(examplecode, indentation + 4).split("\n") elif example and l.strip() and len(l) - len(l.lstrip()) <= indentation: example = False new_text.append(l) # Skip lines as long as we're inside the example block. elif example: continue else: new_text.append(l) return "\n".join(new_text)
def generate_header_rst_file(module, header, documentation, classnames): output = [] for (classname, parents, comment, function_documentation) in documentation: output += [write_class_doc(classname, parents, comment, function_documentation, classnames)] text = "\n".join(output) note = indent(templates.note_template, 4) dictionary = {"module": module, "header": header, "prefix": header.split(".")[0].lower(), "title": header, "formatting": len(header)*"=", "note": note, "text": text} template = templates.header_cpp_template % dictionary return template
def write_docstrings(output_file, module, header, docs, classnames): """Write docstrings from a header file.""" output_file.write( "// Documentation extracted from: (module=%s, header=%s)\n" % (module, header)) documentation = group_overloaded_functions(docs) for (classname, parent, comment, func_docs, order) in documentation: # Create class documentation (if any) and write. if classname is not None and comment is not None: cls_doc = modify_doc(comment, classnames, classname, classname) output_file.write(docstring % ("dolfin::%s" % classname, cls_doc)) # Handle functions in the correct order (according to definition in the # header file). for name in order: func_name = "dolfin::%s::%s" % (classname, name) if classname is None: func_name = "dolfin::%s" % name functions = func_docs[name] if not functions: continue # We've got overloaded functions. if len(functions) > 1: func_doc = "**Overloaded versions**" for signature, doc in functions: args = get_args(signature) doc = "\n\n* %s\ (%s)\n\n" % (name, ", ".join(args)) +\ indent(doc, 2) func_doc += modify_doc(doc, classnames, classname, signature) output_file.write(docstring % (func_name, func_doc)) # Single function else: # Get function (only one) signature, func_doc = functions[0] func_doc = modify_doc(func_doc, classnames, classname, signature) output_file.write(docstring % (func_name, func_doc))
def generate_header_rst_file(module, header, documentation, classnames): output = [] for (classname, parents, comment, function_documentation) in documentation: output += [ write_class_doc(classname, parents, comment, function_documentation, classnames) ] text = "\n".join(output) note = indent(templates.note_template, 4) dictionary = { "module": module, "header": header, "prefix": header.split(".")[0].lower(), "title": header, "formatting": len(header) * "=", "note": note, "text": text } template = templates.header_cpp_template % dictionary return template
def map_argument_and_return_types(text, classnames): """Map C++ types in the *Arguments* and *Returns* sections to corresponding Python types using a simple dictionary. Current implementation assumes the following format: *Returns* type description *Arguments* name0 (type) description name1 (type) description possibly separated with blank lines. """ new_text = text # Could perhaps be handled more elegantly if we rely on the formatting? if "*Returns*" in new_text: # Get lines and find line number with *Returns* lines = new_text.split("\n") r_index = ["*Returns*" in l for l in lines].index(True) arg = False for e, l in enumerate(lines): if e > r_index and not arg: # First none blank line contains our argument if l.strip(): arg = True indentation = len(l) - len(l.lstrip()) lines[e] = indent(map_cpp_type(l.strip(), classnames), indentation) new_text = "\n".join(lines) if "*Arguments*" in new_text: # Get lines and find line number with *Arguments* lines = new_text.split("\n") a_index = ["*Arguments*" in l for l in lines].index(True) a_indent = len(lines[a_index]) - len(lines[a_index].lstrip()) n_indent = 0 for e, l in enumerate(lines): if e > a_index and l.strip(): indentation = len(l) - len(l.lstrip()) # End of argument block if indentation <= a_indent: break # Determine indentation of lines with argument names # first non blank line determines this if n_indent == 0: n_indent = indentation # Get type of arguments defined in lines with name and type if indentation == n_indent: n, t = l.split("(") n = n.strip() t = t.split(")")[0] lines[e] = indent( "%s (%s)" % (n, map_cpp_type(t.strip(), classnames)), n_indent) new_text = "\n".join(lines) return new_text