~ubuntu-branches/ubuntu/saucy/gaupol/saucy-proposed

« back to all changes in this revision

Viewing changes to doc/sphinx/autogen.py

  • Committer: Package Import Robot
  • Author(s): Piotr Ożarowski
  • Date: 2013-01-06 17:10:10 UTC
  • mfrom: (1.1.15) (21 sid)
  • mto: This revision was merged to the branch mainline in revision 22.
  • Revision ID: package-import@ubuntu.com-20130106171010-u4r5prby5kd6dc3m
Tags: 0.21-1
* New upstream release
  - ported to Python 3 (dependencies and build process updated)
* python-aeidon binary package replaced with python3-aeidon
* Update debian/watch file to search for tar.xz files

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#!/usr/bin/env python
 
1
#!/usr/bin/env python3
 
2
# -*- coding: utf-8 -*-
2
3
 
3
 
# Copyright (C) 2009 Osmo Salomaa
 
4
# Copyright (C) 2009,2011 Osmo Salomaa
4
5
#
5
6
# Redistribution and use in source and binary forms, with or without
6
7
# modification, are permitted provided that the following conditions are
25
26
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26
27
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28
 
28
 
"""Walk module sources and autogenerate RST documentation files.
29
 
 
30
 
Usage: python autogen.py MODULE_NAME...
31
 
 
32
 
Requires RST template files 'class.rst.in', 'index.rst.in', 'module.rst.in' and
33
 
'source.rst.in' somewhere in templates_path as defined in conf.py. Suggested to
34
 
be used with the 'autoclean' extension. Together, this script, the templates
35
 
and the 'autoclean' extension should provide decent and complete API
36
 
documentation automatically generated from source code with verbose docstrings
37
 
written in reStructuredText markup. Additional hand-written documentation can
38
 
be added by editing the 'index.rst.in' template to include introductory text or
39
 
links to the separate, handwritten files.
40
 
"""
41
 
 
42
 
import codecs
 
29
"""
 
30
Walk module sources and autogenerate RST documentation files.
 
31
 
 
32
Usage: ``python autogen.py MODULE_NAME...``
 
33
 
 
34
Requires RST template files ``class.rst.in``, ``index.rst.in``,
 
35
``module.rst.in`` and ``source.rst.in`` somewhere in ``templates_path`` as
 
36
defined in ``conf.py``. Suggested to be used with the ``autoclean`` extension.
 
37
Together, this script, the templates and the ``autoclean`` extension should
 
38
provide decent and complete API documentation automatically generated from
 
39
source code with verbose docstrings written in reStructuredText markup.
 
40
Additional hand-written documentation can be added by editing the
 
41
``index.rst.in`` template to include introductory text or links to the
 
42
separate, handwritten files.
 
43
"""
 
44
 
43
45
import imp
44
46
import inspect
45
47
import jinja2
51
53
 
52
54
 
53
55
def document_class(names, cls):
54
 
    """Write RST-file documenting class and its members."""
55
 
    print ".".join(names)
 
56
    """Write RST-file documenting `cls` and its members."""
 
57
    print(".".join(names))
56
58
    write_template("class",
57
59
                   names,
58
60
                   anchestors=get_anchestors(cls),
65
67
                   source_fname=get_source_fname(cls))
66
68
 
67
69
def document_module(names, module):
68
 
    """Write RST-file documenting module and its members."""
69
 
    print ".".join(names)
 
70
    """Write RST-file documenting `module` and its members."""
 
71
    print(".".join(names))
70
72
    document_source(names, module)
71
73
    write_template("module",
72
74
                   names,
87
89
                       getattr(module, name))
88
90
 
89
91
def document_source(names, module):
90
 
    """Write RST-file with module source code."""
 
92
    """Write RST-file with `module` source code."""
91
93
    names_out = list(names)
92
 
    names_out[-1] = "%s_source" % names_out[-1]
 
94
    names_out[-1] = "{}_source".format(names_out[-1])
93
95
    write_template("source",
94
96
                   names_out,
95
97
                   module=".".join(names),
97
99
                   source_include=get_source_include(module))
98
100
 
99
101
def filter_members(members):
100
 
    """Return subset of members to appear in documentation."""
 
102
    """Return subset of `members` to appear in documentation."""
101
103
    if not conf.private_members:
102
104
        members = [x for x in members
103
105
                   if (not x.startswith("_") or
104
106
                       x in conf.include_members)]
 
107
 
105
108
    members = set(members) - set(conf.exclude_members)
106
 
    members = [x for x in members
107
 
               if not x.endswith(tuple(conf.exclude_members_endswith))]
 
109
    exclude = tuple(conf.exclude_members_endswith)
 
110
    members = [x for x in members if not x.endswith(exclude)]
108
111
    return sorted(list(members))
109
112
 
110
113
def get_anchestors(cls):
112
115
    if not cls.__bases__:
113
116
        return []
114
117
    base = cls.__bases__[0]
115
 
    name = "%s.%s" % (base.__module__, base.__name__)
 
118
    name = "{}.{}".format(base.__module__, base.__name__)
116
119
    name = name.replace("__builtin__.", "")
117
120
    return [name] + get_anchestors(base)
118
121
 
119
122
def get_classes(module):
120
 
    """Return list of names of classes defined in module."""
 
123
    """Return list of names of classes defined in `module`."""
121
124
    is_class = lambda x: inspect.isclass(getattr(module, x))
122
 
    classes = filter(is_class, module.__dict__.keys())
 
125
    classes = list(filter(is_class, list(module.__dict__.keys())))
123
126
    top = module.__name__.split(".")[0]
124
 
    for i in reversed(range(len(classes))):
 
127
    for i in list(reversed(range(len(classes)))):
125
128
        candidate = getattr(module, classes[i])
126
129
        parent = inspect.getmodule(candidate)
127
130
        if (parent is None or
130
133
    return filter_members(classes)
131
134
 
132
135
def get_functions(module):
133
 
    """Return list of names of functions defined in module."""
 
136
    """Return list of names of functions defined in `module`."""
134
137
    is_function = lambda x: inspect.isfunction(getattr(module, x))
135
 
    functions = filter(is_function, module.__dict__.keys())
 
138
    functions = list(filter(is_function, list(module.__dict__.keys())))
136
139
    top = module.__name__.split(".")[0]
137
 
    for i in reversed(range(len(functions))):
 
140
    for i in list(reversed(range(len(functions)))):
138
141
        candidate = getattr(module, functions[i])
139
142
        parent = inspect.getmodule(candidate)
140
143
        if (parent is None or
143
146
    return filter_members(functions)
144
147
 
145
148
def get_methods(cls):
146
 
    """Return list of names of methods defined in cls."""
147
 
    is_method = lambda x: inspect.ismethod(getattr(cls, x))
148
 
    methods = filter(is_method, cls.__dict__.keys())
 
149
    """Return list of names of methods defined in `cls`."""
 
150
    is_method = lambda x: inspect.isfunction(getattr(cls, x))
 
151
    methods = list(filter(is_method, list(cls.__dict__.keys())))
149
152
    return filter_members(methods)
150
153
 
151
154
def get_modules(module):
152
 
    """Return list of names of modules defined in module."""
 
155
    """Return list of names of modules defined in `module`."""
153
156
    is_module = lambda x: inspect.ismodule(getattr(module, x))
154
 
    modules = filter(is_module, module.__dict__.keys())
 
157
    modules = list(filter(is_module, list(module.__dict__.keys())))
155
158
    top = module.__name__.split(".")[0]
156
 
    for i in reversed(range(len(modules))):
 
159
    for i in list(reversed(range(len(modules)))):
157
160
        candidate = getattr(module, modules[i])
158
161
        parent = inspect.getmodule(candidate)
159
162
        if (parent is None or
163
166
    return filter_members(modules)
164
167
 
165
168
def get_source_doc(obj):
166
 
    """Return path to obj source RST document or None."""
 
169
    """Return path to `obj` source RST document or ``None``."""
167
170
    if get_source_path(obj) is None:
168
171
        return None
169
172
    dotted_name = None
173
176
        dotted_name = obj.__module__
174
177
    if dotted_name is None:
175
178
        return None
176
 
    return "/%s/%s_source" % (conf.autogen_output_path, dotted_name)
 
179
    return "/{}/{}_source".format(conf.autogen_output_path, dotted_name)
177
180
 
178
181
def get_source_fname(obj):
179
 
    """Return obj filename relative to project root or None."""
 
182
    """Return `obj` filename relative to project root or ``None``."""
180
183
    path = get_source_path(obj)
181
184
    if path is None:
182
185
        return None
189
192
    return fname
190
193
 
191
194
def get_source_include(obj):
192
 
    """Return obj filename relative to documentation root or None."""
 
195
    """Return `obj` filename relative to documentation root or ``None``."""
193
196
    fname = get_source_fname(obj)
194
197
    if fname is None:
195
198
        return None
196
 
    return "/%s" % os.path.join(conf.project_root, fname)
 
199
    return "/{}".format(os.path.join(conf.project_root, fname))
197
200
 
198
201
def get_source_path(obj):
199
 
    """Return absolute path to file obj is defined in or None."""
 
202
    """Return absolute path to file `obj` is defined in or ``None``."""
200
203
    try:
201
204
        path = inspect.getfile(obj)
202
205
    except TypeError:
206
209
    return os.path.abspath(path)
207
210
 
208
211
def main(modules):
209
 
    """Recursively document all modules."""
 
212
    """Recursively document all `modules`."""
210
213
    write_template("index",
211
214
                   ("index",),
212
215
                   project=conf.project,
219
222
                        __import__(module))
220
223
 
221
224
def write_template(name_in, names_out, **kwargs):
222
 
    """Write RST-template to file based in values in kwargs."""
 
225
    """Write RST-template to file based in values in `kwargs`."""
223
226
    directory = os.path.dirname(__file__)
224
 
    basename = "%s.rst.in" % name_in
 
227
    basename = "{}.rst.in".format(name_in)
225
228
    for template_dir in conf.templates_path:
226
229
        template_dir = os.path.join(directory, template_dir)
227
230
        template_file = os.path.join(template_dir, basename)
228
231
        if os.path.isfile(template_file): break
229
 
    text = codecs.open(template_file, "r", conf.source_encoding).read()
 
232
    encoding = conf.source_encoding
 
233
    text = open(template_file, "r", encoding=encoding).read()
230
234
    template = jinja2.Template(text)
231
 
    for key, value in kwargs.items():
232
 
        underline = "%s_double_underline" % key
 
235
    for key, value in list(kwargs.items()):
 
236
        underline = "{}_double_underline".format(key)
233
237
        kwargs[underline] = "=" * len(str(value))
234
 
        underline = "%s_single_underline" % key
 
238
        underline = "{}_single_underline".format(key)
235
239
        kwargs[underline] = "-" * len(str(value))
236
240
    text = template.render(**kwargs)
237
241
    if not text.endswith(("\n", "\r")):
238
 
        text = "%s%s" % (text, os.linesep)
 
242
        text = "".join((text, os.linesep))
239
243
    if name_in == "index":
240
 
        return codecs.open("index.rst", "w", conf.source_encoding).write(text)
 
244
        encoding = conf.source_encoding
 
245
        return open("index.rst", "w", encoding=encoding).write(text)
241
246
    names_out = list(names_out)
242
 
    names_out[-1] = "%s.rst" % names_out[-1]
 
247
    names_out[-1] = "{}.rst".format(names_out[-1])
243
248
    path = os.path.join(directory,
244
249
                        conf.autogen_output_path,
245
250
                        ".".join(names_out))
246
251
 
247
252
    if not os.path.isdir(os.path.dirname(path)):
248
253
        os.makedirs(os.path.dirname(path))
249
 
    codecs.open(path, "w", conf.source_encoding).write(text)
250
 
 
 
254
    encoding = conf.source_encoding
 
255
    open(path, "w", encoding=encoding).write(text)
251
256
 
252
257
if __name__ == "__main__":
253
258
    main(sys.argv[1:])