Skip to content

Commit

Permalink
refactor: Merge arguments of sphinx.util.typing:stringify()
Browse files Browse the repository at this point in the history
  • Loading branch information
tk0miya committed Dec 25, 2021
1 parent bdbad40 commit 35eafcb
Show file tree
Hide file tree
Showing 3 changed files with 202 additions and 195 deletions.
9 changes: 7 additions & 2 deletions sphinx/util/inspect.py
Expand Up @@ -752,6 +752,11 @@ def stringify_signature(sig: inspect.Signature, show_annotation: bool = True,
:param unqualified_typehints: Show annotations as unqualified
(ex. io.StringIO -> StringIO)
"""
if unqualified_typehints:
mode = 'smart'
else:
mode = 'fully-qualified'

args = []
last_kind = None
for param in sig.parameters.values():
Expand All @@ -774,7 +779,7 @@ def stringify_signature(sig: inspect.Signature, show_annotation: bool = True,

if show_annotation and param.annotation is not param.empty:
arg.write(': ')
arg.write(stringify_annotation(param.annotation, unqualified_typehints, True))
arg.write(stringify_annotation(param.annotation, mode))
if param.default is not param.empty:
if show_annotation and param.annotation is not param.empty:
arg.write(' = ')
Expand All @@ -794,7 +799,7 @@ def stringify_signature(sig: inspect.Signature, show_annotation: bool = True,
show_return_annotation is False):
return '(%s)' % ', '.join(args)
else:
annotation = stringify_annotation(sig.return_annotation, unqualified_typehints, True)
annotation = stringify_annotation(sig.return_annotation, mode)
return '(%s) -> %s' % (', '.join(args), annotation)


Expand Down
82 changes: 42 additions & 40 deletions sphinx/util/typing.py
Expand Up @@ -299,19 +299,25 @@ def _restify_py36(cls: Optional[Type]) -> str:
return ':py:obj:`%s.%s`' % (cls.__module__, qualname)


def stringify(annotation: Any, smartref: bool = False, show_typing: bool = False) -> str:
def stringify(annotation: Any, mode: str = 'fully-qualified-except-typing') -> str:
"""Stringify type annotation object.
:param smartref: If true, add "~" prefix to the result to remove the leading
module and class names from the reference text
:param show_typing: If true, do not suppress the "typing" module name
:param mode: Specify a method how annotations will be stringified.
'fully-qualified-except-typing'
Show the module name and qualified name of the annotation except
the "typing" module.
'smart'
Show the name of the annotation.
'fully-qualified'
Show the module name and qualified name of the annotation.
"""
from sphinx.util import inspect # lazy loading

if smartref:
prefix = '~'
if mode == 'smart':
modprefix = '~'
else:
prefix = ''
modprefix = ''

if isinstance(annotation, str):
if annotation.startswith("'") and annotation.endswith("'"):
Expand All @@ -320,22 +326,23 @@ def stringify(annotation: Any, smartref: bool = False, show_typing: bool = False
else:
return annotation
elif isinstance(annotation, TypeVar):
if show_typing is False and annotation.__module__ == 'typing':
if (annotation.__module__ == 'typing' and
mode in ('fully-qualified-except-typing', 'smart')):
return annotation.__name__
else:
return prefix + '.'.join([annotation.__module__, annotation.__name__])
return modprefix + '.'.join([annotation.__module__, annotation.__name__])
elif inspect.isNewType(annotation):
if sys.version_info > (3, 10):
# newtypes have correct module info since Python 3.10+
return prefix + '%s.%s' % (annotation.__module__, annotation.__name__)
return modprefix + '%s.%s' % (annotation.__module__, annotation.__name__)
else:
return annotation.__name__
elif not annotation:
return repr(annotation)
elif annotation is NoneType:
return 'None'
elif annotation in INVALID_BUILTIN_CLASSES:
return prefix + INVALID_BUILTIN_CLASSES[annotation]
return modprefix + INVALID_BUILTIN_CLASSES[annotation]
elif str(annotation).startswith('typing.Annotated'): # for py310+
pass
elif (getattr(annotation, '__module__', None) == 'builtins' and
Expand All @@ -348,12 +355,12 @@ def stringify(annotation: Any, smartref: bool = False, show_typing: bool = False
return '...'

if sys.version_info >= (3, 7): # py37+
return _stringify_py37(annotation, smartref, show_typing)
return _stringify_py37(annotation, mode)
else:
return _stringify_py36(annotation, smartref, show_typing)
return _stringify_py36(annotation, mode)


def _stringify_py37(annotation: Any, smartref: bool = False, show_typing: bool = False) -> str:
def _stringify_py37(annotation: Any, mode: str = 'fully-qualified-except-typing') -> str:
"""stringify() for py37+."""
module = getattr(annotation, '__module__', None)
modprefix = ''
Expand All @@ -367,19 +374,19 @@ def _stringify_py37(annotation: Any, smartref: bool = False, show_typing: bool =
else:
qualname = stringify(annotation.__origin__).replace('typing.', '') # ex. Union

if smartref:
if mode == 'smart':
modprefix = '~%s.' % module
elif show_typing:
elif mode == 'fully-qualified':
modprefix = '%s.' % module
elif hasattr(annotation, '__qualname__'):
if smartref:
if mode == 'smart':
modprefix = '~%s.' % module
else:
modprefix = '%s.' % module
qualname = annotation.__qualname__
elif hasattr(annotation, '__origin__'):
# instantiated generic provided by a user
qualname = stringify(annotation.__origin__, smartref, show_typing)
qualname = stringify(annotation.__origin__, mode)
elif UnionType and isinstance(annotation, UnionType): # types.Union (for py3.10+)
qualname = 'types.Union'
else:
Expand All @@ -394,15 +401,13 @@ def _stringify_py37(annotation: Any, smartref: bool = False, show_typing: bool =
elif qualname in ('Optional', 'Union'):
if len(annotation.__args__) > 1 and annotation.__args__[-1] is NoneType:
if len(annotation.__args__) > 2:
args = ', '.join(stringify(a, smartref, show_typing) for a
in annotation.__args__[:-1])
args = ', '.join(stringify(a, mode) for a in annotation.__args__[:-1])
return '%sOptional[%sUnion[%s]]' % (modprefix, modprefix, args)
else:
return '%sOptional[%s]' % (modprefix, stringify(annotation.__args__[0],
smartref, show_typing))
return '%sOptional[%s]' % (modprefix,
stringify(annotation.__args__[0], mode))
else:
args = ', '.join(stringify(a, smartref, show_typing) for a
in annotation.__args__)
args = ', '.join(stringify(a, mode) for a in annotation.__args__)
return '%sUnion[%s]' % (modprefix, args)
elif qualname == 'types.Union':
if len(annotation.__args__) > 1 and None in annotation.__args__:
Expand All @@ -411,27 +416,25 @@ def _stringify_py37(annotation: Any, smartref: bool = False, show_typing: bool =
else:
return ' | '.join(stringify(a) for a in annotation.__args__)
elif qualname == 'Callable':
args = ', '.join(stringify(a, smartref, show_typing) for a
in annotation.__args__[:-1])
returns = stringify(annotation.__args__[-1], smartref, show_typing)
args = ', '.join(stringify(a, mode) for a in annotation.__args__[:-1])
returns = stringify(annotation.__args__[-1], mode)
return '%s%s[[%s], %s]' % (modprefix, qualname, args, returns)
elif qualname == 'Literal':
args = ', '.join(repr(a) for a in annotation.__args__)
return '%s%s[%s]' % (modprefix, qualname, args)
elif str(annotation).startswith('typing.Annotated'): # for py39+
return stringify(annotation.__args__[0], smartref, show_typing)
return stringify(annotation.__args__[0], mode)
elif all(is_system_TypeVar(a) for a in annotation.__args__):
# Suppress arguments if all system defined TypeVars (ex. Dict[KT, VT])
return modprefix + qualname
else:
args = ', '.join(stringify(a, smartref, show_typing) for a
in annotation.__args__)
args = ', '.join(stringify(a, mode) for a in annotation.__args__)
return '%s%s[%s]' % (modprefix, qualname, args)

return modprefix + qualname


def _stringify_py36(annotation: Any, smartref: bool = False, show_typing: bool = False) -> str:
def _stringify_py36(annotation: Any, mode: str = 'fully-qualified-except-typing') -> str:
"""stringify() for py36."""
module = getattr(annotation, '__module__', None)
modprefix = ''
Expand All @@ -447,12 +450,12 @@ def _stringify_py36(annotation: Any, smartref: bool = False, show_typing: bool =
else:
qualname = repr(annotation).replace('typing.', '')

if smartref:
if mode == 'smart':
modprefix = '~%s.' % module
elif show_typing:
elif mode == 'fully-qualified':
modprefix = '%s.' % module
elif hasattr(annotation, '__qualname__'):
if smartref:
if mode == 'smart':
modprefix = '~%s.' % module
else:
modprefix = '%s.' % module
Expand All @@ -464,7 +467,7 @@ def _stringify_py36(annotation: Any, smartref: bool = False, show_typing: bool =
not hasattr(annotation, '__tuple_params__')): # for Python 3.6
params = annotation.__args__
if params:
param_str = ', '.join(stringify(p, smartref, show_typing) for p in params)
param_str = ', '.join(stringify(p, mode) for p in params)
return '%s%s[%s]' % (modprefix, qualname, param_str)
else:
return modprefix + qualname
Expand All @@ -475,26 +478,25 @@ def _stringify_py36(annotation: Any, smartref: bool = False, show_typing: bool =
elif annotation.__origin__ == Generator: # type: ignore
params = annotation.__args__ # type: ignore
else: # typing.Callable
args = ', '.join(stringify(arg, smartref, show_typing) for arg
args = ', '.join(stringify(arg, mode) for arg
in annotation.__args__[:-1]) # type: ignore
result = stringify(annotation.__args__[-1]) # type: ignore
return '%s%s[[%s], %s]' % (modprefix, qualname, args, result)
if params is not None:
param_str = ', '.join(stringify(p, smartref, show_typing) for p in params)
param_str = ', '.join(stringify(p, mode) for p in params)
return '%s%s[%s]' % (modprefix, qualname, param_str)
elif (hasattr(annotation, '__origin__') and
annotation.__origin__ is typing.Union):
params = annotation.__args__
if params is not None:
if len(params) > 1 and params[-1] is NoneType:
if len(params) > 2:
param_str = ", ".join(stringify(p, smartref, show_typing) for p
in params[:-1])
param_str = ", ".join(stringify(p, mode) for p in params[:-1])
return '%sOptional[%sUnion[%s]]' % (modprefix, modprefix, param_str)
else:
return '%sOptional[%s]' % (modprefix, stringify(params[0]))
else:
param_str = ', '.join(stringify(p, smartref, show_typing) for p in params)
param_str = ', '.join(stringify(p, mode) for p in params)
return '%sUnion[%s]' % (modprefix, param_str)

return modprefix + qualname
Expand Down

0 comments on commit 35eafcb

Please sign in to comment.