diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 1ed8f87a..ecac0386 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -215,6 +215,7 @@ Again, the most checks can be performed by `tox` command, though some additional
* It is allowed to change web API to add new fields or remove optional ones. However, in case of model changes, new API version must be introduced.
* On the other hand, it is allowed to change method signatures, however, it is recommended to add new parameters as optional if possible. Deprecated API can be dropped during major release.
* Enumerations (`Enum` classes) are allowed and recommended. However, it is recommended to use `StrEnum` class if there are from/to string conversions and `IntEnum` otherwise.
+* `Generator` return type is not allowed. Generator functions must return generic `Iterator` object. Documentation should be described as `Yields`, however, because of pylint checks. Unfortunately, `Iterable` return type is not available for generators also, because of specific `contextlib.contextmanager` case.
### Other checks
diff --git a/src/ahriman/application/handlers/versions.py b/src/ahriman/application/handlers/versions.py
index 6b60606a..135f190f 100644
--- a/src/ahriman/application/handlers/versions.py
+++ b/src/ahriman/application/handlers/versions.py
@@ -21,7 +21,7 @@ import argparse
import re
import sys
-from collections.abc import Generator
+from collections.abc import Iterator
from importlib import metadata
from typing import ClassVar
@@ -77,7 +77,7 @@ class Versions(Handler):
return parser
@staticmethod
- def package_dependencies(root: str) -> Generator[tuple[str, str], None, None]:
+ def package_dependencies(root: str) -> Iterator[tuple[str, str]]:
"""
extract list of ahriman package dependencies installed into system with their versions
@@ -87,7 +87,7 @@ class Versions(Handler):
Yields:
tuple[str, str]: map of installed dependency to its version
"""
- def dependencies_by_key(key: str) -> Generator[str, None, None]:
+ def dependencies_by_key(key: str) -> Iterator[str]:
# in importlib it returns requires in the following format
# ["pytest (>=3.0.0) ; extra == 'test'", "pytest-cov ; extra == 'test'"]
try:
diff --git a/src/ahriman/application/handlers/web.py b/src/ahriman/application/handlers/web.py
index 21863158..7a0482da 100644
--- a/src/ahriman/application/handlers/web.py
+++ b/src/ahriman/application/handlers/web.py
@@ -19,7 +19,7 @@
#
import argparse
-from collections.abc import Generator
+from collections.abc import Iterator
from pathlib import Path
from ahriman.application.handlers.handler import Handler, SubParserAction
@@ -86,7 +86,7 @@ class Web(Handler):
return parser
@staticmethod
- def extract_arguments(args: argparse.Namespace, configuration: Configuration) -> Generator[str, None, None]:
+ def extract_arguments(args: argparse.Namespace, configuration: Configuration) -> Iterator[str]:
"""
extract list of arguments used for current command, except for command specific ones
diff --git a/src/ahriman/core/alpm/pacman.py b/src/ahriman/core/alpm/pacman.py
index 4fbbd8a5..acf2ec77 100644
--- a/src/ahriman/core/alpm/pacman.py
+++ b/src/ahriman/core/alpm/pacman.py
@@ -21,7 +21,7 @@ import itertools
import shutil
import tarfile
-from collections.abc import Generator, Iterable
+from collections.abc import Iterable, Iterator
from functools import cached_property
from pathlib import Path
from pyalpm import DB, Handle, Package, SIG_DATABASE_OPTIONAL, SIG_PACKAGE_OPTIONAL # type: ignore[import-not-found]
@@ -188,7 +188,7 @@ class Pacman(LazyLogging):
Returns:
dict[str, set[str]]: map of package name to its list of files
"""
- def extract(tar: tarfile.TarFile, versions: dict[str, str]) -> Generator[tuple[str, set[str]], None, None]:
+ def extract(tar: tarfile.TarFile, versions: dict[str, str]) -> Iterator[tuple[str, set[str]]]:
for package_name, version in versions.items():
path = Path(f"{package_name}-{version}") / "files"
try:
@@ -223,7 +223,7 @@ class Pacman(LazyLogging):
return result
- def package(self, package_name: str) -> Generator[Package, None, None]:
+ def package(self, package_name: str) -> Iterator[Package]:
"""
retrieve list of the packages from the repository by name
@@ -256,7 +256,7 @@ class Pacman(LazyLogging):
return result
- def provided_by(self, package_name: str) -> Generator[Package, None, None]:
+ def provided_by(self, package_name: str) -> Iterator[Package]:
"""
search through databases and emit packages which provides the ``package_name``
diff --git a/src/ahriman/core/alpm/pkgbuild_parser.py b/src/ahriman/core/alpm/pkgbuild_parser.py
index b5b3e157..ded0ae69 100644
--- a/src/ahriman/core/alpm/pkgbuild_parser.py
+++ b/src/ahriman/core/alpm/pkgbuild_parser.py
@@ -21,7 +21,7 @@ import itertools
import re
import shlex
-from collections.abc import Generator
+from collections.abc import Iterator
from enum import StrEnum
from typing import IO
@@ -209,7 +209,7 @@ class PkgbuildParser(shlex.shlex):
Raises:
PkgbuildParserError: if array is not closed
"""
- def extract() -> Generator[str, None, None]:
+ def extract() -> Iterator[str]:
while token := self.get_token():
match token:
case _ if self._is_escaped():
@@ -276,7 +276,7 @@ class PkgbuildParser(shlex.shlex):
return content
- def _parse_token(self, token: str) -> Generator[PkgbuildPatch, None, None]:
+ def _parse_token(self, token: str) -> Iterator[PkgbuildPatch]:
"""
parse single token to the PKGBUILD field
@@ -360,7 +360,7 @@ class PkgbuildParser(shlex.shlex):
raise PkgbuildParserError("reached starting position, no valid symbols found")
- def parse(self) -> Generator[PkgbuildPatch, None, None]:
+ def parse(self) -> Iterator[PkgbuildPatch]:
"""
parse source stream and yield parsed entries
diff --git a/src/ahriman/core/build_tools/sources.py b/src/ahriman/core/build_tools/sources.py
index 7bba7ff7..8808497d 100644
--- a/src/ahriman/core/build_tools/sources.py
+++ b/src/ahriman/core/build_tools/sources.py
@@ -19,7 +19,7 @@
#
import shutil
-from collections.abc import Generator
+from collections.abc import Iterator
from pathlib import Path
from typing import ClassVar
@@ -347,7 +347,7 @@ class Sources(LazyLogging):
"""
gitconfig = gitconfig or {}
- def configuration_flags() -> Generator[str, None, None]:
+ def configuration_flags() -> Iterator[str]:
for option, value in (self.GITCONFIG | gitconfig).items():
yield "-c"
yield f"{option}=\"{value}\""
diff --git a/src/ahriman/core/build_tools/task.py b/src/ahriman/core/build_tools/task.py
index 2809635b..b6f8d084 100644
--- a/src/ahriman/core/build_tools/task.py
+++ b/src/ahriman/core/build_tools/task.py
@@ -17,7 +17,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-from collections.abc import Generator
+from collections.abc import Iterator
from pathlib import Path
from ahriman.core.build_tools.sources import Sources
@@ -77,7 +77,7 @@ class Task(LazyLogging):
Returns:
list[Path]: list of file paths which looks like freshly generated archives
"""
- def files() -> Generator[Path, None, None]:
+ def files() -> Iterator[Path]:
for filepath in sources_dir.iterdir():
if filepath in source_files:
continue # skip files which were already there
diff --git a/src/ahriman/core/configuration/shell_interpolator.py b/src/ahriman/core/configuration/shell_interpolator.py
index 5d99c4c0..df43c7b6 100644
--- a/src/ahriman/core/configuration/shell_interpolator.py
+++ b/src/ahriman/core/configuration/shell_interpolator.py
@@ -21,7 +21,7 @@ import configparser
import os
import sys
-from collections.abc import Generator, Mapping, MutableMapping
+from collections.abc import Iterator, Mapping, MutableMapping
from string import Template
from typing import Any, ClassVar
@@ -37,7 +37,7 @@ class ShellInterpolator(configparser.Interpolation):
@staticmethod
def _extract_variables(parser: MutableMapping[str, Mapping[str, str]], value: str,
- defaults: Mapping[str, str]) -> Generator[tuple[str, str], None, None]:
+ defaults: Mapping[str, str]) -> Iterator[tuple[str, str]]:
"""
extract keys and values (if available) from the configuration. In case if a key is not available, it will be
silently skipped from the result
@@ -50,7 +50,7 @@ class ShellInterpolator(configparser.Interpolation):
Yields:
tuple[str, str]: variable name used for substitution and its value
"""
- def identifiers() -> Generator[tuple[str | None, str], None, None]:
+ def identifiers() -> Iterator[tuple[str | None, str]]:
# extract all found identifiers and parse them
for identifier in ShellTemplate(value).get_identifiers():
match identifier.rsplit(":", maxsplit=1):
diff --git a/src/ahriman/core/configuration/shell_template.py b/src/ahriman/core/configuration/shell_template.py
index e2f82ea7..12f6e6e6 100644
--- a/src/ahriman/core/configuration/shell_template.py
+++ b/src/ahriman/core/configuration/shell_template.py
@@ -20,7 +20,7 @@
import fnmatch
import re
-from collections.abc import Generator, Mapping
+from collections.abc import Iterator, Mapping
from string import Template
@@ -132,7 +132,7 @@ class ShellTemplate(Template):
(self._REPLACE, self._replace, "/"),
)
- def generator(variables: dict[str, str]) -> Generator[tuple[str, str], None, None]:
+ def generator(variables: dict[str, str]) -> Iterator[tuple[str, str]]:
for identifier in self.get_identifiers():
for regex, function, greediness in substitutions:
if m := regex.match(identifier):
diff --git a/src/ahriman/core/database/operations/package_operations.py b/src/ahriman/core/database/operations/package_operations.py
index bb004e51..3b806eb2 100644
--- a/src/ahriman/core/database/operations/package_operations.py
+++ b/src/ahriman/core/database/operations/package_operations.py
@@ -17,7 +17,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-from collections.abc import Generator, Iterable
+from collections.abc import Iterable, Iterator
from sqlite3 import Connection
from ahriman.core.database.operations.operations import Operations
@@ -263,7 +263,7 @@ class PackageOperations(Operations):
"""
repository_id = repository_id or self._repository_id
- def run(connection: Connection) -> Generator[tuple[Package, BuildStatus], None, None]:
+ def run(connection: Connection) -> Iterator[tuple[Package, BuildStatus]]:
packages = self._packages_get_select_package_bases(connection, repository_id)
statuses = self._packages_get_select_statuses(connection, repository_id)
per_package_base = self._packages_get_select_packages(connection, packages, repository_id)
diff --git a/src/ahriman/core/formatters/validation_printer.py b/src/ahriman/core/formatters/validation_printer.py
index bd17a62d..ce23a859 100644
--- a/src/ahriman/core/formatters/validation_printer.py
+++ b/src/ahriman/core/formatters/validation_printer.py
@@ -17,7 +17,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-from collections.abc import Generator
+from collections.abc import Iterator
from typing import Any
from ahriman.core.formatters.string_printer import StringPrinter
@@ -44,8 +44,7 @@ class ValidationPrinter(StringPrinter):
self.errors = errors
@staticmethod
- def get_error_messages(node: str, errors: list[str | dict[str, Any]],
- current_level: int = 1) -> Generator[Property, None, None]:
+ def get_error_messages(node: str, errors: list[str | dict[str, Any]], current_level: int = 1) -> Iterator[Property]:
"""
extract default error message from cerberus class
diff --git a/src/ahriman/core/gitremote/remote_push.py b/src/ahriman/core/gitremote/remote_push.py
index 60c84338..90a70240 100644
--- a/src/ahriman/core/gitremote/remote_push.py
+++ b/src/ahriman/core/gitremote/remote_push.py
@@ -19,7 +19,7 @@
#
import shutil
-from collections.abc import Generator
+from collections.abc import Iterator
from pathlib import Path
from tempfile import TemporaryDirectory
@@ -96,7 +96,7 @@ class RemotePush(LazyLogging):
# ...and finally return path to the copied directory
return package.base
- def packages_update(self, result: Result, target_dir: Path) -> Generator[str, None, None]:
+ def packages_update(self, result: Result, target_dir: Path) -> Iterator[str]:
"""
update all packages from the build result
diff --git a/src/ahriman/core/log/lazy_logging.py b/src/ahriman/core/log/lazy_logging.py
index 1fe86e31..2dc930cc 100644
--- a/src/ahriman/core/log/lazy_logging.py
+++ b/src/ahriman/core/log/lazy_logging.py
@@ -20,7 +20,7 @@
import contextlib
import logging
-from collections.abc import Generator
+from collections.abc import Iterator
from functools import cached_property
from typing import Any
@@ -80,7 +80,7 @@ class LazyLogging:
logging.setLogRecordFactory(package_record_factory)
@contextlib.contextmanager
- def in_package_context(self, package_base: str, version: str | None) -> Generator[None, None, None]:
+ def in_package_context(self, package_base: str, version: str | None) -> Iterator[None]:
"""
execute function while setting package context
diff --git a/src/ahriman/core/module_loader.py b/src/ahriman/core/module_loader.py
index 20257cc3..e45aee62 100644
--- a/src/ahriman/core/module_loader.py
+++ b/src/ahriman/core/module_loader.py
@@ -19,7 +19,7 @@
#
import inspect
-from collections.abc import Generator
+from collections.abc import Iterator
from importlib import import_module
from pathlib import Path
from pkgutil import ModuleInfo, walk_packages
@@ -33,7 +33,7 @@ __all__ = ["implementations"]
T = TypeVar("T")
-def _modules(module_root: Path, prefix: str) -> Generator[ModuleInfo, None, None]:
+def _modules(module_root: Path, prefix: str) -> Iterator[ModuleInfo]:
"""
extract available modules from package
@@ -52,7 +52,7 @@ def _modules(module_root: Path, prefix: str) -> Generator[ModuleInfo, None, None
yield module_info
-def implementations(root_module: ModuleType, base_class: type[T]) -> Generator[type[T], None, None]:
+def implementations(root_module: ModuleType, base_class: type[T]) -> Iterator[type[T]]:
"""
extract implementations of the ``base_class`` from the module
diff --git a/src/ahriman/core/repository/event_logger.py b/src/ahriman/core/repository/event_logger.py
index b1d38562..889a10dc 100644
--- a/src/ahriman/core/repository/event_logger.py
+++ b/src/ahriman/core/repository/event_logger.py
@@ -19,7 +19,7 @@
#
import contextlib
-from typing import Generator
+from collections.abc import Iterator
from ahriman.core.status import Client
from ahriman.models.event import Event, EventType
@@ -55,7 +55,7 @@ class EventLogger:
@contextlib.contextmanager
def in_event(self, package_base: str, event: EventType, message: str | None = None,
- failure: EventType | None = None) -> Generator[None, None, None]:
+ failure: EventType | None = None) -> Iterator[None]:
"""
perform action in package context and log event with time elapsed
diff --git a/src/ahriman/core/support/pkgbuild/pkgbuild_generator.py b/src/ahriman/core/support/pkgbuild/pkgbuild_generator.py
index b673994f..21e60841 100644
--- a/src/ahriman/core/support/pkgbuild/pkgbuild_generator.py
+++ b/src/ahriman/core/support/pkgbuild/pkgbuild_generator.py
@@ -20,7 +20,7 @@
import hashlib
import itertools
-from collections.abc import Callable, Generator
+from collections.abc import Callable, Iterator
from pathlib import Path
from typing import ClassVar
@@ -187,7 +187,7 @@ class PkgbuildGenerator:
Returns:
list[PkgbuildPatch]: list of patches to be applied to the PKGBUILD
"""
- def sources_generator() -> Generator[tuple[str, str], None, None]:
+ def sources_generator() -> Iterator[tuple[str, str]]:
for source, generator in sorted(self.sources().items()):
source_path = source_dir / source
generator(source_path)
diff --git a/src/ahriman/core/triggers/trigger_loader.py b/src/ahriman/core/triggers/trigger_loader.py
index f9ac92cd..2ae9fecf 100644
--- a/src/ahriman/core/triggers/trigger_loader.py
+++ b/src/ahriman/core/triggers/trigger_loader.py
@@ -21,7 +21,7 @@ import atexit
import contextlib
import os
-from collections.abc import Generator
+from collections.abc import Iterator
from importlib import import_module, machinery
from pathlib import Path
from types import ModuleType
@@ -112,7 +112,7 @@ class TriggerLoader(LazyLogging):
return configuration.getlist("build", "triggers", fallback=[])
@contextlib.contextmanager
- def __execute_trigger(self, trigger: Trigger) -> Generator[None, None, None]:
+ def __execute_trigger(self, trigger: Trigger) -> Iterator[None]:
"""
decorator for calling triggers
diff --git a/src/ahriman/core/utils.py b/src/ahriman/core/utils.py
index eacf0dff..7e4e2e1d 100644
--- a/src/ahriman/core/utils.py
+++ b/src/ahriman/core/utils.py
@@ -27,7 +27,7 @@ import re
import selectors
import subprocess
-from collections.abc import Callable, Generator, Iterable, Mapping
+from collections.abc import Callable, Iterable, Iterator, Mapping
from dataclasses import asdict
from enum import Enum
from pathlib import Path
@@ -113,7 +113,7 @@ def check_output(*args: str, exception: Exception | Callable[[int, list[str], st
return channel if channel is not None else io.StringIO()
# wrapper around selectors polling
- def poll(sel: selectors.BaseSelector) -> Generator[tuple[str, str], None, None]:
+ def poll(sel: selectors.BaseSelector) -> Iterator[tuple[str, str]]:
for key, _ in sel.select(): # we don't need to check mask here because we have only subscribed on reading
line = key.fileobj.readline() # type: ignore[union-attr]
if not line: # in case of empty line we remove selector as there is no data here anymore
@@ -499,7 +499,7 @@ def utcnow() -> datetime.datetime:
return datetime.datetime.now(datetime.UTC)
-def walk(directory_path: Path) -> Generator[Path, None, None]:
+def walk(directory_path: Path) -> Iterator[Path]:
"""
list all file paths in given directory
diff --git a/src/ahriman/models/package.py b/src/ahriman/models/package.py
index 14b65c7d..ed7969fc 100644
--- a/src/ahriman/models/package.py
+++ b/src/ahriman/models/package.py
@@ -22,7 +22,7 @@ from __future__ import annotations
import copy
-from collections.abc import Callable, Generator, Iterable
+from collections.abc import Callable, Iterable, Iterator
from dataclasses import dataclass
from pathlib import Path
from pyalpm import vercmp # type: ignore[import-not-found]
@@ -346,7 +346,7 @@ class Package(LazyLogging):
)
@staticmethod
- def local_files(path: Path) -> Generator[Path, None, None]:
+ def local_files(path: Path) -> Iterator[Path]:
"""
extract list of local files
@@ -407,7 +407,7 @@ class Package(LazyLogging):
Returns:
list[str]: combined list of unique entries in properties list
"""
- def generator() -> Generator[str, None, None]:
+ def generator() -> Iterator[str]:
for package in self.packages.values():
yield from extractor(package)
@@ -570,7 +570,7 @@ class Package(LazyLogging):
"""
return dataclass_view(self)
- def with_packages(self, packages: list[Path], pacman: Pacman) -> None:
+ def with_packages(self, packages: Iterable[Path], pacman: Pacman) -> None:
"""
replace packages descriptions with ones from archives
diff --git a/src/ahriman/models/pkgbuild_patch.py b/src/ahriman/models/pkgbuild_patch.py
index 3582f71b..b726d684 100644
--- a/src/ahriman/models/pkgbuild_patch.py
+++ b/src/ahriman/models/pkgbuild_patch.py
@@ -22,7 +22,7 @@ import shlex
from dataclasses import dataclass, fields
from pathlib import Path
-from typing import Any, Generator, Self
+from typing import Any, Iterator, Self
from ahriman.core.configuration.shell_template import ShellTemplate
from ahriman.core.utils import dataclass_view, filter_json
@@ -166,7 +166,7 @@ class PkgbuildPatch:
ValueError: if no closing quotation
"""
- def generator() -> Generator[str, None, None]:
+ def generator() -> Iterator[str]:
token = None
for char in source:
if token is not None:
diff --git a/src/ahriman/models/repository_paths.py b/src/ahriman/models/repository_paths.py
index a9ff1e0a..e3cec7a9 100644
--- a/src/ahriman/models/repository_paths.py
+++ b/src/ahriman/models/repository_paths.py
@@ -21,7 +21,7 @@ import contextlib
import os
import shutil
-from collections.abc import Generator
+from collections.abc import Iterator
from dataclasses import dataclass, field
from functools import cached_property
from pathlib import Path
@@ -170,7 +170,7 @@ class RepositoryPaths(LazyLogging):
Returns:
set[str]: list of repository architectures for which there is created tree
"""
- def walk(repository_dir: Path) -> Generator[str, None, None]:
+ def walk(repository_dir: Path) -> Iterator[str]:
for architecture in filter(lambda path: path.is_dir(), repository_dir.iterdir()):
yield architecture.name
@@ -197,7 +197,7 @@ class RepositoryPaths(LazyLogging):
is loaded in legacy mode
"""
# simply walk through the root. In case if there are subdirectories, emit the name
- def walk(paths: RepositoryPaths) -> Generator[str, None, None]:
+ def walk(paths: RepositoryPaths) -> Iterator[str]:
for repository in filter(lambda path: path.is_dir(), paths._repository_root.iterdir()):
if any(path.is_dir() for path in repository.iterdir()):
yield repository.name
@@ -262,7 +262,7 @@ class RepositoryPaths(LazyLogging):
return self.cache / package_base
@contextlib.contextmanager
- def preserve_owner(self, path: Path | None = None) -> Generator[None, None, None]:
+ def preserve_owner(self, path: Path | None = None) -> Iterator[None]:
"""
perform any action preserving owner for any newly created file or directory
@@ -281,7 +281,7 @@ class RepositoryPaths(LazyLogging):
"""
path = path or self.root
- def walk(root: Path) -> Generator[Path, None, None]:
+ def walk(root: Path) -> Iterator[Path]:
# basically walk, but skipping some content
for child in root.iterdir():
yield child
diff --git a/src/ahriman/web/routes.py b/src/ahriman/web/routes.py
index dc3f8de9..c4915493 100644
--- a/src/ahriman/web/routes.py
+++ b/src/ahriman/web/routes.py
@@ -20,7 +20,7 @@
import re
from aiohttp.web import Application, View
-from collections.abc import Generator
+from collections.abc import Iterator
import ahriman.web.views
@@ -32,7 +32,7 @@ from ahriman.web.views.base import BaseView
__all__ = ["setup_routes"]
-def _dynamic_routes(configuration: Configuration) -> Generator[tuple[str, type[View]], None, None]:
+def _dynamic_routes(configuration: Configuration) -> Iterator[tuple[str, type[View]]]:
"""
extract dynamic routes based on views