summaryrefslogtreecommitdiff
path: root/cxmanage_api/docs/generate_api_rst.py
blob: 776dabe9bfbec2db0d6d96c685bc73816f17165d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
"""Generates .rst files for .py files encountered in the SRC_DIR

:author: Eric Vasquez
:contact: eric.vasquez@calxeda.com
:copyright: (c) 2012-2013, Calxeda Inc.

"""

import os
import sys
import glob

# #
# The actual NAME of your API, as if you were to import it.
API_NAME = 'cxmanage_api'

# #
# SRC_DIR is one directory level up from the docs dir
# assuming a file structure like:
# +--API/
#       |---src_file1.py
#       |---src_fileN.py
#       +---docs/
#               |--Makefile
#               +--generate_api_rst.py
SRC_DIR = os.path.dirname(os.path.abspath('.'))
RST_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'source')

# #
# Any files you don't want docs generated for (no extension needed)
#
# EXAMPLE: To exclude foo.py and bar.py ...
# BLACK_LIST = ['foo', 'bar']
#
BLACKLIST = ['__init__']

# #
# Add any custom title you want for a specific python source file.
#
# EXAMPLE:
# TITLES = {'some_obscure_script_name' : 'Some Less Obscure Title'}
#
TITLES = {
          'simg' : 'SIMG',
          'crc32' : 'CRC32',
          'ubootenv' : 'U-Boot Environment',
         }

def get_source(source_dir):
    """Iterates recursively over dirs and gets all of the <filename>.py files.


    :param source_dir: The (absolute) path to the source directory.
    :type source_dir: string

    :return: A mapping of file names to filename Titles.
    :rtype: dictionary
    """
    if (not source_dir.endswith('/')):
        source_dir += '/'

    source = {API_NAME : {}}
    paths = glob.glob(os.path.join(source_dir, '*.py'))
    for path in paths:
        f_path, _ = os.path.splitext(path)
        f_name = f_path.split(source_dir)[1]
        if (not f_name in BLACKLIST):
            if TITLES.has_key(f_name):
                source[API_NAME][f_name] = TITLES[f_name]
            else:
                source[API_NAME][f_name] = f_name.title()
        else:
            print 'Skipping docgen for source file: %s' % path

    return source

def parse_source(src_file):
    """Parses a given source file to get class and function names.

    :param src_file: A file path. (abspath)
    :type src_file: string
    :return: a dictionary mapping class to methods and a list of functions
    :rtype: dictionary

    """
    def _get_object_name(line):
        """Takes a class, function or method declaration and gets the name."""
        name = line.split()[1].split('(')[0].strip()
        return name.rstrip(':')

    #
    # Parse Source
    #
    classes, functions = {}, []
    with open(src_file, 'r') as file_:
        class_ = None
        lines = file_.readlines()

        for line in lines:
            if (line.startswith('class ')):
                name = _get_object_name(line)
                class_ = name
                classes[name] = []
            elif (line.startswith('    def ') and line.count('(')):
                if (class_):
                    name = _get_object_name(line)
                    if (not name.startswith('_')):
                        classes[class_].append(name)
            elif (line.startswith('def ') and line.count('(')):
                functions.append(_get_object_name(line))

    for class_name, function_names in classes.items():
        classes[class_name] = sorted(list(set(function_names)))

    return classes, sorted(list(set(functions)))

def main():
    """Entry point for this script."""
    src_files = get_source(SRC_DIR)
    for package, module in src_files.items():
        for module_name, module_title in module.items():
            doc = os.path.join(RST_DIR, '%s.rst' % module_name)
            with open('%s' % doc, 'w') as rst_file:
                print 'Generating Sphinx Docs for: %s' % doc
                py_src = os.path.join(SRC_DIR, '%s.py' % module_name)
                classes, functions = parse_source(py_src)
                rst_file.write(module_title + '\n')
                rst_file.write('_' * len(module_title) + '\n\n')

                if (len(functions) > 0):
                    rst_file.write('.. currentmodule:: %s.%s\n\n' %
                                   (package, module_name))
                    rst_file.write('.. autosummary::\n')
                    rst_file.write('    :nosignatures:\n\n')
                    for func in functions:
                        rst_file.write('    %s\n' % func)
                    rst_file.write('\n')

                if (classes != {}):
                    rst_file.write('.. currentmodule:: %s.%s\n\n' %
                                   (package, module_name))
                    rst_file.write('.. autosummary::\n')
                    rst_file.write('    :nosignatures:\n\n')
                    for class_name in classes.keys():
                        rst_file.write('    %s\n' % class_name)
                    rst_file.write('\n')
                    for class_name, function_list in classes.items():
                        if (len(function_list) > 0):
                            rst_file.write('    .. automethod::\n')
                            for function_name in function_list:
                                rst_file.write('        %s.%s\n' %
                                               (class_name, function_name))
                        rst_file.write('\n\n')

                for func in functions:
                    rst_file.write('.. autofunction:: %s\n' % func)

                for class_name in classes.keys():
                    rst_file.write('.. autoclass:: %s\n' % class_name)
                    rst_file.write('    :members:\n')
                    if (module_name not in BLACKLIST):
                        rst_file.write('    :inherited-members:\n')
                    rst_file.write('    :show-inheritance:\n')
                    rst_file.write('\n')


# Go!
if __name__ == '__main__':
    sys.exit(main())


# End of file: ./docs/generate_api_rst.py