Make sphinx.util.typing.stringify render optional unions better

Without this change, stringify(Optional[Union[int, str]]) returns
'Union[int, str, None]' rather than the expected 'Optional[...]'.

This change fixes that.

fixes: #7654
This commit is contained in:
John R. Lenton 2020-05-11 17:20:45 +01:00
parent 1771bbb927
commit 61378fe048
3 changed files with 22 additions and 6 deletions

View File

@ -91,11 +91,15 @@ def _stringify_py37(annotation: Any) -> str:
if getattr(annotation, '__args__', None):
if qualname == 'Union':
if len(annotation.__args__) == 2 and annotation.__args__[1] is NoneType: # type: ignore # NOQA
return 'Optional[%s]' % stringify(annotation.__args__[0])
if len(annotation.__args__) > 1 and annotation.__args__[-1] is NoneType: # type: ignore # NOQA
if len(annotation.__args__) > 2:
args = ', '.join(stringify(a) for a in annotation.__args__[:-1])
return 'Optional[Union[%s]]' % args
else:
return 'Optional[%s]' % stringify(annotation.__args__[0])
else:
args = ', '.join(stringify(a) for a in annotation.__args__)
return '%s[%s]' % (qualname, args)
return 'Union[%s]' % args
elif qualname == 'Callable':
args = ', '.join(stringify(a) for a in annotation.__args__[:-1])
returns = stringify(annotation.__args__[-1])
@ -170,8 +174,12 @@ def _stringify_py36(annotation: Any) -> str:
annotation.__origin__ is typing.Union): # for Python 3.5.2+
params = annotation.__args__
if params is not None:
if len(params) == 2 and params[1] is NoneType: # type: ignore
return 'Optional[%s]' % stringify(params[0])
if len(params) > 1 and params[-1] is NoneType: # type: ignore
if len(params) > 2:
param_str = ", ".join(stringify(p) for p in params[:-1])
return 'Optional[Union[%s]]' % param_str
else:
return 'Optional[%s]' % stringify(params[0])
else:
param_str = ', '.join(stringify(p) for p in params)
return 'Union[%s]' % param_str

View File

@ -127,7 +127,7 @@ def test_signature_partialmethod():
def test_signature_annotations():
from typing_test_data import (f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10,
f11, f12, f13, f14, f15, f16, f17, f18, f19, Node)
f11, f12, f13, f14, f15, f16, f17, f18, f19, f20, Node)
# Class annotations
sig = inspect.signature(f0)
@ -184,6 +184,10 @@ def test_signature_annotations():
sig = inspect.signature(f13)
assert stringify_signature(sig) == '() -> Optional[str]'
# optional union
sig = inspect.signature(f20)
assert stringify_signature(sig) == '() -> Optional[Union[int, str]]'
# Any
sig = inspect.signature(f14)
assert stringify_signature(sig) == '() -> Any'

View File

@ -96,6 +96,10 @@ def f19(*args: int, **kwargs: str):
pass
def f20() -> Optional[Union[int, str]]:
pass
class Node:
def __init__(self, parent: Optional['Node']) -> None: