diff --git a/CHANGES b/CHANGES index 84f1798c386..181b33ec3d8 100644 --- a/CHANGES +++ b/CHANGES @@ -41,6 +41,7 @@ Bugs fixed typing.Generic * #8157: autodoc: TypeError is raised when annotation has invalid __args__ * #7964: autodoc: Tuple in default value is wrongly rendered +* #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 diff --git a/sphinx/ext/autodoc/__init__.py b/sphinx/ext/autodoc/__init__.py index 6eff2710222..5b46339a121 100644 --- a/sphinx/ext/autodoc/__init__.py +++ b/sphinx/ext/autodoc/__init__.py @@ -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) @@ -1500,6 +1492,16 @@ 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__: + analyzer = ModuleAnalyzer.for_module(cls.__module__) + qualname = '.'.join([cls.__qualname__, self._signature_method_name]) + if qualname in analyzer.overloads: + return analyzer.overloads.get(qualname) + + return [] + def add_directive_header(self, sig: str) -> None: sourcename = self.get_sourcename() diff --git a/tests/roots/test-ext-autodoc/target/overload2.py b/tests/roots/test-ext-autodoc/target/overload2.py new file mode 100644 index 00000000000..e901f791b2f --- /dev/null +++ b/tests/roots/test-ext-autodoc/target/overload2.py @@ -0,0 +1,5 @@ +from target.overload import Bar + + +class Baz(Bar): + pass diff --git a/tests/test_ext_autodoc.py b/tests/test_ext_autodoc.py index 7fff09bb6b6..9cb54de5b06 100644 --- a/tests/test_ext_autodoc.py +++ b/tests/test_ext_autodoc.py @@ -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'