diff options
Diffstat (limited to 'sphinx/util/typing.py')
-rw-r--r-- | sphinx/util/typing.py | 27 |
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 |