diff options
author | Adam Turner <9087854+AA-Turner@users.noreply.github.com> | 2023-04-05 13:07:25 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-04-05 13:07:25 +0100 |
commit | 4a3febb69a124300f1481fc33b44a5672f24e0fa (patch) | |
tree | 10defdc4bcc3d606604cab9dae3ca445ba74685b | |
parent | 609b2f2650dfea191e688ce6238ba567da551052 (diff) | |
download | sphinx-git-4a3febb69a124300f1481fc33b44a5672f24e0fa.tar.gz |
Add an option for displaying short ``Literal`` types (#11109)
The new ``python_display_short_literal_types`` configuration option
for the ``py`` domain controls display of PEP 586 ``Literal`` types.
The 'short' format is inspired by PEP 604, using the bitwise OR operator
to distinguish the possible legal values for the argument.
-rw-r--r-- | CHANGES | 2 | ||||
-rw-r--r-- | doc/usage/configuration.rst | 30 | ||||
-rw-r--r-- | sphinx/domains/python.py | 5 | ||||
-rw-r--r-- | tests/test_domain_py.py | 67 |
4 files changed, 104 insertions, 0 deletions
@@ -53,6 +53,8 @@ Features added Patch by Jeremy Maitin-Shepard * #11281: Support for :confval:`imgmath_latex` ``= 'tectonic'`` or ``= 'xelatex'``. Patch by Dimitar Dimitrov +* #11109, #9643: Add :confval:`python_display_short_literal_types` option for + condensed rendering of ``Literal`` types. Bugs fixed ---------- diff --git a/doc/usage/configuration.rst b/doc/usage/configuration.rst index fb5a7615c..c92e468f1 100644 --- a/doc/usage/configuration.rst +++ b/doc/usage/configuration.rst @@ -2936,6 +2936,36 @@ Options for the C++ domain Options for the Python domain ----------------------------- +.. confval:: python_display_short_literal_types + + This value controls how :py:data:`~typing.Literal` types are displayed. + The setting is a boolean, default ``False``. + + Examples + ~~~~~~~~ + + The examples below use the following :rst:dir:`py:function` directive: + + .. code:: reStructuredText + + .. py:function:: serve_food(item: Literal["egg", "spam", "lobster thermidor"]) -> None + + When ``False``, :py:data:`~typing.Literal` types display as per standard + Python syntax, i.e.: + + .. code:: python + + serve_food(item: Literal["egg", "spam", "lobster thermidor"]) -> None + + When ``True``, :py:data:`~typing.Literal` types display with a short, + :PEP:`604`-inspired syntax, i.e.: + + .. code:: python + + serve_food(item: "egg" | "spam" | "lobster thermidor") -> None + + .. versionadded:: 6.2 + .. confval:: python_use_unqualified_type_names If true, suppress the module name of the python reference if it can be diff --git a/sphinx/domains/python.py b/sphinx/domains/python.py index 99bc1bcae..edd4e829f 100644 --- a/sphinx/domains/python.py +++ b/sphinx/domains/python.py @@ -130,6 +130,8 @@ def type_to_xref(target: str, env: BuildEnvironment | None = None, def _parse_annotation(annotation: str, env: BuildEnvironment | None) -> list[Node]: """Parse type annotation.""" + short_literals = env.config.python_display_short_literal_types + def unparse(node: ast.AST) -> list[Node]: if isinstance(node, ast.Attribute): return [nodes.Text(f"{unparse(node.value)[0]}.{node.attr}")] @@ -182,6 +184,8 @@ def _parse_annotation(annotation: str, env: BuildEnvironment | None) -> list[Nod if isinstance(node, ast.Subscript): if getattr(node.value, 'id', '') in {'Optional', 'Union'}: return _unparse_pep_604_annotation(node) + if short_literals and getattr(node.value, 'id', '') == 'Literal': + return _unparse_pep_604_annotation(node) result = unparse(node.value) result.append(addnodes.desc_sig_punctuation('', '[')) result.extend(unparse(node.slice)) @@ -1511,6 +1515,7 @@ def setup(app: Sphinx) -> dict[str, Any]: app.add_domain(PythonDomain) app.add_config_value('python_use_unqualified_type_names', False, 'env') + app.add_config_value('python_display_short_literal_types', False, 'env') app.connect('object-description-transform', filter_meta_fields) app.connect('missing-reference', builtin_resolver, priority=900) diff --git a/tests/test_domain_py.py b/tests/test_domain_py.py index 66204e69e..6cac6cba1 100644 --- a/tests/test_domain_py.py +++ b/tests/test_domain_py.py @@ -1470,3 +1470,70 @@ def test_module_content_line_number(app): source, line = docutils.utils.get_source_line(xrefs[0]) assert 'index.rst' in source assert line == 3 + + +@pytest.mark.sphinx(freshenv=True, confoverrides={'python_display_short_literal_types': True}) +def test_short_literal_types(app): + text = """\ +.. py:function:: literal_ints(x: Literal[1, 2, 3] = 1) -> None +.. py:function:: literal_union(x: Union[Literal["a"], Literal["b"], Literal["c"]]) -> None +""" + doctree = restructuredtext.parse(app, text) + assert_node(doctree, ( + addnodes.index, + [desc, ( + [desc_signature, ( + [desc_name, 'literal_ints'], + [desc_parameterlist, ( + [desc_parameter, ( + [desc_sig_name, 'x'], + [desc_sig_punctuation, ':'], + desc_sig_space, + [desc_sig_name, ( + [desc_sig_literal_number, '1'], + desc_sig_space, + [desc_sig_punctuation, '|'], + desc_sig_space, + [desc_sig_literal_number, '2'], + desc_sig_space, + [desc_sig_punctuation, '|'], + desc_sig_space, + [desc_sig_literal_number, '3'], + )], + desc_sig_space, + [desc_sig_operator, '='], + desc_sig_space, + [nodes.inline, '1'], + )], + )], + [desc_returns, pending_xref, 'None'], + )], + [desc_content, ()], + )], + addnodes.index, + [desc, ( + [desc_signature, ( + [desc_name, 'literal_union'], + [desc_parameterlist, ( + [desc_parameter, ( + [desc_sig_name, 'x'], + [desc_sig_punctuation, ':'], + desc_sig_space, + [desc_sig_name, ( + [desc_sig_literal_string, "'a'"], + desc_sig_space, + [desc_sig_punctuation, '|'], + desc_sig_space, + [desc_sig_literal_string, "'b'"], + desc_sig_space, + [desc_sig_punctuation, '|'], + desc_sig_space, + [desc_sig_literal_string, "'c'"], + )], + )], + )], + [desc_returns, pending_xref, 'None'], + )], + [desc_content, ()], + )], + )) |