1 #! /usr/bin/env python3
2 # -*- coding: utf-8 -*-
4 # Copyright (c) 2019. The SimGrid Team.
7 # This program is free software; you can redistribute it and/or modify it
8 # under the terms of the license (GNU LGPL) which comes with this package.
11 Search for symbols documented in both the XML files produced by Doxygen and the python modules,
12 but not documented with autodoxy in the RST files.
14 This script is tailored to SimGrid own needs and should be made more generic for autodoxy.
21 import xml.etree.ElementTree as ET
25 # 'build/xml/classsimgrid_1_1s4u_1_1Activity.xml',
26 'build/xml/classsimgrid_1_1s4u_1_1Actor.xml',
27 'build/xml/classsimgrid_1_1s4u_1_1Barrier.xml',
28 'build/xml/classsimgrid_1_1s4u_1_1Comm.xml',
29 'build/xml/classsimgrid_1_1s4u_1_1ConditionVariable.xml',
30 'build/xml/classsimgrid_1_1s4u_1_1Disk.xml',
31 'build/xml/classsimgrid_1_1s4u_1_1Engine.xml',
32 'build/xml/classsimgrid_1_1s4u_1_1ExecPar.xml',
33 'build/xml/classsimgrid_1_1s4u_1_1ExecSeq.xml',
34 'build/xml/classsimgrid_1_1s4u_1_1Exec.xml',
35 'build/xml/classsimgrid_1_1s4u_1_1Host.xml',
36 'build/xml/classsimgrid_1_1s4u_1_1Io.xml',
37 'build/xml/classsimgrid_1_1s4u_1_1Link.xml',
38 'build/xml/classsimgrid_1_1s4u_1_1Mailbox.xml',
39 'build/xml/classsimgrid_1_1s4u_1_1Mutex.xml',
40 'build/xml/classsimgrid_1_1s4u_1_1NetZone.xml',
41 'build/xml/classsimgrid_1_1s4u_1_1Semaphore.xml',
42 'build/xml/classsimgrid_1_1s4u_1_1VirtualMachine.xml'
53 ############ Search the python elements in the source, and report undocumented ones
56 # data structure in which we store the declaration we find
59 def handle_python_module(fullname, englobing, elm):
60 """Recursive function exploring the python modules."""
62 def found_decl(kind, obj):
63 """Helper function that add an object in the python_decl data structure"""
64 if not kind in python_decl: python_decl[kind] = []
65 python_decl[kind].append(obj)
68 if fullname in python_ignore:
69 print ("Ignore Python symbol '{}' as requested.".format(fullname))
72 if inspect.isroutine(elm) and inspect.isclass(englobing):
73 found_decl("method", fullname)
74 # print('.. automethod:: {}'.format(fullname))
75 elif inspect.isroutine(elm) and (not inspect.isclass(englobing)):
76 found_decl("function", fullname)
77 # print('.. autofunction:: {}'.format(fullname))
78 elif inspect.isdatadescriptor(elm):
79 found_decl("attribute", fullname)
80 # print('.. autoattribute:: {}'.format(fullname))
81 elif isinstance(elm, str) or isinstance(elm, int): # We do have such a data, directly in the SimGrid top module
82 found_decl("data", fullname)
83 # print('.. autodata:: {}'.format(fullname))
84 elif inspect.ismodule(elm) or inspect.isclass(elm):
85 for name, data in inspect.getmembers(elm):
86 if name.startswith('__'):
88 # print("Recurse on {}.{}".format(fullname, name))
89 handle_python_module("{}.{}".format(fullname, name), elm, data)
91 print('UNHANDLED TYPE {} : {!r} Type: {}'.format(fullname, elm, type(elm)))
93 # Start the recursion on the provided Python modules
94 for name in python_modules:
95 module = __import__(name)
96 for sub in dir(module):
99 handle_python_module("{}.{}".format(name, sub), module, getattr(module, sub))
101 # Forget about the python declarations that were actually done in the RST
102 for kind in python_decl:
103 with os.popen('grep \'[[:blank:]]*auto{}::\' source/*rst|sed \'s/^.*auto{}:: //\''.format(kind, kind)) as pse:
104 for fullname in (l.strip() for l in pse):
105 if not fullname in python_decl[kind]:
106 print("Warning: {} documented but declaration not found in python.".format(fullname))
108 python_decl[kind].remove(fullname)
109 # Dump the missing ones
110 for kind in python_decl:
111 for fullname in python_decl[kind]:
112 print("Missing decl: .. auto{}:: {}".format(kind, fullname))
114 ################ And now deal with Doxygen declarations
117 doxy_funs = {} # {classname: {func_name: [args]} }
118 doxy_vars = {} # {classname: [names]}
120 # find the declarations in the XML files
121 for arg in xml_files[:1]:
122 if arg[-4:] != '.xml':
123 print ("Argument '{}' does not end with '.xml'".format(arg))
125 print("Parse file {}".format(arg))
127 for elem in tree.findall(".//compounddef"):
128 if elem.attrib["prot"] != "public":
130 if "compoundname" in elem:
131 raise Exception("Compound {} has no 'compoundname' child tag.".format(elem))
132 compoundname = elem.find("compoundname").text
133 #print ("compoundname {}".format(compoundname))
134 for member in elem.findall('.//memberdef'):
135 if member.attrib["prot"] != "public":
137 kind = member.attrib["kind"]
138 name = member.find("name").text
139 if kind == "variable":
140 if not compoundname in doxy_vars: doxy_vars[compoundname] = []
141 doxy_vars[compoundname].append(name)
142 elif kind == "function":
143 args = member.find('argsstring').text
144 args = re.sub('\)[^)]*$', ')', args) # ignore what's after the parameters (eg, '=0' or ' const')
146 if not compoundname in doxy_funs: doxy_funs[compoundname] = {}
147 if not name in doxy_funs[compoundname]: doxy_funs[compoundname][name] = []
148 doxy_funs[compoundname][name].append(args)
150 print ("member {}::{} is of kind {}".format(compoundname, name, kind))
152 # Forget about the declarations that are done in the RST
153 with os.popen('grep autodoxymethod:: source/*rst|sed \'s/^.*autodoxymethod:: //\'') as pse:
154 for line in (l.strip() for l in pse):
155 (klass, obj, args) = (None, None, None)
157 (line, args) = line.split('(', 1)
158 args = "({}".format(args)
159 (klass, obj) = line.rsplit('::', 1)
161 if not klass in doxy_funs:
162 print("Warning: {} documented, but class {} not found in doxygen.".format(line, klass))
164 if not obj in doxy_funs[klass]:
165 print("Warning: Object {} documented but not found in {}".format(line, klass))
166 elif len(doxy_funs[klass][obj])==1:
167 del doxy_funs[klass][obj]
168 elif not args in doxy_funs[klass][obj]:
169 print("Warning: Function {}{} not found in {}".format(obj, args, klass))
171 # print("Found {} in {}".format(line, klass))
172 doxy_funs[klass][obj].remove(args)
173 if len(doxy_funs[klass][obj]) == 0:
174 del doxy_funs[klass][obj]
176 # Dump the undocumented Doxygen declarations
177 for obj in doxy_funs:
178 for meth in doxy_funs[obj]:
179 for args in doxy_funs[obj][meth]:
180 print("Missing decl: .. autodoxymethod:: {}::{}{}".format(obj, meth, args))
182 for obj in doxy_vars:
183 for meth in doxy_vars[obj]:
184 print("Missing decl: .. autodoxyfield:: {}::{}".format(obj, meth))