mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Merge pull request #5300 from tk0miya/fix_autodoc_optional
Fix autodoc optional
This commit is contained in:
commit
8d0170ecf1
1
CHANGES
1
CHANGES
@ -27,6 +27,7 @@ Bugs fixed
|
||||
* LaTeX: fix the :confval:`latex_engine` documentation regarding Latin Modern
|
||||
font with XeLaTeX/LuaLateX (refs: #5251)
|
||||
* #5280: autodoc: Fix wrong type annotations for complex typing
|
||||
* autodoc: Optional types are wrongly rendered
|
||||
|
||||
Testing
|
||||
--------
|
||||
|
@ -450,6 +450,19 @@ class Signature(object):
|
||||
|
||||
Displaying complex types from ``typing`` relies on its private API.
|
||||
"""
|
||||
if isinstance(annotation, string_types):
|
||||
return annotation # type: ignore
|
||||
elif isinstance(annotation, typing.TypeVar): # type: ignore
|
||||
return annotation.__name__
|
||||
elif not annotation:
|
||||
return repr(annotation)
|
||||
elif annotation is NoneType: # type: ignore
|
||||
return 'None'
|
||||
elif getattr(annotation, '__module__', None) == 'builtins':
|
||||
return annotation.__qualname__
|
||||
elif annotation is Ellipsis:
|
||||
return '...'
|
||||
|
||||
if sys.version_info >= (3, 7): # py37+
|
||||
return self.format_annotation_new(annotation)
|
||||
else:
|
||||
@ -459,19 +472,6 @@ class Signature(object):
|
||||
# type: (Any) -> str
|
||||
"""format_annotation() for py37+"""
|
||||
module = getattr(annotation, '__module__', None)
|
||||
if isinstance(annotation, string_types):
|
||||
return annotation # type: ignore
|
||||
elif isinstance(annotation, typing.TypeVar): # type: ignore
|
||||
return annotation.__name__
|
||||
elif not annotation:
|
||||
return repr(annotation)
|
||||
elif annotation is NoneType: # type: ignore
|
||||
return 'None'
|
||||
elif module == 'builtins':
|
||||
return annotation.__qualname__
|
||||
elif annotation is Ellipsis:
|
||||
return '...'
|
||||
|
||||
if module == 'typing':
|
||||
if getattr(annotation, '_name', None):
|
||||
qualname = annotation._name
|
||||
@ -486,8 +486,11 @@ class Signature(object):
|
||||
|
||||
if getattr(annotation, '__args__', None):
|
||||
if qualname == 'Union':
|
||||
args = ', '.join(self.format_annotation(a) for a in annotation.__args__)
|
||||
return '%s[%s]' % (qualname, args)
|
||||
if len(annotation.__args__) == 2 and annotation.__args__[1] is NoneType: # type: ignore # NOQA
|
||||
return 'Optional[%s]' % self.format_annotation(annotation.__args__[0])
|
||||
else:
|
||||
args = ', '.join(self.format_annotation(a) for a in annotation.__args__)
|
||||
return '%s[%s]' % (qualname, args)
|
||||
elif qualname == 'Callable':
|
||||
args = ', '.join(self.format_annotation(a) for a in annotation.__args__[:-1])
|
||||
returns = self.format_annotation(annotation.__args__[-1])
|
||||
@ -501,38 +504,26 @@ class Signature(object):
|
||||
def format_annotation_old(self, annotation):
|
||||
# type: (Any) -> str
|
||||
"""format_annotation() for py36 or below"""
|
||||
if isinstance(annotation, string_types):
|
||||
return annotation # type: ignore
|
||||
if isinstance(annotation, typing.TypeVar): # type: ignore
|
||||
return annotation.__name__
|
||||
if annotation == Ellipsis:
|
||||
return '...'
|
||||
if not isinstance(annotation, type):
|
||||
qualified_name = repr(annotation)
|
||||
if qualified_name.startswith('typing.'): # for typing.Union
|
||||
return qualified_name.split('.', 1)[1]
|
||||
module = getattr(annotation, '__module__', None)
|
||||
if module == 'typing':
|
||||
if getattr(annotation, '_name', None):
|
||||
qualname = annotation._name
|
||||
elif getattr(annotation, '__qualname__', None):
|
||||
qualname = annotation.__qualname__
|
||||
else:
|
||||
return qualified_name
|
||||
|
||||
if not annotation:
|
||||
qualified_name = repr(annotation)
|
||||
elif annotation.__module__ == 'typing':
|
||||
qualified_name = annotation.__qualname__ # type: ignore
|
||||
qualname = self.format_annotation(annotation.__origin__) # ex. Union
|
||||
elif hasattr(annotation, '__qualname__'):
|
||||
qualname = '%s.%s' % (module, annotation.__qualname__)
|
||||
else:
|
||||
qualified_name = (annotation.__module__ + '.' + annotation.__qualname__) # type: ignore # NOQA
|
||||
qualname = repr(annotation)
|
||||
|
||||
if annotation is NoneType: # type: ignore
|
||||
return 'None'
|
||||
|
||||
if annotation.__module__ == 'builtins':
|
||||
return annotation.__qualname__ # type: ignore
|
||||
elif (hasattr(typing, 'TupleMeta') and
|
||||
isinstance(annotation, typing.TupleMeta) and # type: ignore
|
||||
not hasattr(annotation, '__tuple_params__')):
|
||||
if (hasattr(typing, 'TupleMeta') and
|
||||
isinstance(annotation, typing.TupleMeta) and # type: ignore
|
||||
not hasattr(annotation, '__tuple_params__')):
|
||||
# This is for Python 3.6+, 3.5 case is handled below
|
||||
params = annotation.__args__
|
||||
param_str = ', '.join(self.format_annotation(p) for p in params)
|
||||
return '%s[%s]' % (qualified_name, param_str)
|
||||
return '%s[%s]' % (qualname, param_str)
|
||||
elif (hasattr(typing, 'GenericMeta') and # for py36 or below
|
||||
isinstance(annotation, typing.GenericMeta)):
|
||||
# In Python 3.5.2+, all arguments are stored in __args__,
|
||||
@ -548,19 +539,32 @@ class Signature(object):
|
||||
args = ', '.join(self.format_annotation(arg) for arg
|
||||
in annotation.__args__[:-1]) # type: ignore
|
||||
result = self.format_annotation(annotation.__args__[-1]) # type: ignore
|
||||
return '%s[[%s], %s]' % (qualified_name, args, result)
|
||||
return '%s[[%s], %s]' % (qualname, args, result)
|
||||
elif hasattr(annotation, '__parameters__'):
|
||||
params = annotation.__parameters__ # type: ignore
|
||||
if params is not None:
|
||||
param_str = ', '.join(self.format_annotation(p) for p in params)
|
||||
return '%s[%s]' % (qualified_name, param_str)
|
||||
return '%s[%s]' % (qualname, param_str)
|
||||
elif (hasattr(typing, 'UnionMeta') and # for py35 or below
|
||||
isinstance(annotation, typing.UnionMeta) and # type: ignore
|
||||
hasattr(annotation, '__union_params__')):
|
||||
params = annotation.__union_params__
|
||||
if params is not None:
|
||||
param_str = ', '.join(self.format_annotation(p) for p in params)
|
||||
return '%s[%s]' % (qualified_name, param_str)
|
||||
if len(params) == 2 and params[1] is NoneType: # type: ignore
|
||||
return 'Optional[%s]' % self.format_annotation(params[0])
|
||||
else:
|
||||
param_str = ', '.join(self.format_annotation(p) for p in params)
|
||||
return '%s[%s]' % (qualname, param_str)
|
||||
elif (hasattr(typing, 'Union') and # for py36
|
||||
hasattr(annotation, '__origin__') and
|
||||
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]' % self.format_annotation(params[0])
|
||||
else:
|
||||
param_str = ', '.join(self.format_annotation(p) for p in params)
|
||||
return 'Union[%s]' % param_str
|
||||
elif (hasattr(typing, 'CallableMeta') and # for py36 or below
|
||||
isinstance(annotation, typing.CallableMeta) and # type: ignore
|
||||
getattr(annotation, '__args__', None) is not None and
|
||||
@ -568,13 +572,13 @@ class Signature(object):
|
||||
# Skipped in the case of plain typing.Callable
|
||||
args = annotation.__args__
|
||||
if args is None:
|
||||
return qualified_name
|
||||
return qualname
|
||||
elif args is Ellipsis:
|
||||
args_str = '...'
|
||||
else:
|
||||
formatted_args = (self.format_annotation(a) for a in args)
|
||||
args_str = '[%s]' % ', '.join(formatted_args)
|
||||
return '%s[%s, %s]' % (qualified_name,
|
||||
return '%s[%s, %s]' % (qualname,
|
||||
args_str,
|
||||
self.format_annotation(annotation.__result__))
|
||||
elif (hasattr(typing, 'TupleMeta') and # for py36 or below
|
||||
@ -586,10 +590,10 @@ class Signature(object):
|
||||
param_strings = [self.format_annotation(p) for p in params]
|
||||
if annotation.__tuple_use_ellipsis__:
|
||||
param_strings.append('...')
|
||||
return '%s[%s]' % (qualified_name,
|
||||
return '%s[%s]' % (qualname,
|
||||
', '.join(param_strings))
|
||||
|
||||
return qualified_name
|
||||
return qualname
|
||||
|
||||
|
||||
if sys.version_info >= (3, 5):
|
||||
|
@ -228,11 +228,11 @@ def test_Signature_partialmethod():
|
||||
assert sig == '()'
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.version_info < (3, 5),
|
||||
reason='type annotation test is available on py35 or above')
|
||||
@pytest.mark.skipif(sys.version_info < (3, 4),
|
||||
reason='type annotation test is available on py34 or above')
|
||||
def test_Signature_annotations():
|
||||
from typing_test_data import (
|
||||
f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, Node)
|
||||
f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, Node)
|
||||
|
||||
# Class annotations
|
||||
sig = inspect.Signature(f0).format_args()
|
||||
@ -289,6 +289,11 @@ def test_Signature_annotations():
|
||||
sig = inspect.Signature(f12).format_args()
|
||||
assert sig == '() -> Tuple[int, str, int]'
|
||||
|
||||
# optional
|
||||
sig = inspect.Signature(f13).format_args()
|
||||
assert sig == '() -> Optional[str]'
|
||||
|
||||
# type hints by string
|
||||
sig = inspect.Signature(Node.children).format_args()
|
||||
assert sig == '(self) -> List[typing_test_data.Node]'
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
from numbers import Integral
|
||||
from typing import List, TypeVar, Union, Callable, Tuple
|
||||
from typing import List, TypeVar, Union, Callable, Tuple, Optional
|
||||
|
||||
|
||||
def f0(x: int, y: Integral) -> None:
|
||||
@ -68,6 +68,10 @@ def f12() -> Tuple[int, str, int]:
|
||||
pass
|
||||
|
||||
|
||||
def f13() -> Optional[str]:
|
||||
pass
|
||||
|
||||
|
||||
class Node:
|
||||
def children(self) -> List['Node']:
|
||||
pass
|
||||
|
Loading…
Reference in New Issue
Block a user