mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Drop python 3.6 support (#10468)
This commit is contained in:
2
.github/workflows/builddoc.yml
vendored
2
.github/workflows/builddoc.yml
vendored
@@ -11,7 +11,7 @@ jobs:
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v1
|
||||
with:
|
||||
python-version: 3.6
|
||||
python-version: 3.8
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt update
|
||||
|
||||
2
.github/workflows/lint.yml
vendored
2
.github/workflows/lint.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v1
|
||||
with:
|
||||
python-version: 3.6
|
||||
python-version: 3.8
|
||||
- name: Install dependencies
|
||||
run: pip install -U tox
|
||||
- name: Run Tox
|
||||
|
||||
2
.github/workflows/main.yml
vendored
2
.github/workflows/main.yml
vendored
@@ -10,8 +10,6 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- python: "3.6"
|
||||
docutils: du14
|
||||
- python: "3.7"
|
||||
docutils: du15
|
||||
- python: "3.8"
|
||||
|
||||
2
CHANGES
2
CHANGES
@@ -4,6 +4,8 @@ Release 6.0.0 (in development)
|
||||
Dependencies
|
||||
------------
|
||||
|
||||
* Drop python 3.6 support
|
||||
|
||||
Incompatible changes
|
||||
--------------------
|
||||
|
||||
|
||||
@@ -172,19 +172,19 @@ of targets and allows testing against multiple different Python environments:
|
||||
|
||||
tox -av
|
||||
|
||||
* To run unit tests for a specific Python version, such as Python 3.6::
|
||||
* To run unit tests for a specific Python version, such as Python 3.10::
|
||||
|
||||
tox -e py36
|
||||
tox -e py310
|
||||
|
||||
* To run unit tests for a specific Python version and turn on deprecation
|
||||
warnings on so they're shown in the test output::
|
||||
|
||||
PYTHONWARNINGS=all tox -e py36
|
||||
PYTHONWARNINGS=all tox -e py310
|
||||
|
||||
* Arguments to ``pytest`` can be passed via ``tox``, e.g. in order to run a
|
||||
particular test::
|
||||
|
||||
tox -e py36 tests/test_module.py::test_new_feature
|
||||
tox -e py310 tests/test_module.py::test_new_feature
|
||||
|
||||
You can also test by installing dependencies in your local environment::
|
||||
|
||||
|
||||
@@ -109,16 +109,16 @@ Ubuntu <https://ubuntu.com/about/release-cycle>`_ that has standard support.
|
||||
For example, as of July 2021, Ubuntu 16.04 has just entered extended
|
||||
security maintenance (therefore, it doesn't count as standard support) and
|
||||
the oldest LTS release to consider is Ubuntu 18.04 LTS, supported until
|
||||
April 2023 and shipping Python 3.6.
|
||||
April 2023 and shipping Python 3.8.
|
||||
|
||||
This is a summary table with the current policy:
|
||||
|
||||
========== ========= ======
|
||||
Date Ubuntu Python
|
||||
========== ========= ======
|
||||
April 2021 18.04 LTS 3.6+
|
||||
---------- --------- ------
|
||||
April 2023 20.04 LTS 3.8+
|
||||
---------- --------- ------
|
||||
April 2025 22.04 LTS 3.10+
|
||||
========== ========= ======
|
||||
|
||||
Release procedures
|
||||
|
||||
@@ -12,7 +12,7 @@ Installing Sphinx
|
||||
Overview
|
||||
--------
|
||||
|
||||
Sphinx is written in `Python`__ and supports Python 3.6+. It builds upon the
|
||||
Sphinx is written in `Python`__ and supports Python 3.7+. It builds upon the
|
||||
shoulders of many third-party libraries such as `Docutils`__ and `Jinja`__,
|
||||
which are installed when Sphinx is installed.
|
||||
|
||||
|
||||
7
setup.py
7
setup.py
@@ -7,8 +7,8 @@ import sphinx
|
||||
with open('README.rst', encoding='utf-8') as f:
|
||||
long_desc = f.read()
|
||||
|
||||
if sys.version_info < (3, 6):
|
||||
print('ERROR: Sphinx requires at least Python 3.6 to run.')
|
||||
if sys.version_info < (3, 7):
|
||||
print('ERROR: Sphinx requires at least Python 3.7 to run.')
|
||||
sys.exit(1)
|
||||
|
||||
install_requires = [
|
||||
@@ -85,7 +85,6 @@ setup(
|
||||
'Programming Language :: Python',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: Python :: 3 :: Only',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
'Programming Language :: Python :: 3.8',
|
||||
'Programming Language :: Python :: 3.9',
|
||||
@@ -127,7 +126,7 @@ setup(
|
||||
'build_sphinx = sphinx.setup_command:BuildDoc',
|
||||
],
|
||||
},
|
||||
python_requires=">=3.6",
|
||||
python_requires=">=3.7",
|
||||
install_requires=install_requires,
|
||||
extras_require=extras_require,
|
||||
)
|
||||
|
||||
@@ -18,7 +18,6 @@ Both, the url string and the caption string must escape ``%`` as ``%%``.
|
||||
"""
|
||||
|
||||
import re
|
||||
import sys
|
||||
from typing import Any, Dict, List, Tuple
|
||||
|
||||
from docutils import nodes, utils
|
||||
@@ -64,12 +63,7 @@ class ExternalLinksChecker(SphinxPostTransform):
|
||||
title = refnode.astext()
|
||||
|
||||
for alias, (base_uri, _caption) in self.app.config.extlinks.items():
|
||||
if sys.version_info < (3, 7):
|
||||
# Replace a leading backslash because re.escape() inserts a backslash before %
|
||||
# on python 3.6
|
||||
uri_pattern = re.compile(re.escape(base_uri).replace('\\%s', '(?P<value>.+)'))
|
||||
else:
|
||||
uri_pattern = re.compile(re.escape(base_uri).replace('%s', '(?P<value>.+)'))
|
||||
uri_pattern = re.compile(re.escape(base_uri).replace('%s', '(?P<value>.+)'))
|
||||
|
||||
match = uri_pattern.match(uri)
|
||||
if match and match.groupdict().get('value'):
|
||||
|
||||
@@ -15,7 +15,7 @@ from io import StringIO
|
||||
from types import MethodType, ModuleType
|
||||
from typing import Any, Callable, Dict, Mapping, Optional, Sequence, Tuple, Type, cast
|
||||
|
||||
from sphinx.pycode.ast import ast # for py36-37
|
||||
from sphinx.pycode.ast import ast # for py37
|
||||
from sphinx.pycode.ast import unparse as ast_unparse
|
||||
from sphinx.util import logging
|
||||
from sphinx.util.typing import ForwardRef
|
||||
@@ -298,7 +298,7 @@ def is_singledispatch_method(obj: Any) -> bool:
|
||||
try:
|
||||
from functools import singledispatchmethod # type: ignore
|
||||
return isinstance(obj, singledispatchmethod)
|
||||
except ImportError: # py36-37
|
||||
except ImportError: # py37
|
||||
return False
|
||||
|
||||
|
||||
@@ -569,25 +569,15 @@ def signature(subject: Callable, bound_method: bool = False, type_aliases: Dict
|
||||
"""
|
||||
|
||||
try:
|
||||
try:
|
||||
if _should_unwrap(subject):
|
||||
signature = inspect.signature(subject)
|
||||
else:
|
||||
signature = inspect.signature(subject, follow_wrapped=True)
|
||||
except ValueError:
|
||||
# follow built-in wrappers up (ex. functools.lru_cache)
|
||||
if _should_unwrap(subject):
|
||||
signature = inspect.signature(subject)
|
||||
parameters = list(signature.parameters.values())
|
||||
return_annotation = signature.return_annotation
|
||||
except IndexError:
|
||||
# Until python 3.6.4, cpython has been crashed on inspection for
|
||||
# partialmethods not having any arguments.
|
||||
# https://bugs.python.org/issue33009
|
||||
if hasattr(subject, '_partialmethod'):
|
||||
parameters = []
|
||||
return_annotation = Parameter.empty
|
||||
else:
|
||||
raise
|
||||
signature = inspect.signature(subject, follow_wrapped=True)
|
||||
except ValueError:
|
||||
# follow built-in wrappers up (ex. functools.lru_cache)
|
||||
signature = inspect.signature(subject)
|
||||
parameters = list(signature.parameters.values())
|
||||
return_annotation = signature.return_annotation
|
||||
|
||||
try:
|
||||
# Resolve annotations using ``get_type_hints()`` and type_aliases.
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import sys
|
||||
import typing
|
||||
import warnings
|
||||
from struct import Struct
|
||||
from types import TracebackType
|
||||
from typing import Any, Callable, Dict, Generator, List, Optional, Tuple, Type, TypeVar, Union
|
||||
@@ -9,7 +10,8 @@ from typing import Any, Callable, Dict, Generator, List, Optional, Tuple, Type,
|
||||
from docutils import nodes
|
||||
from docutils.parsers.rst.states import Inliner
|
||||
|
||||
from sphinx.deprecation import RemovedInSphinx60Warning, deprecated_alias
|
||||
from sphinx.deprecation import (RemovedInSphinx60Warning, RemovedInSphinx70Warning,
|
||||
deprecated_alias)
|
||||
|
||||
if sys.version_info > (3, 7):
|
||||
from typing import ForwardRef
|
||||
@@ -158,10 +160,7 @@ def restify(cls: Optional[Type], mode: str = 'fully-qualified-except-typing') ->
|
||||
else:
|
||||
return ':py:class:`%s`' % cls.__name__
|
||||
else:
|
||||
if sys.version_info >= (3, 7): # py37+
|
||||
return _restify_py37(cls, mode)
|
||||
else:
|
||||
return _restify_py36(cls, mode)
|
||||
return _restify_py37(cls, mode)
|
||||
except (AttributeError, TypeError):
|
||||
return inspect.object_description(cls)
|
||||
|
||||
@@ -234,6 +233,8 @@ def _restify_py37(cls: Optional[Type], mode: str = 'fully-qualified-except-typin
|
||||
|
||||
|
||||
def _restify_py36(cls: Optional[Type], mode: str = 'fully-qualified-except-typing') -> str:
|
||||
warnings.warn('_restify_py36() is deprecated', RemovedInSphinx70Warning)
|
||||
|
||||
if mode == 'smart':
|
||||
modprefix = '~'
|
||||
else:
|
||||
@@ -390,10 +391,7 @@ def stringify(annotation: Any, mode: str = 'fully-qualified-except-typing') -> s
|
||||
elif annotation is Ellipsis:
|
||||
return '...'
|
||||
|
||||
if sys.version_info >= (3, 7): # py37+
|
||||
return _stringify_py37(annotation, mode)
|
||||
else:
|
||||
return _stringify_py36(annotation, mode)
|
||||
return _stringify_py37(annotation, mode)
|
||||
|
||||
|
||||
def _stringify_py37(annotation: Any, mode: str = 'fully-qualified-except-typing') -> str:
|
||||
@@ -472,6 +470,8 @@ def _stringify_py37(annotation: Any, mode: str = 'fully-qualified-except-typing'
|
||||
|
||||
def _stringify_py36(annotation: Any, mode: str = 'fully-qualified-except-typing') -> str:
|
||||
"""stringify() for py36."""
|
||||
warnings.warn('_stringify_py36() is deprecated', RemovedInSphinx70Warning)
|
||||
|
||||
module = getattr(annotation, '__module__', None)
|
||||
modprefix = ''
|
||||
if module == 'typing' and getattr(annotation, '__forward_arg__', None):
|
||||
|
||||
@@ -22,29 +22,23 @@ def nonascii_srcdir(request, rootdir, sphinx_test_tempdir):
|
||||
# If supported, build in a non-ASCII source dir
|
||||
test_name = '\u65e5\u672c\u8a9e'
|
||||
basedir = sphinx_test_tempdir / request.node.originalname
|
||||
try:
|
||||
srcdir = basedir / test_name
|
||||
if not srcdir.exists():
|
||||
(rootdir / 'test-root').copytree(srcdir)
|
||||
except UnicodeEncodeError:
|
||||
# Now Python 3.7+ follows PEP-540 and uses utf-8 encoding for filesystem by default.
|
||||
# So this error handling will be no longer used (after dropping python 3.6 support).
|
||||
srcdir = basedir / 'all'
|
||||
if not srcdir.exists():
|
||||
(rootdir / 'test-root').copytree(srcdir)
|
||||
else:
|
||||
# add a doc with a non-ASCII file name to the source dir
|
||||
(srcdir / (test_name + '.txt')).write_text(dedent("""
|
||||
nonascii file name page
|
||||
=======================
|
||||
"""), encoding='utf8')
|
||||
srcdir = basedir / test_name
|
||||
if not srcdir.exists():
|
||||
(rootdir / 'test-root').copytree(srcdir)
|
||||
|
||||
root_doc = srcdir / 'index.txt'
|
||||
root_doc.write_text(root_doc.read_text(encoding='utf8') + dedent("""
|
||||
.. toctree::
|
||||
# add a doc with a non-ASCII file name to the source dir
|
||||
(srcdir / (test_name + '.txt')).write_text(dedent("""
|
||||
nonascii file name page
|
||||
=======================
|
||||
"""), encoding='utf8')
|
||||
|
||||
root_doc = srcdir / 'index.txt'
|
||||
root_doc.write_text(root_doc.read_text(encoding='utf8') + dedent("""
|
||||
.. toctree::
|
||||
|
||||
%(test_name)s/%(test_name)s
|
||||
""" % {'test_name': test_name}), encoding='utf8')
|
||||
|
||||
%(test_name)s/%(test_name)s
|
||||
""" % {'test_name': test_name}), encoding='utf8')
|
||||
return srcdir
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import sys
|
||||
|
||||
from sphinx.errors import ExtensionError
|
||||
|
||||
|
||||
@@ -10,8 +8,4 @@ def test_extension_error_repr():
|
||||
|
||||
def test_extension_error_with_orig_exc_repr():
|
||||
exc = ExtensionError("foo", Exception("bar"))
|
||||
if sys.version_info < (3, 7):
|
||||
expected = "ExtensionError('foo', Exception('bar',))"
|
||||
else:
|
||||
expected = "ExtensionError('foo', Exception('bar'))"
|
||||
assert repr(exc) == expected
|
||||
assert repr(exc) == "ExtensionError('foo', Exception('bar'))"
|
||||
|
||||
@@ -1860,70 +1860,40 @@ def test_autodoc_GenericAlias(app):
|
||||
options = {"members": None,
|
||||
"undoc-members": None}
|
||||
actual = do_autodoc(app, 'module', 'target.genericalias', options)
|
||||
if sys.version_info < (3, 7):
|
||||
assert list(actual) == [
|
||||
'',
|
||||
'.. py:module:: target.genericalias',
|
||||
'',
|
||||
'',
|
||||
'.. py:class:: Class()',
|
||||
' :module: target.genericalias',
|
||||
'',
|
||||
'',
|
||||
' .. py:attribute:: Class.T',
|
||||
' :module: target.genericalias',
|
||||
'',
|
||||
' A list of int',
|
||||
'',
|
||||
' alias of :py:class:`~typing.List`\\ [:py:class:`int`]',
|
||||
'',
|
||||
'.. py:attribute:: L',
|
||||
' :module: target.genericalias',
|
||||
'',
|
||||
' A list of Class',
|
||||
'',
|
||||
'',
|
||||
'.. py:attribute:: T',
|
||||
' :module: target.genericalias',
|
||||
'',
|
||||
' A list of int',
|
||||
'',
|
||||
]
|
||||
else:
|
||||
assert list(actual) == [
|
||||
'',
|
||||
'.. py:module:: target.genericalias',
|
||||
'',
|
||||
'',
|
||||
'.. py:class:: Class()',
|
||||
' :module: target.genericalias',
|
||||
'',
|
||||
'',
|
||||
' .. py:attribute:: Class.T',
|
||||
' :module: target.genericalias',
|
||||
'',
|
||||
' A list of int',
|
||||
'',
|
||||
' alias of :py:class:`~typing.List`\\ [:py:class:`int`]',
|
||||
'',
|
||||
'',
|
||||
'.. py:data:: L',
|
||||
' :module: target.genericalias',
|
||||
'',
|
||||
' A list of Class',
|
||||
'',
|
||||
' alias of :py:class:`~typing.List`\\ '
|
||||
'[:py:class:`~target.genericalias.Class`]',
|
||||
'',
|
||||
'',
|
||||
'.. py:data:: T',
|
||||
' :module: target.genericalias',
|
||||
'',
|
||||
' A list of int',
|
||||
'',
|
||||
' alias of :py:class:`~typing.List`\\ [:py:class:`int`]',
|
||||
'',
|
||||
]
|
||||
assert list(actual) == [
|
||||
'',
|
||||
'.. py:module:: target.genericalias',
|
||||
'',
|
||||
'',
|
||||
'.. py:class:: Class()',
|
||||
' :module: target.genericalias',
|
||||
'',
|
||||
'',
|
||||
' .. py:attribute:: Class.T',
|
||||
' :module: target.genericalias',
|
||||
'',
|
||||
' A list of int',
|
||||
'',
|
||||
' alias of :py:class:`~typing.List`\\ [:py:class:`int`]',
|
||||
'',
|
||||
'',
|
||||
'.. py:data:: L',
|
||||
' :module: target.genericalias',
|
||||
'',
|
||||
' A list of Class',
|
||||
'',
|
||||
' alias of :py:class:`~typing.List`\\ '
|
||||
'[:py:class:`~target.genericalias.Class`]',
|
||||
'',
|
||||
'',
|
||||
'.. py:data:: T',
|
||||
' :module: target.genericalias',
|
||||
'',
|
||||
' A list of int',
|
||||
'',
|
||||
' alias of :py:class:`~typing.List`\\ [:py:class:`int`]',
|
||||
'',
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.sphinx('html', testroot='ext-autodoc')
|
||||
@@ -2072,37 +2042,21 @@ def test_autodoc_for_egged_code(app):
|
||||
def test_singledispatch(app):
|
||||
options = {"members": None}
|
||||
actual = do_autodoc(app, 'module', 'target.singledispatch', options)
|
||||
if sys.version_info < (3, 7):
|
||||
assert list(actual) == [
|
||||
'',
|
||||
'.. py:module:: target.singledispatch',
|
||||
'',
|
||||
'',
|
||||
'.. py:function:: func(arg, kwarg=None)',
|
||||
' func(arg: float, kwarg=None)',
|
||||
' func(arg: int, kwarg=None)',
|
||||
' func(arg: str, kwarg=None)',
|
||||
' :module: target.singledispatch',
|
||||
'',
|
||||
' A function for general use.',
|
||||
'',
|
||||
]
|
||||
else:
|
||||
assert list(actual) == [
|
||||
'',
|
||||
'.. py:module:: target.singledispatch',
|
||||
'',
|
||||
'',
|
||||
'.. py:function:: func(arg, kwarg=None)',
|
||||
' func(arg: float, kwarg=None)',
|
||||
' func(arg: int, kwarg=None)',
|
||||
' func(arg: str, kwarg=None)',
|
||||
' func(arg: dict, kwarg=None)',
|
||||
' :module: target.singledispatch',
|
||||
'',
|
||||
' A function for general use.',
|
||||
'',
|
||||
]
|
||||
assert list(actual) == [
|
||||
'',
|
||||
'.. py:module:: target.singledispatch',
|
||||
'',
|
||||
'',
|
||||
'.. py:function:: func(arg, kwarg=None)',
|
||||
' func(arg: float, kwarg=None)',
|
||||
' func(arg: int, kwarg=None)',
|
||||
' func(arg: str, kwarg=None)',
|
||||
' func(arg: dict, kwarg=None)',
|
||||
' :module: target.singledispatch',
|
||||
'',
|
||||
' A function for general use.',
|
||||
'',
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.version_info < (3, 8),
|
||||
@@ -2416,7 +2370,6 @@ def test_name_mangling(app):
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.version_info < (3, 7), reason='python 3.7+ is required.')
|
||||
@pytest.mark.sphinx('html', testroot='ext-autodoc')
|
||||
def test_type_union_operator(app):
|
||||
options = {'members': None}
|
||||
|
||||
@@ -4,8 +4,6 @@ This tests mainly the Documenters; the auto directives are tested in a test
|
||||
source file translated by test_build.
|
||||
"""
|
||||
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
|
||||
from .test_ext_autodoc import do_autodoc
|
||||
@@ -141,27 +139,16 @@ def test_autoattribute_slots_variable_str(app):
|
||||
@pytest.mark.sphinx('html', testroot='ext-autodoc')
|
||||
def test_autoattribute_GenericAlias(app):
|
||||
actual = do_autodoc(app, 'attribute', 'target.genericalias.Class.T')
|
||||
if sys.version_info < (3, 7):
|
||||
assert list(actual) == [
|
||||
'',
|
||||
'.. py:attribute:: Class.T',
|
||||
' :module: target.genericalias',
|
||||
' :value: typing.List[int]',
|
||||
'',
|
||||
' A list of int',
|
||||
'',
|
||||
]
|
||||
else:
|
||||
assert list(actual) == [
|
||||
'',
|
||||
'.. py:attribute:: Class.T',
|
||||
' :module: target.genericalias',
|
||||
'',
|
||||
' A list of int',
|
||||
'',
|
||||
' alias of :py:class:`~typing.List`\\ [:py:class:`int`]',
|
||||
'',
|
||||
]
|
||||
assert list(actual) == [
|
||||
'',
|
||||
'.. py:attribute:: Class.T',
|
||||
' :module: target.genericalias',
|
||||
'',
|
||||
' A list of int',
|
||||
'',
|
||||
' alias of :py:class:`~typing.List`\\ [:py:class:`int`]',
|
||||
'',
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.sphinx('html', testroot='ext-autodoc')
|
||||
|
||||
@@ -4,7 +4,6 @@ This tests mainly the Documenters; the auto directives are tested in a test
|
||||
source file translated by test_build.
|
||||
"""
|
||||
|
||||
import sys
|
||||
from typing import List, Union
|
||||
|
||||
import pytest
|
||||
@@ -249,7 +248,6 @@ def test_slots_attribute(app):
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.version_info < (3, 7), reason='python 3.7+ is required.')
|
||||
@pytest.mark.sphinx('html', testroot='ext-autodoc')
|
||||
def test_show_inheritance_for_subclass_of_generic_type(app):
|
||||
options = {'show-inheritance': None}
|
||||
@@ -267,7 +265,6 @@ def test_show_inheritance_for_subclass_of_generic_type(app):
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.version_info < (3, 7), reason='python 3.7+ is required.')
|
||||
@pytest.mark.sphinx('html', testroot='ext-autodoc')
|
||||
def test_show_inheritance_for_decendants_of_generic_type(app):
|
||||
options = {'show-inheritance': None}
|
||||
@@ -299,28 +296,16 @@ def test_autodoc_process_bases(app):
|
||||
|
||||
options = {'show-inheritance': None}
|
||||
actual = do_autodoc(app, 'class', 'target.classes.Quux', options)
|
||||
if sys.version_info < (3, 7):
|
||||
assert list(actual) == [
|
||||
'',
|
||||
'.. py:class:: Quux(*args, **kwds)',
|
||||
' :module: target.classes',
|
||||
'',
|
||||
' Bases: :py:class:`int`, :py:class:`str`',
|
||||
'',
|
||||
' A subclass of List[Union[int, float]]',
|
||||
'',
|
||||
]
|
||||
else:
|
||||
assert list(actual) == [
|
||||
'',
|
||||
'.. py:class:: Quux(iterable=(), /)',
|
||||
' :module: target.classes',
|
||||
'',
|
||||
' Bases: :py:class:`int`, :py:class:`str`',
|
||||
'',
|
||||
' A subclass of List[Union[int, float]]',
|
||||
'',
|
||||
]
|
||||
assert list(actual) == [
|
||||
'',
|
||||
'.. py:class:: Quux(iterable=(), /)',
|
||||
' :module: target.classes',
|
||||
'',
|
||||
' Bases: :py:class:`int`, :py:class:`str`',
|
||||
'',
|
||||
' A subclass of List[Union[int, float]]',
|
||||
'',
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.sphinx('html', testroot='ext-autodoc')
|
||||
|
||||
@@ -4,8 +4,6 @@ This tests mainly the Documenters; the auto directives are tested in a test
|
||||
source file translated by test_build.
|
||||
"""
|
||||
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
|
||||
from .test_ext_autodoc import do_autodoc
|
||||
@@ -71,27 +69,16 @@ def test_autodata_type_comment(app):
|
||||
@pytest.mark.sphinx('html', testroot='ext-autodoc')
|
||||
def test_autodata_GenericAlias(app):
|
||||
actual = do_autodoc(app, 'data', 'target.genericalias.T')
|
||||
if sys.version_info < (3, 7):
|
||||
assert list(actual) == [
|
||||
'',
|
||||
'.. py:data:: T',
|
||||
' :module: target.genericalias',
|
||||
' :value: typing.List[int]',
|
||||
'',
|
||||
' A list of int',
|
||||
'',
|
||||
]
|
||||
else:
|
||||
assert list(actual) == [
|
||||
'',
|
||||
'.. py:data:: T',
|
||||
' :module: target.genericalias',
|
||||
'',
|
||||
' A list of int',
|
||||
'',
|
||||
' alias of :py:class:`~typing.List`\\ [:py:class:`int`]',
|
||||
'',
|
||||
]
|
||||
assert list(actual) == [
|
||||
'',
|
||||
'.. py:data:: T',
|
||||
' :module: target.genericalias',
|
||||
'',
|
||||
' A list of int',
|
||||
'',
|
||||
' alias of :py:class:`~typing.List`\\ [:py:class:`int`]',
|
||||
'',
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.sphinx('html', testroot='ext-autodoc')
|
||||
|
||||
@@ -4,8 +4,6 @@ This tests mainly the Documenters; the auto directives are tested in a test
|
||||
source file translated by test_build.
|
||||
"""
|
||||
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
|
||||
from .test_ext_autodoc import do_autodoc
|
||||
@@ -113,31 +111,18 @@ def test_decorated(app):
|
||||
def test_singledispatch(app):
|
||||
options = {}
|
||||
actual = do_autodoc(app, 'function', 'target.singledispatch.func', options)
|
||||
if sys.version_info < (3, 7):
|
||||
assert list(actual) == [
|
||||
'',
|
||||
'.. py:function:: func(arg, kwarg=None)',
|
||||
' func(arg: float, kwarg=None)',
|
||||
' func(arg: int, kwarg=None)',
|
||||
' func(arg: str, kwarg=None)',
|
||||
' :module: target.singledispatch',
|
||||
'',
|
||||
' A function for general use.',
|
||||
'',
|
||||
]
|
||||
else:
|
||||
assert list(actual) == [
|
||||
'',
|
||||
'.. py:function:: func(arg, kwarg=None)',
|
||||
' func(arg: float, kwarg=None)',
|
||||
' func(arg: int, kwarg=None)',
|
||||
' func(arg: str, kwarg=None)',
|
||||
' func(arg: dict, kwarg=None)',
|
||||
' :module: target.singledispatch',
|
||||
'',
|
||||
' A function for general use.',
|
||||
'',
|
||||
]
|
||||
assert list(actual) == [
|
||||
'',
|
||||
'.. py:function:: func(arg, kwarg=None)',
|
||||
' func(arg: float, kwarg=None)',
|
||||
' func(arg: int, kwarg=None)',
|
||||
' func(arg: str, kwarg=None)',
|
||||
' func(arg: dict, kwarg=None)',
|
||||
' :module: target.singledispatch',
|
||||
'',
|
||||
' A function for general use.',
|
||||
'',
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.sphinx('html', testroot='ext-autodoc')
|
||||
|
||||
@@ -115,11 +115,6 @@ def test_automodule_special_members(app):
|
||||
|
||||
@pytest.mark.sphinx('html', testroot='ext-autodoc')
|
||||
def test_automodule_inherited_members(app):
|
||||
if sys.version_info < (3, 7):
|
||||
args = ''
|
||||
else:
|
||||
args = '(iterable=(), /)'
|
||||
|
||||
options = {'members': None,
|
||||
'undoc-members': None,
|
||||
'inherited-members': 'Base, list'}
|
||||
@@ -170,7 +165,7 @@ def test_automodule_inherited_members(app):
|
||||
' Inherited function.',
|
||||
'',
|
||||
'',
|
||||
'.. py:class:: MyList%s' % args,
|
||||
'.. py:class:: MyList(iterable=(), /)',
|
||||
' :module: target.inheritance',
|
||||
'',
|
||||
'',
|
||||
|
||||
@@ -1231,7 +1231,6 @@ def test_autodoc_typehints_both(app):
|
||||
in context)
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.version_info < (3, 7), reason='python 3.7+ is required.')
|
||||
@pytest.mark.sphinx('text', testroot='ext-autodoc')
|
||||
def test_autodoc_type_aliases(app):
|
||||
# default
|
||||
@@ -1376,7 +1375,6 @@ def test_autodoc_type_aliases(app):
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.version_info < (3, 7), reason='python 3.7+ is required.')
|
||||
@pytest.mark.sphinx('text', testroot='ext-autodoc',
|
||||
srcdir='autodoc_typehints_description_and_type_aliases',
|
||||
confoverrides={'autodoc_typehints': "description",
|
||||
@@ -1543,27 +1541,16 @@ def test_autodoc_typehints_format_fully_qualified_for_class_alias(app):
|
||||
confoverrides={'autodoc_typehints_format': "fully-qualified"})
|
||||
def test_autodoc_typehints_format_fully_qualified_for_generic_alias(app):
|
||||
actual = do_autodoc(app, 'data', 'target.genericalias.L')
|
||||
if sys.version_info < (3, 7):
|
||||
assert list(actual) == [
|
||||
'',
|
||||
'.. py:data:: L',
|
||||
' :module: target.genericalias',
|
||||
' :value: typing.List[target.genericalias.Class]',
|
||||
'',
|
||||
' A list of Class',
|
||||
'',
|
||||
]
|
||||
else:
|
||||
assert list(actual) == [
|
||||
'',
|
||||
'.. py:data:: L',
|
||||
' :module: target.genericalias',
|
||||
'',
|
||||
' A list of Class',
|
||||
'',
|
||||
' alias of :py:class:`~typing.List`\\ [:py:class:`target.genericalias.Class`]',
|
||||
'',
|
||||
]
|
||||
assert list(actual) == [
|
||||
'',
|
||||
'.. py:data:: L',
|
||||
' :module: target.genericalias',
|
||||
'',
|
||||
' A list of Class',
|
||||
'',
|
||||
' alias of :py:class:`~typing.List`\\ [:py:class:`target.genericalias.Class`]',
|
||||
'',
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.sphinx('html', testroot='ext-autodoc',
|
||||
|
||||
@@ -84,7 +84,6 @@ def test_mock_does_not_follow_upper_modules():
|
||||
import_module('sphinx.unknown')
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.version_info < (3, 7), reason='Only for py37 or above')
|
||||
def test_abc_MockObject():
|
||||
mock = _MockObject()
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
"""Tests for :mod:`sphinx.ext.napoleon.__init__` module."""
|
||||
|
||||
import sys
|
||||
from collections import namedtuple
|
||||
from unittest import TestCase, mock
|
||||
|
||||
@@ -134,18 +133,13 @@ class SkipMemberTest(TestCase):
|
||||
mock.Mock()))
|
||||
|
||||
def test_namedtuple(self):
|
||||
if sys.version_info < (3, 7):
|
||||
self.assertSkip('class', '_asdict',
|
||||
SampleNamedTuple._asdict, False,
|
||||
'napoleon_include_private_with_doc')
|
||||
else:
|
||||
# Since python 3.7, namedtuple._asdict() has not been documented
|
||||
# because there is no way to check the method is a member of the
|
||||
# namedtuple class. This testcase confirms only it does not
|
||||
# raise an error on building document (refs: #1455)
|
||||
self.assertSkip('class', '_asdict',
|
||||
SampleNamedTuple._asdict, True,
|
||||
'napoleon_include_private_with_doc')
|
||||
# Since python 3.7, namedtuple._asdict() has not been documented
|
||||
# because there is no way to check the method is a member of the
|
||||
# namedtuple class. This testcase confirms only it does not
|
||||
# raise an error on building document (refs: #1455)
|
||||
self.assertSkip('class', '_asdict',
|
||||
SampleNamedTuple._asdict, True,
|
||||
'napoleon_include_private_with_doc')
|
||||
|
||||
def test_class_private_doc(self):
|
||||
self.assertSkip('class', '_private_doc',
|
||||
|
||||
@@ -163,16 +163,10 @@ def test_signature_annotations():
|
||||
|
||||
# TypeVars and generic types with TypeVars
|
||||
sig = inspect.signature(f2)
|
||||
if sys.version_info < (3, 7):
|
||||
assert stringify_signature(sig) == ('(x: typing.List[typing.T],'
|
||||
' y: typing.List[typing.T_co],'
|
||||
' z: typing.T'
|
||||
') -> typing.List[typing.T_contra]')
|
||||
else:
|
||||
assert stringify_signature(sig) == ('(x: typing.List[tests.typing_test_data.T],'
|
||||
' y: typing.List[tests.typing_test_data.T_co],'
|
||||
' z: tests.typing_test_data.T'
|
||||
') -> typing.List[tests.typing_test_data.T_contra]')
|
||||
assert stringify_signature(sig) == ('(x: typing.List[tests.typing_test_data.T],'
|
||||
' y: typing.List[tests.typing_test_data.T_co],'
|
||||
' z: tests.typing_test_data.T'
|
||||
') -> typing.List[tests.typing_test_data.T_contra]')
|
||||
|
||||
# Union types
|
||||
sig = inspect.signature(f3)
|
||||
@@ -678,7 +672,6 @@ def test_isproperty(app):
|
||||
assert inspect.isproperty(func) is False # function
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.version_info < (3, 7), reason='python 3.7+ is required.')
|
||||
@pytest.mark.sphinx(testroot='ext-autodoc')
|
||||
def test_isgenericalias(app):
|
||||
from target.genericalias import C, T
|
||||
|
||||
@@ -89,17 +89,10 @@ def test_restify_type_hints_containers():
|
||||
|
||||
def test_restify_type_hints_Callable():
|
||||
assert restify(Callable) == ":py:class:`~typing.Callable`"
|
||||
|
||||
if sys.version_info >= (3, 7):
|
||||
assert restify(Callable[[str], int]) == (":py:class:`~typing.Callable`\\ "
|
||||
"[[:py:class:`str`], :py:class:`int`]")
|
||||
assert restify(Callable[..., int]) == (":py:class:`~typing.Callable`\\ "
|
||||
"[[...], :py:class:`int`]")
|
||||
else:
|
||||
assert restify(Callable[[str], int]) == (":py:class:`~typing.Callable`\\ "
|
||||
"[:py:class:`str`, :py:class:`int`]")
|
||||
assert restify(Callable[..., int]) == (":py:class:`~typing.Callable`\\ "
|
||||
"[..., :py:class:`int`]")
|
||||
assert restify(Callable[[str], int]) == (":py:class:`~typing.Callable`\\ "
|
||||
"[[:py:class:`str`], :py:class:`int`]")
|
||||
assert restify(Callable[..., int]) == (":py:class:`~typing.Callable`\\ "
|
||||
"[[...], :py:class:`int`]")
|
||||
|
||||
|
||||
def test_restify_type_hints_Union():
|
||||
@@ -108,30 +101,20 @@ def test_restify_type_hints_Union():
|
||||
assert restify(Union[int, str]) == (":py:obj:`~typing.Union`\\ "
|
||||
"[:py:class:`int`, :py:class:`str`]")
|
||||
|
||||
if sys.version_info >= (3, 7):
|
||||
assert restify(Union[int, Integral]) == (":py:obj:`~typing.Union`\\ "
|
||||
"[:py:class:`int`, :py:class:`numbers.Integral`]")
|
||||
assert restify(Union[int, Integral], "smart") == (":py:obj:`~typing.Union`\\ "
|
||||
"[:py:class:`int`,"
|
||||
" :py:class:`~numbers.Integral`]")
|
||||
assert restify(Union[int, Integral]) == (":py:obj:`~typing.Union`\\ "
|
||||
"[:py:class:`int`, :py:class:`numbers.Integral`]")
|
||||
assert restify(Union[int, Integral], "smart") == (":py:obj:`~typing.Union`\\ "
|
||||
"[:py:class:`int`,"
|
||||
" :py:class:`~numbers.Integral`]")
|
||||
|
||||
assert (restify(Union[MyClass1, MyClass2]) ==
|
||||
(":py:obj:`~typing.Union`\\ "
|
||||
"[:py:class:`tests.test_util_typing.MyClass1`, "
|
||||
":py:class:`tests.test_util_typing.<MyClass2>`]"))
|
||||
assert (restify(Union[MyClass1, MyClass2], "smart") ==
|
||||
(":py:obj:`~typing.Union`\\ "
|
||||
"[:py:class:`~tests.test_util_typing.MyClass1`,"
|
||||
" :py:class:`~tests.test_util_typing.<MyClass2>`]"))
|
||||
else:
|
||||
assert restify(Union[int, Integral]) == ":py:class:`numbers.Integral`"
|
||||
assert restify(Union[int, Integral], "smart") == ":py:class:`~numbers.Integral`"
|
||||
|
||||
assert restify(Union[MyClass1, MyClass2]) == ":py:class:`tests.test_util_typing.MyClass1`"
|
||||
assert restify(Union[MyClass1, MyClass2], "smart") == ":py:class:`~tests.test_util_typing.MyClass1`"
|
||||
assert (restify(Union[MyClass1, MyClass2]) == (":py:obj:`~typing.Union`\\ "
|
||||
"[:py:class:`tests.test_util_typing.MyClass1`, "
|
||||
":py:class:`tests.test_util_typing.<MyClass2>`]"))
|
||||
assert (restify(Union[MyClass1, MyClass2], "smart") == (":py:obj:`~typing.Union`\\ "
|
||||
"[:py:class:`~tests.test_util_typing.MyClass1`,"
|
||||
" :py:class:`~tests.test_util_typing.<MyClass2>`]"))
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.version_info < (3, 7), reason='python 3.7+ is required.')
|
||||
def test_restify_type_hints_typevars():
|
||||
T = TypeVar('T')
|
||||
T_co = TypeVar('T_co', covariant=True)
|
||||
@@ -172,7 +155,6 @@ def test_restify_type_hints_alias():
|
||||
assert restify(MyTuple) == ":py:class:`~typing.Tuple`\\ [:py:class:`str`, :py:class:`str`]"
|
||||
|
||||
|
||||
@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")) == ":py:class:`myint`"
|
||||
@@ -346,22 +328,13 @@ def test_stringify_type_hints_Callable():
|
||||
assert stringify(Callable, "fully-qualified") == "typing.Callable"
|
||||
assert stringify(Callable, "smart") == "~typing.Callable"
|
||||
|
||||
if sys.version_info >= (3, 7):
|
||||
assert stringify(Callable[[str], int]) == "Callable[[str], int]"
|
||||
assert stringify(Callable[[str], int], "fully-qualified") == "typing.Callable[[str], int]"
|
||||
assert stringify(Callable[[str], int], "smart") == "~typing.Callable[[str], int]"
|
||||
assert stringify(Callable[[str], int]) == "Callable[[str], int]"
|
||||
assert stringify(Callable[[str], int], "fully-qualified") == "typing.Callable[[str], int]"
|
||||
assert stringify(Callable[[str], int], "smart") == "~typing.Callable[[str], int]"
|
||||
|
||||
assert stringify(Callable[..., int]) == "Callable[[...], int]"
|
||||
assert stringify(Callable[..., int], "fully-qualified") == "typing.Callable[[...], int]"
|
||||
assert stringify(Callable[..., int], "smart") == "~typing.Callable[[...], int]"
|
||||
else:
|
||||
assert stringify(Callable[[str], int]) == "Callable[str, int]"
|
||||
assert stringify(Callable[[str], int], "fully-qualified") == "typing.Callable[str, int]"
|
||||
assert stringify(Callable[[str], int], "smart") == "~typing.Callable[str, int]"
|
||||
|
||||
assert stringify(Callable[..., int]) == "Callable[..., int]"
|
||||
assert stringify(Callable[..., int], "fully-qualified") == "typing.Callable[..., int]"
|
||||
assert stringify(Callable[..., int], "smart") == "~typing.Callable[..., int]"
|
||||
assert stringify(Callable[..., int]) == "Callable[[...], int]"
|
||||
assert stringify(Callable[..., int], "fully-qualified") == "typing.Callable[[...], int]"
|
||||
assert stringify(Callable[..., int], "smart") == "~typing.Callable[[...], int]"
|
||||
|
||||
|
||||
def test_stringify_type_hints_Union():
|
||||
@@ -377,25 +350,16 @@ def test_stringify_type_hints_Union():
|
||||
assert stringify(Union[int, str], "fully-qualified") == "typing.Union[int, str]"
|
||||
assert stringify(Union[int, str], "smart") == "~typing.Union[int, str]"
|
||||
|
||||
if sys.version_info >= (3, 7):
|
||||
assert stringify(Union[int, Integral]) == "Union[int, numbers.Integral]"
|
||||
assert stringify(Union[int, Integral], "fully-qualified") == "typing.Union[int, numbers.Integral]"
|
||||
assert stringify(Union[int, Integral], "smart") == "~typing.Union[int, ~numbers.Integral]"
|
||||
assert stringify(Union[int, Integral]) == "Union[int, numbers.Integral]"
|
||||
assert stringify(Union[int, Integral], "fully-qualified") == "typing.Union[int, numbers.Integral]"
|
||||
assert stringify(Union[int, Integral], "smart") == "~typing.Union[int, ~numbers.Integral]"
|
||||
|
||||
assert (stringify(Union[MyClass1, MyClass2]) ==
|
||||
"Union[tests.test_util_typing.MyClass1, tests.test_util_typing.<MyClass2>]")
|
||||
assert (stringify(Union[MyClass1, MyClass2], "fully-qualified") ==
|
||||
"typing.Union[tests.test_util_typing.MyClass1, tests.test_util_typing.<MyClass2>]")
|
||||
assert (stringify(Union[MyClass1, MyClass2], "smart") ==
|
||||
"~typing.Union[~tests.test_util_typing.MyClass1, ~tests.test_util_typing.<MyClass2>]")
|
||||
else:
|
||||
assert stringify(Union[int, Integral]) == "numbers.Integral"
|
||||
assert stringify(Union[int, Integral], "fully-qualified") == "numbers.Integral"
|
||||
assert stringify(Union[int, Integral], "smart") == "~numbers.Integral"
|
||||
|
||||
assert stringify(Union[MyClass1, MyClass2]) == "tests.test_util_typing.MyClass1"
|
||||
assert stringify(Union[MyClass1, MyClass2], "fully-qualified") == "tests.test_util_typing.MyClass1"
|
||||
assert stringify(Union[MyClass1, MyClass2], "smart") == "~tests.test_util_typing.MyClass1"
|
||||
assert (stringify(Union[MyClass1, MyClass2]) ==
|
||||
"Union[tests.test_util_typing.MyClass1, tests.test_util_typing.<MyClass2>]")
|
||||
assert (stringify(Union[MyClass1, MyClass2], "fully-qualified") ==
|
||||
"typing.Union[tests.test_util_typing.MyClass1, tests.test_util_typing.<MyClass2>]")
|
||||
assert (stringify(Union[MyClass1, MyClass2], "smart") ==
|
||||
"~typing.Union[~tests.test_util_typing.MyClass1, ~tests.test_util_typing.<MyClass2>]")
|
||||
|
||||
|
||||
def test_stringify_type_hints_typevars():
|
||||
@@ -403,30 +367,17 @@ def test_stringify_type_hints_typevars():
|
||||
T_co = TypeVar('T_co', covariant=True)
|
||||
T_contra = TypeVar('T_contra', contravariant=True)
|
||||
|
||||
if sys.version_info < (3, 7):
|
||||
assert stringify(T) == "T"
|
||||
assert stringify(T, "smart") == "T"
|
||||
assert stringify(T) == "tests.test_util_typing.T"
|
||||
assert stringify(T, "smart") == "~tests.test_util_typing.T"
|
||||
|
||||
assert stringify(T_co) == "T_co"
|
||||
assert stringify(T_co, "smart") == "T_co"
|
||||
assert stringify(T_co) == "tests.test_util_typing.T_co"
|
||||
assert stringify(T_co, "smart") == "~tests.test_util_typing.T_co"
|
||||
|
||||
assert stringify(T_contra) == "T_contra"
|
||||
assert stringify(T_contra, "smart") == "T_contra"
|
||||
assert stringify(T_contra) == "tests.test_util_typing.T_contra"
|
||||
assert stringify(T_contra, "smart") == "~tests.test_util_typing.T_contra"
|
||||
|
||||
assert stringify(List[T]) == "List[T]"
|
||||
assert stringify(List[T], "smart") == "~typing.List[T]"
|
||||
else:
|
||||
assert stringify(T) == "tests.test_util_typing.T"
|
||||
assert stringify(T, "smart") == "~tests.test_util_typing.T"
|
||||
|
||||
assert stringify(T_co) == "tests.test_util_typing.T_co"
|
||||
assert stringify(T_co, "smart") == "~tests.test_util_typing.T_co"
|
||||
|
||||
assert stringify(T_contra) == "tests.test_util_typing.T_contra"
|
||||
assert stringify(T_contra, "smart") == "~tests.test_util_typing.T_contra"
|
||||
|
||||
assert stringify(List[T]) == "List[tests.test_util_typing.T]"
|
||||
assert stringify(List[T], "smart") == "~typing.List[~tests.test_util_typing.T]"
|
||||
assert stringify(List[T]) == "List[tests.test_util_typing.T]"
|
||||
assert stringify(List[T], "smart") == "~typing.List[~tests.test_util_typing.T]"
|
||||
|
||||
if sys.version_info >= (3, 10):
|
||||
assert stringify(MyInt) == "tests.test_util_typing.MyInt"
|
||||
|
||||
Reference in New Issue
Block a user