mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Support callables in `Annotated
` types (#12625)
This commit is contained in:
parent
1ed4ca7e03
commit
dd77f85149
@ -8,6 +8,9 @@ Bugs fixed
|
||||
Patch by Adam Turner.
|
||||
* #12620: Ensure that old-style object description options are respected.
|
||||
Patch by Adam Turner.
|
||||
* #12601, #12625: Support callable objects in :py:class:`~typing.Annotated` type
|
||||
metadata in the Python domain.
|
||||
Patch by Adam Turner.
|
||||
|
||||
Release 7.4.6 (released Jul 18, 2024)
|
||||
=====================================
|
||||
|
@ -161,7 +161,29 @@ def _parse_annotation(annotation: str, env: BuildEnvironment) -> list[Node]:
|
||||
addnodes.desc_sig_punctuation('', ')')]
|
||||
|
||||
return result
|
||||
raise SyntaxError # unsupported syntax
|
||||
if isinstance(node, ast.Call):
|
||||
# Call nodes can be used in Annotated type metadata,
|
||||
# for example Annotated[str, ArbitraryTypeValidator(str, len=10)]
|
||||
args = []
|
||||
for arg in node.args:
|
||||
args += unparse(arg)
|
||||
args.append(addnodes.desc_sig_punctuation('', ','))
|
||||
args.append(addnodes.desc_sig_space())
|
||||
for kwd in node.keywords:
|
||||
args.append(addnodes.desc_sig_name(kwd.arg, kwd.arg)) # type: ignore[arg-type]
|
||||
args.append(addnodes.desc_sig_operator('', '='))
|
||||
args += unparse(kwd.value)
|
||||
args.append(addnodes.desc_sig_punctuation('', ','))
|
||||
args.append(addnodes.desc_sig_space())
|
||||
result = [
|
||||
*unparse(node.func),
|
||||
addnodes.desc_sig_punctuation('', '('),
|
||||
*args[:-2], # skip the final comma and space
|
||||
addnodes.desc_sig_punctuation('', ')'),
|
||||
]
|
||||
return result
|
||||
msg = f'unsupported syntax: {node}'
|
||||
raise SyntaxError(msg) # unsupported syntax
|
||||
|
||||
def _unparse_pep_604_annotation(node: ast.Subscript) -> list[Node]:
|
||||
subscript = node.slice
|
||||
|
@ -370,6 +370,27 @@ def test_parse_annotation(app):
|
||||
[desc_sig_punctuation, "]"]))
|
||||
assert_node(doctree[0], pending_xref, refdomain="py", reftype="obj", reftarget="typing.Literal")
|
||||
|
||||
# Annotated type with callable gets parsed
|
||||
doctree = _parse_annotation("Annotated[Optional[str], annotated_types.MaxLen(max_length=10)]", app.env)
|
||||
assert_node(doctree, (
|
||||
[pending_xref, 'Annotated'],
|
||||
[desc_sig_punctuation, '['],
|
||||
[pending_xref, 'str'],
|
||||
[desc_sig_space, ' '],
|
||||
[desc_sig_punctuation, '|'],
|
||||
[desc_sig_space, ' '],
|
||||
[pending_xref, 'None'],
|
||||
[desc_sig_punctuation, ','],
|
||||
[desc_sig_space, ' '],
|
||||
[pending_xref, 'annotated_types.MaxLen'],
|
||||
[desc_sig_punctuation, '('],
|
||||
[desc_sig_name, 'max_length'],
|
||||
[desc_sig_operator, '='],
|
||||
[desc_sig_literal_number, '10'],
|
||||
[desc_sig_punctuation, ')'],
|
||||
[desc_sig_punctuation, ']'],
|
||||
))
|
||||
|
||||
|
||||
def test_parse_annotation_suppress(app):
|
||||
doctree = _parse_annotation("~typing.Dict[str, str]", app.env)
|
||||
@ -802,7 +823,22 @@ def test_function_pep_695(app):
|
||||
[desc_sig_name, 'A'],
|
||||
[desc_sig_punctuation, ':'],
|
||||
desc_sig_space,
|
||||
[desc_sig_name, ([pending_xref, 'int | Annotated[int, ctype("char")]'])],
|
||||
[desc_sig_name, (
|
||||
[pending_xref, 'int'],
|
||||
[desc_sig_space, ' '],
|
||||
[desc_sig_punctuation, '|'],
|
||||
[desc_sig_space, ' '],
|
||||
[pending_xref, 'Annotated'],
|
||||
[desc_sig_punctuation, '['],
|
||||
[pending_xref, 'int'],
|
||||
[desc_sig_punctuation, ','],
|
||||
[desc_sig_space, ' '],
|
||||
[pending_xref, 'ctype'],
|
||||
[desc_sig_punctuation, '('],
|
||||
[desc_sig_literal_string, "'char'"],
|
||||
[desc_sig_punctuation, ')'],
|
||||
[desc_sig_punctuation, ']'],
|
||||
)],
|
||||
)],
|
||||
[desc_type_parameter, (
|
||||
[desc_sig_operator, '*'],
|
||||
@ -987,7 +1023,7 @@ def test_class_def_pep_696(app):
|
||||
('[T:(*Ts)|int]', '[T: (*Ts) | int]'),
|
||||
('[T:(int|(*Ts))]', '[T: (int | (*Ts))]'),
|
||||
('[T:((*Ts)|int)]', '[T: ((*Ts) | int)]'),
|
||||
('[T:Annotated[int,ctype("char")]]', '[T: Annotated[int, ctype("char")]]'),
|
||||
("[T:Annotated[int,ctype('char')]]", "[T: Annotated[int, ctype('char')]]"),
|
||||
])
|
||||
def test_pep_695_and_pep_696_whitespaces_in_bound(app, tp_list, tptext):
|
||||
text = f'.. py:function:: f{tp_list}()'
|
||||
|
Loading…
Reference in New Issue
Block a user