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

Add fix for #296 #297

Merged
merged 9 commits into from
Jan 17, 2023
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions src/sphinx_autodoc_typehints/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import textwrap
import types
from ast import FunctionDef, Module, stmt
from functools import cache
from typing import Any, AnyStr, Callable, ForwardRef, NewType, TypeVar, get_type_hints

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


@cache # A cute way to make sure the function only runs once.
def fix_autodoc_typehints_for_overloaded_methods() -> None:
"""
sphinx-autodoc-typehints responds to the "autodoc-process-signature" event
to remove types from the signature line of functions.

Normally, `FunctionDocumenter.format_signature` and
`MethodDocumenter.format_signature` call `super().format_signature` which
ends up going to `Documenter.format_signature`, and this last method emits
the `autodoc-process-signature` event. However, if there are overloads,
`FunctionDocumenter.format_signature` does something else and the event
never occurs.

Here we remove this alternative code path by brute force.

See https://github.com/tox-dev/sphinx-autodoc-typehints/issues/296
"""
from sphinx.ext.autodoc import FunctionDocumenter, MethodDocumenter

del FunctionDocumenter.format_signature
del MethodDocumenter.format_signature


def setup(app: Sphinx) -> dict[str, bool]:
app.add_config_value("always_document_param_types", False, "html")
app.add_config_value("typehints_fully_qualified", False, "env")
Expand All @@ -707,6 +731,7 @@ def setup(app: Sphinx) -> dict[str, bool]:
app.connect("env-before-read-docs", validate_config) # config may be changed after “config-inited” event
app.connect("autodoc-process-signature", process_signature)
app.connect("autodoc-process-docstring", process_docstring)
fix_autodoc_typehints_for_overloaded_methods()
return {"parallel_read_safe": True}


Expand Down
27 changes: 25 additions & 2 deletions tests/roots/test-dummy/dummy_module.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from dataclasses import dataclass
from mailbox import Mailbox
from typing import Union # noqa: F401 # needed for expansion of Optional
from typing import Callable, Optional
from typing import Callable, Optional, Union, overload


def get_local_function():
Expand Down Expand Up @@ -286,3 +285,27 @@ def func_with_examples() -> int:

Here are a couple of examples of how to use this function.
"""


@overload
def func_with_overload(a: int, b: int) -> None: # noqa: U100
...


@overload
def func_with_overload(a: str, b: str) -> None: # noqa: U100
...


def func_with_overload(a: Union[int, str], b: Union[int, str]) -> None: # noqa: U100
"""
f does the thing. The arguments can either be ints or strings but they must
both have the same type.

Parameters
----------
a:
The first thing
b:
The second thing
"""
2 changes: 2 additions & 0 deletions tests/roots/test-dummy/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,5 @@ Dummy Module
.. autofunction:: dummy_module.mocked_import

.. autofunction:: dummy_module.func_with_examples

.. autofunction:: dummy_module.func_with_overload
12 changes: 12 additions & 0 deletions tests/test_sphinx_autodoc_typehints.py
Original file line number Diff line number Diff line change
Expand Up @@ -770,6 +770,18 @@ class dummy_module.DataClass(x)
-[ Examples ]-

Here are a couple of examples of how to use this function.

dummy_module.func_with_overload(a, b)

f does the thing. The arguments can either be ints or strings but they must both have the same type.

Parameters:
* **a** ("Union"["int", "str"]) -- The first thing

* **b** ("Union"["int", "str"]) -- The second thing

Return type:
"None"
"""
expected_contents = dedent(expected_contents).format(**format_args).replace("–", "--")
assert text_contents == maybe_fix_py310(expected_contents)
Expand Down
2 changes: 2 additions & 0 deletions whitelist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ dedent
delattr
dirname
docnames
Documenter
dunder
eval
exc
Expand All @@ -31,6 +32,7 @@ isfunction
iterdir
kwonlyargs
libs
memoize
metaclass
ModuleType
multiline
Expand Down