Skip to content

Commit 82eb198

Browse files
committed
Support callables in Annotated
1 parent e439c6f commit 82eb198

File tree

2 files changed

+43
-1
lines changed

2 files changed

+43
-1
lines changed

sphinx/domains/python/_annotations.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,28 @@ def unparse(node: ast.AST) -> list[Node]:
161161
addnodes.desc_sig_punctuation('', ')')]
162162

163163
return result
164-
raise SyntaxError # unsupported syntax
164+
if isinstance(node, ast.Call):
165+
# Call nodes can be used in Annotated type metadata,
166+
# for example Annotated[str, ArbitraryTypeValidator(str, len=10)]
167+
args = []
168+
for arg in node.args:
169+
args += unparse(arg)
170+
args.append(addnodes.desc_sig_punctuation('', ','))
171+
args.append(addnodes.desc_sig_space())
172+
for kwd in node.keywords:
173+
args.append(addnodes.desc_sig_name(kwd.arg, kwd.arg)) # type: ignore[arg-type]
174+
args.append(addnodes.desc_sig_operator('', '='))
175+
args += unparse(kwd.value)
176+
args.append(addnodes.desc_sig_punctuation('', ','))
177+
args.append(addnodes.desc_sig_space())
178+
result = [
179+
*unparse(node.func),
180+
addnodes.desc_sig_punctuation('', '('),
181+
*args[:-2], # skip the final comma and space
182+
addnodes.desc_sig_punctuation('', ')'),
183+
]
184+
return result
185+
raise SyntaxError(f'unsupported syntax: {node}') # unsupported syntax
165186

166187
def _unparse_pep_604_annotation(node: ast.Subscript) -> list[Node]:
167188
subscript = node.slice

tests/test_domains/test_domain_py.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,27 @@ def test_parse_annotation(app):
370370
[desc_sig_punctuation, "]"]))
371371
assert_node(doctree[0], pending_xref, refdomain="py", reftype="obj", reftarget="typing.Literal")
372372

373+
# Annotated type with callable gets parsed
374+
doctree = _parse_annotation("Annotated[Optional[str], annotated_types.MaxLen(max_length=10)]", app.env)
375+
assert_node(doctree, (
376+
[pending_xref, 'Annotated'],
377+
[desc_sig_punctuation, '['],
378+
[pending_xref, 'str'],
379+
[desc_sig_space, ' '],
380+
[desc_sig_punctuation, '|'],
381+
[desc_sig_space, ' '],
382+
[pending_xref, 'None'],
383+
[desc_sig_punctuation, ','],
384+
[desc_sig_space, ' '],
385+
[pending_xref, 'annotated_types.MaxLen'],
386+
[desc_sig_punctuation, '('],
387+
[desc_sig_name, 'max_length'],
388+
[desc_sig_operator, '='],
389+
[desc_sig_literal_number, '10'],
390+
[desc_sig_punctuation, ')'],
391+
[desc_sig_punctuation, ']'],
392+
))
393+
373394

374395
def test_parse_annotation_suppress(app):
375396
doctree = _parse_annotation("~typing.Dict[str, str]", app.env)

0 commit comments

Comments
 (0)