root/trunk/doc/wikidoc.py

Revision 451, 12.2 KB (checked in by mpereira, 18 months ago)

Added make_kernel() to analysis.py

Line 
1# coding: utf-8
2"""Writes documentation for the API in Wiki format."""
3
4import sys
5from NeuroTools import *
6from NeuroTools import __all__
7import types, string, re, logging
8
9#-- Set up logging -------------------------------------------------------------
10logging.basicConfig(level=logging.DEBUG,
11                    format='%(asctime)s %(levelname)-8s %(message)s',
12                    datefmt='%Y%m%d-%H%M%S',
13                    filename='wikidoc.log',
14                    filemode='w')
15# define a Handler which writes WARNING messages or higher to the sys.stderr
16console = logging.StreamHandler()
17console.setLevel(logging.WARNING)
18# set a format which is simpler for console use
19formatter = logging.Formatter('%(message)s')
20# tell the handler to use this format
21console.setFormatter(formatter)
22# add the handler to the root logger
23logging.getLogger('').addHandler(console)
24
25#-- Define global data ---------------------------------------------------------
26
27exclude = set(['__module__','__doc__','__builtins__','__file__','__class__',
28               '__delattr__', '__dict__', '__getattribute__', '__hash__',
29               '__new__','__reduce__','__reduce_ex__','__repr__','__setattr__',
30               '__str__','__weakref__',] #+ dir(int)
31             )
32#               'time','types','copy',]
33#exclude.remove('__init__')
34
35leftquote = re.compile(r"'\b")
36leftdblquote = re.compile(r'"\b')
37camelcase = re.compile(r'(\b([A-Z][a-z]+){2,99})')
38
39#classes = {}
40#functions = []
41#data = []
42
43#-- Process command line parameters --------------------------------------------
44output = sys.argv[1]
45modules = sys.argv[2:]
46
47logging.info('Generating API documentation in %s format' % output)
48
49#-- Define templates -----------------------------------------------------------
50if output == 'wiki':
51    default_arg_fmt  = '%s<span style="color:grey;">=%s</span>'
52    func_sig_fmt     = '%s(<span style="font-weight:normal;">%s</span>)'
53    function_fmt     = '\n====<span style="color:#0066ff;">%s</span>====\n'
54    method_fmt       = '\n====<span style="color:#8888ff;">%s</span>====\n'
55    staticmethod_fmt = '\n====<span style="color:#0066ff;">%s</span> (static)====\n'
56    dict_fmt         = "\n\n'''%s''' = {\n"
57    dict_fmt_end     = '}\n'
58    data_element_fmt = "\n'''%s''' = %s\n"
59    table_begin      = "{|\n"
60    table_end        = "|}\n"
61    table_row_fmt    = "| &nbsp;&nbsp;&nbsp; || %s ||: %s\n|-\n"
62    category_fmt     = '\n==%s==\n'
63    class_fmt        = '\n===<span style="color:green">%s</span>===\n'
64    horiz_line       = '\n----\n'
65elif output == 'trac':
66    module_fmt       = '\n= %s =\n'
67    default_arg_fmt  = '%s=%s'
68    func_sig_fmt     = '%s(%s)'
69    function_fmt     = '\n==== %s ====\n'
70    method_fmt       = '\n==== %s ====\n'
71    staticmethod_fmt = '\n==== %s ====\n'
72    dict_fmt         = "\n\n'''%s''' = {\n"
73    dict_fmt_end     = '}\n'
74    data_element_fmt = "\n'''%s''' = %s\n"
75    table_begin      = "\n"
76    table_end        = "\n"
77    table_row_fmt    = "|| %s ||: %s ||\n"
78    category_fmt     = '\n== %s ==\n'
79    class_fmt        = '\n=== %s ===\n'
80    horiz_line       = '\n----\n'
81elif output == 'latex':
82    default_arg_fmt  = '%s{\\color{grey}=%s}'
83    func_sig_fmt     = '%s(\\mdseries %s)'
84    function_fmt     = '\n\\paragraph*{\\color{brightblue}{%s}}\n'
85    method_fmt       = '\n\\paragraph*{\\color{brightblue}{%s}}\n'
86    staticmethod_fmt = '\n\\paragraph*{\\color{brightblue}{%s} (static)}\n'
87    dict_fmt         = '\n\\textbf{%s} = $\\lbrace$\n\n'
88    dict_fmt_end     = '$\\rbrace$\n'
89    data_element_fmt = "\n\\textbf{%s} = %s\n"
90    table_begin      = "\\begin{tabular}{lll}\n"
91    table_end        = "\\end{tabular}\n"
92    table_row_fmt    = '& %s & :%s\\\\\n'
93    category_fmt     = '\n\\subsection{%s}\n'
94    class_fmt        = '\n\\subsubsection*{%s}\n'
95    horiz_line       = ''
96             
97#-- Define functions -----------------------------------------------------------
98
99def _(str):
100    """Remove extraneous whitespace."""
101    lines = str.strip().split('\n')
102    lines = [line.strip() for line in lines]
103    return '\n'.join(lines)
104
105def funcArgs(func):
106    logging.info('Called funcArgs(%s)' % func)
107    if hasattr(func,'im_func'):
108        func = func.im_func
109    code = func.func_code
110    fname = code.co_name
111    callargs = code.co_argcount
112    args = code.co_varnames[:callargs]
113    return "%s(%s)" % (fname, string.join(args,', '))
114
115def func_sig(func):
116    """Adapted from http://www.lemburg.com/python/hack.py, by  Marc-André Lemburg
117       Returns the signature of a Python function/method as string.
118       Keyword initializers are also shown using
119       repr(). Representations longer than 100 bytes are truncated.
120    """
121    logging.info('Called func_sig(%s)' % func)
122    if hasattr(func,'im_func'): # func is a method
123        func = func.im_func
124    try:
125        code = func.func_code
126        fname = code.co_name
127        callargs = code.co_argcount
128        # XXX Uses hard coded values taken from Include/compile.h
129        args = list(code.co_varnames[:callargs])
130        if func.func_defaults:
131            i = len(args) - len(func.func_defaults)
132            for default in func.func_defaults:
133                if isinstance(default,float):
134                    r = str(default)
135                else:
136                    try:
137                        r = repr(default)
138                    except:
139                        r = '<repr-error>'
140                if len(r) > 100:
141                    r = r[:100] + '...'
142                arg = args[i]
143                if arg[0] == '.':
144                    # anonymous arguments
145                    arg = '(...)'
146                args[i] = default_arg_fmt % (arg,r)
147                i = i + 1
148        if code.co_flags & 0x0004: # CO_VARARGS
149            args.append('*'+code.co_varnames[callargs])
150            callargs = callargs + 1
151        if code.co_flags & 0x0008: # CO_VARKEYWORDS
152            args.append('**'+code.co_varnames[callargs])
153            callargs = callargs + 1
154        return func_sig_fmt % (fname,string.join(args,', '))
155    except AttributeError:
156        logging.warning("%s has no attribute 'func_code'" % func)
157        return None
158
159#-- Main block -----------------------------------------------------------------
160
161outputStr = ''
162for module in modules: #__all__:
163    classes = {}
164    functions = []
165    data = []
166    logging.info("Gathering information from the %s module." % module)
167    for entry in eval('dir(%s)' % module):
168        if entry not in exclude:
169            instance = eval('%s.%s' % (module,entry))
170            entry_type = type(instance)
171            logging.info(%-30s %s' % (entry,entry_type))
172            if entry_type in [types.ClassType, types.TypeType]:
173                classes[entry] = { 'methods': [], 'data': [], 'staticmethods': [] }
174                for classentry in dir(instance):
175                    if classentry not in exclude and (classentry[0] != '_' or classentry[0:2] == '__'): # don't include private methods
176                        classentry_type = type(eval('%s.%s.%s' % (module,entry,classentry)))
177                        logging.info('    %-28s %s' % (classentry,classentry_type))
178                        if classentry_type == types.MethodType:
179                            classes[entry]['methods'].append(classentry)
180                        elif classentry_type == types.FunctionType:
181                            classes[entry]['staticmethods'].append(classentry)
182                        else:
183                            classes[entry]['data'].append(classentry)
184                    else:
185                        logging.info('    %-28s excluded' % classentry)
186            elif  entry_type == types.FunctionType:
187                functions.append(entry)
188            elif entry_type == types.ModuleType:
189                pass
190            else:
191                data.append(entry)
192        else:
193            logging.info(%-30s excluded' % entry)
194
195    # output starts here
196    #outputStr = ''
197    if output == 'latex':
198        outputStr += '\definecolor{brightblue}{rgb}{0.0,0.38,1.0}\n'
199        outputStr += '\definecolor{paleblue}{rgb}{0.5,0.5,1.0}\n'
200        outputStr += '\definecolor{grey}{rgb}{0.5,0.5,0.5}\n'
201   
202    outputStr += module_fmt % module
203    #outputStr += _(eval(module).__doc__)
204    logging.info("==== DATA ====")
205    outputStr += category_fmt % "Data"
206    for element in data:
207        instance = eval('%s.%s' % (module,element))
208        if type(instance) == types.DictType:
209            outputStr += dict_fmt % element
210            outputStr += table_begin
211            for k,v in instance.items():
212                if output == 'latex':
213                    v = str(v).replace('{',' $\\lbrace$').replace('}',' $\\rbrace$')
214                outputStr += table_row_fmt % (k,v)
215            outputStr += table_end
216            outputStr += dict_fmt_end
217        else:
218            outputStr +=  data_element_fmt % (element, instance)
219       
220    logging.info("==== FUNCTIONS ====")
221    outputStr += category_fmt % "Functions"
222    for funcname in functions:
223        funcinst = eval('%s.%s' % (module,funcname))
224        outputStr += function_fmt % func_sig(funcinst)
225        if funcinst.__doc__:
226            outputStr += _(funcinst.__doc__.strip())
227       
228    logging.info("==== CLASSES ====")
229    # sort classes by type:
230    error_classes = {}
231    celltype_classes = {} ####
232    other_classes = {}
233    for classname in classes.keys():
234        if classname.find('Error') > -1:
235            error_classes[classname] = classes[classname]
236        else:
237            other_classes[classname] = classes[classname]
238   
239    logging.info('Sorting classes...')
240    logging.info('Error classes:    %s' % ', '.join(error_classes.keys()))
241    #logging.info('Celltype classes: %s' % ', '.join(celltype_classes.keys()))
242    logging.info('Other classes:    %s' % ', '.join(other_classes.keys()))
243   
244    # Now iterate through the classes
245    outputStr += category_fmt % "Classes"
246    for classes in [celltype_classes, other_classes, error_classes]:
247        classlist = classes.keys()
248        classlist.sort()
249        for classname in classlist:
250            outputStr += class_fmt % classname
251            docstr = eval('%s.%s.__doc__' % (module,classname))
252            if docstr:
253                outputStr += _(docstr)
254            for methodname in classes[classname]['methods']:
255                methodinst = eval('%s.%s.%s' % (module,classname,methodname))
256                fs = func_sig(methodinst)
257                if fs:
258                    outputStr += method_fmt % fs
259                    if methodinst.__doc__:
260                        outputStr += _(methodinst.__doc__.strip())
261            for methodname in classes[classname]['staticmethods']:
262                methodinst = eval('%s.%s.%s' % (module,classname,methodname))
263                fs = func_sig(methodinst)
264                if fs:
265                    outputStr += staticmethod_fmt % fs
266                    if methodinst.__doc__:
267                        outputStr += _(methodinst.__doc__.strip())
268            for element in classes[classname]['data']:
269                instance = eval('%s.%s.%s' % (module,classname,element))
270                if type(instance) == types.DictType:
271                    outputStr += dict_fmt % element
272                    if len(instance) > 0:
273                        outputStr += table_begin
274                        for k,v in instance.items():
275                            if output == 'latex':
276                                v = str(v).replace('{',' $\\lbrace$').replace('}',' $\\rbrace$')
277                                outputStr += table_row_fmt % (k,v)
278                            elif output == 'wiki':
279                                outputStr += table_row_fmt % ('&quot;%s&quot;' % k,v)
280                            elif output == 'trac':
281                                outputStr += table_row_fmt % ("'%s'" % k,v)
282                        outputStr += table_end
283                    outputStr += dict_fmt_end
284                else:
285                    outputStr +=  data_element_fmt % (element, instance)
286                   
287            outputStr += horiz_line
288       
289if output == 'latex':
290    outputStr = outputStr.replace('_','\_')
291    outputStr = outputStr.replace('>','$>$')
292    outputStr = outputStr.replace('<','$<$')
293    outputStr = leftquote.sub('`',outputStr)
294    outputStr = leftdblquote.sub('``',outputStr)
295if output == 'trac':
296    outputStr = outputStr.replace('__','!__')
297    outputStr = camelcase.sub(r'!\1',outputStr)
298
299print outputStr
Note: See TracBrowser for help on using the browser.