# # Copyright 2010-2012 Free Software Foundation, Inc. # # This file was generated by gr_modtool, a tool from the GNU Radio framework # This file is a part of gr-osmosdr # # 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 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # 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 swig_doc.py xml_path outputfilename The file instructs SWIG to transfer the doxygen comments into the python docstrings. """ from __future__ import unicode_literals import sys, time from doxyxml import DoxyIndex, DoxyClass, DoxyFriend, DoxyFunction, DoxyFile from doxyxml import DoxyOther, 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. """ @classmethod def includes(cls, item): if not isinstance(item, DoxyClass): return False # Check for a parsing error. if item.error(): return False 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): """ Convert unicode text into ascii and escape quotes and backslashes. """ if text is None: return '' out = text.encode('ascii', 'replace') # swig will require us to replace blackslash with 4 backslashes out = out.replace(b'\\', b'\\\\\\\\') out = out.replace(b'"', b'\\"').decode('ascii') return str(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: description.append(bd) if dd: 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, params=[]): """ 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 obj.name()) 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: name=obj.name() if "operator " in name: 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): """ 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 func.name()) 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) #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, params=params)) for func in klass.in_category(DoxyFunction): 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) 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: descriptions.append(class_desc) # Get the documentation associated with the make function make_func = di.get_member(make_name(block.name()), DoxyFunction) make_func_desc = combine_descriptions(make_func) if make_func_desc: descriptions.append(make_func_desc) # Get the documentation associated with the file try: block_file = di.get_member(block.name() + ".h", DoxyFile) file_desc = combine_descriptions(block_file) if file_desc: descriptions.append(file_desc) except base.Base.NoSuchMember: # Don't worry if we can't find a matching file. pass # 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)) output.append(make_func_entry(make_func, description=super_description, 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): output = [""" /* * This file was automatically generated using swig_doc.py. * * Any changes to it will be lost next time it is regenerated. */ """] if custom_output is not None: output.append(custom_output) # 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) # 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: 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 and not f.name().startswith('std::')] for f in funcs: try: output.append(make_func_entry(f)) except f.ParsingError: sys.stderr.write('Parsing error for function {0}\n'.format(f.name())) # Create docstrings for classes block_names = [block.name() for block in blocks] 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: 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. output = "\n\n".join(output) swig_doc = open(swigdocfilename, 'w') swig_doc.write(output) swig_doc.close() if __name__ == "__main__": # Parse command line options and set up doxyxml. err_msg = "Execute using: python swig_doc.py xml_path outputfilename" if len(sys.argv) != 3: raise Exception(err_msg) xml_path = sys.argv[1] swigdocfilename = sys.argv[2] di = DoxyIndex(xml_path) # gnuradio.gr.msq_queue.insert_tail 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)