1
Description: Allow extraction of function signature from docstring for extension modules.
2
Backport upstream changesets a8b0ef275438 and de340a6098c7 to allow extraction
3
of function signature from docstring for extension modules.
5
Please note that the feature is disabled by default for the time being.
6
Bug-Debian: http://bugs.debian.org/630409
7
Bug: https://bitbucket.org/birkenfeld/sphinx/issue/564
10
--- a/doc/ext/autodoc.rst
11
+++ b/doc/ext/autodoc.rst
16
+.. confval:: autodoc_docstring_signature
18
+ Functions imported from C modules cannot be introspected, and therefore the
19
+ signature for such functions cannot be automatically determined. However, it
20
+ is an often-used convention to put the signature into the first line of the
21
+ function's docstring.
23
+ If this boolean value is set to ``True``, autodoc will look at the
24
+ first line of the docstring for functions and methods, and if it
25
+ looks like a signature, use the line as the signature and remove it
26
+ from the docstring content.
28
+ The default is ``False``.
30
+ .. versionadded:: 1.1
33
Docstring preprocessing
34
-----------------------
35
--- a/sphinx/ext/autodoc.py
36
+++ b/sphinx/ext/autodoc.py
38
# etc. don't support a prepended module name
39
self.add_line(u' :module: %s' % self.modname, '<autodoc>')
41
- def get_doc(self, encoding=None):
42
+ def get_doc(self, encoding=None, ignore=1):
43
"""Decode and return lines of the docstring(s) for the object."""
44
docstring = self.get_attr(self.object, '__doc__', None)
46
# make sure we have Unicode docstrings, then sanitize and split
48
- return [prepare_docstring(force_decode(docstring, encoding))]
49
+ return [prepare_docstring(force_decode(docstring, encoding), ignore)]
52
def process_doc(self, docstrings):
54
return modname, parents + [base]
57
-class FunctionDocumenter(ModuleLevelDocumenter):
58
+class DocstringSignatureMixin(object):
60
+ Mixin for FunctionDocumenter and MethodDocumenter to provide the
61
+ feature of reading the signature from the docstring.
64
+ def _find_signature(self, encoding=None):
65
+ docstrings = Documenter.get_doc(self, encoding, 2)
66
+ if len(docstrings) != 1:
68
+ doclines = docstrings[0]
69
+ setattr(self, '__new_doclines', doclines)
72
+ # match first line of docstring against signature RE
73
+ match = py_ext_sig_re.match(doclines[0])
76
+ exmod, path, base, args, retann = match.groups()
77
+ # the base name must match ours
78
+ if not self.objpath or base != self.objpath[-1]:
80
+ # ok, now jump over remaining empty lines and set the remaining
81
+ # lines as the new doclines
83
+ while i < len(doclines) and not doclines[i].strip():
85
+ setattr(self, '__new_doclines', doclines[i:])
88
+ def get_doc(self, encoding=None, ignore=1):
89
+ lines = getattr(self, '__new_doclines', None)
90
+ if lines is not None:
92
+ return Documenter.get_doc(self, encoding, ignore)
94
+ def format_signature(self):
95
+ if self.args is None and self.env.config.autodoc_docstring_signature:
96
+ # only act if a signature is not explicitly given already, and if
97
+ # the feature is enabled
98
+ result = self._find_signature()
99
+ if result is not None:
100
+ self.args, self.retann = result
101
+ return Documenter.format_signature(self)
104
+class FunctionDocumenter(DocstringSignatureMixin, ModuleLevelDocumenter):
106
Specialized Documenter subclass for functions.
109
def format_args(self):
110
if inspect.isbuiltin(self.object) or \
111
inspect.ismethoddescriptor(self.object):
112
- # can never get arguments of a C function or method
113
+ # cannot introspect arguments of a C function or method
116
argspec = inspect.getargspec(self.object)
118
self.add_line(_(u' Bases: %s') % ', '.join(bases),
121
- def get_doc(self, encoding=None):
122
+ def get_doc(self, encoding=None, ignore=1):
123
content = self.env.config.autoclass_content
126
@@ -1010,7 +1056,7 @@
130
-class MethodDocumenter(ClassLevelDocumenter):
131
+class MethodDocumenter(DocstringSignatureMixin, ClassLevelDocumenter):
133
Specialized Documenter subclass for methods (normal, static and class).
135
@@ -1225,6 +1271,7 @@
136
app.add_config_value('autoclass_content', 'class', True)
137
app.add_config_value('autodoc_member_order', 'alphabetic', True)
138
app.add_config_value('autodoc_default_flags', [], True)
139
+ app.add_config_value('autodoc_docstring_signature', False, True)
140
app.add_event('autodoc-process-docstring')
141
app.add_event('autodoc-process-signature')
142
app.add_event('autodoc-skip-member')
143
--- a/sphinx/util/docstrings.py
144
+++ b/sphinx/util/docstrings.py
149
-def prepare_docstring(s):
150
+def prepare_docstring(s, ignore=1):
152
Convert a docstring into lines of parseable reST. Return it as a list of
153
lines usable for inserting into a docutils ViewList (used as argument
155
this docstring and following content.
157
lines = s.expandtabs().splitlines()
158
- # Find minimum indentation of any non-blank lines after first line.
159
+ # Find minimum indentation of any non-blank lines after ignored lines.
161
- for line in lines[1:]:
162
+ for line in lines[ignore:]:
163
content = len(line.lstrip())
165
indent = len(line) - content
166
margin = min(margin, indent)
167
- # Remove indentation.
169
- lines[0] = lines[0].lstrip()
170
+ # Remove indentation from ignored lines.
171
+ for i in range(ignore):
173
+ lines[i] = lines[i].lstrip()
174
if margin < sys.maxint:
175
- for i in range(1, len(lines)): lines[i] = lines[i][margin:]
176
+ for i in range(ignore, len(lines)): lines[i] = lines[i][margin:]
177
# Remove any leading blank lines.
178
while lines and not lines[0]:
180
--- a/tests/test_autodoc.py
181
+++ b/tests/test_autodoc.py
183
'attribute', 'mdocattr')
184
del directive.env.temp_data['autodoc:class']
186
+ # test autodoc_docstring_signature
187
+ directive.env.config.autodoc_docstring_signature = True
188
+ assert_result_contains(
189
+ '.. py:method:: DocstringSig.meth(FOO, BAR=1) -> BAZ', 'method',
190
+ 'test_autodoc.DocstringSig.meth')
191
+ assert_result_contains(
192
+ ' rest of docstring', 'method', 'test_autodoc.DocstringSig.meth')
195
# --- generate fodder ------------
199
# should be documented as an alias
203
+class DocstringSig(object):
205
+ """meth(FOO, BAR=1) -> BAZ
206
+First line of docstring