[Debian-astro-commits] [gyoto] 174/221: Use doxygen to provide docstrings in the python bindings (based on doxy2swig)

Thibaut Jean-Claude Paumard thibaut at moszumanska.debian.org
Fri May 22 20:52:44 UTC 2015


This is an automated email from the git hooks/post-receive script.

thibaut pushed a commit to branch master
in repository gyoto.

commit 46e73509da11e0f0ac1b52970689773ce186b4ed
Author: Thibaut Paumard <paumard at users.sourceforge.net>
Date:   Mon Jan 5 15:26:56 2015 +0100

    Use doxygen to provide docstrings in the python bindings (based on doxy2swig)
---
 Makefile.in         |  16 +-
 configure           |   8 +-
 configure.ac        |   4 +-
 doc/Makefile.in     |  11 +-
 doc/doxyfile.in     |   2 +-
 python/Makefile.in  |  12 +-
 python/doxy2swig.py | 460 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 python/gyoto.i      |   2 +
 8 files changed, 492 insertions(+), 23 deletions(-)

diff --git a/Makefile.in b/Makefile.in
index 67a7d56..e96396c 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -83,7 +83,7 @@ DIST_COMMON = INSTALL NEWS README AUTHORS ChangeLog \
 	$(srcdir)/Makefile.in $(srcdir)/Makefile.am \
 	$(top_srcdir)/configure $(am__configure_deps) \
 	$(srcdir)/config.h.in $(top_srcdir)/include/GyotoConfig.h.in \
-	$(top_srcdir)/doc/Makefile.in \
+	$(top_srcdir)/doc/Makefile.in $(top_srcdir)/doc/doxyfile.in \
 	$(top_srcdir)/doc/user_guide/Makefile.in \
 	$(top_srcdir)/yorick/Makefile.in \
 	$(top_srcdir)/yorick/stdplug/Makefile.in \
@@ -93,9 +93,8 @@ DIST_COMMON = INSTALL NEWS README AUTHORS ChangeLog \
 	$(top_srcdir)/python/Makefile.in \
 	$(top_srcdir)/python/setup.py.in \
 	$(top_srcdir)/python/setup_std.py.in \
-	$(top_srcdir)/python/setup_lorene.py.in \
-	$(top_srcdir)/doc/doxyfile.in COPYING compile config.guess \
-	config.sub depcomp install-sh missing ltmain.sh
+	$(top_srcdir)/python/setup_lorene.py.in COPYING compile \
+	config.guess config.sub depcomp install-sh missing ltmain.sh
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_append_compile_flags.m4 \
 	$(top_srcdir)/m4/ax_append_flag.m4 \
@@ -112,11 +111,10 @@ am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
  configure.lineno config.status.lineno
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = config.h $(top_builddir)/include/GyotoConfig.h
-CONFIG_CLEAN_FILES = doc/Makefile doc/user_guide/Makefile \
+CONFIG_CLEAN_FILES = doc/Makefile doc/doxyfile doc/user_guide/Makefile \
 	yorick/Makefile yorick/stdplug/Makefile yorick/gyoto.info \
 	yorick/yorick1 yorick/setpaths.i gyoto python/Makefile \
-	python/setup.py python/setup_std.py python/setup_lorene.py \
-	doc/doxyfile
+	python/setup.py python/setup_std.py python/setup_lorene.py
 CONFIG_CLEAN_VPATH_FILES =
 AM_V_P = $(am__v_P_ at AM_V@)
 am__v_P_ = $(am__v_P_ at AM_DEFAULT_V@)
@@ -464,6 +462,8 @@ distclean-hdr:
 	-rm -f config.h stamp-h1 include/GyotoConfig.h include/stamp-h2
 doc/Makefile: $(top_builddir)/config.status $(top_srcdir)/doc/Makefile.in
 	cd $(top_builddir) && $(SHELL) ./config.status $@
+doc/doxyfile: $(top_builddir)/config.status $(top_srcdir)/doc/doxyfile.in
+	cd $(top_builddir) && $(SHELL) ./config.status $@
 doc/user_guide/Makefile: $(top_builddir)/config.status $(top_srcdir)/doc/user_guide/Makefile.in
 	cd $(top_builddir) && $(SHELL) ./config.status $@
 yorick/Makefile: $(top_builddir)/config.status $(top_srcdir)/yorick/Makefile.in
@@ -486,8 +486,6 @@ python/setup_std.py: $(top_builddir)/config.status $(top_srcdir)/python/setup_st
 	cd $(top_builddir) && $(SHELL) ./config.status $@
 python/setup_lorene.py: $(top_builddir)/config.status $(top_srcdir)/python/setup_lorene.py.in
 	cd $(top_builddir) && $(SHELL) ./config.status $@
-doc/doxyfile: $(top_builddir)/config.status $(top_srcdir)/doc/doxyfile.in
-	cd $(top_builddir) && $(SHELL) ./config.status $@
 
 mostlyclean-libtool:
 	-rm -f *.lo
diff --git a/configure b/configure
index 3108694..aa4efea 100755
--- a/configure
+++ b/configure
@@ -1539,7 +1539,7 @@ Optional Features:
                           bug)
   --disable-debugging     remove debugging code for hypothetical speed gain
   --disable-pthreads      disable POSIX threads parallelization
-  --disable-doc           disable building documentation
+  --disable-doc           disable building documentation (automatically)
 
 Optional Packages:
   --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
@@ -19276,7 +19276,7 @@ cat >>confdefs.h <<_ACEOF
 _ACEOF
 
 
-ac_config_files="$ac_config_files Makefile bin/Makefile doc/Makefile doc/user_guide/Makefile lib/Makefile lib/gyoto.pc lib/gyoto-uninstalled.pc"
+ac_config_files="$ac_config_files Makefile bin/Makefile doc/Makefile doc/doxyfile doc/user_guide/Makefile lib/Makefile lib/gyoto.pc lib/gyoto-uninstalled.pc"
 
 if test "x$YORICK" != "x"; then :
   mySUBDIRS="$mySUBDIRS yorick"
@@ -19300,8 +19300,6 @@ if test "x$PYTHON" != "x"; then :
 fi
 if test "x$DOXYGEN" != "x" && test "x$mkdoc" == "xyes"; then :
   mySUBDIRS="$mySUBDIRS doc"
-   ac_config_files="$ac_config_files doc/doxyfile"
-
 
 
 fi
@@ -20451,6 +20449,7 @@ do
     "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
     "bin/Makefile") CONFIG_FILES="$CONFIG_FILES bin/Makefile" ;;
     "doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;;
+    "doc/doxyfile") CONFIG_FILES="$CONFIG_FILES doc/doxyfile" ;;
     "doc/user_guide/Makefile") CONFIG_FILES="$CONFIG_FILES doc/user_guide/Makefile" ;;
     "lib/Makefile") CONFIG_FILES="$CONFIG_FILES lib/Makefile" ;;
     "lib/gyoto.pc") CONFIG_FILES="$CONFIG_FILES lib/gyoto.pc" ;;
@@ -20465,7 +20464,6 @@ do
     "python/setup.py") CONFIG_FILES="$CONFIG_FILES python/setup.py" ;;
     "python/setup_std.py") CONFIG_FILES="$CONFIG_FILES python/setup_std.py" ;;
     "python/setup_lorene.py") CONFIG_FILES="$CONFIG_FILES python/setup_lorene.py" ;;
-    "doc/doxyfile") CONFIG_FILES="$CONFIG_FILES doc/doxyfile" ;;
 
   *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
   esac
diff --git a/configure.ac b/configure.ac
index 1628dda..a0d3483 100644
--- a/configure.ac
+++ b/configure.ac
@@ -697,7 +697,7 @@ _ACEOF
 # disable doc
 AC_ARG_ENABLE([doc],
   [AS_HELP_STRING([--disable-doc],
-     [disable building documentation])],
+     [disable building documentation (automatically)])],
   [AS_IF([test "x$enable_doc" == "xyes"],
      [mkdoc=yes],
      [test "x$enable_doc" == "xno"],
@@ -734,6 +734,7 @@ AC_DEFINE_UNQUOTED([GYOTO_SOVERS], ["${sovers}"], [Gyoto ABI version])
 AC_CONFIG_FILES([Makefile
                  bin/Makefile
                  doc/Makefile
+                 doc/doxyfile
                  doc/user_guide/Makefile
                  lib/Makefile
                  lib/gyoto.pc
@@ -769,7 +770,6 @@ AS_IF([test "x$PYTHON" != "x"],
 )
 AS_IF([test "x$DOXYGEN" != "x" && test "x$mkdoc" == "xyes"],
   [mySUBDIRS="$mySUBDIRS doc"
-   AC_CONFIG_FILES([doc/doxyfile])
   ]
 )
 AC_SUBST([mySUBDIRS])
diff --git a/doc/Makefile.in b/doc/Makefile.in
index f85035d..cb766ef 100644
--- a/doc/Makefile.in
+++ b/doc/Makefile.in
@@ -1,14 +1,19 @@
 SHELL=/bin/sh
 DOXYGEN=@DOXYGEN@
 
-all: doc
+all: doxygen.stamp latex.stamp
 
-doc: ../include/*.h
+doxygen.stamp: ../include/*.h
 @MKREF_TRUE@	$(DOXYGEN) doxyfile
+	touch  doxygen.stamp
+
+latex.stamp:
 @MKGUIDE_TRUE@	cd user_guide; $(MAKE)
+	touch latex.stamp
 
 distclean clean:
- at MKREF_TRUE@	rm -fr html latex
+	-rm doxygen.stamp latex.stamp
+	-rm -fr html xml latex
 @MKGUIDE_TRUE@	cd user_guide; $(MAKE) clean
 
 %: ;
diff --git a/doc/doxyfile.in b/doc/doxyfile.in
index d55054a..add6991 100644
--- a/doc/doxyfile.in
+++ b/doc/doxyfile.in
@@ -1121,7 +1121,7 @@ MAN_LINKS              = NO
 # generate an XML file that captures the structure of 
 # the code including all documentation.
 
-GENERATE_XML           = NO
+GENERATE_XML           = YES
 
 # The XML_OUTPUT tag is used to specify where the XML pages will be put. 
 # If a relative path is entered the value of OUTPUT_DIRECTORY will be 
diff --git a/python/Makefile.in b/python/Makefile.in
index 30e2f70..e7ed5e4 100644
--- a/python/Makefile.in
+++ b/python/Makefile.in
@@ -84,13 +84,19 @@ export CC
 GYOTO_EXTENSIONS =  _gyoto$(PYTHON_EXTENSION_SUFFIX) \
                     _gyoto_std$(PYTHON_EXTENSION_SUFFIX)
 GYOTO_PYFILES = gyoto.py gyoto_std.py
-GYOTO_SWIGFILES = gyoto.i gyoto_std.i
+GYOTO_SWIGFILES = gyoto.i gyoto_std.i gyoto_doc.i
 @HAVE_LORENE_TRUE at GYOTO_EXTENSIONS += _gyoto_lorene$(PYTHON_EXTENSION_SUFFIX)
 @HAVE_LORENE_TRUE at GYOTO_PYFILES += gyoto_lorene.py
 @HAVE_LORENE_TRUE at GYOTO_SWIGFILES += gyoto_lorene.i
 
 all: $(GYOTO_PYFILES) $(GYOTO_EXTENSIONS)
 
+../doc/xml/index.xml:
+	cd ../doc; $(MAKE) doxygen.stamp
+
+gyoto_doc.i: ../doc/xml/index.xml
+	$(PYTHON) $(srcdir)/doxy2swig.py $< $@ || rm $@
+
 _gyoto$(PYTHON_EXTENSION_SUFFIX): gyoto_wrap.cxx
 	$(PYTHON) $(srcdir)/setup.py build_ext
 
@@ -100,7 +106,7 @@ _gyoto_std$(PYTHON_EXTENSION_SUFFIX): gyoto_std_wrap.cxx
 _gyoto_lorene$(PYTHON_EXTENSION_SUFFIX): gyoto_lorene_wrap.cxx
 	$(PYTHON) $(srcdir)/setup_lorene.py build_ext
 
-gyoto.py gyoto_wrap.cxx: gyoto.i header.py
+gyoto.py gyoto_wrap.cxx: gyoto.i header.py gyoto_doc.i
 	swig2.0 -I$(srcdir)/../include -c++ -python  $(srcdir)/gyoto.i
 	mv gyoto.py trailer.py
 	cat header.py trailer.py > gyoto.py
@@ -150,7 +156,7 @@ uninstall:
 clean:
 	$(PYTHON) setup.py clean
 	-rm -Rf build
-	-rm gyoto*.py gyoto_wrap*.cxx 
+	-rm gyoto*.py gyoto_wrap*.cxx
 
 # Clean up the output of configure
 distclean: 
diff --git a/python/doxy2swig.py b/python/doxy2swig.py
new file mode 100644
index 0000000..0caaa93
--- /dev/null
+++ b/python/doxy2swig.py
@@ -0,0 +1,460 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""Doxygen XML to SWIG docstring converter.
+
+Usage:
+
+  doxy2swig.py [options] input.xml output.i
+
+Converts Doxygen generated XML files into a file containing docstrings
+that can be used by SWIG-1.3.x.  Note that you need to get SWIG
+version > 1.3.23 or use Robin Dunn's docstring patch to be able to use
+the resulting output.
+
+input.xml is your doxygen generated XML file and output.i is where the
+output will be written (the file will be clobbered).
+
+"""
+######################################################################
+#
+# This code is implemented using Mark Pilgrim's code as a guideline:
+#   http://www.faqs.org/docs/diveintopython/kgp_divein.html
+#
+# Author: Prabhu Ramachandran
+# License: BSD style
+#
+# Thanks:
+#   Johan Hake:  the include_function_definition feature
+#   Bill Spotz:  bug reports and testing.
+#   Sebastian Henschel:   Misc. enhancements.
+#
+# Gyoto history:
+#   2015-01-05:
+#      * download this file from
+#   http://www.aero.iitb.ac.in/~prabhu/software/code/python/doxy2swig.py
+#      * change my_open_write to open output with utf-8 encoding;
+#      * small modifications to make the script run under both
+#        python2.7 and python3.4.
+#
+######################################################################
+
+from xml.dom import minidom
+import re
+import textwrap
+import sys
+import types
+import os.path
+import optparse
+import codecs
+
+def my_open_read(source):
+    if hasattr(source, "read"):
+        return source
+    else:
+        return open(source)
+
+def my_open_write(dest):
+    if hasattr(dest, "write"):
+        return dest
+    else:
+        return codecs.open(dest, 'w', 'utf-8')
+
+
+class Doxy2SWIG:    
+    """Converts Doxygen generated XML files into a file containing
+    docstrings that can be used by SWIG-1.3.x that have support for
+    feature("docstring").  Once the data is parsed it is stored in
+    self.pieces.
+
+    """    
+    
+    def __init__(self, src, include_function_definition=True, quiet=False):
+        """Initialize the instance given a source object.  `src` can
+        be a file or filename.  If you do not want to include function
+        definitions from doxygen then set
+        `include_function_definition` to `False`.  This is handy since
+        this allows you to use the swig generated function definition
+        using %feature("autodoc", [0,1]).
+
+        """
+        f = my_open_read(src)
+        self.my_dir = os.path.dirname(f.name)
+        self.xmldoc = minidom.parse(f).documentElement
+        f.close()
+
+        self.pieces = []
+        self.pieces.append('\n// File: %s\n'%\
+                           os.path.basename(f.name))
+
+        self.space_re = re.compile(r'\s+')
+        self.lead_spc = re.compile(r'^(%feature\S+\s+\S+\s*?)"\s+(\S)')
+        self.multi = 0
+        self.ignores = ['inheritancegraph', 'param', 'listofallmembers',
+                        'innerclass', 'name', 'declname', 'incdepgraph',
+                        'invincdepgraph', 'programlisting', 'type',
+                        'references', 'referencedby', 'location',
+                        'collaborationgraph', 'reimplements',
+                        'reimplementedby', 'derivedcompoundref',
+                        'basecompoundref']
+        #self.generics = []
+        self.include_function_definition = include_function_definition
+        if not include_function_definition:
+            self.ignores.append('argsstring')
+
+        self.quiet = quiet
+            
+        
+    def generate(self):
+        """Parses the file set in the initialization.  The resulting
+        data is stored in `self.pieces`.
+
+        """
+        self.parse(self.xmldoc)
+    
+    def parse(self, node):
+        """Parse a given node.  This function in turn calls the
+        `parse_<nodeType>` functions which handle the respective
+        nodes.
+
+        """
+        pm = getattr(self, "parse_%s"%node.__class__.__name__)
+        pm(node)
+
+    def parse_Document(self, node):
+        self.parse(node.documentElement)
+
+    def parse_Text(self, node):
+        txt = node.data
+        txt = txt.replace('\\', r'\\\\')
+        txt = txt.replace('"', r'\"')
+        # ignore pure whitespace
+        m = self.space_re.match(txt)
+        if m and len(m.group()) == len(txt):
+            pass
+        else:
+            self.add_text(textwrap.fill(txt, break_long_words=False))
+
+    def parse_Element(self, node):
+        """Parse an `ELEMENT_NODE`.  This calls specific
+        `do_<tagName>` handers for different elements.  If no handler
+        is available the `generic_parse` method is called.  All
+        tagNames specified in `self.ignores` are simply ignored.
+        
+        """
+        name = node.tagName
+        ignores = self.ignores
+        if name in ignores:
+            return
+        attr = "do_%s" % name
+        if hasattr(self, attr):
+            handlerMethod = getattr(self, attr)
+            handlerMethod(node)
+        else:
+            self.generic_parse(node)
+            #if name not in self.generics: self.generics.append(name)
+
+    def parse_Comment(self, node):
+        """Parse a `COMMENT_NODE`.  This does nothing for now."""
+        return
+
+    def add_text(self, value):
+        """Adds text corresponding to `value` into `self.pieces`."""
+        if type(value) in (list, tuple):
+            self.pieces.extend(value)
+        else:
+            self.pieces.append(value)
+
+    def get_specific_nodes(self, node, names):
+        """Given a node and a sequence of strings in `names`, return a
+        dictionary containing the names as keys and child
+        `ELEMENT_NODEs`, that have a `tagName` equal to the name.
+
+        """
+        nodes = [(x.tagName, x) for x in node.childNodes \
+                 if x.nodeType == x.ELEMENT_NODE and \
+                 x.tagName in names]
+        return dict(nodes)
+
+    def generic_parse(self, node, pad=0):
+        """A Generic parser for arbitrary tags in a node.
+
+        Parameters:
+
+         - node:  A node in the DOM.
+         - pad: `int` (default: 0)
+
+           If 0 the node data is not padded with newlines.  If 1 it
+           appends a newline after parsing the childNodes.  If 2 it
+           pads before and after the nodes are processed.  Defaults to
+           0.
+
+        """
+        npiece = 0
+        if pad:
+            npiece = len(self.pieces)
+            if pad == 2:
+                self.add_text('\n')                
+        for n in node.childNodes:
+            self.parse(n)
+        if pad:
+            if len(self.pieces) > npiece:
+                self.add_text('\n')
+
+    def space_parse(self, node):
+        self.add_text(' ')
+        self.generic_parse(node)
+
+    do_ref = space_parse
+    do_emphasis = space_parse
+    do_bold = space_parse
+    do_computeroutput = space_parse
+    do_formula = space_parse
+
+    def do_compoundname(self, node):
+        self.add_text('\n\n')
+        data = node.firstChild.data
+        self.add_text('%%feature("docstring") %s "\n'%data)
+
+    def do_compounddef(self, node):
+        kind = node.attributes['kind'].value
+        if kind in ('class', 'struct'):
+            prot = node.attributes['prot'].value
+            if prot != 'public':
+                return
+            names = ('compoundname', 'briefdescription',
+                     'detaileddescription', 'includes')
+            first = self.get_specific_nodes(node, names)
+            for n in names:
+                if n in first:
+                    self.parse(first[n])
+            self.add_text(['";','\n'])
+            for n in node.childNodes:
+                if n not in first.values():
+                    self.parse(n)
+        elif kind in ('file', 'namespace'):
+            nodes = node.getElementsByTagName('sectiondef')
+            for n in nodes:
+                self.parse(n)
+
+    def do_includes(self, node):
+        self.add_text('C++ includes: ')
+        self.generic_parse(node, pad=1)
+
+    def do_parameterlist(self, node):
+        text='unknown'
+        for key, val in node.attributes.items():
+            if key == 'kind':
+                if val == 'param': text = 'Parameters'
+                elif val == 'exception': text = 'Exceptions'
+                else: text = val
+                break
+        self.add_text(['\n', '\n', text, ':', '\n'])
+        self.generic_parse(node, pad=1)
+
+    def do_para(self, node):
+        self.add_text('\n')
+        self.generic_parse(node, pad=1)
+
+    def do_parametername(self, node):
+        self.add_text('\n')
+        try:
+            data=node.firstChild.data
+        except AttributeError: # perhaps a <ref> tag in it
+            data=node.firstChild.firstChild.data
+        if data.find('Exception') != -1:
+            self.add_text(data)
+        else:
+            self.add_text("%s: "%data)
+
+    def do_parameterdefinition(self, node):
+        self.generic_parse(node, pad=1)
+
+    def do_detaileddescription(self, node):
+        self.generic_parse(node, pad=1)
+
+    def do_briefdescription(self, node):
+        self.generic_parse(node, pad=1)
+
+    def do_memberdef(self, node):
+        prot = node.attributes['prot'].value
+        id = node.attributes['id'].value
+        kind = node.attributes['kind'].value
+        tmp = node.parentNode.parentNode.parentNode
+        compdef = tmp.getElementsByTagName('compounddef')[0]
+        cdef_kind = compdef.attributes['kind'].value
+        
+        if prot == 'public':
+            first = self.get_specific_nodes(node, ('definition', 'name'))
+            name = first['name'].firstChild.data
+            if name[:8] == 'operator': # Don't handle operators yet.
+                return
+
+            if not 'definition' in first or \
+                   kind in ['variable', 'typedef']:
+                return
+
+            if self.include_function_definition:
+                defn = first['definition'].firstChild.data
+            else:
+                defn = ""
+            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', 'user-defined', ''):
+            self.generic_parse(node)
+
+    def do_header(self, node):
+        """For a user defined section def a header field is present
+        which should not be printed as such, so we comment it in the
+        output."""
+        data = node.firstChild.data
+        self.add_text('\n/*\n %s \n*/\n'%data)
+        # If our immediate sibling is a 'description' node then we
+        # should comment that out also and remove it from the parent
+        # node's children.
+        parent = node.parentNode
+        idx = parent.childNodes.index(node)
+        if len(parent.childNodes) >= idx + 2:
+            nd = parent.childNodes[idx+2]
+            if nd.nodeName == 'description':
+                nd = parent.removeChild(nd)
+                self.add_text('\n/*')
+                self.generic_parse(nd)
+                self.add_text('\n*/\n')
+
+    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)
+            if not self.quiet:
+                print("parsing file: %s"%fname)
+            p = Doxy2SWIG(fname, self.include_function_definition, self.quiet)
+            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:' or i == 'Exceptions:':
+                ret.extend([i, '\n-----------', '\n\n'])
+            elif i.find('// File:') > -1: # leave comments alone.
+                ret.extend([i, '\n'])
+            else:
+                _tmp = textwrap.fill(i.strip(), break_long_words=False)
+                _tmp = self.lead_spc.sub(r'\1"\2', _tmp)
+                ret.extend([_tmp, '\n\n'])
+        return ret
+
+
+def convert(input, output, include_function_definition=True, quiet=False):
+    p = Doxy2SWIG(input, include_function_definition, quiet)
+    p.generate()
+    p.write(output)
+
+def main():
+    usage = __doc__
+    parser = optparse.OptionParser(usage)
+    parser.add_option("-n", '--no-function-definition',
+                      action='store_true',
+                      default=False,
+                      dest='func_def',
+                      help='do not include doxygen function definitions')
+    parser.add_option("-q", '--quiet',
+                      action='store_true',
+                      default=False,
+                      dest='quiet',
+                      help='be quiet and minimize output')
+    
+    options, args = parser.parse_args()
+    if len(args) != 2:
+        parser.error("error: no input and output specified")
+
+    convert(args[0], args[1], not options.func_def, options.quiet)
+    
+
+if __name__ == '__main__':
+    main()
diff --git a/python/gyoto.i b/python/gyoto.i
index d9775b4..5698459 100644
--- a/python/gyoto.i
+++ b/python/gyoto.i
@@ -1,6 +1,8 @@
 %module(docstring="The General relativitY Orbit Tracer of paris Observatory") gyoto
 %feature("autodoc", "1");
 
+%import gyoto_doc.i
+
 %define GYOTO_SWIGIMPORTED
 %enddef
 

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-astro/packages/gyoto.git



More information about the Debian-astro-commits mailing list