Collapse unions of `Literal types in stringify_annotation` (#12325)

This commit is contained in:
Adam Turner 2024-04-25 16:07:10 +01:00 committed by GitHub
parent 7953798074
commit 938d3732f8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 21 additions and 1 deletions

View File

@ -18,6 +18,9 @@ Features added
Patch by James Addison and Adam Turner
.. _officially recommended: https://jinja.palletsprojects.com/en/latest/templates/#template-file-extension
* Flatten ``Union[Literal[T], Literal[U], ...]`` to ``Literal[T, U, ...]``
when turning annotations into strings.
Patch by Adam Turner.
Bugs fixed
----------

View File

@ -439,6 +439,15 @@ def stringify_annotation(
# They must be a list or a tuple, otherwise they are considered 'broken'.
annotation_args = getattr(annotation, '__args__', ())
if annotation_args and isinstance(annotation_args, (list, tuple)):
if (
qualname in {'Union', 'types.UnionType'}
and all(getattr(a, '__origin__', ...) is typing.Literal for a in annotation_args)
):
# special case to flatten a Union of Literals into a literal
flattened_args = typing.Literal[annotation_args].__args__ # type: ignore[attr-defined]
args = ', '.join(_format_literal_arg_stringify(a, mode=mode)
for a in flattened_args)
return f'{module_prefix}Literal[{args}]'
if qualname in {'Optional', 'Union', 'types.UnionType'}:
return ' | '.join(stringify_annotation(a, mode) for a in annotation_args)
elif qualname == 'Callable':

View File

@ -359,6 +359,10 @@ def test_signature_annotations():
sig = inspect.signature(mod.f25)
assert stringify_signature(sig) == '(a, b, /)'
# collapse Literal types
sig = inspect.signature(mod.f26)
assert stringify_signature(sig) == "(x: typing.Literal[1, 2, 3] = 1, y: typing.Literal['a', 'b'] = 'a') -> None"
def test_signature_from_str_basic():
signature = '(a, b, *args, c=0, d="blah", **kwargs)'

View File

@ -1,6 +1,6 @@
from inspect import Signature
from numbers import Integral
from typing import Any, Callable, Dict, List, Optional, Tuple, TypeVar, Union
from typing import Any, Callable, Dict, List, Literal, Optional, Tuple, TypeVar, Union
def f0(x: int, y: Integral) -> None:
@ -121,6 +121,10 @@ def f25(a, b, /):
pass
def f26(x: Literal[1, 2, 3] = 1, y: Union[Literal["a"], Literal["b"]] = "a") -> None:
pass
class Node:
def __init__(self, parent: Optional['Node']) -> None:
pass