summaryrefslogtreecommitdiff
path: root/docs/sphinx/gnuradio_sphinx.py
diff options
context:
space:
mode:
Diffstat (limited to 'docs/sphinx/gnuradio_sphinx.py')
-rw-r--r--docs/sphinx/gnuradio_sphinx.py151
1 files changed, 151 insertions, 0 deletions
diff --git a/docs/sphinx/gnuradio_sphinx.py b/docs/sphinx/gnuradio_sphinx.py
new file mode 100644
index 000000000..6f35a6fce
--- /dev/null
+++ b/docs/sphinx/gnuradio_sphinx.py
@@ -0,0 +1,151 @@
+"""
+Customizations of sphinx for gnuradio use.
+"""
+
+from sphinx.ext.autodoc import py_ext_sig_re
+from sphinx.ext.autodoc import ClassDocumenter, FunctionDocumenter, members_option
+from sphinx.ext.autodoc import bool_option, members_set_option, identity
+from sphinx.ext.autodoc import ALL
+
+# A dictionary of the number of lines to delete from the beginning of docstrings
+lines_to_delete = {}
+
+def setup(sp):
+ # Fix line-breaks in signature.
+ sp.connect('autodoc-process-signature', fix_signature)
+ sp.connect('autodoc-process-docstring', remove_lines)
+ # Add node to autodocument signal-processing blocks.
+ sp.add_autodocumenter(BlockDocumenter)
+ sp.add_autodocumenter(PyBlockDocumenter)
+
+def remove_lines(app, what, name, obj, options, lines):
+ del_lines = lines_to_delete.get(name, 0)
+ # Don't delete any lines if this is called again.
+ lines_to_delete[name] = 0
+ lines[:] = lines[del_lines:]
+
+def fix_signature(app, what, name, obj, options, signature, return_annotation):
+ """
+ SWIG produces signature at the top of docstrings of the form
+ 'blah(int arg1, float arg2) -> return_type'
+ and if the string is long it breaks it over multiple lines.
+
+ Sphinx gets confused if it is broken over multiple lines.
+ fix_signature and remove_lines get around this problem.
+ """
+ if return_annotation is not None:
+ return
+
+ if hasattr(obj, '__doc__'):
+ docs = obj.__doc__
+ else:
+ docs = None
+ if not docs:
+ return None
+ doclines = docs.split('\n')
+ del_lines = remove_linebreaks_in_signature(doclines)
+ # match first line of docstring against signature RE
+ match = py_ext_sig_re.match(doclines[0])
+ if not match:
+ return None
+ exmod, path, base, args, retann = match.groups()
+ # ok, now jump over remaining empty lines and set the remaining
+ # lines as the new doclines
+ i = 1
+ while i < len(doclines) and not doclines[i].strip():
+ i += 1
+ lines_to_delete[name] = i - 1 + del_lines
+ # format args
+ signature = "({0})".format(args)
+ return signature, retann
+
+def remove_linebreaks_in_signature(lines):
+ alllines = '\n'.join(lines)
+ alllines = alllines.lstrip()
+ bits = alllines.split('->')
+ if len(bits) == 1:
+ return 0
+ after = '->'.join(bits[1:])
+ after_lines = after.split('\n')
+ ending = None
+ remainder = []
+ for line in after_lines:
+ if line and ending is None:
+ ending = line
+ elif ending is not None:
+ remainder.append(line)
+ first_line = ' '.join([a.strip() for a in bits[0].split('\n') if a.strip()]) + ' -> ' + ending.strip()
+ match = py_ext_sig_re.match(first_line)
+ # If it is a signature, make the change to lines.
+ if match:
+ new_lines = [first_line] + remainder
+ lines[:] = new_lines
+ return len(bits[0].split('\n'))
+ else:
+ return 0
+
+# These methods are not displayed in the documentation of blocks to
+# avoid redundancy.
+common_block_members =[
+ 'check_topology',
+ 'detail',
+ 'history',
+ 'input_signature',
+ 'name',
+ 'nitems_read',
+ 'nitems_written',
+ 'nthreads',
+ 'output_multiple',
+ 'output_signature',
+ 'relative_rate',
+ 'set_detail',
+ 'set_nthreads',
+ 'start',
+ 'stop',
+ 'thisown',
+ 'to_basic_block',
+ 'unique_id',
+ ]
+
+class BlockDocumenter(FunctionDocumenter):
+ """
+ Specialized Documenter subclass for gnuradio blocks.
+
+ It merges together the documentation for the generator function (e.g. gr.head)
+ with the wrapped sptr (e.g. gr.gr_head_sptr) to keep the documentation
+ tidier.
+ """
+ objtype = 'block'
+ directivetype = 'function'
+ # Don't want to use this for generic functions for give low priority.
+ priority = -10
+
+ def __init__(self, *args, **kwargs):
+ super(BlockDocumenter, self).__init__(*args, **kwargs)
+ # Get class name
+ bits = self.name.split('.')
+ if len(bits) != 3 or bits[0] != 'gnuradio':
+ raise ValueError("expected name to be of form gnuradio.x.y but it is {0}".format(self.name))
+ sptr_name = 'gnuradio.{0}.{0}_{1}_sptr'.format(bits[1], bits[2])
+ # Create a Class Documenter to create documentation for the classes members.
+ self.classdoccer = ClassDocumenter(self.directive, sptr_name, indent=self.content_indent)
+ self.classdoccer.real_modname = self.classdoccer.get_real_modname()
+ self.classdoccer.options.members = ALL
+ self.classdoccer.options.exclude_members = common_block_members
+ self.classdoccer.parse_name()
+ self.classdoccer.import_object()
+
+ def document_members(self, *args, **kwargs):
+ return self.classdoccer.document_members(*args, **kwargs)
+
+class PyBlockDocumenter(ClassDocumenter):
+ """
+ Specialized Documenter subclass for hierarchical python gnuradio blocks.
+ """
+ objtype = 'pyblock'
+ directivetype = 'class'
+
+ def __init__(self, *args, **kwargs):
+ super(PyBlockDocumenter, self).__init__(*args, **kwargs)
+ self.options.members = ALL
+ self.options.exclude_members = common_block_members