256 lines
8.5 KiB

# Copyright 2010,2011 Free Software Foundation, Inc.
# This file is part of GNU Radio
# GNU Radio is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3, or (at your option)
# any later version.
# GNU Radio is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with GNU Radio; see the file COPYING. If not, write to
# the Free Software Foundation, Inc., 51 Franklin Street,
# Boston, MA 02110-1301, USA.
Creates the swig_doc.i SWIG interface file.
Execute using: python xml_path outputfilename
The file instructs SWIG to transfer the doxygen comments into the
python docstrings.
import sys
from doxyxml import DoxyIndex, DoxyClass, DoxyFriend, DoxyFunction, DoxyFile, base
except ImportError:
from gnuradio.doxyxml import DoxyIndex, DoxyClass, DoxyFriend, DoxyFunction, DoxyFile, base
def py_name(name):
bits = name.split('_')
return '_'.join(bits[1:])
def make_name(name):
bits = name.split('_')
return bits[0] + '_make_' + '_'.join(bits[1:])
class Block(object):
Checks if doxyxml produced objects correspond to a gnuradio block.
def includes(cls, item):
if not isinstance(item, DoxyClass):
return False
# Check for a parsing error.
if item.error():
return False
return item.has_member(make_name(, DoxyFriend)
def utoascii(text):
Convert unicode text into ascii and escape quotes.
if text is None:
return ''
out = text.encode('ascii', 'replace')
out = out.replace('"', '\\"')
return out
def combine_descriptions(obj):
Combines the brief and detailed descriptions of an object together.
description = []
bd = obj.brief_description.strip()
dd = obj.detailed_description.strip()
if bd:
if dd:
return utoascii('\n\n'.join(description)).strip()
entry_templ = '%feature("docstring") {name} "{docstring}"'
def make_entry(obj, name=None, templ="{description}", description=None):
Create a docstring entry for a swig interface file.
obj - a doxyxml object from which documentation will be extracted.
name - the name of the C object (defaults to
templ - an optional template for the docstring containing only one
variable named 'description'.
description - if this optional variable is set then it's value is
used as the description instead of extracting it from obj.
if name is None:
if "operator " in name:
return ''
if description is None:
description = combine_descriptions(obj)
docstring = templ.format(description=description)
if not docstring:
return ''
return entry_templ.format(
def make_func_entry(func, name=None, description=None, params=None):
Create a function docstring entry for a swig interface file.
func - a doxyxml object from which documentation will be extracted.
name - the name of the C object (defaults to
description - if this optional variable is set then it's value is
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)
sig = "Params: (NONE)"
templ = "{description}\n\n" + sig
return make_entry(func, name=name, templ=utoascii(templ),
def make_class_entry(klass, description=None):
Create a class docstring for a swig interface file.
output = []
output.append(make_entry(klass, description=description))
for func in klass.in_category(DoxyFunction):
name = + '::' +
output.append(make_func_entry(func, name=name))
return "\n\n".join(output)
def make_block_entry(di, block):
Create class and function docstrings of a gnuradio block for a
swig interface file.
descriptions = []
# Get the documentation associated with the class.
class_desc = combine_descriptions(block)
if class_desc:
# Get the documentation associated with the make function
make_func = di.get_member(make_name(, DoxyFunction)
make_func_desc = combine_descriptions(make_func)
if make_func_desc:
# Get the documentation associated with the file
block_file = di.get_member( + ".h", DoxyFile)
file_desc = combine_descriptions(block_file)
if file_desc:
except base.Base.NoSuchMember:
# Don't worry if we can't find a matching file.
# And join them all together to make a super duper description.
super_description = "\n\n".join(descriptions)
# Associate the combined description with the class and
# the make function.
output = []
output.append(make_class_entry(block, description=super_description))
creator = block.get_member(, DoxyFunction)
output.append(make_func_entry(make_func, description=super_description,
return "\n\n".join(output)
def make_swig_interface_file(di, swigdocfilename, custom_output=None):
output = ["""
* This file was automatically generated using
* Any changes to it will be lost next time it is regenerated.
if custom_output is not None:
# Create docstrings for the blocks.
blocks = di.in_category(Block)
make_funcs = set([])
for block in blocks:
make_func = di.get_member(make_name(, DoxyFunction)
output.append(make_block_entry(di, block))
except block.ParsingError:
print('Parsing error for block %s' %
# 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 not in make_funcs]
for f in funcs:
except f.ParsingError:
print('Parsing error for function %s' %
# Create docstrings for classes
block_names = [ for block in blocks]
klasses = [k for k in di.in_category(DoxyClass) if not in block_names]
for k in klasses:
except k.ParsingError:
print('Parsing error for class %s' %
# Docstrings are not created for anything that is not a function or a class.
# If this excludes anything important please add it here.
output = "\n\n".join(output)
swig_doc = file(swigdocfilename, 'w')
if __name__ == "__main__":
# Parse command line options and set up doxyxml.
err_msg = "Execute using: python xml_path outputfilename"
if len(sys.argv) != 3:
raise StandardError(err_msg)
xml_path = sys.argv[1]
swigdocfilename = sys.argv[2]
di = DoxyIndex(xml_path)
# and delete_head create errors unless docstrings are defined!
# This is presumably a bug in SWIG.
#msg_q = di.get_member(u'gr_msg_queue', DoxyClass)
#insert_tail = msg_q.get_member(u'insert_tail', DoxyFunction)
#delete_head = msg_q.get_member(u'delete_head', DoxyFunction)
output = []
#output.append(make_func_entry(insert_tail, name='gr_py_msg_queue__insert_tail'))
#output.append(make_func_entry(delete_head, name='gr_py_msg_queue__delete_head'))
custom_output = "\n\n".join(output)
# Generate the docstrings interface file.
make_swig_interface_file(di, swigdocfilename, custom_output=custom_output)