-
-
Notifications
You must be signed in to change notification settings - Fork 30
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
37526d5
commit d13759d
Showing
3 changed files
with
128 additions
and
120 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
import inspect | ||
import re | ||
|
||
from sphinx.ext.autodoc import MethodDocumenter | ||
|
||
|
||
class OverloadedPythonMethodDocumenter(MethodDocumenter): | ||
""" | ||
A method documenter which handles overloaded methods, via processing | ||
the docstrings generated by SIP | ||
""" | ||
|
||
objtype = "method" | ||
priority = MethodDocumenter.priority | ||
|
||
@classmethod | ||
def can_document_member(cls, member, membername, isattr, parent): | ||
return MethodDocumenter.can_document_member(member, membername, isattr, parent) | ||
|
||
@staticmethod | ||
def parse_signatures(docstring): | ||
""" | ||
Extracts each signature from a sip generated docstring | ||
""" | ||
signature_pattern = r"(\w+\(.*?\))(?:\s*->\s*\(?\w+(?:,\s*\w+)*\)?)?" | ||
res = [] | ||
current_signature_docs = [] | ||
for line in docstring.split("\n"): | ||
|
||
if re.match(signature_pattern, line): | ||
if current_signature_docs: | ||
res.append(current_signature_docs) | ||
|
||
# Extract just the parameter part of each signature | ||
params = re.search(r"\((.*?)\)", line).group() | ||
current_signature_docs = [params] | ||
else: | ||
current_signature_docs += [line] | ||
if current_signature_docs: | ||
res.append(current_signature_docs) | ||
|
||
return res | ||
|
||
def parse_signature_blocks(self, docstring): | ||
""" | ||
Extracts each signature from a sip generated docstring, and | ||
returns each signature in a tuple with the docs for just | ||
that signature. | ||
""" | ||
res = [] | ||
current_sig = "" | ||
current_desc = "" | ||
for line in docstring.split("\n"): | ||
match = re.match( | ||
r"^\s*\w+(\([^)]*\)(?:\s*->\s*[^:\n]+)?)\s*((?:(?!\w+\().)*)\s*$", line | ||
) | ||
if match: | ||
if current_sig: | ||
res.append((current_sig, current_desc)) | ||
current_sig = match.group(1) | ||
current_desc = match.group(2) | ||
if current_desc: | ||
current_desc += "\n" | ||
else: | ||
current_desc += line + "\n" | ||
|
||
if current_sig: | ||
res.append((current_sig, current_desc)) | ||
|
||
return res | ||
|
||
def add_content(self, more_content): | ||
""" | ||
Parse the docstring to get all signatures and their descriptions | ||
""" | ||
sourcename = self.get_sourcename() | ||
docstring = inspect.getdoc(self.object) | ||
if docstring: | ||
# does this method have multiple overrides? | ||
signature_blocks = self.parse_signature_blocks(docstring) | ||
|
||
if len(signature_blocks) <= 1: | ||
# nope, just use standard formatter then! | ||
super().add_content(more_content) | ||
return | ||
|
||
# add a method output for EVERY override | ||
for i, (signature, description) in enumerate(signature_blocks): | ||
# this pattern is used in the autodoc source! | ||
old_indent = self.indent | ||
new_indent = ( | ||
" " | ||
* len(self.content_indent) | ||
* (len(self.indent) // len(self.content_indent) - 1) | ||
) | ||
self.indent = new_indent | ||
# skip this class, go straight to super. The add_directive_header | ||
# implementation from this class will omit the signatures of | ||
# overridden methods | ||
super().add_directive_header(signature) | ||
self.indent = old_indent | ||
|
||
if i > 0: | ||
# we can only index the first signature! | ||
self.add_line(":no-index:", sourcename) | ||
|
||
self.add_line("", sourcename) | ||
|
||
doc_for_this_override = self.object_name + signature + "\n" + description | ||
for line in self.process_doc([doc_for_this_override.split("\n")]): | ||
self.add_line(line, sourcename) | ||
|
||
def add_directive_header(self, sig): | ||
# Parse the docstring to get all signatures | ||
docstring = inspect.getdoc(self.object) | ||
if docstring: | ||
signatures = self.parse_signatures(docstring) | ||
else: | ||
signatures = [sig] # Use the original signature if no docstring | ||
|
||
if len(signatures) > 1: | ||
# skip overridden method directive headers here, we will generate | ||
# them later when we pass the actual docstring | ||
return | ||
|
||
return super().add_directive_header(sig) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters