diff --git a/CHANGES b/CHANGES index 469f1972cc1..8b1d5b92484 100644 --- a/CHANGES +++ b/CHANGES @@ -20,6 +20,8 @@ Bugs fixed ---------- * #7461: py domain: fails with IndexError for empty tuple in type annotation +* #7510: py domain: keyword-only arguments are documented as having a default of + None * #7418: std domain: :rst:role:`term` role could not match case-insensitively * #7461: autodoc: empty tuple in type annotation is not shown correctly * #7479: autodoc: Sphinx builds has been slower since 3.0.0 on mocking diff --git a/sphinx/util/inspect.py b/sphinx/util/inspect.py index 64c1568f61c..a0ea52047e9 100644 --- a/sphinx/util/inspect.py +++ b/sphinx/util/inspect.py @@ -527,7 +527,7 @@ def signature_from_str(signature: str) -> inspect.Signature: annotation=annotation)) for i, arg in enumerate(args.kwonlyargs): - default = ast_unparse(args.kw_defaults[i]) + default = ast_unparse(args.kw_defaults[i]) or Parameter.empty annotation = ast_unparse(arg.annotation) or Parameter.empty params.append(Parameter(arg.arg, Parameter.KEYWORD_ONLY, default=default, annotation=annotation)) diff --git a/tests/test_domain_py.py b/tests/test_domain_py.py index e330ba6349c..d9d61db1429 100644 --- a/tests/test_domain_py.py +++ b/tests/test_domain_py.py @@ -344,9 +344,7 @@ def test_pyfunction_signature_full_py38(app): doctree = restructuredtext.parse(app, text) assert_node(doctree[1][0][1], [desc_parameterlist, ([desc_parameter, nodes.inline, "*"], - [desc_parameter, ([desc_sig_name, "a"], - [desc_sig_operator, "="], - [nodes.inline, "None"])])]) + [desc_parameter, desc_sig_name, "a"])]) # case: separator in the middle text = ".. py:function:: hello(a, /, b, *, c)" @@ -356,9 +354,7 @@ def test_pyfunction_signature_full_py38(app): [desc_parameter, desc_sig_operator, "/"], [desc_parameter, desc_sig_name, "b"], [desc_parameter, desc_sig_operator, "*"], - [desc_parameter, ([desc_sig_name, "c"], - [desc_sig_operator, "="], - [nodes.inline, "None"])])]) + [desc_parameter, desc_sig_name, "c"])]) # case: separator in the middle (2) text = ".. py:function:: hello(a, /, *, b)" @@ -367,9 +363,7 @@ def test_pyfunction_signature_full_py38(app): [desc_parameterlist, ([desc_parameter, desc_sig_name, "a"], [desc_parameter, desc_sig_operator, "/"], [desc_parameter, desc_sig_operator, "*"], - [desc_parameter, ([desc_sig_name, "b"], - [desc_sig_operator, "="], - [nodes.inline, "None"])])]) + [desc_parameter, desc_sig_name, "b"])]) # case: separator at tail text = ".. py:function:: hello(a, /)" diff --git a/tests/test_util_inspect.py b/tests/test_util_inspect.py index 627d20f54e2..ff1074702c6 100644 --- a/tests/test_util_inspect.py +++ b/tests/test_util_inspect.py @@ -317,6 +317,15 @@ def test_signature_from_str_complex_annotations(): assert sig.return_annotation == 'Callable[[int, int], int]' +def test_signature_from_str_kwonly_args(): + sig = inspect.signature_from_str('(a, *, b)') + assert list(sig.parameters.keys()) == ['a', 'b'] + assert sig.parameters['a'].kind == Parameter.POSITIONAL_OR_KEYWORD + assert sig.parameters['a'].default == Parameter.empty + assert sig.parameters['b'].kind == Parameter.KEYWORD_ONLY + assert sig.parameters['b'].default == Parameter.empty + + @pytest.mark.skipif(sys.version_info < (3, 8), reason='python-3.8 or above is required') def test_signature_from_str_positionaly_only_args():