Skip to content

Commit

Permalink
py domain: Support type union operator (PEP-604) (refs: sphinx-doc#8775)
Browse files Browse the repository at this point in the history
Upgrade annotation parser for python domain to support type union
operator introduced in PEP-604.  It's available on all python
interpreters.
  • Loading branch information
tk0miya committed Feb 1, 2021
1 parent 7ca279e commit 2c2b8c1
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 2 deletions.
1 change: 1 addition & 0 deletions CHANGES
Expand Up @@ -54,6 +54,7 @@ Features added
* #8004: napoleon: Type definitions in Google style docstrings are rendered as
references when :confval:`napoleon_preprocess_types` enabled
* #6241: mathjax: Include mathjax.js only on the document using equations
* #8775: py domain: Support type union operator (PEP-604)
* #8651: std domain: cross-reference for a rubric having inline item is broken
* #7642: std domain: Optimize case-insensitive match of term
* #8681: viewcode: Support incremental build
Expand Down
11 changes: 9 additions & 2 deletions sphinx/domains/python.py
Expand Up @@ -100,12 +100,19 @@ def _parse_annotation(annotation: str, env: BuildEnvironment = None) -> List[Nod
def unparse(node: ast.AST) -> List[Node]:
if isinstance(node, ast.Attribute):
return [nodes.Text("%s.%s" % (unparse(node.value)[0], node.attr))]
elif isinstance(node, ast.BinOp):
result = unparse(node.left) # type: List[Node]
result.extend(unparse(node.op))
result.extend(unparse(node.right))
return result
elif isinstance(node, ast.BitOr):
return [nodes.Text(' '), addnodes.desc_sig_punctuation('', '|'), nodes.Text(' ')]
elif isinstance(node, ast.Expr):
return unparse(node.value)
elif isinstance(node, ast.Index):
return unparse(node.value)
elif isinstance(node, ast.List):
result = [addnodes.desc_sig_punctuation('', '[')] # type: List[Node]
result = [addnodes.desc_sig_punctuation('', '[')]
for elem in node.elts:
result.extend(unparse(elem))
result.append(addnodes.desc_sig_punctuation('', ', '))
Expand Down Expand Up @@ -158,7 +165,7 @@ def unparse(node: ast.AST) -> List[Node]:
tree = ast_parse(annotation)
result = unparse(tree)
for i, node in enumerate(result):
if isinstance(node, nodes.Text):
if isinstance(node, nodes.Text) and node.strip():
result[i] = type_to_xref(str(node), env)
return result
except SyntaxError:
Expand Down
28 changes: 28 additions & 0 deletions tests/test_domain_py.py
Expand Up @@ -429,6 +429,20 @@ def test_pyfunction_with_number_literals(app):
[nodes.inline, "1_6_0"])])])


def test_pyfunction_with_union_type_operator(app):
text = ".. py:function:: hello(age: int | None)"
doctree = restructuredtext.parse(app, text)
assert_node(doctree[1][0][1],
[desc_parameterlist, ([desc_parameter, ([desc_sig_name, "age"],
[desc_sig_punctuation, ":"],
" ",
[desc_sig_name, ([pending_xref, "int"],
" ",
[desc_sig_punctuation, "|"],
" ",
[pending_xref, "None"])])])])


def test_optional_pyfunction_signature(app):
text = ".. py:function:: compile(source [, filename [, symbol]]) -> ast object"
doctree = restructuredtext.parse(app, text)
Expand Down Expand Up @@ -496,6 +510,20 @@ def test_pydata_signature_old(app):
domain="py", objtype="data", noindex=False)


def test_pydata_with_union_type_operator(app):
text = (".. py:data:: version\n"
" :type: int | str")
doctree = restructuredtext.parse(app, text)
assert_node(doctree[1][0],
([desc_name, "version"],
[desc_annotation, (": ",
[pending_xref, "int"],
" ",
[desc_sig_punctuation, "|"],
" ",
[pending_xref, "str"])]))


def test_pyobject_prefix(app):
text = (".. py:class:: Foo\n"
"\n"
Expand Down

0 comments on commit 2c2b8c1

Please sign in to comment.