mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
185 lines
7.3 KiB
Python
185 lines
7.3 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""
|
|
sphinx.ext.autodoc.inspector
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
Inspect utilities for autodoc
|
|
|
|
:copyright: Copyright 2007-2018 by the Sphinx team, see AUTHORS.
|
|
:license: BSD, see LICENSE for details.
|
|
"""
|
|
|
|
import typing
|
|
import warnings
|
|
|
|
from six import StringIO, string_types
|
|
|
|
from sphinx.deprecation import RemovedInSphinx20Warning
|
|
from sphinx.util.inspect import object_description
|
|
|
|
if False:
|
|
# For type annotation
|
|
from typing import Any, Callable, Dict, Tuple # NOQA
|
|
|
|
|
|
def format_annotation(annotation):
|
|
# type: (Any) -> str
|
|
"""Return formatted representation of a type annotation.
|
|
|
|
Show qualified names for types and additional details for types from
|
|
the ``typing`` module.
|
|
|
|
Displaying complex types from ``typing`` relies on its private API.
|
|
"""
|
|
warnings.warn('format_annotation() is now deprecated. '
|
|
'Please use sphinx.util.inspect.Signature instead.',
|
|
RemovedInSphinx20Warning)
|
|
if isinstance(annotation, typing.TypeVar): # type: ignore
|
|
return annotation.__name__
|
|
if annotation == Ellipsis:
|
|
return '...'
|
|
if not isinstance(annotation, type):
|
|
return repr(annotation)
|
|
|
|
qualified_name = (annotation.__module__ + '.' + annotation.__qualname__ # type: ignore
|
|
if annotation else repr(annotation))
|
|
|
|
if annotation.__module__ == 'builtins':
|
|
return annotation.__qualname__ # type: ignore
|
|
else:
|
|
if hasattr(typing, 'GenericMeta') and \
|
|
isinstance(annotation, typing.GenericMeta):
|
|
# In Python 3.5.2+, all arguments are stored in __args__,
|
|
# whereas __parameters__ only contains generic parameters.
|
|
#
|
|
# Prior to Python 3.5.2, __args__ is not available, and all
|
|
# arguments are in __parameters__.
|
|
params = None
|
|
if hasattr(annotation, '__args__'):
|
|
if annotation.__args__ is None or len(annotation.__args__) <= 2: # type: ignore # NOQA
|
|
params = annotation.__args__ # type: ignore
|
|
else: # typing.Callable
|
|
args = ', '.join(format_annotation(a) for a in annotation.__args__[:-1]) # type: ignore # NOQA
|
|
result = format_annotation(annotation.__args__[-1]) # type: ignore
|
|
return '%s[[%s], %s]' % (qualified_name, args, result)
|
|
elif hasattr(annotation, '__parameters__'):
|
|
params = annotation.__parameters__ # type: ignore
|
|
if params is not None:
|
|
param_str = ', '.join(format_annotation(p) for p in params)
|
|
return '%s[%s]' % (qualified_name, param_str)
|
|
elif (hasattr(typing, 'UnionMeta') and
|
|
isinstance(annotation, typing.UnionMeta) and # type: ignore
|
|
hasattr(annotation, '__union_params__')):
|
|
params = annotation.__union_params__
|
|
if params is not None:
|
|
param_str = ', '.join(format_annotation(p) for p in params)
|
|
return '%s[%s]' % (qualified_name, param_str)
|
|
elif (hasattr(typing, 'CallableMeta') and
|
|
isinstance(annotation, typing.CallableMeta) and # type: ignore
|
|
getattr(annotation, '__args__', None) is not None and
|
|
hasattr(annotation, '__result__')):
|
|
# Skipped in the case of plain typing.Callable
|
|
args = annotation.__args__
|
|
if args is None:
|
|
return qualified_name
|
|
elif args is Ellipsis:
|
|
args_str = '...'
|
|
else:
|
|
formatted_args = (format_annotation(a) for a in args)
|
|
args_str = '[%s]' % ', '.join(formatted_args)
|
|
return '%s[%s, %s]' % (qualified_name,
|
|
args_str,
|
|
format_annotation(annotation.__result__))
|
|
elif (hasattr(typing, 'TupleMeta') and
|
|
isinstance(annotation, typing.TupleMeta) and # type: ignore
|
|
hasattr(annotation, '__tuple_params__') and
|
|
hasattr(annotation, '__tuple_use_ellipsis__')):
|
|
params = annotation.__tuple_params__
|
|
if params is not None:
|
|
param_strings = [format_annotation(p) for p in params]
|
|
if annotation.__tuple_use_ellipsis__:
|
|
param_strings.append('...')
|
|
return '%s[%s]' % (qualified_name,
|
|
', '.join(param_strings))
|
|
return qualified_name
|
|
|
|
|
|
def formatargspec(function, args, varargs=None, varkw=None, defaults=None,
|
|
kwonlyargs=(), kwonlydefaults={}, annotations={}):
|
|
# type: (Callable, Tuple[str, ...], str, str, Any, Tuple, Dict, Dict[str, Any]) -> str
|
|
"""Return a string representation of an ``inspect.FullArgSpec`` tuple.
|
|
|
|
An enhanced version of ``inspect.formatargspec()`` that handles typing
|
|
annotations better.
|
|
"""
|
|
warnings.warn('formatargspec() is now deprecated. '
|
|
'Please use sphinx.util.inspect.Signature instead.',
|
|
RemovedInSphinx20Warning)
|
|
|
|
def format_arg_with_annotation(name):
|
|
# type: (str) -> str
|
|
if name in annotations:
|
|
return '%s: %s' % (name, format_annotation(get_annotation(name)))
|
|
return name
|
|
|
|
def get_annotation(name):
|
|
# type: (str) -> str
|
|
value = annotations[name]
|
|
if isinstance(value, string_types):
|
|
return introspected_hints.get(name, value)
|
|
else:
|
|
return value
|
|
|
|
introspected_hints = (typing.get_type_hints(function) # type: ignore
|
|
if typing and hasattr(function, '__code__') else {})
|
|
|
|
fd = StringIO()
|
|
fd.write('(')
|
|
|
|
formatted = []
|
|
defaults_start = len(args) - len(defaults) if defaults else len(args)
|
|
|
|
for i, arg in enumerate(args):
|
|
arg_fd = StringIO()
|
|
if isinstance(arg, list):
|
|
# support tupled arguments list (only for py2): def foo((x, y))
|
|
arg_fd.write('(')
|
|
arg_fd.write(format_arg_with_annotation(arg[0]))
|
|
for param in arg[1:]:
|
|
arg_fd.write(', ')
|
|
arg_fd.write(format_arg_with_annotation(param))
|
|
arg_fd.write(')')
|
|
else:
|
|
arg_fd.write(format_arg_with_annotation(arg))
|
|
if defaults and i >= defaults_start:
|
|
arg_fd.write(' = ' if arg in annotations else '=')
|
|
arg_fd.write(object_description(defaults[i - defaults_start])) # type: ignore
|
|
formatted.append(arg_fd.getvalue())
|
|
|
|
if varargs:
|
|
formatted.append('*' + format_arg_with_annotation(varargs))
|
|
|
|
if kwonlyargs:
|
|
if not varargs:
|
|
formatted.append('*')
|
|
|
|
for kwarg in kwonlyargs:
|
|
arg_fd = StringIO()
|
|
arg_fd.write(format_arg_with_annotation(kwarg))
|
|
if kwonlydefaults and kwarg in kwonlydefaults:
|
|
arg_fd.write(' = ' if kwarg in annotations else '=')
|
|
arg_fd.write(object_description(kwonlydefaults[kwarg])) # type: ignore
|
|
formatted.append(arg_fd.getvalue())
|
|
|
|
if varkw:
|
|
formatted.append('**' + format_arg_with_annotation(varkw))
|
|
|
|
fd.write(', '.join(formatted))
|
|
fd.write(')')
|
|
|
|
if 'return' in annotations:
|
|
fd.write(' -> ')
|
|
fd.write(format_annotation(get_annotation('return')))
|
|
|
|
return fd.getvalue()
|