Skip to content

Commit a2eca72

Browse files
author
Gauvain Pocentek
committed
Automatic doc generation for BaseManager classes
Provide a sphinx extension that parses the required/optioanl attributes and add infoo to the class docstring.
1 parent 770dd4b commit a2eca72

File tree

5 files changed

+100
-8
lines changed

5 files changed

+100
-8
lines changed

docs/conf.py

+2-6
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,11 @@
2121
import sphinx
2222

2323
sys.path.append('../')
24+
sys.path.append(os.path.dirname(__file__))
2425
import gitlab
2526

2627
on_rtd = os.environ.get('READTHEDOCS', None) == 'True'
2728

28-
if sphinx.version_info < (1,3,):
29-
napoleon_version = "sphinxcontrib.napoleon"
30-
else:
31-
napoleon_version = "sphinx.ext.napoleon"
32-
3329
# If extensions (or modules to document with autodoc) are in another directory,
3430
# add these directories to sys.path here. If the directory is relative to the
3531
# documentation root, use os.path.abspath to make it absolute, like shown here.
@@ -44,7 +40,7 @@
4440
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
4541
# ones.
4642
extensions = [
47-
'sphinx.ext.autodoc', 'sphinx.ext.autosummary', napoleon_version,
43+
'sphinx.ext.autodoc', 'sphinx.ext.autosummary', 'ext.docstrings'
4844
]
4945

5046
# Add any paths that contain templates here, relative to this directory.

docs/ext/__init__.py

Whitespace-only changes.

docs/ext/docstrings.py

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import itertools
2+
import os
3+
4+
import jinja2
5+
import six
6+
import sphinx
7+
import sphinx.ext.napoleon as napoleon
8+
from sphinx.ext.napoleon.docstring import GoogleDocstring
9+
10+
11+
def setup(app):
12+
app.connect('autodoc-process-docstring', _process_docstring)
13+
app.connect('autodoc-skip-member', napoleon._skip_member)
14+
15+
conf = napoleon.Config._config_values
16+
17+
for name, (default, rebuild) in six.iteritems(conf):
18+
app.add_config_value(name, default, rebuild)
19+
return {'version': sphinx.__display_version__, 'parallel_read_safe': True}
20+
21+
22+
def _process_docstring(app, what, name, obj, options, lines):
23+
result_lines = lines
24+
docstring = GitlabDocstring(result_lines, app.config, app, what, name, obj,
25+
options)
26+
result_lines = docstring.lines()
27+
lines[:] = result_lines[:]
28+
29+
30+
class GitlabDocstring(GoogleDocstring):
31+
def _build_doc(self):
32+
cls = self._obj.obj_cls
33+
md_create_list = list(itertools.chain(cls.requiredUrlAttrs,
34+
cls.requiredCreateAttrs))
35+
opt_create_list = cls.optionalCreateAttrs
36+
37+
md_create_keys = opt_create_keys = "None"
38+
if md_create_list:
39+
md_create_keys = "%s" % ", ".join(['``%s``' % i for i in
40+
md_create_list])
41+
if opt_create_list:
42+
opt_create_keys = "%s" % ", ".join(['``%s``' % i for i in
43+
opt_create_list])
44+
45+
md_update_list = list(itertools.chain(cls.requiredUrlAttrs,
46+
cls.requiredUpdateAttrs))
47+
opt_update_list = cls.optionalUpdateAttrs
48+
49+
md_update_keys = opt_update_keys = "None"
50+
if md_update_list:
51+
md_update_keys = "%s" % ", ".join(['``%s``' % i for i in
52+
md_update_list])
53+
if opt_update_list:
54+
opt_update_keys = "%s" % ", ".join(['``%s``' % i for i in
55+
opt_update_list])
56+
57+
tmpl_file = os.path.join(os.path.dirname(__file__), 'template.j2')
58+
with open(tmpl_file) as fd:
59+
template = jinja2.Template(fd.read(), trim_blocks=False)
60+
output = template.render(filename=tmpl_file,
61+
cls=cls,
62+
md_create_keys=md_create_keys,
63+
opt_create_keys=opt_create_keys,
64+
md_update_keys=md_update_keys,
65+
opt_update_keys=opt_update_keys)
66+
67+
return output.split('\n')
68+
69+
def __init__(self, *args, **kwargs):
70+
super(GitlabDocstring, self).__init__(*args, **kwargs)
71+
72+
if not hasattr(self._obj, 'obj_cls') or self._obj.obj_cls is None:
73+
return
74+
75+
self._parsed_lines = self._build_doc()

docs/ext/template.j2

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
Manager for :class:`gitlab.objects.{{ cls.__name__ }}` objects.
2+
3+
Available actions for this class:
4+
5+
{% if cls.canList %}- Objects listing{%endif%}
6+
{% if cls.canGet %}- Unique object retrieval{%endif%}
7+
{% if cls.canCreate %}- Object creation{%endif%}
8+
{% if cls.canUpdate %}- Object update{%endif%}
9+
{% if cls.canDelete %}- Object deletion{%endif%}
10+
11+
{% if cls.canCreate %}
12+
Mandatory arguments for object creation: {{ md_create_keys }}
13+
14+
Optional arguments for object creation: {{ opt_create_keys }}
15+
{% endif %}
16+
17+
{% if cls.canUpdate %}
18+
Mandatory arguments for object update: {{ md_create_keys }}
19+
20+
Optional arguments for object update: {{ opt_create_keys }}
21+
{% endif %}

test-requirements.txt

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@ discover
22
testrepository
33
hacking>=0.9.2,<0.10
44
httmock
5+
jinja2
56
mock
6-
sphinx>=1.1.2,!=1.2.0,<1.3
7-
sphinxcontrib-napoleon
7+
sphinx>=1.3

0 commit comments

Comments
 (0)