Skip to content

Commit 4e6bc55

Browse files
Fixed default options not displaying for parameters without type hints. (#279)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Resolves #234
1 parent 32dc422 commit 4e6bc55

File tree

4 files changed

+147
-35
lines changed

4 files changed

+147
-35
lines changed

src/sphinx_autodoc_typehints/__init__.py

Lines changed: 47 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -475,19 +475,27 @@ def add(val: str) -> None:
475475
return result
476476

477477

478-
def format_default(app: Sphinx, default: Any) -> str | None:
478+
def format_default(app: Sphinx, default: Any, is_annotated: bool) -> str | None:
479479
if default is inspect.Parameter.empty:
480480
return None
481481
formatted = repr(default).replace("\\", "\\\\")
482-
if app.config.typehints_defaults.startswith("braces"):
483-
return f" (default: ``{formatted}``)"
482+
483+
if is_annotated:
484+
if app.config.typehints_defaults.startswith("braces"):
485+
return f" (default: ``{formatted}``)"
486+
else: # other option is comma
487+
return f", default: ``{formatted}``"
484488
else:
485-
return f", default: ``{formatted}``"
489+
if app.config.typehints_defaults == "braces-after":
490+
return f" (default: ``{formatted}``)"
491+
else:
492+
return f"default: ``{formatted}``"
486493

487494

488495
def process_docstring(
489496
app: Sphinx, what: str, name: str, obj: Any, options: Options | None, lines: list[str] # noqa: U100
490497
) -> None:
498+
491499
original_obj = obj
492500
obj = obj.fget if isinstance(obj, property) else obj
493501
if not callable(obj):
@@ -561,41 +569,45 @@ def _inject_types_to_docstring(
561569
name: str,
562570
lines: list[str],
563571
) -> None:
564-
for arg_name, annotation in type_hints.items():
565-
if arg_name == "return":
566-
continue # this is handled separately later
567-
if signature is None or arg_name not in signature.parameters:
568-
default = inspect.Parameter.empty
569-
else:
572+
573+
if signature is not None:
574+
for arg_name in signature.parameters:
575+
annotation = type_hints.get(arg_name, None)
576+
570577
default = signature.parameters[arg_name].default
571-
if arg_name.endswith("_"):
572-
arg_name = f"{arg_name[:-1]}\\_"
573578

574-
formatted_annotation = format_annotation(annotation, app.config)
579+
if arg_name.endswith("_"):
580+
arg_name = f"{arg_name[:-1]}\\_"
575581

576-
insert_index = None
577-
for at, line in enumerate(lines):
578-
if _line_is_param_line_for_arg(line, arg_name):
579-
# Get the arg_name from the doc to match up for type in case it has a star prefix.
580-
# Line is in the correct format so this is guaranteed to return tuple[str, str].
581-
_, arg_name = _get_sphinx_line_keyword_and_argument(line) # type: ignore[assignment, misc]
582-
insert_index = at
583-
break
582+
insert_index = None
583+
for at, line in enumerate(lines):
584+
if _line_is_param_line_for_arg(line, arg_name):
585+
# Get the arg_name from the doc to match up for type in case it has a star prefix.
586+
# Line is in the correct format so this is guaranteed to return tuple[str, str].
587+
_, arg_name = _get_sphinx_line_keyword_and_argument(line) # type: ignore[assignment, misc]
588+
insert_index = at
589+
break
590+
591+
if annotation is not None and insert_index is None and app.config.always_document_param_types:
592+
lines.append(f":param {arg_name}:")
593+
insert_index = len(lines)
584594

585-
if insert_index is None and app.config.always_document_param_types:
586-
lines.append(f":param {arg_name}:")
587-
insert_index = len(lines)
588-
589-
if insert_index is not None:
590-
type_annotation = f":type {arg_name}: {formatted_annotation}"
591-
if app.config.typehints_defaults:
592-
formatted_default = format_default(app, default)
593-
if formatted_default:
594-
if app.config.typehints_defaults.endswith("after"):
595-
lines[insert_index] += formatted_default
596-
else: # add to last param doc line
597-
type_annotation += formatted_default
598-
lines.insert(insert_index, type_annotation)
595+
if insert_index is not None:
596+
if annotation is None:
597+
type_annotation = f":type {arg_name}: "
598+
else:
599+
formatted_annotation = format_annotation(annotation, app.config)
600+
type_annotation = f":type {arg_name}: {formatted_annotation}"
601+
602+
if app.config.typehints_defaults:
603+
formatted_default = format_default(app, default, annotation is not None)
604+
if formatted_default:
605+
if app.config.typehints_defaults.endswith("after"):
606+
lines[insert_index] += formatted_default
607+
else: # add to last param doc line
608+
type_annotation += formatted_default
609+
610+
lines.insert(insert_index, type_annotation)
599611

600612
if "return" in type_hints and not inspect.isclass(original_obj):
601613
if what == "method" and name.endswith(".__init__"): # avoid adding a return type for data class __init__
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
def function_with_some_defaults_and_without_typehints(x, y=None): # noqa: U100
2+
"""
3+
Function docstring.
4+
5+
:param x: foo
6+
:param y: bar
7+
"""
8+
9+
10+
def function_with_some_defaults_and_some_typehints(x: int, y=None): # noqa: U100
11+
"""
12+
Function docstring.
13+
14+
:param x: foo
15+
:param y: bar
16+
"""
17+
18+
19+
def function_with_some_defaults_and_more_typehints(x: int, y=None) -> str: # noqa: U100
20+
"""
21+
Function docstring.
22+
23+
:param x: foo
24+
:param y: bar
25+
"""
26+
27+
28+
def function_with_defaults_and_some_typehints(x: int = 0, y=None) -> str: # noqa: U100
29+
"""
30+
Function docstring.
31+
32+
:param x: foo
33+
:param y: bar
34+
"""
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Simple Module
2+
=============
3+
4+
.. autofunction:: dummy_module_without_complete_typehints.function_with_some_defaults_and_without_typehints
5+
.. autofunction:: dummy_module_without_complete_typehints.function_with_some_defaults_and_some_typehints
6+
.. autofunction:: dummy_module_without_complete_typehints.function_with_some_defaults_and_more_typehints
7+
.. autofunction:: dummy_module_without_complete_typehints.function_with_defaults_and_some_typehints

tests/test_sphinx_autodoc_typehints.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1121,3 +1121,62 @@ def test_sphinx_output_with_use_signature_and_return(app: SphinxTestApp, status:
11211121
"str"
11221122
"""
11231123
assert text_contents == dedent(expected_contents)
1124+
1125+
1126+
@pytest.mark.sphinx("text", testroot="dummy")
1127+
@patch("sphinx.writers.text.MAXWIDTH", 2000)
1128+
def test_default_annotation_without_typehints(app: SphinxTestApp, status: StringIO) -> None:
1129+
set_python_path()
1130+
app.config.master_doc = "without_complete_typehints" # type: ignore # create flag
1131+
app.config.typehints_defaults = "comma" # type: ignore
1132+
app.build()
1133+
assert "build succeeded" in status.getvalue()
1134+
text_path = pathlib.Path(app.srcdir) / "_build" / "text" / "without_complete_typehints.txt"
1135+
text_contents = text_path.read_text().replace("–", "--")
1136+
expected_contents = """\
1137+
Simple Module
1138+
*************
1139+
1140+
dummy_module_without_complete_typehints.function_with_some_defaults_and_without_typehints(x, y=None)
1141+
1142+
Function docstring.
1143+
1144+
Parameters:
1145+
* **x** -- foo
1146+
1147+
* **y** (default: "None") -- bar
1148+
1149+
dummy_module_without_complete_typehints.function_with_some_defaults_and_some_typehints(x, y=None)
1150+
1151+
Function docstring.
1152+
1153+
Parameters:
1154+
* **x** ("int") -- foo
1155+
1156+
* **y** (default: "None") -- bar
1157+
1158+
dummy_module_without_complete_typehints.function_with_some_defaults_and_more_typehints(x, y=None)
1159+
1160+
Function docstring.
1161+
1162+
Parameters:
1163+
* **x** ("int") -- foo
1164+
1165+
* **y** (default: "None") -- bar
1166+
1167+
Return type:
1168+
"str"
1169+
1170+
dummy_module_without_complete_typehints.function_with_defaults_and_some_typehints(x=0, y=None)
1171+
1172+
Function docstring.
1173+
1174+
Parameters:
1175+
* **x** ("int", default: "0") -- foo
1176+
1177+
* **y** (default: "None") -- bar
1178+
1179+
Return type:
1180+
"str"
1181+
"""
1182+
assert text_contents == dedent(expected_contents)

0 commit comments

Comments
 (0)