Merge branch '3.x'

This commit is contained in:
Takeshi KOMIYA
2020-12-29 18:37:45 +09:00
36 changed files with 728 additions and 156 deletions
@@ -27,3 +27,6 @@ class Qux:
class Quux(List[Union[int, float]]):
"""A subclass of List[Union[int, float]]"""
pass
Alias = Foo
@@ -0,0 +1,16 @@
"""
docsting of empty_all module.
"""
__all__ = []
def foo():
"""docstring"""
def bar():
"""docstring"""
def baz():
"""docstring"""
@@ -0,0 +1,19 @@
#: docstring
#:
#: :meta hide-value:
SENTINEL1 = object()
#: :meta hide-value:
SENTINEL2 = object()
class Foo:
"""docstring"""
#: docstring
#:
#: :meta hide-value:
SENTINEL1 = object()
#: :meta hide-value:
SENTINEL2 = object()
@@ -28,4 +28,9 @@ class TestAutodoc(object):
return None
class Inherited(missing_module.Class):
"""docstring"""
pass
sphinx.missing_module4.missing_function(len(missing_name2))
@@ -9,3 +9,7 @@ def _public_function(name):
:meta public:
"""
PRIVATE_CONSTANT = None #: :meta private:
_PUBLIC_CONSTANT = None #: :meta public:
@@ -0,0 +1 @@
exclude_patterns = ['_build']
@@ -0,0 +1,6 @@
.. image:: http://localhost:7777/
:target: http://localhost:7777/
`weblate.org`_
.. _weblate.org: http://localhost:7777/
+37
View File
@@ -573,3 +573,40 @@ def test_limit_rate_bails_out_after_waiting_max_time(app):
checker.rate_limits = {"localhost": RateLimit(90.0, 0.0)}
next_check = checker.limit_rate(FakeResponse())
assert next_check is None
@pytest.mark.sphinx(
'linkcheck', testroot='linkcheck-localserver-two-links', freshenv=True,
)
def test_priorityqueue_items_are_comparable(app):
with http_server(OKHandler):
app.builder.build_all()
content = (app.outdir / 'output.json').read_text()
rows = [json.loads(x) for x in sorted(content.splitlines())]
assert rows == [
{
'filename': 'index.rst',
# Should not be None.
'lineno': 0,
'status': 'working',
'code': 0,
'uri': 'http://localhost:7777/',
'info': '',
},
{
'filename': 'index.rst',
'lineno': 0,
'status': 'working',
'code': 0,
'uri': 'http://localhost:7777/',
'info': '',
},
{
'filename': 'index.rst',
'lineno': 4,
'status': 'working',
'code': 0,
'uri': 'http://localhost:7777/',
'info': '',
}
]
+4 -2
View File
@@ -23,7 +23,7 @@ def test_create_single_index(app):
".. index:: Sphinx\n"
".. index:: Ель\n"
".. index:: ёлка\n"
".. index:: תירבע\n"
".. index:: עברית\n"
".. index:: 9-symbol\n"
".. index:: &-symbol\n"
".. index:: £100\n")
@@ -41,7 +41,9 @@ def test_create_single_index(app):
assert index[4] == ('Е',
[('ёлка', [[('', '#index-6')], [], None]),
('Ель', [[('', '#index-5')], [], None])])
assert index[5] == ('ת', [('‏תירבע‎', [[('', '#index-7')], [], None])])
# Here the word starts with U+200F RIGHT-TO-LEFT MARK, which should be
# ignored when getting the first letter.
assert index[5] == ('ע', [('‏עברית‎', [[('', '#index-7')], [], None])])
@pytest.mark.sphinx('dummy', freshenv=True)
+47
View File
@@ -689,6 +689,7 @@ def test_autodoc_special_members(app):
actual = do_autodoc(app, 'class', 'target.Class', options)
assert list(filter(lambda l: '::' in l, actual)) == [
'.. py:class:: Class(arg)',
' .. py:attribute:: Class.__annotations__',
' .. py:attribute:: Class.__dict__',
' .. py:method:: Class.__init__(arg)',
' .. py:attribute:: Class.__module__',
@@ -2223,3 +2224,49 @@ def test_name_mangling(app):
' name of Foo',
'',
]
@pytest.mark.skipif(sys.version_info < (3, 6), reason='python 3.6+ is required.')
@pytest.mark.sphinx('html', testroot='ext-autodoc')
def test_hide_value(app):
options = {'members': True}
actual = do_autodoc(app, 'module', 'target.hide_value', options)
assert list(actual) == [
'',
'.. py:module:: target.hide_value',
'',
'',
'.. py:class:: Foo()',
' :module: target.hide_value',
'',
' docstring',
'',
'',
' .. py:attribute:: Foo.SENTINEL1',
' :module: target.hide_value',
'',
' docstring',
'',
' :meta hide-value:',
'',
'',
' .. py:attribute:: Foo.SENTINEL2',
' :module: target.hide_value',
'',
' :meta hide-value:',
'',
'',
'.. py:data:: SENTINEL1',
' :module: target.hide_value',
'',
' docstring',
'',
' :meta hide-value:',
'',
'',
'.. py:data:: SENTINEL2',
' :module: target.hide_value',
'',
' :meta hide-value:',
'',
]
+26
View File
@@ -189,3 +189,29 @@ def test_autoattribute_TypeVar(app):
" alias of TypeVar('T1')",
'',
]
@pytest.mark.skipif(sys.version_info < (3, 6), reason='python 3.6+ is required.')
@pytest.mark.sphinx('html', testroot='ext-autodoc')
def test_autoattribute_hide_value(app):
actual = do_autodoc(app, 'attribute', 'target.hide_value.Foo.SENTINEL1')
assert list(actual) == [
'',
'.. py:attribute:: Foo.SENTINEL1',
' :module: target.hide_value',
'',
' docstring',
'',
' :meta hide-value:',
'',
]
actual = do_autodoc(app, 'attribute', 'target.hide_value.Foo.SENTINEL2')
assert list(actual) == [
'',
'.. py:attribute:: Foo.SENTINEL2',
' :module: target.hide_value',
'',
' :meta hide-value:',
'',
]
+18
View File
@@ -173,3 +173,21 @@ def test_show_inheritance_for_subclass_of_generic_type(app):
' A subclass of List[Union[int, float]]',
'',
]
def test_class_alias(app):
def autodoc_process_docstring(*args):
"""A handler always raises an error.
This confirms this handler is never called for class aliases.
"""
raise
app.connect('autodoc-process-docstring', autodoc_process_docstring)
actual = do_autodoc(app, 'class', 'target.classes.Alias')
assert list(actual) == [
'',
'.. py:attribute:: Alias',
' :module: target.classes',
'',
' alias of :class:`target.classes.Foo`',
]
+26
View File
@@ -129,3 +129,29 @@ def test_autodata_TypeVar(app):
" alias of TypeVar('T1')",
'',
]
@pytest.mark.skipif(sys.version_info < (3, 6), reason='python 3.6+ is required.')
@pytest.mark.sphinx('html', testroot='ext-autodoc')
def test_autodata_hide_value(app):
actual = do_autodoc(app, 'data', 'target.hide_value.SENTINEL1')
assert list(actual) == [
'',
'.. py:data:: SENTINEL1',
' :module: target.hide_value',
'',
' docstring',
'',
' :meta hide-value:',
'',
]
actual = do_autodoc(app, 'data', 'target.hide_value.SENTINEL2')
assert list(actual) == [
'',
'.. py:data:: SENTINEL2',
' :module: target.hide_value',
'',
' :meta hide-value:',
'',
]
+44
View File
@@ -0,0 +1,44 @@
"""
test_ext_autodoc_autocmodule
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Test the autodoc extension. This tests mainly the Documenters; the auto
directives are tested in a test source file translated by test_build.
:copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
import sys
import pytest
from .test_ext_autodoc import do_autodoc
@pytest.mark.sphinx('html', testroot='ext-autodoc')
def test_empty_all(app):
options = {'members': True}
actual = do_autodoc(app, 'module', 'target.empty_all', options)
assert list(actual) == [
'',
'.. py:module:: target.empty_all',
'',
'docsting of empty_all module.',
'',
]
@pytest.mark.sphinx('html', testroot='ext-autodoc',
confoverrides={'autodoc_mock_imports': ['missing_module',
'missing_package1',
'missing_package2',
'missing_package3',
'sphinx.missing_module4']})
@pytest.mark.usefixtures("rollback_sysmodules")
def test_subclass_of_mocked_object(app):
sys.modules.pop('target', None) # unload target module to clear the module cache
options = {'members': True}
actual = do_autodoc(app, 'module', 'target.need_mocks', options)
assert '.. py:class:: Inherited(*args: Any, **kwargs: Any)' in actual
+3
View File
@@ -429,7 +429,10 @@ def test_autoclass_content_and_docstring_signature_both(app):
@pytest.mark.sphinx('html', testroot='ext-autodoc')
@pytest.mark.usefixtures("rollback_sysmodules")
def test_mocked_module_imports(app, warning):
sys.modules.pop('target', None) # unload target module to clear the module cache
# no autodoc_mock_imports
options = {"members": 'TestAutodoc,decoratedFunction,func'}
actual = do_autodoc(app, 'module', 'target.need_mocks', options)
+17 -1
View File
@@ -15,7 +15,7 @@ from typing import TypeVar
import pytest
from sphinx.ext.autodoc.mock import _MockModule, _MockObject, mock
from sphinx.ext.autodoc.mock import _MockModule, _MockObject, ismock, mock
def test_MockModule():
@@ -129,3 +129,19 @@ def test_mock_decorator():
assert func.__doc__ == "docstring"
assert Foo.meth.__doc__ == "docstring"
assert Bar.__doc__ == "docstring"
def test_ismock():
with mock(['sphinx.unknown']):
mod1 = import_module('sphinx.unknown')
mod2 = import_module('sphinx.application')
class Inherited(mod1.Class):
pass
assert ismock(mod1) is True
assert ismock(mod1.Class) is True
assert ismock(Inherited) is False
assert ismock(mod2) is False
assert ismock(mod2.Sphinx) is False
+29 -1
View File
@@ -23,6 +23,13 @@ def test_private_field(app):
'.. py:module:: target.private',
'',
'',
'.. py:data:: _PUBLIC_CONSTANT',
' :module: target.private',
' :value: None',
'',
' :meta public:',
'',
'',
'.. py:function:: _public_function(name)',
' :module: target.private',
'',
@@ -44,6 +51,20 @@ def test_private_field_and_private_members(app):
'.. py:module:: target.private',
'',
'',
'.. py:data:: PRIVATE_CONSTANT',
' :module: target.private',
' :value: None',
'',
' :meta private:',
'',
'',
'.. py:data:: _PUBLIC_CONSTANT',
' :module: target.private',
' :value: None',
'',
' :meta public:',
'',
'',
'.. py:function:: _public_function(name)',
' :module: target.private',
'',
@@ -66,13 +87,20 @@ def test_private_field_and_private_members(app):
def test_private_members(app):
app.config.autoclass_content = 'class'
options = {"members": None,
"private-members": "_public_function"}
"private-members": "_PUBLIC_CONSTANT,_public_function"}
actual = do_autodoc(app, 'module', 'target.private', options)
assert list(actual) == [
'',
'.. py:module:: target.private',
'',
'',
'.. py:data:: _PUBLIC_CONSTANT',
' :module: target.private',
' :value: None',
'',
' :meta public:',
'',
'',
'.. py:function:: _public_function(name)',
' :module: target.private',
'',
+37 -17
View File
@@ -379,27 +379,47 @@ def test_autosummary_generate_overwrite2(app_params, make_app):
@pytest.mark.sphinx('dummy', testroot='ext-autosummary-recursive')
def test_autosummary_recursive(app, status, warning):
app.build()
try:
app.build()
# autosummary having :recursive: option
assert (app.srcdir / 'generated' / 'package.rst').exists()
assert (app.srcdir / 'generated' / 'package.module.rst').exists()
assert (app.srcdir / 'generated' / 'package.module_importfail.rst').exists() is False
assert (app.srcdir / 'generated' / 'package.package.rst').exists()
assert (app.srcdir / 'generated' / 'package.package.module.rst').exists()
# autosummary having :recursive: option
assert (app.srcdir / 'generated' / 'package.rst').exists()
assert (app.srcdir / 'generated' / 'package.module.rst').exists()
assert (app.srcdir / 'generated' / 'package.module_importfail.rst').exists() is False
assert (app.srcdir / 'generated' / 'package.package.rst').exists()
assert (app.srcdir / 'generated' / 'package.package.module.rst').exists()
# autosummary not having :recursive: option
assert (app.srcdir / 'generated' / 'package2.rst').exists()
assert (app.srcdir / 'generated' / 'package2.module.rst').exists() is False
# autosummary not having :recursive: option
assert (app.srcdir / 'generated' / 'package2.rst').exists()
assert (app.srcdir / 'generated' / 'package2.module.rst').exists() is False
# Check content of recursively generated stub-files
content = (app.srcdir / 'generated' / 'package.rst').read_text()
assert 'package.module' in content
assert 'package.package' in content
assert 'package.module_importfail' in content
# Check content of recursively generated stub-files
content = (app.srcdir / 'generated' / 'package.rst').read_text()
assert 'package.module' in content
assert 'package.package' in content
assert 'package.module_importfail' in content
content = (app.srcdir / 'generated' / 'package.package.rst').read_text()
assert 'package.package.module' in content
content = (app.srcdir / 'generated' / 'package.package.rst').read_text()
assert 'package.package.module' in content
finally:
sys.modules.pop('package.package', None)
sys.modules.pop('package.package.module', None)
@pytest.mark.sphinx('dummy', testroot='ext-autosummary-recursive',
srcdir='test_autosummary_recursive_skips_mocked_modules',
confoverrides={'autosummary_mock_imports': ['package.package']})
def test_autosummary_recursive_skips_mocked_modules(app, status, warning):
try:
app.build()
assert (app.srcdir / 'generated' / 'package.rst').exists()
assert (app.srcdir / 'generated' / 'package.module.rst').exists()
assert (app.srcdir / 'generated' / 'package.package.rst').exists() is False
assert (app.srcdir / 'generated' / 'package.package.module.rst').exists() is False
finally:
sys.modules.pop('package.package', None)
sys.modules.pop('package.package.module', None)
@pytest.mark.sphinx('dummy', testroot='ext-autosummary-filename-map')
+6
View File
@@ -109,6 +109,12 @@ def test_restify_type_hints_alias():
assert restify(MyTuple) == ":class:`Tuple`\\ [:class:`str`, :class:`str`]" # type: ignore
@pytest.mark.skipif(sys.version_info < (3, 7), reason='python 3.7+ is required.')
def test_restify_type_ForwardRef():
from typing import ForwardRef # type: ignore
assert restify(ForwardRef("myint")) == ":class:`myint`"
def test_restify_broken_type_hints():
assert restify(BrokenType) == ':class:`tests.test_util_typing.BrokenType`'