root / docs / doxygen / swig_doc.py @ 11d58fe2
History | View | Annotate | Download (8.4 kB)
| 1 | #
|
|---|---|
| 2 | # Copyright 2010,2011 Free Software Foundation, Inc.
|
| 3 | #
|
| 4 | # This file is part of GNU Radio
|
| 5 | #
|
| 6 | # GNU Radio is free software; you can redistribute it and/or modify
|
| 7 | # it under the terms of the GNU General Public License as published by
|
| 8 | # the Free Software Foundation; either version 3, or (at your option)
|
| 9 | # any later version.
|
| 10 | #
|
| 11 | # GNU Radio is distributed in the hope that it will be useful,
|
| 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 14 | # GNU General Public License for more details.
|
| 15 | #
|
| 16 | # You should have received a copy of the GNU General Public License
|
| 17 | # along with GNU Radio; see the file COPYING. If not, write to
|
| 18 | # the Free Software Foundation, Inc., 51 Franklin Street,
|
| 19 | # Boston, MA 02110-1301, USA.
|
| 20 | #
|
| 21 | """
|
| 22 | Creates the swig_doc.i SWIG interface file.
|
| 23 | Execute using: python swig_doc.py xml_path outputfilename
|
| 24 | |
| 25 | The file instructs SWIG to transfer the doxygen comments into the
|
| 26 | python docstrings.
|
| 27 | |
| 28 | """
|
| 29 | |
| 30 | import sys |
| 31 | |
| 32 | try:
|
| 33 | from doxyxml import DoxyIndex, DoxyClass, DoxyFriend, DoxyFunction, DoxyFile, base |
| 34 | except ImportError: |
| 35 | from gnuradio.doxyxml import DoxyIndex, DoxyClass, DoxyFriend, DoxyFunction, DoxyFile, base |
| 36 | |
| 37 | |
| 38 | def py_name(name): |
| 39 | bits = name.split('_')
|
| 40 | return '_'.join(bits[1:]) |
| 41 | |
| 42 | def make_name(name): |
| 43 | bits = name.split('_')
|
| 44 | return bits[0] + '_make_' + '_'.join(bits[1:]) |
| 45 | |
| 46 | |
| 47 | class Block(object): |
| 48 | """
|
| 49 | Checks if doxyxml produced objects correspond to a gnuradio block.
|
| 50 | """ |
| 51 | |
| 52 | @classmethod
|
| 53 | def includes(cls, item): |
| 54 | if not isinstance(item, DoxyClass): |
| 55 | return False |
| 56 | # Check for a parsing error.
|
| 57 | if item.error():
|
| 58 | return False |
| 59 | return item.has_member(make_name(item.name()), DoxyFriend)
|
| 60 | |
| 61 | |
| 62 | def utoascii(text): |
| 63 | """
|
| 64 | Convert unicode text into ascii and escape quotes.
|
| 65 | """ |
| 66 | if text is None: |
| 67 | return '' |
| 68 | out = text.encode('ascii', 'replace') |
| 69 | out = out.replace('"', '\\"') |
| 70 | return out
|
| 71 | |
| 72 | |
| 73 | def combine_descriptions(obj): |
| 74 | """
|
| 75 | Combines the brief and detailed descriptions of an object together.
|
| 76 | """ |
| 77 | description = [] |
| 78 | bd = obj.brief_description.strip() |
| 79 | dd = obj.detailed_description.strip() |
| 80 | if bd:
|
| 81 | description.append(bd) |
| 82 | if dd:
|
| 83 | description.append(dd) |
| 84 | return utoascii('\n\n'.join(description)).strip() |
| 85 | |
| 86 | |
| 87 | entry_templ = '%feature("docstring") {name} "{docstring}"'
|
| 88 | def make_entry(obj, name=None, templ="{description}", description=None): |
| 89 | """
|
| 90 | Create a docstring entry for a swig interface file.
|
| 91 |
|
| 92 | obj - a doxyxml object from which documentation will be extracted.
|
| 93 | name - the name of the C object (defaults to obj.name())
|
| 94 | templ - an optional template for the docstring containing only one
|
| 95 | variable named 'description'.
|
| 96 | description - if this optional variable is set then it's value is
|
| 97 | used as the description instead of extracting it from obj.
|
| 98 | """ |
| 99 | if name is None: |
| 100 | name=obj.name() |
| 101 | if description is None: |
| 102 | description = combine_descriptions(obj) |
| 103 | docstring = templ.format(description=description) |
| 104 | if not docstring: |
| 105 | return '' |
| 106 | return entry_templ.format(
|
| 107 | name=name, |
| 108 | docstring=docstring, |
| 109 | ) |
| 110 | |
| 111 | |
| 112 | def make_func_entry(func, name=None, description=None, params=None): |
| 113 | """
|
| 114 | Create a function docstring entry for a swig interface file.
|
| 115 | |
| 116 | func - a doxyxml object from which documentation will be extracted.
|
| 117 | name - the name of the C object (defaults to func.name())
|
| 118 | description - if this optional variable is set then it's value is
|
| 119 | used as the description instead of extracting it from func.
|
| 120 | params - a parameter list that overrides using func.params.
|
| 121 | """ |
| 122 | if params is None: |
| 123 | params = func.params |
| 124 | params = [prm.declname for prm in params] |
| 125 | if params:
|
| 126 | sig = "Params: (%s)" % ", ".join(params) |
| 127 | else:
|
| 128 | sig = "Params: (NONE)"
|
| 129 | templ = "{description}\n\n" + sig
|
| 130 | return make_entry(func, name=name, templ=utoascii(templ),
|
| 131 | description=description) |
| 132 | |
| 133 | |
| 134 | def make_class_entry(klass, description=None): |
| 135 | """
|
| 136 | Create a class docstring for a swig interface file.
|
| 137 | """ |
| 138 | output = [] |
| 139 | output.append(make_entry(klass, description=description)) |
| 140 | for func in klass.in_category(DoxyFunction): |
| 141 | name = klass.name() + '::' + func.name()
|
| 142 | output.append(make_func_entry(func, name=name)) |
| 143 | return "\n\n".join(output) |
| 144 | |
| 145 | |
| 146 | def make_block_entry(di, block): |
| 147 | """
|
| 148 | Create class and function docstrings of a gnuradio block for a
|
| 149 | swig interface file.
|
| 150 | """ |
| 151 | descriptions = [] |
| 152 | # Get the documentation associated with the class.
|
| 153 | class_desc = combine_descriptions(block) |
| 154 | if class_desc:
|
| 155 | descriptions.append(class_desc) |
| 156 | # Get the documentation associated with the make function
|
| 157 | make_func = di.get_member(make_name(block.name()), DoxyFunction) |
| 158 | make_func_desc = combine_descriptions(make_func) |
| 159 | if make_func_desc:
|
| 160 | descriptions.append(make_func_desc) |
| 161 | # Get the documentation associated with the file
|
| 162 | try:
|
| 163 | block_file = di.get_member(block.name() + ".h", DoxyFile)
|
| 164 | file_desc = combine_descriptions(block_file) |
| 165 | if file_desc:
|
| 166 | descriptions.append(file_desc) |
| 167 | except base.Base.NoSuchMember:
|
| 168 | # Don't worry if we can't find a matching file.
|
| 169 | pass
|
| 170 | # And join them all together to make a super duper description.
|
| 171 | super_description = "\n\n".join(descriptions)
|
| 172 | # Associate the combined description with the class and
|
| 173 | # the make function.
|
| 174 | output = [] |
| 175 | output.append(make_class_entry(block, description=super_description)) |
| 176 | creator = block.get_member(block.name(), DoxyFunction) |
| 177 | output.append(make_func_entry(make_func, description=super_description, |
| 178 | params=creator.params)) |
| 179 | return "\n\n".join(output) |
| 180 | |
| 181 | |
| 182 | def make_swig_interface_file(di, swigdocfilename, custom_output=None): |
| 183 | |
| 184 | output = ["""
|
| 185 | /*
|
| 186 | * This file was automatically generated using swig_doc.py.
|
| 187 | *
|
| 188 | * Any changes to it will be lost next time it is regenerated.
|
| 189 | */
|
| 190 | """]
|
| 191 | |
| 192 | if custom_output is not None: |
| 193 | output.append(custom_output) |
| 194 | |
| 195 | # Create docstrings for the blocks.
|
| 196 | blocks = di.in_category(Block) |
| 197 | make_funcs = set([])
|
| 198 | for block in blocks: |
| 199 | try:
|
| 200 | make_func = di.get_member(make_name(block.name()), DoxyFunction) |
| 201 | make_funcs.add(make_func.name()) |
| 202 | output.append(make_block_entry(di, block)) |
| 203 | except block.ParsingError:
|
| 204 | print('Parsing error for block %s' % block.name())
|
| 205 | |
| 206 | # Create docstrings for functions
|
| 207 | # Don't include the make functions since they have already been dealt with.
|
| 208 | funcs = [f for f in di.in_category(DoxyFunction) if f.name() not in make_funcs] |
| 209 | for f in funcs: |
| 210 | try:
|
| 211 | output.append(make_func_entry(f)) |
| 212 | except f.ParsingError:
|
| 213 | print('Parsing error for function %s' % f.name())
|
| 214 | |
| 215 | # Create docstrings for classes
|
| 216 | block_names = [block.name() for block in blocks] |
| 217 | klasses = [k for k in di.in_category(DoxyClass) if k.name() not in block_names] |
| 218 | for k in klasses: |
| 219 | try:
|
| 220 | output.append(make_class_entry(k)) |
| 221 | except k.ParsingError:
|
| 222 | print('Parsing error for class %s' % k.name())
|
| 223 | |
| 224 | # Docstrings are not created for anything that is not a function or a class.
|
| 225 | # If this excludes anything important please add it here.
|
| 226 | |
| 227 | output = "\n\n".join(output)
|
| 228 | |
| 229 | swig_doc = file(swigdocfilename, 'w') |
| 230 | swig_doc.write(output) |
| 231 | swig_doc.close() |
| 232 | |
| 233 | if __name__ == "__main__": |
| 234 | # Parse command line options and set up doxyxml.
|
| 235 | err_msg = "Execute using: python swig_doc.py xml_path outputfilename"
|
| 236 | if len(sys.argv) != 3: |
| 237 | raise StandardError(err_msg) |
| 238 | xml_path = sys.argv[1]
|
| 239 | swigdocfilename = sys.argv[2]
|
| 240 | di = DoxyIndex(xml_path) |
| 241 | |
| 242 | # gnuradio.gr.msq_queue.insert_tail and delete_head create errors unless docstrings are defined!
|
| 243 | # This is presumably a bug in SWIG.
|
| 244 | #msg_q = di.get_member(u'gr_msg_queue', DoxyClass)
|
| 245 | #insert_tail = msg_q.get_member(u'insert_tail', DoxyFunction)
|
| 246 | #delete_head = msg_q.get_member(u'delete_head', DoxyFunction)
|
| 247 | output = [] |
| 248 | #output.append(make_func_entry(insert_tail, name='gr_py_msg_queue__insert_tail'))
|
| 249 | #output.append(make_func_entry(delete_head, name='gr_py_msg_queue__delete_head'))
|
| 250 | custom_output = "\n\n".join(output)
|
| 251 | |
| 252 | # Generate the docstrings interface file.
|
| 253 | make_swig_interface_file(di, swigdocfilename, custom_output=custom_output) |