commit-gnuradio
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Commit-gnuradio] [gnuradio] 03/08: modtool: update python docstring gen


From: git
Subject: [Commit-gnuradio] [gnuradio] 03/08: modtool: update python docstring generation
Date: Tue, 16 Aug 2016 16:24:33 +0000 (UTC)

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

jcorgan pushed a commit to branch master
in repository gnuradio.

commit ac925c426dd8dc75b6ee0bd82506e0f59cc5f207
Author: Sebastian Müller <address@hidden>
Date:   Mon Aug 15 16:05:25 2016 +0200

    modtool: update python docstring generation
---
 .../gr-newmod/docs/doxygen/doxyxml/doxyindex.py    |  86 +++++++++++--
 .../modtool/gr-newmod/docs/doxygen/swig_doc.py     | 143 ++++++++++++++++-----
 2 files changed, 183 insertions(+), 46 deletions(-)

diff --git 
a/gr-utils/python/modtool/gr-newmod/docs/doxygen/doxyxml/doxyindex.py 
b/gr-utils/python/modtool/gr-newmod/docs/doxygen/doxyxml/doxyindex.py
index 0132ab8..78e8153 100644
--- a/gr-utils/python/modtool/gr-newmod/docs/doxygen/doxyxml/doxyindex.py
+++ b/gr-utils/python/modtool/gr-newmod/docs/doxygen/doxyxml/doxyindex.py
@@ -43,13 +43,16 @@ class DoxyIndex(Base):
         self._root = index.parse(os.path.join(self._xml_path, 'index.xml'))
         for mem in self._root.compound:
             converted = self.convert_mem(mem)
-            # For files we want the contents to be accessible directly
-            # from the parent rather than having to go through the file
-            # object.
+            # For files and namespaces we want the contents to be
+            # accessible directly from the parent rather than having
+            # to go through the file object.
             if self.get_cls(mem) == DoxyFile:
                 if mem.name.endswith('.h'):
                     self._members += converted.members()
                     self._members.append(converted)
+            elif self.get_cls(mem) == DoxyNamespace:
+                self._members += converted.members()
+                self._members.append(converted)
             else:
                 self._members.append(converted)
 
@@ -80,13 +83,29 @@ class DoxyCompMem(Base):
         self._data['brief_description'] = bd
         self._data['detailed_description'] = dd
 
+    def set_parameters(self, data):
+        vs = [ddc.value for ddc in data.detaileddescription.content_]
+        pls = []
+        for v in vs:
+            if hasattr(v, 'parameterlist'):
+                pls += v.parameterlist
+        pis = []
+        for pl in pls:
+            pis += pl.parameteritem
+        dpis = []
+        for pi in pis:
+            dpi = DoxyParameterItem(pi)
+            dpi._parse()
+            dpis.append(dpi)
+        self._data['params'] = dpis
+
+
 class DoxyCompound(DoxyCompMem):
     pass
 
 class DoxyMember(DoxyCompMem):
     pass
 
-
 class DoxyFunction(DoxyMember):
 
     __module__ = "gnuradio.utils.doxyxml"
@@ -98,10 +117,13 @@ class DoxyFunction(DoxyMember):
             return
         super(DoxyFunction, self)._parse()
         self.set_descriptions(self._parse_data)
-        self._data['params'] = []
-        prms = self._parse_data.param
-        for prm in prms:
-            self._data['params'].append(DoxyParam(prm))
+        self.set_parameters(self._parse_data)
+        if not self._data['params']:
+            # If the params weren't set by a comment then just grab the names.
+            self._data['params'] = []
+            prms = self._parse_data.param
+            for prm in prms:
+                self._data['params'].append(DoxyParam(prm))
 
     brief_description = property(lambda self: self.data()['brief_description'])
     detailed_description = property(lambda self: 
self.data()['detailed_description'])
@@ -121,9 +143,39 @@ class DoxyParam(DoxyMember):
         self.set_descriptions(self._parse_data)
         self._data['declname'] = self._parse_data.declname
 
+    @property
+    def description(self):
+        descriptions = []
+        if self.brief_description:
+            descriptions.append(self.brief_description)
+        if self.detailed_description:
+            descriptions.append(self.detailed_description)
+        return '\n\n'.join(descriptions)
+
     brief_description = property(lambda self: self.data()['brief_description'])
     detailed_description = property(lambda self: 
self.data()['detailed_description'])
-    declname = property(lambda self: self.data()['declname'])
+    name = property(lambda self: self.data()['declname'])
+
+class DoxyParameterItem(DoxyMember):
+    """A different representation of a parameter in Doxygen."""
+
+    def _parse(self):
+        if self._parsed:
+            return
+        super(DoxyParameterItem, self)._parse()
+        names = []
+        for nl in self._parse_data.parameternamelist:
+            for pn in nl.parametername:
+                names.append(description(pn))
+        # Just take first name
+        self._data['name'] = names[0]
+        # Get description
+        pd = description(self._parse_data.get_parameterdescription())
+        self._data['description'] = pd
+
+    description = property(lambda self: self.data()['description'])
+    name = property(lambda self: self.data()['name'])
+
 
 class DoxyClass(DoxyCompound):
 
@@ -139,12 +191,14 @@ class DoxyClass(DoxyCompound):
         if self._error:
             return
         self.set_descriptions(self._retrieved_data.compounddef)
+        self.set_parameters(self._retrieved_data.compounddef)
         # Sectiondef.kind tells about whether private or public.
         # We just ignore this for now.
         self.process_memberdefs()
 
     brief_description = property(lambda self: self.data()['brief_description'])
     detailed_description = property(lambda self: 
self.data()['detailed_description'])
+    params = property(lambda self: self.data()['params'])
 
 Base.mem_classes.append(DoxyClass)
 
@@ -177,6 +231,16 @@ class DoxyNamespace(DoxyCompound):
 
     kind = 'namespace'
 
+    def _parse(self):
+        if self._parsed:
+            return
+        super(DoxyNamespace, self)._parse()
+        self.retrieve_data()
+        self.set_descriptions(self._retrieved_data.compounddef)
+        if self._error:
+            return
+        self.process_memberdefs()
+
 Base.mem_classes.append(DoxyNamespace)
 
 
@@ -227,11 +291,11 @@ class DoxyOther(Base):
 
     __module__ = "gnuradio.utils.doxyxml"
 
-    kinds = set(['variable', 'struct', 'union', 'define', 'typedef', 'enum', 
'dir', 'page'])
+    kinds = set(['variable', 'struct', 'union', 'define', 'typedef', 'enum',
+                 'dir', 'page', 'signal', 'slot', 'property'])
 
     @classmethod
     def can_parse(cls, obj):
         return obj.kind in cls.kinds
 
 Base.mem_classes.append(DoxyOther)
-
diff --git a/gr-utils/python/modtool/gr-newmod/docs/doxygen/swig_doc.py 
b/gr-utils/python/modtool/gr-newmod/docs/doxygen/swig_doc.py
index 4e1ce2e..d3536db 100644
--- a/gr-utils/python/modtool/gr-newmod/docs/doxygen/swig_doc.py
+++ b/gr-utils/python/modtool/gr-newmod/docs/doxygen/swig_doc.py
@@ -1,5 +1,5 @@
 #
-# Copyright 2010,2011 Free Software Foundation, Inc.
+# Copyright 2010-2012 Free Software Foundation, Inc.
 #
 # This file is part of GNU Radio
 #
@@ -27,13 +27,10 @@ python docstrings.
 
 """
 
-import sys
-
-try:
-    from doxyxml import DoxyIndex, DoxyClass, DoxyFriend, DoxyFunction, 
DoxyFile, base
-except ImportError:
-    from gnuradio.doxyxml import DoxyIndex, DoxyClass, DoxyFriend, 
DoxyFunction, DoxyFile, base
+import sys, time
 
+from doxyxml import DoxyIndex, DoxyClass, DoxyFriend, DoxyFunction, DoxyFile
+from doxyxml import DoxyOther, base
 
 def py_name(name):
     bits = name.split('_')
@@ -56,7 +53,28 @@ class Block(object):
         # Check for a parsing error.
         if item.error():
             return False
-        return item.has_member(make_name(item.name()), DoxyFriend)
+        friendname = make_name(item.name())
+        is_a_block = item.has_member(friendname, DoxyFriend)
+        # But now sometimes the make function isn't a friend so check again.
+        if not is_a_block:
+            is_a_block = di.has_member(friendname, DoxyFunction)
+        return is_a_block
+
+class Block2(object):
+    """
+    Checks if doxyxml produced objects correspond to a new style
+    gnuradio block.
+    """
+
+    @classmethod
+    def includes(cls, item):
+        if not isinstance(item, DoxyClass):
+            return False
+        # Check for a parsing error.
+        if item.error():
+            return False
+        is_a_block2 = item.has_member('make', DoxyFunction) and 
item.has_member('sptr', DoxyOther)
+        return is_a_block2
 
 
 def utoascii(text):
@@ -83,9 +101,15 @@ def combine_descriptions(obj):
         description.append(dd)
     return utoascii('\n\n'.join(description)).strip()
 
+def format_params(parameteritems):
+    output = ['Args:']
+    template = '    {0} : {1}'
+    for pi in parameteritems:
+        output.append(template.format(pi.name, pi.description))
+    return '\n'.join(output)
 
 entry_templ = '%feature("docstring") {name} "{docstring}"'
-def make_entry(obj, name=None, templ="{description}", description=None):
+def make_entry(obj, name=None, templ="{description}", description=None, 
params=[]):
     """
     Create a docstring entry for a swig interface file.
 
@@ -102,13 +126,16 @@ def make_entry(obj, name=None, templ="{description}", 
description=None):
         return ''
     if description is None:
         description = combine_descriptions(obj)
+    if params:
+        description += '\n\n'
+        description += utoascii(format_params(params))
     docstring = templ.format(description=description)
     if not docstring:
         return ''
     return entry_templ.format(
         name=name,
         docstring=docstring,
-        )
+    )
 
 
 def make_func_entry(func, name=None, description=None, params=None):
@@ -121,27 +148,31 @@ def make_func_entry(func, name=None, description=None, 
params=None):
             used as the description instead of extracting it from func.
     params - a parameter list that overrides using func.params.
     """
-    if params is None:
-        params = func.params
-    params = [prm.declname for prm in params]
-    if params:
-        sig = "Params: (%s)" % ", ".join(params)
-    else:
-        sig = "Params: (NONE)"
-    templ = "{description}\n\n" + sig
-    return make_entry(func, name=name, templ=utoascii(templ),
-                      description=description)
-
-
-def make_class_entry(klass, description=None):
+    #if params is None:
+    #    params = func.params
+    #params = [prm.declname for prm in params]
+    #if params:
+    #    sig = "Params: (%s)" % ", ".join(params)
+    #else:
+    #    sig = "Params: (NONE)"
+    #templ = "{description}\n\n" + sig
+    #return make_entry(func, name=name, templ=utoascii(templ),
+    #                  description=description)
+    return make_entry(func, name=name, description=description, params=params)
+
+
+def make_class_entry(klass, description=None, ignored_methods=[], params=None):
     """
     Create a class docstring for a swig interface file.
     """
+    if params is None:
+        params = klass.params
     output = []
-    output.append(make_entry(klass, description=description))
+    output.append(make_entry(klass, description=description, params=params))
     for func in klass.in_category(DoxyFunction):
-        name = klass.name() + '::' + func.name()
-        output.append(make_func_entry(func, name=name))
+        if func.name() not in ignored_methods:
+            name = klass.name() + '::' + func.name()
+            output.append(make_func_entry(func, name=name))
     return "\n\n".join(output)
 
 
@@ -175,11 +206,33 @@ def make_block_entry(di, block):
     # the make function.
     output = []
     output.append(make_class_entry(block, description=super_description))
-    creator = block.get_member(block.name(), DoxyFunction)
     output.append(make_func_entry(make_func, description=super_description,
-                                  params=creator.params))
+                                  params=block.params))
     return "\n\n".join(output)
 
+def make_block2_entry(di, block):
+    """
+    Create class and function docstrings of a new style gnuradio block for a
+    swig interface file.
+    """
+    descriptions = []
+    # For new style blocks all the relevant documentation should be
+    # associated with the 'make' method.
+    class_description = combine_descriptions(block)
+    make_func = block.get_member('make', DoxyFunction)
+    make_description = combine_descriptions(make_func)
+    description = class_description + "\n\nConstructor Specific 
Documentation:\n\n" + make_description
+    # Associate the combined description with the class and
+    # the make function.
+    output = []
+    output.append(make_class_entry(
+        block, description=description,
+        ignored_methods=['make'], params=make_func.params))
+    makename = block.name() + '::make'
+    output.append(make_func_entry(
+        make_func, name=makename, description=description,
+        params=make_func.params))
+    return "\n\n".join(output)
 
 def make_swig_interface_file(di, swigdocfilename, custom_output=None):
 
@@ -196,32 +249,52 @@ def make_swig_interface_file(di, swigdocfilename, 
custom_output=None):
 
     # Create docstrings for the blocks.
     blocks = di.in_category(Block)
+    blocks2 = di.in_category(Block2)
+
     make_funcs = set([])
     for block in blocks:
         try:
             make_func = di.get_member(make_name(block.name()), DoxyFunction)
-            make_funcs.add(make_func.name())
-            output.append(make_block_entry(di, block))
+            # Don't want to risk writing to output twice.
+            if make_func.name() not in make_funcs:
+                make_funcs.add(make_func.name())
+                output.append(make_block_entry(di, block))
+        except block.ParsingError:
+            sys.stderr.write('Parsing error for block 
{0}\n'.format(block.name()))
+            raise
+
+    for block in blocks2:
+        try:
+            make_func = block.get_member('make', DoxyFunction)
+            make_func_name = block.name() +'::make'
+            # Don't want to risk writing to output twice.
+            if make_func_name not in make_funcs:
+                make_funcs.add(make_func_name)
+                output.append(make_block2_entry(di, block))
         except block.ParsingError:
-            print('Parsing error for block %s' % block.name())
+            sys.stderr.write('Parsing error for block 
{0}\n'.format(block.name()))
+            raise
 
     # Create docstrings for functions
     # Don't include the make functions since they have already been dealt with.
-    funcs = [f for f in di.in_category(DoxyFunction) if f.name() not in 
make_funcs]
+    funcs = [f for f in di.in_category(DoxyFunction)
+             if f.name() not in make_funcs and not 
f.name().startswith('std::')]
     for f in funcs:
         try:
             output.append(make_func_entry(f))
         except f.ParsingError:
-            print('Parsing error for function %s' % f.name())
+            sys.stderr.write('Parsing error for function 
{0}\n'.format(f.name()))
 
     # Create docstrings for classes
     block_names = [block.name() for block in blocks]
-    klasses = [k for k in di.in_category(DoxyClass) if k.name() not in 
block_names]
+    block_names += [block.name() for block in blocks2]
+    klasses = [k for k in di.in_category(DoxyClass)
+               if k.name() not in block_names and not 
k.name().startswith('std::')]
     for k in klasses:
         try:
             output.append(make_class_entry(k))
         except k.ParsingError:
-            print('Parsing error for class %s' % k.name())
+            sys.stderr.write('Parsing error for class {0}\n'.format(k.name()))
 
     # Docstrings are not created for anything that is not a function or a 
class.
     # If this excludes anything important please add it here.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]