diff --git a/.github/workflows/setup.sh b/.github/workflows/setup.sh
index 37c93dc1..5f5aebaa 100755
--- a/.github/workflows/setup.sh
+++ b/.github/workflows/setup.sh
@@ -10,7 +10,7 @@ echo -e '[arcanisrepo]\nServer = http://repo.arcanis.me/$arch\nSigLevel = Never'
# refresh the image
pacman --noconfirm -Syu
# main dependencies
-pacman --noconfirm -Sy base-devel devtools git pyalpm python-cerberus python-inflection python-passlib python-requests python-setuptools python-srcinfo sudo
+pacman --noconfirm -Sy base-devel devtools git pyalpm python-cerberus python-inflection python-passlib python-requests python-srcinfo sudo
# make dependencies
pacman --noconfirm -Sy python-build python-installer python-wheel
# optional dependencies
diff --git a/.github/workflows/tests.sh b/.github/workflows/tests.sh
index 736a189b..50c6f7cd 100755
--- a/.github/workflows/tests.sh
+++ b/.github/workflows/tests.sh
@@ -4,7 +4,7 @@
set -ex
# install dependencies
-pacman --noconfirm -Syu base-devel python-pip python-setuptools python-tox
+pacman --noconfirm -Syu base-devel python-setuptools python-tox
# run test and check targets
make check tests
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 9cc9ce94..ca945987 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -90,8 +90,9 @@ Again, the most checks can be performed by `make check` command, though some add
self.instance_attribute = ""
```
-* Type annotations are the must, even for local functions.
+* Type annotations are the must, even for local functions. For the function argument `self` (for instance methods) and `cls` (for class methods) should not be annotated.
* 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]`).
+* `classmethod` should always return `Self`. In case of mypy warning (e.g. if there is a branch in which function doesn't return the instance of `cls`) consider using `staticmethod` instead.
* Recommended order of function definitions in class:
```python
@@ -103,7 +104,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) -> Self: ...
@staticmethod
def static_method() -> Any: ...
diff --git a/Dockerfile b/Dockerfile
index 7737bb8e..96b5ae8d 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -28,7 +28,7 @@ RUN useradd -m -d "/home/build" -s "/usr/bin/nologin" build && \
COPY "docker/install-aur-package.sh" "/usr/local/bin/install-aur-package"
## install package dependencies
## darcs is not installed by reasons, because it requires a lot haskell packages which dramatically increase image size
-RUN pacman --noconfirm -Sy devtools git pyalpm python-cerberus python-inflection python-passlib python-requests python-setuptools python-srcinfo && \
+RUN pacman --noconfirm -Sy devtools git pyalpm python-cerberus python-inflection python-passlib python-requests python-srcinfo && \
pacman --noconfirm -Sy python-build python-installer python-wheel && \
pacman --noconfirm -Sy breezy mercurial python-aiohttp python-aiohttp-cors python-boto3 python-cryptography python-jinja python-requests-unixsocket rsync subversion && \
runuser -u build -- install-aur-package python-aioauth-client python-aiohttp-apispec-git python-aiohttp-jinja2 \
diff --git a/package/archlinux/PKGBUILD b/package/archlinux/PKGBUILD
index f14122d4..44c33b11 100644
--- a/package/archlinux/PKGBUILD
+++ b/package/archlinux/PKGBUILD
@@ -7,7 +7,7 @@ pkgdesc="ArcH linux ReposItory MANager"
arch=('any')
url="https://github.com/arcan1s/ahriman"
license=('GPL3')
-depends=('devtools' 'git' 'pyalpm' 'python-cerberus' 'python-inflection' 'python-passlib' 'python-requests' 'python-setuptools' 'python-srcinfo')
+depends=('devtools' 'git' 'pyalpm' 'python-cerberus' 'python-inflection' 'python-passlib' 'python-requests' 'python-srcinfo')
makedepends=('python-build' 'python-installer' 'python-wheel')
optdepends=('breezy: -bzr packages support'
'darcs: -darcs packages support'
diff --git a/setup.py b/setup.py
index 9eee78fc..56226e62 100644
--- a/setup.py
+++ b/setup.py
@@ -34,7 +34,6 @@ setup(
"inflection",
"passlib",
"requests",
- "setuptools",
"srcinfo",
],
setup_requires=[
diff --git a/src/ahriman/__init__.py b/src/ahriman/__init__.py
index 8fc622e9..1c75c71f 100644
--- a/src/ahriman/__init__.py
+++ b/src/ahriman/__init__.py
@@ -17,3 +17,12 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
+# workaround for python3.10 while it wasn't yet released in arch
+# also remove mypy --python-version flag later
+import typing
+import typing_extensions
+
+
+for extension in dir(typing_extensions):
+ if extension not in dir(typing):
+ setattr(typing, extension, getattr(typing_extensions, extension))
diff --git a/src/ahriman/application/application/application_properties.py b/src/ahriman/application/application/application_properties.py
index eb7dead4..66aac048 100644
--- a/src/ahriman/application/application/application_properties.py
+++ b/src/ahriman/application/application/application_properties.py
@@ -21,6 +21,7 @@ from ahriman.core.configuration import Configuration
from ahriman.core.database import SQLite
from ahriman.core.log import LazyLogging
from ahriman.core.repository import Repository
+from ahriman.models.pacman_synchronization import PacmanSynchronization
class ApplicationProperties(LazyLogging):
@@ -34,8 +35,8 @@ class ApplicationProperties(LazyLogging):
repository(Repository): repository instance
"""
- def __init__(self, architecture: str, configuration: Configuration, *,
- report: bool, unsafe: bool, refresh_pacman_database: int = 0) -> None:
+ def __init__(self, architecture: str, configuration: Configuration, *, report: bool, unsafe: bool,
+ refresh_pacman_database: PacmanSynchronization = PacmanSynchronization.Disabled) -> None:
"""
default constructor
@@ -44,8 +45,8 @@ class ApplicationProperties(LazyLogging):
configuration(Configuration): configuration instance
report(bool): force enable or disable reporting
unsafe(bool): if set no user check will be performed before path creation
- refresh_pacman_database(int, optional): pacman database syncronization level, ``0`` is disabled
- (Default value = 0)
+ refresh_pacman_database(PacmanSynchronization, optional): pacman database synchronization level
+ (Default value = PacmanSynchronization.Disabled)
"""
self.configuration = configuration
self.architecture = architecture
diff --git a/src/ahriman/application/handlers/add.py b/src/ahriman/application/handlers/add.py
index 00536b5b..414c4299 100644
--- a/src/ahriman/application/handlers/add.py
+++ b/src/ahriman/application/handlers/add.py
@@ -30,7 +30,7 @@ class Add(Handler):
"""
@classmethod
- def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
+ def run(cls, 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 5561fdbc..c2bc5da7 100644
--- a/src/ahriman/application/handlers/backup.py
+++ b/src/ahriman/application/handlers/backup.py
@@ -36,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, args: argparse.Namespace, architecture: str, configuration: Configuration, *,
report: bool, unsafe: bool) -> None:
"""
callback for command line
diff --git a/src/ahriman/application/handlers/clean.py b/src/ahriman/application/handlers/clean.py
index 47919251..5b3e54c2 100644
--- a/src/ahriman/application/handlers/clean.py
+++ b/src/ahriman/application/handlers/clean.py
@@ -30,7 +30,7 @@ class Clean(Handler):
"""
@classmethod
- def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
+ def run(cls, 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 33ae3a74..3ef65fd0 100644
--- a/src/ahriman/application/handlers/daemon.py
+++ b/src/ahriman/application/handlers/daemon.py
@@ -30,7 +30,7 @@ class Daemon(Handler):
"""
@classmethod
- def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
+ def run(cls, 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 121363ea..2a1d23a3 100644
--- a/src/ahriman/application/handlers/dump.py
+++ b/src/ahriman/application/handlers/dump.py
@@ -32,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, 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 db6d5600..186ca259 100644
--- a/src/ahriman/application/handlers/handler.py
+++ b/src/ahriman/application/handlers/handler.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 __future__ import annotations
-
import argparse
import logging
@@ -52,7 +50,7 @@ class Handler:
ALLOW_MULTI_ARCHITECTURE_RUN = True
@classmethod
- def architectures_extract(cls: type[Handler], args: argparse.Namespace) -> list[str]:
+ def architectures_extract(cls, args: argparse.Namespace) -> list[str]:
"""
get known architectures
@@ -83,7 +81,7 @@ class Handler:
return sorted(architectures)
@classmethod
- def call(cls: type[Handler], args: argparse.Namespace, architecture: str) -> bool:
+ def call(cls, args: argparse.Namespace, architecture: str) -> bool:
"""
additional function to wrap all calls for multiprocessing library
@@ -108,7 +106,7 @@ class Handler:
return False
@classmethod
- def execute(cls: type[Handler], args: argparse.Namespace) -> int:
+ def execute(cls, args: argparse.Namespace) -> int:
"""
execute function for all aru
@@ -137,7 +135,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, 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 dafd351f..f8417bde 100644
--- a/src/ahriman/application/handlers/help.py
+++ b/src/ahriman/application/handlers/help.py
@@ -31,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, 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 d6447f1b..4293a890 100644
--- a/src/ahriman/application/handlers/key_import.py
+++ b/src/ahriman/application/handlers/key_import.py
@@ -32,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, 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 d2b2cc34..385018a6 100644
--- a/src/ahriman/application/handlers/patch.py
+++ b/src/ahriman/application/handlers/patch.py
@@ -38,7 +38,7 @@ class Patch(Handler):
"""
@classmethod
- def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
+ def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *,
report: bool, unsafe: bool) -> None:
"""
callback for command line
diff --git a/src/ahriman/application/handlers/rebuild.py b/src/ahriman/application/handlers/rebuild.py
index 15cb2745..2aea52a5 100644
--- a/src/ahriman/application/handlers/rebuild.py
+++ b/src/ahriman/application/handlers/rebuild.py
@@ -32,7 +32,7 @@ class Rebuild(Handler):
"""
@classmethod
- def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
+ def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *,
report: bool, unsafe: bool) -> None:
"""
callback for command line
diff --git a/src/ahriman/application/handlers/remove.py b/src/ahriman/application/handlers/remove.py
index 7a84272a..2c3eba06 100644
--- a/src/ahriman/application/handlers/remove.py
+++ b/src/ahriman/application/handlers/remove.py
@@ -30,7 +30,7 @@ class Remove(Handler):
"""
@classmethod
- def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
+ def run(cls, 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 895ae1fc..33d367c3 100644
--- a/src/ahriman/application/handlers/remove_unknown.py
+++ b/src/ahriman/application/handlers/remove_unknown.py
@@ -31,7 +31,7 @@ class RemoveUnknown(Handler):
"""
@classmethod
- def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
+ def run(cls, 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 0e425205..abd68165 100644
--- a/src/ahriman/application/handlers/restore.py
+++ b/src/ahriman/application/handlers/restore.py
@@ -33,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, 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 625c64d8..2e2f25d1 100644
--- a/src/ahriman/application/handlers/search.py
+++ b/src/ahriman/application/handlers/search.py
@@ -40,10 +40,14 @@ class Search(Handler):
"""
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
+ SORT_FIELDS = {
+ field.name
+ for field in fields(AURPackage)
+ if field.default_factory is not list # type: ignore[comparison-overlap]
+ }
@classmethod
- def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
+ def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *,
report: bool, unsafe: bool) -> None:
"""
callback for command line
diff --git a/src/ahriman/application/handlers/service_updates.py b/src/ahriman/application/handlers/service_updates.py
index 0e25f13c..feb2a400 100644
--- a/src/ahriman/application/handlers/service_updates.py
+++ b/src/ahriman/application/handlers/service_updates.py
@@ -35,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, 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 7a29d9d8..d3ffe97d 100644
--- a/src/ahriman/application/handlers/setup.py
+++ b/src/ahriman/application/handlers/setup.py
@@ -45,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, args: argparse.Namespace, architecture: str, configuration: Configuration, *,
report: bool, unsafe: bool) -> None:
"""
callback for command line
@@ -153,7 +153,7 @@ class Setup(Handler):
configuration = Configuration(allow_no_value=True)
# preserve case
# stupid mypy thinks that it is impossible
- configuration.optionxform = lambda key: key # type: ignore
+ configuration.optionxform = lambda key: key # type: ignore[method-assign]
# load default configuration first
# we cannot use Include here because it will be copied to new chroot, thus no includes there
diff --git a/src/ahriman/application/handlers/shell.py b/src/ahriman/application/handlers/shell.py
index 99afd391..797b3e97 100644
--- a/src/ahriman/application/handlers/shell.py
+++ b/src/ahriman/application/handlers/shell.py
@@ -37,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, 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 c2fd0e3f..d6076542 100644
--- a/src/ahriman/application/handlers/sign.py
+++ b/src/ahriman/application/handlers/sign.py
@@ -30,7 +30,7 @@ class Sign(Handler):
"""
@classmethod
- def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
+ def run(cls, 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 1ae4c0d8..11e5132f 100644
--- a/src/ahriman/application/handlers/status.py
+++ b/src/ahriman/application/handlers/status.py
@@ -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, args: argparse.Namespace, architecture: str, configuration: Configuration, *,
report: bool, unsafe: bool) -> None:
"""
callback for command line
diff --git a/src/ahriman/application/handlers/status_update.py b/src/ahriman/application/handlers/status_update.py
index 60832513..ac496ac1 100644
--- a/src/ahriman/application/handlers/status_update.py
+++ b/src/ahriman/application/handlers/status_update.py
@@ -33,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, 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 56493fba..9c378485 100644
--- a/src/ahriman/application/handlers/structure.py
+++ b/src/ahriman/application/handlers/structure.py
@@ -34,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, 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 2c990499..3f5d406d 100644
--- a/src/ahriman/application/handlers/triggers.py
+++ b/src/ahriman/application/handlers/triggers.py
@@ -31,7 +31,7 @@ class Triggers(Handler):
"""
@classmethod
- def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
+ def run(cls, 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 d40f9107..ed0002af 100644
--- a/src/ahriman/application/handlers/unsafe_commands.py
+++ b/src/ahriman/application/handlers/unsafe_commands.py
@@ -33,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, args: argparse.Namespace, architecture: str, configuration: Configuration, *,
report: bool, unsafe: bool) -> None:
"""
callback for command line
diff --git a/src/ahriman/application/handlers/update.py b/src/ahriman/application/handlers/update.py
index 8f62ee32..a90d87d3 100644
--- a/src/ahriman/application/handlers/update.py
+++ b/src/ahriman/application/handlers/update.py
@@ -32,7 +32,7 @@ class Update(Handler):
"""
@classmethod
- def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
+ def run(cls, 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 964cb9d4..2d570b6e 100644
--- a/src/ahriman/application/handlers/users.py
+++ b/src/ahriman/application/handlers/users.py
@@ -39,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, args: argparse.Namespace, architecture: str, configuration: Configuration, *,
report: bool, unsafe: bool) -> None:
"""
callback for command line
diff --git a/src/ahriman/application/handlers/validate.py b/src/ahriman/application/handlers/validate.py
index f27e9041..f67812ee 100644
--- a/src/ahriman/application/handlers/validate.py
+++ b/src/ahriman/application/handlers/validate.py
@@ -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, args: argparse.Namespace, architecture: str, configuration: Configuration, *,
report: bool, unsafe: bool) -> None:
"""
callback for command line
diff --git a/src/ahriman/application/handlers/versions.py b/src/ahriman/application/handlers/versions.py
index 86a31f55..8b98e013 100644
--- a/src/ahriman/application/handlers/versions.py
+++ b/src/ahriman/application/handlers/versions.py
@@ -18,9 +18,12 @@
# along with this program. If not, see .
#
import argparse
-import pkg_resources
+import re
import sys
+from collections.abc import Generator
+from importlib import metadata
+
from ahriman import version
from ahriman.application.handlers import Handler
from ahriman.core.configuration import Configuration
@@ -30,12 +33,16 @@ from ahriman.core.formatters import VersionPrinter
class Versions(Handler):
"""
version handler
+
+ Attributes:
+ PEP423_PACKAGE_NAME(str): (class attribute) special regex for valid PEP423 package name
"""
ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture"
+ PEP423_PACKAGE_NAME = re.compile(r"^[A-Za-z0-9._-]+")
@classmethod
- def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
+ def run(cls, args: argparse.Namespace, architecture: str, configuration: Configuration, *,
report: bool, unsafe: bool) -> None:
"""
callback for command line
@@ -49,37 +56,43 @@ class Versions(Handler):
"""
VersionPrinter(f"Module version {version.__version__}",
{"Python": sys.version}).print(verbose=False, separator=" ")
- packages = Versions.package_dependencies("ahriman", ("pacman", "s3", "web"))
- VersionPrinter("Installed packages", packages).print(verbose=False, separator=" ")
+ packages = Versions.package_dependencies("ahriman")
+ VersionPrinter("Installed packages", dict(packages)).print(verbose=False, separator=" ")
@staticmethod
- def package_dependencies(root: str, root_extras: tuple[str, ...] = ()) -> dict[str, str]:
+ def package_dependencies(root: str) -> Generator[tuple[str, str], None, None]:
"""
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 = ())
Returns:
- dict[str, str]: map of installed dependency to its version
+ Generator[tuple[str, str], None, None]: map of installed dependency to its version
"""
- 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]:
- return [entry.key for entry in resources[key].requires(extras)]
+ def dependencies_by_key(key: str) -> Generator[str, None, None]:
+ # in importlib it returns requires in the following format
+ # ["pytest (>=3.0.0) ; extra == 'test'", "pytest-cov ; extra == 'test'"]
+ try:
+ requires = metadata.requires(key)
+ except metadata.PackageNotFoundError:
+ return
+ for entry in requires or []:
+ yield from Versions.PEP423_PACKAGE_NAME.findall(entry)
keys: list[str] = []
- portion = {key for key in dependencies_by_key(root, root_extras) if key in resources}
+ portion = set(dependencies_by_key(root))
while portion:
keys.extend(portion)
portion = {
key
- for key in sum((dependencies_by_key(key) for key in portion), start=[])
- if key not in keys and key in resources
+ for key in sum((list(dependencies_by_key(key)) for key in portion), start=[])
+ if key not in keys
}
- return {
- resource.project_name: resource.version
- for resource in map(lambda key: resources[key], keys)
- }
+ for key in keys:
+ try:
+ distribution = metadata.distribution(key)
+ yield distribution.name, distribution.version
+ except metadata.PackageNotFoundError:
+ continue
diff --git a/src/ahriman/application/handlers/web.py b/src/ahriman/application/handlers/web.py
index 6c2b08ba..b6ae9793 100644
--- a/src/ahriman/application/handlers/web.py
+++ b/src/ahriman/application/handlers/web.py
@@ -33,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, 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 da552f75..b10cc495 100644
--- a/src/ahriman/application/lock.py
+++ b/src/ahriman/application/lock.py
@@ -17,12 +17,10 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-from __future__ import annotations
-
import argparse
from types import TracebackType
-from typing import Literal
+from typing import Literal, Self
from ahriman import version
from ahriman.core.configuration import Configuration
@@ -111,7 +109,7 @@ class Lock(LazyLogging):
except FileExistsError:
raise DuplicateRunError()
- def __enter__(self) -> Lock:
+ def __enter__(self) -> Self:
"""
default workflow is the following:
@@ -120,6 +118,9 @@ class Lock(LazyLogging):
3. Check web status watcher status
4. Create lock file
5. Report to status page if enabled
+
+ Returns:
+ Self: always instance of self
"""
self.check_user()
self.check_version()
diff --git a/src/ahriman/core/alpm/pacman.py b/src/ahriman/core/alpm/pacman.py
index ee586fba..03657b54 100644
--- a/src/ahriman/core/alpm/pacman.py
+++ b/src/ahriman/core/alpm/pacman.py
@@ -21,12 +21,13 @@ 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 pyalpm import DB, Handle, Package, SIG_PACKAGE, error as PyalpmError # type: ignore[import]
from typing import Any
from ahriman.core.configuration import Configuration
from ahriman.core.log import LazyLogging
from ahriman.core.util import trim_package
+from ahriman.models.pacman_synchronization import PacmanSynchronization
from ahriman.models.repository_paths import RepositoryPaths
@@ -40,28 +41,28 @@ class Pacman(LazyLogging):
handle: Handle
- def __init__(self, architecture: str, configuration: Configuration, *, refresh_database: int) -> None:
+ def __init__(self, architecture: str, configuration: Configuration, *,
+ refresh_database: PacmanSynchronization) -> None:
"""
default constructor
Args:
architecture(str): repository architecture
configuration(Configuration): configuration instance
- refresh_database(int): synchronize local cache to remote. If set to ``0``, no synchronization will be
- enabled, if set to ``1`` - normal synchronization, if set to ``2`` - force synchronization
+ refresh_database(PacmanSynchronization): synchronize local cache to remote
"""
self.__create_handle_fn: Callable[[], Handle] = lambda: self.__create_handle(
architecture, configuration, refresh_database=refresh_database)
- def __create_handle(self, architecture: str, configuration: Configuration, *, refresh_database: int) -> Handle:
+ def __create_handle(self, architecture: str, configuration: Configuration, *,
+ refresh_database: PacmanSynchronization) -> Handle:
"""
create lazy handle function
Args:
architecture(str): repository architecture
configuration(Configuration): configuration instance
- refresh_database(int): synchronize local cache to remote. If set to ``0``, no synchronization will be
- enabled, if set to ``1`` - normal synchronization, if set to ``2`` - force synchronization
+ refresh_database(PacmanSynchronization): synchronize local cache to remote
Returns:
Handle: fully initialized pacman handle
@@ -79,7 +80,7 @@ class Pacman(LazyLogging):
self.database_copy(handle, database, pacman_root, paths, use_ahriman_cache=use_ahriman_cache)
if use_ahriman_cache and refresh_database:
- self.database_sync(handle, force=refresh_database > 1)
+ self.database_sync(handle, force=refresh_database == PacmanSynchronization.Force)
return handle
diff --git a/src/ahriman/core/alpm/remote/aur.py b/src/ahriman/core/alpm/remote/aur.py
index 4007f278..14cb1150 100644
--- a/src/ahriman/core/alpm/remote/aur.py
+++ b/src/ahriman/core/alpm/remote/aur.py
@@ -44,6 +44,33 @@ class AUR(Remote):
DEFAULT_RPC_VERSION = "5"
DEFAULT_TIMEOUT = 30
+ @classmethod
+ def remote_git_url(cls, package_base: str, repository: str) -> str:
+ """
+ generate remote git url from the package base
+
+ Args
+ package_base(str): package base
+ repository(str): repository name
+
+ Returns:
+ str: git url for the specific base
+ """
+ return f"{AUR.DEFAULT_AUR_URL}/{package_base}.git"
+
+ @classmethod
+ def remote_web_url(cls, package_base: str) -> str:
+ """
+ generate remote web url from the package base
+
+ Args
+ package_base(str): package base
+
+ Returns:
+ str: web url for the specific base
+ """
+ return f"{AUR.DEFAULT_AUR_URL}/packages/{package_base}"
+
@staticmethod
def parse_response(response: dict[str, Any]) -> list[AURPackage]:
"""
@@ -64,33 +91,6 @@ class AUR(Remote):
raise PackageInfoError(error_details)
return [AURPackage.from_json(package) for package in response["results"]]
- @classmethod
- def remote_git_url(cls: type[Remote], package_base: str, repository: str) -> str:
- """
- generate remote git url from the package base
-
- Args
- package_base(str): package base
- repository(str): repository name
-
- Returns:
- str: git url for the specific base
- """
- return f"{AUR.DEFAULT_AUR_URL}/{package_base}.git"
-
- @classmethod
- def remote_web_url(cls: type[Remote], package_base: str) -> str:
- """
- generate remote web url from the package base
-
- Args
- package_base(str): package base
-
- Returns:
- str: web url for the specific base
- """
- return f"{AUR.DEFAULT_AUR_URL}/packages/{package_base}"
-
def make_request(self, request_type: str, *args: str, **kwargs: str) -> list[AURPackage]:
"""
perform request to AUR RPC
diff --git a/src/ahriman/core/alpm/remote/official.py b/src/ahriman/core/alpm/remote/official.py
index e551f65f..5b7e48e4 100644
--- a/src/ahriman/core/alpm/remote/official.py
+++ b/src/ahriman/core/alpm/remote/official.py
@@ -44,6 +44,35 @@ class Official(Remote):
DEFAULT_RPC_URL = "https://archlinux.org/packages/search/json"
DEFAULT_TIMEOUT = 30
+ @classmethod
+ def remote_git_url(cls, package_base: str, repository: str) -> str:
+ """
+ generate remote git url from the package base
+
+ Args
+ package_base(str): package base
+ repository(str): repository name
+
+ Returns:
+ str: git url for the specific base
+ """
+ if repository.lower() in ("core", "extra", "testing", "kde-unstable"):
+ return "https://github.com/archlinux/svntogit-packages.git" # hardcoded, ok
+ return "https://github.com/archlinux/svntogit-community.git"
+
+ @classmethod
+ def remote_web_url(cls, package_base: str) -> str:
+ """
+ generate remote web url from the package base
+
+ Args
+ package_base(str): package base
+
+ Returns:
+ str: web url for the specific base
+ """
+ return f"{Official.DEFAULT_ARCHLINUX_URL}/packages/{package_base}"
+
@staticmethod
def parse_response(response: dict[str, Any]) -> list[AURPackage]:
"""
@@ -62,35 +91,6 @@ class Official(Remote):
raise PackageInfoError("API validation error")
return [AURPackage.from_repo(package) for package in response["results"]]
- @classmethod
- def remote_git_url(cls: type[Remote], package_base: str, repository: str) -> str:
- """
- generate remote git url from the package base
-
- Args
- package_base(str): package base
- repository(str): repository name
-
- Returns:
- str: git url for the specific base
- """
- if repository.lower() in ("core", "extra", "testing", "kde-unstable"):
- return "https://github.com/archlinux/svntogit-packages.git" # hardcoded, ok
- return "https://github.com/archlinux/svntogit-community.git"
-
- @classmethod
- def remote_web_url(cls: type[Remote], package_base: str) -> str:
- """
- generate remote web url from the package base
-
- Args
- package_base(str): package base
-
- Returns:
- str: web url for the specific base
- """
- return f"{Official.DEFAULT_ARCHLINUX_URL}/packages/{package_base}"
-
def make_request(self, *args: str, by: str) -> list[AURPackage]:
"""
perform request to official repositories RPC
diff --git a/src/ahriman/core/alpm/remote/remote.py b/src/ahriman/core/alpm/remote/remote.py
index 32733ac1..81660877 100644
--- a/src/ahriman/core/alpm/remote/remote.py
+++ b/src/ahriman/core/alpm/remote/remote.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 __future__ import annotations
-
from ahriman.core.alpm.pacman import Pacman
from ahriman.core.log import LazyLogging
from ahriman.models.aur_package import AURPackage
@@ -42,7 +40,7 @@ class Remote(LazyLogging):
"""
@classmethod
- def info(cls: type[Remote], package_name: str, *, pacman: Pacman) -> AURPackage:
+ def info(cls, package_name: str, *, pacman: Pacman) -> AURPackage:
"""
get package info by its name
@@ -56,7 +54,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, *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
@@ -80,7 +78,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, package_base: str, repository: str) -> str:
"""
generate remote git url from the package base
@@ -97,7 +95,7 @@ class Remote(LazyLogging):
raise NotImplementedError
@classmethod
- def remote_web_url(cls: type[Remote], package_base: str) -> str:
+ def remote_web_url(cls, package_base: str) -> str:
"""
generate remote web url from the package base
@@ -113,7 +111,7 @@ class Remote(LazyLogging):
raise NotImplementedError
@classmethod
- def search(cls: type[Remote], *keywords: str, pacman: Pacman) -> list[AURPackage]:
+ def search(cls, *keywords: str, pacman: Pacman) -> list[AURPackage]:
"""
search package in AUR web
diff --git a/src/ahriman/core/auth/auth.py b/src/ahriman/core/auth/auth.py
index 9f9ac6af..e9316ce0 100644
--- a/src/ahriman/core/auth/auth.py
+++ b/src/ahriman/core/auth/auth.py
@@ -62,8 +62,8 @@ class Auth(LazyLogging):
"""
return """"""
- @classmethod
- def load(cls: type[Auth], configuration: Configuration, database: SQLite) -> Auth:
+ @staticmethod
+ def load(configuration: Configuration, database: SQLite) -> Auth:
"""
load authorization module from settings
@@ -81,7 +81,7 @@ class Auth(LazyLogging):
if provider == AuthSettings.OAuth:
from ahriman.core.auth.oauth import OAuth
return OAuth(configuration, database)
- return cls(configuration)
+ return Auth(configuration)
async def check_credentials(self, username: str | None, password: str | None) -> bool:
"""
diff --git a/src/ahriman/core/auth/helpers.py b/src/ahriman/core/auth/helpers.py
index 8232ef2e..14c38b2b 100644
--- a/src/ahriman/core/auth/helpers.py
+++ b/src/ahriman/core/auth/helpers.py
@@ -20,7 +20,7 @@
from typing import Any
try:
- import aiohttp_security # type: ignore
+ import aiohttp_security # type: ignore[import]
_has_aiohttp_security = True
except ImportError:
_has_aiohttp_security = False
diff --git a/src/ahriman/core/auth/oauth.py b/src/ahriman/core/auth/oauth.py
index e9456f16..f1c1fbeb 100644
--- a/src/ahriman/core/auth/oauth.py
+++ b/src/ahriman/core/auth/oauth.py
@@ -128,7 +128,7 @@ class OAuth(Mapping):
client.access_token = access_token
user, _ = await client.user_info()
- username: str = user.email # type: ignore
+ username: str = user.email # type: ignore[attr-defined]
return username
except Exception:
self.logger.exception("got exception while performing request")
diff --git a/src/ahriman/core/configuration/configuration.py b/src/ahriman/core/configuration/configuration.py
index 2ee49642..4547a205 100644
--- a/src/ahriman/core/configuration/configuration.py
+++ b/src/ahriman/core/configuration/configuration.py
@@ -17,15 +17,13 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-from __future__ import annotations
-
import configparser
import shlex
import sys
from collections.abc import Callable
from pathlib import Path
-from typing import Any
+from typing import Any, Self
from ahriman.core.exceptions import InitializeError
from ahriman.models.repository_paths import RepositoryPaths
@@ -113,7 +111,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, path: Path, architecture: str) -> Self:
"""
constructor with full object initialization
@@ -122,7 +120,7 @@ class Configuration(configparser.RawConfigParser):
architecture(str): repository architecture
Returns:
- Configuration: configuration instance
+ Self: configuration instance
"""
configuration = cls()
configuration.load(path)
@@ -186,9 +184,9 @@ 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[empty-body]
- def getpath(self, *args: Any, **kwargs: Any) -> Path: ... # type: ignore
+ def getpath(self, *args: Any, **kwargs: Any) -> Path: ... # type: ignore[empty-body]
def gettype(self, section: str, architecture: str, *, fallback: str | None = None) -> tuple[str, str]:
"""
diff --git a/src/ahriman/core/configuration/validator.py b/src/ahriman/core/configuration/validator.py
index 26011391..c7e98915 100644
--- a/src/ahriman/core/configuration/validator.py
+++ b/src/ahriman/core/configuration/validator.py
@@ -19,7 +19,7 @@
#
import ipaddress
-from cerberus import TypeDefinition, Validator as RootValidator # type: ignore
+from cerberus import TypeDefinition, Validator as RootValidator # type: ignore[import]
from pathlib import Path
from typing import Any
from urllib.parse import urlparse
@@ -74,7 +74,7 @@ class Validator(RootValidator):
bool: value converted to boolean according to configuration rules
"""
# pylint: disable=protected-access
- converted: bool = self.configuration._convert_to_boolean(value) # type: ignore
+ converted: bool = self.configuration._convert_to_boolean(value) # type: ignore[attr-defined]
return converted
def _normalize_coerce_integer(self, value: str) -> int:
diff --git a/src/ahriman/core/database/migrations/m005_make_opt_depends.py b/src/ahriman/core/database/migrations/m005_make_opt_depends.py
index add68775..e337d4b5 100644
--- a/src/ahriman/core/database/migrations/m005_make_opt_depends.py
+++ b/src/ahriman/core/database/migrations/m005_make_opt_depends.py
@@ -23,6 +23,7 @@ from ahriman.core.alpm.pacman import Pacman
from ahriman.core.configuration import Configuration
from ahriman.core.util import package_like
from ahriman.models.package import Package
+from ahriman.models.pacman_synchronization import PacmanSynchronization
__all__ = ["migrate_data", "steps"]
@@ -61,7 +62,7 @@ def migrate_package_depends(connection: Connection, configuration: Configuration
return
_, architecture = configuration.check_loaded()
- pacman = Pacman(architecture, configuration, refresh_database=False)
+ pacman = Pacman(architecture, configuration, refresh_database=PacmanSynchronization.Disabled)
package_list = []
for full_path in filter(package_like, configuration.repository_paths.repository.iterdir()):
diff --git a/src/ahriman/core/database/sqlite.py b/src/ahriman/core/database/sqlite.py
index eb68b761..1bbc8bae 100644
--- a/src/ahriman/core/database/sqlite.py
+++ b/src/ahriman/core/database/sqlite.py
@@ -17,12 +17,11 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-from __future__ import annotations
-
import json
import sqlite3
from pathlib import Path
+from typing import Self
from ahriman.core.configuration import Configuration
from ahriman.core.database.migrations import Migrations
@@ -46,7 +45,7 @@ class SQLite(AuthOperations, BuildOperations, LogsOperations, PackageOperations,
"""
@classmethod
- def load(cls: type[SQLite], configuration: Configuration) -> SQLite:
+ def load(cls, configuration: Configuration) -> Self:
"""
construct instance from configuration
@@ -54,7 +53,7 @@ class SQLite(AuthOperations, BuildOperations, LogsOperations, PackageOperations,
configuration(Configuration): configuration instance
Returns:
- SQLite: fully initialized instance of the database
+ Self: fully initialized instance of the database
"""
path = cls.database_path(configuration)
database = cls(path)
diff --git a/src/ahriman/core/gitremote/remote_pull_trigger.py b/src/ahriman/core/gitremote/remote_pull_trigger.py
index 20092c60..e9c400a5 100644
--- a/src/ahriman/core/gitremote/remote_pull_trigger.py
+++ b/src/ahriman/core/gitremote/remote_pull_trigger.py
@@ -68,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, configuration: Configuration) -> list[str]:
"""
extract configuration sections from configuration
diff --git a/src/ahriman/core/gitremote/remote_push_trigger.py b/src/ahriman/core/gitremote/remote_push_trigger.py
index 8a1a10a9..d5f9a2a1 100644
--- a/src/ahriman/core/gitremote/remote_push_trigger.py
+++ b/src/ahriman/core/gitremote/remote_push_trigger.py
@@ -76,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, configuration: Configuration) -> list[str]:
"""
extract configuration sections from configuration
diff --git a/src/ahriman/core/log/http_log_handler.py b/src/ahriman/core/log/http_log_handler.py
index 3347f990..bff807a5 100644
--- a/src/ahriman/core/log/http_log_handler.py
+++ b/src/ahriman/core/log/http_log_handler.py
@@ -17,10 +17,10 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-from __future__ import annotations
-
import logging
+from typing import Self
+
from ahriman.core.configuration import Configuration
@@ -52,7 +52,7 @@ class HttpLogHandler(logging.Handler):
self.suppress_errors = suppress_errors
@classmethod
- def load(cls, configuration: Configuration, *, report: bool) -> HttpLogHandler:
+ def load(cls, configuration: Configuration, *, report: bool) -> Self:
"""
install logger. This function creates handler instance and adds it to the handler list in case if no other
http handler found
@@ -60,6 +60,9 @@ class HttpLogHandler(logging.Handler):
Args:
configuration(Configuration): configuration instance
report(bool): force enable or disable reporting
+
+ Returns:
+ Self: logger instance with loaded settings
"""
root = logging.getLogger()
if (handler := next((handler for handler in root.handlers if isinstance(handler, cls)), None)) is not None:
diff --git a/src/ahriman/core/report/report.py b/src/ahriman/core/report/report.py
index c2937a3b..f512a5d7 100644
--- a/src/ahriman/core/report/report.py
+++ b/src/ahriman/core/report/report.py
@@ -66,8 +66,8 @@ class Report(LazyLogging):
self.architecture = architecture
self.configuration = configuration
- @classmethod
- def load(cls: type[Report], architecture: str, configuration: Configuration, target: str) -> Report:
+ @staticmethod
+ def load(architecture: str, configuration: Configuration, target: str) -> Report:
"""
load client from settings
@@ -93,7 +93,7 @@ class Report(LazyLogging):
if provider == ReportSettings.Telegram:
from ahriman.core.report.telegram import Telegram
return Telegram(architecture, configuration, section)
- return cls(architecture, configuration) # should never happen
+ return Report(architecture, configuration) # should never happen
def generate(self, packages: list[Package], result: Result) -> None:
"""
diff --git a/src/ahriman/core/report/report_trigger.py b/src/ahriman/core/report/report_trigger.py
index 1994f66d..9a4691af 100644
--- a/src/ahriman/core/report/report_trigger.py
+++ b/src/ahriman/core/report/report_trigger.py
@@ -205,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, configuration: Configuration) -> list[str]:
"""
extract configuration sections from configuration
diff --git a/src/ahriman/core/repository/repository.py b/src/ahriman/core/repository/repository.py
index 8fe21736..a6fa210c 100644
--- a/src/ahriman/core/repository/repository.py
+++ b/src/ahriman/core/repository/repository.py
@@ -17,10 +17,9 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-from __future__ import annotations
-
from collections.abc import Iterable
from pathlib import Path
+from typing import Self
from ahriman.core import _Context, context
from ahriman.core.alpm.pacman import Pacman
@@ -32,6 +31,7 @@ from ahriman.core.sign.gpg import GPG
from ahriman.core.util import package_like
from ahriman.models.context_key import ContextKey
from ahriman.models.package import Package
+from ahriman.models.pacman_synchronization import PacmanSynchronization
class Repository(Executor, UpdateHandler):
@@ -58,8 +58,8 @@ class Repository(Executor, UpdateHandler):
"""
@classmethod
- def load(cls: type[Repository], architecture: str, configuration: Configuration, database: SQLite, *,
- report: bool, unsafe: bool, refresh_pacman_database: int = 0) -> Repository:
+ def load(cls, architecture: str, configuration: Configuration, database: SQLite, *, report: bool, unsafe: bool,
+ refresh_pacman_database: PacmanSynchronization = PacmanSynchronization.Disabled) -> Self:
"""
load instance from argument list
@@ -69,8 +69,11 @@ class Repository(Executor, UpdateHandler):
database(SQLite): database instance
report(bool): force enable or disable reporting
unsafe(bool): if set no user check will be performed before path creation
- refresh_pacman_database(int, optional): pacman database syncronization level, ``0`` is disabled
- (Default value = 0)
+ refresh_pacman_database(PacmanSynchronization, optional): pacman database synchronization level
+ (Default value = PacmanSynchronization.Disabled)
+
+ Returns:
+ Self: fully loaded repository class instance
"""
instance = cls(architecture, configuration, database,
report=report, unsafe=unsafe, refresh_pacman_database=refresh_pacman_database)
diff --git a/src/ahriman/core/repository/repository_properties.py b/src/ahriman/core/repository/repository_properties.py
index cc2da460..0c961d65 100644
--- a/src/ahriman/core/repository/repository_properties.py
+++ b/src/ahriman/core/repository/repository_properties.py
@@ -27,6 +27,7 @@ from ahriman.core.sign.gpg import GPG
from ahriman.core.status.client import Client
from ahriman.core.triggers import TriggerLoader
from ahriman.core.util import check_user
+from ahriman.models.pacman_synchronization import PacmanSynchronization
from ahriman.models.repository_paths import RepositoryPaths
@@ -49,8 +50,8 @@ class RepositoryProperties(LazyLogging):
vcs_allowed_age(int): maximal age of the VCS packages before they will be checked
"""
- def __init__(self, architecture: str, configuration: Configuration, database: SQLite, *,
- report: bool, unsafe: bool, refresh_pacman_database: int) -> None:
+ def __init__(self, architecture: str, configuration: Configuration, database: SQLite, *, report: bool, unsafe: bool,
+ refresh_pacman_database: PacmanSynchronization) -> None:
"""
default constructor
@@ -60,7 +61,7 @@ class RepositoryProperties(LazyLogging):
database(SQLite): database instance
report(bool): force enable or disable reporting
unsafe(bool): if set no user check will be performed before path creation
- refresh_pacman_database(int, optional): pacman database syncronization level, ``0`` is disabled
+ refresh_pacman_database(PacmanSynchronization): pacman database synchronization level
"""
self.architecture = architecture
self.configuration = configuration
diff --git a/src/ahriman/core/status/client.py b/src/ahriman/core/status/client.py
index 4000c870..d3efafca 100644
--- a/src/ahriman/core/status/client.py
+++ b/src/ahriman/core/status/client.py
@@ -32,8 +32,8 @@ class Client:
base build status reporter client
"""
- @classmethod
- def load(cls: type[Client], configuration: Configuration, *, report: bool) -> Client:
+ @staticmethod
+ def load(configuration: Configuration, *, report: bool) -> Client:
"""
load client from settings
@@ -45,7 +45,7 @@ class Client:
Client: client according to current settings
"""
if not report:
- return cls()
+ return Client()
address = configuration.get("web", "address", fallback=None)
host = configuration.get("web", "host", fallback=None)
@@ -58,7 +58,7 @@ class Client:
if address or (host and port) or socket:
from ahriman.core.status.web_client import WebClient
return WebClient(configuration)
- return cls()
+ return Client()
def add(self, package: Package, status: BuildStatusEnum) -> None:
"""
diff --git a/src/ahriman/core/status/web_client.py b/src/ahriman/core/status/web_client.py
index a835fae1..3dc2f00f 100644
--- a/src/ahriman/core/status/web_client.py
+++ b/src/ahriman/core/status/web_client.py
@@ -131,7 +131,7 @@ class WebClient(Client, LazyLogging):
requests.Session: generated session object
"""
if use_unix_socket:
- import requests_unixsocket # type: ignore
+ import requests_unixsocket # type: ignore[import]
session: requests.Session = requests_unixsocket.Session()
return session
diff --git a/src/ahriman/core/triggers/trigger.py b/src/ahriman/core/triggers/trigger.py
index d931c068..6442097c 100644
--- a/src/ahriman/core/triggers/trigger.py
+++ b/src/ahriman/core/triggers/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 __future__ import annotations
-
from ahriman.core.configuration import Configuration
from ahriman.core.configuration.schema import ConfigurationSchema
from ahriman.core.log import LazyLogging
@@ -70,8 +68,7 @@ class Trigger(LazyLogging):
self.configuration = configuration
@classmethod
- def configuration_schema(cls: type[Trigger], architecture: str,
- configuration: Configuration | None) -> ConfigurationSchema:
+ def configuration_schema(cls, architecture: str, configuration: Configuration | None) -> ConfigurationSchema:
"""
configuration schema based on supplied service configuration
@@ -102,7 +99,7 @@ class Trigger(LazyLogging):
return result
@classmethod
- def configuration_sections(cls: type[Trigger], configuration: Configuration) -> list[str]:
+ def configuration_sections(cls, configuration: Configuration) -> list[str]:
"""
extract configuration sections from configuration
@@ -116,8 +113,8 @@ class Trigger(LazyLogging):
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]:
+ >>> @classmethod
+ >>> def configuration_sections(cls, configuration: Configuration) -> list[str]:
>>> return configuration.getlist("report", "target", fallback=[])
"""
del configuration
diff --git a/src/ahriman/core/triggers/trigger_loader.py b/src/ahriman/core/triggers/trigger_loader.py
index 4d23344c..ace455cf 100644
--- a/src/ahriman/core/triggers/trigger_loader.py
+++ b/src/ahriman/core/triggers/trigger_loader.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 __future__ import annotations
-
import contextlib
import os
@@ -26,6 +24,7 @@ from collections.abc import Generator
from importlib import import_module, machinery
from pathlib import Path
from types import ModuleType
+from typing import Self
from ahriman.core.configuration import Configuration
from ahriman.core.exceptions import ExtensionError
@@ -66,7 +65,7 @@ class TriggerLoader(LazyLogging):
self.triggers: list[Trigger] = []
@classmethod
- def load(cls: type[TriggerLoader], architecture: str, configuration: Configuration) -> TriggerLoader:
+ def load(cls, architecture: str, configuration: Configuration) -> Self:
"""
create instance from configuration
@@ -75,7 +74,7 @@ class TriggerLoader(LazyLogging):
configuration(Configuration): configuration instance
Returns:
- TriggerLoader: fully loaded trigger instance
+ Self: fully loaded trigger instance
"""
instance = cls()
instance.triggers = [
diff --git a/src/ahriman/core/upload/s3.py b/src/ahriman/core/upload/s3.py
index b086e734..dbf3bc4b 100644
--- a/src/ahriman/core/upload/s3.py
+++ b/src/ahriman/core/upload/s3.py
@@ -17,7 +17,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-import boto3 # type: ignore
+import boto3 # type: ignore[import]
import hashlib
import mimetypes
diff --git a/src/ahriman/core/upload/upload.py b/src/ahriman/core/upload/upload.py
index 052fc335..3b8f9fb1 100644
--- a/src/ahriman/core/upload/upload.py
+++ b/src/ahriman/core/upload/upload.py
@@ -66,8 +66,8 @@ class Upload(LazyLogging):
self.architecture = architecture
self.configuration = configuration
- @classmethod
- def load(cls: type[Upload], architecture: str, configuration: Configuration, target: str) -> Upload:
+ @staticmethod
+ def load(architecture: str, configuration: Configuration, target: str) -> Upload:
"""
load client from settings
@@ -90,7 +90,7 @@ class Upload(LazyLogging):
if provider == UploadSettings.Github:
from ahriman.core.upload.github import Github
return Github(architecture, configuration, section)
- return cls(architecture, configuration) # should never happen
+ return Upload(architecture, configuration) # should never happen
def run(self, path: Path, built_packages: list[Package]) -> None:
"""
diff --git a/src/ahriman/core/upload/upload_trigger.py b/src/ahriman/core/upload/upload_trigger.py
index ad96f30e..a3af9b6e 100644
--- a/src/ahriman/core/upload/upload_trigger.py
+++ b/src/ahriman/core/upload/upload_trigger.py
@@ -136,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, configuration: Configuration) -> list[str]:
"""
extract configuration sections from configuration
diff --git a/src/ahriman/models/aur_package.py b/src/ahriman/models/aur_package.py
index 709ee096..851ae17d 100644
--- a/src/ahriman/models/aur_package.py
+++ b/src/ahriman/models/aur_package.py
@@ -17,15 +17,13 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-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
+from pyalpm import Package # type: ignore[import]
+from typing import Any, Self
from ahriman.core.util import filter_json, full_version
@@ -102,7 +100,7 @@ class AURPackage:
keywords: list[str] = field(default_factory=list)
@classmethod
- def from_json(cls: type[AURPackage], dump: dict[str, Any]) -> AURPackage:
+ def from_json(cls, dump: dict[str, Any]) -> Self:
"""
construct package descriptor from RPC properties
@@ -110,7 +108,7 @@ class AURPackage:
dump(dict[str, Any]): json dump body
Returns:
- AURPackage: AUR package descriptor
+ Self: AUR package descriptor
"""
# filter to only known fields
known_fields = [pair.name for pair in fields(cls)]
@@ -118,7 +116,7 @@ class AURPackage:
return cls(**filter_json(properties, known_fields))
@classmethod
- def from_pacman(cls: type[AURPackage], package: Package) -> AURPackage:
+ def from_pacman(cls, package: Package) -> Self:
"""
construct package descriptor from official repository wrapper
@@ -126,7 +124,7 @@ class AURPackage:
package(Package): pyalpm package descriptor
Returns:
- AURPackage: AUR package descriptor
+ Self: AUR package descriptor
"""
return cls(
id=0,
@@ -155,7 +153,7 @@ class AURPackage:
)
@classmethod
- def from_repo(cls: type[AURPackage], dump: dict[str, Any]) -> AURPackage:
+ def from_repo(cls, dump: dict[str, Any]) -> Self:
"""
construct package descriptor from official repository RPC properties
@@ -163,7 +161,7 @@ class AURPackage:
dump(dict[str, Any]): json dump body
Returns:
- AURPackage: AUR package descriptor
+ Self: AUR package descriptor
"""
return cls(
id=0,
diff --git a/src/ahriman/models/auth_settings.py b/src/ahriman/models/auth_settings.py
index b61917a6..c036be54 100644
--- a/src/ahriman/models/auth_settings.py
+++ b/src/ahriman/models/auth_settings.py
@@ -36,23 +36,6 @@ class AuthSettings(str, Enum):
Configuration = "configuration"
OAuth = "oauth2"
- @classmethod
- def from_option(cls: type[AuthSettings], value: str) -> AuthSettings:
- """
- construct value from configuration
-
- Args:
- value(str): configuration value
-
- Returns:
- AuthSettings: parsed value
- """
- if value.lower() in ("configuration", "mapping"):
- return cls.Configuration
- if value.lower() in ("oauth", "oauth2"):
- return cls.OAuth
- return cls.Disabled
-
@property
def is_enabled(self) -> bool:
"""
@@ -64,3 +47,20 @@ class AuthSettings(str, Enum):
if self == AuthSettings.Disabled:
return False
return True
+
+ @staticmethod
+ def from_option(value: str) -> AuthSettings:
+ """
+ construct value from configuration
+
+ Args:
+ value(str): configuration value
+
+ Returns:
+ AuthSettings: parsed value
+ """
+ if value.lower() in ("configuration", "mapping"):
+ return AuthSettings.Configuration
+ if value.lower() in ("oauth", "oauth2"):
+ return AuthSettings.OAuth
+ return AuthSettings.Disabled
diff --git a/src/ahriman/models/build_status.py b/src/ahriman/models/build_status.py
index fe68dd49..03307c5e 100644
--- a/src/ahriman/models/build_status.py
+++ b/src/ahriman/models/build_status.py
@@ -17,11 +17,9 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-from __future__ import annotations
-
from dataclasses import dataclass, field, fields
from enum import Enum
-from typing import Any
+from typing import Any, Self
from ahriman.core.util import filter_json, pretty_datetime, utcnow
@@ -65,7 +63,7 @@ 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, dump: dict[str, Any]) -> Self:
"""
construct status properties from json dump
@@ -73,7 +71,7 @@ class BuildStatus:
dump(dict[str, Any]): json dump body
Returns:
- BuildStatus: status properties
+ Self: status properties
"""
known_fields = [pair.name for pair in fields(cls)]
return cls(**filter_json(dump, known_fields))
diff --git a/src/ahriman/models/counters.py b/src/ahriman/models/counters.py
index ccb2f8ea..8b99505c 100644
--- a/src/ahriman/models/counters.py
+++ b/src/ahriman/models/counters.py
@@ -17,10 +17,8 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-from __future__ import annotations
-
from dataclasses import dataclass, fields
-from typing import Any
+from typing import Any, Self
from ahriman.core.util import filter_json
from ahriman.models.build_status import BuildStatus
@@ -49,7 +47,7 @@ class Counters:
success: int = 0
@classmethod
- def from_json(cls: type[Counters], dump: dict[str, Any]) -> Counters:
+ def from_json(cls, dump: dict[str, Any]) -> Self:
"""
construct counters from json dump
@@ -57,14 +55,14 @@ class Counters:
dump(dict[str, Any]): json dump body
Returns:
- Counters: status counters
+ Self: status counters
"""
# filter to only known fields
known_fields = [pair.name for pair in fields(cls)]
return cls(**filter_json(dump, known_fields))
@classmethod
- def from_packages(cls: type[Counters], packages: list[tuple[Package, BuildStatus]]) -> Counters:
+ def from_packages(cls, packages: list[tuple[Package, BuildStatus]]) -> Self:
"""
construct counters from packages statuses
@@ -72,7 +70,7 @@ class Counters:
packages(list[tuple[Package, BuildStatus]]): list of package and their status as per watcher property
Returns:
- Counters: status counters
+ Self: status counters
"""
per_status = {"total": len(packages)}
for _, status in packages:
diff --git a/src/ahriman/models/internal_status.py b/src/ahriman/models/internal_status.py
index 8b76c1d8..1dbb6444 100644
--- a/src/ahriman/models/internal_status.py
+++ b/src/ahriman/models/internal_status.py
@@ -17,10 +17,8 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-from __future__ import annotations
-
from dataclasses import asdict, dataclass, field
-from typing import Any
+from typing import Any, Self
from ahriman.models.build_status import BuildStatus
from ahriman.models.counters import Counters
@@ -46,7 +44,7 @@ class InternalStatus:
version: str | None = None
@classmethod
- def from_json(cls: type[InternalStatus], dump: dict[str, Any]) -> InternalStatus:
+ def from_json(cls, dump: dict[str, Any]) -> Self:
"""
construct internal status from json dump
@@ -54,7 +52,7 @@ class InternalStatus:
dump(dict[str, Any]): json dump body
Returns:
- InternalStatus: internal status
+ Self: internal status
"""
counters = Counters.from_json(dump["packages"]) if "packages" in dump else Counters(total=0)
build_status = dump.get("status") or {}
diff --git a/src/ahriman/models/package.py b/src/ahriman/models/package.py
index 1523e9a1..64315992 100644
--- a/src/ahriman/models/package.py
+++ b/src/ahriman/models/package.py
@@ -25,9 +25,9 @@ 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
+from pyalpm import vercmp # type: ignore[import]
+from srcinfo.parse import parse_srcinfo # type: ignore[import]
+from typing import Any, Self
from ahriman.core.alpm.pacman import Pacman
from ahriman.core.alpm.remote import AUR, Official, OfficialSyncdb
@@ -179,7 +179,7 @@ class Package(LazyLogging):
return sorted(packages)
@classmethod
- def from_archive(cls: type[Package], path: Path, pacman: Pacman, remote: RemoteSource | None) -> Package:
+ def from_archive(cls, path: Path, pacman: Pacman, remote: RemoteSource | None) -> Self:
"""
construct package properties from package archive
@@ -189,14 +189,14 @@ class Package(LazyLogging):
remote(RemoteSource): package remote source if applicable
Returns:
- Package: package properties
+ Self: package properties
"""
package = pacman.handle.load_pkg(str(path))
description = PackageDescription.from_package(package, path)
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, name: str, pacman: Pacman) -> Self:
"""
construct package properties from AUR page
@@ -205,7 +205,7 @@ class Package(LazyLogging):
pacman(Pacman): alpm wrapper instance
Returns:
- Package: package properties
+ Self: package properties
"""
package = AUR.info(name, pacman=pacman)
remote = RemoteSource.from_source(PackageSource.AUR, package.package_base, package.repository)
@@ -216,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, path: Path, architecture: str) -> Self:
"""
construct package properties from sources directory
@@ -225,7 +225,7 @@ class Package(LazyLogging):
architecture(str): load package for specific architecture
Returns:
- Package: package properties
+ Self: package properties
Raises:
InvalidPackageInfo: if there are parsing errors
@@ -254,7 +254,7 @@ 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, dump: dict[str, Any]) -> Self:
"""
construct package properties from json dump
@@ -262,7 +262,7 @@ class Package(LazyLogging):
dump(dict[str, Any]): json dump body
Returns:
- Package: package properties
+ Self: package properties
"""
packages_json = dump.get("packages") or {}
packages = {
@@ -273,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, name: str, pacman: Pacman, *, use_syncdb: bool = True) -> Self:
"""
construct package properties from official repository page
@@ -283,7 +283,7 @@ class Package(LazyLogging):
use_syncdb(bool, optional): use pacman databases instead of official repositories RPC (Default value = True)
Returns:
- Package: package properties
+ Self: package properties
"""
package = OfficialSyncdb.info(name, pacman=pacman) if use_syncdb else Official.info(name, pacman=pacman)
remote = RemoteSource.from_source(PackageSource.Repository, package.package_base, package.repository)
diff --git a/src/ahriman/models/package_description.py b/src/ahriman/models/package_description.py
index 4868f93e..6f627922 100644
--- a/src/ahriman/models/package_description.py
+++ b/src/ahriman/models/package_description.py
@@ -17,12 +17,10 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-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
+from pyalpm import Package # type: ignore[import]
+from typing import Any, Self
from ahriman.core.util import filter_json, trim_package
from ahriman.models.aur_package import AURPackage
@@ -99,7 +97,7 @@ class PackageDescription:
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, package: AURPackage) -> Self:
"""
construct properties from AUR package model
@@ -107,7 +105,7 @@ class PackageDescription:
package(AURPackage): AUR package model
Returns:
- PackageDescription: package properties based on source AUR package
+ Self: package properties based on source AUR package
"""
return cls(
depends=package.depends,
@@ -120,7 +118,7 @@ class PackageDescription:
)
@classmethod
- def from_json(cls: type[PackageDescription], dump: dict[str, Any]) -> PackageDescription:
+ def from_json(cls, dump: dict[str, Any]) -> Self:
"""
construct package properties from json dump
@@ -128,14 +126,14 @@ class PackageDescription:
dump(dict[str, Any]): json dump body
Returns:
- PackageDescription: package properties
+ Self: package properties
"""
# filter to only known fields
known_fields = [pair.name for pair in fields(cls)]
return cls(**filter_json(dump, known_fields))
@classmethod
- def from_package(cls: type[PackageDescription], package: Package, path: Path) -> PackageDescription:
+ def from_package(cls, package: Package, path: Path) -> Self:
"""
construct class from alpm package class
@@ -144,7 +142,7 @@ class PackageDescription:
path(Path): path to package archive
Returns:
- PackageDescription: package properties based on tarball
+ Self: package properties based on tarball
"""
return cls(
architecture=package.arch,
diff --git a/src/ahriman/models/pacman_synchronization.py b/src/ahriman/models/pacman_synchronization.py
new file mode 100644
index 00000000..ac9e2f10
--- /dev/null
+++ b/src/ahriman/models/pacman_synchronization.py
@@ -0,0 +1,35 @@
+#
+# Copyright (c) 2021-2023 ahriman team.
+#
+# This file is part of ahriman
+# (see https://github.com/arcan1s/ahriman).
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+from enum import Enum
+
+
+class PacmanSynchronization(int, Enum):
+ """
+ pacman database synchronization flag
+
+ Attributes:
+ Disabled(PacmanSynchronization): (class attribute) do not synchronize local database
+ Enabled(PacmanSynchronization): (class attribute) synchronize local database (same as pacman -Sy)
+ Force(PacmanSynchronization): (class attribute) force synchronize local database (same as pacman -Syy)
+ """
+
+ Disabled = 0
+ Enabled = 1
+ Force = 2
diff --git a/src/ahriman/models/remote_source.py b/src/ahriman/models/remote_source.py
index 47aca111..4960b7c6 100644
--- a/src/ahriman/models/remote_source.py
+++ b/src/ahriman/models/remote_source.py
@@ -17,11 +17,9 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-from __future__ import annotations
-
from dataclasses import asdict, dataclass, fields
from pathlib import Path
-from typing import Any
+from typing import Any, Self
from ahriman.core.util import filter_json
from ahriman.models.package_source import PackageSource
@@ -63,7 +61,7 @@ class RemoteSource:
return Path(self.path)
@classmethod
- def from_json(cls: type[RemoteSource], dump: dict[str, Any]) -> RemoteSource | None:
+ def from_json(cls, dump: dict[str, Any]) -> Self | None:
"""
construct remote source from the json dump (or database row)
@@ -71,7 +69,7 @@ class RemoteSource:
dump(dict[str, Any]): json dump body
Returns:
- RemoteSource | None: remote source
+ Self | None: remote source
"""
# filter to only known fields
known_fields = [pair.name for pair in fields(cls)]
@@ -81,8 +79,7 @@ class RemoteSource:
return None
@classmethod
- def from_source(cls: type[RemoteSource], source: PackageSource, package_base: str,
- repository: str) -> RemoteSource | None:
+ def from_source(cls, source: PackageSource, package_base: str, repository: str) -> Self | None:
"""
generate remote source from the package base
@@ -92,11 +89,11 @@ class RemoteSource:
repository(str): repository name
Returns:
- RemoteSource | None: generated remote source if any, None otherwise
+ Self | None: generated remote source if any, None otherwise
"""
if source == PackageSource.AUR:
from ahriman.core.alpm.remote import AUR
- return RemoteSource(
+ return cls(
git_url=AUR.remote_git_url(package_base, repository),
web_url=AUR.remote_web_url(package_base),
path=".",
@@ -105,7 +102,7 @@ class RemoteSource:
)
if source == PackageSource.Repository:
from ahriman.core.alpm.remote import Official
- return RemoteSource(
+ return cls(
git_url=Official.remote_git_url(package_base, repository),
web_url=Official.remote_web_url(package_base),
path="trunk",
diff --git a/src/ahriman/models/report_settings.py b/src/ahriman/models/report_settings.py
index d6eef851..258e0386 100644
--- a/src/ahriman/models/report_settings.py
+++ b/src/ahriman/models/report_settings.py
@@ -40,8 +40,8 @@ class ReportSettings(str, Enum):
Console = "console"
Telegram = "telegram"
- @classmethod
- def from_option(cls: type[ReportSettings], value: str) -> ReportSettings:
+ @staticmethod
+ def from_option(value: str) -> ReportSettings:
"""
construct value from configuration
@@ -52,11 +52,11 @@ class ReportSettings(str, Enum):
ReportSettings: parsed value
"""
if value.lower() in ("html",):
- return cls.HTML
+ return ReportSettings.HTML
if value.lower() in ("email",):
- return cls.Email
+ return ReportSettings.Email
if value.lower() in ("console",):
- return cls.Console
+ return ReportSettings.Console
if value.lower() in ("telegram",):
- return cls.Telegram
- return cls.Disabled
+ return ReportSettings.Telegram
+ return ReportSettings.Disabled
diff --git a/src/ahriman/models/repository_paths.py b/src/ahriman/models/repository_paths.py
index 607d5915..42ac1f06 100644
--- a/src/ahriman/models/repository_paths.py
+++ b/src/ahriman/models/repository_paths.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 __future__ import annotations
-
import os
import shutil
@@ -117,7 +115,7 @@ class RepositoryPaths:
return self.owner(self.root)
@classmethod
- def known_architectures(cls: type[RepositoryPaths], root: Path) -> set[str]:
+ def known_architectures(cls, root: Path) -> set[str]:
"""
get known architectures
diff --git a/src/ahriman/models/sign_settings.py b/src/ahriman/models/sign_settings.py
index bfeadb76..73dd51d9 100644
--- a/src/ahriman/models/sign_settings.py
+++ b/src/ahriman/models/sign_settings.py
@@ -36,8 +36,8 @@ class SignSettings(str, Enum):
Packages = "packages"
Repository = "repository"
- @classmethod
- def from_option(cls: type[SignSettings], value: str) -> SignSettings:
+ @staticmethod
+ def from_option(value: str) -> SignSettings:
"""
construct value from configuration
@@ -48,7 +48,7 @@ class SignSettings(str, Enum):
SignSettings: parsed value
"""
if value.lower() in ("package", "packages", "sign-package"):
- return cls.Packages
+ return SignSettings.Packages
if value.lower() in ("repository", "sign-repository"):
- return cls.Repository
- return cls.Disabled
+ return SignSettings.Repository
+ return SignSettings.Disabled
diff --git a/src/ahriman/models/smtp_ssl_settings.py b/src/ahriman/models/smtp_ssl_settings.py
index 752fa84d..e7eac78b 100644
--- a/src/ahriman/models/smtp_ssl_settings.py
+++ b/src/ahriman/models/smtp_ssl_settings.py
@@ -36,8 +36,8 @@ class SmtpSSLSettings(str, Enum):
SSL = "ssl"
STARTTLS = "starttls"
- @classmethod
- def from_option(cls: type[SmtpSSLSettings], value: str) -> SmtpSSLSettings:
+ @staticmethod
+ def from_option(value: str) -> SmtpSSLSettings:
"""
construct value from configuration
@@ -48,7 +48,7 @@ class SmtpSSLSettings(str, Enum):
SmtpSSLSettings: parsed value
"""
if value.lower() in ("ssl", "ssl/tls"):
- return cls.SSL
+ return SmtpSSLSettings.SSL
if value.lower() in ("starttls",):
- return cls.STARTTLS
- return cls.Disabled
+ return SmtpSSLSettings.STARTTLS
+ return SmtpSSLSettings.Disabled
diff --git a/src/ahriman/models/upload_settings.py b/src/ahriman/models/upload_settings.py
index 26456642..d6f959e6 100644
--- a/src/ahriman/models/upload_settings.py
+++ b/src/ahriman/models/upload_settings.py
@@ -38,8 +38,8 @@ class UploadSettings(str, Enum):
S3 = "s3"
Github = "github"
- @classmethod
- def from_option(cls: type[UploadSettings], value: str) -> UploadSettings:
+ @staticmethod
+ def from_option(value: str) -> UploadSettings:
"""
construct value from configuration
@@ -50,9 +50,9 @@ class UploadSettings(str, Enum):
UploadSettings: parsed value
"""
if value.lower() in ("rsync",):
- return cls.Rsync
+ return UploadSettings.Rsync
if value.lower() in ("s3",):
- return cls.S3
+ return UploadSettings.S3
if value.lower() in ("github",):
- return cls.Github
- return cls.Disabled
+ return UploadSettings.Github
+ return UploadSettings.Disabled
diff --git a/src/ahriman/models/user.py b/src/ahriman/models/user.py
index 20efa6de..8c9b1864 100644
--- a/src/ahriman/models/user.py
+++ b/src/ahriman/models/user.py
@@ -17,11 +17,10 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-from __future__ import annotations
-
from dataclasses import dataclass, replace
from passlib.hash import sha512_crypt
from passlib.pwd import genword as generate_password
+from typing import Self
from ahriman.models.user_access import UserAccess
@@ -66,8 +65,8 @@ class User:
_HASHER = sha512_crypt
@classmethod
- def from_option(cls: type[User], username: str | None, password: str | None,
- access: UserAccess = UserAccess.Read) -> User | None:
+ def from_option(cls, username: str | None, password: str | None,
+ access: UserAccess = UserAccess.Read) -> Self | None:
"""
build user descriptor from configuration options
@@ -77,7 +76,7 @@ class User:
access(UserAccess, optional): optional user access (Default value = UserAccess.Read)
Returns:
- User | None: generated user descriptor if all options are supplied and None otherwise
+ Self | None: generated user descriptor if all options are supplied and None otherwise
"""
if username is None or password is None:
return None
@@ -114,7 +113,7 @@ class User:
verified = False # the absence of evidence is not the evidence of absence (c) Gin Rummy
return verified
- def hash_password(self, salt: str) -> User:
+ def hash_password(self, salt: str) -> Self:
"""
generate hashed password from plain text
@@ -122,7 +121,7 @@ class User:
salt(str): salt for hashed password
Returns:
- User: user with hashed password to store in configuration
+ Self: user with hashed password to store in configuration
"""
if not self.password:
# in case of empty password we leave it empty. This feature is used by any external (like OAuth) provider
diff --git a/src/ahriman/web/apispec.py b/src/ahriman/web/apispec.py
index 21bf7a80..e4d55b25 100644
--- a/src/ahriman/web/apispec.py
+++ b/src/ahriman/web/apispec.py
@@ -17,7 +17,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-import aiohttp_apispec # type: ignore
+import aiohttp_apispec # type: ignore[import]
from aiohttp.web import Application
from typing import Any
diff --git a/src/ahriman/web/cors.py b/src/ahriman/web/cors.py
index 83f75399..2d9f19cc 100644
--- a/src/ahriman/web/cors.py
+++ b/src/ahriman/web/cors.py
@@ -17,7 +17,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-import aiohttp_cors # type: ignore
+import aiohttp_cors # type: ignore[import]
from aiohttp.web import Application
diff --git a/src/ahriman/web/middlewares/auth_handler.py b/src/ahriman/web/middlewares/auth_handler.py
index 21770383..82360f83 100644
--- a/src/ahriman/web/middlewares/auth_handler.py
+++ b/src/ahriman/web/middlewares/auth_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 .
#
-import aiohttp_security # type: ignore
+import aiohttp_security # type: ignore[import]
import socket
import types
diff --git a/src/ahriman/web/views/base.py b/src/ahriman/web/views/base.py
index 15ceffe1..5a57c084 100644
--- a/src/ahriman/web/views/base.py
+++ b/src/ahriman/web/views/base.py
@@ -17,9 +17,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-from __future__ import annotations
-
-from aiohttp_cors import CorsViewMixin # type: ignore
+from aiohttp_cors import CorsViewMixin # type: ignore[import]
from aiohttp.web import Request, StreamResponse, View
from collections.abc import Awaitable, Callable
from typing import Any, TypeVar
@@ -89,7 +87,7 @@ class BaseView(View, CorsViewMixin):
return validator
@classmethod
- async def get_permission(cls: type[BaseView], request: Request) -> UserAccess:
+ async def get_permission(cls, request: Request) -> UserAccess:
"""
retrieve user permission from the request
@@ -168,7 +166,7 @@ class BaseView(View, CorsViewMixin):
return await self.data_as_json(list_keys or [])
# pylint: disable=not-callable,protected-access
- async def head(self) -> StreamResponse: # type: ignore
+ async def head(self) -> StreamResponse: # type: ignore[return]
"""
HEAD method implementation based on the result of GET method
@@ -181,7 +179,7 @@ class BaseView(View, CorsViewMixin):
if get_method is not None:
# there is a bug in pylint, see https://github.com/pylint-dev/pylint/issues/6005
response = await get_method()
- response._body = b"" # type: ignore
+ response._body = b"" # type: ignore[assignment]
return response
self._raise_allowed_methods()
diff --git a/src/ahriman/web/views/service/add.py b/src/ahriman/web/views/service/add.py
index 581d8479..e74524fc 100644
--- a/src/ahriman/web/views/service/add.py
+++ b/src/ahriman/web/views/service/add.py
@@ -17,7 +17,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-import aiohttp_apispec # type: ignore
+import aiohttp_apispec # type: ignore[import]
from aiohttp.web import HTTPBadRequest, HTTPNoContent
diff --git a/src/ahriman/web/views/service/pgp.py b/src/ahriman/web/views/service/pgp.py
index df4513e9..80f48fb0 100644
--- a/src/ahriman/web/views/service/pgp.py
+++ b/src/ahriman/web/views/service/pgp.py
@@ -17,7 +17,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-import aiohttp_apispec # type: ignore
+import aiohttp_apispec # type: ignore[import]
from aiohttp.web import HTTPBadRequest, HTTPNoContent, HTTPNotFound, Response, json_response
diff --git a/src/ahriman/web/views/service/rebuild.py b/src/ahriman/web/views/service/rebuild.py
index 9b062cbd..7ee12b78 100644
--- a/src/ahriman/web/views/service/rebuild.py
+++ b/src/ahriman/web/views/service/rebuild.py
@@ -17,7 +17,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-import aiohttp_apispec # type: ignore
+import aiohttp_apispec # type: ignore[import]
from aiohttp.web import HTTPBadRequest, HTTPNoContent
diff --git a/src/ahriman/web/views/service/remove.py b/src/ahriman/web/views/service/remove.py
index 664ef565..a3e7ac62 100644
--- a/src/ahriman/web/views/service/remove.py
+++ b/src/ahriman/web/views/service/remove.py
@@ -17,7 +17,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-import aiohttp_apispec # type: ignore
+import aiohttp_apispec # type: ignore[import]
from aiohttp.web import HTTPBadRequest, HTTPNoContent
diff --git a/src/ahriman/web/views/service/request.py b/src/ahriman/web/views/service/request.py
index a5342dfa..7e5dd695 100644
--- a/src/ahriman/web/views/service/request.py
+++ b/src/ahriman/web/views/service/request.py
@@ -17,7 +17,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-import aiohttp_apispec # type: ignore
+import aiohttp_apispec # type: ignore[import]
from aiohttp.web import HTTPBadRequest, HTTPNoContent
diff --git a/src/ahriman/web/views/service/search.py b/src/ahriman/web/views/service/search.py
index 2cd33010..85906767 100644
--- a/src/ahriman/web/views/service/search.py
+++ b/src/ahriman/web/views/service/search.py
@@ -17,7 +17,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-import aiohttp_apispec # type: ignore
+import aiohttp_apispec # type: ignore[import]
from aiohttp.web import HTTPBadRequest, HTTPNotFound, Response, json_response
from collections.abc import Callable
diff --git a/src/ahriman/web/views/service/update.py b/src/ahriman/web/views/service/update.py
index da8da5e5..a164f563 100644
--- a/src/ahriman/web/views/service/update.py
+++ b/src/ahriman/web/views/service/update.py
@@ -17,7 +17,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-import aiohttp_apispec # type: ignore
+import aiohttp_apispec # type: ignore[import]
from aiohttp.web import HTTPNoContent
diff --git a/src/ahriman/web/views/status/logs.py b/src/ahriman/web/views/status/logs.py
index 7cc5c07b..6d2a6694 100644
--- a/src/ahriman/web/views/status/logs.py
+++ b/src/ahriman/web/views/status/logs.py
@@ -17,7 +17,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-import aiohttp_apispec # type: ignore
+import aiohttp_apispec # type: ignore[import]
from aiohttp.web import HTTPBadRequest, HTTPNoContent, HTTPNotFound, Response, json_response
diff --git a/src/ahriman/web/views/status/package.py b/src/ahriman/web/views/status/package.py
index 0813a428..23e3e3d5 100644
--- a/src/ahriman/web/views/status/package.py
+++ b/src/ahriman/web/views/status/package.py
@@ -17,7 +17,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-import aiohttp_apispec # type: ignore
+import aiohttp_apispec # type: ignore[import]
from aiohttp.web import HTTPBadRequest, HTTPNoContent, HTTPNotFound, Response, json_response
diff --git a/src/ahriman/web/views/status/packages.py b/src/ahriman/web/views/status/packages.py
index 4a46f1e4..fb0b7ae6 100644
--- a/src/ahriman/web/views/status/packages.py
+++ b/src/ahriman/web/views/status/packages.py
@@ -17,7 +17,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-import aiohttp_apispec # type: ignore
+import aiohttp_apispec # type: ignore[import]
from aiohttp.web import HTTPNoContent, Response, json_response
diff --git a/src/ahriman/web/views/status/status.py b/src/ahriman/web/views/status/status.py
index 29e214b2..e6269d18 100644
--- a/src/ahriman/web/views/status/status.py
+++ b/src/ahriman/web/views/status/status.py
@@ -17,7 +17,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-import aiohttp_apispec # type: ignore
+import aiohttp_apispec # type: ignore[import]
from aiohttp.web import HTTPBadRequest, HTTPNoContent, Response, json_response
diff --git a/src/ahriman/web/views/user/login.py b/src/ahriman/web/views/user/login.py
index ecaf6b04..35e1c59e 100644
--- a/src/ahriman/web/views/user/login.py
+++ b/src/ahriman/web/views/user/login.py
@@ -17,7 +17,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-import aiohttp_apispec # type: ignore
+import aiohttp_apispec # type: ignore[import]
from aiohttp.web import HTTPFound, HTTPMethodNotAllowed, HTTPUnauthorized
diff --git a/src/ahriman/web/views/user/logout.py b/src/ahriman/web/views/user/logout.py
index 24ab01ff..4e7e4ba9 100644
--- a/src/ahriman/web/views/user/logout.py
+++ b/src/ahriman/web/views/user/logout.py
@@ -17,7 +17,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-import aiohttp_apispec # type: ignore
+import aiohttp_apispec # type: ignore[import]
from aiohttp.web import HTTPFound, HTTPUnauthorized
diff --git a/src/ahriman/web/web.py b/src/ahriman/web/web.py
index f25f72a8..f9b8884a 100644
--- a/src/ahriman/web/web.py
+++ b/src/ahriman/web/web.py
@@ -163,7 +163,7 @@ def setup_service(architecture: str, configuration: Configuration, spawner: Spaw
application.logger.info("setup debug panel")
debug_enabled = configuration.getboolean("web", "debug", fallback=False)
if debug_enabled:
- import aiohttp_debugtoolbar # type: ignore
+ import aiohttp_debugtoolbar # type: ignore[import]
aiohttp_debugtoolbar.setup(application,
hosts=configuration.getlist("web", "debug_allowed_hosts", fallback=[]),
check_host=configuration.getboolean("web", "debug_check_host", fallback=False))
diff --git a/tests/ahriman/application/handlers/test_handler_versions.py b/tests/ahriman/application/handlers/test_handler_versions.py
index 44f55aed..735ffed3 100644
--- a/tests/ahriman/application/handlers/test_handler_versions.py
+++ b/tests/ahriman/application/handlers/test_handler_versions.py
@@ -15,7 +15,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration, mocker: Moc
print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
Versions.run(args, "x86_64", configuration, report=False, unsafe=False)
- application_mock.assert_called_once_with("ahriman", ("pacman", "s3", "web"))
+ application_mock.assert_called_once_with("ahriman")
print_mock.assert_has_calls([MockCall(verbose=False, separator=" "), MockCall(verbose=False, separator=" ")])
@@ -23,7 +23,7 @@ def test_package_dependencies() -> None:
"""
must extract package dependencies
"""
- packages = Versions.package_dependencies("srcinfo")
+ packages = dict(Versions.package_dependencies("srcinfo"))
assert packages
assert packages.get("parse") is not None
@@ -32,7 +32,7 @@ def test_package_dependencies_missing() -> None:
"""
must extract package dependencies even if some of them are missing
"""
- packages = Versions.package_dependencies("ahriman", ("docs", "pacman", "s3", "web"))
+ packages = dict(Versions.package_dependencies("ahriman"))
assert packages
assert packages.get("pyalpm") is not None
assert packages.get("Sphinx") is None
diff --git a/tests/ahriman/web/conftest.py b/tests/ahriman/web/conftest.py
index eeb4885b..665bbdac 100644
--- a/tests/ahriman/web/conftest.py
+++ b/tests/ahriman/web/conftest.py
@@ -68,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[attr-defined]
return next(schema["schema"] for schema in schemas if schema["put_into"] == location)
@@ -84,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[attr-defined]
schema = schemas[code]["schema"]
if callable(schema):
schema = schema()
diff --git a/tests/ahriman/web/views/api/test_views_api_swagger.py b/tests/ahriman/web/views/api/test_views_api_swagger.py
index 80490b3c..5d39e977 100644
--- a/tests/ahriman/web/views/api/test_views_api_swagger.py
+++ b/tests/ahriman/web/views/api/test_views_api_swagger.py
@@ -1,22 +1,25 @@
import pytest
from aiohttp.test_utils import TestClient
+from pytest_mock import MockerFixture
+from typing import Any
from ahriman.models.user_access import UserAccess
from ahriman.web.views.api.swagger import SwaggerView
-def _client(client: TestClient) -> TestClient:
+def _client(client: TestClient, mocker: MockerFixture) -> TestClient:
"""
- generate test client with docs
+ generate test client with docs. Thanks to deprecation, we can't change application state since it was run
Args:
client(TestClient): test client fixture
+ mocker(MockerFixture): mocker object
Returns:
TestClient: test client fixture with additional properties
"""
- client.app["swagger_dict"] = {
+ swagger_dict = {
"paths": {
"/api/v1/logout": {
"get": {
@@ -62,6 +65,14 @@ def _client(client: TestClient) -> TestClient:
},
],
}
+ source = client.app.__getitem__
+
+ def getitem(name: str) -> Any:
+ if name == "swagger_dict":
+ return swagger_dict
+ return source(name)
+
+ mocker.patch("aiohttp.web.Application.__getitem__", side_effect=getitem)
return client
@@ -75,11 +86,11 @@ async def test_get_permission() -> None:
assert await SwaggerView.get_permission(request) == UserAccess.Unauthorized
-async def test_get(client: TestClient) -> None:
+async def test_get(client: TestClient, mocker: MockerFixture) -> None:
"""
must generate api-docs correctly
"""
- client = _client(client)
+ client = _client(client, mocker)
response = await client.get("/api-docs/swagger.json")
assert response.ok
diff --git a/tox.ini b/tox.ini
index ff76590f..d19b3ad3 100644
--- a/tox.ini
+++ b/tox.ini
@@ -4,7 +4,7 @@ dependencies = -e .[pacman,s3,web]
project_name = ahriman
[mypy]
-flags = --implicit-reexport --strict --allow-untyped-decorators --allow-subclassing-any
+flags = --implicit-reexport --strict --allow-untyped-decorators --allow-subclassing-any --python-version 3.11
[pytest]
addopts = --cov=ahriman --cov-report=term-missing:skip-covered --no-cov-on-fail --cov-fail-under=100 --spec
@@ -57,5 +57,6 @@ commands =
deps =
{[tox]dependencies}
-e .[tests]
+ typing_extensions
commands =
pytest {posargs}