2 """doxy2swig.py [options] index.xml output.i
4 Doxygen XML to SWIG docstring converter (improved version).
6 Converts Doxygen generated XML files into a file containing docstrings
9 index.xml is your doxygen generated XML file and output.i is where the
10 output will be written (the file will be clobbered).
13 # The current version of this code is hosted on a github repository:
14 # https://github.com/m7thon/doxy2swig
16 # This code is implemented using Mark Pilgrim's code as a guideline:
17 # http://www.faqs.org/docs/diveintopython/kgp_divein.html
19 # Original Author: Prabhu Ramachandran
20 # Modified by: Michael Thon (June 2015)
24 # Johan Hake: the include_function_definition feature
25 # Bill Spotz: bug reports and testing.
26 # Sebastian Henschel: Misc. enhancements.
29 # June 2015 (Michael Thon):
30 # - class documentation:
31 # -c: add constructor call signatures and a "Constructors" section
32 # collecting the respective docs (e.g. for python)
33 # -a: add "Attributes" section collecting the documentation for member
34 # variables (e.g. for python)
35 # - overloaded functions:
36 # -o: collect all documentation into one "Overloaded function" section
37 # - option to include function definition / signature renamed to -f
39 # + included function signatures slightly reformatted
40 # + option (-t) to turn off/on type information for funciton signatures
41 # + lists (incl. nested and ordered)
42 # + attempt to produce docstrings that render nicely as markdown
43 # + translate code, emphasis, bold, linebreak, hruler, blockquote,
44 # verbatim, heading tags to markdown
45 # + new text-wrapping and option -w to specify the text width
48 from xml.dom import minidom
56 def my_open_read(source):
57 if hasattr(source, "read"):
61 return open(source, encoding='utf-8')
65 def my_open_write(dest):
66 if hasattr(dest, "write"):
70 return open(dest, 'w', encoding='utf-8')
72 return open(dest, 'w')
74 # MARK: Text handling:
75 def shift(txt, indent = ' ', prepend = ''):
76 """Return a list corresponding to the lines of text in the `txt` list
77 indented by `indent`. Prepend instead the string given in `prepend` to the
78 beginning of the first line. Note that if len(prepend) > len(indent), then
79 `prepend` will be truncated (doing better is tricky!). This preserves a
80 special '' entry at the end of `txt` (see `do_para` for the meaning).
82 if type(indent) is int:
84 special_end = txt[-1:] == ['']
85 lines = ''.join(txt).splitlines(True)
86 for i in range(1,len(lines)):
87 if lines[i].strip() or indent.strip():
88 lines[i] = indent + lines[i]
91 prepend = prepend[:len(indent)]
92 indent = indent[len(prepend):]
93 lines[0] = prepend + indent + lines[0]
94 ret = [''.join(lines)]
100 """Converts Doxygen generated XML files into a file containing
101 docstrings that can be used by SWIG-1.3.x that have support for
102 feature("docstring"). Once the data is parsed it is stored in
107 def __init__(self, src,
108 with_function_signature = False,
109 with_type_info = False,
110 with_constructor_list = False,
111 with_attribute_list = False,
112 with_overloaded_functions = False,
115 """Initialize the instance given a source object. `src` can
116 be a file or filename. If you do not want to include function
117 definitions from doxygen then set
118 `include_function_definition` to `False`. This is handy since
119 this allows you to use the swig generated function definition
120 using %feature("autodoc", [0,1]).
124 self.with_function_signature = with_function_signature
125 self.with_type_info = with_type_info
126 self.with_constructor_list = with_constructor_list
127 self.with_attribute_list = with_attribute_list
128 self.with_overloaded_functions = with_overloaded_functions
129 self.textwidth = textwidth
137 f = my_open_read(src)
138 self.my_dir = os.path.dirname(f.name)
139 self.xmldoc = minidom.parse(f).documentElement
142 self.pieces.append('\n// File: %s\n' %
143 os.path.basename(f.name))
145 self.space_re = re.compile(r'\s+')
146 self.lead_spc = re.compile(r'^(%feature\S+\s+\S+\s*?)"\s+(\S)')
148 self.ignores = ['inheritancegraph', 'param', 'listofallmembers',
149 'innerclass', 'name', 'declname', 'incdepgraph',
150 'invincdepgraph', 'programlisting', 'type',
151 'references', 'referencedby', 'location',
152 'collaborationgraph', 'reimplements',
153 'reimplementedby', 'derivedcompoundref',
155 'argsstring', 'definition', 'exceptions']
159 """Parses the file set in the initialization. The resulting
160 data is stored in `self.pieces`.
163 self.parse(self.xmldoc)
165 def write(self, fname):
166 o = my_open_write(fname)
167 o.write(''.join(self.pieces))
171 def parse(self, node):
172 """Parse a given node. This function in turn calls the
173 `parse_<nodeType>` functions which handle the respective
177 pm = getattr(self, "parse_%s" % node.__class__.__name__)
180 def parse_Document(self, node):
181 self.parse(node.documentElement)
183 def parse_Text(self, node):
186 # this can happen when two tags follow in a text, e.g.,
187 # " ...</emph> <formaula>$..." etc.
188 # here we want to keep the space.
191 txt = txt.replace('\\', r'\\')
192 txt = txt.replace('"', r'\"')
193 # ignore pure whitespace
194 m = self.space_re.match(txt)
195 if m and len(m.group()) == len(txt):
200 def parse_Comment(self, node):
201 """Parse a `COMMENT_NODE`. This does nothing for now."""
204 def parse_Element(self, node):
205 """Parse an `ELEMENT_NODE`. This calls specific
206 `do_<tagName>` handers for different elements. If no handler
207 is available the `subnode_parse` method is called. All
208 tagNames specified in `self.ignores` are simply ignored.
212 ignores = self.ignores
215 attr = "do_%s" % name
216 if hasattr(self, attr):
217 handlerMethod = getattr(self, attr)
220 self.subnode_parse(node)
221 #if name not in self.generics: self.generics.append(name)
223 # MARK: Special format parsing
224 def subnode_parse(self, node, pieces=None, indent=0, ignore=[], restrict=None):
225 """Parse the subnodes of a given node. Subnodes with tags in the
226 `ignore` list are ignored. If pieces is given, use this as target for
227 the parse results instead of self.pieces. Indent all lines by the amount
228 given in `indent`. Note that the initial content in `pieces` is not
229 indented. The final result is in any case added to self.pieces."""
230 if pieces is not None:
231 old_pieces, self.pieces = self.pieces, pieces
234 if type(indent) is int:
235 indent = indent * ' '
237 pieces = ''.join(self.pieces)
238 i_piece = pieces[:len(indent)]
239 if self.pieces[-1:] == ['']:
240 self.pieces = [pieces[len(indent):]] + ['']
241 elif self.pieces != []:
242 self.pieces = [pieces[len(indent):]]
243 self.indent += len(indent)
244 for n in node.childNodes:
245 if restrict is not None:
246 if n.nodeType == n.ELEMENT_NODE and n.tagName in restrict:
248 elif n.nodeType != n.ELEMENT_NODE or n.tagName not in ignore:
251 self.pieces = shift(self.pieces, indent, i_piece)
252 self.indent -= len(indent)
253 old_pieces.extend(self.pieces)
254 self.pieces = old_pieces
256 def surround_parse(self, node, pre_char, post_char):
257 """Parse the subnodes of a given node. Subnodes with tags in the
258 `ignore` list are ignored. Prepend `pre_char` and append `post_char` to
259 the output in self.pieces."""
260 self.add_text(pre_char)
261 self.subnode_parse(node)
262 self.add_text(post_char)
264 # MARK: Helper functions
265 def get_specific_subnodes(self, node, name, recursive=0):
266 """Given a node and a name, return a list of child `ELEMENT_NODEs`, that
267 have a `tagName` matching the `name`. Search recursively for `recursive`
270 children = [x for x in node.childNodes if x.nodeType == x.ELEMENT_NODE]
271 ret = [x for x in children if x.tagName == name]
274 ret.extend(self.get_specific_subnodes(x, name, recursive-1))
277 def get_specific_nodes(self, node, names):
278 """Given a node and a sequence of strings in `names`, return a
279 dictionary containing the names as keys and child
280 `ELEMENT_NODEs`, that have a `tagName` equal to the name.
283 nodes = [(x.tagName, x) for x in node.childNodes
284 if x.nodeType == x.ELEMENT_NODE and
288 def add_text(self, value):
289 """Adds text corresponding to `value` into `self.pieces`."""
290 if isinstance(value, (list, tuple)):
291 self.pieces.extend(value)
293 self.pieces.append(value)
295 def start_new_paragraph(self):
296 """Make sure to create an empty line. This is overridden, if the previous
297 text ends with the special marker ''. In that case, nothing is done.
299 if self.pieces[-1:] == ['']: # respect special marker
301 elif self.pieces == []: # first paragraph, add '\n', override with ''
303 elif self.pieces[-1][-1:] != '\n': # previous line not ended
304 self.pieces.extend([' \n' ,'\n'])
306 self.pieces.append('\n')
308 def add_line_with_subsequent_indent(self, line, indent=4):
309 """Add line of text and wrap such that subsequent lines are indented
312 if isinstance(line, (list, tuple)):
315 width = self.textwidth-self.indent-indent
316 wrapped_lines = textwrap.wrap(line[indent:], width=width)
317 for i in range(len(wrapped_lines)):
318 if wrapped_lines[i] != '':
319 wrapped_lines[i] = indent * ' ' + wrapped_lines[i]
320 self.pieces.append(line[:indent] + '\n'.join(wrapped_lines)[indent:] + ' \n')
322 def extract_text(self, node):
323 """Return the string representation of the node or list of nodes by parsing the
324 subnodes, but returning the result as a string instead of adding it to `self.pieces`.
325 Note that this allows extracting text even if the node is in the ignore list.
327 if not isinstance(node, (list, tuple)):
329 pieces, self.pieces = self.pieces, ['']
331 for sn in n.childNodes:
333 ret = ''.join(self.pieces)
337 def get_function_signature(self, node):
338 """Returns the function signature string for memberdef nodes."""
339 name = self.extract_text(self.get_specific_subnodes(node, 'name'))
340 if self.with_type_info:
341 argsstring = self.extract_text(self.get_specific_subnodes(node, 'argsstring'))
345 for n_param in self.get_specific_subnodes(node, 'param'):
346 declname = self.extract_text(self.get_specific_subnodes(n_param, 'declname'))
348 declname = 'arg' + str(param_id)
349 defval = self.extract_text(self.get_specific_subnodes(n_param, 'defval'))
351 defval = '=' + defval
352 argsstring.append(declname + defval)
353 param_id = param_id + 1
354 argsstring = '(' + ', '.join(argsstring) + ')'
355 type = self.extract_text(self.get_specific_subnodes(node, 'type'))
356 function_definition = name + argsstring
357 if type != '' and type != 'void':
358 function_definition = function_definition + ' -> ' + type
359 return '`' + function_definition + '` '
361 # MARK: Special parsing tasks (need to be called manually)
362 def make_constructor_list(self, constructor_nodes, classname):
363 """Produces the "Constructors" section and the constructor signatures
364 (since swig does not do so for classes) for class docstrings."""
365 if constructor_nodes == []:
367 self.add_text(['\n', 'Constructors',
368 '\n', '------------'])
369 for n in constructor_nodes:
371 self.add_line_with_subsequent_indent('* ' + self.get_function_signature(n))
372 self.subnode_parse(n, pieces = [], indent=4, ignore=['definition', 'name'])
374 def make_attribute_list(self, node):
375 """Produces the "Attributes" section in class docstrings for public
376 member variables (attributes).
379 for n in self.get_specific_subnodes(node, 'memberdef', recursive=2):
380 if n.attributes['kind'].value == 'variable' and n.attributes['prot'].value == 'public':
384 self.add_text(['\n', 'Attributes',
387 name = self.extract_text(self.get_specific_subnodes(n, 'name'))
388 self.add_text(['\n* ', '`', name, '`', ' : '])
389 self.add_text(['`', self.extract_text(self.get_specific_subnodes(n, 'type')), '`'])
391 restrict = ['briefdescription', 'detaileddescription']
392 self.subnode_parse(n, pieces=[''], indent=4, restrict=restrict)
394 def get_memberdef_nodes_and_signatures(self, node, kind):
395 """Collects the memberdef nodes and corresponding signatures that
396 correspond to public function entries that are at most depth 2 deeper
397 than the current (compounddef) node. Returns a dictionary with
398 function signatures (what swig expects after the %feature directive)
399 as keys, and a list of corresponding memberdef nodes as values."""
402 if kind in ('file', 'namespace'):
403 ns_node = node.getElementsByTagName('innernamespace')
404 if not ns_node and kind == 'namespace':
405 ns_node = node.getElementsByTagName('compoundname')
407 sig_prefix = self.extract_text(ns_node[0]) + '::'
408 elif kind in ('class', 'struct'):
409 # Get the full function name.
410 cn_node = node.getElementsByTagName('compoundname')
411 sig_prefix = self.extract_text(cn_node[0]) + '::'
413 md_nodes = self.get_specific_subnodes(node, 'memberdef', recursive=2)
415 if n.attributes['prot'].value != 'public':
417 if n.attributes['kind'].value in ['variable', 'typedef']:
419 if not self.get_specific_subnodes(n, 'definition'):
421 name = self.extract_text(self.get_specific_subnodes(n, 'name'))
422 if name[:8] == 'operator':
424 sig = sig_prefix + name
426 sig_dict[sig].append(n)
431 def handle_typical_memberdefs_no_overload(self, signature, memberdef_nodes):
432 """Produce standard documentation for memberdef_nodes."""
433 for n in memberdef_nodes:
434 self.add_text(['\n', '%feature("docstring") ', signature, ' "', '\n'])
435 if self.with_function_signature:
436 self.add_line_with_subsequent_indent(self.get_function_signature(n))
437 self.subnode_parse(n, pieces=[], ignore=['definition', 'name'])
438 self.add_text(['";', '\n'])
440 def handle_typical_memberdefs(self, signature, memberdef_nodes):
441 """Produces docstring entries containing an "Overloaded function"
442 section with the documentation for each overload, if the function is
443 overloaded and self.with_overloaded_functions is set. Else, produce
444 normal documentation.
446 if len(memberdef_nodes) == 1 or not self.with_overloaded_functions:
447 self.handle_typical_memberdefs_no_overload(signature, memberdef_nodes)
450 self.add_text(['\n', '%feature("docstring") ', signature, ' "', '\n'])
451 if self.with_function_signature:
452 for n in memberdef_nodes:
453 self.add_line_with_subsequent_indent(self.get_function_signature(n))
455 self.add_text(['Overloaded function', '\n',
456 '-------------------'])
457 for n in memberdef_nodes:
459 self.add_line_with_subsequent_indent('* ' + self.get_function_signature(n))
460 self.subnode_parse(n, pieces=[], indent=4, ignore=['definition', 'name'])
461 self.add_text(['";', '\n'])
465 def do_linebreak(self, node):
468 def do_ndash(self, node):
471 def do_mdash(self, node):
474 def do_emphasis(self, node):
475 self.surround_parse(node, '*', '*')
477 def do_bold(self, node):
478 self.surround_parse(node, '**', '**')
480 def do_computeroutput(self, node):
481 self.surround_parse(node, '`', '`')
483 def do_heading(self, node):
484 self.start_new_paragraph()
485 pieces, self.pieces = self.pieces, ['']
486 level = int(node.attributes['level'].value)
487 self.subnode_parse(node)
489 self.pieces.insert(0, '\n')
490 self.add_text(['\n', len(''.join(self.pieces).strip()) * '='])
492 self.add_text(['\n', len(''.join(self.pieces).strip()) * '-'])
494 self.pieces.insert(0, level * '#' + ' ')
495 # make following text have no gap to the heading:
496 pieces.extend([''.join(self.pieces) + ' \n', ''])
499 def do_verbatim(self, node):
500 self.start_new_paragraph()
501 self.subnode_parse(node, pieces=[''], indent=4)
503 def do_blockquote(self, node):
504 self.start_new_paragraph()
505 self.subnode_parse(node, pieces=[''], indent='> ')
507 def do_hruler(self, node):
508 self.start_new_paragraph()
509 self.add_text('* * * * * \n')
511 def do_includes(self, node):
512 self.add_text('\nC++ includes: ')
513 self.subnode_parse(node)
516 # MARK: Para tag handler
517 def do_para(self, node):
518 """This is the only place where text wrapping is automatically performed.
519 Generally, this function parses the node (locally), wraps the text, and
520 then adds the result to self.pieces. However, it may be convenient to
521 allow the previous content of self.pieces to be included in the text
522 wrapping. For this, use the following *convention*:
523 If self.pieces ends with '', treat the _previous_ entry as part of the
524 current paragraph. Else, insert new-line and start a new paragraph
525 and "wrapping context".
526 Paragraphs always end with ' \n', but if the parsed content ends with
527 the special symbol '', this is passed on.
529 if self.pieces[-1:] == ['']:
530 pieces, self.pieces = self.pieces[:-2], self.pieces[-2:-1]
533 pieces, self.pieces = self.pieces, ['']
534 self.subnode_parse(node)
535 dont_end_paragraph = self.pieces[-1:] == ['']
536 # Now do the text wrapping:
537 width = self.textwidth - self.indent
539 for line in ''.join(self.pieces).splitlines():
540 keep_markdown_newline = line[-2:] == ' '
541 w_line = textwrap.wrap(line, width=width, break_long_words=False)
544 if keep_markdown_newline:
545 w_line[-1] = w_line[-1] + ' '
547 wrapped_para.append(wl + '\n')
549 if wrapped_para[-1][-3:] != ' \n':
550 wrapped_para[-1] = wrapped_para[-1][:-1] + ' \n'
551 if dont_end_paragraph:
552 wrapped_para.append('')
553 pieces.extend(wrapped_para)
556 # MARK: List tag handlers
557 def do_itemizedlist(self, node):
558 if self.listitem == '':
559 self.start_new_paragraph()
560 elif self.pieces != [] and self.pieces[-1:] != ['']:
562 listitem = self.listitem
563 if self.listitem in ['*', '-']:
567 self.subnode_parse(node)
568 self.listitem = listitem
570 def do_orderedlist(self, node):
571 if self.listitem == '':
572 self.start_new_paragraph()
573 elif self.pieces != [] and self.pieces[-1:] != ['']:
575 listitem = self.listitem
577 self.subnode_parse(node)
578 self.listitem = listitem
580 def do_listitem(self, node):
582 self.listitem = int(self.listitem) + 1
583 item = str(self.listitem) + '. '
585 item = str(self.listitem) + ' '
586 self.subnode_parse(node, item, indent=4)
588 # MARK: Parameter list tag handlers
589 def do_parameterlist(self, node):
590 self.start_new_paragraph()
592 for key, val in node.attributes.items():
596 elif val == 'exception':
598 elif val == 'retval':
604 self.add_text([text, '\n', len(text) * '-', '\n'])
606 self.add_text([text, ': \n'])
607 self.subnode_parse(node)
609 def do_parameteritem(self, node):
610 self.subnode_parse(node, pieces=['* ', ''])
612 def do_parameternamelist(self, node):
613 self.subnode_parse(node)
614 self.add_text([' :', ' \n'])
616 def do_parametername(self, node):
617 if self.pieces != [] and self.pieces != ['* ', '']:
619 data = self.extract_text(node)
620 self.add_text(['`', data, '`'])
622 def do_parameterdescription(self, node):
623 self.subnode_parse(node, pieces=[''], indent=4)
625 # MARK: Section tag handler
626 def do_simplesect(self, node):
627 kind = node.attributes['kind'].value
628 if kind in ('date', 'rcs', 'version'):
630 self.start_new_paragraph()
631 if kind == 'warning':
632 self.subnode_parse(node, pieces=['**Warning**: ',''], indent=4)
634 self.subnode_parse(node, pieces=['See also: ',''], indent=4)
635 elif kind == 'return':
637 pieces = ['Returns', '\n', len('Returns') * '-', '\n', '']
639 pieces = ['Returns:', '\n', '']
640 self.subnode_parse(node, pieces=pieces)
642 self.subnode_parse(node, pieces=[kind + ': ',''], indent=4)
644 # MARK: %feature("docstring") producing tag handlers
645 def do_compounddef(self, node):
646 """This produces %feature("docstring") entries for classes, and handles
647 class, namespace and file memberdef entries specially to allow for
648 overloaded functions. For other cases, passes parsing on to standard
649 handlers (which may produce unexpected results).
651 kind = node.attributes['kind'].value
652 if kind in ('class', 'struct'):
653 prot = node.attributes['prot'].value
656 self.add_text('\n\n')
657 classdefn = self.extract_text(self.get_specific_subnodes(node, 'compoundname'))
658 classname = classdefn.split('::')[-1]
659 self.add_text('%%feature("docstring") %s "\n' % classdefn)
661 if self.with_constructor_list:
662 constructor_nodes = []
663 for n in self.get_specific_subnodes(node, 'memberdef', recursive=2):
664 if n.attributes['prot'].value == 'public':
665 if self.extract_text(self.get_specific_subnodes(n, 'definition')) == classdefn + '::' + classname:
666 constructor_nodes.append(n)
667 for n in constructor_nodes:
668 self.add_line_with_subsequent_indent(self.get_function_signature(n))
670 names = ('briefdescription','detaileddescription')
671 sub_dict = self.get_specific_nodes(node, names)
672 for n in ('briefdescription','detaileddescription'):
674 self.parse(sub_dict[n])
675 if self.with_constructor_list:
676 self.make_constructor_list(constructor_nodes, classname)
677 if self.with_attribute_list:
678 self.make_attribute_list(node)
680 sub_list = self.get_specific_subnodes(node, 'includes')
682 self.parse(sub_list[0])
683 self.add_text(['";', '\n'])
685 names = ['compoundname', 'briefdescription','detaileddescription', 'includes']
686 self.subnode_parse(node, ignore = names)
688 elif kind in ('file', 'namespace'):
689 nodes = node.getElementsByTagName('sectiondef')
693 # now explicitely handle possibly overloaded member functions.
694 if kind in ['class', 'struct','file', 'namespace']:
695 md_nodes = self.get_memberdef_nodes_and_signatures(node, kind)
697 self.handle_typical_memberdefs(sig, md_nodes[sig])
699 def do_memberdef(self, node):
700 """Handle cases outside of class, struct, file or namespace. These are
701 now dealt with by `handle_overloaded_memberfunction`.
702 Do these even exist???
704 prot = node.attributes['prot'].value
705 id = node.attributes['id'].value
706 kind = node.attributes['kind'].value
707 tmp = node.parentNode.parentNode.parentNode
708 compdef = tmp.getElementsByTagName('compounddef')[0]
709 cdef_kind = compdef.attributes['kind'].value
710 if cdef_kind in ('file', 'namespace', 'class', 'struct'):
711 # These cases are now handled by `handle_typical_memberdefs`
715 first = self.get_specific_nodes(node, ('definition', 'name'))
716 name = self.extract_text(first['name'])
717 if name[:8] == 'operator': # Don't handle operators yet.
719 if not 'definition' in first or kind in ['variable', 'typedef']:
722 data = self.extract_text(first['definition'])
724 self.add_text(['/* where did this entry come from??? */', '\n'])
725 self.add_text('%feature("docstring") %s "\n%s' % (data, data))
727 for n in node.childNodes:
728 if n not in first.values():
730 self.add_text(['";', '\n'])
732 # MARK: Entry tag handlers (dont print anything meaningful)
733 def do_sectiondef(self, node):
734 kind = node.attributes['kind'].value
735 if kind in ('public-func', 'func', 'user-defined', ''):
736 self.subnode_parse(node)
738 def do_header(self, node):
739 """For a user defined section def a header field is present
740 which should not be printed as such, so we comment it in the
742 data = self.extract_text(node)
743 self.add_text('\n/*\n %s \n*/\n' % data)
744 # If our immediate sibling is a 'description' node then we
745 # should comment that out also and remove it from the parent
747 parent = node.parentNode
748 idx = parent.childNodes.index(node)
749 if len(parent.childNodes) >= idx + 2:
750 nd = parent.childNodes[idx + 2]
751 if nd.nodeName == 'description':
752 nd = parent.removeChild(nd)
753 self.add_text('\n/*')
754 self.subnode_parse(nd)
755 self.add_text('\n*/\n')
757 def do_member(self, node):
758 kind = node.attributes['kind'].value
759 refid = node.attributes['refid'].value
760 if kind == 'function' and refid[:9] == 'namespace':
761 self.subnode_parse(node)
763 def do_doxygenindex(self, node):
765 comps = node.getElementsByTagName('compound')
767 refid = c.attributes['refid'].value
768 fname = refid + '.xml'
769 if not os.path.exists(fname):
770 fname = os.path.join(self.my_dir, fname)
772 print("parsing file: %s" % fname)
774 with_function_signature = self.with_function_signature,
775 with_type_info = self.with_type_info,
776 with_constructor_list = self.with_constructor_list,
777 with_attribute_list = self.with_attribute_list,
778 with_overloaded_functions = self.with_overloaded_functions,
779 textwidth = self.textwidth,
782 self.pieces.extend(p.pieces)
787 parser = optparse.OptionParser(usage)
788 parser.add_option("-f", '--function-signature',
792 help='include function signature in the documentation. This is handy when not using swig auto-generated function definitions %feature("autodoc", [0,1])')
793 parser.add_option("-t", '--type-info',
797 help='include type information for arguments in function signatures. This is similar to swig autodoc level 1')
798 parser.add_option("-c", '--constructor-list',
802 help='generate a constructor list for class documentation. Useful for target languages where the object construction should be documented in the class documentation.')
803 parser.add_option("-a", '--attribute-list',
807 help='generate an attributes list for class documentation. Useful for target languages where class attributes should be documented in the class documentation.')
808 parser.add_option("-o", '--overloaded-functions',
812 help='collect all documentation for overloaded functions. Useful for target languages that have no concept of overloaded functions, but also to avoid having to attach the correct docstring to each function overload manually')
813 parser.add_option("-w", '--width', type="int",
817 help='textwidth for wrapping (default: 80). Note that the generated lines may include 2 additional spaces (for markdown).')
818 parser.add_option("-q", '--quiet',
822 help='be quiet and minimize output')
824 options, args = parser.parse_args()
826 parser.error("no input and output specified")
828 p = Doxy2SWIG(args[0],
829 with_function_signature = options.f,
830 with_type_info = options.t,
831 with_constructor_list = options.c,
832 with_attribute_list = options.a,
833 with_overloaded_functions = options.o,
834 textwidth = options.w,
839 if __name__ == '__main__':