diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 58f44ab2..9cc9ce94 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -91,6 +91,7 @@ Again, the most checks can be performed by `make check` command, though some add
```
* Type annotations are the must, even for local functions.
+* For collection types built-in classes must be used if possible (e.g. `dict` instead of `typing.Dict`, `tuple` instead of `typing.Tuple`). In case if built-in type is not available, but `collections.abc` provides interface, it must be used (e.g. `collections.abc.Awaitable` instead of `typing.Awaitable`, `collections.abc.Iterable` instead of `typing.Iterable`). For union classes, the bar operator (`|`) must be used (e.g. `float | int` instead of `typing.Union[float, int]`), which also includes `typinng.Optional` (e.g. `str | None` instead of `Optional[str]`).
* Recommended order of function definitions in class:
```python
@@ -102,7 +103,7 @@ Again, the most checks can be performed by `make check` command, though some add
def property(self) -> Any: ...
@classmethod
- def class_method(cls: Type[Clazz]) -> Clazz: ...
+ def class_method(cls: type[Clazz]) -> Clazz: ...
@staticmethod
def static_method() -> Any: ...
diff --git a/docs/architecture.rst b/docs/architecture.rst
index 7e877852..4dacfdde 100644
--- a/docs/architecture.rst
+++ b/docs/architecture.rst
@@ -121,7 +121,7 @@ Type conversions
By default, it parses rows into python dictionary. In addition, the following pseudo-types are supported:
-* ``Dict[str, Any]``, ``List[Any]`` - for storing JSON data structures in database (technically there is no restriction on types for dictionary keys and values, but it is recommended to use only string keys). The type is stored as ``json`` data type and ``json.loads`` and ``json.dumps`` methods are used in order to read and write from/to database respectively.
+* ``dict[str, Any]``, ``list[Any]`` - for storing JSON data structures in database (technically there is no restriction on types for dictionary keys and values, but it is recommended to use only string keys). The type is stored as ``json`` data type and ``json.loads`` and ``json.dumps`` methods are used in order to read and write from/to database respectively.
Basic flows
-----------
@@ -235,7 +235,7 @@ Triggers are extensions which can be used in order to perform any actions on app
The main idea is to load classes by their full path (e.g. ``ahriman.core.upload.UploadTrigger``) by using ``importlib``: get the last part of the import and treat it as class name, join remain part by ``.`` and interpret as module path, import module and extract attribute from it.
-The loaded triggers will be called with ``ahriman.models.result.Result`` and ``List[Packages]`` arguments, which describes the process result and current repository packages respectively. Any exception raised will be suppressed and will generate an exception message in logs.
+The loaded triggers will be called with ``ahriman.models.result.Result`` and ``list[Packages]`` arguments, which describes the process result and current repository packages respectively. Any exception raised will be suppressed and will generate an exception message in logs.
In addition triggers can implement ``on_start`` and ``on_stop`` actions which will be called on the application start and right before the application exit. The ``on_start`` action is usually being called from handlers directly in order to make sure that no trigger will be run when it is not required (e.g. on user management). As soon as ``on_start`` action is called, the additional flag will be set; ``ahriman.core.triggers.TriggerLoader`` class implements ``__del__`` method in which, if the flag is set, the ``on_stop`` actions will be called.
diff --git a/setup.py b/setup.py
index c2797f18..1b3697b2 100644
--- a/setup.py
+++ b/setup.py
@@ -1,10 +1,10 @@
from pathlib import Path
from setuptools import find_packages, setup
-from typing import Any, Dict
+from typing import Any
metadata_path = Path(__file__).resolve().parent / "src/ahriman/version.py"
-metadata: Dict[str, Any] = {}
+metadata: dict[str, Any] = {}
with metadata_path.open() as metadata_file:
exec(metadata_file.read(), metadata) # pylint: disable=exec-used
diff --git a/src/ahriman/application/ahriman.py b/src/ahriman/application/ahriman.py
index 2afb3981..61234551 100644
--- a/src/ahriman/application/ahriman.py
+++ b/src/ahriman/application/ahriman.py
@@ -23,7 +23,7 @@ import sys
import tempfile
from pathlib import Path
-from typing import List, TypeVar
+from typing import TypeVar
from ahriman import version
from ahriman.application import handlers
@@ -35,7 +35,7 @@ from ahriman.models.sign_settings import SignSettings
from ahriman.models.user_access import UserAccess
-__all__: List[str] = []
+__all__: list[str] = []
# this workaround is for several things
diff --git a/src/ahriman/application/application/application.py b/src/ahriman/application/application/application.py
index 1e17a14c..4cf8a360 100644
--- a/src/ahriman/application/application/application.py
+++ b/src/ahriman/application/application/application.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 typing import Iterable, List, Set
+from collections.abc import Iterable
from ahriman.application.application.application_packages import ApplicationPackages
from ahriman.application.application.application_repository import ApplicationRepository
@@ -50,14 +50,14 @@ class Application(ApplicationPackages, ApplicationRepository):
be used instead.
"""
- def _known_packages(self) -> Set[str]:
+ def _known_packages(self) -> set[str]:
"""
load packages from repository and pacman repositories
Returns:
- Set[str]: list of known packages
+ set[str]: list of known packages
"""
- known_packages: Set[str] = set()
+ known_packages: set[str] = set()
# local set
for base in self.repository.packages():
for package, properties in base.packages.items():
@@ -89,15 +89,15 @@ class Application(ApplicationPackages, ApplicationRepository):
"""
self.repository.triggers.on_stop()
- def with_dependencies(self, packages: List[Package], *, process_dependencies: bool) -> List[Package]:
+ def with_dependencies(self, packages: list[Package], *, process_dependencies: bool) -> list[Package]:
"""
add missing dependencies to list of packages
Args:
- packages(List[Package]): list of source packages of which dependencies have to be processed
+ packages(list[Package]): list of source packages of which dependencies have to be processed
process_dependencies(bool): if no set, dependencies will not be processed
"""
- def missing_dependencies(source: Iterable[Package]) -> Set[str]:
+ def missing_dependencies(source: Iterable[Package]) -> set[str]:
# build initial list of dependencies
result = set()
for package in source:
diff --git a/src/ahriman/application/application/application_packages.py b/src/ahriman/application/application/application_packages.py
index 4f28645e..2bb30216 100644
--- a/src/ahriman/application/application/application_packages.py
+++ b/src/ahriman/application/application/application_packages.py
@@ -20,8 +20,9 @@
import requests
import shutil
+from collections.abc import Iterable
from pathlib import Path
-from typing import Any, Iterable
+from typing import Any
from ahriman.application.application.application_properties import ApplicationProperties
from ahriman.core.build_tools.sources import Sources
diff --git a/src/ahriman/application/application/application_repository.py b/src/ahriman/application/application/application_repository.py
index e6685e6a..3fd5bde2 100644
--- a/src/ahriman/application/application/application_repository.py
+++ b/src/ahriman/application/application/application_repository.py
@@ -17,8 +17,8 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
+from collections.abc import Callable, Iterable
from pathlib import Path
-from typing import Callable, Iterable, List
from ahriman.application.application.application_properties import ApplicationProperties
from ahriman.core.build_tools.sources import Sources
@@ -89,19 +89,19 @@ class ApplicationRepository(ApplicationProperties):
# process triggers
self.on_result(Result())
- def unknown(self) -> List[str]:
+ def unknown(self) -> list[str]:
"""
get packages which were not found in AUR
Returns:
- List[str]: unknown package archive list
+ list[str]: unknown package archive list
"""
def has_local(probe: Package) -> bool:
cache_dir = self.repository.paths.cache_for(probe.base)
return cache_dir.is_dir() and not Sources.has_remotes(cache_dir)
- def unknown_aur(probe: Package) -> List[str]:
- packages: List[str] = []
+ def unknown_aur(probe: Package) -> list[str]:
+ packages: list[str] = []
for single in probe.packages:
try:
_ = Package.from_aur(single, self.repository.pacman)
@@ -109,7 +109,7 @@ class ApplicationRepository(ApplicationProperties):
packages.append(single)
return packages
- def unknown_local(probe: Package) -> List[str]:
+ def unknown_local(probe: Package) -> list[str]:
cache_dir = self.repository.paths.cache_for(probe.base)
local = Package.from_build(cache_dir, self.architecture)
packages = set(probe.packages.keys()).difference(local.packages.keys())
@@ -155,7 +155,7 @@ class ApplicationRepository(ApplicationProperties):
return build_result
def updates(self, filter_packages: Iterable[str], *,
- aur: bool, local: bool, manual: bool, vcs: bool, log_fn: Callable[[str], None]) -> List[Package]:
+ aur: bool, local: bool, manual: bool, vcs: bool, log_fn: Callable[[str], None]) -> list[Package]:
"""
get list of packages to run update process
@@ -168,7 +168,7 @@ class ApplicationRepository(ApplicationProperties):
log_fn(Callable[[str], None]): logger function to log updates
Returns:
- List[Package]: list of out-of-dated packages
+ list[Package]: list of out-of-dated packages
"""
updates = {}
diff --git a/src/ahriman/application/handlers/add.py b/src/ahriman/application/handlers/add.py
index a129bc05..00536b5b 100644
--- a/src/ahriman/application/handlers/add.py
+++ b/src/ahriman/application/handlers/add.py
@@ -19,8 +19,6 @@
#
import argparse
-from typing import Type
-
from ahriman.application.application import Application
from ahriman.application.handlers import Handler
from ahriman.core.configuration import Configuration
@@ -32,7 +30,7 @@ class Add(Handler):
"""
@classmethod
- def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
+ def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
report: bool, unsafe: bool) -> None:
"""
callback for command line
diff --git a/src/ahriman/application/handlers/backup.py b/src/ahriman/application/handlers/backup.py
index f1fb1696..5561fdbc 100644
--- a/src/ahriman/application/handlers/backup.py
+++ b/src/ahriman/application/handlers/backup.py
@@ -22,7 +22,6 @@ import pwd
from pathlib import Path
from tarfile import TarFile
-from typing import Set, Type
from ahriman.application.handlers import Handler
from ahriman.core.configuration import Configuration
@@ -37,7 +36,7 @@ class Backup(Handler):
ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture"
@classmethod
- def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
+ def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
report: bool, unsafe: bool) -> None:
"""
callback for command line
@@ -55,7 +54,7 @@ class Backup(Handler):
archive.add(backup_path)
@staticmethod
- def get_paths(configuration: Configuration) -> Set[Path]:
+ def get_paths(configuration: Configuration) -> set[Path]:
"""
extract paths to back up
@@ -63,7 +62,7 @@ class Backup(Handler):
configuration(Configuration): configuration instance
Returns:
- Set[Path]: map of the filesystem paths
+ set[Path]: map of the filesystem paths
"""
paths = set(configuration.include.glob("*.ini"))
diff --git a/src/ahriman/application/handlers/clean.py b/src/ahriman/application/handlers/clean.py
index 7d754f33..47919251 100644
--- a/src/ahriman/application/handlers/clean.py
+++ b/src/ahriman/application/handlers/clean.py
@@ -19,8 +19,6 @@
#
import argparse
-from typing import Type
-
from ahriman.application.application import Application
from ahriman.application.handlers import Handler
from ahriman.core.configuration import Configuration
@@ -32,7 +30,7 @@ class Clean(Handler):
"""
@classmethod
- def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
+ def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
report: bool, unsafe: bool) -> None:
"""
callback for command line
diff --git a/src/ahriman/application/handlers/daemon.py b/src/ahriman/application/handlers/daemon.py
index 8a9999de..33ae3a74 100644
--- a/src/ahriman/application/handlers/daemon.py
+++ b/src/ahriman/application/handlers/daemon.py
@@ -20,8 +20,6 @@
import argparse
import threading
-from typing import Type
-
from ahriman.application.handlers import Handler
from ahriman.core.configuration import Configuration
@@ -32,7 +30,7 @@ class Daemon(Handler):
"""
@classmethod
- def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
+ def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
report: bool, unsafe: bool) -> None:
"""
callback for command line
diff --git a/src/ahriman/application/handlers/dump.py b/src/ahriman/application/handlers/dump.py
index a3aa5c72..121363ea 100644
--- a/src/ahriman/application/handlers/dump.py
+++ b/src/ahriman/application/handlers/dump.py
@@ -19,8 +19,6 @@
#
import argparse
-from typing import Type
-
from ahriman.application.handlers import Handler
from ahriman.core.configuration import Configuration
from ahriman.core.formatters import ConfigurationPrinter
@@ -34,7 +32,7 @@ class Dump(Handler):
ALLOW_AUTO_ARCHITECTURE_RUN = False
@classmethod
- def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
+ def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
report: bool, unsafe: bool) -> None:
"""
callback for command line
diff --git a/src/ahriman/application/handlers/handler.py b/src/ahriman/application/handlers/handler.py
index 9517d849..db6d5600 100644
--- a/src/ahriman/application/handlers/handler.py
+++ b/src/ahriman/application/handlers/handler.py
@@ -23,7 +23,6 @@ import argparse
import logging
from multiprocessing import Pool
-from typing import List, Type
from ahriman.application.lock import Lock
from ahriman.core.configuration import Configuration
@@ -53,7 +52,7 @@ class Handler:
ALLOW_MULTI_ARCHITECTURE_RUN = True
@classmethod
- def architectures_extract(cls: Type[Handler], args: argparse.Namespace) -> List[str]:
+ def architectures_extract(cls: type[Handler], args: argparse.Namespace) -> list[str]:
"""
get known architectures
@@ -61,7 +60,7 @@ class Handler:
args(argparse.Namespace): command line args
Returns:
- List[str]: list of architectures for which tree is created
+ list[str]: list of architectures for which tree is created
Raises:
MissingArchitecture: if no architecture set and automatic detection is not allowed or failed
@@ -84,7 +83,7 @@ class Handler:
return sorted(architectures)
@classmethod
- def call(cls: Type[Handler], args: argparse.Namespace, architecture: str) -> bool:
+ def call(cls: type[Handler], args: argparse.Namespace, architecture: str) -> bool:
"""
additional function to wrap all calls for multiprocessing library
@@ -109,7 +108,7 @@ class Handler:
return False
@classmethod
- def execute(cls: Type[Handler], args: argparse.Namespace) -> int:
+ def execute(cls: type[Handler], args: argparse.Namespace) -> int:
"""
execute function for all aru
@@ -138,7 +137,7 @@ class Handler:
return 0 if all(result) else 1
@classmethod
- def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
+ def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
report: bool, unsafe: bool) -> None:
"""
callback for command line
diff --git a/src/ahriman/application/handlers/help.py b/src/ahriman/application/handlers/help.py
index 94c65dba..dafd351f 100644
--- a/src/ahriman/application/handlers/help.py
+++ b/src/ahriman/application/handlers/help.py
@@ -19,8 +19,6 @@
#
import argparse
-from typing import Type
-
from ahriman.application.handlers import Handler
from ahriman.core.configuration import Configuration
@@ -33,7 +31,7 @@ class Help(Handler):
ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture"
@classmethod
- def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
+ def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
report: bool, unsafe: bool) -> None:
"""
callback for command line
diff --git a/src/ahriman/application/handlers/key_import.py b/src/ahriman/application/handlers/key_import.py
index 38f7d34d..d6447f1b 100644
--- a/src/ahriman/application/handlers/key_import.py
+++ b/src/ahriman/application/handlers/key_import.py
@@ -19,8 +19,6 @@
#
import argparse
-from typing import Type
-
from ahriman.application.application import Application
from ahriman.application.handlers import Handler
from ahriman.core.configuration import Configuration
@@ -34,7 +32,7 @@ class KeyImport(Handler):
ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture"
@classmethod
- def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
+ def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
report: bool, unsafe: bool) -> None:
"""
callback for command line
diff --git a/src/ahriman/application/handlers/patch.py b/src/ahriman/application/handlers/patch.py
index 65e3fa9d..d2b2cc34 100644
--- a/src/ahriman/application/handlers/patch.py
+++ b/src/ahriman/application/handlers/patch.py
@@ -21,7 +21,6 @@ import argparse
import sys
from pathlib import Path
-from typing import List, Optional, Tuple, Type
from ahriman.application.application import Application
from ahriman.application.handlers import Handler
@@ -39,7 +38,7 @@ class Patch(Handler):
"""
@classmethod
- def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
+ def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
report: bool, unsafe: bool) -> None:
"""
callback for command line
@@ -66,17 +65,17 @@ class Patch(Handler):
Patch.patch_set_remove(application, args.package, args.variable)
@staticmethod
- def patch_create_from_diff(sources_dir: Path, architecture: str, track: List[str]) -> Tuple[str, PkgbuildPatch]:
+ def patch_create_from_diff(sources_dir: Path, architecture: str, track: list[str]) -> tuple[str, PkgbuildPatch]:
"""
create PKGBUILD plain diff patches from sources directory
Args:
sources_dir(Path): path to directory with the package sources
architecture(str): repository architecture
- track(List[str]): track files which match the glob before creating the patch
+ track(list[str]): track files which match the glob before creating the patch
Returns:
- Tuple[str, PkgbuildPatch]: package base and created PKGBUILD patch based on the diff from master HEAD
+ tuple[str, PkgbuildPatch]: package base and created PKGBUILD patch based on the diff from master HEAD
to current files
"""
package = Package.from_build(sources_dir, architecture)
@@ -84,13 +83,13 @@ class Patch(Handler):
return package.base, PkgbuildPatch(None, patch)
@staticmethod
- def patch_create_from_function(variable: str, patch_path: Optional[Path]) -> PkgbuildPatch:
+ def patch_create_from_function(variable: str, patch_path: Path | None) -> PkgbuildPatch:
"""
create single-function patch set for the package base
Args:
variable(str): function or variable name inside PKGBUILD
- patch_path(Path): optional path to patch content. If not set, it will be read from stdin
+ patch_path(Path | None): optional path to patch content. If not set, it will be read from stdin
Returns:
PkgbuildPatch: created patch for the PKGBUILD function
@@ -116,15 +115,15 @@ class Patch(Handler):
application.database.patches_insert(package_base, patch)
@staticmethod
- def patch_set_list(application: Application, package_base: Optional[str], variables: List[str],
+ def patch_set_list(application: Application, package_base: str | None, variables: list[str],
exit_code: bool) -> None:
"""
list patches available for the package base
Args:
application(Application): application instance
- package_base(Optional[str]): package base
- variables(List[str]): extract patches only for specified PKGBUILD variables
+ package_base(str | None): package base
+ variables(list[str]): extract patches only for specified PKGBUILD variables
exit_code(bool): exit with error on empty search result
"""
patches = application.database.patches_list(package_base, variables)
@@ -134,13 +133,13 @@ class Patch(Handler):
PatchPrinter(base, patch).print(verbose=True, separator=" = ")
@staticmethod
- def patch_set_remove(application: Application, package_base: str, variables: List[str]) -> None:
+ def patch_set_remove(application: Application, package_base: str, variables: list[str]) -> None:
"""
remove patch set for the package base
Args:
application(Application): application instance
package_base(str): package base
- variables(List[str]): remove patches only for specified PKGBUILD variables
+ variables(list[str]): remove patches only for specified PKGBUILD variables
"""
application.database.patches_remove(package_base, variables)
diff --git a/src/ahriman/application/handlers/rebuild.py b/src/ahriman/application/handlers/rebuild.py
index 2c14f139..15cb2745 100644
--- a/src/ahriman/application/handlers/rebuild.py
+++ b/src/ahriman/application/handlers/rebuild.py
@@ -19,8 +19,6 @@
#
import argparse
-from typing import List, Type
-
from ahriman.application.application import Application
from ahriman.application.handlers import Handler
from ahriman.core.configuration import Configuration
@@ -34,7 +32,7 @@ class Rebuild(Handler):
"""
@classmethod
- def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
+ def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
report: bool, unsafe: bool) -> None:
"""
callback for command line
@@ -46,13 +44,11 @@ class Rebuild(Handler):
report(bool): force enable or disable reporting
unsafe(bool): if set no user check will be performed before path creation
"""
- depends_on = set(args.depends_on) if args.depends_on else None
-
application = Application(architecture, configuration, report=report, unsafe=unsafe)
application.on_start()
packages = Rebuild.extract_packages(application, from_database=args.from_database)
- updates = application.repository.packages_depend_on(packages, depends_on)
+ updates = application.repository.packages_depend_on(packages, args.depends_on or None)
Rebuild.check_if_empty(args.exit_code, not updates)
if args.dry_run:
@@ -64,7 +60,7 @@ class Rebuild(Handler):
Rebuild.check_if_empty(args.exit_code, result.is_empty)
@staticmethod
- def extract_packages(application: Application, *, from_database: bool) -> List[Package]:
+ def extract_packages(application: Application, *, from_database: bool) -> list[Package]:
"""
extract packages from database file
@@ -73,7 +69,7 @@ class Rebuild(Handler):
from_database(bool): extract packages from database instead of repository filesystem
Returns:
- List[Package]: list of packages which were stored in database
+ list[Package]: list of packages which were stored in database
"""
if from_database:
return [package for (package, _) in application.database.packages_get()]
diff --git a/src/ahriman/application/handlers/remove.py b/src/ahriman/application/handlers/remove.py
index 14ca4cd7..7a84272a 100644
--- a/src/ahriman/application/handlers/remove.py
+++ b/src/ahriman/application/handlers/remove.py
@@ -19,8 +19,6 @@
#
import argparse
-from typing import Type
-
from ahriman.application.application import Application
from ahriman.application.handlers import Handler
from ahriman.core.configuration import Configuration
@@ -32,7 +30,7 @@ class Remove(Handler):
"""
@classmethod
- def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
+ def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
report: bool, unsafe: bool) -> None:
"""
callback for command line
diff --git a/src/ahriman/application/handlers/remove_unknown.py b/src/ahriman/application/handlers/remove_unknown.py
index aca626e6..895ae1fc 100644
--- a/src/ahriman/application/handlers/remove_unknown.py
+++ b/src/ahriman/application/handlers/remove_unknown.py
@@ -19,8 +19,6 @@
#
import argparse
-from typing import Type
-
from ahriman.application.application import Application
from ahriman.application.handlers import Handler
from ahriman.core.configuration import Configuration
@@ -33,7 +31,7 @@ class RemoveUnknown(Handler):
"""
@classmethod
- def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
+ def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
report: bool, unsafe: bool) -> None:
"""
callback for command line
diff --git a/src/ahriman/application/handlers/restore.py b/src/ahriman/application/handlers/restore.py
index 97d02469..0e425205 100644
--- a/src/ahriman/application/handlers/restore.py
+++ b/src/ahriman/application/handlers/restore.py
@@ -19,7 +19,6 @@
#
import argparse
-from typing import Type
from tarfile import TarFile
from ahriman.application.handlers import Handler
@@ -34,7 +33,7 @@ class Restore(Handler):
ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture"
@classmethod
- def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
+ def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
report: bool, unsafe: bool) -> None:
"""
callback for command line
diff --git a/src/ahriman/application/handlers/search.py b/src/ahriman/application/handlers/search.py
index de451b11..625c64d8 100644
--- a/src/ahriman/application/handlers/search.py
+++ b/src/ahriman/application/handlers/search.py
@@ -20,7 +20,7 @@
import argparse
from dataclasses import fields
-from typing import Callable, Iterable, List, Tuple, Type
+from collections.abc import Callable, Iterable
from ahriman.application.application import Application
from ahriman.application.handlers import Handler
@@ -36,14 +36,14 @@ class Search(Handler):
packages search handler
Attributes:
- SORT_FIELDS(Set[str]): (class attribute) allowed fields to sort the package list
+ SORT_FIELDS(set[str]): (class attribute) allowed fields to sort the package list
"""
ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture"
SORT_FIELDS = {field.name for field in fields(AURPackage) if field.default_factory is not list} # type: ignore
@classmethod
- def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
+ def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
report: bool, unsafe: bool) -> None:
"""
callback for command line
@@ -67,7 +67,7 @@ class Search(Handler):
AurPrinter(package).print(verbose=args.info)
@staticmethod
- def sort(packages: Iterable[AURPackage], sort_by: str) -> List[AURPackage]:
+ def sort(packages: Iterable[AURPackage], sort_by: str) -> list[AURPackage]:
"""
sort package list by specified field
@@ -76,7 +76,7 @@ class Search(Handler):
sort_by(str): AUR package field name to sort by
Returns:
- List[AURPackage]: sorted list for packages
+ list[AURPackage]: sorted list for packages
Raises:
InvalidOption: if search fields is not in list of allowed ones
@@ -85,6 +85,6 @@ class Search(Handler):
raise OptionError(sort_by)
# always sort by package name at the last
# well technically it is not a string, but we can deal with it
- comparator: Callable[[AURPackage], Tuple[str, str]] =\
+ comparator: Callable[[AURPackage], tuple[str, str]] =\
lambda package: (getattr(package, sort_by), package.name)
return sorted(packages, key=comparator)
diff --git a/src/ahriman/application/handlers/service_updates.py b/src/ahriman/application/handlers/service_updates.py
index 8aa1f0e3..0e25f13c 100644
--- a/src/ahriman/application/handlers/service_updates.py
+++ b/src/ahriman/application/handlers/service_updates.py
@@ -19,8 +19,6 @@
#
import argparse
-from typing import Type
-
from ahriman import version
from ahriman.application.application import Application
from ahriman.application.handlers import Handler
@@ -37,7 +35,7 @@ class ServiceUpdates(Handler):
ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture"
@classmethod
- def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
+ def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
report: bool, unsafe: bool) -> None:
"""
callback for command line
diff --git a/src/ahriman/application/handlers/setup.py b/src/ahriman/application/handlers/setup.py
index bc419a91..7a29d9d8 100644
--- a/src/ahriman/application/handlers/setup.py
+++ b/src/ahriman/application/handlers/setup.py
@@ -21,7 +21,6 @@ import argparse
from pathlib import Path
from pwd import getpwuid
-from typing import Optional, Type
from ahriman.application.application import Application
from ahriman.application.handlers import Handler
@@ -46,7 +45,7 @@ class Setup(Handler):
SUDOERS_DIR_PATH = Path("/etc/sudoers.d")
@classmethod
- def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
+ def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
report: bool, unsafe: bool) -> None:
"""
callback for command line
@@ -132,7 +131,7 @@ class Setup(Handler):
configuration.write(ahriman_configuration)
@staticmethod
- def configuration_create_devtools(prefix: str, architecture: str, source: Path, mirror: Optional[str],
+ def configuration_create_devtools(prefix: str, architecture: str, source: Path, mirror: str | None,
multilib: bool, repository: str, paths: RepositoryPaths) -> None:
"""
create configuration for devtools based on ``source`` configuration
@@ -144,7 +143,7 @@ class Setup(Handler):
prefix(str): command prefix in {prefix}-{architecture}-build
architecture(str): repository architecture
source(Path): path to source configuration file
- mirror(Optional[str]): link to package server mirror
+ mirror(str | None): link to package server mirror
multilib(bool): add or do not multilib repository to the configuration
repository(str): repository name
paths(RepositoryPaths): repository paths instance
diff --git a/src/ahriman/application/handlers/shell.py b/src/ahriman/application/handlers/shell.py
index 1ad30f7f..d1221751 100644
--- a/src/ahriman/application/handlers/shell.py
+++ b/src/ahriman/application/handlers/shell.py
@@ -22,7 +22,6 @@ import code
import sys
from pathlib import Path
-from typing import Type
from ahriman.application.application import Application
from ahriman.application.handlers import Handler
@@ -38,7 +37,7 @@ class Shell(Handler):
ALLOW_MULTI_ARCHITECTURE_RUN = False
@classmethod
- def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
+ def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
report: bool, unsafe: bool) -> None:
"""
callback for command line
diff --git a/src/ahriman/application/handlers/sign.py b/src/ahriman/application/handlers/sign.py
index acb86c89..c2fd0e3f 100644
--- a/src/ahriman/application/handlers/sign.py
+++ b/src/ahriman/application/handlers/sign.py
@@ -19,8 +19,6 @@
#
import argparse
-from typing import Type
-
from ahriman.application.application import Application
from ahriman.application.handlers import Handler
from ahriman.core.configuration import Configuration
@@ -32,7 +30,7 @@ class Sign(Handler):
"""
@classmethod
- def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
+ def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
report: bool, unsafe: bool) -> None:
"""
callback for command line
diff --git a/src/ahriman/application/handlers/status.py b/src/ahriman/application/handlers/status.py
index 396860ad..1ae4c0d8 100644
--- a/src/ahriman/application/handlers/status.py
+++ b/src/ahriman/application/handlers/status.py
@@ -19,7 +19,7 @@
#
import argparse
-from typing import Callable, Iterable, Tuple, Type
+from collections.abc import Callable
from ahriman.application.application import Application
from ahriman.application.handlers import Handler
@@ -37,7 +37,7 @@ class Status(Handler):
ALLOW_AUTO_ARCHITECTURE_RUN = False
@classmethod
- def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
+ def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
report: bool, unsafe: bool) -> None:
"""
callback for command line
@@ -55,7 +55,7 @@ class Status(Handler):
service_status = client.get_internal()
StatusPrinter(service_status.status).print(verbose=args.info)
if args.package:
- packages: Iterable[Tuple[Package, BuildStatus]] = sum(
+ packages: list[tuple[Package, BuildStatus]] = sum(
(client.get(base) for base in args.package),
start=[])
else:
@@ -63,8 +63,8 @@ class Status(Handler):
Status.check_if_empty(args.exit_code, not packages)
- comparator: Callable[[Tuple[Package, BuildStatus]], str] = lambda item: item[0].base
- filter_fn: Callable[[Tuple[Package, BuildStatus]], bool] =\
+ comparator: Callable[[tuple[Package, BuildStatus]], str] = lambda item: item[0].base
+ filter_fn: Callable[[tuple[Package, BuildStatus]], bool] =\
lambda item: args.status is None or item[1].status == args.status
for package, package_status in sorted(filter(filter_fn, packages), key=comparator):
PackagePrinter(package, package_status).print(verbose=args.info)
diff --git a/src/ahriman/application/handlers/status_update.py b/src/ahriman/application/handlers/status_update.py
index d6ed0dd8..60832513 100644
--- a/src/ahriman/application/handlers/status_update.py
+++ b/src/ahriman/application/handlers/status_update.py
@@ -19,8 +19,6 @@
#
import argparse
-from typing import Type
-
from ahriman.application.application import Application
from ahriman.application.handlers import Handler
from ahriman.core.configuration import Configuration
@@ -35,7 +33,7 @@ class StatusUpdate(Handler):
ALLOW_AUTO_ARCHITECTURE_RUN = False
@classmethod
- def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
+ def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
report: bool, unsafe: bool) -> None:
"""
callback for command line
diff --git a/src/ahriman/application/handlers/structure.py b/src/ahriman/application/handlers/structure.py
index df889165..56493fba 100644
--- a/src/ahriman/application/handlers/structure.py
+++ b/src/ahriman/application/handlers/structure.py
@@ -19,8 +19,6 @@
#
import argparse
-from typing import Type
-
from ahriman.application.application import Application
from ahriman.application.handlers import Handler
from ahriman.core.configuration import Configuration
@@ -36,7 +34,7 @@ class Structure(Handler):
ALLOW_AUTO_ARCHITECTURE_RUN = False
@classmethod
- def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
+ def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
report: bool, unsafe: bool) -> None:
"""
callback for command line
diff --git a/src/ahriman/application/handlers/triggers.py b/src/ahriman/application/handlers/triggers.py
index 6527c29c..2c990499 100644
--- a/src/ahriman/application/handlers/triggers.py
+++ b/src/ahriman/application/handlers/triggers.py
@@ -19,8 +19,6 @@
#
import argparse
-from typing import Type
-
from ahriman.application.application import Application
from ahriman.application.handlers import Handler
from ahriman.core.configuration import Configuration
@@ -33,7 +31,7 @@ class Triggers(Handler):
"""
@classmethod
- def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
+ def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
report: bool, unsafe: bool) -> None:
"""
callback for command line
diff --git a/src/ahriman/application/handlers/unsafe_commands.py b/src/ahriman/application/handlers/unsafe_commands.py
index 41c18636..d40f9107 100644
--- a/src/ahriman/application/handlers/unsafe_commands.py
+++ b/src/ahriman/application/handlers/unsafe_commands.py
@@ -20,8 +20,6 @@
import argparse
import shlex
-from typing import List, Type
-
from ahriman.application.handlers import Handler
from ahriman.core.configuration import Configuration
from ahriman.core.formatters import StringPrinter
@@ -35,7 +33,7 @@ class UnsafeCommands(Handler):
ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture"
@classmethod
- def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
+ def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
report: bool, unsafe: bool) -> None:
"""
callback for command line
@@ -56,20 +54,20 @@ class UnsafeCommands(Handler):
UnsafeCommands.check_unsafe(args.command, unsafe_commands, parser)
@staticmethod
- def check_unsafe(command: str, unsafe_commands: List[str], parser: argparse.ArgumentParser) -> None:
+ def check_unsafe(command: str, unsafe_commands: list[str], parser: argparse.ArgumentParser) -> None:
"""
check if command is unsafe
Args:
command(str): command to check
- unsafe_commands(List[str]): list of unsafe commands
+ unsafe_commands(list[str]): list of unsafe commands
parser(argparse.ArgumentParser): generated argument parser
"""
args = parser.parse_args(shlex.split(command))
UnsafeCommands.check_if_empty(True, args.command in unsafe_commands)
@staticmethod
- def get_unsafe_commands(parser: argparse.ArgumentParser) -> List[str]:
+ def get_unsafe_commands(parser: argparse.ArgumentParser) -> list[str]:
"""
extract unsafe commands from argument parser
@@ -77,7 +75,7 @@ class UnsafeCommands(Handler):
parser(argparse.ArgumentParser): generated argument parser
Returns:
- List[str]: list of commands with default unsafe flag
+ list[str]: list of commands with default unsafe flag
"""
# should never fail
# pylint: disable=protected-access
diff --git a/src/ahriman/application/handlers/update.py b/src/ahriman/application/handlers/update.py
index 7749081b..8f62ee32 100644
--- a/src/ahriman/application/handlers/update.py
+++ b/src/ahriman/application/handlers/update.py
@@ -19,7 +19,7 @@
#
import argparse
-from typing import Callable, Type
+from collections.abc import Callable
from ahriman.application.application import Application
from ahriman.application.handlers import Handler
@@ -32,7 +32,7 @@ class Update(Handler):
"""
@classmethod
- def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
+ def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
report: bool, unsafe: bool) -> None:
"""
callback for command line
diff --git a/src/ahriman/application/handlers/users.py b/src/ahriman/application/handlers/users.py
index 9236e8d6..964cb9d4 100644
--- a/src/ahriman/application/handlers/users.py
+++ b/src/ahriman/application/handlers/users.py
@@ -21,7 +21,6 @@ import argparse
import getpass
from pathlib import Path
-from typing import Optional, Tuple, Type
from ahriman.application.handlers import Handler
from ahriman.core.configuration import Configuration
@@ -40,7 +39,7 @@ class Users(Handler):
ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture"
@classmethod
- def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
+ def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
report: bool, unsafe: bool) -> None:
"""
callback for command line
@@ -119,7 +118,7 @@ class Users(Handler):
path.chmod(0o600)
@staticmethod
- def get_salt(configuration: Configuration, salt_length: int = 20) -> Tuple[Optional[str], str]:
+ def get_salt(configuration: Configuration, salt_length: int = 20) -> tuple[str | None, str]:
"""
get salt from configuration or create new string
@@ -128,7 +127,7 @@ class Users(Handler):
salt_length(int, optional): salt length (Default value = 20)
Returns:
- Tuple[Optional[str], str]: tuple containing salt from configuration if any and actual salt which must be
+ tuple[str | None, str]: tuple containing salt from configuration if any and actual salt which must be
used for password hash
"""
if salt := configuration.get("auth", "salt", fallback=None):
diff --git a/src/ahriman/application/handlers/validate.py b/src/ahriman/application/handlers/validate.py
index 788f3fcd..f27e9041 100644
--- a/src/ahriman/application/handlers/validate.py
+++ b/src/ahriman/application/handlers/validate.py
@@ -20,7 +20,7 @@
import argparse
import copy
-from typing import Any, Dict, Type
+from typing import Any
from ahriman.application.handlers import Handler
from ahriman.core.configuration import Configuration
@@ -39,7 +39,7 @@ class Validate(Handler):
ALLOW_AUTO_ARCHITECTURE_RUN = False
@classmethod
- def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
+ def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
report: bool, unsafe: bool) -> None:
"""
callback for command line
@@ -112,17 +112,17 @@ class Validate(Handler):
return schema
@staticmethod
- def schema_merge(source: Dict[str, Any], schema: Dict[str, Any]) -> Dict[str, Any]:
+ def schema_merge(source: dict[str, Any], schema: dict[str, Any]) -> dict[str, Any]:
"""
merge child schema into source. In case if source already contains values, new keys will be added
(possibly with overrides - in case if such key already set also)
Args:
- source(Dict[str, Any]): source (current) schema into which will be merged
- schema(Dict[str, Any]): new schema to be merged
+ source(dict[str, Any]): source (current) schema into which will be merged
+ schema(dict[str, Any]): new schema to be merged
Returns:
- Dict[str, Any]: schema with added elements from source schema if they were set before and not presented
+ dict[str, Any]: schema with added elements from source schema if they were set before and not presented
in the new one. Note, that schema will be modified in-place
"""
for key, value in source.items():
diff --git a/src/ahriman/application/handlers/versions.py b/src/ahriman/application/handlers/versions.py
index 78ec4040..86a31f55 100644
--- a/src/ahriman/application/handlers/versions.py
+++ b/src/ahriman/application/handlers/versions.py
@@ -21,8 +21,6 @@ import argparse
import pkg_resources
import sys
-from typing import Dict, List, Tuple, Type
-
from ahriman import version
from ahriman.application.handlers import Handler
from ahriman.core.configuration import Configuration
@@ -37,7 +35,7 @@ class Versions(Handler):
ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture"
@classmethod
- def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
+ def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
report: bool, unsafe: bool) -> None:
"""
callback for command line
@@ -55,23 +53,23 @@ class Versions(Handler):
VersionPrinter("Installed packages", packages).print(verbose=False, separator=" ")
@staticmethod
- def package_dependencies(root: str, root_extras: Tuple[str, ...] = ()) -> Dict[str, str]:
+ def package_dependencies(root: str, root_extras: tuple[str, ...] = ()) -> dict[str, str]:
"""
extract list of ahriman package dependencies installed into system with their versions
Args:
root(str): root package name
- root_extras(Tuple[str, ...], optional): extras for the root package (Default value = ())
+ root_extras(tuple[str, ...], optional): extras for the root package (Default value = ())
Returns:
- Dict[str, str]: map of installed dependency to its version
+ dict[str, str]: map of installed dependency to its version
"""
- resources: Dict[str, pkg_resources.Distribution] = pkg_resources.working_set.by_key # type: ignore
+ resources: dict[str, pkg_resources.Distribution] = pkg_resources.working_set.by_key # type: ignore
- def dependencies_by_key(key: str, extras: Tuple[str, ...] = ()) -> List[str]:
+ def dependencies_by_key(key: str, extras: tuple[str, ...] = ()) -> list[str]:
return [entry.key for entry in resources[key].requires(extras)]
- keys: List[str] = []
+ keys: list[str] = []
portion = {key for key in dependencies_by_key(root, root_extras) if key in resources}
while portion:
keys.extend(portion)
diff --git a/src/ahriman/application/handlers/web.py b/src/ahriman/application/handlers/web.py
index df5ca37a..6c2b08ba 100644
--- a/src/ahriman/application/handlers/web.py
+++ b/src/ahriman/application/handlers/web.py
@@ -19,8 +19,6 @@
#
import argparse
-from typing import Type
-
from ahriman.application.handlers import Handler
from ahriman.core.configuration import Configuration
from ahriman.core.spawn import Spawn
@@ -35,7 +33,7 @@ class Web(Handler):
ALLOW_MULTI_ARCHITECTURE_RUN = False # required to be able to spawn external processes
@classmethod
- def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
+ def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
report: bool, unsafe: bool) -> None:
"""
callback for command line
diff --git a/src/ahriman/application/lock.py b/src/ahriman/application/lock.py
index a764441e..da552f75 100644
--- a/src/ahriman/application/lock.py
+++ b/src/ahriman/application/lock.py
@@ -22,7 +22,7 @@ from __future__ import annotations
import argparse
from types import TracebackType
-from typing import Literal, Optional, Type
+from typing import Literal
from ahriman import version
from ahriman.core.configuration import Configuration
@@ -127,14 +127,14 @@ class Lock(LazyLogging):
self.reporter.update_self(BuildStatusEnum.Building)
return self
- def __exit__(self, exc_type: Optional[Type[Exception]], exc_val: Optional[Exception],
+ def __exit__(self, exc_type: type[Exception] | None, exc_val: Exception | None,
exc_tb: TracebackType) -> Literal[False]:
"""
remove lock file when done
Args:
- exc_type(Optional[Type[Exception]]): exception type name if any
- exc_val(Optional[Exception]): exception raised if any
+ exc_type(type[Exception] | None): exception type name if any
+ exc_val(Exception | None): exception raised if any
exc_tb(TracebackType): exception traceback if any
Returns:
diff --git a/src/ahriman/core/__init__.py b/src/ahriman/core/__init__.py
index f8713782..536f3bf3 100644
--- a/src/ahriman/core/__init__.py
+++ b/src/ahriman/core/__init__.py
@@ -17,8 +17,9 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
+from collections.abc import Iterator
from contextvars import ContextVar
-from typing import Any, Dict, Iterator, TypeVar
+from typing import Any, TypeVar
from ahriman.models.context_key import ContextKey
@@ -35,7 +36,7 @@ class _Context:
"""
default constructor. Must not be used directly
"""
- self._content: Dict[str, Any] = {}
+ self._content: dict[str, Any] = {}
def get(self, key: ContextKey[T]) -> T:
"""
diff --git a/src/ahriman/core/alpm/pacman.py b/src/ahriman/core/alpm/pacman.py
index 878287e3..ee586fba 100644
--- a/src/ahriman/core/alpm/pacman.py
+++ b/src/ahriman/core/alpm/pacman.py
@@ -19,9 +19,10 @@
#
import shutil
+from collections.abc import Callable, Generator
from pathlib import Path
from pyalpm import DB, Handle, Package, SIG_PACKAGE, error as PyalpmError # type: ignore
-from typing import Any, Callable, Generator, Set
+from typing import Any
from ahriman.core.configuration import Configuration
from ahriman.core.log import LazyLogging
@@ -166,14 +167,14 @@ class Pacman(LazyLogging):
continue
yield package
- def packages(self) -> Set[str]:
+ def packages(self) -> set[str]:
"""
get list of packages known for alpm
Returns:
- Set[str]: list of package names
+ set[str]: list of package names
"""
- result: Set[str] = set()
+ result: set[str] = set()
for database in self.handle.get_syncdbs():
for package in database.pkgcache:
# package itself
diff --git a/src/ahriman/core/alpm/remote/aur.py b/src/ahriman/core/alpm/remote/aur.py
index edc81c82..4007f278 100644
--- a/src/ahriman/core/alpm/remote/aur.py
+++ b/src/ahriman/core/alpm/remote/aur.py
@@ -19,7 +19,7 @@
#
import requests
-from typing import Any, Dict, List, Type
+from typing import Any
from ahriman.core.alpm.pacman import Pacman
from ahriman.core.alpm.remote import Remote
@@ -45,15 +45,15 @@ class AUR(Remote):
DEFAULT_TIMEOUT = 30
@staticmethod
- def parse_response(response: Dict[str, Any]) -> List[AURPackage]:
+ def parse_response(response: dict[str, Any]) -> list[AURPackage]:
"""
parse RPC response to package list
Args:
- response(Dict[str, Any]): RPC response json
+ response(dict[str, Any]): RPC response json
Returns:
- List[AURPackage]: list of parsed packages
+ list[AURPackage]: list of parsed packages
Raises:
InvalidPackageInfo: for error API response
@@ -65,7 +65,7 @@ class AUR(Remote):
return [AURPackage.from_json(package) for package in response["results"]]
@classmethod
- def remote_git_url(cls: Type[Remote], package_base: str, repository: str) -> str:
+ def remote_git_url(cls: type[Remote], package_base: str, repository: str) -> str:
"""
generate remote git url from the package base
@@ -79,7 +79,7 @@ class AUR(Remote):
return f"{AUR.DEFAULT_AUR_URL}/{package_base}.git"
@classmethod
- def remote_web_url(cls: Type[Remote], package_base: str) -> str:
+ def remote_web_url(cls: type[Remote], package_base: str) -> str:
"""
generate remote web url from the package base
@@ -91,7 +91,7 @@ class AUR(Remote):
"""
return f"{AUR.DEFAULT_AUR_URL}/packages/{package_base}"
- def make_request(self, request_type: str, *args: str, **kwargs: str) -> List[AURPackage]:
+ def make_request(self, request_type: str, *args: str, **kwargs: str) -> list[AURPackage]:
"""
perform request to AUR RPC
@@ -101,9 +101,9 @@ class AUR(Remote):
**kwargs(str): list of additional named parameters like by
Returns:
- List[AURPackage]: response parsed to package list
+ list[AURPackage]: response parsed to package list
"""
- query: Dict[str, Any] = {
+ query: dict[str, Any] = {
"type": request_type,
"v": self.DEFAULT_RPC_VERSION
}
@@ -145,7 +145,7 @@ class AUR(Remote):
except StopIteration:
raise UnknownPackageError(package_name)
- def package_search(self, *keywords: str, pacman: Pacman) -> List[AURPackage]:
+ def package_search(self, *keywords: str, pacman: Pacman) -> list[AURPackage]:
"""
search package in AUR web
@@ -154,6 +154,6 @@ class AUR(Remote):
pacman(Pacman): alpm wrapper instance
Returns:
- List[AURPackage]: list of packages which match the criteria
+ list[AURPackage]: list of packages which match the criteria
"""
return self.make_request("search", *keywords, by="name-desc")
diff --git a/src/ahriman/core/alpm/remote/official.py b/src/ahriman/core/alpm/remote/official.py
index 8666e0b3..e551f65f 100644
--- a/src/ahriman/core/alpm/remote/official.py
+++ b/src/ahriman/core/alpm/remote/official.py
@@ -19,7 +19,7 @@
#
import requests
-from typing import Any, Dict, List, Type
+from typing import Any
from ahriman.core.alpm.pacman import Pacman
from ahriman.core.alpm.remote import Remote
@@ -34,7 +34,7 @@ class Official(Remote):
Attributes:
DEFAULT_ARCHLINUX_URL(str): (class attribute) default archlinux url
- DEFAULT_SEARCH_REPOSITORIES(List[str]): (class attribute) default list of repositories to search
+ DEFAULT_SEARCH_REPOSITORIES(list[str]): (class attribute) default list of repositories to search
DEFAULT_RPC_URL(str): (class attribute) default archlinux repositories RPC url
DEFAULT_TIMEOUT(int): (class attribute) HTTP request timeout in seconds
"""
@@ -45,15 +45,15 @@ class Official(Remote):
DEFAULT_TIMEOUT = 30
@staticmethod
- def parse_response(response: Dict[str, Any]) -> List[AURPackage]:
+ def parse_response(response: dict[str, Any]) -> list[AURPackage]:
"""
parse RPC response to package list
Args:
- response(Dict[str, Any]): RPC response json
+ response(dict[str, Any]): RPC response json
Returns:
- List[AURPackage]: list of parsed packages
+ list[AURPackage]: list of parsed packages
Raises:
InvalidPackageInfo: for error API response
@@ -63,7 +63,7 @@ class Official(Remote):
return [AURPackage.from_repo(package) for package in response["results"]]
@classmethod
- def remote_git_url(cls: Type[Remote], package_base: str, repository: str) -> str:
+ def remote_git_url(cls: type[Remote], package_base: str, repository: str) -> str:
"""
generate remote git url from the package base
@@ -79,7 +79,7 @@ class Official(Remote):
return "https://github.com/archlinux/svntogit-community.git"
@classmethod
- def remote_web_url(cls: Type[Remote], package_base: str) -> str:
+ def remote_web_url(cls: type[Remote], package_base: str) -> str:
"""
generate remote web url from the package base
@@ -91,7 +91,7 @@ class Official(Remote):
"""
return f"{Official.DEFAULT_ARCHLINUX_URL}/packages/{package_base}"
- def make_request(self, *args: str, by: str) -> List[AURPackage]:
+ def make_request(self, *args: str, by: str) -> list[AURPackage]:
"""
perform request to official repositories RPC
@@ -100,7 +100,7 @@ class Official(Remote):
by(str): search by the field
Returns:
- List[AURPackage]: response parsed to package list
+ list[AURPackage]: response parsed to package list
"""
try:
response = requests.get(
@@ -133,7 +133,7 @@ class Official(Remote):
except StopIteration:
raise UnknownPackageError(package_name)
- def package_search(self, *keywords: str, pacman: Pacman) -> List[AURPackage]:
+ def package_search(self, *keywords: str, pacman: Pacman) -> list[AURPackage]:
"""
search package in AUR web
@@ -142,6 +142,6 @@ class Official(Remote):
pacman(Pacman): alpm wrapper instance
Returns:
- List[AURPackage]: list of packages which match the criteria
+ list[AURPackage]: list of packages which match the criteria
"""
return self.make_request(*keywords, by="q")
diff --git a/src/ahriman/core/alpm/remote/remote.py b/src/ahriman/core/alpm/remote/remote.py
index 170db8af..32733ac1 100644
--- a/src/ahriman/core/alpm/remote/remote.py
+++ b/src/ahriman/core/alpm/remote/remote.py
@@ -19,8 +19,6 @@
#
from __future__ import annotations
-from typing import Dict, List, Type
-
from ahriman.core.alpm.pacman import Pacman
from ahriman.core.log import LazyLogging
from ahriman.models.aur_package import AURPackage
@@ -44,7 +42,7 @@ class Remote(LazyLogging):
"""
@classmethod
- def info(cls: Type[Remote], package_name: str, *, pacman: Pacman) -> AURPackage:
+ def info(cls: type[Remote], package_name: str, *, pacman: Pacman) -> AURPackage:
"""
get package info by its name
@@ -58,7 +56,7 @@ class Remote(LazyLogging):
return cls().package_info(package_name, pacman=pacman)
@classmethod
- def multisearch(cls: Type[Remote], *keywords: str, pacman: Pacman) -> List[AURPackage]:
+ def multisearch(cls: type[Remote], *keywords: str, pacman: Pacman) -> list[AURPackage]:
"""
search in remote repository by using API with multiple words. This method is required in order to handle
https://bugs.archlinux.org/task/49133. In addition, short words will be dropped
@@ -68,10 +66,10 @@ class Remote(LazyLogging):
pacman(Pacman): alpm wrapper instance
Returns:
- List[AURPackage]: list of packages each of them matches all search terms
+ list[AURPackage]: list of packages each of them matches all search terms
"""
instance = cls()
- packages: Dict[str, AURPackage] = {}
+ packages: dict[str, AURPackage] = {}
for term in filter(lambda word: len(word) >= 3, keywords):
portion = instance.search(term, pacman=pacman)
packages = {
@@ -82,7 +80,7 @@ class Remote(LazyLogging):
return list(packages.values())
@classmethod
- def remote_git_url(cls: Type[Remote], package_base: str, repository: str) -> str:
+ def remote_git_url(cls: type[Remote], package_base: str, repository: str) -> str:
"""
generate remote git url from the package base
@@ -99,7 +97,7 @@ class Remote(LazyLogging):
raise NotImplementedError
@classmethod
- def remote_web_url(cls: Type[Remote], package_base: str) -> str:
+ def remote_web_url(cls: type[Remote], package_base: str) -> str:
"""
generate remote web url from the package base
@@ -115,7 +113,7 @@ class Remote(LazyLogging):
raise NotImplementedError
@classmethod
- def search(cls: Type[Remote], *keywords: str, pacman: Pacman) -> List[AURPackage]:
+ def search(cls: type[Remote], *keywords: str, pacman: Pacman) -> list[AURPackage]:
"""
search package in AUR web
@@ -124,7 +122,7 @@ class Remote(LazyLogging):
pacman(Pacman): alpm wrapper instance
Returns:
- List[AURPackage]: list of packages which match the criteria
+ list[AURPackage]: list of packages which match the criteria
"""
return cls().package_search(*keywords, pacman=pacman)
@@ -144,7 +142,7 @@ class Remote(LazyLogging):
"""
raise NotImplementedError
- def package_search(self, *keywords: str, pacman: Pacman) -> List[AURPackage]:
+ def package_search(self, *keywords: str, pacman: Pacman) -> list[AURPackage]:
"""
search package in AUR web
@@ -153,7 +151,7 @@ class Remote(LazyLogging):
pacman(Pacman): alpm wrapper instance
Returns:
- List[AURPackage]: list of packages which match the criteria
+ list[AURPackage]: list of packages which match the criteria
Raises:
NotImplementedError: not implemented method
diff --git a/src/ahriman/core/alpm/repo.py b/src/ahriman/core/alpm/repo.py
index 25160659..85c29fa7 100644
--- a/src/ahriman/core/alpm/repo.py
+++ b/src/ahriman/core/alpm/repo.py
@@ -18,7 +18,6 @@
# along with this program. If not, see .
#
from pathlib import Path
-from typing import List
from ahriman.core.exceptions import BuildError
from ahriman.core.log import LazyLogging
@@ -33,20 +32,20 @@ class Repo(LazyLogging):
Attributes:
name(str): repository name
paths(RepositoryPaths): repository paths instance
- sign_args(List[str]): additional args which have to be used to sign repository archive
+ sign_args(list[str]): additional args which have to be used to sign repository archive
uid(int): uid of the repository owner user
"""
_check_output = check_output
- def __init__(self, name: str, paths: RepositoryPaths, sign_args: List[str]) -> None:
+ def __init__(self, name: str, paths: RepositoryPaths, sign_args: list[str]) -> None:
"""
default constructor
Args:
name(str): repository name
paths(RepositoryPaths): repository paths instance
- sign_args(List[str]): additional args which have to be used to sign repository archive
+ sign_args(list[str]): additional args which have to be used to sign repository archive
"""
self.name = name
self.paths = paths
diff --git a/src/ahriman/core/auth/auth.py b/src/ahriman/core/auth/auth.py
index 99fedc6d..9f9ac6af 100644
--- a/src/ahriman/core/auth/auth.py
+++ b/src/ahriman/core/auth/auth.py
@@ -19,8 +19,6 @@
#
from __future__ import annotations
-from typing import Optional, Type
-
from ahriman.core.configuration import Configuration
from ahriman.core.database import SQLite
from ahriman.core.log import LazyLogging
@@ -65,7 +63,7 @@ class Auth(LazyLogging):
return """"""
@classmethod
- def load(cls: Type[Auth], configuration: Configuration, database: SQLite) -> Auth:
+ def load(cls: type[Auth], configuration: Configuration, database: SQLite) -> Auth:
"""
load authorization module from settings
@@ -85,13 +83,13 @@ class Auth(LazyLogging):
return OAuth(configuration, database)
return cls(configuration)
- async def check_credentials(self, username: Optional[str], password: Optional[str]) -> bool:
+ async def check_credentials(self, username: str | None, password: str | None) -> bool:
"""
validate user password
Args:
- username(Optional[str]): username
- password(Optional[str]): entered password
+ username(str | None): username
+ password(str | None): entered password
Returns:
bool: True in case if password matches, False otherwise
@@ -99,12 +97,12 @@ class Auth(LazyLogging):
del username, password
return True
- async def known_username(self, username: Optional[str]) -> bool:
+ async def known_username(self, username: str | None) -> bool:
"""
check if user is known
Args:
- username(Optional[str]): username
+ username(str | None): username
Returns:
bool: True in case if user is known and can be authorized and False otherwise
@@ -112,14 +110,14 @@ class Auth(LazyLogging):
del username
return True
- async def verify_access(self, username: str, required: UserAccess, context: Optional[str]) -> bool:
+ async def verify_access(self, username: str, required: UserAccess, context: str | None) -> bool:
"""
validate if user has access to requested resource
Args:
username(str): username
required(UserAccess): required access level
- context(Optional[str]): URI request path
+ context(str | None): URI request path
Returns:
bool: True in case if user is allowed to do this request and False otherwise
diff --git a/src/ahriman/core/auth/mapping.py b/src/ahriman/core/auth/mapping.py
index 8a9f4ed3..00991230 100644
--- a/src/ahriman/core/auth/mapping.py
+++ b/src/ahriman/core/auth/mapping.py
@@ -17,8 +17,6 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-from typing import Optional
-
from ahriman.core.auth import Auth
from ahriman.core.configuration import Configuration
from ahriman.core.database import SQLite
@@ -50,13 +48,13 @@ class Mapping(Auth):
self.database = database
self.salt = configuration.get("auth", "salt")
- async def check_credentials(self, username: Optional[str], password: Optional[str]) -> bool:
+ async def check_credentials(self, username: str | None, password: str | None) -> bool:
"""
validate user password
Args:
- username(Optional[str]): username
- password(Optional[str]): entered password
+ username(str | None): username
+ password(str | None): entered password
Returns:
bool: True in case if password matches, False otherwise
@@ -66,7 +64,7 @@ class Mapping(Auth):
user = self.get_user(username)
return user is not None and user.check_credentials(password, self.salt)
- def get_user(self, username: str) -> Optional[User]:
+ def get_user(self, username: str) -> User | None:
"""
retrieve user from in-memory mapping
@@ -74,30 +72,30 @@ class Mapping(Auth):
username(str): username
Returns:
- Optional[User]: user descriptor if username is known and None otherwise
+ User | None: user descriptor if username is known and None otherwise
"""
return self.database.user_get(username)
- async def known_username(self, username: Optional[str]) -> bool:
+ async def known_username(self, username: str | None) -> bool:
"""
check if user is known
Args:
- username(Optional[str]): username
+ username(str | None): username
Returns:
bool: True in case if user is known and can be authorized and False otherwise
"""
return username is not None and self.get_user(username) is not None
- async def verify_access(self, username: str, required: UserAccess, context: Optional[str]) -> bool:
+ async def verify_access(self, username: str, required: UserAccess, context: str | None) -> bool:
"""
validate if user has access to requested resource
Args:
username(str): username
required(UserAccess): required access level
- context(Optional[str]): URI request path
+ context(str | None): URI request path
Returns:
bool: True in case if user is allowed to do this request and False otherwise
diff --git a/src/ahriman/core/auth/oauth.py b/src/ahriman/core/auth/oauth.py
index 6628375e..e9456f16 100644
--- a/src/ahriman/core/auth/oauth.py
+++ b/src/ahriman/core/auth/oauth.py
@@ -19,8 +19,6 @@
#
import aioauth_client
-from typing import Optional, Type
-
from ahriman.core.auth.mapping import Mapping
from ahriman.core.configuration import Configuration
from ahriman.core.database import SQLite
@@ -72,7 +70,7 @@ class OAuth(Mapping):
return """ login"""
@staticmethod
- def get_provider(name: str) -> Type[aioauth_client.OAuth2Client]:
+ def get_provider(name: str) -> type[aioauth_client.OAuth2Client]:
"""
load OAuth2 provider by name
@@ -80,12 +78,12 @@ class OAuth(Mapping):
name(str): name of the provider. Must be valid class defined in aioauth-client library
Returns:
- Type[aioauth_client.OAuth2Client]: loaded provider type
+ type[aioauth_client.OAuth2Client]: loaded provider type
Raises:
InvalidOption: in case if invalid OAuth provider name supplied
"""
- provider: Type[aioauth_client.OAuth2Client] = getattr(aioauth_client, name)
+ provider: type[aioauth_client.OAuth2Client] = getattr(aioauth_client, name)
try:
is_oauth2_client = issubclass(provider, aioauth_client.OAuth2Client)
except TypeError: # what if it is random string?
@@ -114,7 +112,7 @@ class OAuth(Mapping):
uri: str = client.get_authorize_url(scope=self.scopes, redirect_uri=self.redirect_uri)
return uri
- async def get_oauth_username(self, code: str) -> Optional[str]:
+ async def get_oauth_username(self, code: str) -> str | None:
"""
extract OAuth username from remote
@@ -122,7 +120,7 @@ class OAuth(Mapping):
code(str): authorization code provided by external service
Returns:
- Optional[str]: username as is in OAuth provider
+ str | None: username as is in OAuth provider
"""
try:
client = self.get_client()
diff --git a/src/ahriman/core/build_tools/sources.py b/src/ahriman/core/build_tools/sources.py
index ab43b9c3..93d90c06 100644
--- a/src/ahriman/core/build_tools/sources.py
+++ b/src/ahriman/core/build_tools/sources.py
@@ -20,7 +20,6 @@
import shutil
from pathlib import Path
-from typing import List, Optional
from ahriman.core.log import LazyLogging
from ahriman.core.util import check_output, utcnow, walk
@@ -44,7 +43,7 @@ class Sources(LazyLogging):
_check_output = check_output
@staticmethod
- def extend_architectures(sources_dir: Path, architecture: str) -> List[PkgbuildPatch]:
+ def extend_architectures(sources_dir: Path, architecture: str) -> list[PkgbuildPatch]:
"""
extend existing PKGBUILD with repository architecture
@@ -53,7 +52,7 @@ class Sources(LazyLogging):
architecture(str): repository architecture
Returns:
- List[PkgbuildPatch]: generated patch for PKGBUILD architectures if required
+ list[PkgbuildPatch]: generated patch for PKGBUILD architectures if required
"""
architectures = Package.supported_architectures(sources_dir)
if "any" in architectures: # makepkg does not like when there is any other arch except for any
@@ -62,13 +61,13 @@ class Sources(LazyLogging):
return [PkgbuildPatch("arch", list(architectures))]
@staticmethod
- def fetch(sources_dir: Path, remote: Optional[RemoteSource]) -> None:
+ def fetch(sources_dir: Path, remote: RemoteSource | None) -> None:
"""
either clone repository or update it to origin/``remote.branch``
Args:
sources_dir(Path): local path to fetch
- remote(Optional[RemoteSource]): remote target (from where to fetch)
+ remote(RemoteSource | None): remote target (from where to fetch)
"""
instance = Sources()
# local directory exists and there is .git directory
@@ -127,14 +126,14 @@ class Sources(LazyLogging):
cwd=sources_dir, logger=instance.logger)
@staticmethod
- def load(sources_dir: Path, package: Package, patches: List[PkgbuildPatch], paths: RepositoryPaths) -> None:
+ def load(sources_dir: Path, package: Package, patches: list[PkgbuildPatch], paths: RepositoryPaths) -> None:
"""
fetch sources from remote and apply patches
Args:
sources_dir(Path): local path to fetch
package(Package): package definitions
- patches(List[PkgbuildPatch]): optional patch to be applied
+ patches(list[PkgbuildPatch]): optional patch to be applied
paths(RepositoryPaths): repository paths instance
"""
instance = Sources()
@@ -165,7 +164,7 @@ class Sources(LazyLogging):
return f"{diff}\n" # otherwise, patch will be broken
@staticmethod
- def push(sources_dir: Path, remote: RemoteSource, *pattern: str, commit_author: Optional[str] = None) -> None:
+ def push(sources_dir: Path, remote: RemoteSource, *pattern: str, commit_author: str | None = None) -> None:
"""
commit selected changes and push files to the remote repository
@@ -173,7 +172,7 @@ class Sources(LazyLogging):
sources_dir(Path): local path to git repository
remote(RemoteSource): remote target, branch and url
*pattern(str): glob patterns
- commit_author(Optional[str], optional): commit author in form of git config (i.e. ``user ``)
+ commit_author(str | None, optional): commit author in form of git config (i.e. ``user ``)
(Default value = None)
"""
instance = Sources()
@@ -192,7 +191,7 @@ class Sources(LazyLogging):
--intent-to-add git flag (Default value = False)
"""
# glob directory to find files which match the specified patterns
- found_files: List[Path] = []
+ found_files: list[Path] = []
for glob in pattern:
found_files.extend(sources_dir.glob(glob))
if not found_files:
@@ -203,15 +202,15 @@ class Sources(LazyLogging):
Sources._check_output("git", "add", *args, *[str(fn.relative_to(sources_dir)) for fn in found_files],
cwd=sources_dir, logger=self.logger)
- def commit(self, sources_dir: Path, message: Optional[str] = None, author: Optional[str] = None) -> None:
+ def commit(self, sources_dir: Path, message: str | None = None, author: str | None = None) -> None:
"""
commit changes
Args:
sources_dir(Path): local path to git repository
- message(Optional[str], optional): optional commit message if any. If none set, message will be generated
+ message(str | None, optional): optional commit message if any. If none set, message will be generated
according to the current timestamp (Default value = None)
- author(Optional[str], optional): optional commit author if any (Default value = None)
+ author(str | None, optional): optional commit author if any (Default value = None)
"""
if message is None:
message = f"Autogenerated commit at {utcnow()}"
diff --git a/src/ahriman/core/build_tools/task.py b/src/ahriman/core/build_tools/task.py
index f5ee165a..84255f34 100644
--- a/src/ahriman/core/build_tools/task.py
+++ b/src/ahriman/core/build_tools/task.py
@@ -18,7 +18,6 @@
# along with this program. If not, see .
#
from pathlib import Path
-from typing import List
from ahriman.core.build_tools.sources import Sources
from ahriman.core.configuration import Configuration
@@ -60,7 +59,7 @@ class Task(LazyLogging):
self.makepkg_flags = configuration.getlist("build", "makepkg_flags", fallback=[])
self.makechrootpkg_flags = configuration.getlist("build", "makechrootpkg_flags", fallback=[])
- def build(self, sources_dir: Path) -> List[Path]:
+ def build(self, sources_dir: Path) -> list[Path]:
"""
run package build
@@ -68,7 +67,7 @@ class Task(LazyLogging):
sources_dir(Path): path to where sources are
Returns:
- List[Path]: paths of produced packages
+ list[Path]: paths of produced packages
"""
command = [self.build_command, "-r", str(self.paths.chroot)]
command.extend(self.archbuild_flags)
diff --git a/src/ahriman/core/configuration/configuration.py b/src/ahriman/core/configuration/configuration.py
index 7f9532b7..2ee49642 100644
--- a/src/ahriman/core/configuration/configuration.py
+++ b/src/ahriman/core/configuration/configuration.py
@@ -23,8 +23,9 @@ import configparser
import shlex
import sys
+from collections.abc import Callable
from pathlib import Path
-from typing import Any, Callable, Dict, List, Optional, Tuple, Type
+from typing import Any
from ahriman.core.exceptions import InitializeError
from ahriman.models.repository_paths import RepositoryPaths
@@ -35,11 +36,11 @@ class Configuration(configparser.RawConfigParser):
extension for built-in configuration parser
Attributes:
- ARCHITECTURE_SPECIFIC_SECTIONS(List[str]): (class attribute) known sections which can be architecture specific.
+ ARCHITECTURE_SPECIFIC_SECTIONS(list[str]): (class attribute) known sections which can be architecture specific.
Required by dump and merging functions
SYSTEM_CONFIGURATION_PATH(Path): (class attribute) default system configuration path distributed by package
- architecture(Optional[str]): repository architecture
- path(Optional[Path]): path to root configuration file
+ architecture(str | None): repository architecture
+ path(Path | None): path to root configuration file
Examples:
Configuration class provides additional method in order to handle application configuration. Since this class is
@@ -63,7 +64,7 @@ class Configuration(configparser.RawConfigParser):
ARCHITECTURE_SPECIFIC_SECTIONS = ["alpm", "build", "sign", "web"]
SYSTEM_CONFIGURATION_PATH = Path(sys.prefix) / "share" / "ahriman" / "settings" / "ahriman.ini"
- converters: Dict[str, Callable[[str], Any]] # typing guard
+ converters: dict[str, Callable[[str], Any]] # typing guard
def __init__(self, allow_no_value: bool = False) -> None:
"""
@@ -77,8 +78,8 @@ class Configuration(configparser.RawConfigParser):
"list": shlex.split,
"path": self._convert_path,
})
- self.architecture: Optional[str] = None
- self.path: Optional[Path] = None
+ self.architecture: str | None = None
+ self.path: Path | None = None
@property
def include(self) -> Path:
@@ -112,7 +113,7 @@ class Configuration(configparser.RawConfigParser):
return RepositoryPaths(self.getpath("repository", "root"), architecture)
@classmethod
- def from_path(cls: Type[Configuration], path: Path, architecture: str) -> Configuration:
+ def from_path(cls: type[Configuration], path: Path, architecture: str) -> Configuration:
"""
constructor with full object initialization
@@ -157,12 +158,12 @@ class Configuration(configparser.RawConfigParser):
return path
return self.path.parent / path
- def check_loaded(self) -> Tuple[Path, str]:
+ def check_loaded(self) -> tuple[Path, str]:
"""
check if service was actually loaded
Returns:
- Tuple[Path, str]: configuration root path and architecture if loaded
+ tuple[Path, str]: configuration root path and architecture if loaded
Raises:
InitializeError: in case if architecture and/or path are not set
@@ -171,12 +172,12 @@ class Configuration(configparser.RawConfigParser):
raise InitializeError("Configuration path and/or architecture are not set")
return self.path, self.architecture
- def dump(self) -> Dict[str, Dict[str, str]]:
+ def dump(self) -> dict[str, dict[str, str]]:
"""
dump configuration to dictionary
Returns:
- Dict[str, Dict[str, str]]: configuration dump for specific architecture
+ dict[str, dict[str, str]]: configuration dump for specific architecture
"""
return {
section: dict(self[section])
@@ -185,11 +186,11 @@ class Configuration(configparser.RawConfigParser):
# pylint and mypy are too stupid to find these methods
# pylint: disable=missing-function-docstring,multiple-statements,unused-argument
- def getlist(self, *args: Any, **kwargs: Any) -> List[str]: ... # type: ignore
+ def getlist(self, *args: Any, **kwargs: Any) -> list[str]: ... # type: ignore
def getpath(self, *args: Any, **kwargs: Any) -> Path: ... # type: ignore
- def gettype(self, section: str, architecture: str, *, fallback: Optional[str] = None) -> Tuple[str, str]:
+ def gettype(self, section: str, architecture: str, *, fallback: str | None = None) -> tuple[str, str]:
"""
get type variable with fallback to old logic. Despite the fact that it has same semantics as other get* methods,
but it has different argument list
@@ -197,11 +198,11 @@ class Configuration(configparser.RawConfigParser):
Args:
section(str): section name
architecture(str): repository architecture
- fallback(Optional[str], optional): optional fallback type if any. If set, second element of the tuple will
+ fallback(str | None, optional): optional fallback type if any. If set, second element of the tuple will
be always set to this value (Default value = None)
Returns:
- Tuple[str, str]: section name and found type name
+ tuple[str, str]: section name and found type name
Raises:
configparser.NoSectionError: in case if no section found
diff --git a/src/ahriman/core/configuration/schema.py b/src/ahriman/core/configuration/schema.py
index 3ca3a422..e490d459 100644
--- a/src/ahriman/core/configuration/schema.py
+++ b/src/ahriman/core/configuration/schema.py
@@ -17,13 +17,13 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-from typing import Any, Dict
+from typing import Any
__all__ = ["CONFIGURATION_SCHEMA", "ConfigurationSchema"]
-ConfigurationSchema = Dict[str, Dict[str, Any]]
+ConfigurationSchema = dict[str, dict[str, Any]]
CONFIGURATION_SCHEMA: ConfigurationSchema = {
diff --git a/src/ahriman/core/configuration/validator.py b/src/ahriman/core/configuration/validator.py
index 8976727f..26011391 100644
--- a/src/ahriman/core/configuration/validator.py
+++ b/src/ahriman/core/configuration/validator.py
@@ -21,7 +21,7 @@ import ipaddress
from cerberus import TypeDefinition, Validator as RootValidator # type: ignore
from pathlib import Path
-from typing import Any, List
+from typing import Any
from urllib.parse import urlparse
from ahriman.core.configuration import Configuration
@@ -90,7 +90,7 @@ class Validator(RootValidator):
del self
return int(value)
- def _normalize_coerce_list(self, value: str) -> List[str]:
+ def _normalize_coerce_list(self, value: str) -> list[str]:
"""
extract string list from string value
@@ -98,17 +98,17 @@ class Validator(RootValidator):
value(str): converting value
Returns:
- List[str]: value converted to string list instance according to configuration rules
+ list[str]: value converted to string list instance according to configuration rules
"""
- converted: List[str] = self.configuration.converters["list"](value)
+ converted: list[str] = self.configuration.converters["list"](value)
return converted
- def _validate_is_ip_address(self, constraint: List[str], field: str, value: str) -> None:
+ def _validate_is_ip_address(self, constraint: list[str], field: str, value: str) -> None:
"""
check if the specified value is valid ip address
Args:
- constraint(List[str]): optional list of allowed special words (e.g. ``localhost``)
+ constraint(list[str]): optional list of allowed special words (e.g. ``localhost``)
field(str): field name to be checked
value(Path): value to be checked
@@ -123,12 +123,12 @@ class Validator(RootValidator):
except ValueError:
self._error(field, f"Value {value} must be valid IP address")
- def _validate_is_url(self, constraint: List[str], field: str, value: str) -> None:
+ def _validate_is_url(self, constraint: list[str], field: str, value: str) -> None:
"""
check if the specified value is a valid url
Args:
- constraint(List[str]): optional list of supported schemas. If empty, no schema validation will be performed
+ constraint(list[str]): optional list of supported schemas. If empty, no schema validation will be performed
field(str): field name to be checked
value(str): value to be checked
diff --git a/src/ahriman/core/database/migrations/__init__.py b/src/ahriman/core/database/migrations/__init__.py
index 76bc8d7b..72df8146 100644
--- a/src/ahriman/core/database/migrations/__init__.py
+++ b/src/ahriman/core/database/migrations/__init__.py
@@ -17,11 +17,11 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
+from collections.abc import Callable
from importlib import import_module
from pathlib import Path
from pkgutil import iter_modules
from sqlite3 import Connection, Cursor
-from typing import Callable, List
from ahriman.core.configuration import Configuration
from ahriman.core.log import LazyLogging
@@ -83,22 +83,22 @@ class Migrations(LazyLogging):
"data migration %s at index %s has been performed",
migration.name, migration.index)
- def migrations(self) -> List[Migration]:
+ def migrations(self) -> list[Migration]:
"""
extract all migrations from the current package
idea comes from https://julienharbulot.com/python-dynamical-import.html
Returns:
- List[Migration]: list of found migrations
+ list[Migration]: list of found migrations
"""
- migrations: List[Migration] = []
+ migrations: list[Migration] = []
package_dir = Path(__file__).resolve().parent
modules = [module_name for (_, module_name, _) in iter_modules([str(package_dir)])]
for index, module_name in enumerate(sorted(modules)):
module = import_module(f"{__name__}.{module_name}")
- steps: List[str] = getattr(module, "steps", [])
+ steps: list[str] = getattr(module, "steps", [])
self.logger.debug("found migration %s at index %s with steps count %s", module_name, index, len(steps))
migrate_data: Callable[[Connection, Configuration], None] = \
diff --git a/src/ahriman/core/database/operations/auth_operations.py b/src/ahriman/core/database/operations/auth_operations.py
index 6e26464c..67270352 100644
--- a/src/ahriman/core/database/operations/auth_operations.py
+++ b/src/ahriman/core/database/operations/auth_operations.py
@@ -18,7 +18,6 @@
# along with this program. If not, see .
#
from sqlite3 import Connection
-from typing import List, Optional
from ahriman.core.database.operations import Operations
from ahriman.models.user import User
@@ -30,7 +29,7 @@ class AuthOperations(Operations):
authorization operations
"""
- def user_get(self, username: str) -> Optional[User]:
+ def user_get(self, username: str) -> User | None:
"""
get user by username
@@ -38,25 +37,25 @@ class AuthOperations(Operations):
username(str): username
Returns:
- Optional[User]: user if it was found
+ User | None: user if it was found
"""
return next(iter(self.user_list(username, None)), None)
- def user_list(self, username: Optional[str], access: Optional[UserAccess]) -> List[User]:
+ def user_list(self, username: str | None, access: UserAccess | None) -> list[User]:
"""
get users by filter
Args:
- username(Optional[str]): optional filter by username
- access(Optional[UserAccess]): optional filter by role
+ username(str | None): optional filter by username
+ access(UserAccess | None): optional filter by role
Returns:
- List[User]: list of users who match criteria
+ list[User]: list of users who match criteria
"""
username_filter = username.lower() if username is not None else username
access_filter = access.value if access is not None else access
- def run(connection: Connection) -> List[User]:
+ def run(connection: Connection) -> list[User]:
return [
User(username=cursor["username"], password=cursor["password"], access=UserAccess(cursor["access"]))
for cursor in connection.execute(
diff --git a/src/ahriman/core/database/operations/build_operations.py b/src/ahriman/core/database/operations/build_operations.py
index ae6a9898..13e33e1d 100644
--- a/src/ahriman/core/database/operations/build_operations.py
+++ b/src/ahriman/core/database/operations/build_operations.py
@@ -18,7 +18,6 @@
# along with this program. If not, see .
#
from sqlite3 import Connection
-from typing import List, Optional
from ahriman.core.database.operations import Operations
from ahriman.models.package import Package
@@ -29,12 +28,12 @@ class BuildOperations(Operations):
operations for build queue functions
"""
- def build_queue_clear(self, package_base: Optional[str]) -> None:
+ def build_queue_clear(self, package_base: str | None) -> None:
"""
remove packages from build queue
Args:
- package_base(Optional[str]): optional filter by package base
+ package_base(str | None): optional filter by package base
"""
def run(connection: Connection) -> None:
connection.execute(
@@ -46,14 +45,14 @@ class BuildOperations(Operations):
return self.with_connection(run, commit=True)
- def build_queue_get(self) -> List[Package]:
+ def build_queue_get(self) -> list[Package]:
"""
retrieve packages from build queue
Return:
- List[Package]: list of packages to be built
+ list[Package]: list of packages to be built
"""
- def run(connection: Connection) -> List[Package]:
+ def run(connection: Connection) -> list[Package]:
return [
Package.from_json(row["properties"])
for row in connection.execute("""select * from build_queue""")
diff --git a/src/ahriman/core/database/operations/logs_operations.py b/src/ahriman/core/database/operations/logs_operations.py
index 2d3f317c..e9365eb7 100644
--- a/src/ahriman/core/database/operations/logs_operations.py
+++ b/src/ahriman/core/database/operations/logs_operations.py
@@ -18,7 +18,6 @@
# along with this program. If not, see .
#
from sqlite3 import Connection
-from typing import List, Optional
from ahriman.core.database.operations import Operations
from ahriman.core.util import pretty_datetime
@@ -40,7 +39,7 @@ class LogsOperations(Operations):
Return:
str: full package log
"""
- def run(connection: Connection) -> List[str]:
+ def run(connection: Connection) -> list[str]:
return [
f"""[{pretty_datetime(row["created"])}] {row["record"]}"""
for row in connection.execute(
@@ -81,13 +80,13 @@ class LogsOperations(Operations):
return self.with_connection(run, commit=True)
- def logs_remove(self, package_base: str, current_process_id: Optional[int]) -> None:
+ def logs_remove(self, package_base: str, current_process_id: int | None) -> None:
"""
remove log records for the specified package
Args:
package_base(str): package base to remove logs
- current_process_id(Optional[int]): current process id. If set it will remove only logs belonging to another
+ current_process_id(int | None): current process id. If set it will remove only logs belonging to another
process
"""
def run(connection: Connection) -> None:
diff --git a/src/ahriman/core/database/operations/operations.py b/src/ahriman/core/database/operations/operations.py
index a6738773..9a447adf 100644
--- a/src/ahriman/core/database/operations/operations.py
+++ b/src/ahriman/core/database/operations/operations.py
@@ -19,8 +19,9 @@
#
import sqlite3
+from collections.abc import Callable
from pathlib import Path
-from typing import Any, Callable, Dict, Tuple, TypeVar
+from typing import Any, TypeVar
from ahriman.core.log import LazyLogging
@@ -46,16 +47,16 @@ class Operations(LazyLogging):
self.path = path
@staticmethod
- def factory(cursor: sqlite3.Cursor, row: Tuple[Any, ...]) -> Dict[str, Any]:
+ def factory(cursor: sqlite3.Cursor, row: tuple[Any, ...]) -> dict[str, Any]:
"""
dictionary factory based on official documentation
Args:
cursor(Cursor): cursor descriptor
- row(Tuple[Any, ...]): fetched row
+ row(tuple[Any, ...]): fetched row
Returns:
- Dict[str, Any]: row converted to dictionary
+ dict[str, Any]: row converted to dictionary
"""
result = {}
for index, column in enumerate(cursor.description):
diff --git a/src/ahriman/core/database/operations/package_operations.py b/src/ahriman/core/database/operations/package_operations.py
index e54d3192..c6b10d18 100644
--- a/src/ahriman/core/database/operations/package_operations.py
+++ b/src/ahriman/core/database/operations/package_operations.py
@@ -17,8 +17,8 @@
# 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 sqlite3 import Connection
-from typing import Dict, Generator, Iterable, List, Tuple
from ahriman.core.database.operations import Operations
from ahriman.models.build_status import BuildStatus
@@ -148,7 +148,7 @@ class PackageOperations(Operations):
{"package_base": package_base, "status": status.status.value, "last_updated": status.timestamp})
@staticmethod
- def _packages_get_select_package_bases(connection: Connection) -> Dict[str, Package]:
+ def _packages_get_select_package_bases(connection: Connection) -> dict[str, Package]:
"""
select package bases from the table
@@ -156,7 +156,7 @@ class PackageOperations(Operations):
connection(Connection): database connection
Returns:
- Dict[str, Package]: map of the package base to its descriptor (without packages themselves)
+ dict[str, Package]: map of the package base to its descriptor (without packages themselves)
"""
return {
row["package_base"]: Package(
@@ -168,16 +168,16 @@ class PackageOperations(Operations):
}
@staticmethod
- def _packages_get_select_packages(connection: Connection, packages: Dict[str, Package]) -> Dict[str, Package]:
+ def _packages_get_select_packages(connection: Connection, packages: dict[str, Package]) -> dict[str, Package]:
"""
select packages from the table
Args:
connection(Connection): database connection
- packages(Dict[str, Package]): packages descriptor map
+ packages(dict[str, Package]): packages descriptor map
Returns:
- Dict[str, Package]: map of the package base to its descriptor including individual packages
+ dict[str, Package]: map of the package base to its descriptor including individual packages
"""
for row in connection.execute("""select * from packages"""):
if row["package_base"] not in packages:
@@ -186,7 +186,7 @@ class PackageOperations(Operations):
return packages
@staticmethod
- def _packages_get_select_statuses(connection: Connection) -> Dict[str, BuildStatus]:
+ def _packages_get_select_statuses(connection: Connection) -> dict[str, BuildStatus]:
"""
select package build statuses from the table
@@ -194,7 +194,7 @@ class PackageOperations(Operations):
connection(Connection): database connection
Returns:
- Dict[str, BuildStatus]: map of the package base to its status
+ dict[str, BuildStatus]: map of the package base to its status
"""
return {
row["package_base"]: BuildStatus.from_json({"status": row["status"], "timestamp": row["last_updated"]})
@@ -230,14 +230,14 @@ class PackageOperations(Operations):
return self.with_connection(run, commit=True)
- def packages_get(self) -> List[Tuple[Package, BuildStatus]]:
+ def packages_get(self) -> list[tuple[Package, BuildStatus]]:
"""
get package list and their build statuses from database
Return:
- List[Tuple[Package, BuildStatus]]: list of package properties and their statuses
+ list[tuple[Package, BuildStatus]]: list of package properties and their statuses
"""
- def run(connection: Connection) -> Generator[Tuple[Package, BuildStatus], None, None]:
+ def run(connection: Connection) -> Generator[tuple[Package, BuildStatus], None, None]:
packages = self._packages_get_select_package_bases(connection)
statuses = self._packages_get_select_statuses(connection)
for package_base, package in self._packages_get_select_packages(connection, packages).items():
@@ -256,12 +256,12 @@ class PackageOperations(Operations):
lambda connection: self._package_update_insert_base(connection, package),
commit=True)
- def remotes_get(self) -> Dict[str, RemoteSource]:
+ def remotes_get(self) -> dict[str, RemoteSource]:
"""
get packages remotes based on current settings
Returns:
- Dict[str, RemoteSource]: map of package base to its remote sources
+ dict[str, RemoteSource]: map of package base to its remote sources
"""
packages = self.with_connection(self._packages_get_select_package_bases)
return {
diff --git a/src/ahriman/core/database/operations/patch_operations.py b/src/ahriman/core/database/operations/patch_operations.py
index 7febb304..5cfd0cc4 100644
--- a/src/ahriman/core/database/operations/patch_operations.py
+++ b/src/ahriman/core/database/operations/patch_operations.py
@@ -20,7 +20,6 @@
from collections import defaultdict
from sqlite3 import Connection
-from typing import Dict, List, Optional, Tuple
from ahriman.core.database.operations import Operations
from ahriman.models.pkgbuild_patch import PkgbuildPatch
@@ -31,7 +30,7 @@ class PatchOperations(Operations):
operations for patches
"""
- def patches_get(self, package_base: str) -> List[PkgbuildPatch]:
+ def patches_get(self, package_base: str) -> list[PkgbuildPatch]:
"""
retrieve patches for the package
@@ -39,7 +38,7 @@ class PatchOperations(Operations):
package_base(str): package base to search for patches
Returns:
- List[PkgbuildPatch]: plain text patch for the package
+ list[PkgbuildPatch]: plain text patch for the package
"""
return self.patches_list(package_base, []).get(package_base, [])
@@ -65,18 +64,18 @@ class PatchOperations(Operations):
return self.with_connection(run, commit=True)
- def patches_list(self, package_base: Optional[str], variables: List[str]) -> Dict[str, List[PkgbuildPatch]]:
+ def patches_list(self, package_base: str | None, variables: list[str]) -> dict[str, list[PkgbuildPatch]]:
"""
extract all patches
Args:
- package_base(Optional[str]): optional filter by package base
- variables(List[str]): extract patches only for specified PKGBUILD variables
+ package_base(str | None): optional filter by package base
+ variables(list[str]): extract patches only for specified PKGBUILD variables
Returns:
- Dict[str, List[PkgbuildPatch]]: map of package base to patch content
+ dict[str, list[PkgbuildPatch]]: map of package base to patch content
"""
- def run(connection: Connection) -> List[Tuple[str, PkgbuildPatch]]:
+ def run(connection: Connection) -> list[tuple[str, PkgbuildPatch]]:
return [
(cursor["package_base"], PkgbuildPatch(cursor["variable"], cursor["patch"]))
for cursor in connection.execute(
@@ -85,20 +84,20 @@ class PatchOperations(Operations):
]
# we could use itertools & operator but why?
- patches: Dict[str, List[PkgbuildPatch]] = defaultdict(list)
+ patches: dict[str, list[PkgbuildPatch]] = defaultdict(list)
for package, patch in self.with_connection(run):
if variables and patch.key not in variables:
continue
patches[package].append(patch)
return dict(patches)
- def patches_remove(self, package_base: str, variables: List[str]) -> None:
+ def patches_remove(self, package_base: str, variables: list[str]) -> None:
"""
remove patch set
Args:
package_base(str): package base to clear patches
- variables(List[str]): remove patches only for specified PKGBUILD variables
+ variables(list[str]): remove patches only for specified PKGBUILD variables
"""
def run_many(connection: Connection) -> None:
connection.executemany(
diff --git a/src/ahriman/core/database/sqlite.py b/src/ahriman/core/database/sqlite.py
index 83f875a6..eb68b761 100644
--- a/src/ahriman/core/database/sqlite.py
+++ b/src/ahriman/core/database/sqlite.py
@@ -23,7 +23,6 @@ import json
import sqlite3
from pathlib import Path
-from typing import Type
from ahriman.core.configuration import Configuration
from ahriman.core.database.migrations import Migrations
@@ -47,7 +46,7 @@ class SQLite(AuthOperations, BuildOperations, LogsOperations, PackageOperations,
"""
@classmethod
- def load(cls: Type[SQLite], configuration: Configuration) -> SQLite:
+ def load(cls: type[SQLite], configuration: Configuration) -> SQLite:
"""
construct instance from configuration
diff --git a/src/ahriman/core/formatters/aur_printer.py b/src/ahriman/core/formatters/aur_printer.py
index 974fe54b..649223c1 100644
--- a/src/ahriman/core/formatters/aur_printer.py
+++ b/src/ahriman/core/formatters/aur_printer.py
@@ -17,8 +17,6 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-from typing import List
-
from ahriman.core.formatters import StringPrinter
from ahriman.core.util import pretty_datetime
from ahriman.models.aur_package import AURPackage
@@ -43,12 +41,12 @@ class AurPrinter(StringPrinter):
StringPrinter.__init__(self, f"{package.name} {package.version} ({package.num_votes})")
self.package = package
- def properties(self) -> List[Property]:
+ def properties(self) -> list[Property]:
"""
convert content into printable data
Returns:
- List[Property]: list of content properties
+ list[Property]: list of content properties
"""
return [
Property("Package base", self.package.package_base),
diff --git a/src/ahriman/core/formatters/configuration_printer.py b/src/ahriman/core/formatters/configuration_printer.py
index 8116f429..c76b19ab 100644
--- a/src/ahriman/core/formatters/configuration_printer.py
+++ b/src/ahriman/core/formatters/configuration_printer.py
@@ -17,8 +17,6 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-from typing import Dict, List
-
from ahriman.core.formatters import StringPrinter
from ahriman.models.property import Property
@@ -28,9 +26,9 @@ class ConfigurationPrinter(StringPrinter):
print content of the configuration section
Attributes:
- HIDE_KEYS(List[str]): (class attribute) hide values for mentioned keys. This list must be used in order to hide
+ HIDE_KEYS(list[str]): (class attribute) hide values for mentioned keys. This list must be used in order to hide
passwords from outputs
- values(Dict[str, str]): configuration values dictionary
+ values(dict[str, str]): configuration values dictionary
"""
HIDE_KEYS = [
@@ -42,23 +40,23 @@ class ConfigurationPrinter(StringPrinter):
"secret_key", # aws secret key
]
- def __init__(self, section: str, values: Dict[str, str]) -> None:
+ def __init__(self, section: str, values: dict[str, str]) -> None:
"""
default constructor
Args:
section(str): section name
- values(Dict[str, str]): configuration values dictionary
+ values(dict[str, str]): configuration values dictionary
"""
StringPrinter.__init__(self, f"[{section}]")
self.values = values
- def properties(self) -> List[Property]:
+ def properties(self) -> list[Property]:
"""
convert content into printable data
Returns:
- List[Property]: list of content properties
+ list[Property]: list of content properties
"""
return [
Property(key, value, is_required=key not in self.HIDE_KEYS)
diff --git a/src/ahriman/core/formatters/package_printer.py b/src/ahriman/core/formatters/package_printer.py
index b02da4b7..0cddf9b1 100644
--- a/src/ahriman/core/formatters/package_printer.py
+++ b/src/ahriman/core/formatters/package_printer.py
@@ -17,8 +17,6 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-from typing import List
-
from ahriman.core.formatters import StringPrinter
from ahriman.models.build_status import BuildStatus
from ahriman.models.package import Package
@@ -46,12 +44,12 @@ class PackagePrinter(StringPrinter):
self.package = package
self.status = status
- def properties(self) -> List[Property]:
+ def properties(self) -> list[Property]:
"""
convert content into printable data
Returns:
- List[Property]: list of content properties
+ list[Property]: list of content properties
"""
return [
Property("Version", self.package.version, is_required=True),
diff --git a/src/ahriman/core/formatters/patch_printer.py b/src/ahriman/core/formatters/patch_printer.py
index 517d11b6..ba04074a 100644
--- a/src/ahriman/core/formatters/patch_printer.py
+++ b/src/ahriman/core/formatters/patch_printer.py
@@ -17,8 +17,6 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-from typing import List
-
from ahriman.core.formatters import StringPrinter
from ahriman.models.pkgbuild_patch import PkgbuildPatch
from ahriman.models.property import Property
@@ -29,26 +27,26 @@ class PatchPrinter(StringPrinter):
print content of the PKGBUILD patch
Attributes:
- patches(List[PkgbuildPatch]): PKGBUILD patch object
+ patches(list[PkgbuildPatch]): PKGBUILD patch object
"""
- def __init__(self, package_base: str, patches: List[PkgbuildPatch]) -> None:
+ def __init__(self, package_base: str, patches: list[PkgbuildPatch]) -> None:
"""
default constructor
Args:
package_base(str): package base
- patches(List[PkgbuildPatch]): PKGBUILD patch object
+ patches(list[PkgbuildPatch]): PKGBUILD patch object
"""
StringPrinter.__init__(self, package_base)
self.patches = patches
- def properties(self) -> List[Property]:
+ def properties(self) -> list[Property]:
"""
convert content into printable data
Returns:
- List[Property]: list of content properties
+ list[Property]: list of content properties
"""
return [
Property(patch.key or "Full source diff", patch.value, is_required=True)
diff --git a/src/ahriman/core/formatters/printer.py b/src/ahriman/core/formatters/printer.py
index 67dd6196..844b322e 100644
--- a/src/ahriman/core/formatters/printer.py
+++ b/src/ahriman/core/formatters/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 typing import Callable, List, Optional
+from collections.abc import Callable
from ahriman.models.property import Property
@@ -44,19 +44,19 @@ class Printer:
indent = "\t" * prop.indent
log_fn(f"{indent}{prop.name}{separator}{prop.value}")
- def properties(self) -> List[Property]:
+ def properties(self) -> list[Property]:
"""
convert content into printable data
Returns:
- List[Property]: list of content properties
+ list[Property]: list of content properties
"""
return []
- def title(self) -> Optional[str]:
+ def title(self) -> str | None:
"""
generate entry title from content
Returns:
- Optional[str]: content title if it can be generated and None otherwise
+ str | None: content title if it can be generated and None otherwise
"""
diff --git a/src/ahriman/core/formatters/string_printer.py b/src/ahriman/core/formatters/string_printer.py
index d29df4ca..ba621228 100644
--- a/src/ahriman/core/formatters/string_printer.py
+++ b/src/ahriman/core/formatters/string_printer.py
@@ -17,8 +17,6 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-from typing import Optional
-
from ahriman.core.formatters import Printer
@@ -39,11 +37,11 @@ class StringPrinter(Printer):
"""
self.content = content
- def title(self) -> Optional[str]:
+ def title(self) -> str | None:
"""
generate entry title from content
Returns:
- Optional[str]: content title if it can be generated and None otherwise
+ str | None: content title if it can be generated and None otherwise
"""
return self.content
diff --git a/src/ahriman/core/formatters/tree_printer.py b/src/ahriman/core/formatters/tree_printer.py
index 175d05f7..3a9ac902 100644
--- a/src/ahriman/core/formatters/tree_printer.py
+++ b/src/ahriman/core/formatters/tree_printer.py
@@ -17,8 +17,6 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-from typing import Iterable, List
-
from ahriman.core.formatters import StringPrinter
from ahriman.models.package import Package
from ahriman.models.property import Property
@@ -29,25 +27,25 @@ class TreePrinter(StringPrinter):
print content of the package tree level
Attributes:
- packages(Iterable[Package]): packages which belong to this level
+ packages(list[Package]): packages which belong to this level
"""
- def __init__(self, level: int, packages: Iterable[Package]) -> None:
+ def __init__(self, level: int, packages: list[Package]) -> None:
"""
default constructor
Args:
level(int): dependencies tree level
- packages(Iterable[Package]): packages which belong to this level
+ packages(list[Package]): packages which belong to this level
"""
StringPrinter.__init__(self, f"level {level}")
self.packages = packages
- def properties(self) -> List[Property]:
+ def properties(self) -> list[Property]:
"""
convert content into printable data
Returns:
- List[Property]: list of content properties
+ list[Property]: list of content properties
"""
return [Property(package.base, package.version, is_required=True) for package in self.packages]
diff --git a/src/ahriman/core/formatters/update_printer.py b/src/ahriman/core/formatters/update_printer.py
index f1f277f2..09f499f2 100644
--- a/src/ahriman/core/formatters/update_printer.py
+++ b/src/ahriman/core/formatters/update_printer.py
@@ -17,8 +17,6 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-from typing import List, Optional
-
from ahriman.core.formatters import StringPrinter
from ahriman.models.package import Package
from ahriman.models.property import Property
@@ -30,26 +28,26 @@ class UpdatePrinter(StringPrinter):
Attributes:
package(Package): remote (new) package object
- local_version(Optional[str]): local version of the package if any
+ local_version(str | None): local version of the package if any
"""
- def __init__(self, remote: Package, local_version: Optional[str]) -> None:
+ def __init__(self, remote: Package, local_version: str | None) -> None:
"""
default constructor
Args:
remote(Package): remote (new) package object
- local_version(Optional[str]): local version of the package if any
+ local_version(str | None): local version of the package if any
"""
StringPrinter.__init__(self, remote.base)
self.package = remote
self.local_version = local_version or "N/A"
- def properties(self) -> List[Property]:
+ def properties(self) -> list[Property]:
"""
convert content into printable data
Returns:
- List[Property]: list of content properties
+ list[Property]: list of content properties
"""
return [Property(self.local_version, self.package.version, is_required=True)]
diff --git a/src/ahriman/core/formatters/user_printer.py b/src/ahriman/core/formatters/user_printer.py
index b243ca78..52cc9406 100644
--- a/src/ahriman/core/formatters/user_printer.py
+++ b/src/ahriman/core/formatters/user_printer.py
@@ -17,8 +17,6 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-from typing import List
-
from ahriman.core.formatters import StringPrinter
from ahriman.models.property import Property
from ahriman.models.user import User
@@ -42,11 +40,11 @@ class UserPrinter(StringPrinter):
StringPrinter.__init__(self, user.username)
self.user = user
- def properties(self) -> List[Property]:
+ def properties(self) -> list[Property]:
"""
convert content into printable data
Returns:
- List[Property]: list of content properties
+ list[Property]: list of content properties
"""
return [Property("role", self.user.access.value, is_required=True)]
diff --git a/src/ahriman/core/formatters/validation_printer.py b/src/ahriman/core/formatters/validation_printer.py
index 21d0e2ee..54c4888d 100644
--- a/src/ahriman/core/formatters/validation_printer.py
+++ b/src/ahriman/core/formatters/validation_printer.py
@@ -17,7 +17,8 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-from typing import Any, Dict, Generator, List, Union
+from collections.abc import Generator
+from typing import Any
from ahriman.core.formatters import StringPrinter
from ahriman.models.property import Property
@@ -29,30 +30,30 @@ class ValidationPrinter(StringPrinter):
Attributes:
node(str): root level name
- errors(List[Union[str, Dict[str, Any]]]): validation errors
+ errors(list[str | dict[str, Any]]): validation errors
"""
- def __init__(self, node: str, errors: List[Union[str, Dict[str, Any]]]) -> None:
+ def __init__(self, node: str, errors: list[str | dict[str, Any]]) -> None:
"""
default constructor
Args:
node(str): root level name
- errors(List[Union[str, Dict[str, Any]]]): validation errors
+ errors(list[str | dict[str, Any]]): validation errors
"""
StringPrinter.__init__(self, node)
self.node = node
self.errors = errors
@staticmethod
- def get_error_messages(node: str, errors: List[Union[str, Dict[str, Any]]],
+ def get_error_messages(node: str, errors: list[str | dict[str, Any]],
current_level: int = 1) -> Generator[Property, None, None]:
"""
extract default error message from cerberus class
Args:
node(str): current node level name
- errors(List[Union[str, Dict[str, Any]]]): current node validation errors
+ errors(list[str | dict[str, Any]]): current node validation errors
current_level(int, optional): current level number (Default value = 1)
Yields:
@@ -67,11 +68,11 @@ class ValidationPrinter(StringPrinter):
else: # current node errors
yield Property(node, error, is_required=True, indent=current_level)
- def properties(self) -> List[Property]:
+ def properties(self) -> list[Property]:
"""
convert content into printable data
Returns:
- List[Property]: list of content properties
+ list[Property]: list of content properties
"""
return list(self.get_error_messages(self.node, self.errors))
diff --git a/src/ahriman/core/formatters/version_printer.py b/src/ahriman/core/formatters/version_printer.py
index 809bb169..68477dac 100644
--- a/src/ahriman/core/formatters/version_printer.py
+++ b/src/ahriman/core/formatters/version_printer.py
@@ -17,8 +17,6 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-from typing import Dict, List
-
from ahriman.core.formatters import StringPrinter
from ahriman.models.property import Property
@@ -28,26 +26,26 @@ class VersionPrinter(StringPrinter):
print content of the python package versions
Attributes:
- packages(Dict[str, str]): map of package name to its version
+ packages(dict[str, str]): map of package name to its version
"""
- def __init__(self, title: str, packages: Dict[str, str]) -> None:
+ def __init__(self, title: str, packages: dict[str, str]) -> None:
"""
default constructor
Args:
title(str): title of the message
- packages(Dict[str, str]): map of package name to its version
+ packages(dict[str, str]): map of package name to its version
"""
StringPrinter.__init__(self, title)
self.packages = packages
- def properties(self) -> List[Property]:
+ def properties(self) -> list[Property]:
"""
convert content into printable data
Returns:
- List[Property]: list of content properties
+ list[Property]: list of content properties
"""
return [
Property(package, version, is_required=True)
diff --git a/src/ahriman/core/gitremote/remote_pull_trigger.py b/src/ahriman/core/gitremote/remote_pull_trigger.py
index ed757dd5..20092c60 100644
--- a/src/ahriman/core/gitremote/remote_pull_trigger.py
+++ b/src/ahriman/core/gitremote/remote_pull_trigger.py
@@ -17,8 +17,6 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-from typing import List, Type
-
from ahriman.core.configuration import Configuration
from ahriman.core.gitremote.remote_pull import RemotePull
from ahriman.core.triggers import Trigger
@@ -29,7 +27,7 @@ class RemotePullTrigger(Trigger):
trigger based on pulling PKGBUILDs before the actions
Attributes:
- targets(List[str]): git remote target list
+ targets(list[str]): git remote target list
"""
CONFIGURATION_SCHEMA = {
@@ -70,7 +68,7 @@ class RemotePullTrigger(Trigger):
self.targets = self.configuration_sections(configuration)
@classmethod
- def configuration_sections(cls: Type[Trigger], configuration: Configuration) -> List[str]:
+ def configuration_sections(cls: type[Trigger], configuration: Configuration) -> list[str]:
"""
extract configuration sections from configuration
@@ -78,7 +76,7 @@ class RemotePullTrigger(Trigger):
configuration(Configuration): configuration instance
Returns:
- List[str]: read configuration sections belong to this trigger
+ list[str]: read configuration sections belong to this trigger
"""
return configuration.getlist("remote-pull", "target", fallback=[])
diff --git a/src/ahriman/core/gitremote/remote_push.py b/src/ahriman/core/gitremote/remote_push.py
index 401d05de..b9c4cc4d 100644
--- a/src/ahriman/core/gitremote/remote_push.py
+++ b/src/ahriman/core/gitremote/remote_push.py
@@ -19,9 +19,9 @@
#
import shutil
+from collections.abc import Generator
from pathlib import Path
from tempfile import TemporaryDirectory
-from typing import Generator
from ahriman.core.build_tools.sources import Sources
from ahriman.core.configuration import Configuration
@@ -39,7 +39,7 @@ class RemotePush(LazyLogging):
sync PKGBUILDs to remote repository after actions
Attributes:
- commit_author(Optional[str]): optional commit author in form of git config (i.e. ``user ``)
+ commit_author(str | None): optional commit author in form of git config (i.e. ``user ``)
database(SQLite): database instance
remote_source(RemoteSource): repository remote source (remote pull url and branch)
"""
diff --git a/src/ahriman/core/gitremote/remote_push_trigger.py b/src/ahriman/core/gitremote/remote_push_trigger.py
index 159adccb..8a1a10a9 100644
--- a/src/ahriman/core/gitremote/remote_push_trigger.py
+++ b/src/ahriman/core/gitremote/remote_push_trigger.py
@@ -17,8 +17,6 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-from typing import Iterable, List, Type
-
from ahriman.core import context
from ahriman.core.configuration import Configuration
from ahriman.core.database import SQLite
@@ -34,7 +32,7 @@ class RemotePushTrigger(Trigger):
trigger for syncing PKGBUILDs to remote repository
Attributes:
- targets(List[str]): git remote target list
+ targets(list[str]): git remote target list
"""
CONFIGURATION_SCHEMA = {
@@ -78,7 +76,7 @@ class RemotePushTrigger(Trigger):
self.targets = self.configuration_sections(configuration)
@classmethod
- def configuration_sections(cls: Type[Trigger], configuration: Configuration) -> List[str]:
+ def configuration_sections(cls: type[Trigger], configuration: Configuration) -> list[str]:
"""
extract configuration sections from configuration
@@ -86,17 +84,17 @@ class RemotePushTrigger(Trigger):
configuration(Configuration): configuration instance
Returns:
- List[str]: read configuration sections belong to this trigger
+ list[str]: read configuration sections belong to this trigger
"""
return configuration.getlist("remote-push", "target", fallback=[])
- def on_result(self, result: Result, packages: Iterable[Package]) -> None:
+ def on_result(self, result: Result, packages: list[Package]) -> None:
"""
trigger action which will be called after build process with process result
Args:
result(Result): build result
- packages(Iterable[Package]): list of all available packages
+ packages(list[Package]): list of all available packages
Raises:
GitRemoteError: if database is not set in context
diff --git a/src/ahriman/core/log/lazy_logging.py b/src/ahriman/core/log/lazy_logging.py
index 9af8ba64..1ad9461e 100644
--- a/src/ahriman/core/log/lazy_logging.py
+++ b/src/ahriman/core/log/lazy_logging.py
@@ -20,7 +20,8 @@
import contextlib
import logging
-from typing import Any, Generator
+from collections.abc import Generator
+from typing import Any
class LazyLogging:
diff --git a/src/ahriman/core/report/console.py b/src/ahriman/core/report/console.py
index 095b11c7..626f8094 100644
--- a/src/ahriman/core/report/console.py
+++ b/src/ahriman/core/report/console.py
@@ -17,8 +17,6 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-from typing import Iterable
-
from ahriman.core.configuration import Configuration
from ahriman.core.formatters import BuildPrinter
from ahriman.core.report.report import Report
@@ -46,12 +44,12 @@ class Console(Report):
Report.__init__(self, architecture, configuration)
self.use_utf = configuration.getboolean(section, "use_utf", fallback=True)
- def generate(self, packages: Iterable[Package], result: Result) -> None:
+ def generate(self, packages: list[Package], result: Result) -> None:
"""
generate report for the specified packages
Args:
- packages(Iterable[Package]): list of packages to generate report
+ packages(list[Package]): list of packages to generate report
result(Result): build result
"""
for package in result.success:
diff --git a/src/ahriman/core/report/email.py b/src/ahriman/core/report/email.py
index 065dc28f..e51825a4 100644
--- a/src/ahriman/core/report/email.py
+++ b/src/ahriman/core/report/email.py
@@ -21,7 +21,6 @@ import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
-from typing import Dict, Iterable
from ahriman.core.configuration import Configuration
from ahriman.core.report.jinja_template import JinjaTemplate
@@ -40,13 +39,13 @@ class Email(Report, JinjaTemplate):
full_template_path(Path): path to template for full package list
host(str): SMTP host to connect
no_empty_report(bool): skip empty report generation
- password(Optional[str]): password to authenticate via SMTP
+ password(str | None): password to authenticate via SMTP
port(int): SMTP port to connect
- receivers(List[str]): list of receivers emails
+ receivers(list[str]): list of receivers emails
sender(str): sender email address
ssl(SmtpSSLSettings): SSL mode for SMTP connection
template_path(Path): path to template for built packages
- user(Optional[str]): username to authenticate via SMTP
+ user(str | None): username to authenticate via SMTP
"""
def __init__(self, architecture: str, configuration: Configuration, section: str) -> None:
@@ -74,13 +73,13 @@ class Email(Report, JinjaTemplate):
self.ssl = SmtpSSLSettings.from_option(configuration.get(section, "ssl", fallback="disabled"))
self.user = configuration.get(section, "user", fallback=None)
- def _send(self, text: str, attachment: Dict[str, str]) -> None:
+ def _send(self, text: str, attachment: dict[str, str]) -> None:
"""
send email callback
Args:
text(str): email body text
- attachment(Dict[str, str]): map of attachment filename to attachment content
+ attachment(dict[str, str]): map of attachment filename to attachment content
"""
message = MIMEMultipart()
message["From"] = self.sender
@@ -104,12 +103,12 @@ class Email(Report, JinjaTemplate):
session.sendmail(self.sender, self.receivers, message.as_string())
session.quit()
- def generate(self, packages: Iterable[Package], result: Result) -> None:
+ def generate(self, packages: list[Package], result: Result) -> None:
"""
generate report for the specified packages
Args:
- packages(Iterable[Package]): list of packages to generate report
+ packages(list[Package]): list of packages to generate report
result(Result): build result
"""
if self.no_empty_report and not result.success:
diff --git a/src/ahriman/core/report/html.py b/src/ahriman/core/report/html.py
index d7f265d1..8c5edf13 100644
--- a/src/ahriman/core/report/html.py
+++ b/src/ahriman/core/report/html.py
@@ -17,8 +17,6 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-from typing import Iterable
-
from ahriman.core.configuration import Configuration
from ahriman.core.report.jinja_template import JinjaTemplate
from ahriman.core.report.report import Report
@@ -50,12 +48,12 @@ class HTML(Report, JinjaTemplate):
self.report_path = configuration.getpath(section, "path")
self.template_path = configuration.getpath(section, "template_path")
- def generate(self, packages: Iterable[Package], result: Result) -> None:
+ def generate(self, packages: list[Package], result: Result) -> None:
"""
generate report for the specified packages
Args:
- packages(Iterable[Package]): list of packages to generate report
+ packages(list[Package]): list of packages to generate report
result(Result): build result
"""
html = self.make_html(Result(success=packages), self.template_path)
diff --git a/src/ahriman/core/report/jinja_template.py b/src/ahriman/core/report/jinja_template.py
index 18417b4b..eb232706 100644
--- a/src/ahriman/core/report/jinja_template.py
+++ b/src/ahriman/core/report/jinja_template.py
@@ -19,8 +19,8 @@
#
import jinja2
+from collections.abc import Callable
from pathlib import Path
-from typing import Callable, Dict
from ahriman.core.configuration import Configuration
from ahriman.core.sign.gpg import GPG
@@ -56,11 +56,11 @@ class JinjaTemplate:
* repository - repository name, string, required
Attributes:
- homepage(Optional[str]): homepage link if any (for footer)
+ homepage(str | None): homepage link if any (for footer)
link_path(str): prefix fo packages to download
name(str): repository name
- default_pgp_key(Optional[str]): default PGP key
- sign_targets(Set[SignSettings]): targets to sign enabled in configuration
+ default_pgp_key(str | None): default PGP key
+ sign_targets(set[SignSettings]): targets to sign enabled in configuration
"""
def __init__(self, section: str, configuration: Configuration) -> None:
@@ -108,7 +108,7 @@ class JinjaTemplate:
"version": base.version
} for base in result.success for package, properties in base.packages.items()
]
- comparator: Callable[[Dict[str, str]], str] = lambda item: item["filename"]
+ comparator: Callable[[dict[str, str]], str] = lambda item: item["filename"]
return template.render(
homepage=self.homepage,
diff --git a/src/ahriman/core/report/report.py b/src/ahriman/core/report/report.py
index 9ab0cebc..c2937a3b 100644
--- a/src/ahriman/core/report/report.py
+++ b/src/ahriman/core/report/report.py
@@ -19,8 +19,6 @@
#
from __future__ import annotations
-from typing import Iterable, Type
-
from ahriman.core.configuration import Configuration
from ahriman.core.exceptions import ReportError
from ahriman.core.log import LazyLogging
@@ -69,7 +67,7 @@ class Report(LazyLogging):
self.configuration = configuration
@classmethod
- def load(cls: Type[Report], architecture: str, configuration: Configuration, target: str) -> Report:
+ def load(cls: type[Report], architecture: str, configuration: Configuration, target: str) -> Report:
"""
load client from settings
@@ -97,22 +95,22 @@ class Report(LazyLogging):
return Telegram(architecture, configuration, section)
return cls(architecture, configuration) # should never happen
- def generate(self, packages: Iterable[Package], result: Result) -> None:
+ def generate(self, packages: list[Package], result: Result) -> None:
"""
generate report for the specified packages
Args:
- packages(Iterable[Package]): list of packages to generate report
+ packages(list[Package]): list of packages to generate report
result(Result): build result
"""
- def run(self, result: Result, packages: Iterable[Package]) -> None:
+ def run(self, result: Result, packages: list[Package]) -> None:
"""
run report generation
Args:
result(Result): build result
- packages(Iterable[Package]): list of packages to generate report
+ packages(list[Package]): list of packages to generate report
Raises:
ReportFailed: in case of any report unmatched exception
diff --git a/src/ahriman/core/report/report_trigger.py b/src/ahriman/core/report/report_trigger.py
index d9c37bbf..1994f66d 100644
--- a/src/ahriman/core/report/report_trigger.py
+++ b/src/ahriman/core/report/report_trigger.py
@@ -17,8 +17,6 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-from typing import Iterable, List, Type
-
from ahriman.core.configuration import Configuration
from ahriman.core.triggers import Trigger
from ahriman.core.report.report import Report
@@ -31,7 +29,7 @@ class ReportTrigger(Trigger):
report trigger
Attributes:
- targets(List[str]): report target list
+ targets(list[str]): report target list
"""
CONFIGURATION_SCHEMA = {
@@ -207,7 +205,7 @@ class ReportTrigger(Trigger):
self.targets = self.configuration_sections(configuration)
@classmethod
- def configuration_sections(cls: Type[Trigger], configuration: Configuration) -> List[str]:
+ def configuration_sections(cls: type[Trigger], configuration: Configuration) -> list[str]:
"""
extract configuration sections from configuration
@@ -215,17 +213,17 @@ class ReportTrigger(Trigger):
configuration(Configuration): configuration instance
Returns:
- List[str]: read configuration sections belong to this trigger
+ list[str]: read configuration sections belong to this trigger
"""
return configuration.getlist("report", "target", fallback=[])
- def on_result(self, result: Result, packages: Iterable[Package]) -> None:
+ def on_result(self, result: Result, packages: list[Package]) -> None:
"""
run trigger
Args:
result(Result): build result
- packages(Iterable[Package]): list of all available packages
+ packages(list[Package]): list of all available packages
"""
for target in self.targets:
runner = Report.load(self.architecture, self.configuration, target)
diff --git a/src/ahriman/core/report/telegram.py b/src/ahriman/core/report/telegram.py
index efb413be..6a5b0610 100644
--- a/src/ahriman/core/report/telegram.py
+++ b/src/ahriman/core/report/telegram.py
@@ -19,8 +19,6 @@
#
import requests # technically we could use python-telegram-bot, but it is just a single request, c'mon
-from typing import Iterable
-
from ahriman.core.configuration import Configuration
from ahriman.core.report.jinja_template import JinjaTemplate
from ahriman.core.report.report import Report
@@ -84,12 +82,12 @@ class Telegram(Report, JinjaTemplate):
self.logger.exception("could not perform request")
raise
- def generate(self, packages: Iterable[Package], result: Result) -> None:
+ def generate(self, packages: list[Package], result: Result) -> None:
"""
generate report for the specified packages
Args:
- packages(Iterable[Package]): list of packages to generate report
+ packages(list[Package]): list of packages to generate report
result(Result): build result
"""
if not result.success:
diff --git a/src/ahriman/core/repository/cleaner.py b/src/ahriman/core/repository/cleaner.py
index 26bf54bd..d18051c4 100644
--- a/src/ahriman/core/repository/cleaner.py
+++ b/src/ahriman/core/repository/cleaner.py
@@ -20,7 +20,6 @@
import shutil
from pathlib import Path
-from typing import List
from ahriman.core.repository.repository_properties import RepositoryProperties
@@ -69,12 +68,12 @@ class Cleaner(RepositoryProperties):
self.logger.info("clear build queue")
self.database.build_queue_clear(None)
- def packages_built(self) -> List[Path]:
+ def packages_built(self) -> list[Path]:
"""
get list of files in built packages directory
Returns:
- List[Path]: list of filenames from the directory
+ list[Path]: list of filenames from the directory
Raises:
NotImplementedError: not implemented method
diff --git a/src/ahriman/core/repository/executor.py b/src/ahriman/core/repository/executor.py
index e34644a4..4753d0b2 100644
--- a/src/ahriman/core/repository/executor.py
+++ b/src/ahriman/core/repository/executor.py
@@ -19,9 +19,9 @@
#
import shutil
+from collections.abc import Iterable
from pathlib import Path
from tempfile import TemporaryDirectory
-from typing import Dict, Iterable, List, Optional
from ahriman.core.build_tools.task import Task
from ahriman.core.repository.cleaner import Cleaner
@@ -36,7 +36,7 @@ class Executor(Cleaner):
trait for common repository update processes
"""
- def load_archives(self, packages: Iterable[Path]) -> List[Package]:
+ def load_archives(self, packages: Iterable[Path]) -> list[Package]:
"""
load packages from list of archives
@@ -44,19 +44,19 @@ class Executor(Cleaner):
packages(Iterable[Path]): paths to package archives
Returns:
- List[Package]: list of read packages
+ list[Package]: list of read packages
Raises:
NotImplementedError: not implemented method
"""
raise NotImplementedError
- def packages(self) -> List[Package]:
+ def packages(self) -> list[Package]:
"""
generate list of repository packages
Returns:
- List[Package]: list of packages properties
+ list[Package]: list of packages properties
Raises:
NotImplementedError: not implemented method
@@ -122,8 +122,8 @@ class Executor(Cleaner):
except Exception:
self.logger.exception("could not remove %s", package)
- packages_to_remove: Dict[str, Path] = {}
- bases_to_remove: List[str] = []
+ packages_to_remove: dict[str, Path] = {}
+ bases_to_remove: list[str] = []
# build package list based on user input
requested = set(packages)
@@ -177,7 +177,7 @@ class Executor(Cleaner):
shutil.move(self.paths.packages / archive.filename, self.paths.packages / safe)
archive.filename = safe
- def update_single(name: Optional[str], package_base: str) -> None:
+ def update_single(name: str | None, package_base: str) -> None:
if name is None:
self.logger.warning("received empty package name for base %s", package_base)
return # suppress type checking, it never can be none actually
@@ -191,7 +191,7 @@ class Executor(Cleaner):
self.repo.add(package_path)
current_packages = self.packages()
- removed_packages: List[str] = [] # list of packages which have been removed from the base
+ removed_packages: list[str] = [] # list of packages which have been removed from the base
updates = self.load_archives(packages)
result = Result()
diff --git a/src/ahriman/core/repository/repository.py b/src/ahriman/core/repository/repository.py
index b243baf5..8fe21736 100644
--- a/src/ahriman/core/repository/repository.py
+++ b/src/ahriman/core/repository/repository.py
@@ -19,8 +19,8 @@
#
from __future__ import annotations
+from collections.abc import Iterable
from pathlib import Path
-from typing import Dict, Iterable, List, Optional, Type
from ahriman.core import _Context, context
from ahriman.core.alpm.pacman import Pacman
@@ -58,7 +58,7 @@ class Repository(Executor, UpdateHandler):
"""
@classmethod
- def load(cls: Type[Repository], architecture: str, configuration: Configuration, database: SQLite, *,
+ def load(cls: type[Repository], architecture: str, configuration: Configuration, database: SQLite, *,
report: bool, unsafe: bool, refresh_pacman_database: int = 0) -> Repository:
"""
load instance from argument list
@@ -99,7 +99,7 @@ class Repository(Executor, UpdateHandler):
context.set(ctx)
- def load_archives(self, packages: Iterable[Path]) -> List[Package]:
+ def load_archives(self, packages: Iterable[Path]) -> list[Package]:
"""
load packages from list of archives
@@ -107,11 +107,11 @@ class Repository(Executor, UpdateHandler):
packages(Iterable[Path]): paths to package archives
Returns:
- List[Package]: list of read packages
+ list[Package]: list of read packages
"""
sources = self.database.remotes_get()
- result: Dict[str, Package] = {}
+ result: dict[str, Package] = {}
# we are iterating over bases, not single packages
for full_path in packages:
try:
@@ -130,34 +130,34 @@ class Repository(Executor, UpdateHandler):
self.logger.exception("could not load package from %s", full_path)
return list(result.values())
- def packages(self) -> List[Package]:
+ def packages(self) -> list[Package]:
"""
generate list of repository packages
Returns:
- List[Package]: list of packages properties
+ list[Package]: list of packages properties
"""
return self.load_archives(filter(package_like, self.paths.repository.iterdir()))
- def packages_built(self) -> List[Path]:
+ def packages_built(self) -> list[Path]:
"""
get list of files in built packages directory
Returns:
- List[Path]: list of filenames from the directory
+ list[Path]: list of filenames from the directory
"""
return list(filter(package_like, self.paths.packages.iterdir()))
- def packages_depend_on(self, packages: List[Package], depends_on: Optional[Iterable[str]]) -> List[Package]:
+ def packages_depend_on(self, packages: list[Package], depends_on: Iterable[str] | None) -> list[Package]:
"""
extract list of packages which depends on specified package
Args:
- packages(List[Package]): list of packages to be filtered
- depends_on(Optional[Iterable[str]]): dependencies of the packages
+ packages(list[Package]): list of packages to be filtered
+ depends_on(Iterable[str] | None): dependencies of the packages
Returns:
- List[Package]: list of repository packages which depend on specified packages
+ list[Package]: list of repository packages which depend on specified packages
"""
if depends_on is None:
return packages # no list provided extract everything by default
diff --git a/src/ahriman/core/repository/repository_properties.py b/src/ahriman/core/repository/repository_properties.py
index 62d2d43f..6015d7a3 100644
--- a/src/ahriman/core/repository/repository_properties.py
+++ b/src/ahriman/core/repository/repository_properties.py
@@ -37,7 +37,7 @@ class RepositoryProperties(LazyLogging):
architecture(str): repository architecture
configuration(Configuration): configuration instance
database(SQLite): database instance
- ignore_list(List[str]): package bases which will be ignored during auto updates
+ ignore_list(list[str]): package bases which will be ignored during auto updates
name(str): repository name
pacman(Pacman): alpm wrapper instance
paths(RepositoryPaths): repository paths instance
diff --git a/src/ahriman/core/repository/update_handler.py b/src/ahriman/core/repository/update_handler.py
index a7c6a697..1d5f438b 100644
--- a/src/ahriman/core/repository/update_handler.py
+++ b/src/ahriman/core/repository/update_handler.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 typing import Iterable, List
+from collections.abc import Iterable
from ahriman.core.build_tools.sources import Sources
from ahriman.core.repository.cleaner import Cleaner
@@ -30,19 +30,19 @@ class UpdateHandler(Cleaner):
trait to get package update list
"""
- def packages(self) -> List[Package]:
+ def packages(self) -> list[Package]:
"""
generate list of repository packages
Returns:
- List[Package]: list of packages properties
+ list[Package]: list of packages properties
Raises:
NotImplementedError: not implemented method
"""
raise NotImplementedError
- def updates_aur(self, filter_packages: Iterable[str], *, vcs: bool) -> List[Package]:
+ def updates_aur(self, filter_packages: Iterable[str], *, vcs: bool) -> list[Package]:
"""
check AUR for updates
@@ -51,9 +51,9 @@ class UpdateHandler(Cleaner):
vcs(bool): enable or disable checking of VCS packages
Returns:
- List[Package]: list of packages which are out-of-dated
+ list[Package]: list of packages which are out-of-dated
"""
- result: List[Package] = []
+ result: list[Package] = []
for local in self.packages():
with self.in_package_context(local.base):
@@ -81,7 +81,7 @@ class UpdateHandler(Cleaner):
return result
- def updates_local(self, *, vcs: bool) -> List[Package]:
+ def updates_local(self, *, vcs: bool) -> list[Package]:
"""
check local packages for updates
@@ -89,9 +89,9 @@ class UpdateHandler(Cleaner):
vcs(bool): enable or disable checking of VCS packages
Returns:
- List[Package]: list of local packages which are out-of-dated
+ list[Package]: list of local packages which are out-of-dated
"""
- result: List[Package] = []
+ result: list[Package] = []
packages = {local.base: local for local in self.packages()}
for cache_dir in self.paths.cache.iterdir():
@@ -114,14 +114,14 @@ class UpdateHandler(Cleaner):
return result
- def updates_manual(self) -> List[Package]:
+ def updates_manual(self) -> list[Package]:
"""
check for packages for which manual update has been requested
Returns:
- List[Package]: list of packages which are out-of-dated
+ list[Package]: list of packages which are out-of-dated
"""
- result: List[Package] = []
+ result: list[Package] = []
known_bases = {package.base for package in self.packages()}
try:
diff --git a/src/ahriman/core/sign/gpg.py b/src/ahriman/core/sign/gpg.py
index 7ffb1b88..976fac7e 100644
--- a/src/ahriman/core/sign/gpg.py
+++ b/src/ahriman/core/sign/gpg.py
@@ -20,7 +20,6 @@
import requests
from pathlib import Path
-from typing import List, Optional, Set, Tuple
from ahriman.core.configuration import Configuration
from ahriman.core.exceptions import BuildError
@@ -37,8 +36,8 @@ class GPG(LazyLogging):
DEFAULT_TIMEOUT(int): (class attribute) HTTP request timeout in seconds
architecture(str): repository architecture
configuration(Configuration): configuration instance
- default_key(Optional[str]): default PGP key ID to use
- targets(Set[SignSettings]): list of targets to sign (repository, package etc)
+ default_key(str | None): default PGP key ID to use
+ targets(set[SignSettings]): list of targets to sign (repository, package etc)
"""
_check_output = check_output
@@ -57,12 +56,12 @@ class GPG(LazyLogging):
self.targets, self.default_key = self.sign_options(configuration)
@property
- def repository_sign_args(self) -> List[str]:
+ def repository_sign_args(self) -> list[str]:
"""
get command line arguments based on settings
Returns:
- List[str]: command line arguments for repo-add command to sign database
+ list[str]: command line arguments for repo-add command to sign database
"""
if SignSettings.Repository not in self.targets:
return []
@@ -72,7 +71,7 @@ class GPG(LazyLogging):
return ["--sign", "--key", self.default_key]
@staticmethod
- def sign_command(path: Path, key: str) -> List[str]:
+ def sign_command(path: Path, key: str) -> list[str]:
"""
gpg command to run
@@ -81,12 +80,12 @@ class GPG(LazyLogging):
key(str): PGP key ID
Returns:
- List[str]: gpg command with all required arguments
+ list[str]: gpg command with all required arguments
"""
return ["gpg", "-u", key, "-b", str(path)]
@staticmethod
- def sign_options(configuration: Configuration) -> Tuple[Set[SignSettings], Optional[str]]:
+ def sign_options(configuration: Configuration) -> tuple[set[SignSettings], str | None]:
"""
extract default sign options from configuration
@@ -94,9 +93,9 @@ class GPG(LazyLogging):
configuration(Configuration): configuration instance
Returns:
- Tuple[Set[SignSettings], Optional[str]]: tuple of sign targets and default PGP key
+ tuple[set[SignSettings], str | None]: tuple of sign targets and default PGP key
"""
- targets: Set[SignSettings] = set()
+ targets: set[SignSettings] = set()
for option in configuration.getlist("sign", "target", fallback=[]):
target = SignSettings.from_option(option)
if target == SignSettings.Disabled:
@@ -140,7 +139,7 @@ class GPG(LazyLogging):
key_body = self.key_download(server, key)
GPG._check_output("gpg", "--import", input_data=key_body, logger=self.logger)
- def process(self, path: Path, key: str) -> List[Path]:
+ def process(self, path: Path, key: str) -> list[Path]:
"""
gpg command wrapper
@@ -149,7 +148,7 @@ class GPG(LazyLogging):
key(str): PGP key ID
Returns:
- List[Path]: list of generated files including original file
+ list[Path]: list of generated files including original file
"""
GPG._check_output(
*GPG.sign_command(path, key),
@@ -157,7 +156,7 @@ class GPG(LazyLogging):
logger=self.logger)
return [path, path.parent / f"{path.name}.sig"]
- def process_sign_package(self, path: Path, package_base: str) -> List[Path]:
+ def process_sign_package(self, path: Path, package_base: str) -> list[Path]:
"""
sign package if required by configuration
@@ -166,7 +165,7 @@ class GPG(LazyLogging):
package_base(str): package base required to check for key overrides
Returns:
- List[Path]: list of generated files including original file
+ list[Path]: list of generated files including original file
"""
if SignSettings.Packages not in self.targets:
return [path]
@@ -176,7 +175,7 @@ class GPG(LazyLogging):
return [path]
return self.process(path, key)
- def process_sign_repository(self, path: Path) -> List[Path]:
+ def process_sign_repository(self, path: Path) -> list[Path]:
"""
sign repository if required by configuration
@@ -187,7 +186,7 @@ class GPG(LazyLogging):
path(Path): path to repository database
Returns:
- List[Path]: list of generated files including original file
+ list[Path]: list of generated files including original file
"""
if SignSettings.Repository not in self.targets:
return [path]
diff --git a/src/ahriman/core/spawn.py b/src/ahriman/core/spawn.py
index bccf45d2..abbd2d7f 100644
--- a/src/ahriman/core/spawn.py
+++ b/src/ahriman/core/spawn.py
@@ -22,9 +22,9 @@ from __future__ import annotations
import argparse
import uuid
+from collections.abc import Callable, Iterable
from multiprocessing import Process, Queue
from threading import Lock, Thread
-from typing import Callable, Dict, Iterable, Optional, Tuple
from ahriman.core.configuration import Configuration
from ahriman.core.log import LazyLogging
@@ -37,10 +37,10 @@ class Spawn(Thread, LazyLogging):
MUST NOT be used directly, the only one usage allowed is to spawn process from web services
Attributes:
- active(Dict[str, Process]): map of active child processes required to avoid zombies
+ active(dict[str, Process]): map of active child processes required to avoid zombies
architecture(str): repository architecture
configuration(Configuration): configuration instance
- queue(Queue[Tuple[str, bool]]): multiprocessing queue to read updates from processes
+ queue(Queue[tuple[str, bool]]): multiprocessing queue to read updates from processes
"""
def __init__(self, args_parser: argparse.ArgumentParser, architecture: str, configuration: Configuration) -> None:
@@ -58,13 +58,13 @@ class Spawn(Thread, LazyLogging):
self.configuration = configuration
self.lock = Lock()
- self.active: Dict[str, Process] = {}
+ self.active: dict[str, Process] = {}
# stupid pylint does not know that it is possible
- self.queue: Queue[Tuple[str, bool] | None] = Queue() # pylint: disable=unsubscriptable-object
+ self.queue: Queue[tuple[str, bool] | None] = Queue() # pylint: disable=unsubscriptable-object
@staticmethod
def process(callback: Callable[[argparse.Namespace, str], bool], args: argparse.Namespace, architecture: str,
- process_id: str, queue: Queue[Tuple[str, bool]]) -> None: # pylint: disable=unsubscriptable-object
+ process_id: str, queue: Queue[tuple[str, bool]]) -> None: # pylint: disable=unsubscriptable-object
"""
helper to run external process
@@ -73,7 +73,7 @@ class Spawn(Thread, LazyLogging):
args(argparse.Namespace): command line arguments
architecture(str): repository architecture
process_id(str): process unique identifier
- queue(Queue[Tuple[str, bool]]): output queue
+ queue(Queue[tuple[str, bool]]): output queue
"""
result = callback(args, architecture)
queue.put((process_id, result))
@@ -113,13 +113,13 @@ class Spawn(Thread, LazyLogging):
with self.lock:
self.active[process_id] = process
- def key_import(self, key: str, server: Optional[str]) -> None:
+ def key_import(self, key: str, server: str | None) -> None:
"""
import key to service cache
Args:
key(str): key to import
- server(str): PGP key server
+ server(str | None): PGP key server
"""
kwargs = {} if server is None else {"key-server": server}
self._spawn_process("service-key-import", key, **kwargs)
@@ -155,7 +155,7 @@ class Spawn(Thread, LazyLogging):
"""
self._spawn_process("package-remove", *packages)
- def packages_update(self, ) -> None:
+ def packages_update(self) -> None:
"""
run full repository update
"""
diff --git a/src/ahriman/core/status/client.py b/src/ahriman/core/status/client.py
index 60784eb0..4000c870 100644
--- a/src/ahriman/core/status/client.py
+++ b/src/ahriman/core/status/client.py
@@ -21,8 +21,6 @@ from __future__ import annotations
import logging
-from typing import List, Optional, Tuple, Type
-
from ahriman.core.configuration import Configuration
from ahriman.models.build_status import BuildStatus, BuildStatusEnum
from ahriman.models.internal_status import InternalStatus
@@ -35,7 +33,7 @@ class Client:
"""
@classmethod
- def load(cls: Type[Client], configuration: Configuration, *, report: bool) -> Client:
+ def load(cls: type[Client], configuration: Configuration, *, report: bool) -> Client:
"""
load client from settings
@@ -71,15 +69,15 @@ class Client:
status(BuildStatusEnum): current package build status
"""
- def get(self, package_base: Optional[str]) -> List[Tuple[Package, BuildStatus]]:
+ def get(self, package_base: str | None) -> list[tuple[Package, BuildStatus]]:
"""
get package status
Args:
- package_base(Optional[str]): package base to get
+ package_base(str | None): package base to get
Returns:
- List[Tuple[Package, BuildStatus]]: list of current package description and status if it has been found
+ list[tuple[Package, BuildStatus]]: list of current package description and status if it has been found
"""
del package_base
return []
diff --git a/src/ahriman/core/status/watcher.py b/src/ahriman/core/status/watcher.py
index 45287675..356b8873 100644
--- a/src/ahriman/core/status/watcher.py
+++ b/src/ahriman/core/status/watcher.py
@@ -19,8 +19,6 @@
#
import os
-from typing import Dict, List, Optional, Tuple
-
from ahriman.core.configuration import Configuration
from ahriman.core.database import SQLite
from ahriman.core.exceptions import UnknownPackageError
@@ -38,7 +36,7 @@ class Watcher(LazyLogging):
Attributes:
architecture(str): repository architecture
database(SQLite): database instance
- known(Dict[str, Tuple[Package, BuildStatus]]): list of known packages. For the most cases ``packages`` should
+ known(dict[str, tuple[Package, BuildStatus]]): list of known packages. For the most cases ``packages`` should
be used instead
repository(Repository): repository object
status(BuildStatus): daemon status
@@ -57,23 +55,23 @@ class Watcher(LazyLogging):
self.database = database
self.repository = Repository.load(architecture, configuration, database, report=False, unsafe=False)
- self.known: Dict[str, Tuple[Package, BuildStatus]] = {}
+ self.known: dict[str, tuple[Package, BuildStatus]] = {}
self.status = BuildStatus()
# special variables for updating logs
self._last_log_record_id = LogRecordId("", os.getpid())
@property
- def packages(self) -> List[Tuple[Package, BuildStatus]]:
+ def packages(self) -> list[tuple[Package, BuildStatus]]:
"""
get current known packages list
Returns:
- List[Tuple[Package, BuildStatus]]: list of packages together with their statuses
+ list[tuple[Package, BuildStatus]]: list of packages together with their statuses
"""
return list(self.known.values())
- def get(self, package_base: str) -> Tuple[Package, BuildStatus]:
+ def get(self, package_base: str) -> tuple[Package, BuildStatus]:
"""
get current package base build status
@@ -81,7 +79,7 @@ class Watcher(LazyLogging):
package_base(str): package base
Returns:
- Tuple[Package, BuildStatus]: package and its status
+ tuple[Package, BuildStatus]: package and its status
Raises:
UnknownPackage: if no package found
@@ -130,24 +128,24 @@ class Watcher(LazyLogging):
self.database.package_remove(package_base)
self.remove_logs(package_base, None)
- def remove_logs(self, package_base: str, current_process_id: Optional[int]) -> None:
+ def remove_logs(self, package_base: str, current_process_id: int | None) -> None:
"""
remove package related logs
Args:
package_base(str): package base
- current_process_id(int): current process id
+ current_process_id(int | None): current process id
"""
self.database.logs_remove(package_base, current_process_id)
- def update(self, package_base: str, status: BuildStatusEnum, package: Optional[Package]) -> None:
+ def update(self, package_base: str, status: BuildStatusEnum, package: Package | None) -> None:
"""
update package status and description
Args:
package_base(str): package base to update
status(BuildStatusEnum): new build status
- package(Optional[Package]): optional new package description. In case if not set current properties will be used
+ package(Package | None): optional package description. In case if not set current properties will be used
Raises:
UnknownPackage: if no package found
diff --git a/src/ahriman/core/status/web_client.py b/src/ahriman/core/status/web_client.py
index 31f97949..da121118 100644
--- a/src/ahriman/core/status/web_client.py
+++ b/src/ahriman/core/status/web_client.py
@@ -21,7 +21,7 @@ import contextlib
import logging
import requests
-from typing import Generator, List, Optional, Tuple
+from collections.abc import Generator
from urllib.parse import quote_plus as urlencode
from ahriman.core.configuration import Configuration
@@ -40,7 +40,7 @@ class WebClient(Client, LazyLogging):
Attributes:
address(str): address of the web service
- user(Optional[User]): web service user descriptor
+ user(User | None): web service user descriptor
"""
def __init__(self, configuration: Configuration) -> None:
@@ -78,7 +78,7 @@ class WebClient(Client, LazyLogging):
return f"{self.address}/api/v1/status"
@staticmethod
- def parse_address(configuration: Configuration) -> Tuple[str, bool]:
+ def parse_address(configuration: Configuration) -> tuple[str, bool]:
"""
parse address from configuration
@@ -86,7 +86,7 @@ class WebClient(Client, LazyLogging):
configuration(Configuration): configuration instance
Returns:
- Tuple[str, bool]: tuple of server address and socket flag (True in case if unix socket must be used)
+ tuple[str, bool]: tuple of server address and socket flag (True in case if unix socket must be used)
"""
if (unix_socket := configuration.get("web", "unix_socket", fallback=None)) is not None:
# special pseudo-protocol which is used for unix sockets
@@ -190,15 +190,15 @@ class WebClient(Client, LazyLogging):
response = self.__session.post(self._package_url(package.base), json=payload)
response.raise_for_status()
- def get(self, package_base: Optional[str]) -> List[Tuple[Package, BuildStatus]]:
+ def get(self, package_base: str | None) -> list[tuple[Package, BuildStatus]]:
"""
get package status
Args:
- package_base(Optional[str]): package base to get
+ package_base(str | None): package base to get
Returns:
- List[Tuple[Package, BuildStatus]]: list of current package description and status if it has been found
+ list[tuple[Package, BuildStatus]]: list of current package description and status if it has been found
"""
with self.__execute_request():
response = self.__session.get(self._package_url(package_base or ""))
diff --git a/src/ahriman/core/tree.py b/src/ahriman/core/tree.py
index ecc501bd..cccb9a48 100644
--- a/src/ahriman/core/tree.py
+++ b/src/ahriman/core/tree.py
@@ -21,7 +21,7 @@ from __future__ import annotations
import functools
-from typing import Callable, Iterable, List
+from collections.abc import Callable, Iterable
from ahriman.core.util import partition
from ahriman.models.package import Package
@@ -32,7 +32,7 @@ class Leaf:
tree leaf implementation
Attributes:
- dependencies(Set[str]): list of package dependencies
+ dependencies(set[str]): list of package dependencies
package(Package): leaf package properties
"""
@@ -92,7 +92,7 @@ class Tree:
dependency tree implementation
Attributes:
- leaves[List[Leaf]): list of tree leaves
+ leaves[list[Leaf]): list of tree leaves
Examples:
The most important feature here is to generate tree levels one by one which can be achieved by using class
@@ -119,17 +119,17 @@ class Tree:
>>> tree = Tree(leaves)
"""
- def __init__(self, leaves: List[Leaf]) -> None:
+ def __init__(self, leaves: list[Leaf]) -> None:
"""
default constructor
Args:
- leaves(List[Leaf]): leaves to build the tree
+ leaves(list[Leaf]): leaves to build the tree
"""
self.leaves = leaves
@staticmethod
- def resolve(packages: Iterable[Package]) -> List[List[Package]]:
+ def resolve(packages: Iterable[Package]) -> list[list[Package]]:
"""
resolve dependency tree
@@ -137,20 +137,20 @@ class Tree:
packages(Iterable[Package]): packages list
Returns:
- List[List[Package]]: list of packages lists based on their dependencies
+ list[list[Package]]: list of packages lists based on their dependencies
"""
leaves = [Leaf(package) for package in packages]
instance = Tree(leaves)
return instance.levels()
- def levels(self) -> List[List[Package]]:
+ def levels(self) -> list[list[Package]]:
"""
get build levels starting from the packages which do not require any other package to build
Returns:
- List[List[Package]]: sorted list of packages lists based on their dependencies
+ list[list[Package]]: sorted list of packages lists based on their dependencies
"""
- unsorted: List[List[Leaf]] = []
+ unsorted: list[list[Leaf]] = []
# build initial tree
unprocessed = self.leaves[:]
diff --git a/src/ahriman/core/triggers/trigger.py b/src/ahriman/core/triggers/trigger.py
index 56e3e8ce..d931c068 100644
--- a/src/ahriman/core/triggers/trigger.py
+++ b/src/ahriman/core/triggers/trigger.py
@@ -19,8 +19,6 @@
#
from __future__ import annotations
-from typing import Iterable, List, Optional, Type
-
from ahriman.core.configuration import Configuration
from ahriman.core.configuration.schema import ConfigurationSchema
from ahriman.core.log import LazyLogging
@@ -34,7 +32,7 @@ class Trigger(LazyLogging):
Attributes:
CONFIGURATION_SCHEMA(ConfigurationSchema): (class attribute) configuration schema template
- CONFIGURATION_SCHEMA_FALLBACK(Optional[str]): (class attribute) optional fallback option for defining
+ CONFIGURATION_SCHEMA_FALLBACK(str | None): (class attribute) optional fallback option for defining
configuration schema type used
architecture(str): repository architecture
configuration(Configuration): configuration instance
@@ -43,7 +41,7 @@ class Trigger(LazyLogging):
This class must be used in order to create own extension. Basically idea is the following::
>>> class CustomTrigger(Trigger):
- >>> def on_result(self, result: Result, packages: Iterable[Package]) -> None:
+ >>> def on_result(self, result: Result, packages: list[Package]) -> None:
>>> perform_some_action()
Having this class you can pass it to ``configuration`` and it will be run on action::
@@ -58,7 +56,7 @@ class Trigger(LazyLogging):
"""
CONFIGURATION_SCHEMA: ConfigurationSchema = {}
- CONFIGURATION_SCHEMA_FALLBACK: Optional[str] = None
+ CONFIGURATION_SCHEMA_FALLBACK: str | None = None
def __init__(self, architecture: str, configuration: Configuration) -> None:
"""
@@ -72,8 +70,8 @@ class Trigger(LazyLogging):
self.configuration = configuration
@classmethod
- def configuration_schema(cls: Type[Trigger], architecture: str,
- configuration: Optional[Configuration]) -> ConfigurationSchema:
+ def configuration_schema(cls: type[Trigger], architecture: str,
+ configuration: Configuration | None) -> ConfigurationSchema:
"""
configuration schema based on supplied service configuration
@@ -82,7 +80,7 @@ class Trigger(LazyLogging):
Args:
architecture(str): repository architecture
- configuration(Optional[Configuration]): configuration instance. If set to None, the default schema
+ configuration(Configuration | None): configuration instance. If set to None, the default schema
should be returned
Returns:
@@ -104,7 +102,7 @@ class Trigger(LazyLogging):
return result
@classmethod
- def configuration_sections(cls: Type[Trigger], configuration: Configuration) -> List[str]:
+ def configuration_sections(cls: type[Trigger], configuration: Configuration) -> list[str]:
"""
extract configuration sections from configuration
@@ -112,26 +110,26 @@ class Trigger(LazyLogging):
configuration(Configuration): configuration instance
Returns:
- List[str]: read configuration sections belong to this trigger
+ list[str]: read configuration sections belong to this trigger
Examples:
This method can be used in order to extract specific configuration sections which are set by user, e.g.
from sources::
>>> @staticmethod
- >>> def configuration_sections(cls: Type[Trigger], configuration: Configuration) -> List[str]:
+ >>> def configuration_sections(cls: type[Trigger], configuration: Configuration) -> list[str]:
>>> return configuration.getlist("report", "target", fallback=[])
"""
del configuration
return []
- def on_result(self, result: Result, packages: Iterable[Package]) -> None:
+ def on_result(self, result: Result, packages: list[Package]) -> None:
"""
trigger action which will be called after build process with process result
Args:
result(Result): build result
- packages(Iterable[Package]): list of all available packages
+ packages(list[Package]): list of all available packages
"""
if (run := getattr(self, "run", None)) is not None:
run(result, packages) # compatibility with old triggers
diff --git a/src/ahriman/core/triggers/trigger_loader.py b/src/ahriman/core/triggers/trigger_loader.py
index ce88f8c2..f4d22de9 100644
--- a/src/ahriman/core/triggers/trigger_loader.py
+++ b/src/ahriman/core/triggers/trigger_loader.py
@@ -23,9 +23,9 @@ import contextlib
import importlib
import os
+from collections.abc import Generator
from pathlib import Path
from types import ModuleType
-from typing import Generator, Iterable, List, Type
from ahriman.core.configuration import Configuration
from ahriman.core.exceptions import ExtensionError
@@ -40,7 +40,7 @@ class TriggerLoader(LazyLogging):
trigger loader class
Attributes:
- triggers(List[Trigger]): list of loaded triggers according to the configuration
+ triggers(list[Trigger]): list of loaded triggers according to the configuration
Examples:
This class more likely must not be used directly, but the usual workflow is the following::
@@ -63,10 +63,10 @@ class TriggerLoader(LazyLogging):
default constructor
"""
self._on_stop_requested = False
- self.triggers: List[Trigger] = []
+ self.triggers: list[Trigger] = []
@classmethod
- def load(cls: Type[TriggerLoader], architecture: str, configuration: Configuration) -> TriggerLoader:
+ def load(cls: type[TriggerLoader], architecture: str, configuration: Configuration) -> TriggerLoader:
"""
create instance from configuration
@@ -86,7 +86,7 @@ class TriggerLoader(LazyLogging):
return instance
@staticmethod
- def selected_triggers(configuration: Configuration) -> List[str]:
+ def selected_triggers(configuration: Configuration) -> list[str]:
"""
read configuration and return triggers which are set by settings
@@ -94,7 +94,7 @@ class TriggerLoader(LazyLogging):
configuration(Configuration): configuration instance
Returns:
- List[str]: list of triggers according to configuration
+ list[str]: list of triggers according to configuration
"""
return configuration.getlist("build", "triggers", fallback=[])
@@ -176,7 +176,7 @@ class TriggerLoader(LazyLogging):
return trigger
- def load_trigger_class(self, module_path: str) -> Type[Trigger]:
+ def load_trigger_class(self, module_path: str) -> type[Trigger]:
"""
load trigger class by module path
@@ -184,7 +184,7 @@ class TriggerLoader(LazyLogging):
module_path(str): module import path to load
Returns:
- Type[Trigger]: loaded trigger type by module path
+ type[Trigger]: loaded trigger type by module path
Raises:
InvalidExtension: in case if module cannot be loaded from the specified module path or is not a trigger
@@ -208,13 +208,13 @@ class TriggerLoader(LazyLogging):
self.logger.info("loaded type %s of package %s", class_name, package_or_path)
return trigger_type
- def on_result(self, result: Result, packages: Iterable[Package]) -> None:
+ def on_result(self, result: Result, packages: list[Package]) -> None:
"""
run trigger with result of application run
Args:
result(Result): build result
- packages(Iterable[Package]): list of all available packages
+ packages(list[Package]): list of all available packages
"""
self.logger.debug("executing triggers on result")
for trigger in self.triggers:
diff --git a/src/ahriman/core/upload/github.py b/src/ahriman/core/upload/github.py
index 8076ca01..c595ebbf 100644
--- a/src/ahriman/core/upload/github.py
+++ b/src/ahriman/core/upload/github.py
@@ -21,7 +21,7 @@ import mimetypes
import requests
from pathlib import Path
-from typing import Any, Dict, Iterable, Optional
+from typing import Any
from ahriman.core.configuration import Configuration
from ahriman.core.upload.http_upload import HttpUpload
@@ -51,12 +51,12 @@ class Github(HttpUpload):
self.github_owner = configuration.get(section, "owner")
self.github_repository = configuration.get(section, "repository")
- def asset_remove(self, release: Dict[str, Any], name: str) -> None:
+ def asset_remove(self, release: dict[str, Any], name: str) -> None:
"""
remove asset from the release by name
Args:
- release(Dict[str, Any]): release object
+ release(dict[str, Any]): release object
name(str): asset name
"""
try:
@@ -65,12 +65,12 @@ class Github(HttpUpload):
except StopIteration:
self.logger.info("no asset %s found in release %s", name, release["name"])
- def asset_upload(self, release: Dict[str, Any], path: Path) -> None:
+ def asset_upload(self, release: dict[str, Any], path: Path) -> None:
"""
upload asset to the release
Args:
- release(Dict[str, Any]): release object
+ release(dict[str, Any]): release object
path(Path): path to local file
"""
exists = any(path.name == asset["name"] for asset in release["assets"])
@@ -81,7 +81,7 @@ class Github(HttpUpload):
headers = {"Content-Type": mime} if mime is not None else {"Content-Type": "application/octet-stream"}
self._request("POST", url, params={"name": path.name}, data=path.open("rb"), headers=headers)
- def get_local_files(self, path: Path) -> Dict[Path, str]:
+ def get_local_files(self, path: Path) -> dict[Path, str]:
"""
get all local files and their calculated checksums
@@ -89,21 +89,21 @@ class Github(HttpUpload):
path(Path): local path to sync
Returns:
- Dict[Path, str]: map of path objects to its checksum
+ dict[Path, str]: map of path objects to its checksum
"""
return {
local_file: self.calculate_hash(local_file)
for local_file in walk(path)
}
- def files_remove(self, release: Dict[str, Any], local_files: Dict[Path, str], remote_files: Dict[str, str]) -> None:
+ def files_remove(self, release: dict[str, Any], local_files: dict[Path, str], remote_files: dict[str, str]) -> None:
"""
remove files from github
Args:
- release(Dict[str, Any]): release object
- local_files(Dict[Path, str]): map of local file paths to its checksum
- remote_files(Dict[str, str]): map of the remote files and its checksum
+ release(dict[str, Any]): release object
+ local_files(dict[Path, str]): map of local file paths to its checksum
+ remote_files(dict[str, str]): map of the remote files and its checksum
"""
local_filenames = {local_file.name for local_file in local_files}
for remote_file in remote_files:
@@ -111,14 +111,14 @@ class Github(HttpUpload):
continue
self.asset_remove(release, remote_file)
- def files_upload(self, release: Dict[str, Any], local_files: Dict[Path, str], remote_files: Dict[str, str]) -> None:
+ def files_upload(self, release: dict[str, Any], local_files: dict[Path, str], remote_files: dict[str, str]) -> None:
"""
upload files to github
Args:
- release(Dict[str, Any]): release object
- local_files(Dict[Path, str]): map of local file paths to its checksum
- remote_files(Dict[str, str]): map of the remote files and its checksum
+ release(dict[str, Any]): release object
+ local_files(dict[Path, str]): map of local file paths to its checksum
+ remote_files(dict[str, str]): map of the remote files and its checksum
"""
for local_file, checksum in local_files.items():
remote_checksum = remote_files.get(local_file.name)
@@ -126,29 +126,29 @@ class Github(HttpUpload):
continue
self.asset_upload(release, local_file)
- def release_create(self) -> Dict[str, Any]:
+ def release_create(self) -> dict[str, Any]:
"""
create empty release
Returns:
- Dict[str, Any]: github API release object for the new release
+ dict[str, Any]: github API release object for the new release
"""
url = f"https://api.github.com/repos/{self.github_owner}/{self.github_repository}/releases"
response = self._request("POST", url, json={"tag_name": self.architecture, "name": self.architecture})
- release: Dict[str, Any] = response.json()
+ release: dict[str, Any] = response.json()
return release
- def release_get(self) -> Optional[Dict[str, Any]]:
+ def release_get(self) -> dict[str, Any] | None:
"""
get release object if any
Returns:
- Optional[Dict[str, Any]]: github API release object if release found and None otherwise
+ dict[str, Any] | None: github API release object if release found and None otherwise
"""
url = f"https://api.github.com/repos/{self.github_owner}/{self.github_repository}/releases/tags/{self.architecture}"
try:
response = self._request("GET", url)
- release: Dict[str, Any] = response.json()
+ release: dict[str, Any] = response.json()
return release
except requests.HTTPError as e:
status_code = e.response.status_code if e.response is not None else None
@@ -156,23 +156,23 @@ class Github(HttpUpload):
return None
raise
- def release_update(self, release: Dict[str, Any], body: str) -> None:
+ def release_update(self, release: dict[str, Any], body: str) -> None:
"""
update release
Args:
- release(Dict[str, Any]): release object
+ release(dict[str, Any]): release object
body(str): new release body
"""
self._request("POST", release["url"], json={"body": body})
- def sync(self, path: Path, built_packages: Iterable[Package]) -> None:
+ def sync(self, path: Path, built_packages: list[Package]) -> None:
"""
sync data to remote server
Args:
path(Path): local path to sync
- built_packages(Iterable[Package]): list of packages which has just been built
+ built_packages(list[Package]): list of packages which has just been built
"""
release = self.release_get()
if release is None:
diff --git a/src/ahriman/core/upload/http_upload.py b/src/ahriman/core/upload/http_upload.py
index ad10b3f5..df423292 100644
--- a/src/ahriman/core/upload/http_upload.py
+++ b/src/ahriman/core/upload/http_upload.py
@@ -21,7 +21,7 @@ import hashlib
import requests
from pathlib import Path
-from typing import Any, Dict
+from typing import Any
from ahriman.core.configuration import Configuration
from ahriman.core.upload.upload import Upload
@@ -33,7 +33,7 @@ class HttpUpload(Upload):
helper for the http based uploads
Attributes:
- auth(Optional[Tuple[str, str]]): HTTP auth object if set
+ auth(tuple[str, str] | None): HTTP auth object if set
timeout(int): HTTP request timeout in seconds
"""
@@ -68,12 +68,12 @@ class HttpUpload(Upload):
return md5.hexdigest()
@staticmethod
- def get_body(local_files: Dict[Path, str]) -> str:
+ def get_body(local_files: dict[Path, str]) -> str:
"""
generate release body from the checksums as returned from HttpUpload.get_hashes method
Args:
- local_files(Dict[Path, str]): map of the paths to its checksum
+ local_files(dict[Path, str]): map of the paths to its checksum
Returns:
str: body to be inserted into release
@@ -81,7 +81,7 @@ class HttpUpload(Upload):
return "\n".join(f"{file.name} {md5}" for file, md5 in sorted(local_files.items()))
@staticmethod
- def get_hashes(body: str) -> Dict[str, str]:
+ def get_hashes(body: str) -> dict[str, str]:
"""
get checksums of the content from the repository
@@ -89,7 +89,7 @@ class HttpUpload(Upload):
body(str): release string body object
Returns:
- Dict[str, str]: map of the filename to its checksum as it is written in body
+ dict[str, str]: map of the filename to its checksum as it is written in body
"""
files = {}
for line in body.splitlines():
diff --git a/src/ahriman/core/upload/rsync.py b/src/ahriman/core/upload/rsync.py
index 0348f86f..fd5c66ea 100644
--- a/src/ahriman/core/upload/rsync.py
+++ b/src/ahriman/core/upload/rsync.py
@@ -18,7 +18,6 @@
# along with this program. If not, see .
#
from pathlib import Path
-from typing import Iterable
from ahriman.core.configuration import Configuration
from ahriman.core.upload.upload import Upload
@@ -31,7 +30,7 @@ class Rsync(Upload):
rsync wrapper
Attributes:
- command(List[str]): command arguments for sync
+ command(list[str]): command arguments for sync
remote(str): remote address to sync
"""
@@ -50,12 +49,12 @@ class Rsync(Upload):
self.command = configuration.getlist(section, "command")
self.remote = configuration.get(section, "remote")
- def sync(self, path: Path, built_packages: Iterable[Package]) -> None:
+ def sync(self, path: Path, built_packages: list[Package]) -> None:
"""
sync data to remote server
Args:
path(Path): local path to sync
- built_packages(Iterable[Package]): list of packages which has just been built
+ built_packages(list[Package]): list of packages which has just been built
"""
Rsync._check_output(*self.command, str(path), self.remote, logger=self.logger)
diff --git a/src/ahriman/core/upload/s3.py b/src/ahriman/core/upload/s3.py
index dc886e03..b086e734 100644
--- a/src/ahriman/core/upload/s3.py
+++ b/src/ahriman/core/upload/s3.py
@@ -22,7 +22,7 @@ import hashlib
import mimetypes
from pathlib import Path
-from typing import Any, Dict, Iterable
+from typing import Any
from ahriman.core.configuration import Configuration
from ahriman.core.upload.upload import Upload
@@ -97,27 +97,27 @@ class S3(Upload):
return client.Bucket(configuration.get(section, "bucket"))
@staticmethod
- def files_remove(local_files: Dict[Path, str], remote_objects: Dict[Path, Any]) -> None:
+ def files_remove(local_files: dict[Path, str], remote_objects: dict[Path, Any]) -> None:
"""
remove files which have been removed locally
Args:
- local_files(Dict[Path, str]): map of local path object to its checksum
- remote_objects(Dict[Path, Any]): map of remote path object to the remote s3 object
+ local_files(dict[Path, str]): map of local path object to its checksum
+ remote_objects(dict[Path, Any]): map of remote path object to the remote s3 object
"""
for local_file, remote_object in remote_objects.items():
if local_file in local_files:
continue
remote_object.delete()
- def files_upload(self, path: Path, local_files: Dict[Path, str], remote_objects: Dict[Path, Any]) -> None:
+ def files_upload(self, path: Path, local_files: dict[Path, str], remote_objects: dict[Path, Any]) -> None:
"""
upload changed files to s3
Args:
path(Path): local path to sync
- local_files(Dict[Path, str]): map of local path object to its checksum
- remote_objects(Dict[Path, Any]): map of remote path object to the remote s3 object
+ local_files(dict[Path, str]): map of local path object to its checksum
+ remote_objects(dict[Path, Any]): map of remote path object to the remote s3 object
"""
for local_file, checksum in local_files.items():
remote_object = remote_objects.get(local_file)
@@ -133,7 +133,7 @@ class S3(Upload):
self.bucket.upload_file(Filename=str(local_path), Key=str(remote_path), ExtraArgs=extra_args)
- def get_local_files(self, path: Path) -> Dict[Path, str]:
+ def get_local_files(self, path: Path) -> dict[Path, str]:
"""
get all local files and their calculated checksums
@@ -141,30 +141,30 @@ class S3(Upload):
path(Path): local path to sync
Returns:
- Dict[Path, str]: map of path object to its checksum
+ dict[Path, str]: map of path object to its checksum
"""
return {
local_file.relative_to(path): self.calculate_etag(local_file, self.chunk_size)
for local_file in walk(path)
}
- def get_remote_objects(self) -> Dict[Path, Any]:
+ def get_remote_objects(self) -> dict[Path, Any]:
"""
get all remote objects and their checksums
Returns:
- Dict[Path, Any]: map of path object to the remote s3 object
+ dict[Path, Any]: map of path object to the remote s3 object
"""
objects = self.bucket.objects.filter(Prefix=self.architecture)
return {Path(item.key).relative_to(self.architecture): item for item in objects}
- def sync(self, path: Path, built_packages: Iterable[Package]) -> None:
+ def sync(self, path: Path, built_packages: list[Package]) -> None:
"""
sync data to remote server
Args:
path(Path): local path to sync
- built_packages(Iterable[Package]): list of packages which has just been built
+ built_packages(list[Package]): list of packages which has just been built
"""
remote_objects = self.get_remote_objects()
local_files = self.get_local_files(path)
diff --git a/src/ahriman/core/upload/upload.py b/src/ahriman/core/upload/upload.py
index 5f43ca98..052fc335 100644
--- a/src/ahriman/core/upload/upload.py
+++ b/src/ahriman/core/upload/upload.py
@@ -20,7 +20,6 @@
from __future__ import annotations
from pathlib import Path
-from typing import Iterable, Type
from ahriman.core.configuration import Configuration
from ahriman.core.exceptions import SynchronizationError
@@ -68,7 +67,7 @@ class Upload(LazyLogging):
self.configuration = configuration
@classmethod
- def load(cls: Type[Upload], architecture: str, configuration: Configuration, target: str) -> Upload:
+ def load(cls: type[Upload], architecture: str, configuration: Configuration, target: str) -> Upload:
"""
load client from settings
@@ -93,13 +92,13 @@ class Upload(LazyLogging):
return Github(architecture, configuration, section)
return cls(architecture, configuration) # should never happen
- def run(self, path: Path, built_packages: Iterable[Package]) -> None:
+ def run(self, path: Path, built_packages: list[Package]) -> None:
"""
run remote sync
Args:
path(Path): local path to sync
- built_packages(Iterable[Package]): list of packages which has just been built
+ built_packages(list[Package]): list of packages which has just been built
Raises:
SyncFailed: in case of any synchronization unmatched exception
@@ -110,11 +109,11 @@ class Upload(LazyLogging):
self.logger.exception("remote sync failed")
raise SynchronizationError()
- def sync(self, path: Path, built_packages: Iterable[Package]) -> None:
+ def sync(self, path: Path, built_packages: list[Package]) -> None:
"""
sync data to remote server
Args:
path(Path): local path to sync
- built_packages(Iterable[Package]): list of packages which has just been built
+ built_packages(list[Package]): list of packages which has just been built
"""
diff --git a/src/ahriman/core/upload/upload_trigger.py b/src/ahriman/core/upload/upload_trigger.py
index 88450722..ad96f30e 100644
--- a/src/ahriman/core/upload/upload_trigger.py
+++ b/src/ahriman/core/upload/upload_trigger.py
@@ -17,8 +17,6 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-from typing import Iterable, List, Type
-
from ahriman.core.configuration import Configuration
from ahriman.core.triggers import Trigger
from ahriman.core.upload.upload import Upload
@@ -31,7 +29,7 @@ class UploadTrigger(Trigger):
synchronization trigger
Attributes:
- targets(List[str]): upload target list
+ targets(list[str]): upload target list
"""
CONFIGURATION_SCHEMA = {
@@ -138,7 +136,7 @@ class UploadTrigger(Trigger):
self.targets = self.configuration_sections(configuration)
@classmethod
- def configuration_sections(cls: Type[Trigger], configuration: Configuration) -> List[str]:
+ def configuration_sections(cls: type[Trigger], configuration: Configuration) -> list[str]:
"""
extract configuration sections from configuration
@@ -146,17 +144,17 @@ class UploadTrigger(Trigger):
configuration(Configuration): configuration instance
Returns:
- List[str]: read configuration sections belong to this trigger
+ list[str]: read configuration sections belong to this trigger
"""
return configuration.getlist("upload", "target", fallback=[])
- def on_result(self, result: Result, packages: Iterable[Package]) -> None:
+ def on_result(self, result: Result, packages: list[Package]) -> None:
"""
run trigger
Args:
result(Result): build result
- packages(Iterable[Package]): list of all available packages
+ packages(list[Package]): list of all available packages
"""
for target in self.targets:
runner = Upload.load(self.architecture, self.configuration, target)
diff --git a/src/ahriman/core/util.py b/src/ahriman/core/util.py
index fd42b478..357bc8b8 100644
--- a/src/ahriman/core/util.py
+++ b/src/ahriman/core/util.py
@@ -26,10 +26,11 @@ import re
import requests
import subprocess
+from collections.abc import Callable, Generator, Iterable
from enum import Enum
from pathlib import Path
from pwd import getpwuid
-from typing import Any, Callable, Dict, Generator, IO, Iterable, List, Optional, Tuple, Type, TypeVar, Union
+from typing import Any, IO, TypeVar
from ahriman.core.exceptions import OptionError, UnsafeRunError
from ahriman.models.repository_paths import RepositoryPaths
@@ -56,20 +57,19 @@ __all__ = [
T = TypeVar("T")
-def check_output(*args: str, exception: Optional[Exception] = None, cwd: Optional[Path] = None,
- input_data: Optional[str] = None, logger: Optional[logging.Logger] = None,
- user: Optional[int] = None) -> str:
+def check_output(*args: str, exception: Exception | None = None, cwd: Path | None = None, input_data: str | None = None,
+ logger: logging.Logger | None = None, user: int | None = None) -> str:
"""
subprocess wrapper
Args:
*args(str): command line arguments
- exception(Optional[Exception], optional): exception which has to be reraised instead of default subprocess
+ exception(Exception | None, optional): exception which has to be reraised instead of default subprocess
exception (Default value = None)
- cwd(Optional[Path], optional): current working directory (Default value = None)
- input_data(Optional[str], optional): data which will be written to command stdin (Default value = None)
- logger(Optional[logging.Logger], optional): logger to log command result if required (Default value = None)
- user(Optional[int], optional): run process as specified user (Default value = None)
+ cwd(Path | None, optional): current working directory (Default value = None)
+ input_data(str | None, optional): data which will be written to command stdin (Default value = None)
+ logger(logging.Logger | None, optional): logger to log command result if required (Default value = None)
+ user(int | None, optional): run process as specified user (Default value = None)
Returns:
str: command output
@@ -94,9 +94,9 @@ def check_output(*args: str, exception: Optional[Exception] = None, cwd: Optiona
>>> check_output("false", exception=RuntimeError("An exception occurred"))
"""
- # hack for Optional[IO[str]] handle
+ # hack for IO[str] handle
def get_io(proc: subprocess.Popen[str], channel_name: str) -> IO[str]:
- channel: Optional[IO[str]] = getattr(proc, channel_name, None)
+ channel: IO[str] | None = getattr(proc, channel_name, None)
return channel if channel is not None else io.StringIO()
def log(single: str) -> None:
@@ -114,7 +114,7 @@ def check_output(*args: str, exception: Optional[Exception] = None, cwd: Optiona
input_channel.close()
# read stdout and append to output result
- result: List[str] = []
+ result: list[str] = []
for line in iter(get_io(process, "stdout").readline, ""):
line = line.strip()
if not line: # skip empty lines
@@ -162,15 +162,15 @@ def check_user(paths: RepositoryPaths, *, unsafe: bool) -> None:
raise UnsafeRunError(current_uid, root_uid)
-def enum_values(enum: Type[Enum]) -> List[str]:
+def enum_values(enum: type[Enum]) -> list[str]:
"""
generate list of enumeration values from the source
Args:
- enum(Type[Enum]): source enumeration class
+ enum(type[Enum]): source enumeration class
Returns:
- List[str]: available enumeration values as string
+ list[str]: available enumeration values as string
"""
return [str(key.value) for key in enum] # explicit str conversion for typing
@@ -189,16 +189,16 @@ def exception_response_text(exception: requests.exceptions.HTTPError) -> str:
return result
-def filter_json(source: Dict[str, Any], known_fields: Iterable[str]) -> Dict[str, Any]:
+def filter_json(source: dict[str, Any], known_fields: Iterable[str]) -> dict[str, Any]:
"""
filter json object by fields used for json-to-object conversion
Args:
- source(Dict[str, Any]): raw json object
+ source(dict[str, Any]): raw json object
known_fields(Iterable[str]): list of fields which have to be known for the target object
Returns:
- Dict[str, Any]: json object without unknown and empty fields
+ dict[str, Any]: json object without unknown and empty fields
Examples:
This wrapper is mainly used for the dataclasses, thus the flow must be something like this::
@@ -213,12 +213,12 @@ def filter_json(source: Dict[str, Any], known_fields: Iterable[str]) -> Dict[str
return {key: value for key, value in source.items() if key in known_fields and value is not None}
-def full_version(epoch: Union[str, int, None], pkgver: str, pkgrel: str) -> str:
+def full_version(epoch: str | int | None, pkgver: str, pkgrel: str) -> str:
"""
generate full version from components
Args:
- epoch(Union[str, int, None]): package epoch if any
+ epoch(str | int | None): package epoch if any
pkgver(str): package version
pkgrel(str): package release version (arch linux specific)
@@ -243,27 +243,27 @@ def package_like(filename: Path) -> bool:
return ".pkg." in name and not name.endswith(".sig")
-def partition(source: List[T], predicate: Callable[[T], bool]) -> Tuple[List[T], List[T]]:
+def partition(source: list[T], predicate: Callable[[T], bool]) -> tuple[list[T], list[T]]:
"""
partition list into two based on predicate, based on # https://docs.python.org/dev/library/itertools.html#itertools-recipes
Args:
- source(List[T]): source list to be partitioned
+ source(list[T]): source list to be partitioned
predicate(Callable[[T], bool]): filter function
Returns:
- Tuple[List[T], List[T]]: two lists, first is which ``predicate`` is ``True``, second is ``False``
+ tuple[list[T], list[T]]: two lists, first is which ``predicate`` is ``True``, second is ``False``
"""
first_iter, second_iter = itertools.tee(source)
return list(filter(predicate, first_iter)), list(itertools.filterfalse(predicate, second_iter))
-def pretty_datetime(timestamp: Optional[Union[datetime.datetime, float, int]]) -> str:
+def pretty_datetime(timestamp: datetime.datetime | float | int | None) -> str:
"""
convert datetime object to string
Args:
- timestamp(Optional[Union[datetime.datetime, float, int]]): datetime to convert
+ timestamp(datetime.datetime | float | int | None): datetime to convert
Returns:
str: pretty printable datetime as string
@@ -275,12 +275,12 @@ def pretty_datetime(timestamp: Optional[Union[datetime.datetime, float, int]]) -
return timestamp.strftime("%Y-%m-%d %H:%M:%S")
-def pretty_size(size: Optional[float], level: int = 0) -> str:
+def pretty_size(size: float | None, level: int = 0) -> str:
"""
convert size to string
Args:
- size(Optional[float]): size to convert
+ size(float | None): size to convert
level(int, optional): represents current units, 0 is B, 1 is KiB, etc (Default value = 0)
Returns:
diff --git a/src/ahriman/models/aur_package.py b/src/ahriman/models/aur_package.py
index 65c8c0d9..709ee096 100644
--- a/src/ahriman/models/aur_package.py
+++ b/src/ahriman/models/aur_package.py
@@ -22,9 +22,10 @@ from __future__ import annotations
import datetime
import inflection
+from collections.abc import Callable
from dataclasses import dataclass, field, fields
from pyalpm import Package # type: ignore
-from typing import Any, Callable, Dict, List, Optional, Type
+from typing import Any
from ahriman.core.util import filter_json, full_version
@@ -40,23 +41,23 @@ class AURPackage:
package_base_id(int): package base ID
version(str): package base version
description(str): package base description
- url(Optional[str]): package upstream URL
+ url(str | None): package upstream URL
num_votes(int): number of votes for the package
popularity(float): package popularity
- out_of_date(Optional[datetime.datetime]): package out of date timestamp if any
- maintainer(Optional[str]): package maintainer
- submitter(Optional[str]): package first submitter
+ out_of_date(datetime.datetime | None): package out of date timestamp if any
+ maintainer(str | None): package maintainer
+ submitter(str | None): package first submitter
first_submitted(datetime.datetime): timestamp of the first package submission
last_modified(datetime.datetime): timestamp of the last package submission
url_path(str): AUR package path
repository(str): repository name of the package
- depends(List[str]): list of package dependencies
- make_depends(List[str]): list of package make dependencies
- opt_depends(List[str]): list of package optional dependencies
- conflicts(List[str]): conflicts list for the package
- provides(List[str]): list of packages which this package provides
- license(List[str]): list of package licenses
- keywords(List[str]): list of package keywords
+ depends(list[str]): list of package dependencies
+ make_depends(l[str]): list of package make dependencies
+ opt_depends(list[str]): list of package optional dependencies
+ conflicts(list[str]): conflicts list for the package
+ provides(list[str]): list of packages which this package provides
+ license(list[str]): list of package licenses
+ keywords(list[str]): list of package keywords
Examples:
Mainly this class must be used from class methods instead of default ``__init__``::
@@ -87,26 +88,26 @@ class AURPackage:
last_modified: datetime.datetime
url_path: str
description: str = "" # despite the fact that the field is required some packages don't have it
- url: Optional[str] = None
- out_of_date: Optional[datetime.datetime] = None
- maintainer: Optional[str] = None
- submitter: Optional[str] = None
+ url: str | None = None
+ out_of_date: datetime.datetime | None = None
+ maintainer: str | None = None
+ submitter: str | None = None
repository: str = "aur"
- depends: List[str] = field(default_factory=list)
- make_depends: List[str] = field(default_factory=list)
- opt_depends: List[str] = field(default_factory=list)
- conflicts: List[str] = field(default_factory=list)
- provides: List[str] = field(default_factory=list)
- license: List[str] = field(default_factory=list)
- keywords: List[str] = field(default_factory=list)
+ depends: list[str] = field(default_factory=list)
+ make_depends: list[str] = field(default_factory=list)
+ opt_depends: list[str] = field(default_factory=list)
+ conflicts: list[str] = field(default_factory=list)
+ provides: list[str] = field(default_factory=list)
+ license: list[str] = field(default_factory=list)
+ keywords: list[str] = field(default_factory=list)
@classmethod
- def from_json(cls: Type[AURPackage], dump: Dict[str, Any]) -> AURPackage:
+ def from_json(cls: type[AURPackage], dump: dict[str, Any]) -> AURPackage:
"""
construct package descriptor from RPC properties
Args:
- dump(Dict[str, Any]): json dump body
+ dump(dict[str, Any]): json dump body
Returns:
AURPackage: AUR package descriptor
@@ -117,7 +118,7 @@ class AURPackage:
return cls(**filter_json(properties, known_fields))
@classmethod
- def from_pacman(cls: Type[AURPackage], package: Package) -> AURPackage:
+ def from_pacman(cls: type[AURPackage], package: Package) -> AURPackage:
"""
construct package descriptor from official repository wrapper
@@ -154,12 +155,12 @@ class AURPackage:
)
@classmethod
- def from_repo(cls: Type[AURPackage], dump: Dict[str, Any]) -> AURPackage:
+ def from_repo(cls: type[AURPackage], dump: dict[str, Any]) -> AURPackage:
"""
construct package descriptor from official repository RPC properties
Args:
- dump(Dict[str, Any]): json dump body
+ dump(dict[str, Any]): json dump body
Returns:
AURPackage: AUR package descriptor
@@ -193,24 +194,24 @@ class AURPackage:
)
@staticmethod
- def convert(descriptor: Dict[str, Any]) -> Dict[str, Any]:
+ def convert(descriptor: dict[str, Any]) -> dict[str, Any]:
"""
covert AUR RPC key names to package keys
Args:
- descriptor(Dict[str, Any]): RPC package descriptor
+ descriptor(dict[str, Any]): RPC package descriptor
Returns:
- Dict[str, Any]: package descriptor with names converted to snake case
+ dict[str, Any]: package descriptor with names converted to snake case
"""
identity_mapper: Callable[[Any], Any] = lambda value: value
- value_mapper: Dict[str, Callable[[Any], Any]] = {
+ value_mapper: dict[str, Callable[[Any], Any]] = {
"out_of_date": lambda value: datetime.datetime.utcfromtimestamp(value) if value is not None else None,
"first_submitted": datetime.datetime.utcfromtimestamp,
"last_modified": datetime.datetime.utcfromtimestamp,
}
- result: Dict[str, Any] = {}
+ result: dict[str, Any] = {}
for api_key, api_value in descriptor.items():
property_key = inflection.underscore(api_key)
mapper = value_mapper.get(property_key, identity_mapper)
diff --git a/src/ahriman/models/auth_settings.py b/src/ahriman/models/auth_settings.py
index 1109007d..b61917a6 100644
--- a/src/ahriman/models/auth_settings.py
+++ b/src/ahriman/models/auth_settings.py
@@ -20,7 +20,6 @@
from __future__ import annotations
from enum import Enum
-from typing import Type
class AuthSettings(str, Enum):
@@ -38,7 +37,7 @@ class AuthSettings(str, Enum):
OAuth = "oauth2"
@classmethod
- def from_option(cls: Type[AuthSettings], value: str) -> AuthSettings:
+ def from_option(cls: type[AuthSettings], value: str) -> AuthSettings:
"""
construct value from configuration
diff --git a/src/ahriman/models/build_status.py b/src/ahriman/models/build_status.py
index 18b3b8b3..fe68dd49 100644
--- a/src/ahriman/models/build_status.py
+++ b/src/ahriman/models/build_status.py
@@ -21,7 +21,7 @@ from __future__ import annotations
from dataclasses import dataclass, field, fields
from enum import Enum
-from typing import Any, Dict, Type
+from typing import Any
from ahriman.core.util import filter_json, pretty_datetime, utcnow
@@ -65,12 +65,12 @@ class BuildStatus:
object.__setattr__(self, "status", BuildStatusEnum(self.status))
@classmethod
- def from_json(cls: Type[BuildStatus], dump: Dict[str, Any]) -> BuildStatus:
+ def from_json(cls: type[BuildStatus], dump: dict[str, Any]) -> BuildStatus:
"""
construct status properties from json dump
Args:
- dump(Dict[str, Any]): json dump body
+ dump(dict[str, Any]): json dump body
Returns:
BuildStatus: status properties
@@ -87,12 +87,12 @@ class BuildStatus:
"""
return f"{self.status.value} ({pretty_datetime(self.timestamp)})"
- def view(self) -> Dict[str, Any]:
+ def view(self) -> dict[str, Any]:
"""
generate json status view
Returns:
- Dict[str, Any]: json-friendly dictionary
+ dict[str, Any]: json-friendly dictionary
"""
return {
"status": self.status.value,
diff --git a/src/ahriman/models/context_key.py b/src/ahriman/models/context_key.py
index 3ec68b3a..e2e39228 100644
--- a/src/ahriman/models/context_key.py
+++ b/src/ahriman/models/context_key.py
@@ -18,7 +18,7 @@
# along with this program. If not, see .
#
from dataclasses import dataclass
-from typing import Generic, Type, TypeVar
+from typing import Generic, TypeVar
T = TypeVar("T")
@@ -31,7 +31,7 @@ class ContextKey(Generic[T]):
Attributes:
key(str): context key to lookup
- return_type(Type[T]): return type used for the specified context key
+ return_type(type[T]): return type used for the specified context key
"""
key: str
- return_type: Type[T]
+ return_type: type[T]
diff --git a/src/ahriman/models/counters.py b/src/ahriman/models/counters.py
index 3978f4d8..ccb2f8ea 100644
--- a/src/ahriman/models/counters.py
+++ b/src/ahriman/models/counters.py
@@ -20,7 +20,7 @@
from __future__ import annotations
from dataclasses import dataclass, fields
-from typing import Any, Dict, List, Tuple, Type
+from typing import Any
from ahriman.core.util import filter_json
from ahriman.models.build_status import BuildStatus
@@ -49,12 +49,12 @@ class Counters:
success: int = 0
@classmethod
- def from_json(cls: Type[Counters], dump: Dict[str, Any]) -> Counters:
+ def from_json(cls: type[Counters], dump: dict[str, Any]) -> Counters:
"""
construct counters from json dump
Args:
- dump(Dict[str, Any]): json dump body
+ dump(dict[str, Any]): json dump body
Returns:
Counters: status counters
@@ -64,12 +64,12 @@ class Counters:
return cls(**filter_json(dump, known_fields))
@classmethod
- def from_packages(cls: Type[Counters], packages: List[Tuple[Package, BuildStatus]]) -> Counters:
+ def from_packages(cls: type[Counters], packages: list[tuple[Package, BuildStatus]]) -> Counters:
"""
construct counters from packages statuses
Args:
- packages(List[Tuple[Package, BuildStatus]]): list of package and their status as per watcher property
+ packages(list[tuple[Package, BuildStatus]]): list of package and their status as per watcher property
Returns:
Counters: status counters
diff --git a/src/ahriman/models/internal_status.py b/src/ahriman/models/internal_status.py
index 444424c1..8b76c1d8 100644
--- a/src/ahriman/models/internal_status.py
+++ b/src/ahriman/models/internal_status.py
@@ -20,7 +20,7 @@
from __future__ import annotations
from dataclasses import asdict, dataclass, field
-from typing import Any, Dict, Optional, Type
+from typing import Any
from ahriman.models.build_status import BuildStatus
from ahriman.models.counters import Counters
@@ -33,25 +33,25 @@ class InternalStatus:
Attributes:
status(BuildStatus): service status
- architecture(Optional[str]): repository architecture
+ architecture(str | None): repository architecture
packages(Counters): packages statuses counter object
- repository(Optional[str]): repository name
- version(Optional[str]): service version
+ repository(str | None): repository name
+ version(str | None): service version
"""
status: BuildStatus
- architecture: Optional[str] = None
+ architecture: str | None = None
packages: Counters = field(default=Counters(total=0))
- repository: Optional[str] = None
- version: Optional[str] = None
+ repository: str | None = None
+ version: str | None = None
@classmethod
- def from_json(cls: Type[InternalStatus], dump: Dict[str, Any]) -> InternalStatus:
+ def from_json(cls: type[InternalStatus], dump: dict[str, Any]) -> InternalStatus:
"""
construct internal status from json dump
Args:
- dump(Dict[str, Any]): json dump body
+ dump(dict[str, Any]): json dump body
Returns:
InternalStatus: internal status
@@ -64,11 +64,11 @@ class InternalStatus:
repository=dump.get("repository"),
version=dump.get("version"))
- def view(self) -> Dict[str, Any]:
+ def view(self) -> dict[str, Any]:
"""
generate json status view
Returns:
- Dict[str, Any]: json-friendly dictionary
+ dict[str, Any]: json-friendly dictionary
"""
return asdict(self)
diff --git a/src/ahriman/models/migration.py b/src/ahriman/models/migration.py
index 6af20158..fe7f703e 100644
--- a/src/ahriman/models/migration.py
+++ b/src/ahriman/models/migration.py
@@ -17,9 +17,9 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
+from collections.abc import Callable
from dataclasses import dataclass
from sqlite3 import Connection
-from typing import Callable, List
from ahriman.core.configuration import Configuration
@@ -32,11 +32,11 @@ class Migration:
Attributes:
index(int): migration position
name(str): migration name
- steps(List[str]): migration steps
+ steps(list[str]): migration steps
migrate_data(Callable[[Connection, Configuration], None]): data migration callback
"""
index: int
name: str
- steps: List[str]
+ steps: list[str]
migrate_data: Callable[[Connection, Configuration], None]
diff --git a/src/ahriman/models/package.py b/src/ahriman/models/package.py
index 3f909163..1523e9a1 100644
--- a/src/ahriman/models/package.py
+++ b/src/ahriman/models/package.py
@@ -22,11 +22,12 @@ from __future__ import annotations
import copy
+from collections.abc import Iterable
from dataclasses import asdict, dataclass
from pathlib import Path
from pyalpm import vercmp # type: ignore
from srcinfo.parse import parse_srcinfo # type: ignore
-from typing import Any, Dict, Iterable, List, Optional, Set, Type, Union
+from typing import Any
from ahriman.core.alpm.pacman import Pacman
from ahriman.core.alpm.remote import AUR, Official, OfficialSyncdb
@@ -46,9 +47,9 @@ class Package(LazyLogging):
Attributes:
base(str): package base name
- packages(Dict[str, PackageDescription): map of package names to their properties.
+ packages(dict[str, PackageDescription): map of package names to their properties.
Filled only on load from archive
- remote(Optional[RemoteSource]): package remote source if applicable
+ remote(RemoteSource | None): package remote source if applicable
version(str): package full version
Examples:
@@ -73,58 +74,58 @@ class Package(LazyLogging):
base: str
version: str
- remote: Optional[RemoteSource]
- packages: Dict[str, PackageDescription]
+ remote: RemoteSource | None
+ packages: dict[str, PackageDescription]
_check_output = check_output
@property
- def depends(self) -> List[str]:
+ def depends(self) -> list[str]:
"""
get package base dependencies
Returns:
- List[str]: sum of dependencies per each package
+ list[str]: sum of dependencies per each package
"""
return sorted(set(sum((package.depends for package in self.packages.values()), start=[])))
@property
- def depends_build(self) -> Set[str]:
+ def depends_build(self) -> set[str]:
"""
get full list of external dependencies which has to be installed for build process
Returns:
- Set[str]: full dependencies list used by devtools
+ set[str]: full dependencies list used by devtools
"""
return (set(self.depends) | set(self.depends_make)).difference(self.packages_full)
@property
- def depends_make(self) -> List[str]:
+ def depends_make(self) -> list[str]:
"""
get package make dependencies
Returns:
- List[str]: sum of make dependencies per each package
+ list[str]: sum of make dependencies per each package
"""
return sorted(set(sum((package.make_depends for package in self.packages.values()), start=[])))
@property
- def depends_opt(self) -> List[str]:
+ def depends_opt(self) -> list[str]:
"""
get package optional dependencies
Returns:
- List[str]: sum of optional dependencies per each package
+ list[str]: sum of optional dependencies per each package
"""
return sorted(set(sum((package.opt_depends for package in self.packages.values()), start=[])))
@property
- def groups(self) -> List[str]:
+ def groups(self) -> list[str]:
"""
get package base groups
Returns:
- List[str]: sum of groups per each package
+ list[str]: sum of groups per each package
"""
return sorted(set(sum((package.groups for package in self.packages.values()), start=[])))
@@ -154,22 +155,22 @@ class Package(LazyLogging):
or self.base.endswith("-svn")
@property
- def licenses(self) -> List[str]:
+ def licenses(self) -> list[str]:
"""
get package base licenses
Returns:
- List[str]: sum of licenses per each package
+ list[str]: sum of licenses per each package
"""
return sorted(set(sum((package.licenses for package in self.packages.values()), start=[])))
@property
- def packages_full(self) -> List[str]:
+ def packages_full(self) -> list[str]:
"""
get full packages list including provides
Returns:
- List[str]: full list of packages which this base contains
+ list[str]: full list of packages which this base contains
"""
packages = set()
for package, properties in self.packages.items():
@@ -178,7 +179,7 @@ class Package(LazyLogging):
return sorted(packages)
@classmethod
- def from_archive(cls: Type[Package], path: Path, pacman: Pacman, remote: Optional[RemoteSource]) -> Package:
+ def from_archive(cls: type[Package], path: Path, pacman: Pacman, remote: RemoteSource | None) -> Package:
"""
construct package properties from package archive
@@ -195,7 +196,7 @@ class Package(LazyLogging):
return cls(base=package.base, version=package.version, remote=remote, packages={package.name: description})
@classmethod
- def from_aur(cls: Type[Package], name: str, pacman: Pacman) -> Package:
+ def from_aur(cls: type[Package], name: str, pacman: Pacman) -> Package:
"""
construct package properties from AUR page
@@ -215,7 +216,7 @@ class Package(LazyLogging):
packages={package.name: PackageDescription.from_aur(package)})
@classmethod
- def from_build(cls: Type[Package], path: Path, architecture: str) -> Package:
+ def from_build(cls: type[Package], path: Path, architecture: str) -> Package:
"""
construct package properties from sources directory
@@ -234,10 +235,10 @@ class Package(LazyLogging):
if errors:
raise PackageInfoError(errors)
- def get_property(key: str, properties: Dict[str, Any], default: Any) -> Any:
+ def get_property(key: str, properties: dict[str, Any], default: Any) -> Any:
return properties.get(key) or srcinfo.get(key) or default
- def get_list(key: str, properties: Dict[str, Any]) -> Any:
+ def get_list(key: str, properties: dict[str, Any]) -> Any:
return get_property(key, properties, []) + get_property(f"{key}_{architecture}", properties, [])
packages = {
@@ -253,12 +254,12 @@ class Package(LazyLogging):
return cls(base=srcinfo["pkgbase"], version=version, remote=None, packages=packages)
@classmethod
- def from_json(cls: Type[Package], dump: Dict[str, Any]) -> Package:
+ def from_json(cls: type[Package], dump: dict[str, Any]) -> Package:
"""
construct package properties from json dump
Args:
- dump(Dict[str, Any]): json dump body
+ dump(dict[str, Any]): json dump body
Returns:
Package: package properties
@@ -272,7 +273,7 @@ class Package(LazyLogging):
return cls(base=dump["base"], version=dump["version"], remote=RemoteSource.from_json(remote), packages=packages)
@classmethod
- def from_official(cls: Type[Package], name: str, pacman: Pacman, *, use_syncdb: bool = True) -> Package:
+ def from_official(cls: type[Package], name: str, pacman: Pacman, *, use_syncdb: bool = True) -> Package:
"""
construct package properties from official repository page
@@ -293,7 +294,7 @@ class Package(LazyLogging):
packages={package.name: PackageDescription.from_aur(package)})
@staticmethod
- def supported_architectures(path: Path) -> Set[str]:
+ def supported_architectures(path: Path) -> set[str]:
"""
load supported architectures from package sources
@@ -301,7 +302,7 @@ class Package(LazyLogging):
path(Path): path to package sources directory
Returns:
- Set[str]: list of package supported architectures
+ set[str]: list of package supported architectures
Raises:
InvalidPackageInfo: if there are parsing errors
@@ -349,7 +350,7 @@ class Package(LazyLogging):
return self.version
- def full_depends(self, pacman: Pacman, packages: Iterable[Package]) -> List[str]:
+ def full_depends(self, pacman: Pacman, packages: Iterable[Package]) -> list[str]:
"""
generate full dependencies list including transitive dependencies
@@ -358,7 +359,7 @@ class Package(LazyLogging):
packages(Iterable[Package]): repository package list
Returns:
- List[str]: all dependencies of the package
+ list[str]: all dependencies of the package
"""
dependencies = {}
# load own package dependencies
@@ -375,7 +376,7 @@ class Package(LazyLogging):
dependencies[provides] = pacman_package.depends
result = set(self.depends)
- current_depends: Set[str] = set()
+ current_depends: set[str] = set()
while result != current_depends:
current_depends = copy.deepcopy(result)
for package in current_depends:
@@ -383,12 +384,12 @@ class Package(LazyLogging):
return sorted(result)
- def is_newer_than(self, timestamp: Union[float, int]) -> bool:
+ def is_newer_than(self, timestamp: float | int) -> bool:
"""
check if package was built after the specified timestamp
Args:
- timestamp(int): timestamp to check build date against
+ timestamp(float | int): timestamp to check build date against
Returns:
bool: True in case if package was built after the specified date and False otherwise. In case if build date
@@ -401,7 +402,7 @@ class Package(LazyLogging):
)
def is_outdated(self, remote: Package, paths: RepositoryPaths, *,
- vcs_allowed_age: Union[float, int] = 0,
+ vcs_allowed_age: float | int = 0,
calculate_version: bool = True) -> bool:
"""
check if package is out-of-dated
@@ -409,7 +410,7 @@ class Package(LazyLogging):
Args:
remote(Package): package properties from remote source
paths(RepositoryPaths): repository paths instance. Required for VCS packages cache
- vcs_allowed_age(Union[float, int], optional): max age of the built packages before they will be
+ vcs_allowed_age(float | int, optional): max age of the built packages before they will be
forced to calculate actual version (Default value = 0)
calculate_version(bool, optional): expand version to actual value (by calculating git versions)
(Default value = True)
@@ -436,11 +437,11 @@ class Package(LazyLogging):
details = "" if self.is_single_package else f""" ({" ".join(sorted(self.packages.keys()))})"""
return f"{self.base}{details}"
- def view(self) -> Dict[str, Any]:
+ def view(self) -> dict[str, Any]:
"""
generate json package view
Returns:
- Dict[str, Any]: json-friendly dictionary
+ dict[str, Any]: json-friendly dictionary
"""
return asdict(self)
diff --git a/src/ahriman/models/package_description.py b/src/ahriman/models/package_description.py
index 4aebf465..4868f93e 100644
--- a/src/ahriman/models/package_description.py
+++ b/src/ahriman/models/package_description.py
@@ -22,7 +22,7 @@ from __future__ import annotations
from dataclasses import asdict, dataclass, field, fields
from pathlib import Path
from pyalpm import Package # type: ignore
-from typing import Any, Dict, List, Optional, Type
+from typing import Any
from ahriman.core.util import filter_json, trim_package
from ahriman.models.aur_package import AURPackage
@@ -34,19 +34,19 @@ class PackageDescription:
package specific properties
Attributes:
- architecture(Optional[str]): package architecture
- archive_size(Optional[int]): package archive size
- build_date(Optional[int]): package build date
- depends(List[str]): package dependencies list
- opt_depends(List[str]): optional package dependencies list
- make_depends(List[str]): package dependencies list used for building
- description(Optional[str]): package description
- filename(Optional[str]): package archive name
- groups(List[str]): package groups
- installed_size(Optional[int]): package installed size
- licenses(List[str]): package licenses list
- provides(List[str]): list of provided packages
- url(Optional[str]): package url
+ architecture(str | None): package architecture
+ archive_size(int | None): package archive size
+ build_date(int | None): package build date
+ depends(list[str]): package dependencies list
+ opt_depends(list[str]): optional package dependencies list
+ make_depends(list[str]): package dependencies list used for building
+ description(str | None): package description
+ filename(str | None): package archive name
+ groups(list[str]): package groups
+ installed_size(int | None): package installed size
+ licenses(list[str]): package licenses list
+ provides(list[str]): list of provided packages
+ url(str | None): package url
Examples:
Unlike the ``Package`` class, this implementation only holds properties. The recommended way to deal with it is
@@ -66,19 +66,19 @@ class PackageDescription:
>>> pyalpm_description, Path("/var/cache/pacman/pkg/pacman-6.0.1-4-x86_64.pkg.tar.zst"))
"""
- architecture: Optional[str] = None
- archive_size: Optional[int] = None
- build_date: Optional[int] = None
- depends: List[str] = field(default_factory=list)
- make_depends: List[str] = field(default_factory=list)
- opt_depends: List[str] = field(default_factory=list)
- description: Optional[str] = None
- filename: Optional[str] = None
- groups: List[str] = field(default_factory=list)
- installed_size: Optional[int] = None
- licenses: List[str] = field(default_factory=list)
- provides: List[str] = field(default_factory=list)
- url: Optional[str] = None
+ architecture: str | None = None
+ archive_size: int | None = None
+ build_date: int | None = None
+ depends: list[str] = field(default_factory=list)
+ make_depends: list[str] = field(default_factory=list)
+ opt_depends: list[str] = field(default_factory=list)
+ description: str | None = None
+ filename: str | None = None
+ groups: list[str] = field(default_factory=list)
+ installed_size: int | None = None
+ licenses: list[str] = field(default_factory=list)
+ provides: list[str] = field(default_factory=list)
+ url: str | None = None
def __post_init__(self) -> None:
"""
@@ -89,17 +89,17 @@ class PackageDescription:
self.make_depends = [trim_package(package) for package in self.make_depends]
@property
- def filepath(self) -> Optional[Path]:
+ def filepath(self) -> Path | None:
"""
wrapper for filename, convert it to Path object
Returns:
- Optional[Path]: path object for current filename
+ Path | None: path object for current filename
"""
return Path(self.filename) if self.filename is not None else None
@classmethod
- def from_aur(cls: Type[PackageDescription], package: AURPackage) -> PackageDescription:
+ def from_aur(cls: type[PackageDescription], package: AURPackage) -> PackageDescription:
"""
construct properties from AUR package model
@@ -120,12 +120,12 @@ class PackageDescription:
)
@classmethod
- def from_json(cls: Type[PackageDescription], dump: Dict[str, Any]) -> PackageDescription:
+ def from_json(cls: type[PackageDescription], dump: dict[str, Any]) -> PackageDescription:
"""
construct package properties from json dump
Args:
- dump(Dict[str, Any]): json dump body
+ dump(dict[str, Any]): json dump body
Returns:
PackageDescription: package properties
@@ -135,7 +135,7 @@ class PackageDescription:
return cls(**filter_json(dump, known_fields))
@classmethod
- def from_package(cls: Type[PackageDescription], package: Package, path: Path) -> PackageDescription:
+ def from_package(cls: type[PackageDescription], package: Package, path: Path) -> PackageDescription:
"""
construct class from alpm package class
@@ -162,11 +162,11 @@ class PackageDescription:
url=package.url,
)
- def view(self) -> Dict[str, Any]:
+ def view(self) -> dict[str, Any]:
"""
generate json package view
Returns:
- Dict[str, Any]: json-friendly dictionary
+ dict[str, Any]: json-friendly dictionary
"""
return asdict(self)
diff --git a/src/ahriman/models/pkgbuild_patch.py b/src/ahriman/models/pkgbuild_patch.py
index fab8f78b..a547874c 100644
--- a/src/ahriman/models/pkgbuild_patch.py
+++ b/src/ahriman/models/pkgbuild_patch.py
@@ -21,7 +21,6 @@ import shlex
from dataclasses import dataclass, field
from pathlib import Path
-from typing import List, Optional, Union
@dataclass(frozen=True)
@@ -30,15 +29,15 @@ class PkgbuildPatch:
wrapper for patching PKBGUILDs
Attributes:
- key(Optional[str]): name of the property in PKGBUILD, e.g. version, url etc. If not set, patch will be
+ key(str | None): name of the property in PKGBUILD, e.g. version, url etc. If not set, patch will be
considered as full PKGBUILD diffs
- value(Union[str, List[str]]): value of the stored PKGBUILD property. It must be either string or list of string
+ value(str | list[str]): value of the stored PKGBUILD property. It must be either string or list of string
values
unsafe(bool): if set, value will be not quoted, might break PKGBUILD
"""
- key: Optional[str]
- value: Union[str, List[str]]
+ key: str | None
+ value: str | list[str]
unsafe: bool = field(default=False, kw_only=True)
def __post_init__(self) -> None:
@@ -81,7 +80,7 @@ class PkgbuildPatch:
def serialize(self) -> str:
"""
- serialize key-value pair into PKBGBUILD string. List values will be put inside parentheses. All string
+ serialize key-value pair into PKGBUILD string. List values will be put inside parentheses. All string
values (including the ones inside list values) will be put inside quotes, no shell variables expanding supported
at the moment
diff --git a/src/ahriman/models/remote_source.py b/src/ahriman/models/remote_source.py
index 2f5c93ad..47aca111 100644
--- a/src/ahriman/models/remote_source.py
+++ b/src/ahriman/models/remote_source.py
@@ -21,7 +21,7 @@ from __future__ import annotations
from dataclasses import asdict, dataclass, fields
from pathlib import Path
-from typing import Any, Dict, Optional, Type
+from typing import Any
from ahriman.core.util import filter_json
from ahriman.models.package_source import PackageSource
@@ -63,15 +63,15 @@ class RemoteSource:
return Path(self.path)
@classmethod
- def from_json(cls: Type[RemoteSource], dump: Dict[str, Any]) -> Optional[RemoteSource]:
+ def from_json(cls: type[RemoteSource], dump: dict[str, Any]) -> RemoteSource | None:
"""
construct remote source from the json dump (or database row)
Args:
- dump(Dict[str, Any]): json dump body
+ dump(dict[str, Any]): json dump body
Returns:
- Optional[RemoteSource]: remote source
+ RemoteSource | None: remote source
"""
# filter to only known fields
known_fields = [pair.name for pair in fields(cls)]
@@ -81,8 +81,8 @@ class RemoteSource:
return None
@classmethod
- def from_source(cls: Type[RemoteSource], source: PackageSource, package_base: str,
- repository: str) -> Optional[RemoteSource]:
+ def from_source(cls: type[RemoteSource], source: PackageSource, package_base: str,
+ repository: str) -> RemoteSource | None:
"""
generate remote source from the package base
@@ -92,7 +92,7 @@ class RemoteSource:
repository(str): repository name
Returns:
- Optional[RemoteSource]: generated remote source if any, None otherwise
+ RemoteSource | None: generated remote source if any, None otherwise
"""
if source == PackageSource.AUR:
from ahriman.core.alpm.remote import AUR
@@ -114,11 +114,11 @@ class RemoteSource:
)
return None
- def view(self) -> Dict[str, Any]:
+ def view(self) -> dict[str, Any]:
"""
generate json package remote view
Returns:
- Dict[str, Any]: json-friendly dictionary
+ dict[str, Any]: json-friendly dictionary
"""
return asdict(self)
diff --git a/src/ahriman/models/report_settings.py b/src/ahriman/models/report_settings.py
index 290d667b..d6eef851 100644
--- a/src/ahriman/models/report_settings.py
+++ b/src/ahriman/models/report_settings.py
@@ -20,7 +20,6 @@
from __future__ import annotations
from enum import Enum
-from typing import Type
class ReportSettings(str, Enum):
@@ -42,7 +41,7 @@ class ReportSettings(str, Enum):
Telegram = "telegram"
@classmethod
- def from_option(cls: Type[ReportSettings], value: str) -> ReportSettings:
+ def from_option(cls: type[ReportSettings], value: str) -> ReportSettings:
"""
construct value from configuration
diff --git a/src/ahriman/models/repository_paths.py b/src/ahriman/models/repository_paths.py
index 68f61ad1..607d5915 100644
--- a/src/ahriman/models/repository_paths.py
+++ b/src/ahriman/models/repository_paths.py
@@ -24,7 +24,6 @@ import shutil
from dataclasses import dataclass
from pathlib import Path
-from typing import Set, Tuple, Type
from ahriman.core.exceptions import PathError
@@ -108,17 +107,17 @@ class RepositoryPaths:
return self.root / "repository" / self.architecture
@property
- def root_owner(self) -> Tuple[int, int]:
+ def root_owner(self) -> tuple[int, int]:
"""
get UID and GID of the root directory
Returns:
- Tuple[int, int]: owner user and group of the root directory
+ tuple[int, int]: owner user and group of the root directory
"""
return self.owner(self.root)
@classmethod
- def known_architectures(cls: Type[RepositoryPaths], root: Path) -> Set[str]:
+ def known_architectures(cls: type[RepositoryPaths], root: Path) -> set[str]:
"""
get known architectures
@@ -126,7 +125,7 @@ class RepositoryPaths:
root(Path): repository root
Returns:
- Set[str]: list of architectures for which tree is created
+ set[str]: list of architectures for which tree is created
"""
paths = cls(root, "")
return {
@@ -136,7 +135,7 @@ class RepositoryPaths:
}
@staticmethod
- def owner(path: Path) -> Tuple[int, int]:
+ def owner(path: Path) -> tuple[int, int]:
"""
retrieve owner information by path
@@ -144,7 +143,7 @@ class RepositoryPaths:
path(Path): path for which extract ids
Returns:
- Tuple[int, int]: owner user and group ids of the directory
+ tuple[int, int]: owner user and group ids of the directory
"""
stat = path.stat()
return stat.st_uid, stat.st_gid
diff --git a/src/ahriman/models/result.py b/src/ahriman/models/result.py
index 1fbb7326..75cc0034 100644
--- a/src/ahriman/models/result.py
+++ b/src/ahriman/models/result.py
@@ -19,7 +19,8 @@
#
from __future__ import annotations
-from typing import Any, Iterable, List, Optional
+from collections.abc import Iterable
+from typing import Any
from ahriman.core.exceptions import UnprocessedPackageStatusError
from ahriman.models.package import Package
@@ -30,13 +31,13 @@ class Result:
build result class holder
"""
- def __init__(self, success: Optional[Iterable[Package]] = None, failed: Optional[Iterable[Package]] = None) -> None:
+ def __init__(self, success: Iterable[Package] | None = None, failed: Iterable[Package] | None = None) -> None:
"""
default constructor
Args:
- success(Optional[Iterable[Package]], optional): initial list of successes packages (Default value = None)
- failed(Optional[Iterable[Package]], optional): initial list of failed packages (Default value = None)
+ success(Iterable[Package] | None, optional): initial list of successes packages (Default value = None)
+ failed(Iterable[Package] | None, optional): initial list of failed packages (Default value = None)
"""
success = success or []
self._success = {package.base: package for package in success}
@@ -44,12 +45,12 @@ class Result:
self._failed = {package.base: package for package in failed}
@property
- def failed(self) -> List[Package]:
+ def failed(self) -> list[Package]:
"""
get list of failed packages
Returns:
- List[Package]: list of packages which were failed
+ list[Package]: list of packages which were failed
"""
return list(self._failed.values())
@@ -64,12 +65,12 @@ class Result:
return not bool(self._success)
@property
- def success(self) -> List[Package]:
+ def success(self) -> list[Package]:
"""
get list of success builds
Returns:
- List[Package]: list of packages with success result
+ list[Package]: list of packages with success result
"""
return list(self._success.values())
diff --git a/src/ahriman/models/sign_settings.py b/src/ahriman/models/sign_settings.py
index 20b70dea..bfeadb76 100644
--- a/src/ahriman/models/sign_settings.py
+++ b/src/ahriman/models/sign_settings.py
@@ -20,7 +20,6 @@
from __future__ import annotations
from enum import Enum
-from typing import Type
class SignSettings(str, Enum):
@@ -38,7 +37,7 @@ class SignSettings(str, Enum):
Repository = "repository"
@classmethod
- def from_option(cls: Type[SignSettings], value: str) -> SignSettings:
+ def from_option(cls: type[SignSettings], value: str) -> SignSettings:
"""
construct value from configuration
diff --git a/src/ahriman/models/smtp_ssl_settings.py b/src/ahriman/models/smtp_ssl_settings.py
index 48843725..752fa84d 100644
--- a/src/ahriman/models/smtp_ssl_settings.py
+++ b/src/ahriman/models/smtp_ssl_settings.py
@@ -20,7 +20,6 @@
from __future__ import annotations
from enum import Enum
-from typing import Type
class SmtpSSLSettings(str, Enum):
@@ -38,7 +37,7 @@ class SmtpSSLSettings(str, Enum):
STARTTLS = "starttls"
@classmethod
- def from_option(cls: Type[SmtpSSLSettings], value: str) -> SmtpSSLSettings:
+ def from_option(cls: type[SmtpSSLSettings], value: str) -> SmtpSSLSettings:
"""
construct value from configuration
diff --git a/src/ahriman/models/upload_settings.py b/src/ahriman/models/upload_settings.py
index 3ebaff94..26456642 100644
--- a/src/ahriman/models/upload_settings.py
+++ b/src/ahriman/models/upload_settings.py
@@ -20,7 +20,6 @@
from __future__ import annotations
from enum import Enum
-from typing import Type
class UploadSettings(str, Enum):
@@ -40,7 +39,7 @@ class UploadSettings(str, Enum):
Github = "github"
@classmethod
- def from_option(cls: Type[UploadSettings], value: str) -> UploadSettings:
+ def from_option(cls: type[UploadSettings], value: str) -> UploadSettings:
"""
construct value from configuration
diff --git a/src/ahriman/models/user.py b/src/ahriman/models/user.py
index ecf7f2af..20efa6de 100644
--- a/src/ahriman/models/user.py
+++ b/src/ahriman/models/user.py
@@ -20,9 +20,8 @@
from __future__ import annotations
from dataclasses import dataclass, replace
-from typing import Optional, Type
+from passlib.hash import sha512_crypt
from passlib.pwd import genword as generate_password
-from passlib.handlers.sha2_crypt import sha512_crypt
from ahriman.models.user_access import UserAccess
@@ -67,18 +66,18 @@ class User:
_HASHER = sha512_crypt
@classmethod
- def from_option(cls: Type[User], username: Optional[str], password: Optional[str],
- access: UserAccess = UserAccess.Read) -> Optional[User]:
+ def from_option(cls: type[User], username: str | None, password: str | None,
+ access: UserAccess = UserAccess.Read) -> User | None:
"""
build user descriptor from configuration options
Args:
- username(Optional[str]): username
- password(Optional[str]): password as string
+ username(str | None): username
+ password(str | None): password as string
access(UserAccess, optional): optional user access (Default value = UserAccess.Read)
Returns:
- Optional[User]: generated user descriptor if all options are supplied and None otherwise
+ User | None: generated user descriptor if all options are supplied and None otherwise
"""
if username is None or password is None:
return None
diff --git a/src/ahriman/web/apispec.py b/src/ahriman/web/apispec.py
index a7117064..21bf7a80 100644
--- a/src/ahriman/web/apispec.py
+++ b/src/ahriman/web/apispec.py
@@ -20,7 +20,7 @@
import aiohttp_apispec # type: ignore
from aiohttp.web import Application
-from typing import Any, Dict, List
+from typing import Any
from ahriman import version
from ahriman.core.configuration import Configuration
@@ -29,12 +29,12 @@ from ahriman.core.configuration import Configuration
__all__ = ["setup_apispec"]
-def _info() -> Dict[str, Any]:
+def _info() -> dict[str, Any]:
"""
create info object for swagger docs
Returns:
- Dict[str, Any]: info object as per openapi specification
+ dict[str, Any]: info object as per openapi specification
"""
return {
"title": "ahriman",
@@ -62,12 +62,12 @@ def _info() -> Dict[str, Any]:
}
-def _security() -> List[Dict[str, Any]]:
+def _security() -> list[dict[str, Any]]:
"""
get security definitions
Returns:
- List[Dict[str, Any]]: generated security definition
+ list[dict[str, Any]]: generated security definition
"""
return [{
"token": {
@@ -78,7 +78,7 @@ def _security() -> List[Dict[str, Any]]:
}]
-def _servers(application: Application) -> List[Dict[str, Any]]:
+def _servers(application: Application) -> list[dict[str, Any]]:
"""
get list of defined addresses for server
@@ -86,7 +86,7 @@ def _servers(application: Application) -> List[Dict[str, Any]]:
application(Application): web application instance
Returns:
- List[Dict[str, Any]]: list (actually only one) of defined web urls
+ list[dict[str, Any]]: list (actually only one) of defined web urls
"""
configuration: Configuration = application["configuration"]
address = configuration.get("web", "address", fallback=None)
diff --git a/src/ahriman/web/middlewares/__init__.py b/src/ahriman/web/middlewares/__init__.py
index 784a4c7b..361512c7 100644
--- a/src/ahriman/web/middlewares/__init__.py
+++ b/src/ahriman/web/middlewares/__init__.py
@@ -18,7 +18,7 @@
# along with this program. If not, see .
#
from aiohttp.web import Request, StreamResponse
-from typing import Awaitable, Callable
+from collections.abc import Awaitable, Callable
HandlerType = Callable[[Request], Awaitable[StreamResponse]]
diff --git a/src/ahriman/web/middlewares/auth_handler.py b/src/ahriman/web/middlewares/auth_handler.py
index cb651cf4..21770383 100644
--- a/src/ahriman/web/middlewares/auth_handler.py
+++ b/src/ahriman/web/middlewares/auth_handler.py
@@ -25,7 +25,6 @@ from aiohttp.web import Application, Request, StaticResource, StreamResponse, mi
from aiohttp_session import setup as setup_session
from aiohttp_session.cookie_storage import EncryptedCookieStorage
from cryptography import fernet
-from typing import Optional
from ahriman.core.auth import Auth
from ahriman.core.configuration import Configuration
@@ -53,7 +52,7 @@ class _AuthorizationPolicy(aiohttp_security.AbstractAuthorizationPolicy):
"""
self.validator = validator
- async def authorized_userid(self, identity: str) -> Optional[str]:
+ async def authorized_userid(self, identity: str) -> str | None:
"""
retrieve authenticated username
@@ -61,18 +60,18 @@ class _AuthorizationPolicy(aiohttp_security.AbstractAuthorizationPolicy):
identity(str): username
Returns:
- Optional[str]: user identity (username) in case if user exists and None otherwise
+ str | None: user identity (username) in case if user exists and None otherwise
"""
return identity if await self.validator.known_username(identity) else None
- async def permits(self, identity: str, permission: UserAccess, context: Optional[str] = None) -> bool:
+ async def permits(self, identity: str, permission: UserAccess, context: str | None = None) -> bool:
"""
check user permissions
Args:
identity(str): username
permission(UserAccess): requested permission level
- context(Optional[str], optional): URI request path (Default value = None)
+ context(str | None, optional): URI request path (Default value = None)
Returns:
bool: True in case if user is allowed to perform this request and False otherwise
diff --git a/src/ahriman/web/views/api/docs.py b/src/ahriman/web/views/api/docs.py
index 8f9564a2..24a6bfd5 100644
--- a/src/ahriman/web/views/api/docs.py
+++ b/src/ahriman/web/views/api/docs.py
@@ -19,7 +19,7 @@
#
import aiohttp_jinja2
-from typing import Any, Dict
+from typing import Any
from ahriman.models.user_access import UserAccess
from ahriman.web.views.base import BaseView
@@ -36,11 +36,11 @@ class DocsView(BaseView):
GET_PERMISSION = UserAccess.Unauthorized
@aiohttp_jinja2.template("api.jinja2")
- async def get(self) -> Dict[str, Any]:
+ async def get(self) -> dict[str, Any]:
"""
return static docs html
Returns:
- Dict[str, Any]: parameters for jinja template
+ dict[str, Any]: parameters for jinja template
"""
return {}
diff --git a/src/ahriman/web/views/api/swagger.py b/src/ahriman/web/views/api/swagger.py
index 6a11483f..a27ae60a 100644
--- a/src/ahriman/web/views/api/swagger.py
+++ b/src/ahriman/web/views/api/swagger.py
@@ -18,7 +18,7 @@
# along with this program. If not, see .
#
from aiohttp.web import Response, json_response
-from typing import Callable, Dict
+from collections.abc import Callable
from ahriman.core.util import partition
from ahriman.models.user_access import UserAccess
@@ -43,7 +43,7 @@ class SwaggerView(BaseView):
Response: 200 with json api specification
"""
spec = self.request.app["swagger_dict"]
- is_body_parameter: Callable[[Dict[str, str]], bool] = lambda p: p["in"] == "body"
+ is_body_parameter: Callable[[dict[str, str]], bool] = lambda p: p["in"] == "body"
# special workaround because it writes request body to parameters section
paths = spec["paths"]
diff --git a/src/ahriman/web/views/base.py b/src/ahriman/web/views/base.py
index b21e2d6c..15ceffe1 100644
--- a/src/ahriman/web/views/base.py
+++ b/src/ahriman/web/views/base.py
@@ -21,7 +21,8 @@ from __future__ import annotations
from aiohttp_cors import CorsViewMixin # type: ignore
from aiohttp.web import Request, StreamResponse, View
-from typing import Any, Awaitable, Callable, Dict, List, Optional, Type, TypeVar
+from collections.abc import Awaitable, Callable
+from typing import Any, TypeVar
from ahriman.core.auth import Auth
from ahriman.core.configuration import Configuration
@@ -29,7 +30,8 @@ from ahriman.core.spawn import Spawn
from ahriman.core.status.watcher import Watcher
from ahriman.models.user_access import UserAccess
-T = TypeVar("T", str, List[str])
+
+T = TypeVar("T", str, list[str])
class BaseView(View, CorsViewMixin):
@@ -87,7 +89,7 @@ class BaseView(View, CorsViewMixin):
return validator
@classmethod
- async def get_permission(cls: Type[BaseView], request: Request) -> UserAccess:
+ async def get_permission(cls: type[BaseView], request: Request) -> UserAccess:
"""
retrieve user permission from the request
@@ -102,12 +104,12 @@ class BaseView(View, CorsViewMixin):
return permission
@staticmethod
- def get_non_empty(extractor: Callable[[str], Optional[T]], key: str) -> T:
+ def get_non_empty(extractor: Callable[[str], T | None], key: str) -> T:
"""
get non-empty value from request parameters
Args:
- extractor(Callable[[str], T]): function to get value by the specified key
+ extractor(Callable[[str], T | None]): function to get value by the specified key
key(str): key to extract value
Returns:
@@ -124,19 +126,19 @@ class BaseView(View, CorsViewMixin):
raise KeyError(f"Key {key} is missing or empty")
return value
- async def data_as_json(self, list_keys: List[str]) -> Dict[str, Any]:
+ async def data_as_json(self, list_keys: list[str]) -> dict[str, Any]:
"""
extract form data and convert it to json object
Args:
- list_keys(List[str]): list of keys which must be forced to list from form data
+ list_keys(list[str]): list of keys which must be forced to list from form data
Returns:
- Dict[str, Any]: form data converted to json. In case if a key is found multiple times
+ dict[str, Any]: form data converted to json. In case if a key is found multiple times
it will be returned as list
"""
raw = await self.request.post()
- json: Dict[str, Any] = {}
+ json: dict[str, Any] = {}
for key, value in raw.items():
if key in json and isinstance(json[key], list):
json[key].append(value)
@@ -148,19 +150,19 @@ class BaseView(View, CorsViewMixin):
json[key] = value
return json
- async def extract_data(self, list_keys: Optional[List[str]] = None) -> Dict[str, Any]:
+ async def extract_data(self, list_keys: list[str] | None = None) -> dict[str, Any]:
"""
extract json data from either json or form data
Args:
- list_keys(Optional[List[str]], optional): optional list of keys which must be forced to list from form data
+ list_keys(list[str] | None, optional): optional list of keys which must be forced to list from form data
(Default value = None)
Returns:
- Dict[str, Any]: raw json object or form data converted to json
+ dict[str, Any]: raw json object or form data converted to json
"""
try:
- json: Dict[str, Any] = await self.request.json()
+ json: dict[str, Any] = await self.request.json()
return json
except ValueError:
return await self.data_as_json(list_keys or [])
@@ -173,7 +175,7 @@ class BaseView(View, CorsViewMixin):
Raises:
HTTPMethodNotAllowed: in case if there is no GET method implemented
"""
- get_method: Optional[Callable[..., Awaitable[StreamResponse]]] = getattr(self, "get", None)
+ get_method: Callable[..., Awaitable[StreamResponse]] | None = getattr(self, "get", None)
# using if/else in order to suppress mypy warning which doesn't know that
# ``_raise_allowed_methods`` raises exception
if get_method is not None:
diff --git a/src/ahriman/web/views/index.py b/src/ahriman/web/views/index.py
index bbc6810c..b2df4a48 100644
--- a/src/ahriman/web/views/index.py
+++ b/src/ahriman/web/views/index.py
@@ -19,7 +19,7 @@
#
import aiohttp_jinja2
-from typing import Any, Dict
+from typing import Any
from ahriman.core.auth.helpers import authorized_userid
from ahriman.models.user_access import UserAccess
@@ -46,12 +46,12 @@ class IndexView(BaseView):
GET_PERMISSION = UserAccess.Unauthorized
@aiohttp_jinja2.template("build-status.jinja2")
- async def get(self) -> Dict[str, Any]:
+ async def get(self) -> dict[str, Any]:
"""
process get request. No parameters supported here
Returns:
- Dict[str, Any]: parameters for jinja template
+ dict[str, Any]: parameters for jinja template
"""
auth_username = await authorized_userid(self.request)
auth = {
diff --git a/src/ahriman/web/views/service/search.py b/src/ahriman/web/views/service/search.py
index a1b79257..2cd33010 100644
--- a/src/ahriman/web/views/service/search.py
+++ b/src/ahriman/web/views/service/search.py
@@ -20,7 +20,7 @@
import aiohttp_apispec # type: ignore
from aiohttp.web import HTTPBadRequest, HTTPNotFound, Response, json_response
-from typing import Callable, List
+from collections.abc import Callable
from ahriman.core.alpm.remote import AUR
from ahriman.models.aur_package import AURPackage
@@ -70,7 +70,7 @@ class SearchView(BaseView):
HTTPNotFound: if no packages found
"""
try:
- search: List[str] = self.get_non_empty(lambda key: self.request.query.getall(key, default=[]), "for")
+ search: list[str] = self.get_non_empty(lambda key: self.request.query.getall(key, default=[]), "for")
packages = AUR.multisearch(*search, pacman=self.service.repository.pacman)
except Exception as e:
raise HTTPBadRequest(reason=str(e))
diff --git a/src/ahriman/web/web.py b/src/ahriman/web/web.py
index 057af31e..f25f72a8 100644
--- a/src/ahriman/web/web.py
+++ b/src/ahriman/web/web.py
@@ -23,7 +23,6 @@ import logging
import socket
from aiohttp.web import Application, normalize_path_middleware, run_app
-from typing import Optional
from ahriman.core.auth import Auth
from ahriman.core.configuration import Configuration
@@ -41,7 +40,7 @@ from ahriman.web.routes import setup_routes
__all__ = ["run_server", "setup_service"]
-def _create_socket(configuration: Configuration, application: Application) -> Optional[socket.socket]:
+def _create_socket(configuration: Configuration, application: Application) -> socket.socket | None:
"""
create unix socket based on configuration option
@@ -50,7 +49,7 @@ def _create_socket(configuration: Configuration, application: Application) -> Op
application(Application): web application instance
Returns:
- Optional[socket.socket]: unix socket object if set by option
+ socket.socket | None: unix socket object if set by option
"""
unix_socket = configuration.getpath("web", "unix_socket", fallback=None)
if unix_socket is None:
diff --git a/tests/ahriman/application/handlers/test_handler_rebuild.py b/tests/ahriman/application/handlers/test_handler_rebuild.py
index 7f46706b..b7e7416b 100644
--- a/tests/ahriman/application/handlers/test_handler_rebuild.py
+++ b/tests/ahriman/application/handlers/test_handler_rebuild.py
@@ -99,7 +99,7 @@ def test_run_filter(args: argparse.Namespace, configuration: Configuration, repo
application_packages_mock = mocker.patch("ahriman.core.repository.repository.Repository.packages_depend_on")
Rebuild.run(args, "x86_64", configuration, report=False, unsafe=False)
- application_packages_mock.assert_called_once_with([], {"python-aur"})
+ application_packages_mock.assert_called_once_with([], ["python-aur"])
def test_run_without_filter(args: argparse.Namespace, configuration: Configuration, repository: Repository,
diff --git a/tests/ahriman/conftest.py b/tests/ahriman/conftest.py
index 131ea780..a7a7a138 100644
--- a/tests/ahriman/conftest.py
+++ b/tests/ahriman/conftest.py
@@ -3,7 +3,7 @@ import pytest
from pathlib import Path
from pytest_mock import MockerFixture
-from typing import Any, Dict, Type, TypeVar
+from typing import Any, TypeVar
from unittest.mock import MagicMock
from ahriman.core.alpm.pacman import Pacman
@@ -31,12 +31,12 @@ T = TypeVar("T")
# helpers
# https://stackoverflow.com/a/21611963
@pytest.helpers.register
-def anyvar(cls: Type[T], strict: bool = False) -> T:
+def anyvar(cls: type[T], strict: bool = False) -> T:
"""
any value helper for mocker calls check
Args:
- cls(Type[T]): type of the variable to check
+ cls(type[T]): type of the variable to check
strict(bool, optional): if True then check type of supplied argument (Default value = False)
Returns:
@@ -61,7 +61,7 @@ def anyvar(cls: Type[T], strict: bool = False) -> T:
@pytest.helpers.register
-def get_package_status(package: Package) -> Dict[str, Any]:
+def get_package_status(package: Package) -> dict[str, Any]:
"""
helper to extract package status from package
@@ -69,13 +69,13 @@ def get_package_status(package: Package) -> Dict[str, Any]:
package(Package): package object
Returns:
- Dict[str, Any]: simplified package status map (with only status and view)
+ dict[str, Any]: simplified package status map (with only status and view)
"""
return {"status": BuildStatusEnum.Unknown.value, "package": package.view()}
@pytest.helpers.register
-def get_package_status_extended(package: Package) -> Dict[str, Any]:
+def get_package_status_extended(package: Package) -> dict[str, Any]:
"""
helper to extract package status from package
@@ -83,7 +83,7 @@ def get_package_status_extended(package: Package) -> Dict[str, Any]:
package(Package): package object
Returns:
- Dict[str, Any]: full package status map (with timestamped build status and view)
+ dict[str, Any]: full package status map (with timestamped build status and view)
"""
return {"status": BuildStatus().view(), "package": package.view()}
diff --git a/tests/ahriman/core/repository/test_repository.py b/tests/ahriman/core/repository/test_repository.py
index e958a324..8120ee7b 100644
--- a/tests/ahriman/core/repository/test_repository.py
+++ b/tests/ahriman/core/repository/test_repository.py
@@ -125,7 +125,7 @@ def test_packages_depend_on(repository: Repository, package_ahriman: Package, pa
"""
mocker.patch("ahriman.core.repository.repository.Repository.packages",
return_value=[package_ahriman, package_python_schedule])
- assert repository.packages_depend_on([package_ahriman], ["python-srcinfo"]) == [package_ahriman]
+ assert repository.packages_depend_on([package_ahriman], {"python-srcinfo"}) == [package_ahriman]
def test_packages_depend_on_empty(repository: Repository, package_ahriman: Package, package_python_schedule: Package,
diff --git a/tests/ahriman/core/upload/conftest.py b/tests/ahriman/core/upload/conftest.py
index cbb18ec3..00b4abb2 100644
--- a/tests/ahriman/core/upload/conftest.py
+++ b/tests/ahriman/core/upload/conftest.py
@@ -1,6 +1,6 @@
import pytest
-from typing import Any, Dict, List
+from typing import Any
from unittest.mock import MagicMock
from ahriman.core.configuration import Configuration
@@ -24,12 +24,12 @@ def github(configuration: Configuration) -> Github:
@pytest.fixture
-def github_release() -> Dict[str, Any]:
+def github_release() -> dict[str, Any]:
"""
fixture for the github release object
Returns:
- Dict[str, Any]: github test release object
+ dict[str, Any]: github test release object
"""
return {
"url": "release_url",
@@ -74,12 +74,12 @@ def s3(configuration: Configuration) -> S3:
@pytest.fixture
-def s3_remote_objects() -> List[MagicMock]:
+def s3_remote_objects() -> list[MagicMock]:
"""
fixture for boto3 like S3 objects
Returns:
- List[MagicMock]: boto3 like S3 objects test instance
+ list[MagicMock]: boto3 like S3 objects test instance
"""
delete_mock = MagicMock()
diff --git a/tests/ahriman/core/upload/test_github.py b/tests/ahriman/core/upload/test_github.py
index 1b62712f..b810b9f9 100644
--- a/tests/ahriman/core/upload/test_github.py
+++ b/tests/ahriman/core/upload/test_github.py
@@ -3,13 +3,13 @@ import requests
from pathlib import Path
from pytest_mock import MockerFixture
-from typing import Any, Dict
+from typing import Any
from unittest.mock import call as MockCall
from ahriman.core.upload.github import Github
-def test_asset_remove(github: Github, github_release: Dict[str, Any], mocker: MockerFixture) -> None:
+def test_asset_remove(github: Github, github_release: dict[str, Any], mocker: MockerFixture) -> None:
"""
must remove asset from the release
"""
@@ -18,7 +18,7 @@ def test_asset_remove(github: Github, github_release: Dict[str, Any], mocker: Mo
request_mock.assert_called_once_with("DELETE", "asset_url")
-def test_asset_remove_unknown(github: Github, github_release: Dict[str, Any], mocker: MockerFixture) -> None:
+def test_asset_remove_unknown(github: Github, github_release: dict[str, Any], mocker: MockerFixture) -> None:
"""
must not fail if no asset found
"""
@@ -27,7 +27,7 @@ def test_asset_remove_unknown(github: Github, github_release: Dict[str, Any], mo
request_mock.assert_not_called()
-def test_asset_upload(github: Github, github_release: Dict[str, Any], mocker: MockerFixture) -> None:
+def test_asset_upload(github: Github, github_release: dict[str, Any], mocker: MockerFixture) -> None:
"""
must upload asset to the repository
"""
@@ -41,7 +41,7 @@ def test_asset_upload(github: Github, github_release: Dict[str, Any], mocker: Mo
remove_mock.assert_not_called()
-def test_asset_upload_with_removal(github: Github, github_release: Dict[str, Any], mocker: MockerFixture) -> None:
+def test_asset_upload_with_removal(github: Github, github_release: dict[str, Any], mocker: MockerFixture) -> None:
"""
must remove existing file before upload
"""
@@ -57,7 +57,7 @@ def test_asset_upload_with_removal(github: Github, github_release: Dict[str, Any
])
-def test_asset_upload_empty_mimetype(github: Github, github_release: Dict[str, Any], mocker: MockerFixture) -> None:
+def test_asset_upload_empty_mimetype(github: Github, github_release: dict[str, Any], mocker: MockerFixture) -> None:
"""
must upload asset to the repository with empty mime type if the library cannot guess it
"""
@@ -80,7 +80,7 @@ def test_get_local_files(github: Github, resource_path_root: Path, mocker: Mocke
walk_mock.assert_called()
-def test_files_remove(github: Github, github_release: Dict[str, Any], mocker: MockerFixture) -> None:
+def test_files_remove(github: Github, github_release: dict[str, Any], mocker: MockerFixture) -> None:
"""
must remove files from the remote
"""
@@ -89,7 +89,7 @@ def test_files_remove(github: Github, github_release: Dict[str, Any], mocker: Mo
remove_mock.assert_called_once_with(github_release, "b")
-def test_files_remove_empty(github: Github, github_release: Dict[str, Any], mocker: MockerFixture) -> None:
+def test_files_remove_empty(github: Github, github_release: dict[str, Any], mocker: MockerFixture) -> None:
"""
must remove nothing if nothing changed
"""
@@ -98,7 +98,7 @@ def test_files_remove_empty(github: Github, github_release: Dict[str, Any], mock
remove_mock.assert_not_called()
-def test_files_upload(github: Github, github_release: Dict[str, Any], mocker: MockerFixture) -> None:
+def test_files_upload(github: Github, github_release: dict[str, Any], mocker: MockerFixture) -> None:
"""
must upload files to the remote
"""
@@ -110,7 +110,7 @@ def test_files_upload(github: Github, github_release: Dict[str, Any], mocker: Mo
])
-def test_files_upload_empty(github: Github, github_release: Dict[str, Any], mocker: MockerFixture) -> None:
+def test_files_upload_empty(github: Github, github_release: dict[str, Any], mocker: MockerFixture) -> None:
"""
must upload nothing if nothing changed
"""
@@ -167,7 +167,7 @@ def test_release_get_exception_http_error(github: Github, mocker: MockerFixture)
github.release_get()
-def test_release_update(github: Github, github_release: Dict[str, Any], mocker: MockerFixture) -> None:
+def test_release_update(github: Github, github_release: dict[str, Any], mocker: MockerFixture) -> None:
"""
must update release
"""
diff --git a/tests/ahriman/core/upload/test_s3.py b/tests/ahriman/core/upload/test_s3.py
index 33815891..7442fd71 100644
--- a/tests/ahriman/core/upload/test_s3.py
+++ b/tests/ahriman/core/upload/test_s3.py
@@ -1,6 +1,6 @@
from pathlib import Path
from pytest_mock import MockerFixture
-from typing import Any, List, Optional, Tuple
+from typing import Any
from unittest.mock import MagicMock, call as MockCall
from ahriman.core.upload.s3 import S3
@@ -33,7 +33,7 @@ def test_calculate_etag_small(resource_path_root: Path) -> None:
assert S3.calculate_etag(path, _chunk_size) == "79b0f84e0232ed34fd191a85c383ecc5"
-def test_files_remove(s3_remote_objects: List[Any]) -> None:
+def test_files_remove(s3_remote_objects: list[Any]) -> None:
"""
must remove remote objects
"""
@@ -46,11 +46,11 @@ def test_files_remove(s3_remote_objects: List[Any]) -> None:
remote_objects[Path("x86_64/a")].delete.assert_called_once_with()
-def test_files_upload(s3: S3, s3_remote_objects: List[Any], mocker: MockerFixture) -> None:
+def test_files_upload(s3: S3, s3_remote_objects: list[Any], mocker: MockerFixture) -> None:
"""
must upload changed files
"""
- def mimetype(path: Path) -> Tuple[Optional[str], None]:
+ def mimetype(path: Path) -> tuple[str | None, None]:
return ("text/html", None) if path.name == "b" else (None, None)
root = Path("path")
@@ -87,7 +87,7 @@ def test_get_local_files(s3: S3, resource_path_root: Path, mocker: MockerFixture
walk_mock.assert_called()
-def test_get_remote_objects(s3: S3, s3_remote_objects: List[Any]) -> None:
+def test_get_remote_objects(s3: S3, s3_remote_objects: list[Any]) -> None:
"""
must generate list of remote objects by calling boto3 function
"""
diff --git a/tests/ahriman/models/test_aur_package.py b/tests/ahriman/models/test_aur_package.py
index c9cb2753..3e402834 100644
--- a/tests/ahriman/models/test_aur_package.py
+++ b/tests/ahriman/models/test_aur_package.py
@@ -5,12 +5,12 @@ import pyalpm # typing: ignore
from dataclasses import asdict, fields
from pathlib import Path
from pytest_mock import MockerFixture
-from typing import Any, Dict
+from typing import Any
from ahriman.models.aur_package import AURPackage
-def _get_aur_data(resource_path_root: Path) -> Dict[str, Any]:
+def _get_aur_data(resource_path_root: Path) -> dict[str, Any]:
"""
load package description from resource file
@@ -18,13 +18,13 @@ def _get_aur_data(resource_path_root: Path) -> Dict[str, Any]:
resource_path_root(Path): path to resource root
Returns:
- Dict[str, Any]: json descriptor
+ dict[str, Any]: json descriptor
"""
response = (resource_path_root / "models" / "package_ahriman_aur").read_text()
return json.loads(response)["results"][0]
-def _get_official_data(resource_path_root: Path) -> Dict[str, Any]:
+def _get_official_data(resource_path_root: Path) -> dict[str, Any]:
"""
load package description from resource file
@@ -32,7 +32,7 @@ def _get_official_data(resource_path_root: Path) -> Dict[str, Any]:
resource_path_root(Path): path to resource root
Returns:
- Dict[str, Any]: json descriptor
+ dict[str, Any]: json descriptor
"""
response = (resource_path_root / "models" / "package_akonadi_aur").read_text()
return json.loads(response)["results"][0]
diff --git a/tests/ahriman/models/test_package_source.py b/tests/ahriman/models/test_package_source.py
index a75ebe16..22c55651 100644
--- a/tests/ahriman/models/test_package_source.py
+++ b/tests/ahriman/models/test_package_source.py
@@ -1,6 +1,6 @@
+from collections.abc import Callable
from pytest_mock import MockerFixture
from pathlib import Path
-from typing import Callable
from ahriman.models.package_description import PackageDescription
from ahriman.models.package_source import PackageSource
diff --git a/tests/ahriman/models/test_repository_paths.py b/tests/ahriman/models/test_repository_paths.py
index 69645938..a4d849f2 100644
--- a/tests/ahriman/models/test_repository_paths.py
+++ b/tests/ahriman/models/test_repository_paths.py
@@ -1,8 +1,8 @@
import pytest
+from collections.abc import Callable
from pathlib import Path
from pytest_mock import MockerFixture
-from typing import Callable, Tuple
from unittest.mock import MagicMock, call as MockCall
from ahriman.core.exceptions import PathError
@@ -10,7 +10,7 @@ from ahriman.models.package import Package
from ahriman.models.repository_paths import RepositoryPaths
-def _get_owner(root: Path, same: bool) -> Callable[[Path], Tuple[int, int]]:
+def _get_owner(root: Path, same: bool) -> Callable[[Path], tuple[int, int]]:
"""
mocker function for owner definition
@@ -19,7 +19,7 @@ def _get_owner(root: Path, same: bool) -> Callable[[Path], Tuple[int, int]]:
same(bool): if True then returns the same as root directory and different otherwise
Returns:
- Callable[[Path], Tuple[int, int]]: function which can define ownership
+ Callable[[Path], tuple[int, int]]: function which can define ownership
"""
root_owner = (42, 42)
non_root_owner = (42, 42) if same else (1, 1)
diff --git a/tests/ahriman/web/conftest.py b/tests/ahriman/web/conftest.py
index 6f0d260a..eeb4885b 100644
--- a/tests/ahriman/web/conftest.py
+++ b/tests/ahriman/web/conftest.py
@@ -3,9 +3,10 @@ import pytest
from asyncio import BaseEventLoop
from aiohttp.web import Application, Resource, UrlMappingMatchInfo
from aiohttp.test_utils import TestClient
+from collections.abc import Awaitable, Callable
from marshmallow import Schema
from pytest_mock import MockerFixture
-from typing import Any, Awaitable, Callable, Dict, Optional
+from typing import Any
from unittest.mock import MagicMock
import ahriman.core.auth.helpers
@@ -21,7 +22,7 @@ from ahriman.web.web import setup_service
@pytest.helpers.register
def request(application: Application, path: str, method: str, json: Any = None, data: Any = None,
- extra: Optional[Dict[str, Any]] = None, resource: Optional[Resource] = None) -> MagicMock:
+ extra: dict[str, Any] | None = None, resource: Resource | None = None) -> MagicMock:
"""
request generator helper
@@ -31,8 +32,8 @@ def request(application: Application, path: str, method: str, json: Any = None,
method(str): method for the request
json(Any, optional): json payload of the request (Default value = None)
data(Any, optional): form data payload of the request (Default value = None)
- extra(Optional[Dict[str, Any]], optional): extra info which will be injected for ``get_extra_info`` command
- resource(Optional[Resource], optional): optional web resource for the request (Default value = None)
+ extra(dict[str, Any] | None, optional): extra info which will be injected for ``get_extra_info`` command
+ resource(Resource | None, optional): optional web resource for the request (Default value = None)
Returns:
MagicMock: dummy request mock
@@ -67,7 +68,7 @@ def schema_request(handler: Callable[..., Awaitable[Any]], *, location: str = "j
Returns:
Schema: request schema as set by the decorators
"""
- schemas: List[Dict[str, Any]] = handler.__schemas__ # type: ignore
+ schemas: list[dict[str, Any]] = handler.__schemas__ # type: ignore
return next(schema["schema"] for schema in schemas if schema["put_into"] == location)
@@ -83,7 +84,7 @@ def schema_response(handler: Callable[..., Awaitable[Any]], *, code: int = 200)
Returns:
Schema: response schema as set by the decorators
"""
- schemas: Dict[int, Any] = handler.__apispec__["responses"] # type: ignore
+ schemas: dict[int, Any] = handler.__apispec__["responses"] # type: ignore
schema = schemas[code]["schema"]
if callable(schema):
schema = schema()