Skip to content

Commit

Permalink
Added options to retain original typehints in signatures (#278)
Browse files Browse the repository at this point in the history
* Update __init__.py

* Update __init__.py

* Updated README.md

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Added tests for use_signature and use_signature_return

* Removed .idea* from gitignore

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
  • Loading branch information
BhavyeMathur and pre-commit-ci[bot] committed Jan 5, 2023
1 parent 477c438 commit 32dc422
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 2 deletions.
2 changes: 2 additions & 0 deletions README.md
Expand Up @@ -83,6 +83,8 @@ The following configuration options are accepted:
- `typehints_formatter` (default: `None`): If set to a function, this function will be called with `annotation` as first
argument and `sphinx.config.Config` argument second. The function is expected to return a string with reStructuredText
code or `None` to fall back to the default formatter.
- `typehints_use_signature` (default: `False`): If `True`, typehints for parameters in the signature are shown.
- `typehints_use_signature_return` (default: `False`): If `True`, return annotations in the signature are shown.

## How it works

Expand Down
13 changes: 11 additions & 2 deletions src/sphinx_autodoc_typehints/__init__.py
Expand Up @@ -254,7 +254,11 @@ def process_signature(

obj = inspect.unwrap(obj)
sph_signature = sphinx_signature(obj)
parameters = [param.replace(annotation=inspect.Parameter.empty) for param in sph_signature.parameters.values()]

if app.config.typehints_use_signature:
parameters = list(sph_signature.parameters.values())
else:
parameters = [param.replace(annotation=inspect.Parameter.empty) for param in sph_signature.parameters.values()]

# if we have parameters we may need to delete first argument that's not documented, e.g. self
start = 0
Expand All @@ -277,7 +281,10 @@ def process_signature(
if not isinstance(method_object, (classmethod, staticmethod)):
start = 1

sph_signature = sph_signature.replace(parameters=parameters[start:], return_annotation=inspect.Signature.empty)
sph_signature = sph_signature.replace(parameters=parameters[start:])
if not app.config.typehints_use_signature_return:
sph_signature = sph_signature.replace(return_annotation=inspect.Signature.empty)

return stringify_signature(sph_signature).replace("\\", "\\\\"), None


Expand Down Expand Up @@ -634,6 +641,8 @@ def setup(app: Sphinx) -> dict[str, bool]:
app.add_config_value("typehints_defaults", None, "env")
app.add_config_value("simplify_optional_unions", True, "env")
app.add_config_value("typehints_formatter", None, "env")
app.add_config_value("typehints_use_signature", False, "env")
app.add_config_value("typehints_use_signature_return", False, "env")
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)
Expand Down
88 changes: 88 additions & 0 deletions tests/test_sphinx_autodoc_typehints.py
Expand Up @@ -1033,3 +1033,91 @@ def test_sphinx_output_formatter_no_use_rtype(app: SphinxTestApp, status: String
"str" -- A string
"""
assert text_contents == dedent(expected_contents)


@pytest.mark.sphinx("text", testroot="dummy")
@patch("sphinx.writers.text.MAXWIDTH", 2000)
def test_sphinx_output_with_use_signature(app: SphinxTestApp, status: StringIO) -> None:
set_python_path()
app.config.master_doc = "simple" # type: ignore # create flag
app.config.typehints_use_signature = True # type: ignore
app.build()
assert "build succeeded" in status.getvalue()
text_path = pathlib.Path(app.srcdir) / "_build" / "text" / "simple.txt"
text_contents = text_path.read_text().replace("–", "--")
expected_contents = """\
Simple Module
*************
dummy_module_simple.function(x: bool, y: int = 1)
Function docstring.
Parameters:
* **x** ("bool") -- foo
* **y** ("int") -- bar
Return type:
"str"
"""
assert text_contents == dedent(expected_contents)


@pytest.mark.sphinx("text", testroot="dummy")
@patch("sphinx.writers.text.MAXWIDTH", 2000)
def test_sphinx_output_with_use_signature_return(app: SphinxTestApp, status: StringIO) -> None:
set_python_path()
app.config.master_doc = "simple" # type: ignore # create flag
app.config.typehints_use_signature_return = True # type: ignore
app.build()
assert "build succeeded" in status.getvalue()
text_path = pathlib.Path(app.srcdir) / "_build" / "text" / "simple.txt"
text_contents = text_path.read_text().replace("–", "--")
expected_contents = """\
Simple Module
*************
dummy_module_simple.function(x, y=1) -> str
Function docstring.
Parameters:
* **x** ("bool") -- foo
* **y** ("int") -- bar
Return type:
"str"
"""
assert text_contents == dedent(expected_contents)


@pytest.mark.sphinx("text", testroot="dummy")
@patch("sphinx.writers.text.MAXWIDTH", 2000)
def test_sphinx_output_with_use_signature_and_return(app: SphinxTestApp, status: StringIO) -> None:
set_python_path()
app.config.master_doc = "simple" # type: ignore # create flag
app.config.typehints_use_signature = True # type: ignore
app.config.typehints_use_signature_return = True # type: ignore
app.build()
assert "build succeeded" in status.getvalue()
text_path = pathlib.Path(app.srcdir) / "_build" / "text" / "simple.txt"
text_contents = text_path.read_text().replace("–", "--")
expected_contents = """\
Simple Module
*************
dummy_module_simple.function(x: bool, y: int = 1) -> str
Function docstring.
Parameters:
* **x** ("bool") -- foo
* **y** ("int") -- bar
Return type:
"str"
"""
assert text_contents == dedent(expected_contents)

0 comments on commit 32dc422

Please sign in to comment.