From ad61e4115776846b917f0a0f0a0bedbc06d6e1a3 Mon Sep 17 00:00:00 2001 From: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Date: Tue, 25 Jul 2023 02:07:23 +0100 Subject: [PATCH] Drop support for Python 3.8 (#11511) --- .github/workflows/main.yml | 1 - doc/conf.py | 2 ++ doc/usage/extensions/doctest.rst | 4 ++-- doc/usage/installation.rst | 10 ++++----- pyproject.toml | 11 ++++++---- sphinx/addnodes.py | 4 +++- sphinx/builders/__init__.py | 4 +++- sphinx/builders/gettext.py | 5 ++++- sphinx/builders/html/__init__.py | 11 ++++++---- sphinx/builders/latex/__init__.py | 5 ++++- sphinx/builders/linkcheck.py | 3 ++- sphinx/builders/texinfo.py | 5 ++++- sphinx/builders/text.py | 5 ++++- sphinx/builders/xml.py | 5 ++++- sphinx/config.py | 4 +++- sphinx/directives/__init__.py | 4 ++-- sphinx/domains/__init__.py | 4 +++- sphinx/domains/c.py | 5 ++++- sphinx/domains/cpp.py | 5 ++++- sphinx/domains/index.py | 4 +++- sphinx/domains/javascript.py | 7 +++++-- sphinx/domains/math.py | 4 +++- sphinx/domains/python.py | 14 ++++++------- sphinx/domains/rst.py | 5 ++++- sphinx/domains/std.py | 4 +++- sphinx/environment/__init__.py | 7 +++++-- sphinx/environment/adapters/toctree.py | 3 ++- sphinx/environment/collectors/metadata.py | 4 ++-- sphinx/environment/collectors/toctree.py | 5 ++++- sphinx/ext/apidoc.py | 5 ++++- sphinx/ext/autodoc/__init__.py | 15 +++---------- sphinx/ext/autodoc/importer.py | 14 ++++++++++++- sphinx/ext/autodoc/mock.py | 5 ++++- sphinx/ext/autodoc/type_comment.py | 16 +++++++------- sphinx/ext/autodoc/typehints.py | 3 ++- sphinx/ext/autosummary/__init__.py | 7 +++++-- sphinx/ext/autosummary/generate.py | 3 ++- sphinx/ext/doctest.py | 4 +++- sphinx/ext/inheritance_diagram.py | 3 ++- sphinx/ext/intersphinx.py | 7 ++++--- sphinx/ext/viewcode.py | 5 ++++- sphinx/jinja2glue.py | 4 +++- sphinx/locale/__init__.py | 6 +++++- sphinx/project.py | 5 ++++- sphinx/pycode/ast.py | 17 +++++---------- sphinx/registry.py | 4 +++- sphinx/search/__init__.py | 20 ++++-------------- sphinx/search/da.py | 2 +- sphinx/search/de.py | 2 +- sphinx/search/en.py | 2 +- sphinx/search/es.py | 2 +- sphinx/search/fi.py | 2 +- sphinx/search/fr.py | 2 +- sphinx/search/hu.py | 2 +- sphinx/search/it.py | 2 +- sphinx/search/ja.py | 2 +- sphinx/search/nl.py | 2 +- sphinx/search/no.py | 2 +- sphinx/search/pt.py | 2 +- sphinx/search/ro.py | 2 +- sphinx/search/ru.py | 2 +- sphinx/search/sv.py | 2 +- sphinx/search/tr.py | 2 +- sphinx/search/zh.py | 2 +- sphinx/testing/fixtures.py | 5 ++++- sphinx/testing/util.py | 3 ++- sphinx/transforms/__init__.py | 4 +++- sphinx/transforms/i18n.py | 4 +++- sphinx/transforms/post_transforms/__init__.py | 5 ++++- sphinx/util/__init__.py | 13 ++++-------- sphinx/util/display.py | 3 ++- sphinx/util/docfields.py | 6 +++--- sphinx/util/docutils.py | 3 ++- sphinx/util/i18n.py | 4 +++- sphinx/util/inspect.py | 20 +++++------------- sphinx/util/inventory.py | 4 +++- sphinx/util/logging.py | 4 +++- sphinx/util/matching.py | 5 ++++- sphinx/util/nodes.py | 6 ++++-- sphinx/util/osutil.py | 5 ++++- sphinx/util/parallel.py | 5 ++++- sphinx/util/rst.py | 5 ++++- sphinx/util/tags.py | 6 +++++- sphinx/util/typing.py | 21 +++++++++---------- sphinx/versioning.py | 4 +++- sphinx/writers/html5.py | 3 ++- sphinx/writers/latex.py | 3 ++- sphinx/writers/manpage.py | 3 ++- sphinx/writers/texinfo.py | 3 ++- sphinx/writers/text.py | 3 ++- .../test-ext-autodoc/target/TYPE_CHECKING.py | 6 ++++++ tests/test_ext_autodoc.py | 11 ++++++---- tests/test_ext_autodoc_autoclass.py | 5 +++-- tests/test_util_inspect.py | 2 +- tests/test_util_typing.py | 14 +++++++++---- tests/typing_test_data.py | 2 +- tox.ini | 4 ++-- 97 files changed, 319 insertions(+), 206 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 255d0bd57ff..723aa472014 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -23,7 +23,6 @@ jobs: fail-fast: false matrix: python: - - "3.8" - "3.9" - "3.10" - "3.11" diff --git a/doc/conf.py b/doc/conf.py index c4effb870ab..cc5d18046dc 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -131,7 +131,9 @@ ('js:func', 'string'), ('py:attr', 'srcline'), ('py:class', 'Element'), # sphinx.domains.Domain + ('py:class', 'IndexEntry'), # sphinx.domains.IndexEntry ('py:class', 'Node'), # sphinx.domains.Domain + ('py:class', 'NullTranslations'), # gettext.NullTranslations ('py:class', 'RoleFunction'), # sphinx.domains.Domain ('py:class', 'Theme'), # sphinx.application.TemplateBridge ('py:class', 'TitleGetter'), # sphinx.domains.Domain diff --git a/doc/usage/extensions/doctest.rst b/doc/usage/extensions/doctest.rst index 1b9c8226872..27cccdabe75 100644 --- a/doc/usage/extensions/doctest.rst +++ b/doc/usage/extensions/doctest.rst @@ -79,10 +79,10 @@ a comma-separated list of group names. * ``pyversion``, a string option, can be used to specify the required Python version for the example to be tested. For instance, in the following case - the example will be tested only for Python versions greater than 3.3:: + the example will be tested only for Python versions greater than 3.10:: .. doctest:: - :pyversion: > 3.3 + :pyversion: > 3.10 The following operands are supported: diff --git a/doc/usage/installation.rst b/doc/usage/installation.rst index 9a60c541e86..e85603e913f 100644 --- a/doc/usage/installation.rst +++ b/doc/usage/installation.rst @@ -12,7 +12,7 @@ Installing Sphinx Overview -------- -Sphinx is written in `Python`__ and supports Python 3.8+. It builds upon the +Sphinx is written in `Python`__ and supports Python 3.9+. It builds upon the shoulders of many third-party libraries such as `Docutils`__ and `Jinja`__, which are installed when Sphinx is installed. @@ -84,18 +84,18 @@ Install either ``python3x-sphinx`` using :command:`port`: :: - $ sudo port install py38-sphinx + $ sudo port install py39-sphinx To set up the executable paths, use the ``port select`` command: :: - $ sudo port select --set python python38 - $ sudo port select --set sphinx py38-sphinx + $ sudo port select --set python python39 + $ sudo port select --set sphinx py39-sphinx For more information, refer to the `package overview`__. -__ https://www.macports.org/ports.php?by=library&substr=py38-sphinx +__ https://www.macports.org/ports.php?by=library&substr=py39-sphinx Anaconda ~~~~~~~~ diff --git a/pyproject.toml b/pyproject.toml index d6f0ef9807d..8d5b5d3aed7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -13,7 +13,7 @@ urls.Download = "https://pypi.org/project/Sphinx/" urls.Homepage = "https://www.sphinx-doc.org/" urls."Issue tracker" = "https://github.com/sphinx-doc/sphinx/issues" license.text = "BSD-2-Clause" -requires-python = ">=3.8" +requires-python = ">=3.9" # Classifiers list: https://pypi.org/classifiers/ classifiers = [ @@ -30,10 +30,10 @@ classifiers = [ "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: PyPy", "Framework :: Sphinx", @@ -134,7 +134,7 @@ profile = "black" remove_redundant_aliases = true [tool.ruff] -target-version = "py38" # Pin Ruff to Python 3.8 +target-version = "py39" # Pin Ruff to Python 3.9 line-length = 95 show-source = true exclude = [ @@ -286,6 +286,9 @@ select = [ "sphinx/environment/adapters/toctree.py" = ["B026"] "tests/*" = ["E501"] +# these tests need old ``typing`` generic aliases +"tests/test_util_typing.py" = ["UP006", "UP035"] +"tests/typing_test_data.py" = ["UP006", "UP035"] [tool.ruff.flake8-quotes] inline-quotes = "single" @@ -296,7 +299,7 @@ disallow_incomplete_defs = true follow_imports = "skip" ignore_missing_imports = true no_implicit_optional = true -python_version = "3.8" +python_version = "3.9" show_column_numbers = true show_error_codes = true show_error_context = true diff --git a/sphinx/addnodes.py b/sphinx/addnodes.py index d85d9309ea4..bad31e72dcd 100644 --- a/sphinx/addnodes.py +++ b/sphinx/addnodes.py @@ -2,12 +2,14 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Any, Sequence +from typing import TYPE_CHECKING, Any from docutils import nodes from docutils.nodes import Element if TYPE_CHECKING: + from collections.abc import Sequence + from sphinx.application import Sphinx # deprecated name -> (object to return, canonical path or empty string) diff --git a/sphinx/builders/__init__.py b/sphinx/builders/__init__.py index 4ac15efe080..d393a131d95 100644 --- a/sphinx/builders/__init__.py +++ b/sphinx/builders/__init__.py @@ -6,7 +6,7 @@ import pickle import time from os import path -from typing import TYPE_CHECKING, Any, Iterable, Sequence +from typing import TYPE_CHECKING, Any from docutils import nodes from docutils.nodes import Node @@ -34,6 +34,8 @@ from sphinx import roles # noqa: F401 isort:skip if TYPE_CHECKING: + from collections.abc import Iterable, Sequence + from sphinx.application import Sphinx diff --git a/sphinx/builders/gettext.py b/sphinx/builders/gettext.py index 58fdfedddf0..b2f66eabef3 100644 --- a/sphinx/builders/gettext.py +++ b/sphinx/builders/gettext.py @@ -7,7 +7,7 @@ from datetime import datetime, timedelta, timezone, tzinfo from os import getenv, path, walk from time import time -from typing import Any, Generator, Iterable +from typing import TYPE_CHECKING, Any from uuid import uuid4 from docutils import nodes @@ -27,6 +27,9 @@ from sphinx.util.tags import Tags from sphinx.util.template import SphinxRenderer +if TYPE_CHECKING: + from collections.abc import Generator, Iterable + logger = logging.getLogger(__name__) diff --git a/sphinx/builders/html/__init__.py b/sphinx/builders/html/__init__.py index db0c9247bbf..9d76636badc 100644 --- a/sphinx/builders/html/__init__.py +++ b/sphinx/builders/html/__init__.py @@ -11,7 +11,7 @@ import zlib from datetime import datetime, timezone from os import path -from typing import IO, Any, Iterable, Iterator, List, Tuple, Type +from typing import IO, TYPE_CHECKING, Any from urllib.parse import quote import docutils.readers.doctree @@ -49,19 +49,22 @@ from sphinx.writers.html import HTMLWriter from sphinx.writers.html5 import HTML5Translator +if TYPE_CHECKING: + from collections.abc import Iterable, Iterator + #: the filename for the inventory of objects INVENTORY_FILENAME = 'objects.inv' logger = logging.getLogger(__name__) return_codes_re = re.compile('[\r\n]+') -DOMAIN_INDEX_TYPE = Tuple[ +DOMAIN_INDEX_TYPE = tuple[ # Index name (e.g. py-modindex) str, # Index class - Type[Index], + type[Index], # list of (heading string, list of index entries) pairs. - List[Tuple[str, List[IndexEntry]]], + list[tuple[str, list[IndexEntry]]], # whether sub-entries should start collapsed bool, ] diff --git a/sphinx/builders/latex/__init__.py b/sphinx/builders/latex/__init__.py index e3e4d5042f2..0b1fb74ae64 100644 --- a/sphinx/builders/latex/__init__.py +++ b/sphinx/builders/latex/__init__.py @@ -5,7 +5,7 @@ import os import warnings from os import path -from typing import Any, Iterable +from typing import TYPE_CHECKING, Any from docutils.frontend import OptionParser from docutils.nodes import Node @@ -35,6 +35,9 @@ # load docutils.nodes after loading sphinx.builders.latex.nodes from docutils import nodes # isort:skip +if TYPE_CHECKING: + from collections.abc import Iterable + XINDY_LANG_OPTIONS = { # language codes from docutils.writers.latex2e.Babel # ! xindy language names may differ from those in use by LaTeX/babel diff --git a/sphinx/builders/linkcheck.py b/sphinx/builders/linkcheck.py index 3592f9551fd..58c0a7835a1 100644 --- a/sphinx/builders/linkcheck.py +++ b/sphinx/builders/linkcheck.py @@ -26,7 +26,8 @@ from sphinx.util.nodes import get_node_line if TYPE_CHECKING: - from typing import Any, Callable, Generator, Iterator + from collections.abc import Generator, Iterator + from typing import Any, Callable from requests import Response diff --git a/sphinx/builders/texinfo.py b/sphinx/builders/texinfo.py index 0b642af4cae..ddfe0c6b87b 100644 --- a/sphinx/builders/texinfo.py +++ b/sphinx/builders/texinfo.py @@ -5,7 +5,7 @@ import os import warnings from os import path -from typing import Any, Iterable +from typing import TYPE_CHECKING, Any from docutils import nodes from docutils.frontend import OptionParser @@ -28,6 +28,9 @@ from sphinx.util.osutil import SEP, ensuredir, make_filename_from_project from sphinx.writers.texinfo import TexinfoTranslator, TexinfoWriter +if TYPE_CHECKING: + from collections.abc import Iterable + logger = logging.getLogger(__name__) template_dir = os.path.join(package_dir, 'templates', 'texinfo') diff --git a/sphinx/builders/text.py b/sphinx/builders/text.py index a3cc14d1bdc..171e8b53860 100644 --- a/sphinx/builders/text.py +++ b/sphinx/builders/text.py @@ -3,7 +3,7 @@ from __future__ import annotations from os import path -from typing import Any, Iterator +from typing import TYPE_CHECKING, Any from docutils.io import StringOutput from docutils.nodes import Node @@ -15,6 +15,9 @@ from sphinx.util.osutil import ensuredir, os_path from sphinx.writers.text import TextTranslator, TextWriter +if TYPE_CHECKING: + from collections.abc import Iterator + logger = logging.getLogger(__name__) diff --git a/sphinx/builders/xml.py b/sphinx/builders/xml.py index c6ac752b43b..46b95e1b37e 100644 --- a/sphinx/builders/xml.py +++ b/sphinx/builders/xml.py @@ -3,7 +3,7 @@ from __future__ import annotations from os import path -from typing import Any, Iterator +from typing import TYPE_CHECKING, Any from docutils import nodes from docutils.io import StringOutput @@ -17,6 +17,9 @@ from sphinx.util.osutil import ensuredir, os_path from sphinx.writers.xml import PseudoXMLWriter, XMLWriter +if TYPE_CHECKING: + from collections.abc import Iterator + logger = logging.getLogger(__name__) diff --git a/sphinx/config.py b/sphinx/config.py index 8b8a136e185..3aa62651ca8 100644 --- a/sphinx/config.py +++ b/sphinx/config.py @@ -6,7 +6,7 @@ import traceback import types from os import getenv, path -from typing import TYPE_CHECKING, Any, Callable, Generator, Iterator, NamedTuple +from typing import TYPE_CHECKING, Any, Callable, NamedTuple from sphinx.errors import ConfigError, ExtensionError from sphinx.locale import _, __ @@ -22,6 +22,8 @@ from sphinx.util.osutil import _chdir as chdir if TYPE_CHECKING: + from collections.abc import Generator, Iterator + from sphinx.application import Sphinx from sphinx.environment import BuildEnvironment diff --git a/sphinx/directives/__init__.py b/sphinx/directives/__init__.py index 517a5290081..2328067df4c 100644 --- a/sphinx/directives/__init__.py +++ b/sphinx/directives/__init__.py @@ -3,7 +3,7 @@ from __future__ import annotations import re -from typing import TYPE_CHECKING, Any, Generic, List, TypeVar, cast +from typing import TYPE_CHECKING, Any, Generic, TypeVar, cast from docutils import nodes from docutils.nodes import Node @@ -298,7 +298,7 @@ def run(self) -> list[Node]: literal_block, line=self.lineno) messages += [error] - return cast(List[nodes.Node], messages) + return cast(list[nodes.Node], messages) class DefaultDomain(SphinxDirective): diff --git a/sphinx/domains/__init__.py b/sphinx/domains/__init__.py index 8e4d22f1a19..81703230889 100644 --- a/sphinx/domains/__init__.py +++ b/sphinx/domains/__init__.py @@ -8,7 +8,7 @@ import copy from abc import ABC, abstractmethod -from typing import TYPE_CHECKING, Any, Callable, Iterable, NamedTuple, Optional, cast +from typing import TYPE_CHECKING, Any, Callable, NamedTuple, Optional, cast from docutils import nodes from docutils.nodes import Element, Node, system_message @@ -21,6 +21,8 @@ from sphinx.util.typing import RoleFunction if TYPE_CHECKING: + from collections.abc import Iterable + from docutils.parsers.rst import Directive from sphinx.builders import Builder diff --git a/sphinx/domains/c.py b/sphinx/domains/c.py index 0bb505fba5b..8fe0ed47cd1 100644 --- a/sphinx/domains/c.py +++ b/sphinx/domains/c.py @@ -3,7 +3,7 @@ from __future__ import annotations import re -from typing import Any, Callable, Generator, Iterator, TypeVar, Union, cast +from typing import TYPE_CHECKING, Any, Callable, TypeVar, Union, cast from docutils import nodes from docutils.nodes import Element, Node, TextElement, system_message @@ -47,6 +47,9 @@ from sphinx.util.nodes import make_refnode from sphinx.util.typing import OptionSpec +if TYPE_CHECKING: + from collections.abc import Generator, Iterator + logger = logging.getLogger(__name__) T = TypeVar('T') diff --git a/sphinx/domains/cpp.py b/sphinx/domains/cpp.py index 5b0a2416354..35620dac298 100644 --- a/sphinx/domains/cpp.py +++ b/sphinx/domains/cpp.py @@ -3,7 +3,7 @@ from __future__ import annotations import re -from typing import Any, Callable, Generator, Iterator, TypeVar +from typing import TYPE_CHECKING, Any, Callable, TypeVar from docutils import nodes from docutils.nodes import Element, Node, TextElement, system_message @@ -48,6 +48,9 @@ from sphinx.util.nodes import make_refnode from sphinx.util.typing import OptionSpec +if TYPE_CHECKING: + from collections.abc import Generator, Iterator + logger = logging.getLogger(__name__) T = TypeVar('T') diff --git a/sphinx/domains/index.py b/sphinx/domains/index.py index 681d89c61e3..3715907487f 100644 --- a/sphinx/domains/index.py +++ b/sphinx/domains/index.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Any, Iterable +from typing import TYPE_CHECKING, Any from docutils import nodes from docutils.nodes import Node, system_message @@ -17,6 +17,8 @@ from sphinx.util.typing import OptionSpec if TYPE_CHECKING: + from collections.abc import Iterable + from sphinx.application import Sphinx diff --git a/sphinx/domains/javascript.py b/sphinx/domains/javascript.py index 885d84e6157..1ee4d8c3c0e 100644 --- a/sphinx/domains/javascript.py +++ b/sphinx/domains/javascript.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Any, Iterator, Tuple, cast +from typing import TYPE_CHECKING, Any, cast from docutils import nodes from docutils.nodes import Element, Node @@ -24,10 +24,13 @@ from sphinx.util.nodes import make_id, make_refnode, nested_parse_with_titles from sphinx.util.typing import OptionSpec +if TYPE_CHECKING: + from collections.abc import Iterator + logger = logging.getLogger(__name__) -class JSObject(ObjectDescription[Tuple[str, str]]): +class JSObject(ObjectDescription[tuple[str, str]]): """ Description of a JavaScript object. """ diff --git a/sphinx/domains/math.py b/sphinx/domains/math.py index 2d947667069..79cbb6f64b0 100644 --- a/sphinx/domains/math.py +++ b/sphinx/domains/math.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Any, Iterable +from typing import TYPE_CHECKING, Any from docutils import nodes from docutils.nodes import Element, Node, make_id, system_message @@ -16,6 +16,8 @@ from sphinx.util.nodes import make_refnode if TYPE_CHECKING: + from collections.abc import Iterable + from sphinx.application import Sphinx from sphinx.builders import Builder diff --git a/sphinx/domains/python.py b/sphinx/domains/python.py index 6ebe7458d01..a67f17013bb 100644 --- a/sphinx/domains/python.py +++ b/sphinx/domains/python.py @@ -9,7 +9,7 @@ import token import typing from inspect import Parameter -from typing import Any, Iterable, Iterator, List, NamedTuple, Tuple, cast +from typing import TYPE_CHECKING, Any, NamedTuple, cast from docutils import nodes from docutils.nodes import Element, Node @@ -38,6 +38,9 @@ ) from sphinx.util.typing import OptionSpec, TextlikeNode +if TYPE_CHECKING: + from collections.abc import Iterable, Iterator + logger = logging.getLogger(__name__) @@ -162,8 +165,6 @@ def unparse(node: ast.AST) -> list[Node]: return [nodes.Text(repr(node.value))] if isinstance(node, ast.Expr): return unparse(node.value) - if isinstance(node, ast.Index): - return unparse(node.value) if isinstance(node, ast.Invert): return [addnodes.desc_sig_punctuation('', '~')] if isinstance(node, ast.List): @@ -220,9 +221,6 @@ def unparse(node: ast.AST) -> list[Node]: def _unparse_pep_604_annotation(node: ast.Subscript) -> list[Node]: subscript = node.slice - if isinstance(subscript, ast.Index): - # py38 only - subscript = subscript.value # type: ignore[assignment] flattened: list[Node] = [] if isinstance(subscript, ast.Tuple): @@ -652,7 +650,7 @@ class PyTypedField(PyXrefMixin, TypedField): pass -class PyObject(ObjectDescription[Tuple[str, str]]): +class PyObject(ObjectDescription[tuple[str, str]]): """ Description of a general Python object. @@ -1354,7 +1352,7 @@ def filter_meta_fields(app: Sphinx, domain: str, objtype: str, content: Element) for node in content: if isinstance(node, nodes.field_list): - fields = cast(List[nodes.field], node) + fields = cast(list[nodes.field], node) # removing list items while iterating the list needs reversed() for field in reversed(fields): field_name = cast(nodes.field_body, field[0]).astext().strip() diff --git a/sphinx/domains/rst.py b/sphinx/domains/rst.py index c81e40e9543..2822aa7ff1a 100644 --- a/sphinx/domains/rst.py +++ b/sphinx/domains/rst.py @@ -3,7 +3,7 @@ from __future__ import annotations import re -from typing import Any, Iterator, cast +from typing import TYPE_CHECKING, Any, cast from docutils.nodes import Element from docutils.parsers.rst import directives @@ -21,6 +21,9 @@ from sphinx.util.nodes import make_id, make_refnode from sphinx.util.typing import OptionSpec +if TYPE_CHECKING: + from collections.abc import Iterator + logger = logging.getLogger(__name__) dir_sig_re = re.compile(r'\.\. (.+?)::(.*)$') diff --git a/sphinx/domains/std.py b/sphinx/domains/std.py index 786bbbc6cfb..348c251383c 100644 --- a/sphinx/domains/std.py +++ b/sphinx/domains/std.py @@ -4,7 +4,7 @@ import re from copy import copy -from typing import TYPE_CHECKING, Any, Callable, Final, Iterable, Iterator, cast +from typing import TYPE_CHECKING, Any, Callable, Final, cast from docutils import nodes from docutils.nodes import Element, Node, system_message @@ -23,6 +23,8 @@ from sphinx.util.typing import OptionSpec, RoleFunction if TYPE_CHECKING: + from collections.abc import Iterable, Iterator + from sphinx.application import Sphinx from sphinx.builders import Builder from sphinx.environment import BuildEnvironment diff --git a/sphinx/environment/__init__.py b/sphinx/environment/__init__.py index 1d34e867a1e..7736725f58d 100644 --- a/sphinx/environment/__init__.py +++ b/sphinx/environment/__init__.py @@ -9,7 +9,7 @@ from copy import copy from datetime import datetime, timezone from os import path -from typing import TYPE_CHECKING, Any, Callable, Generator, Iterator +from typing import TYPE_CHECKING, Any, Callable from docutils import nodes from docutils.nodes import Node @@ -30,6 +30,8 @@ from sphinx.util.osutil import canon_path, os_path if TYPE_CHECKING: + from collections.abc import Generator, Iterator + from sphinx.application import Sphinx from sphinx.builders import Builder @@ -76,7 +78,8 @@ } if TYPE_CHECKING: - from typing import Literal, MutableMapping + from collections.abc import MutableMapping + from typing import Literal from typing_extensions import overload diff --git a/sphinx/environment/adapters/toctree.py b/sphinx/environment/adapters/toctree.py index 4f651e09a80..edc085005ff 100644 --- a/sphinx/environment/adapters/toctree.py +++ b/sphinx/environment/adapters/toctree.py @@ -2,7 +2,8 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Any, Iterable, TypeVar, cast +from collections.abc import Iterable +from typing import TYPE_CHECKING, Any, TypeVar, cast from docutils import nodes from docutils.nodes import Element, Node diff --git a/sphinx/environment/collectors/metadata.py b/sphinx/environment/collectors/metadata.py index 7dd9400cf53..a51a21bd029 100644 --- a/sphinx/environment/collectors/metadata.py +++ b/sphinx/environment/collectors/metadata.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Any, List, cast +from typing import Any, cast from docutils import nodes @@ -35,7 +35,7 @@ def process_doc(self, app: Sphinx, doctree: nodes.document) -> None: for node in doctree[index]: # type: ignore # nodes are multiply inherited... if isinstance(node, nodes.authors): - authors = cast(List[nodes.author], node) + authors = cast(list[nodes.author], node) md['authors'] = [author.astext() for author in authors] elif isinstance(node, nodes.field): assert len(node) == 2 diff --git a/sphinx/environment/collectors/toctree.py b/sphinx/environment/collectors/toctree.py index 7e4e887e694..3753332317b 100644 --- a/sphinx/environment/collectors/toctree.py +++ b/sphinx/environment/collectors/toctree.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Any, Sequence, TypeVar, cast +from typing import TYPE_CHECKING, Any, TypeVar, cast from docutils import nodes from docutils.nodes import Element, Node @@ -16,6 +16,9 @@ from sphinx.transforms import SphinxContentsFilter from sphinx.util import logging, url_re +if TYPE_CHECKING: + from collections.abc import Sequence + N = TypeVar('N') logger = logging.getLogger(__name__) diff --git a/sphinx/ext/apidoc.py b/sphinx/ext/apidoc.py index 108515d7363..08be97df5a3 100644 --- a/sphinx/ext/apidoc.py +++ b/sphinx/ext/apidoc.py @@ -20,7 +20,7 @@ from fnmatch import fnmatch from importlib.machinery import EXTENSION_SUFFIXES from os import path -from typing import Any, Generator +from typing import TYPE_CHECKING, Any import sphinx.locale from sphinx import __display_version__, package_dir @@ -29,6 +29,9 @@ from sphinx.util.osutil import FileAvoidWrite, ensuredir from sphinx.util.template import ReSTRenderer +if TYPE_CHECKING: + from collections.abc import Generator + # automodule options if 'SPHINX_APIDOC_OPTIONS' in os.environ: OPTIONS = os.environ['SPHINX_APIDOC_OPTIONS'].split(',') diff --git a/sphinx/ext/autodoc/__init__.py b/sphinx/ext/autodoc/__init__.py index 6974da2fe52..1f8580a1363 100644 --- a/sphinx/ext/autodoc/__init__.py +++ b/sphinx/ext/autodoc/__init__.py @@ -10,17 +10,7 @@ import re import sys from inspect import Parameter, Signature -from typing import ( - TYPE_CHECKING, - Any, - Callable, - Iterator, - List, - Sequence, - Tuple, - TypeVar, - Union, -) +from typing import TYPE_CHECKING, Any, Callable, TypeVar, Union from docutils.statemachine import StringList @@ -44,6 +34,7 @@ from sphinx.util.typing import OptionSpec, get_type_hints, restify, stringify_annotation if TYPE_CHECKING: + from collections.abc import Iterator, Sequence from types import ModuleType from sphinx.ext.autodoc.directive import DocumenterBridge @@ -286,7 +277,7 @@ def __init__(self, name: str, obj: Any, docstring: str | None = None, self.class_ = class_ -ObjectMembers = Union[List[ObjectMember], List[Tuple[str, Any]]] +ObjectMembers = Union[list[ObjectMember], list[tuple[str, Any]]] class Documenter: diff --git a/sphinx/ext/autodoc/importer.py b/sphinx/ext/autodoc/importer.py index 20ab4994bf8..bae61f11830 100644 --- a/sphinx/ext/autodoc/importer.py +++ b/sphinx/ext/autodoc/importer.py @@ -4,6 +4,7 @@ import importlib import traceback +import typing import warnings from typing import TYPE_CHECKING, Any, Callable, NamedTuple @@ -84,7 +85,18 @@ def import_object(modname: str, objpath: list[str], objtype: str = '', objpath = list(objpath) while module is None: try: - module = import_module(modname, warningiserror=warningiserror) + try: + # try importing with ``typing.TYPE_CHECKING == True`` + typing.TYPE_CHECKING = True + module = import_module(modname, warningiserror=warningiserror) + except ImportError: + # if that fails (e.g. circular import), retry with + # ``typing.TYPE_CHECKING == False`` + typing.TYPE_CHECKING = False + module = import_module(modname, warningiserror=warningiserror) + finally: + # ensure ``typing.TYPE_CHECKING == False`` + typing.TYPE_CHECKING = False logger.debug('[autodoc] import %s => %r', modname, module) except ImportError as exc: logger.debug('[autodoc] import %s => failed', modname) diff --git a/sphinx/ext/autodoc/mock.py b/sphinx/ext/autodoc/mock.py index bbec2ec6fbb..7034977c334 100644 --- a/sphinx/ext/autodoc/mock.py +++ b/sphinx/ext/autodoc/mock.py @@ -8,11 +8,14 @@ from importlib.abc import Loader, MetaPathFinder from importlib.machinery import ModuleSpec from types import MethodType, ModuleType -from typing import Any, Generator, Iterator, Sequence +from typing import TYPE_CHECKING, Any from sphinx.util import logging from sphinx.util.inspect import isboundmethod, safe_getattr +if TYPE_CHECKING: + from collections.abc import Generator, Iterator, Sequence + logger = logging.getLogger(__name__) diff --git a/sphinx/ext/autodoc/type_comment.py b/sphinx/ext/autodoc/type_comment.py index e16d5d190dc..6aef922b1e5 100644 --- a/sphinx/ext/autodoc/type_comment.py +++ b/sphinx/ext/autodoc/type_comment.py @@ -4,7 +4,7 @@ import ast from inspect import Parameter, Signature, getsource -from typing import Any, cast +from typing import TYPE_CHECKING, Any, cast import sphinx from sphinx.application import Sphinx @@ -12,18 +12,20 @@ from sphinx.pycode.ast import unparse as ast_unparse from sphinx.util import inspect, logging +if TYPE_CHECKING: + from collections.abc import Sequence + logger = logging.getLogger(__name__) -def not_suppressed(argtypes: list[ast.AST] = []) -> bool: +def not_suppressed(argtypes: Sequence[ast.expr] = ()) -> bool: """Check given *argtypes* is suppressed type_comment or not.""" if len(argtypes) == 0: # no argtypees return False - if len(argtypes) == 1 and ast_unparse(argtypes[0]) == "...": # suppressed - # Note: To support multiple versions of python, this uses ``ast_unparse()`` for - # comparison with Ellipsis. Since 3.8, ast.Constant has been used to represent - # Ellipsis node instead of ast.Ellipsis. - return False + if len(argtypes) == 1: + arg = argtypes[0] + if isinstance(arg, ast.Constant) and arg.value is ...: # suppressed + return False # not suppressed return True diff --git a/sphinx/ext/autodoc/typehints.py b/sphinx/ext/autodoc/typehints.py index 9cbd1b14db1..c7330c4d80a 100644 --- a/sphinx/ext/autodoc/typehints.py +++ b/sphinx/ext/autodoc/typehints.py @@ -3,7 +3,8 @@ from __future__ import annotations import re -from typing import Any, Iterable, cast +from collections.abc import Iterable +from typing import Any, cast from docutils import nodes from docutils.nodes import Element diff --git a/sphinx/ext/autosummary/__init__.py b/sphinx/ext/autosummary/__init__.py index 76d99b83e8b..035b94752ba 100644 --- a/sphinx/ext/autosummary/__init__.py +++ b/sphinx/ext/autosummary/__init__.py @@ -56,7 +56,7 @@ from inspect import Parameter from os import path from types import ModuleType -from typing import Any, List, Sequence, cast +from typing import TYPE_CHECKING, Any, cast from docutils import nodes from docutils.nodes import Node, system_message @@ -91,6 +91,9 @@ from sphinx.util.typing import OptionSpec from sphinx.writers.html import HTML5Translator +if TYPE_CHECKING: + from collections.abc import Sequence + logger = logging.getLogger(__name__) @@ -127,7 +130,7 @@ def autosummary_table_visit_html(self: HTML5Translator, node: autosummary_table) table = cast(nodes.table, node[0]) tgroup = cast(nodes.tgroup, table[0]) tbody = cast(nodes.tbody, tgroup[-1]) - rows = cast(List[nodes.row], tbody) + rows = cast(list[nodes.row], tbody) for row in rows: col1_entry = cast(nodes.entry, row[0]) par = cast(nodes.paragraph, col1_entry[0]) diff --git a/sphinx/ext/autosummary/generate.py b/sphinx/ext/autosummary/generate.py index b74ce014294..1fceba4f362 100644 --- a/sphinx/ext/autosummary/generate.py +++ b/sphinx/ext/autosummary/generate.py @@ -23,7 +23,7 @@ import re import sys from os import path -from typing import TYPE_CHECKING, Any, NamedTuple, Sequence +from typing import TYPE_CHECKING, Any, NamedTuple from jinja2 import TemplateNotFound from jinja2.sandbox import SandboxedEnvironment @@ -50,6 +50,7 @@ from sphinx.util.template import SphinxTemplateLoader if TYPE_CHECKING: + from collections.abc import Sequence from gettext import NullTranslations logger = logging.getLogger(__name__) diff --git a/sphinx/ext/doctest.py b/sphinx/ext/doctest.py index 10eb0fc82ca..418f3801b74 100644 --- a/sphinx/ext/doctest.py +++ b/sphinx/ext/doctest.py @@ -11,7 +11,7 @@ import time from io import StringIO from os import path -from typing import TYPE_CHECKING, Any, Callable, Iterable, Sequence +from typing import TYPE_CHECKING, Any, Callable from docutils import nodes from docutils.nodes import Element, Node, TextElement @@ -29,6 +29,8 @@ from sphinx.util.typing import OptionSpec if TYPE_CHECKING: + from collections.abc import Iterable, Sequence + from sphinx.application import Sphinx diff --git a/sphinx/ext/inheritance_diagram.py b/sphinx/ext/inheritance_diagram.py index 8994f578c6b..a25bbcbc32a 100644 --- a/sphinx/ext/inheritance_diagram.py +++ b/sphinx/ext/inheritance_diagram.py @@ -33,8 +33,9 @@ class E(B): pass import builtins import inspect import re +from collections.abc import Iterable from importlib import import_module -from typing import Any, Iterable, cast +from typing import Any, cast from docutils import nodes from docutils.nodes import Node diff --git a/sphinx/ext/intersphinx.py b/sphinx/ext/intersphinx.py index a3d048e43df..cb85af1aab9 100644 --- a/sphinx/ext/intersphinx.py +++ b/sphinx/ext/intersphinx.py @@ -25,7 +25,7 @@ import sys import time from os import path -from typing import IO, TYPE_CHECKING, Any, Iterable, cast +from typing import TYPE_CHECKING, cast from urllib.parse import urlsplit, urlunsplit from docutils import nodes @@ -42,8 +42,9 @@ from sphinx.util.inventory import InventoryFile if TYPE_CHECKING: + from collections.abc import Iterable from types import ModuleType - from typing import Tuple, Union + from typing import IO, Any, Union from docutils.nodes import Node, TextElement, system_message from docutils.utils import Reporter @@ -54,7 +55,7 @@ from sphinx.environment import BuildEnvironment from sphinx.util.typing import Inventory, InventoryItem, RoleFunction - InventoryCacheEntry = Tuple[Union[str, None], int, Inventory] + InventoryCacheEntry = tuple[Union[str, None], int, Inventory] logger = logging.getLogger(__name__) diff --git a/sphinx/ext/viewcode.py b/sphinx/ext/viewcode.py index 4bef39726b6..6bb957db8f0 100644 --- a/sphinx/ext/viewcode.py +++ b/sphinx/ext/viewcode.py @@ -5,7 +5,7 @@ import posixpath import traceback from os import path -from typing import Any, Generator, Iterable, cast +from typing import TYPE_CHECKING, Any, cast from docutils import nodes from docutils.nodes import Element, Node @@ -23,6 +23,9 @@ from sphinx.util.display import status_iterator from sphinx.util.nodes import make_refnode +if TYPE_CHECKING: + from collections.abc import Generator, Iterable + logger = logging.getLogger(__name__) diff --git a/sphinx/jinja2glue.py b/sphinx/jinja2glue.py index 8a25ed6b228..1abd380d668 100644 --- a/sphinx/jinja2glue.py +++ b/sphinx/jinja2glue.py @@ -5,7 +5,7 @@ import pathlib from os import path from pprint import pformat -from typing import TYPE_CHECKING, Any, Callable, Iterator +from typing import TYPE_CHECKING, Any, Callable from jinja2 import BaseLoader, FileSystemLoader, TemplateNotFound from jinja2.environment import Environment @@ -23,6 +23,8 @@ from jinja2 import contextfunction as pass_context if TYPE_CHECKING: + from collections.abc import Iterator + from sphinx.builders import Builder diff --git a/sphinx/locale/__init__.py b/sphinx/locale/__init__.py index 46f629ca36c..ca7b71a9b00 100644 --- a/sphinx/locale/__init__.py +++ b/sphinx/locale/__init__.py @@ -5,7 +5,11 @@ import locale from gettext import NullTranslations, translation from os import path -from typing import Any, Callable, Iterable +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from collections.abc import Iterable + from typing import Any, Callable class _TranslationProxy: diff --git a/sphinx/project.py b/sphinx/project.py index cb4a71f5816..52043d97a93 100644 --- a/sphinx/project.py +++ b/sphinx/project.py @@ -4,13 +4,16 @@ import os from glob import glob -from typing import Iterable +from typing import TYPE_CHECKING from sphinx.locale import __ from sphinx.util import logging from sphinx.util.matching import get_matching_files from sphinx.util.osutil import SEP, path_stabilize, relpath +if TYPE_CHECKING: + from collections.abc import Iterable + logger = logging.getLogger(__name__) EXCLUDE_PATHS = ['**/_sources', '.#*', '**/.#*', '*.lproj/**'] diff --git a/sphinx/pycode/ast.py b/sphinx/pycode/ast.py index 6596287afc3..f193f35293f 100644 --- a/sphinx/pycode/ast.py +++ b/sphinx/pycode/ast.py @@ -143,9 +143,6 @@ def visit_Dict(self, node: ast.Dict) -> str: items = (k + ": " + v for k, v in zip(keys, values)) return "{" + ", ".join(items) + "}" - def visit_Index(self, node: ast.Index) -> str: - return self.visit(node.value) - def visit_Lambda(self, node: ast.Lambda) -> str: return "lambda %s: ..." % self.visit(node.args) @@ -159,21 +156,17 @@ def visit_Set(self, node: ast.Set) -> str: return "{" + ", ".join(self.visit(e) for e in node.elts) + "}" def visit_Subscript(self, node: ast.Subscript) -> str: - def is_simple_tuple(value: ast.AST) -> bool: + def is_simple_tuple(value: ast.expr) -> bool: return ( - isinstance(value, ast.Tuple) and - bool(value.elts) and - not any(isinstance(elt, ast.Starred) for elt in value.elts) + isinstance(value, ast.Tuple) + and bool(value.elts) + and not any(isinstance(elt, ast.Starred) for elt in value.elts) ) if is_simple_tuple(node.slice): elts = ", ".join(self.visit(e) for e in node.slice.elts) # type: ignore return f"{self.visit(node.value)}[{elts}]" - elif isinstance(node.slice, ast.Index) and is_simple_tuple(node.slice.value): - elts = ", ".join(self.visit(e) for e in node.slice.value.elts) # type: ignore - return f"{self.visit(node.value)}[{elts}]" - else: - return f"{self.visit(node.value)}[{self.visit(node.slice)}]" + return f"{self.visit(node.value)}[{self.visit(node.slice)}]" def visit_UnaryOp(self, node: ast.UnaryOp) -> str: # UnaryOp is one of {UAdd, USub, Invert, Not}, which refer to ``+x``, diff --git a/sphinx/registry.py b/sphinx/registry.py index 5eda1bb0186..755a9fd3cc9 100644 --- a/sphinx/registry.py +++ b/sphinx/registry.py @@ -6,7 +6,7 @@ import traceback from importlib import import_module from types import MethodType -from typing import TYPE_CHECKING, Any, Callable, Iterator +from typing import TYPE_CHECKING, Any, Callable from docutils import nodes from docutils.core import Publisher @@ -36,6 +36,8 @@ from sphinx.util.typing import RoleFunction, TitleGetter if TYPE_CHECKING: + from collections.abc import Iterator + from sphinx.application import Sphinx from sphinx.ext.autodoc import Documenter diff --git a/sphinx/search/__init__.py b/sphinx/search/__init__.py index f981905c711..5d20a514939 100644 --- a/sphinx/search/__init__.py +++ b/sphinx/search/__init__.py @@ -9,22 +9,7 @@ import re from importlib import import_module from os import path -from typing import ( - IO, - Any, - Callable, - Dict, - Generator, - Iterable, - Iterator, - List, - Optional, - Sequence, - Set, - Tuple, - Type, - Union, -) +from typing import IO, TYPE_CHECKING, Any from docutils import nodes from docutils.nodes import Element, Node @@ -33,6 +18,9 @@ from sphinx.environment import BuildEnvironment from sphinx.util import split_index_msg +if TYPE_CHECKING: + from collections.abc import Iterable + class SearchLanguage: """ diff --git a/sphinx/search/da.py b/sphinx/search/da.py index 73afd09029b..9b5b9f5e35d 100644 --- a/sphinx/search/da.py +++ b/sphinx/search/da.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Dict +from typing import TYPE_CHECKING, Dict import snowballstemmer diff --git a/sphinx/search/de.py b/sphinx/search/de.py index a10c0fc63c8..1c253fdf706 100644 --- a/sphinx/search/de.py +++ b/sphinx/search/de.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Dict +from typing import TYPE_CHECKING, Dict import snowballstemmer diff --git a/sphinx/search/en.py b/sphinx/search/en.py index 5f6b893689a..caa6f66ec03 100644 --- a/sphinx/search/en.py +++ b/sphinx/search/en.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Dict +from typing import TYPE_CHECKING, Dict import snowballstemmer diff --git a/sphinx/search/es.py b/sphinx/search/es.py index 201778ce696..c5d9a5c7910 100644 --- a/sphinx/search/es.py +++ b/sphinx/search/es.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Dict +from typing import TYPE_CHECKING, Dict import snowballstemmer diff --git a/sphinx/search/fi.py b/sphinx/search/fi.py index 1f3c37115df..70114f876f7 100644 --- a/sphinx/search/fi.py +++ b/sphinx/search/fi.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Dict +from typing import TYPE_CHECKING, Dict import snowballstemmer diff --git a/sphinx/search/fr.py b/sphinx/search/fr.py index 6003ada3f7a..01319dd860b 100644 --- a/sphinx/search/fr.py +++ b/sphinx/search/fr.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Dict +from typing import TYPE_CHECKING, Dict import snowballstemmer diff --git a/sphinx/search/hu.py b/sphinx/search/hu.py index 0950115a7f2..eed08dbdecb 100644 --- a/sphinx/search/hu.py +++ b/sphinx/search/hu.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Dict +from typing import TYPE_CHECKING, Dict import snowballstemmer diff --git a/sphinx/search/it.py b/sphinx/search/it.py index 2f6cde8d232..7bf712b7726 100644 --- a/sphinx/search/it.py +++ b/sphinx/search/it.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Dict +from typing import TYPE_CHECKING, Dict import snowballstemmer diff --git a/sphinx/search/ja.py b/sphinx/search/ja.py index 88c5061989b..de221ced163 100644 --- a/sphinx/search/ja.py +++ b/sphinx/search/ja.py @@ -13,7 +13,7 @@ import os import re import sys -from typing import Any, Dict, List +from typing import TYPE_CHECKING, Any, Dict, List try: import MeCab diff --git a/sphinx/search/nl.py b/sphinx/search/nl.py index 6ab629c8f00..a610b12db19 100644 --- a/sphinx/search/nl.py +++ b/sphinx/search/nl.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Dict +from typing import TYPE_CHECKING, Dict import snowballstemmer diff --git a/sphinx/search/no.py b/sphinx/search/no.py index 1ca031d665b..a69380b410b 100644 --- a/sphinx/search/no.py +++ b/sphinx/search/no.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Dict +from typing import TYPE_CHECKING, Dict import snowballstemmer diff --git a/sphinx/search/pt.py b/sphinx/search/pt.py index 6caa5d7e6c2..908a4179c20 100644 --- a/sphinx/search/pt.py +++ b/sphinx/search/pt.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Dict +from typing import TYPE_CHECKING, Dict import snowballstemmer diff --git a/sphinx/search/ro.py b/sphinx/search/ro.py index 28714aeba91..b6c9d67b6ac 100644 --- a/sphinx/search/ro.py +++ b/sphinx/search/ro.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Dict, Set +from typing import TYPE_CHECKING, Dict, Set import snowballstemmer diff --git a/sphinx/search/ru.py b/sphinx/search/ru.py index 67d1a74e7ba..b8412c1e846 100644 --- a/sphinx/search/ru.py +++ b/sphinx/search/ru.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Dict +from typing import TYPE_CHECKING, Dict import snowballstemmer diff --git a/sphinx/search/sv.py b/sphinx/search/sv.py index 81282d375b7..88cc5602d86 100644 --- a/sphinx/search/sv.py +++ b/sphinx/search/sv.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Dict +from typing import TYPE_CHECKING, Dict import snowballstemmer diff --git a/sphinx/search/tr.py b/sphinx/search/tr.py index 6a7fd709725..f4a865ca84e 100644 --- a/sphinx/search/tr.py +++ b/sphinx/search/tr.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Dict, Set +from typing import TYPE_CHECKING, Dict, Set import snowballstemmer diff --git a/sphinx/search/zh.py b/sphinx/search/zh.py index 93bc0c8acf5..2a3a6e7b571 100644 --- a/sphinx/search/zh.py +++ b/sphinx/search/zh.py @@ -4,7 +4,7 @@ import os import re -from typing import Dict, List +from typing import TYPE_CHECKING, Dict, List import snowballstemmer diff --git a/sphinx/testing/fixtures.py b/sphinx/testing/fixtures.py index 710cadcd81b..157fe93414a 100644 --- a/sphinx/testing/fixtures.py +++ b/sphinx/testing/fixtures.py @@ -6,13 +6,16 @@ import sys from collections import namedtuple from io import StringIO -from typing import Any, Callable, Generator +from typing import TYPE_CHECKING, Any, Callable import pytest from sphinx.testing import util from sphinx.testing.util import SphinxTestApp, SphinxTestAppWrapperForSkipBuilding +if TYPE_CHECKING: + from collections.abc import Generator + DEFAULT_ENABLED_MARKERS = [ ( 'sphinx(builder, testroot=None, freshenv=False, confoverrides=None, tags=None,' diff --git a/sphinx/testing/util.py b/sphinx/testing/util.py index 72b6a13d66d..48ae126c210 100644 --- a/sphinx/testing/util.py +++ b/sphinx/testing/util.py @@ -6,7 +6,7 @@ import re import sys import warnings -from typing import IO, TYPE_CHECKING, Any, Generator +from typing import IO, TYPE_CHECKING, Any from xml.etree import ElementTree from docutils import nodes @@ -19,6 +19,7 @@ from sphinx.util.osutil import relpath if TYPE_CHECKING: + from collections.abc import Generator from io import StringIO __all__ = [ diff --git a/sphinx/transforms/__init__.py b/sphinx/transforms/__init__.py index be38c6f244f..21beb6c3a90 100644 --- a/sphinx/transforms/__init__.py +++ b/sphinx/transforms/__init__.py @@ -4,7 +4,7 @@ import re import unicodedata -from typing import TYPE_CHECKING, Any, Generator, cast +from typing import TYPE_CHECKING, Any, cast from docutils import nodes from docutils.nodes import Node, Text @@ -23,6 +23,8 @@ from sphinx.util.nodes import apply_source_workaround, is_smartquotable if TYPE_CHECKING: + from collections.abc import Generator + from sphinx.application import Sphinx from sphinx.domains.std import StandardDomain from sphinx.environment import BuildEnvironment diff --git a/sphinx/transforms/i18n.py b/sphinx/transforms/i18n.py index d16b8f75488..ceb9e241235 100644 --- a/sphinx/transforms/i18n.py +++ b/sphinx/transforms/i18n.py @@ -6,7 +6,7 @@ from os import path from re import DOTALL, match from textwrap import indent -from typing import TYPE_CHECKING, Any, Sequence, TypeVar +from typing import TYPE_CHECKING, Any, TypeVar from docutils import nodes from docutils.io import StringInput @@ -29,6 +29,8 @@ ) if TYPE_CHECKING: + from collections.abc import Sequence + from sphinx.application import Sphinx diff --git a/sphinx/transforms/post_transforms/__init__.py b/sphinx/transforms/post_transforms/__init__.py index e7e458000be..da0df34de36 100644 --- a/sphinx/transforms/post_transforms/__init__.py +++ b/sphinx/transforms/post_transforms/__init__.py @@ -3,7 +3,7 @@ from __future__ import annotations import re -from typing import Any, Sequence, cast +from typing import TYPE_CHECKING, Any, cast from docutils import nodes from docutils.nodes import Element, Node @@ -19,6 +19,9 @@ from sphinx.util.docutils import SphinxTranslator from sphinx.util.nodes import find_pending_xref_condition, process_only_nodes +if TYPE_CHECKING: + from collections.abc import Sequence + logger = logging.getLogger(__name__) diff --git a/sphinx/util/__init__.py b/sphinx/util/__init__.py index 087ec0d96ee..dc490f53785 100644 --- a/sphinx/util/__init__.py +++ b/sphinx/util/__init__.py @@ -6,7 +6,6 @@ import os import posixpath import re -import sys from importlib import import_module from os import path from typing import IO, Any @@ -108,23 +107,19 @@ def __setstate__(self, state: set[str]) -> None: def md5(data=b'', **kwargs): """Wrapper around hashlib.md5 - Attempt call with 'usedforsecurity=False' if supported. + Call with 'usedforsecurity=False'. """ - if sys.version_info[:2] > (3, 8): - return hashlib.md5(data, usedforsecurity=False) - return hashlib.md5(data, **kwargs) + return hashlib.md5(data, usedforsecurity=False) def sha1(data=b'', **kwargs): """Wrapper around hashlib.sha1 - Attempt call with 'usedforsecurity=False' if supported. + Call with 'usedforsecurity=False'. """ - if sys.version_info[:2] > (3, 8): - return hashlib.sha1(data, usedforsecurity=False) - return hashlib.sha1(data, **kwargs) + return hashlib.sha1(data, usedforsecurity=False) class DownloadFiles(dict): diff --git a/sphinx/util/display.py b/sphinx/util/display.py index f0e016c3ada..407c2e300a6 100644 --- a/sphinx/util/display.py +++ b/sphinx/util/display.py @@ -1,13 +1,14 @@ from __future__ import annotations import functools -from typing import Any, Callable, Iterable, Iterator, TypeVar +from typing import Any, Callable, TypeVar from sphinx.locale import __ from sphinx.util import logging from sphinx.util.console import bold # type: ignore if False: + from collections.abc import Iterable, Iterator from types import TracebackType logger = logging.getLogger(__name__) diff --git a/sphinx/util/docfields.py b/sphinx/util/docfields.py index 6d046822787..63823c280f2 100644 --- a/sphinx/util/docfields.py +++ b/sphinx/util/docfields.py @@ -6,7 +6,7 @@ from __future__ import annotations import contextlib -from typing import TYPE_CHECKING, Any, List, Tuple, cast +from typing import TYPE_CHECKING, Any, cast from docutils import nodes from docutils.nodes import Element, Node @@ -294,7 +294,7 @@ def transform(self, node: nodes.field_list) -> None: types: dict[str, dict] = {} # step 1: traverse all fields and collect field types and content - for field in cast(List[nodes.field], node): + for field in cast(list[nodes.field], node): assert len(field) == 2 field_name = cast(nodes.field_name, field[0]) field_body = cast(nodes.field_body, field[1]) @@ -378,7 +378,7 @@ def transform(self, node: nodes.field_list) -> None: # get one entry per field if typedesc.is_grouped: if typename in groupindices: - group = cast(Tuple[Field, List, Node], entries[groupindices[typename]]) + group = cast(tuple[Field, list, Node], entries[groupindices[typename]]) else: groupindices[typename] = len(entries) group = (typedesc, [], field) diff --git a/sphinx/util/docutils.py b/sphinx/util/docutils.py index 5485caeffbf..8faa7ad3033 100644 --- a/sphinx/util/docutils.py +++ b/sphinx/util/docutils.py @@ -7,7 +7,7 @@ from contextlib import contextmanager from copy import copy from os import path -from typing import IO, TYPE_CHECKING, Any, Callable, Generator, cast +from typing import IO, TYPE_CHECKING, Any, Callable, cast import docutils from docutils import nodes @@ -28,6 +28,7 @@ report_re = re.compile('^(.+?:(?:\\d+)?): \\((DEBUG|INFO|WARNING|ERROR|SEVERE)/(\\d+)?\\) ') if TYPE_CHECKING: + from collections.abc import Generator from types import ModuleType from docutils.frontend import Values diff --git a/sphinx/util/i18n.py b/sphinx/util/i18n.py index 177f4284027..04c8ccb35fa 100644 --- a/sphinx/util/i18n.py +++ b/sphinx/util/i18n.py @@ -6,7 +6,7 @@ import re from datetime import datetime, timezone from os import path -from typing import TYPE_CHECKING, Callable, Generator, NamedTuple +from typing import TYPE_CHECKING, Callable, NamedTuple import babel.dates from babel.messages.mofile import write_mo @@ -18,6 +18,8 @@ from sphinx.util.osutil import SEP, canon_path, relpath if TYPE_CHECKING: + from collections.abc import Generator + from sphinx.environment import BuildEnvironment diff --git a/sphinx/util/inspect.py b/sphinx/util/inspect.py index 8e98ca44715..986419da9dd 100644 --- a/sphinx/util/inspect.py +++ b/sphinx/util/inspect.py @@ -11,6 +11,7 @@ import sys import types import typing +from collections.abc import Mapping, Sequence from functools import cached_property, partial, partialmethod, singledispatchmethod from importlib import import_module from inspect import ( # noqa: F401 @@ -29,7 +30,7 @@ ModuleType, WrapperDescriptorType, ) -from typing import Any, Callable, Dict, Mapping, Sequence, cast +from typing import Any, Callable, cast from sphinx.pycode.ast import unparse as ast_unparse from sphinx.util import logging @@ -324,15 +325,7 @@ def isproperty(obj: Any) -> bool: def isgenericalias(obj: Any) -> bool: """Check if the object is GenericAlias.""" - if isinstance(obj, typing._GenericAlias): # type: ignore - return True - if (hasattr(types, 'GenericAlias') # only for py39+ - and isinstance(obj, types.GenericAlias)): - return True - if (hasattr(typing, '_SpecialGenericAlias') # for py39+ - and isinstance(obj, typing._SpecialGenericAlias)): - return True - return False + return isinstance(obj, (types.GenericAlias, typing._BaseGenericAlias)) # type: ignore def safe_getattr(obj: Any, name: str, *defargs: Any) -> Any: @@ -488,7 +481,7 @@ def __getattr__(self, name: str) -> Any: return getattr(self.__module, name) -class TypeAliasNamespace(Dict[str, Any]): +class TypeAliasNamespace(dict[str, Any]): """Pseudo namespace class for autodoc_type_aliases. This enables to look up nested modules and classes like `mod1.mod2.Class`. @@ -584,10 +577,7 @@ def evaluate_signature(sig: inspect.Signature, globalns: dict | None = None, """Evaluate unresolved type annotations in a signature object.""" def evaluate_forwardref(ref: ForwardRef, globalns: dict, localns: dict) -> Any: """Evaluate a forward reference.""" - if sys.version_info[:2] >= (3, 9): - return ref._evaluate(globalns, localns, frozenset()) - else: - return ref._evaluate(globalns, localns) + return ref._evaluate(globalns, localns, frozenset()) def evaluate(annotation: Any, globalns: dict, localns: dict) -> Any: """Evaluate unresolved type annotation.""" diff --git a/sphinx/util/inventory.py b/sphinx/util/inventory.py index 123a86d25dc..560fa92939a 100644 --- a/sphinx/util/inventory.py +++ b/sphinx/util/inventory.py @@ -4,7 +4,7 @@ import os import re import zlib -from typing import IO, TYPE_CHECKING, Callable, Iterator +from typing import IO, TYPE_CHECKING, Callable from sphinx.util import logging from sphinx.util.typing import Inventory, InventoryItem @@ -13,6 +13,8 @@ logger = logging.getLogger(__name__) if TYPE_CHECKING: + from collections.abc import Iterator + from sphinx.builders import Builder from sphinx.environment import BuildEnvironment diff --git a/sphinx/util/logging.py b/sphinx/util/logging.py index 1b2d6e45035..0fb683b6b98 100644 --- a/sphinx/util/logging.py +++ b/sphinx/util/logging.py @@ -6,7 +6,7 @@ import logging.handlers from collections import defaultdict from contextlib import contextmanager -from typing import IO, TYPE_CHECKING, Any, Generator +from typing import IO, TYPE_CHECKING, Any from docutils import nodes from docutils.nodes import Node @@ -17,6 +17,8 @@ from sphinx.util.osutil import abspath if TYPE_CHECKING: + from collections.abc import Generator + from sphinx.application import Sphinx diff --git a/sphinx/util/matching.py b/sphinx/util/matching.py index 0a0be72f70b..04422ed53ab 100644 --- a/sphinx/util/matching.py +++ b/sphinx/util/matching.py @@ -4,10 +4,13 @@ import os.path import re -from typing import Callable, Iterable, Iterator +from typing import TYPE_CHECKING, Callable from sphinx.util.osutil import canon_path, path_stabilize +if TYPE_CHECKING: + from collections.abc import Iterable, Iterator + def _translate_pattern(pat: str) -> str: """Translate a shell-style glob pattern to a regular expression. diff --git a/sphinx/util/nodes.py b/sphinx/util/nodes.py index 35c654a6c02..8aff570d65e 100644 --- a/sphinx/util/nodes.py +++ b/sphinx/util/nodes.py @@ -5,7 +5,7 @@ import contextlib import re import unicodedata -from typing import TYPE_CHECKING, Any, Callable, Iterable +from typing import TYPE_CHECKING, Any, Callable from docutils import nodes from docutils.nodes import Element, Node @@ -18,6 +18,8 @@ from sphinx.util import logging if TYPE_CHECKING: + from collections.abc import Iterable + from sphinx.builders import Builder from sphinx.environment import BuildEnvironment from sphinx.util.tags import Tags @@ -47,7 +49,7 @@ class NodeMatcher: following example searches ``reference`` node having ``refdomain`` attributes:: from __future__ import annotations -from typing import Any +from typing import TYPE_CHECKING, Any matcher = NodeMatcher(nodes.reference, refdomain=Any) doctree.findall(matcher) # => [, , ...] diff --git a/sphinx/util/osutil.py b/sphinx/util/osutil.py index 0ba1a686210..f5f0a2e0c96 100644 --- a/sphinx/util/osutil.py +++ b/sphinx/util/osutil.py @@ -11,10 +11,13 @@ import unicodedata from io import StringIO from os import path -from typing import Any, Iterator +from typing import TYPE_CHECKING, Any from sphinx.deprecation import _deprecation_warning +if TYPE_CHECKING: + from collections.abc import Iterator + try: # for ALT Linux (#6712) from sphinx.testing.path import path as Path diff --git a/sphinx/util/parallel.py b/sphinx/util/parallel.py index 928d5b0dcfb..0afdff9dee5 100644 --- a/sphinx/util/parallel.py +++ b/sphinx/util/parallel.py @@ -6,7 +6,7 @@ import time import traceback from math import sqrt -from typing import Any, Callable, Sequence +from typing import TYPE_CHECKING, Any, Callable try: import multiprocessing @@ -17,6 +17,9 @@ from sphinx.errors import SphinxParallelError from sphinx.util import logging +if TYPE_CHECKING: + from collections.abc import Sequence + logger = logging.getLogger(__name__) # our parallel functionality only works for the forking Process diff --git a/sphinx/util/rst.py b/sphinx/util/rst.py index c875ea5b54e..441f7c0e3b1 100644 --- a/sphinx/util/rst.py +++ b/sphinx/util/rst.py @@ -5,7 +5,7 @@ import re from collections import defaultdict from contextlib import contextmanager -from typing import Generator +from typing import TYPE_CHECKING from unicodedata import east_asian_width from docutils.parsers.rst import roles @@ -18,6 +18,9 @@ from sphinx.locale import __ from sphinx.util import docutils, logging +if TYPE_CHECKING: + from collections.abc import Generator + logger = logging.getLogger(__name__) FIELD_NAME_RE = re.compile(Body.patterns['field_marker']) diff --git a/sphinx/util/tags.py b/sphinx/util/tags.py index a9f767672d1..40f9bcde59a 100644 --- a/sphinx/util/tags.py +++ b/sphinx/util/tags.py @@ -1,12 +1,16 @@ from __future__ import annotations -from typing import Iterator +from typing import TYPE_CHECKING from jinja2 import nodes from jinja2.environment import Environment from jinja2.nodes import Node from jinja2.parser import Parser +if TYPE_CHECKING: + from collections.abc import Iterator + + env = Environment() diff --git a/sphinx/util/typing.py b/sphinx/util/typing.py index fd1e33233fa..7af34dbefb2 100644 --- a/sphinx/util/typing.py +++ b/sphinx/util/typing.py @@ -6,7 +6,7 @@ import typing from struct import Struct from types import TracebackType -from typing import Any, Callable, Dict, ForwardRef, List, Tuple, TypeVar, Union +from typing import Any, Callable, ForwardRef, TypeVar, Union from docutils import nodes from docutils.parsers.rst.states import Inliner @@ -16,10 +16,10 @@ except ImportError: UnionType = None -# builtin classes that have incorrect __module__ +# classes that have incorrect __module__ INVALID_BUILTIN_CLASSES = { - Struct: 'struct.Struct', # Before Python 3.9 - TracebackType: 'types.TracebackType', + Struct: 'struct.Struct', # Struct.__module__ == '_struct' + TracebackType: 'types.TracebackType', # TracebackType.__module__ == 'builtins' } @@ -41,23 +41,23 @@ def is_invalid_builtin_class(obj: Any) -> bool: PathMatcher = Callable[[str], bool] # common role functions -RoleFunction = Callable[[str, str, str, int, Inliner, Dict[str, Any], List[str]], - Tuple[List[nodes.Node], List[nodes.system_message]]] +RoleFunction = Callable[[str, str, str, int, Inliner, dict[str, Any], list[str]], + tuple[list[nodes.Node], list[nodes.system_message]]] # A option spec for directive -OptionSpec = Dict[str, Callable[[str], Any]] +OptionSpec = dict[str, Callable[[str], Any]] # title getter functions for enumerable nodes (see sphinx.domains.std) TitleGetter = Callable[[nodes.Node], str] # inventory data on memory -InventoryItem = Tuple[ +InventoryItem = tuple[ str, # project name str, # project version str, # URL str, # display name ] -Inventory = Dict[str, Dict[str, InventoryItem]] +Inventory = dict[str, dict[str, InventoryItem]] def get_type_hints( @@ -80,8 +80,7 @@ def get_type_hints( # Failed to evaluate ForwardRef (maybe not runtime checkable) return safe_getattr(obj, '__annotations__', {}) except TypeError: - # Invalid object is given. But try to get __annotations__ as a fallback for - # the code using type union operator (PEP 604) in python 3.9 or below. + # Invalid object is given. But try to get __annotations__ as a fallback. return safe_getattr(obj, '__annotations__', {}) except KeyError: # a broken class found (refs: https://github.com/sphinx-doc/sphinx/issues/8084) diff --git a/sphinx/versioning.py b/sphinx/versioning.py index 86cd1e43f5e..ecfa6c18ac5 100644 --- a/sphinx/versioning.py +++ b/sphinx/versioning.py @@ -5,7 +5,7 @@ from itertools import product, zip_longest from operator import itemgetter from os import path -from typing import TYPE_CHECKING, Any, Iterator +from typing import TYPE_CHECKING, Any from uuid import uuid4 from docutils.nodes import Node @@ -13,6 +13,8 @@ from sphinx.transforms import SphinxTransform if TYPE_CHECKING: + from collections.abc import Iterator + from sphinx.application import Sphinx try: diff --git a/sphinx/writers/html5.py b/sphinx/writers/html5.py index 8298e44c9c8..c92f190c430 100644 --- a/sphinx/writers/html5.py +++ b/sphinx/writers/html5.py @@ -6,7 +6,8 @@ import posixpath import re import urllib.parse -from typing import TYPE_CHECKING, Iterable, cast +from collections.abc import Iterable +from typing import TYPE_CHECKING, cast from docutils import nodes from docutils.nodes import Element, Node, Text diff --git a/sphinx/writers/latex.py b/sphinx/writers/latex.py index 2d1898ac5c6..b10fa94e39b 100644 --- a/sphinx/writers/latex.py +++ b/sphinx/writers/latex.py @@ -8,8 +8,9 @@ import re from collections import defaultdict +from collections.abc import Iterable from os import path -from typing import TYPE_CHECKING, Any, Iterable, cast +from typing import TYPE_CHECKING, Any, cast from docutils import nodes, writers from docutils.nodes import Element, Node, Text diff --git a/sphinx/writers/manpage.py b/sphinx/writers/manpage.py index d4fe0a91c25..10c6e7ad722 100644 --- a/sphinx/writers/manpage.py +++ b/sphinx/writers/manpage.py @@ -2,7 +2,8 @@ from __future__ import annotations -from typing import Any, Iterable, cast +from collections.abc import Iterable +from typing import Any, cast from docutils import nodes from docutils.nodes import Element diff --git a/sphinx/writers/texinfo.py b/sphinx/writers/texinfo.py index 24316260edc..08bd0c3794e 100644 --- a/sphinx/writers/texinfo.py +++ b/sphinx/writers/texinfo.py @@ -4,8 +4,9 @@ import re import textwrap +from collections.abc import Iterable, Iterator from os import path -from typing import TYPE_CHECKING, Any, Iterable, Iterator, cast +from typing import TYPE_CHECKING, Any, cast from docutils import nodes, writers from docutils.nodes import Element, Node, Text diff --git a/sphinx/writers/text.py b/sphinx/writers/text.py index 8614ee25ee5..110281c0b4d 100644 --- a/sphinx/writers/text.py +++ b/sphinx/writers/text.py @@ -5,8 +5,9 @@ import os import re import textwrap +from collections.abc import Generator, Iterable from itertools import chain, groupby -from typing import TYPE_CHECKING, Any, Generator, Iterable, cast +from typing import TYPE_CHECKING, Any, cast from docutils import nodes, writers from docutils.nodes import Element, Text diff --git a/tests/roots/test-ext-autodoc/target/TYPE_CHECKING.py b/tests/roots/test-ext-autodoc/target/TYPE_CHECKING.py index df30ab62cc7..85aea3a090e 100644 --- a/tests/roots/test-ext-autodoc/target/TYPE_CHECKING.py +++ b/tests/roots/test-ext-autodoc/target/TYPE_CHECKING.py @@ -1,10 +1,16 @@ from __future__ import annotations +from gettext import NullTranslations from typing import TYPE_CHECKING if TYPE_CHECKING: + from collections.abc import Iterable from io import StringIO class Foo: attr1: StringIO + + +def spam(ham: Iterable[str]) -> tuple[NullTranslations, bool]: + pass diff --git a/tests/test_ext_autodoc.py b/tests/test_ext_autodoc.py index 1023323aa6a..a281b6d46ac 100644 --- a/tests/test_ext_autodoc.py +++ b/tests/test_ext_autodoc.py @@ -217,7 +217,7 @@ class ListSubclass(list): class ExceptionSubclass(Exception): pass - # Exception has no __text_signature__ at least in Python 3.8 + # Exception has no __text_signature__ at least in Python 3.11 if getattr(Exception, '__text_signature__', None) is None: assert formatsig('class', 'C', ExceptionSubclass, None, None) == '' @@ -810,7 +810,7 @@ def test_autodoc_imported_members(app): "imported-members": None, "ignore-module-all": None} actual = do_autodoc(app, 'module', 'target', options) - assert '.. py:function:: function_to_be_imported(app: Sphinx | None) -> str' in actual + assert '.. py:function:: function_to_be_imported(app: ~sphinx.application.Sphinx | None) -> str' in actual @pytest.mark.sphinx('html', testroot='ext-autodoc') @@ -1984,7 +1984,6 @@ def test_autodoc_TypeVar(app): ] -@pytest.mark.skipif(sys.version_info[:2] <= (3, 8), reason='py39+ is required.') @pytest.mark.sphinx('html', testroot='ext-autodoc') def test_autodoc_Annotated(app): options = {"members": None} @@ -2018,7 +2017,11 @@ def test_autodoc_TYPE_CHECKING(app): '', ' .. py:attribute:: Foo.attr1', ' :module: target.TYPE_CHECKING', - ' :type: StringIO', + ' :type: ~_io.StringIO', + '', + '', + '.. py:function:: spam(ham: ~collections.abc.Iterable[str]) -> tuple[gettext.NullTranslations, bool]', + ' :module: target.TYPE_CHECKING', '', ] diff --git a/tests/test_ext_autodoc_autoclass.py b/tests/test_ext_autodoc_autoclass.py index fd4e4165bcf..92c259afa96 100644 --- a/tests/test_ext_autodoc_autoclass.py +++ b/tests/test_ext_autodoc_autoclass.py @@ -6,7 +6,8 @@ from __future__ import annotations -from typing import List, Union +import typing +from typing import Union import pytest @@ -304,7 +305,7 @@ def autodoc_process_bases(app, name, obj, options, bases): assert obj.__name__ == 'Quux' assert options == {'show-inheritance': True, 'members': []} - assert bases == [List[Union[int, float]]] + assert bases == [typing.List[Union[int, float]]] # NoQA: UP006 bases.pop() bases.extend([int, str]) diff --git a/tests/test_util_inspect.py b/tests/test_util_inspect.py index a14c8a15fcd..87a71ba9998 100644 --- a/tests/test_util_inspect.py +++ b/tests/test_util_inspect.py @@ -188,7 +188,7 @@ def test_signature_annotations(): # Generic types with concrete parameters sig = inspect.signature(f1) - assert stringify_signature(sig) == '(x: typing.List[int]) -> typing.List[int]' + assert stringify_signature(sig) == '(x: list[int]) -> typing.List[int]' # TypeVars and generic types with TypeVars sig = inspect.signature(f2) diff --git a/tests/test_util_typing.py b/tests/test_util_typing.py index c156e75ff66..a036cea1459 100644 --- a/tests/test_util_typing.py +++ b/tests/test_util_typing.py @@ -20,7 +20,7 @@ import pytest from sphinx.ext.autodoc import mock -from sphinx.util.typing import restify, stringify_annotation +from sphinx.util.typing import INVALID_BUILTIN_CLASSES, restify, stringify_annotation class MyClass1: @@ -69,6 +69,15 @@ def test_restify(): assert restify('str', "smart") == "str" +def test_is_invalid_builtin_class(): + # if these tests start failing, it means that the __module__ + # of one of these classes has changed, and INVALID_BUILTIN_CLASSES + # in sphinx.util.typing needs to be updated. + assert INVALID_BUILTIN_CLASSES.keys() == {Struct, TracebackType} + assert Struct.__module__ == '_struct' + assert TracebackType.__module__ == 'builtins' + + def test_restify_type_hints_containers(): assert restify(List) == ":py:class:`~typing.List`" assert restify(Dict) == ":py:class:`~typing.Dict`" @@ -177,7 +186,6 @@ def test_restify_type_Literal(): assert restify(Literal[1, "2", "\r"]) == ":py:obj:`~typing.Literal`\\ [1, '2', '\\r']" -@pytest.mark.skipif(sys.version_info[:2] <= (3, 8), reason='python 3.9+ is required.') def test_restify_pep_585(): assert restify(list[str]) == ":py:class:`list`\\ [:py:class:`str`]" # type: ignore assert restify(dict[str, str]) == (":py:class:`dict`\\ " # type: ignore @@ -283,7 +291,6 @@ def test_stringify_type_hints_containers(): assert stringify_annotation(Generator[None, None, None], "smart") == "~typing.Generator[None, None, None]" -@pytest.mark.skipif(sys.version_info[:2] <= (3, 8), reason='python 3.9+ is required.') def test_stringify_type_hints_pep_585(): assert stringify_annotation(list[int], 'fully-qualified-except-typing') == "list[int]" assert stringify_annotation(list[int], "smart") == "list[int]" @@ -310,7 +317,6 @@ def test_stringify_type_hints_pep_585(): assert stringify_annotation(type[int], "smart") == "type[int]" -@pytest.mark.skipif(sys.version_info[:2] <= (3, 8), reason='python 3.9+ is required.') def test_stringify_Annotated(): from typing import Annotated # type: ignore assert stringify_annotation(Annotated[str, "foo", "bar"], 'fully-qualified-except-typing') == "str" diff --git a/tests/typing_test_data.py b/tests/typing_test_data.py index 26f619fdcf1..b211aad8029 100644 --- a/tests/typing_test_data.py +++ b/tests/typing_test_data.py @@ -7,7 +7,7 @@ def f0(x: int, y: Integral) -> None: pass -def f1(x: List[int]) -> List[int]: +def f1(x: list[int]) -> List[int]: pass diff --git a/tox.ini b/tox.ini index 512aa5f74e5..a3dc5621123 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] minversion = 2.4.0 -envlist = py{38,39,310,311,312} +envlist = py{39,310,311,312} isolated_build = True [testenv] @@ -17,7 +17,7 @@ passenv = EPUBCHECK_PATH TERM description = - py{38,39,310,311,312}: Run unit tests against {envname}. + py{39,310,311,312}: Run unit tests against {envname}. extras = test setenv =