Skip to content

Commit 2cea8d4

Browse files
authored
Add fix for #296 (#297)
1 parent 01633e1 commit 2cea8d4

File tree

5 files changed

+66
-2
lines changed

5 files changed

+66
-2
lines changed

src/sphinx_autodoc_typehints/__init__.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import textwrap
77
import types
88
from ast import FunctionDef, Module, stmt
9+
from functools import lru_cache
910
from typing import Any, AnyStr, Callable, ForwardRef, NewType, TypeVar, get_type_hints
1011

1112
from sphinx.application import Sphinx
@@ -694,6 +695,29 @@ def validate_config(app: Sphinx, env: BuildEnvironment, docnames: list[str]) ->
694695
raise ValueError(f"typehints_formatter needs to be callable or `None`, not {formatter}")
695696

696697

698+
@lru_cache() # A cute way to make sure the function only runs once.
699+
def fix_autodoc_typehints_for_overloaded_methods() -> None:
700+
"""
701+
sphinx-autodoc-typehints responds to the "autodoc-process-signature" event
702+
to remove types from the signature line of functions.
703+
704+
Normally, `FunctionDocumenter.format_signature` and
705+
`MethodDocumenter.format_signature` call `super().format_signature` which
706+
ends up going to `Documenter.format_signature`, and this last method emits
707+
the `autodoc-process-signature` event. However, if there are overloads,
708+
`FunctionDocumenter.format_signature` does something else and the event
709+
never occurs.
710+
711+
Here we remove this alternative code path by brute force.
712+
713+
See https://github.com/tox-dev/sphinx-autodoc-typehints/issues/296
714+
"""
715+
from sphinx.ext.autodoc import FunctionDocumenter, MethodDocumenter
716+
717+
del FunctionDocumenter.format_signature
718+
del MethodDocumenter.format_signature
719+
720+
697721
def setup(app: Sphinx) -> dict[str, bool]:
698722
app.add_config_value("always_document_param_types", False, "html")
699723
app.add_config_value("typehints_fully_qualified", False, "env")
@@ -707,6 +731,7 @@ def setup(app: Sphinx) -> dict[str, bool]:
707731
app.connect("env-before-read-docs", validate_config) # config may be changed after “config-inited” event
708732
app.connect("autodoc-process-signature", process_signature)
709733
app.connect("autodoc-process-docstring", process_docstring)
734+
fix_autodoc_typehints_for_overloaded_methods()
710735
return {"parallel_read_safe": True}
711736

712737

tests/roots/test-dummy/dummy_module.py

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
from dataclasses import dataclass
22
from mailbox import Mailbox
3-
from typing import Union # noqa: F401 # needed for expansion of Optional
4-
from typing import Callable, Optional
3+
from typing import Callable, Optional, Union, overload
54

65

76
def get_local_function():
@@ -286,3 +285,27 @@ def func_with_examples() -> int:
286285
287286
Here are a couple of examples of how to use this function.
288287
"""
288+
289+
290+
@overload
291+
def func_with_overload(a: int, b: int) -> None: # noqa: U100
292+
...
293+
294+
295+
@overload
296+
def func_with_overload(a: str, b: str) -> None: # noqa: U100
297+
...
298+
299+
300+
def func_with_overload(a: Union[int, str], b: Union[int, str]) -> None: # noqa: U100
301+
"""
302+
f does the thing. The arguments can either be ints or strings but they must
303+
both have the same type.
304+
305+
Parameters
306+
----------
307+
a:
308+
The first thing
309+
b:
310+
The second thing
311+
"""

tests/roots/test-dummy/index.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,5 @@ Dummy Module
4040
.. autofunction:: dummy_module.mocked_import
4141

4242
.. autofunction:: dummy_module.func_with_examples
43+
44+
.. autofunction:: dummy_module.func_with_overload

tests/test_sphinx_autodoc_typehints.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -770,6 +770,18 @@ class dummy_module.DataClass(x)
770770
-[ Examples ]-
771771
772772
Here are a couple of examples of how to use this function.
773+
774+
dummy_module.func_with_overload(a, b)
775+
776+
f does the thing. The arguments can either be ints or strings but they must both have the same type.
777+
778+
Parameters:
779+
* **a** ("Union"["int", "str"]) -- The first thing
780+
781+
* **b** ("Union"["int", "str"]) -- The second thing
782+
783+
Return type:
784+
"None"
773785
"""
774786
expected_contents = dedent(expected_contents).format(**format_args).replace("–", "--")
775787
assert text_contents == maybe_fix_py310(expected_contents)

whitelist.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ dedent
1111
delattr
1212
dirname
1313
docnames
14+
Documenter
1415
dunder
1516
eval
1617
exc
@@ -31,6 +32,7 @@ isfunction
3132
iterdir
3233
kwonlyargs
3334
libs
35+
lru
3436
metaclass
3537
ModuleType
3638
multiline

0 commit comments

Comments
 (0)