diff --git a/sphinx/builders/gettext.py b/sphinx/builders/gettext.py index 35abf1fd7..c669aa5d1 100644 --- a/sphinx/builders/gettext.py +++ b/sphinx/builders/gettext.py @@ -27,7 +27,7 @@ from sphinx.util.template import SphinxRenderer if TYPE_CHECKING: import os - from collections.abc import Generator, Iterable + from collections.abc import Iterable, Iterator from docutils.nodes import Element @@ -69,7 +69,7 @@ class Catalog: line = -1 self.metadata[msg].append((origin.source, line, origin.uid)) # type: ignore[arg-type] - def __iter__(self) -> Generator[Message, None, None]: + def __iter__(self) -> Iterator[Message]: for message in self.messages: positions = sorted({(source, line) for source, line, uuid in self.metadata[message]}) diff --git a/sphinx/builders/linkcheck.py b/sphinx/builders/linkcheck.py index 89a3543e8..3cec33fe3 100644 --- a/sphinx/builders/linkcheck.py +++ b/sphinx/builders/linkcheck.py @@ -29,7 +29,7 @@ from sphinx.util.http_date import rfc1123_to_epoch from sphinx.util.nodes import get_node_line if TYPE_CHECKING: - from collections.abc import Generator, Iterator + from collections.abc import Iterator from typing import Any, Callable from requests import Response @@ -224,7 +224,7 @@ class HyperlinkAvailabilityChecker: self.to_ignore: list[re.Pattern[str]] = list(map(re.compile, self.config.linkcheck_ignore)) - def check(self, hyperlinks: dict[str, Hyperlink]) -> Generator[CheckResult, None, None]: + def check(self, hyperlinks: dict[str, Hyperlink]) -> Iterator[CheckResult]: self.invoke_threads() total_links = 0 diff --git a/sphinx/domains/c/_symbol.py b/sphinx/domains/c/_symbol.py index 8547d6f28..5205204c4 100644 --- a/sphinx/domains/c/_symbol.py +++ b/sphinx/domains/c/_symbol.py @@ -11,7 +11,7 @@ from sphinx.locale import __ from sphinx.util import logging if TYPE_CHECKING: - from collections.abc import Generator, Iterator + from collections.abc import Iterator from typing_extensions import Self @@ -248,7 +248,7 @@ class Symbol: Symbol.debug_print("recurseInAnon: ", recurseInAnon) Symbol.debug_print("searchInSiblings: ", searchInSiblings) - def candidates() -> Generator[Symbol, None, None]: + def candidates() -> Iterator[Symbol]: s = self if Symbol.debug_lookup: Symbol.debug_print("searching in self:") diff --git a/sphinx/domains/cpp/_symbol.py b/sphinx/domains/cpp/_symbol.py index d5dfbb89a..4caa43070 100644 --- a/sphinx/domains/cpp/_symbol.py +++ b/sphinx/domains/cpp/_symbol.py @@ -17,7 +17,7 @@ from sphinx.locale import __ from sphinx.util import logging if TYPE_CHECKING: - from collections.abc import Generator, Iterator + from collections.abc import Iterator from sphinx.environment import BuildEnvironment @@ -237,7 +237,7 @@ class Symbol: yield from sChild.get_all_symbols() @property - def children_recurse_anon(self) -> Generator[Symbol, None, None]: + def children_recurse_anon(self) -> Iterator[Symbol]: for c in self._children: yield c if not c.identOrOp.is_anon(): @@ -347,7 +347,7 @@ class Symbol: return False return True - def candidates() -> Generator[Symbol, None, None]: + def candidates() -> Iterator[Symbol]: s = self if Symbol.debug_lookup: Symbol.debug_print("searching in self:") diff --git a/sphinx/environment/__init__.py b/sphinx/environment/__init__.py index 53616fc4b..e145c92d5 100644 --- a/sphinx/environment/__init__.py +++ b/sphinx/environment/__init__.py @@ -23,7 +23,7 @@ from sphinx.util.nodes import is_translatable from sphinx.util.osutil import canon_path, os_path if TYPE_CHECKING: - from collections.abc import Generator, Iterator + from collections.abc import Iterator from pathlib import Path from docutils import nodes @@ -524,7 +524,7 @@ class BuildEnvironment: return added, changed, removed - def check_dependents(self, app: Sphinx, already: set[str]) -> Generator[str, None, None]: + def check_dependents(self, app: Sphinx, already: set[str]) -> Iterator[str]: to_rewrite: list[str] = [] for docnames in self.events.emit('env-get-updated', self): to_rewrite.extend(docnames) diff --git a/sphinx/ext/apidoc.py b/sphinx/ext/apidoc.py index aa625ae3b..b2e2291be 100644 --- a/sphinx/ext/apidoc.py +++ b/sphinx/ext/apidoc.py @@ -32,7 +32,7 @@ from sphinx.util.osutil import FileAvoidWrite, ensuredir from sphinx.util.template import ReSTRenderer if TYPE_CHECKING: - from collections.abc import Generator, Sequence + from collections.abc import Iterator, Sequence logger = logging.getLogger(__name__) @@ -214,7 +214,7 @@ def is_skipped_module(filename: str, opts: Any, _excludes: Sequence[re.Pattern[s def walk(rootpath: str, excludes: Sequence[re.Pattern[str]], opts: Any, - ) -> Generator[tuple[str, list[str], list[str]], None, None]: + ) -> Iterator[tuple[str, list[str], list[str]]]: """Walk through the directory and list files and subdirectories up.""" followlinks = getattr(opts, 'followlinks', False) includeprivate = getattr(opts, 'includeprivate', False) diff --git a/sphinx/ext/autodoc/importer.py b/sphinx/ext/autodoc/importer.py index 60457c530..784fa71f6 100644 --- a/sphinx/ext/autodoc/importer.py +++ b/sphinx/ext/autodoc/importer.py @@ -25,7 +25,7 @@ from sphinx.util.inspect import ( ) if TYPE_CHECKING: - from collections.abc import Callable, Generator, Mapping + from collections.abc import Callable, Iterator, Mapping from types import ModuleType from typing import Any @@ -38,7 +38,7 @@ def _filter_enum_dict( enum_class: type[Enum], attrgetter: Callable[[Any, str, Any], Any], enum_class_dict: Mapping[str, object], -) -> Generator[tuple[str, type, Any], None, None]: +) -> Iterator[tuple[str, type, Any]]: """Find the attributes to document of an enumeration class. The output consists of triplets ``(attribute name, defining class, value)`` diff --git a/sphinx/ext/autodoc/mock.py b/sphinx/ext/autodoc/mock.py index 4036bd588..c2ab0feb4 100644 --- a/sphinx/ext/autodoc/mock.py +++ b/sphinx/ext/autodoc/mock.py @@ -14,7 +14,7 @@ from sphinx.util import logging from sphinx.util.inspect import isboundmethod, safe_getattr if TYPE_CHECKING: - from collections.abc import Generator, Iterator, Sequence + from collections.abc import Iterator, Sequence logger = logging.getLogger(__name__) @@ -137,7 +137,7 @@ class MockFinder(MetaPathFinder): @contextlib.contextmanager -def mock(modnames: list[str]) -> Generator[None, None, None]: +def mock(modnames: list[str]) -> Iterator[None]: """Insert mock modules during context:: with mock(['target.module.name']): diff --git a/sphinx/ext/viewcode.py b/sphinx/ext/viewcode.py index 5cd4b5d9b..5df6d50b9 100644 --- a/sphinx/ext/viewcode.py +++ b/sphinx/ext/viewcode.py @@ -22,7 +22,7 @@ from sphinx.util.display import status_iterator from sphinx.util.nodes import make_refnode if TYPE_CHECKING: - from collections.abc import Generator, Iterable + from collections.abc import Iterable, Iterator from sphinx.application import Sphinx from sphinx.builders import Builder @@ -239,7 +239,7 @@ def should_generate_module_page(app: Sphinx, modname: str) -> bool: return True -def collect_pages(app: Sphinx) -> Generator[tuple[str, dict[str, Any], str], None, None]: +def collect_pages(app: Sphinx) -> Iterator[tuple[str, dict[str, Any], str]]: env = app.builder.env if not hasattr(env, '_viewcode_modules'): return diff --git a/sphinx/testing/fixtures.py b/sphinx/testing/fixtures.py index b48221fc2..95cf177c4 100644 --- a/sphinx/testing/fixtures.py +++ b/sphinx/testing/fixtures.py @@ -14,7 +14,7 @@ import pytest from sphinx.testing.util import SphinxTestApp, SphinxTestAppWrapperForSkipBuilding if TYPE_CHECKING: - from collections.abc import Callable, Generator + from collections.abc import Callable, Iterator from pathlib import Path from typing import Any @@ -147,7 +147,7 @@ def app( app_params: tuple[dict, dict], make_app: Callable, shared_result: SharedResult, -) -> Generator[SphinxTestApp, None, None]: +) -> Iterator[SphinxTestApp]: """ Provides the 'sphinx.application.Sphinx' object """ @@ -183,7 +183,7 @@ def warning(app: SphinxTestApp) -> StringIO: @pytest.fixture() -def make_app(test_params: dict, monkeypatch: Any) -> Generator[Callable, None, None]: +def make_app(test_params: dict, monkeypatch: Any) -> Iterator[Callable]: """ Provides make_app function to initialize SphinxTestApp instance. if you want to initialize 'app' in your test function. please use this @@ -289,7 +289,7 @@ def sphinx_test_tempdir(tmp_path_factory: Any) -> Path: @pytest.fixture() -def rollback_sysmodules() -> Generator[None, None, None]: # NoQA: PT004 +def rollback_sysmodules() -> Iterator[None]: # NoQA: PT004 """ Rollback sys.modules to its value before testing to unload modules during tests. diff --git a/sphinx/transforms/__init__.py b/sphinx/transforms/__init__.py index f8923396b..d6582f4cb 100644 --- a/sphinx/transforms/__init__.py +++ b/sphinx/transforms/__init__.py @@ -21,7 +21,7 @@ from sphinx.util.i18n import format_date from sphinx.util.nodes import apply_source_workaround, is_smartquotable if TYPE_CHECKING: - from collections.abc import Generator + from collections.abc import Iterator from docutils.nodes import Node, Text @@ -376,7 +376,7 @@ class SphinxSmartQuotes(SmartQuotes, SphinxTransform): for tag in normalize_language_tag(language) ) - def get_tokens(self, txtnodes: list[Text]) -> Generator[tuple[str, str], None, None]: + def get_tokens(self, txtnodes: list[Text]) -> Iterator[tuple[str, str]]: # A generator that yields ``(texttype, nodetext)`` tuples for a list # of "Text" nodes (interface to ``smartquotes.educate_tokens()``). for txtnode in txtnodes: diff --git a/sphinx/util/docutils.py b/sphinx/util/docutils.py index 62a6553bd..6a24d2e11 100644 --- a/sphinx/util/docutils.py +++ b/sphinx/util/docutils.py @@ -27,7 +27,7 @@ logger = logging.getLogger(__name__) report_re = re.compile('^(.+?:(?:\\d+)?): \\((DEBUG|INFO|WARNING|ERROR|SEVERE)/(\\d+)?\\) ') if TYPE_CHECKING: - from collections.abc import Generator + from collections.abc import Iterator from types import ModuleType from docutils.frontend import Values @@ -43,7 +43,7 @@ additional_nodes: set[type[Element]] = set() @contextmanager -def docutils_namespace() -> Generator[None, None, None]: +def docutils_namespace() -> Iterator[None]: """Create namespace for reST parsers.""" try: _directives = copy(directives._directives) # type: ignore[attr-defined] @@ -121,7 +121,7 @@ def unregister_node(node: type[Element]) -> None: @contextmanager -def patched_get_language() -> Generator[None, None, None]: +def patched_get_language() -> Iterator[None]: """Patch docutils.languages.get_language() temporarily. This ignores the second argument ``reporter`` to suppress warnings. @@ -141,7 +141,7 @@ def patched_get_language() -> Generator[None, None, None]: @contextmanager -def patched_rst_get_language() -> Generator[None, None, None]: +def patched_rst_get_language() -> Iterator[None]: """Patch docutils.parsers.rst.languages.get_language(). Starting from docutils 0.17, get_language() in ``rst.languages`` also has a reporter, which needs to be disabled temporarily. @@ -165,7 +165,7 @@ def patched_rst_get_language() -> Generator[None, None, None]: @contextmanager -def using_user_docutils_conf(confdir: str | None) -> Generator[None, None, None]: +def using_user_docutils_conf(confdir: str | None) -> Iterator[None]: """Let docutils know the location of ``docutils.conf`` for Sphinx.""" try: docutilsconfig = os.environ.get('DOCUTILSCONFIG', None) @@ -181,7 +181,7 @@ def using_user_docutils_conf(confdir: str | None) -> Generator[None, None, None] @contextmanager -def du19_footnotes() -> Generator[None, None, None]: +def du19_footnotes() -> Iterator[None]: def visit_footnote(self: HTMLTranslator, node: Element) -> None: label_style = self.settings.footnote_references if not isinstance(node.previous_sibling(), type(node)): @@ -214,7 +214,7 @@ def du19_footnotes() -> Generator[None, None, None]: @contextmanager -def patch_docutils(confdir: str | None = None) -> Generator[None, None, None]: +def patch_docutils(confdir: str | None = None) -> Iterator[None]: """Patch to docutils temporarily.""" with patched_get_language(), \ patched_rst_get_language(), \ @@ -359,7 +359,7 @@ class NullReporter(Reporter): @contextmanager -def switch_source_input(state: State, content: StringList) -> Generator[None, None, None]: +def switch_source_input(state: State, content: StringList) -> Iterator[None]: """Switch current source input of state temporarily.""" try: # remember the original ``get_source_and_line()`` method diff --git a/sphinx/util/i18n.py b/sphinx/util/i18n.py index ae512bd36..c14e3f099 100644 --- a/sphinx/util/i18n.py +++ b/sphinx/util/i18n.py @@ -19,7 +19,7 @@ from sphinx.util.osutil import SEP, canon_path, relpath if TYPE_CHECKING: import datetime as dt - from collections.abc import Generator + from collections.abc import Iterator from typing import Protocol, Union from babel.core import Locale @@ -112,7 +112,7 @@ class CatalogRepository: self.encoding = encoding @property - def locale_dirs(self) -> Generator[str, None, None]: + def locale_dirs(self) -> Iterator[str]: if not self.language: return @@ -125,7 +125,7 @@ class CatalogRepository: logger.verbose(__('locale_dir %s does not exist'), locale_path) @property - def pofiles(self) -> Generator[tuple[str, str], None, None]: + def pofiles(self) -> Iterator[tuple[str, str]]: for locale_dir in self.locale_dirs: basedir = path.join(locale_dir, self.language, 'LC_MESSAGES') for root, dirnames, filenames in os.walk(basedir): @@ -139,7 +139,7 @@ class CatalogRepository: yield basedir, relpath(fullpath, basedir) @property - def catalogs(self) -> Generator[CatalogInfo, None, None]: + def catalogs(self) -> Iterator[CatalogInfo]: for basedir, filename in self.pofiles: domain = canon_path(path.splitext(filename)[0]) yield CatalogInfo(basedir, domain, self.encoding) diff --git a/sphinx/util/logging.py b/sphinx/util/logging.py index c0a8c08b0..e107a568d 100644 --- a/sphinx/util/logging.py +++ b/sphinx/util/logging.py @@ -16,7 +16,7 @@ from sphinx.util.console import colorize from sphinx.util.osutil import abspath if TYPE_CHECKING: - from collections.abc import Generator + from collections.abc import Iterator from docutils.nodes import Node @@ -246,7 +246,7 @@ class MemoryHandler(logging.handlers.BufferingHandler): @contextmanager -def pending_warnings() -> Generator[logging.Handler, None, None]: +def pending_warnings() -> Iterator[logging.Handler]: """Context manager to postpone logging warnings temporarily. Similar to :func:`pending_logging`. @@ -274,7 +274,7 @@ def pending_warnings() -> Generator[logging.Handler, None, None]: @contextmanager -def suppress_logging() -> Generator[MemoryHandler, None, None]: +def suppress_logging() -> Iterator[MemoryHandler]: """Context manager to suppress logging all logs temporarily. For example:: @@ -303,7 +303,7 @@ def suppress_logging() -> Generator[MemoryHandler, None, None]: @contextmanager -def pending_logging() -> Generator[MemoryHandler, None, None]: +def pending_logging() -> Iterator[MemoryHandler]: """Context manager to postpone logging all logs temporarily. For example:: @@ -323,7 +323,7 @@ def pending_logging() -> Generator[MemoryHandler, None, None]: @contextmanager -def skip_warningiserror(skip: bool = True) -> Generator[None, None, None]: +def skip_warningiserror(skip: bool = True) -> Iterator[None]: """Context manager to skip WarningIsErrorFilter temporarily.""" logger = logging.getLogger(NAMESPACE) @@ -343,7 +343,7 @@ def skip_warningiserror(skip: bool = True) -> Generator[None, None, None]: @contextmanager -def prefixed_warnings(prefix: str) -> Generator[None, None, None]: +def prefixed_warnings(prefix: str) -> Iterator[None]: """Context manager to prepend prefix to all warning log records temporarily. For example:: @@ -393,7 +393,7 @@ class LogCollector: self.logs: list[logging.LogRecord] = [] @contextmanager - def collect(self) -> Generator[None, None, None]: + def collect(self) -> Iterator[None]: with pending_logging() as memhandler: yield diff --git a/sphinx/util/rst.py b/sphinx/util/rst.py index 9d0e83071..4e8fdee2e 100644 --- a/sphinx/util/rst.py +++ b/sphinx/util/rst.py @@ -18,7 +18,7 @@ from sphinx.locale import __ from sphinx.util import docutils, logging if TYPE_CHECKING: - from collections.abc import Generator + from collections.abc import Iterator from docutils.statemachine import StringList @@ -61,7 +61,7 @@ def heading(env: Environment, text: str, level: int = 1) -> str: @contextmanager -def default_role(docname: str, name: str) -> Generator[None, None, None]: +def default_role(docname: str, name: str) -> Iterator[None]: if name: dummy_reporter = Reporter('', 4, 4) role_fn, _ = roles.role(name, english, 0, dummy_reporter) diff --git a/sphinx/writers/text.py b/sphinx/writers/text.py index ce3e2c915..d2dd20836 100644 --- a/sphinx/writers/text.py +++ b/sphinx/writers/text.py @@ -5,7 +5,7 @@ import math import os import re import textwrap -from collections.abc import Generator, Iterable, Sequence +from collections.abc import Iterable, Iterator, Sequence from itertools import chain, groupby from typing import TYPE_CHECKING, Any, cast @@ -166,7 +166,7 @@ class Table: return width + (cell.colspan - 1) * 3 @property - def cells(self) -> Generator[Cell, None, None]: + def cells(self) -> Iterator[Cell]: seen: set[Cell] = set() for line in self.lines: for cell in line: diff --git a/tests/conftest.py b/tests/conftest.py index 6d5dbd2e9..1c8d5250e 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -14,7 +14,7 @@ import sphinx.pycode from sphinx.testing.util import _clean_up_global_state if TYPE_CHECKING: - from collections.abc import Generator + from collections.abc import Iterator def _init_console( @@ -52,7 +52,7 @@ def pytest_report_header(config: pytest.Config) -> str: @pytest.fixture(autouse=True) -def _cleanup_docutils() -> Generator[None, None, None]: +def _cleanup_docutils() -> Iterator[None]: saved_path = sys.path yield # run the test sys.path[:] = saved_path diff --git a/tests/test_addnodes.py b/tests/test_addnodes.py index a941a6fdd..aa993433f 100644 --- a/tests/test_addnodes.py +++ b/tests/test_addnodes.py @@ -9,11 +9,11 @@ import pytest from sphinx import addnodes if TYPE_CHECKING: - from collections.abc import Generator + from collections.abc import Iterator @pytest.fixture() -def sig_elements() -> Generator[set[type[addnodes.desc_sig_element]], None, None]: +def sig_elements() -> Iterator[set[type[addnodes.desc_sig_element]]]: """Fixture returning the current ``addnodes.SIG_ELEMENTS`` set.""" original = addnodes.SIG_ELEMENTS.copy() # safe copy of the current nodes yield {*addnodes.SIG_ELEMENTS} # temporary value to use during tests diff --git a/tests/test_builders/conftest.py b/tests/test_builders/conftest.py index 1a4c71535..1203d5dc5 100644 --- a/tests/test_builders/conftest.py +++ b/tests/test_builders/conftest.py @@ -7,7 +7,7 @@ import pytest from sphinx.testing.util import etree_parse if TYPE_CHECKING: - from collections.abc import Callable, Generator + from collections.abc import Callable, Iterator from pathlib import Path from xml.etree.ElementTree import ElementTree @@ -23,6 +23,6 @@ def _parse(path: Path) -> ElementTree: @pytest.fixture(scope='package') -def cached_etree_parse() -> Generator[Callable[[Path], ElementTree], None, None]: +def cached_etree_parse() -> Iterator[Callable[[Path], ElementTree]]: yield _parse _etree_cache.clear() diff --git a/tests/test_util/test_util_typing.py b/tests/test_util/test_util_typing.py index 2e90d7168..619fc3442 100644 --- a/tests/test_util/test_util_typing.py +++ b/tests/test_util/test_util_typing.py @@ -32,6 +32,7 @@ from typing import ( Callable, Dict, Generator, + Iterator, List, NewType, Optional, @@ -175,6 +176,8 @@ def test_restify_type_hints_containers(): assert restify(Generator[None, None, None]) == (":py:class:`~typing.Generator`\\ " "[:py:obj:`None`, :py:obj:`None`, " ":py:obj:`None`]") + assert restify(Iterator[None]) == (":py:class:`~typing.Iterator`\\ " + "[:py:obj:`None`]") def test_restify_type_hints_Callable(): @@ -389,6 +392,10 @@ def test_stringify_type_hints_containers(): assert stringify_annotation(Generator[None, None, None], "fully-qualified") == "typing.Generator[None, None, None]" assert stringify_annotation(Generator[None, None, None], "smart") == "~typing.Generator[None, None, None]" + assert stringify_annotation(Iterator[None], 'fully-qualified-except-typing') == "Iterator[None]" + assert stringify_annotation(Iterator[None], "fully-qualified") == "typing.Iterator[None]" + assert stringify_annotation(Iterator[None], "smart") == "~typing.Iterator[None]" + def test_stringify_type_hints_pep_585(): assert stringify_annotation(list[int], 'fully-qualified-except-typing') == "list[int]"