Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #7786: autodoc: can't detect overloaded methods defined in other file #8283

Merged
merged 1 commit into from Oct 5, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGES
Expand Up @@ -42,6 +42,7 @@ Bugs fixed
* #8157: autodoc: TypeError is raised when annotation has invalid __args__
* #7964: autodoc: Tuple in default value is wrongly rendered
* #8200: autodoc: type aliases break type formatting of autoattribute
* #7786: autodoc: can't detect overloaded methods defined in other file
* #8192: napoleon: description is disappeared when it contains inline literals
* #8142: napoleon: Potential of regex denial of service in google style docs
* #8169: LaTeX: pxjahyper loaded even when latex_engine is not platex
Expand Down
30 changes: 18 additions & 12 deletions sphinx/ext/autodoc/__init__.py
Expand Up @@ -1471,22 +1471,14 @@ def format_signature(self, **kwargs: Any) -> str:
return ''

sig = super().format_signature()

overloaded = False
qualname = None
# TODO: recreate analyzer for the module of class (To be clear, owner of the method)
if self._signature_class and self._signature_method_name and self.analyzer:
qualname = '.'.join([self._signature_class.__qualname__,
self._signature_method_name])
if qualname in self.analyzer.overloads:
overloaded = True

sigs = []
if overloaded:

overloads = self.get_overloaded_signatures()
if overloads:
# Use signatures for overloaded methods instead of the implementation method.
method = safe_getattr(self._signature_class, self._signature_method_name, None)
__globals__ = safe_getattr(method, '__globals__', {})
for overload in self.analyzer.overloads.get(qualname):
for overload in overloads:
overload = evaluate_signature(overload, __globals__,
self.env.config.autodoc_type_aliases)

Expand All @@ -1500,6 +1492,20 @@ def format_signature(self, **kwargs: Any) -> str:

return "\n".join(sigs)

def get_overloaded_signatures(self) -> List[Signature]:
if self._signature_class and self._signature_method_name:
for cls in self._signature_class.__mro__:
try:
analyzer = ModuleAnalyzer.for_module(cls.__module__)
analyzer.parse()
qualname = '.'.join([cls.__qualname__, self._signature_method_name])
if qualname in analyzer.overloads:
return analyzer.overloads.get(qualname)
except PycodeError:
pass

return []

def add_directive_header(self, sig: str) -> None:
sourcename = self.get_sourcename()

Expand Down
5 changes: 5 additions & 0 deletions tests/roots/test-ext-autodoc/target/overload2.py
@@ -0,0 +1,5 @@
from target.overload import Bar


class Baz(Bar):
pass
16 changes: 16 additions & 0 deletions tests/test_ext_autodoc.py
Expand Up @@ -2002,6 +2002,22 @@ def test_overload(app):
]


@pytest.mark.sphinx('html', testroot='ext-autodoc')
def test_overload2(app):
options = {"members": None}
actual = do_autodoc(app, 'module', 'target.overload2', options)
assert list(actual) == [
'',
'.. py:module:: target.overload2',
'',
'',
'.. py:class:: Baz(x: int, y: int)',
' Baz(x: str, y: str)',
' :module: target.overload2',
'',
]


@pytest.mark.sphinx('html', testroot='ext-autodoc')
def test_pymodule_for_ModuleLevelDocumenter(app):
app.env.ref_context['py:module'] = 'target.classes'
Expand Down