summaryrefslogtreecommitdiff
path: root/sphinx/util/typing.py
diff options
context:
space:
mode:
Diffstat (limited to 'sphinx/util/typing.py')
-rw-r--r--sphinx/util/typing.py27
1 files changed, 21 insertions, 6 deletions
diff --git a/sphinx/util/typing.py b/sphinx/util/typing.py
index 72da10dd1..8ad8bf75d 100644
--- a/sphinx/util/typing.py
+++ b/sphinx/util/typing.py
@@ -39,6 +39,12 @@ TitleGetter = Callable[[nodes.Node], str]
Inventory = Dict[str, Dict[str, Tuple[str, str, str, str]]]
+def is_system_TypeVar(typ: Any) -> bool:
+ """Check *typ* is system defined TypeVar."""
+ modname = getattr(typ, '__module__', '')
+ return modname == 'typing' and isinstance(typ, TypeVar) # type: ignore
+
+
def stringify(annotation: Any) -> str:
"""Stringify type annotation object."""
if isinstance(annotation, str):
@@ -85,18 +91,23 @@ 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])
return '%s[[%s], %s]' % (qualname, args, returns)
elif str(annotation).startswith('typing.Annotated'): # for py39+
return stringify(annotation.__args__[0])
- elif getattr(annotation, '_special', False):
+ elif all(is_system_TypeVar(a) for a in annotation.__args__):
+ # Suppress arguments if all system defined TypeVars (ex. Dict[KT, VT])
return qualname
else:
args = ', '.join(stringify(a) for a in annotation.__args__)
@@ -148,8 +159,12 @@ def _stringify_py36(annotation: Any) -> str:
annotation.__origin__ is typing.Union):
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