mirror of
https://github.com/arcan1s/ahriman.git
synced 2025-04-24 15:27:17 +00:00
PEP-585 complaint: remove type aliases (#93)
This commit is contained in:
parent
54d36ccf36
commit
abf29083c4
@ -91,6 +91,7 @@ Again, the most checks can be performed by `make check` command, though some add
|
||||
```
|
||||
|
||||
* Type annotations are the must, even for local functions.
|
||||
* For collection types built-in classes must be used if possible (e.g. `dict` instead of `typing.Dict`, `tuple` instead of `typing.Tuple`). In case if built-in type is not available, but `collections.abc` provides interface, it must be used (e.g. `collections.abc.Awaitable` instead of `typing.Awaitable`, `collections.abc.Iterable` instead of `typing.Iterable`). For union classes, the bar operator (`|`) must be used (e.g. `float | int` instead of `typing.Union[float, int]`), which also includes `typinng.Optional` (e.g. `str | None` instead of `Optional[str]`).
|
||||
* Recommended order of function definitions in class:
|
||||
|
||||
```python
|
||||
@ -102,7 +103,7 @@ Again, the most checks can be performed by `make check` command, though some add
|
||||
def property(self) -> Any: ...
|
||||
|
||||
@classmethod
|
||||
def class_method(cls: Type[Clazz]) -> Clazz: ...
|
||||
def class_method(cls: type[Clazz]) -> Clazz: ...
|
||||
|
||||
@staticmethod
|
||||
def static_method() -> Any: ...
|
||||
|
@ -121,7 +121,7 @@ Type conversions
|
||||
|
||||
By default, it parses rows into python dictionary. In addition, the following pseudo-types are supported:
|
||||
|
||||
* ``Dict[str, Any]``, ``List[Any]`` - for storing JSON data structures in database (technically there is no restriction on types for dictionary keys and values, but it is recommended to use only string keys). The type is stored as ``json`` data type and ``json.loads`` and ``json.dumps`` methods are used in order to read and write from/to database respectively.
|
||||
* ``dict[str, Any]``, ``list[Any]`` - for storing JSON data structures in database (technically there is no restriction on types for dictionary keys and values, but it is recommended to use only string keys). The type is stored as ``json`` data type and ``json.loads`` and ``json.dumps`` methods are used in order to read and write from/to database respectively.
|
||||
|
||||
Basic flows
|
||||
-----------
|
||||
@ -235,7 +235,7 @@ Triggers are extensions which can be used in order to perform any actions on app
|
||||
|
||||
The main idea is to load classes by their full path (e.g. ``ahriman.core.upload.UploadTrigger``) by using ``importlib``: get the last part of the import and treat it as class name, join remain part by ``.`` and interpret as module path, import module and extract attribute from it.
|
||||
|
||||
The loaded triggers will be called with ``ahriman.models.result.Result`` and ``List[Packages]`` arguments, which describes the process result and current repository packages respectively. Any exception raised will be suppressed and will generate an exception message in logs.
|
||||
The loaded triggers will be called with ``ahriman.models.result.Result`` and ``list[Packages]`` arguments, which describes the process result and current repository packages respectively. Any exception raised will be suppressed and will generate an exception message in logs.
|
||||
|
||||
In addition triggers can implement ``on_start`` and ``on_stop`` actions which will be called on the application start and right before the application exit. The ``on_start`` action is usually being called from handlers directly in order to make sure that no trigger will be run when it is not required (e.g. on user management). As soon as ``on_start`` action is called, the additional flag will be set; ``ahriman.core.triggers.TriggerLoader`` class implements ``__del__`` method in which, if the flag is set, the ``on_stop`` actions will be called.
|
||||
|
||||
|
4
setup.py
4
setup.py
@ -1,10 +1,10 @@
|
||||
from pathlib import Path
|
||||
from setuptools import find_packages, setup
|
||||
from typing import Any, Dict
|
||||
from typing import Any
|
||||
|
||||
|
||||
metadata_path = Path(__file__).resolve().parent / "src/ahriman/version.py"
|
||||
metadata: Dict[str, Any] = {}
|
||||
metadata: dict[str, Any] = {}
|
||||
with metadata_path.open() as metadata_file:
|
||||
exec(metadata_file.read(), metadata) # pylint: disable=exec-used
|
||||
|
||||
|
@ -23,7 +23,7 @@ import sys
|
||||
import tempfile
|
||||
|
||||
from pathlib import Path
|
||||
from typing import List, TypeVar
|
||||
from typing import TypeVar
|
||||
|
||||
from ahriman import version
|
||||
from ahriman.application import handlers
|
||||
@ -35,7 +35,7 @@ from ahriman.models.sign_settings import SignSettings
|
||||
from ahriman.models.user_access import UserAccess
|
||||
|
||||
|
||||
__all__: List[str] = []
|
||||
__all__: list[str] = []
|
||||
|
||||
|
||||
# this workaround is for several things
|
||||
|
@ -17,7 +17,7 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
from typing import Iterable, List, Set
|
||||
from collections.abc import Iterable
|
||||
|
||||
from ahriman.application.application.application_packages import ApplicationPackages
|
||||
from ahriman.application.application.application_repository import ApplicationRepository
|
||||
@ -50,14 +50,14 @@ class Application(ApplicationPackages, ApplicationRepository):
|
||||
be used instead.
|
||||
"""
|
||||
|
||||
def _known_packages(self) -> Set[str]:
|
||||
def _known_packages(self) -> set[str]:
|
||||
"""
|
||||
load packages from repository and pacman repositories
|
||||
|
||||
Returns:
|
||||
Set[str]: list of known packages
|
||||
set[str]: list of known packages
|
||||
"""
|
||||
known_packages: Set[str] = set()
|
||||
known_packages: set[str] = set()
|
||||
# local set
|
||||
for base in self.repository.packages():
|
||||
for package, properties in base.packages.items():
|
||||
@ -89,15 +89,15 @@ class Application(ApplicationPackages, ApplicationRepository):
|
||||
"""
|
||||
self.repository.triggers.on_stop()
|
||||
|
||||
def with_dependencies(self, packages: List[Package], *, process_dependencies: bool) -> List[Package]:
|
||||
def with_dependencies(self, packages: list[Package], *, process_dependencies: bool) -> list[Package]:
|
||||
"""
|
||||
add missing dependencies to list of packages
|
||||
|
||||
Args:
|
||||
packages(List[Package]): list of source packages of which dependencies have to be processed
|
||||
packages(list[Package]): list of source packages of which dependencies have to be processed
|
||||
process_dependencies(bool): if no set, dependencies will not be processed
|
||||
"""
|
||||
def missing_dependencies(source: Iterable[Package]) -> Set[str]:
|
||||
def missing_dependencies(source: Iterable[Package]) -> set[str]:
|
||||
# build initial list of dependencies
|
||||
result = set()
|
||||
for package in source:
|
||||
|
@ -20,8 +20,9 @@
|
||||
import requests
|
||||
import shutil
|
||||
|
||||
from collections.abc import Iterable
|
||||
from pathlib import Path
|
||||
from typing import Any, Iterable
|
||||
from typing import Any
|
||||
|
||||
from ahriman.application.application.application_properties import ApplicationProperties
|
||||
from ahriman.core.build_tools.sources import Sources
|
||||
|
@ -17,8 +17,8 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
from collections.abc import Callable, Iterable
|
||||
from pathlib import Path
|
||||
from typing import Callable, Iterable, List
|
||||
|
||||
from ahriman.application.application.application_properties import ApplicationProperties
|
||||
from ahriman.core.build_tools.sources import Sources
|
||||
@ -89,19 +89,19 @@ class ApplicationRepository(ApplicationProperties):
|
||||
# process triggers
|
||||
self.on_result(Result())
|
||||
|
||||
def unknown(self) -> List[str]:
|
||||
def unknown(self) -> list[str]:
|
||||
"""
|
||||
get packages which were not found in AUR
|
||||
|
||||
Returns:
|
||||
List[str]: unknown package archive list
|
||||
list[str]: unknown package archive list
|
||||
"""
|
||||
def has_local(probe: Package) -> bool:
|
||||
cache_dir = self.repository.paths.cache_for(probe.base)
|
||||
return cache_dir.is_dir() and not Sources.has_remotes(cache_dir)
|
||||
|
||||
def unknown_aur(probe: Package) -> List[str]:
|
||||
packages: List[str] = []
|
||||
def unknown_aur(probe: Package) -> list[str]:
|
||||
packages: list[str] = []
|
||||
for single in probe.packages:
|
||||
try:
|
||||
_ = Package.from_aur(single, self.repository.pacman)
|
||||
@ -109,7 +109,7 @@ class ApplicationRepository(ApplicationProperties):
|
||||
packages.append(single)
|
||||
return packages
|
||||
|
||||
def unknown_local(probe: Package) -> List[str]:
|
||||
def unknown_local(probe: Package) -> list[str]:
|
||||
cache_dir = self.repository.paths.cache_for(probe.base)
|
||||
local = Package.from_build(cache_dir, self.architecture)
|
||||
packages = set(probe.packages.keys()).difference(local.packages.keys())
|
||||
@ -155,7 +155,7 @@ class ApplicationRepository(ApplicationProperties):
|
||||
return build_result
|
||||
|
||||
def updates(self, filter_packages: Iterable[str], *,
|
||||
aur: bool, local: bool, manual: bool, vcs: bool, log_fn: Callable[[str], None]) -> List[Package]:
|
||||
aur: bool, local: bool, manual: bool, vcs: bool, log_fn: Callable[[str], None]) -> list[Package]:
|
||||
"""
|
||||
get list of packages to run update process
|
||||
|
||||
@ -168,7 +168,7 @@ class ApplicationRepository(ApplicationProperties):
|
||||
log_fn(Callable[[str], None]): logger function to log updates
|
||||
|
||||
Returns:
|
||||
List[Package]: list of out-of-dated packages
|
||||
list[Package]: list of out-of-dated packages
|
||||
"""
|
||||
updates = {}
|
||||
|
||||
|
@ -19,8 +19,6 @@
|
||||
#
|
||||
import argparse
|
||||
|
||||
from typing import Type
|
||||
|
||||
from ahriman.application.application import Application
|
||||
from ahriman.application.handlers import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
@ -32,7 +30,7 @@ class Add(Handler):
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||
def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||
report: bool, unsafe: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
|
@ -22,7 +22,6 @@ import pwd
|
||||
|
||||
from pathlib import Path
|
||||
from tarfile import TarFile
|
||||
from typing import Set, Type
|
||||
|
||||
from ahriman.application.handlers import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
@ -37,7 +36,7 @@ class Backup(Handler):
|
||||
ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture"
|
||||
|
||||
@classmethod
|
||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||
def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||
report: bool, unsafe: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
@ -55,7 +54,7 @@ class Backup(Handler):
|
||||
archive.add(backup_path)
|
||||
|
||||
@staticmethod
|
||||
def get_paths(configuration: Configuration) -> Set[Path]:
|
||||
def get_paths(configuration: Configuration) -> set[Path]:
|
||||
"""
|
||||
extract paths to back up
|
||||
|
||||
@ -63,7 +62,7 @@ class Backup(Handler):
|
||||
configuration(Configuration): configuration instance
|
||||
|
||||
Returns:
|
||||
Set[Path]: map of the filesystem paths
|
||||
set[Path]: map of the filesystem paths
|
||||
"""
|
||||
paths = set(configuration.include.glob("*.ini"))
|
||||
|
||||
|
@ -19,8 +19,6 @@
|
||||
#
|
||||
import argparse
|
||||
|
||||
from typing import Type
|
||||
|
||||
from ahriman.application.application import Application
|
||||
from ahriman.application.handlers import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
@ -32,7 +30,7 @@ class Clean(Handler):
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||
def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||
report: bool, unsafe: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
|
@ -20,8 +20,6 @@
|
||||
import argparse
|
||||
import threading
|
||||
|
||||
from typing import Type
|
||||
|
||||
from ahriman.application.handlers import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
|
||||
@ -32,7 +30,7 @@ class Daemon(Handler):
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||
def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||
report: bool, unsafe: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
|
@ -19,8 +19,6 @@
|
||||
#
|
||||
import argparse
|
||||
|
||||
from typing import Type
|
||||
|
||||
from ahriman.application.handlers import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.formatters import ConfigurationPrinter
|
||||
@ -34,7 +32,7 @@ class Dump(Handler):
|
||||
ALLOW_AUTO_ARCHITECTURE_RUN = False
|
||||
|
||||
@classmethod
|
||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||
def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||
report: bool, unsafe: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
|
@ -23,7 +23,6 @@ import argparse
|
||||
import logging
|
||||
|
||||
from multiprocessing import Pool
|
||||
from typing import List, Type
|
||||
|
||||
from ahriman.application.lock import Lock
|
||||
from ahriman.core.configuration import Configuration
|
||||
@ -53,7 +52,7 @@ class Handler:
|
||||
ALLOW_MULTI_ARCHITECTURE_RUN = True
|
||||
|
||||
@classmethod
|
||||
def architectures_extract(cls: Type[Handler], args: argparse.Namespace) -> List[str]:
|
||||
def architectures_extract(cls: type[Handler], args: argparse.Namespace) -> list[str]:
|
||||
"""
|
||||
get known architectures
|
||||
|
||||
@ -61,7 +60,7 @@ class Handler:
|
||||
args(argparse.Namespace): command line args
|
||||
|
||||
Returns:
|
||||
List[str]: list of architectures for which tree is created
|
||||
list[str]: list of architectures for which tree is created
|
||||
|
||||
Raises:
|
||||
MissingArchitecture: if no architecture set and automatic detection is not allowed or failed
|
||||
@ -84,7 +83,7 @@ class Handler:
|
||||
return sorted(architectures)
|
||||
|
||||
@classmethod
|
||||
def call(cls: Type[Handler], args: argparse.Namespace, architecture: str) -> bool:
|
||||
def call(cls: type[Handler], args: argparse.Namespace, architecture: str) -> bool:
|
||||
"""
|
||||
additional function to wrap all calls for multiprocessing library
|
||||
|
||||
@ -109,7 +108,7 @@ class Handler:
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
def execute(cls: Type[Handler], args: argparse.Namespace) -> int:
|
||||
def execute(cls: type[Handler], args: argparse.Namespace) -> int:
|
||||
"""
|
||||
execute function for all aru
|
||||
|
||||
@ -138,7 +137,7 @@ class Handler:
|
||||
return 0 if all(result) else 1
|
||||
|
||||
@classmethod
|
||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||
def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||
report: bool, unsafe: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
|
@ -19,8 +19,6 @@
|
||||
#
|
||||
import argparse
|
||||
|
||||
from typing import Type
|
||||
|
||||
from ahriman.application.handlers import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
|
||||
@ -33,7 +31,7 @@ class Help(Handler):
|
||||
ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture"
|
||||
|
||||
@classmethod
|
||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||
def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||
report: bool, unsafe: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
|
@ -19,8 +19,6 @@
|
||||
#
|
||||
import argparse
|
||||
|
||||
from typing import Type
|
||||
|
||||
from ahriman.application.application import Application
|
||||
from ahriman.application.handlers import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
@ -34,7 +32,7 @@ class KeyImport(Handler):
|
||||
ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture"
|
||||
|
||||
@classmethod
|
||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||
def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||
report: bool, unsafe: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
|
@ -21,7 +21,6 @@ import argparse
|
||||
import sys
|
||||
|
||||
from pathlib import Path
|
||||
from typing import List, Optional, Tuple, Type
|
||||
|
||||
from ahriman.application.application import Application
|
||||
from ahriman.application.handlers import Handler
|
||||
@ -39,7 +38,7 @@ class Patch(Handler):
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||
def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||
report: bool, unsafe: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
@ -66,17 +65,17 @@ class Patch(Handler):
|
||||
Patch.patch_set_remove(application, args.package, args.variable)
|
||||
|
||||
@staticmethod
|
||||
def patch_create_from_diff(sources_dir: Path, architecture: str, track: List[str]) -> Tuple[str, PkgbuildPatch]:
|
||||
def patch_create_from_diff(sources_dir: Path, architecture: str, track: list[str]) -> tuple[str, PkgbuildPatch]:
|
||||
"""
|
||||
create PKGBUILD plain diff patches from sources directory
|
||||
|
||||
Args:
|
||||
sources_dir(Path): path to directory with the package sources
|
||||
architecture(str): repository architecture
|
||||
track(List[str]): track files which match the glob before creating the patch
|
||||
track(list[str]): track files which match the glob before creating the patch
|
||||
|
||||
Returns:
|
||||
Tuple[str, PkgbuildPatch]: package base and created PKGBUILD patch based on the diff from master HEAD
|
||||
tuple[str, PkgbuildPatch]: package base and created PKGBUILD patch based on the diff from master HEAD
|
||||
to current files
|
||||
"""
|
||||
package = Package.from_build(sources_dir, architecture)
|
||||
@ -84,13 +83,13 @@ class Patch(Handler):
|
||||
return package.base, PkgbuildPatch(None, patch)
|
||||
|
||||
@staticmethod
|
||||
def patch_create_from_function(variable: str, patch_path: Optional[Path]) -> PkgbuildPatch:
|
||||
def patch_create_from_function(variable: str, patch_path: Path | None) -> PkgbuildPatch:
|
||||
"""
|
||||
create single-function patch set for the package base
|
||||
|
||||
Args:
|
||||
variable(str): function or variable name inside PKGBUILD
|
||||
patch_path(Path): optional path to patch content. If not set, it will be read from stdin
|
||||
patch_path(Path | None): optional path to patch content. If not set, it will be read from stdin
|
||||
|
||||
Returns:
|
||||
PkgbuildPatch: created patch for the PKGBUILD function
|
||||
@ -116,15 +115,15 @@ class Patch(Handler):
|
||||
application.database.patches_insert(package_base, patch)
|
||||
|
||||
@staticmethod
|
||||
def patch_set_list(application: Application, package_base: Optional[str], variables: List[str],
|
||||
def patch_set_list(application: Application, package_base: str | None, variables: list[str],
|
||||
exit_code: bool) -> None:
|
||||
"""
|
||||
list patches available for the package base
|
||||
|
||||
Args:
|
||||
application(Application): application instance
|
||||
package_base(Optional[str]): package base
|
||||
variables(List[str]): extract patches only for specified PKGBUILD variables
|
||||
package_base(str | None): package base
|
||||
variables(list[str]): extract patches only for specified PKGBUILD variables
|
||||
exit_code(bool): exit with error on empty search result
|
||||
"""
|
||||
patches = application.database.patches_list(package_base, variables)
|
||||
@ -134,13 +133,13 @@ class Patch(Handler):
|
||||
PatchPrinter(base, patch).print(verbose=True, separator=" = ")
|
||||
|
||||
@staticmethod
|
||||
def patch_set_remove(application: Application, package_base: str, variables: List[str]) -> None:
|
||||
def patch_set_remove(application: Application, package_base: str, variables: list[str]) -> None:
|
||||
"""
|
||||
remove patch set for the package base
|
||||
|
||||
Args:
|
||||
application(Application): application instance
|
||||
package_base(str): package base
|
||||
variables(List[str]): remove patches only for specified PKGBUILD variables
|
||||
variables(list[str]): remove patches only for specified PKGBUILD variables
|
||||
"""
|
||||
application.database.patches_remove(package_base, variables)
|
||||
|
@ -19,8 +19,6 @@
|
||||
#
|
||||
import argparse
|
||||
|
||||
from typing import List, Type
|
||||
|
||||
from ahriman.application.application import Application
|
||||
from ahriman.application.handlers import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
@ -34,7 +32,7 @@ class Rebuild(Handler):
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||
def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||
report: bool, unsafe: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
@ -46,13 +44,11 @@ class Rebuild(Handler):
|
||||
report(bool): force enable or disable reporting
|
||||
unsafe(bool): if set no user check will be performed before path creation
|
||||
"""
|
||||
depends_on = set(args.depends_on) if args.depends_on else None
|
||||
|
||||
application = Application(architecture, configuration, report=report, unsafe=unsafe)
|
||||
application.on_start()
|
||||
|
||||
packages = Rebuild.extract_packages(application, from_database=args.from_database)
|
||||
updates = application.repository.packages_depend_on(packages, depends_on)
|
||||
updates = application.repository.packages_depend_on(packages, args.depends_on or None)
|
||||
|
||||
Rebuild.check_if_empty(args.exit_code, not updates)
|
||||
if args.dry_run:
|
||||
@ -64,7 +60,7 @@ class Rebuild(Handler):
|
||||
Rebuild.check_if_empty(args.exit_code, result.is_empty)
|
||||
|
||||
@staticmethod
|
||||
def extract_packages(application: Application, *, from_database: bool) -> List[Package]:
|
||||
def extract_packages(application: Application, *, from_database: bool) -> list[Package]:
|
||||
"""
|
||||
extract packages from database file
|
||||
|
||||
@ -73,7 +69,7 @@ class Rebuild(Handler):
|
||||
from_database(bool): extract packages from database instead of repository filesystem
|
||||
|
||||
Returns:
|
||||
List[Package]: list of packages which were stored in database
|
||||
list[Package]: list of packages which were stored in database
|
||||
"""
|
||||
if from_database:
|
||||
return [package for (package, _) in application.database.packages_get()]
|
||||
|
@ -19,8 +19,6 @@
|
||||
#
|
||||
import argparse
|
||||
|
||||
from typing import Type
|
||||
|
||||
from ahriman.application.application import Application
|
||||
from ahriman.application.handlers import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
@ -32,7 +30,7 @@ class Remove(Handler):
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||
def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||
report: bool, unsafe: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
|
@ -19,8 +19,6 @@
|
||||
#
|
||||
import argparse
|
||||
|
||||
from typing import Type
|
||||
|
||||
from ahriman.application.application import Application
|
||||
from ahriman.application.handlers import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
@ -33,7 +31,7 @@ class RemoveUnknown(Handler):
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||
def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||
report: bool, unsafe: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
|
@ -19,7 +19,6 @@
|
||||
#
|
||||
import argparse
|
||||
|
||||
from typing import Type
|
||||
from tarfile import TarFile
|
||||
|
||||
from ahriman.application.handlers import Handler
|
||||
@ -34,7 +33,7 @@ class Restore(Handler):
|
||||
ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture"
|
||||
|
||||
@classmethod
|
||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||
def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||
report: bool, unsafe: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
|
@ -20,7 +20,7 @@
|
||||
import argparse
|
||||
|
||||
from dataclasses import fields
|
||||
from typing import Callable, Iterable, List, Tuple, Type
|
||||
from collections.abc import Callable, Iterable
|
||||
|
||||
from ahriman.application.application import Application
|
||||
from ahriman.application.handlers import Handler
|
||||
@ -36,14 +36,14 @@ class Search(Handler):
|
||||
packages search handler
|
||||
|
||||
Attributes:
|
||||
SORT_FIELDS(Set[str]): (class attribute) allowed fields to sort the package list
|
||||
SORT_FIELDS(set[str]): (class attribute) allowed fields to sort the package list
|
||||
"""
|
||||
|
||||
ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture"
|
||||
SORT_FIELDS = {field.name for field in fields(AURPackage) if field.default_factory is not list} # type: ignore
|
||||
|
||||
@classmethod
|
||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||
def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||
report: bool, unsafe: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
@ -67,7 +67,7 @@ class Search(Handler):
|
||||
AurPrinter(package).print(verbose=args.info)
|
||||
|
||||
@staticmethod
|
||||
def sort(packages: Iterable[AURPackage], sort_by: str) -> List[AURPackage]:
|
||||
def sort(packages: Iterable[AURPackage], sort_by: str) -> list[AURPackage]:
|
||||
"""
|
||||
sort package list by specified field
|
||||
|
||||
@ -76,7 +76,7 @@ class Search(Handler):
|
||||
sort_by(str): AUR package field name to sort by
|
||||
|
||||
Returns:
|
||||
List[AURPackage]: sorted list for packages
|
||||
list[AURPackage]: sorted list for packages
|
||||
|
||||
Raises:
|
||||
InvalidOption: if search fields is not in list of allowed ones
|
||||
@ -85,6 +85,6 @@ class Search(Handler):
|
||||
raise OptionError(sort_by)
|
||||
# always sort by package name at the last
|
||||
# well technically it is not a string, but we can deal with it
|
||||
comparator: Callable[[AURPackage], Tuple[str, str]] =\
|
||||
comparator: Callable[[AURPackage], tuple[str, str]] =\
|
||||
lambda package: (getattr(package, sort_by), package.name)
|
||||
return sorted(packages, key=comparator)
|
||||
|
@ -19,8 +19,6 @@
|
||||
#
|
||||
import argparse
|
||||
|
||||
from typing import Type
|
||||
|
||||
from ahriman import version
|
||||
from ahriman.application.application import Application
|
||||
from ahriman.application.handlers import Handler
|
||||
@ -37,7 +35,7 @@ class ServiceUpdates(Handler):
|
||||
ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture"
|
||||
|
||||
@classmethod
|
||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||
def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||
report: bool, unsafe: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
|
@ -21,7 +21,6 @@ import argparse
|
||||
|
||||
from pathlib import Path
|
||||
from pwd import getpwuid
|
||||
from typing import Optional, Type
|
||||
|
||||
from ahriman.application.application import Application
|
||||
from ahriman.application.handlers import Handler
|
||||
@ -46,7 +45,7 @@ class Setup(Handler):
|
||||
SUDOERS_DIR_PATH = Path("/etc/sudoers.d")
|
||||
|
||||
@classmethod
|
||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||
def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||
report: bool, unsafe: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
@ -132,7 +131,7 @@ class Setup(Handler):
|
||||
configuration.write(ahriman_configuration)
|
||||
|
||||
@staticmethod
|
||||
def configuration_create_devtools(prefix: str, architecture: str, source: Path, mirror: Optional[str],
|
||||
def configuration_create_devtools(prefix: str, architecture: str, source: Path, mirror: str | None,
|
||||
multilib: bool, repository: str, paths: RepositoryPaths) -> None:
|
||||
"""
|
||||
create configuration for devtools based on ``source`` configuration
|
||||
@ -144,7 +143,7 @@ class Setup(Handler):
|
||||
prefix(str): command prefix in {prefix}-{architecture}-build
|
||||
architecture(str): repository architecture
|
||||
source(Path): path to source configuration file
|
||||
mirror(Optional[str]): link to package server mirror
|
||||
mirror(str | None): link to package server mirror
|
||||
multilib(bool): add or do not multilib repository to the configuration
|
||||
repository(str): repository name
|
||||
paths(RepositoryPaths): repository paths instance
|
||||
|
@ -22,7 +22,6 @@ import code
|
||||
import sys
|
||||
|
||||
from pathlib import Path
|
||||
from typing import Type
|
||||
|
||||
from ahriman.application.application import Application
|
||||
from ahriman.application.handlers import Handler
|
||||
@ -38,7 +37,7 @@ class Shell(Handler):
|
||||
ALLOW_MULTI_ARCHITECTURE_RUN = False
|
||||
|
||||
@classmethod
|
||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||
def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||
report: bool, unsafe: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
|
@ -19,8 +19,6 @@
|
||||
#
|
||||
import argparse
|
||||
|
||||
from typing import Type
|
||||
|
||||
from ahriman.application.application import Application
|
||||
from ahriman.application.handlers import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
@ -32,7 +30,7 @@ class Sign(Handler):
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||
def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||
report: bool, unsafe: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
|
@ -19,7 +19,7 @@
|
||||
#
|
||||
import argparse
|
||||
|
||||
from typing import Callable, Iterable, Tuple, Type
|
||||
from collections.abc import Callable
|
||||
|
||||
from ahriman.application.application import Application
|
||||
from ahriman.application.handlers import Handler
|
||||
@ -37,7 +37,7 @@ class Status(Handler):
|
||||
ALLOW_AUTO_ARCHITECTURE_RUN = False
|
||||
|
||||
@classmethod
|
||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||
def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||
report: bool, unsafe: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
@ -55,7 +55,7 @@ class Status(Handler):
|
||||
service_status = client.get_internal()
|
||||
StatusPrinter(service_status.status).print(verbose=args.info)
|
||||
if args.package:
|
||||
packages: Iterable[Tuple[Package, BuildStatus]] = sum(
|
||||
packages: list[tuple[Package, BuildStatus]] = sum(
|
||||
(client.get(base) for base in args.package),
|
||||
start=[])
|
||||
else:
|
||||
@ -63,8 +63,8 @@ class Status(Handler):
|
||||
|
||||
Status.check_if_empty(args.exit_code, not packages)
|
||||
|
||||
comparator: Callable[[Tuple[Package, BuildStatus]], str] = lambda item: item[0].base
|
||||
filter_fn: Callable[[Tuple[Package, BuildStatus]], bool] =\
|
||||
comparator: Callable[[tuple[Package, BuildStatus]], str] = lambda item: item[0].base
|
||||
filter_fn: Callable[[tuple[Package, BuildStatus]], bool] =\
|
||||
lambda item: args.status is None or item[1].status == args.status
|
||||
for package, package_status in sorted(filter(filter_fn, packages), key=comparator):
|
||||
PackagePrinter(package, package_status).print(verbose=args.info)
|
||||
|
@ -19,8 +19,6 @@
|
||||
#
|
||||
import argparse
|
||||
|
||||
from typing import Type
|
||||
|
||||
from ahriman.application.application import Application
|
||||
from ahriman.application.handlers import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
@ -35,7 +33,7 @@ class StatusUpdate(Handler):
|
||||
ALLOW_AUTO_ARCHITECTURE_RUN = False
|
||||
|
||||
@classmethod
|
||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||
def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||
report: bool, unsafe: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
|
@ -19,8 +19,6 @@
|
||||
#
|
||||
import argparse
|
||||
|
||||
from typing import Type
|
||||
|
||||
from ahriman.application.application import Application
|
||||
from ahriman.application.handlers import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
@ -36,7 +34,7 @@ class Structure(Handler):
|
||||
ALLOW_AUTO_ARCHITECTURE_RUN = False
|
||||
|
||||
@classmethod
|
||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||
def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||
report: bool, unsafe: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
|
@ -19,8 +19,6 @@
|
||||
#
|
||||
import argparse
|
||||
|
||||
from typing import Type
|
||||
|
||||
from ahriman.application.application import Application
|
||||
from ahriman.application.handlers import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
@ -33,7 +31,7 @@ class Triggers(Handler):
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||
def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||
report: bool, unsafe: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
|
@ -20,8 +20,6 @@
|
||||
import argparse
|
||||
import shlex
|
||||
|
||||
from typing import List, Type
|
||||
|
||||
from ahriman.application.handlers import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.formatters import StringPrinter
|
||||
@ -35,7 +33,7 @@ class UnsafeCommands(Handler):
|
||||
ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture"
|
||||
|
||||
@classmethod
|
||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||
def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||
report: bool, unsafe: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
@ -56,20 +54,20 @@ class UnsafeCommands(Handler):
|
||||
UnsafeCommands.check_unsafe(args.command, unsafe_commands, parser)
|
||||
|
||||
@staticmethod
|
||||
def check_unsafe(command: str, unsafe_commands: List[str], parser: argparse.ArgumentParser) -> None:
|
||||
def check_unsafe(command: str, unsafe_commands: list[str], parser: argparse.ArgumentParser) -> None:
|
||||
"""
|
||||
check if command is unsafe
|
||||
|
||||
Args:
|
||||
command(str): command to check
|
||||
unsafe_commands(List[str]): list of unsafe commands
|
||||
unsafe_commands(list[str]): list of unsafe commands
|
||||
parser(argparse.ArgumentParser): generated argument parser
|
||||
"""
|
||||
args = parser.parse_args(shlex.split(command))
|
||||
UnsafeCommands.check_if_empty(True, args.command in unsafe_commands)
|
||||
|
||||
@staticmethod
|
||||
def get_unsafe_commands(parser: argparse.ArgumentParser) -> List[str]:
|
||||
def get_unsafe_commands(parser: argparse.ArgumentParser) -> list[str]:
|
||||
"""
|
||||
extract unsafe commands from argument parser
|
||||
|
||||
@ -77,7 +75,7 @@ class UnsafeCommands(Handler):
|
||||
parser(argparse.ArgumentParser): generated argument parser
|
||||
|
||||
Returns:
|
||||
List[str]: list of commands with default unsafe flag
|
||||
list[str]: list of commands with default unsafe flag
|
||||
"""
|
||||
# should never fail
|
||||
# pylint: disable=protected-access
|
||||
|
@ -19,7 +19,7 @@
|
||||
#
|
||||
import argparse
|
||||
|
||||
from typing import Callable, Type
|
||||
from collections.abc import Callable
|
||||
|
||||
from ahriman.application.application import Application
|
||||
from ahriman.application.handlers import Handler
|
||||
@ -32,7 +32,7 @@ class Update(Handler):
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||
def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||
report: bool, unsafe: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
|
@ -21,7 +21,6 @@ import argparse
|
||||
import getpass
|
||||
|
||||
from pathlib import Path
|
||||
from typing import Optional, Tuple, Type
|
||||
|
||||
from ahriman.application.handlers import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
@ -40,7 +39,7 @@ class Users(Handler):
|
||||
ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture"
|
||||
|
||||
@classmethod
|
||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||
def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||
report: bool, unsafe: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
@ -119,7 +118,7 @@ class Users(Handler):
|
||||
path.chmod(0o600)
|
||||
|
||||
@staticmethod
|
||||
def get_salt(configuration: Configuration, salt_length: int = 20) -> Tuple[Optional[str], str]:
|
||||
def get_salt(configuration: Configuration, salt_length: int = 20) -> tuple[str | None, str]:
|
||||
"""
|
||||
get salt from configuration or create new string
|
||||
|
||||
@ -128,7 +127,7 @@ class Users(Handler):
|
||||
salt_length(int, optional): salt length (Default value = 20)
|
||||
|
||||
Returns:
|
||||
Tuple[Optional[str], str]: tuple containing salt from configuration if any and actual salt which must be
|
||||
tuple[str | None, str]: tuple containing salt from configuration if any and actual salt which must be
|
||||
used for password hash
|
||||
"""
|
||||
if salt := configuration.get("auth", "salt", fallback=None):
|
||||
|
@ -20,7 +20,7 @@
|
||||
import argparse
|
||||
import copy
|
||||
|
||||
from typing import Any, Dict, Type
|
||||
from typing import Any
|
||||
|
||||
from ahriman.application.handlers import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
@ -39,7 +39,7 @@ class Validate(Handler):
|
||||
ALLOW_AUTO_ARCHITECTURE_RUN = False
|
||||
|
||||
@classmethod
|
||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||
def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||
report: bool, unsafe: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
@ -112,17 +112,17 @@ class Validate(Handler):
|
||||
return schema
|
||||
|
||||
@staticmethod
|
||||
def schema_merge(source: Dict[str, Any], schema: Dict[str, Any]) -> Dict[str, Any]:
|
||||
def schema_merge(source: dict[str, Any], schema: dict[str, Any]) -> dict[str, Any]:
|
||||
"""
|
||||
merge child schema into source. In case if source already contains values, new keys will be added
|
||||
(possibly with overrides - in case if such key already set also)
|
||||
|
||||
Args:
|
||||
source(Dict[str, Any]): source (current) schema into which will be merged
|
||||
schema(Dict[str, Any]): new schema to be merged
|
||||
source(dict[str, Any]): source (current) schema into which will be merged
|
||||
schema(dict[str, Any]): new schema to be merged
|
||||
|
||||
Returns:
|
||||
Dict[str, Any]: schema with added elements from source schema if they were set before and not presented
|
||||
dict[str, Any]: schema with added elements from source schema if they were set before and not presented
|
||||
in the new one. Note, that schema will be modified in-place
|
||||
"""
|
||||
for key, value in source.items():
|
||||
|
@ -21,8 +21,6 @@ import argparse
|
||||
import pkg_resources
|
||||
import sys
|
||||
|
||||
from typing import Dict, List, Tuple, Type
|
||||
|
||||
from ahriman import version
|
||||
from ahriman.application.handlers import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
@ -37,7 +35,7 @@ class Versions(Handler):
|
||||
ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture"
|
||||
|
||||
@classmethod
|
||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||
def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||
report: bool, unsafe: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
@ -55,23 +53,23 @@ class Versions(Handler):
|
||||
VersionPrinter("Installed packages", packages).print(verbose=False, separator=" ")
|
||||
|
||||
@staticmethod
|
||||
def package_dependencies(root: str, root_extras: Tuple[str, ...] = ()) -> Dict[str, str]:
|
||||
def package_dependencies(root: str, root_extras: tuple[str, ...] = ()) -> dict[str, str]:
|
||||
"""
|
||||
extract list of ahriman package dependencies installed into system with their versions
|
||||
|
||||
Args:
|
||||
root(str): root package name
|
||||
root_extras(Tuple[str, ...], optional): extras for the root package (Default value = ())
|
||||
root_extras(tuple[str, ...], optional): extras for the root package (Default value = ())
|
||||
|
||||
Returns:
|
||||
Dict[str, str]: map of installed dependency to its version
|
||||
dict[str, str]: map of installed dependency to its version
|
||||
"""
|
||||
resources: Dict[str, pkg_resources.Distribution] = pkg_resources.working_set.by_key # type: ignore
|
||||
resources: dict[str, pkg_resources.Distribution] = pkg_resources.working_set.by_key # type: ignore
|
||||
|
||||
def dependencies_by_key(key: str, extras: Tuple[str, ...] = ()) -> List[str]:
|
||||
def dependencies_by_key(key: str, extras: tuple[str, ...] = ()) -> list[str]:
|
||||
return [entry.key for entry in resources[key].requires(extras)]
|
||||
|
||||
keys: List[str] = []
|
||||
keys: list[str] = []
|
||||
portion = {key for key in dependencies_by_key(root, root_extras) if key in resources}
|
||||
while portion:
|
||||
keys.extend(portion)
|
||||
|
@ -19,8 +19,6 @@
|
||||
#
|
||||
import argparse
|
||||
|
||||
from typing import Type
|
||||
|
||||
from ahriman.application.handlers import Handler
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.spawn import Spawn
|
||||
@ -35,7 +33,7 @@ class Web(Handler):
|
||||
ALLOW_MULTI_ARCHITECTURE_RUN = False # required to be able to spawn external processes
|
||||
|
||||
@classmethod
|
||||
def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||
def run(cls: type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration, *,
|
||||
report: bool, unsafe: bool) -> None:
|
||||
"""
|
||||
callback for command line
|
||||
|
@ -22,7 +22,7 @@ from __future__ import annotations
|
||||
import argparse
|
||||
|
||||
from types import TracebackType
|
||||
from typing import Literal, Optional, Type
|
||||
from typing import Literal
|
||||
|
||||
from ahriman import version
|
||||
from ahriman.core.configuration import Configuration
|
||||
@ -127,14 +127,14 @@ class Lock(LazyLogging):
|
||||
self.reporter.update_self(BuildStatusEnum.Building)
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type: Optional[Type[Exception]], exc_val: Optional[Exception],
|
||||
def __exit__(self, exc_type: type[Exception] | None, exc_val: Exception | None,
|
||||
exc_tb: TracebackType) -> Literal[False]:
|
||||
"""
|
||||
remove lock file when done
|
||||
|
||||
Args:
|
||||
exc_type(Optional[Type[Exception]]): exception type name if any
|
||||
exc_val(Optional[Exception]): exception raised if any
|
||||
exc_type(type[Exception] | None): exception type name if any
|
||||
exc_val(Exception | None): exception raised if any
|
||||
exc_tb(TracebackType): exception traceback if any
|
||||
|
||||
Returns:
|
||||
|
@ -17,8 +17,9 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
from collections.abc import Iterator
|
||||
from contextvars import ContextVar
|
||||
from typing import Any, Dict, Iterator, TypeVar
|
||||
from typing import Any, TypeVar
|
||||
|
||||
from ahriman.models.context_key import ContextKey
|
||||
|
||||
@ -35,7 +36,7 @@ class _Context:
|
||||
"""
|
||||
default constructor. Must not be used directly
|
||||
"""
|
||||
self._content: Dict[str, Any] = {}
|
||||
self._content: dict[str, Any] = {}
|
||||
|
||||
def get(self, key: ContextKey[T]) -> T:
|
||||
"""
|
||||
|
@ -19,9 +19,10 @@
|
||||
#
|
||||
import shutil
|
||||
|
||||
from collections.abc import Callable, Generator
|
||||
from pathlib import Path
|
||||
from pyalpm import DB, Handle, Package, SIG_PACKAGE, error as PyalpmError # type: ignore
|
||||
from typing import Any, Callable, Generator, Set
|
||||
from typing import Any
|
||||
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.log import LazyLogging
|
||||
@ -166,14 +167,14 @@ class Pacman(LazyLogging):
|
||||
continue
|
||||
yield package
|
||||
|
||||
def packages(self) -> Set[str]:
|
||||
def packages(self) -> set[str]:
|
||||
"""
|
||||
get list of packages known for alpm
|
||||
|
||||
Returns:
|
||||
Set[str]: list of package names
|
||||
set[str]: list of package names
|
||||
"""
|
||||
result: Set[str] = set()
|
||||
result: set[str] = set()
|
||||
for database in self.handle.get_syncdbs():
|
||||
for package in database.pkgcache:
|
||||
# package itself
|
||||
|
@ -19,7 +19,7 @@
|
||||
#
|
||||
import requests
|
||||
|
||||
from typing import Any, Dict, List, Type
|
||||
from typing import Any
|
||||
|
||||
from ahriman.core.alpm.pacman import Pacman
|
||||
from ahriman.core.alpm.remote import Remote
|
||||
@ -45,15 +45,15 @@ class AUR(Remote):
|
||||
DEFAULT_TIMEOUT = 30
|
||||
|
||||
@staticmethod
|
||||
def parse_response(response: Dict[str, Any]) -> List[AURPackage]:
|
||||
def parse_response(response: dict[str, Any]) -> list[AURPackage]:
|
||||
"""
|
||||
parse RPC response to package list
|
||||
|
||||
Args:
|
||||
response(Dict[str, Any]): RPC response json
|
||||
response(dict[str, Any]): RPC response json
|
||||
|
||||
Returns:
|
||||
List[AURPackage]: list of parsed packages
|
||||
list[AURPackage]: list of parsed packages
|
||||
|
||||
Raises:
|
||||
InvalidPackageInfo: for error API response
|
||||
@ -65,7 +65,7 @@ class AUR(Remote):
|
||||
return [AURPackage.from_json(package) for package in response["results"]]
|
||||
|
||||
@classmethod
|
||||
def remote_git_url(cls: Type[Remote], package_base: str, repository: str) -> str:
|
||||
def remote_git_url(cls: type[Remote], package_base: str, repository: str) -> str:
|
||||
"""
|
||||
generate remote git url from the package base
|
||||
|
||||
@ -79,7 +79,7 @@ class AUR(Remote):
|
||||
return f"{AUR.DEFAULT_AUR_URL}/{package_base}.git"
|
||||
|
||||
@classmethod
|
||||
def remote_web_url(cls: Type[Remote], package_base: str) -> str:
|
||||
def remote_web_url(cls: type[Remote], package_base: str) -> str:
|
||||
"""
|
||||
generate remote web url from the package base
|
||||
|
||||
@ -91,7 +91,7 @@ class AUR(Remote):
|
||||
"""
|
||||
return f"{AUR.DEFAULT_AUR_URL}/packages/{package_base}"
|
||||
|
||||
def make_request(self, request_type: str, *args: str, **kwargs: str) -> List[AURPackage]:
|
||||
def make_request(self, request_type: str, *args: str, **kwargs: str) -> list[AURPackage]:
|
||||
"""
|
||||
perform request to AUR RPC
|
||||
|
||||
@ -101,9 +101,9 @@ class AUR(Remote):
|
||||
**kwargs(str): list of additional named parameters like by
|
||||
|
||||
Returns:
|
||||
List[AURPackage]: response parsed to package list
|
||||
list[AURPackage]: response parsed to package list
|
||||
"""
|
||||
query: Dict[str, Any] = {
|
||||
query: dict[str, Any] = {
|
||||
"type": request_type,
|
||||
"v": self.DEFAULT_RPC_VERSION
|
||||
}
|
||||
@ -145,7 +145,7 @@ class AUR(Remote):
|
||||
except StopIteration:
|
||||
raise UnknownPackageError(package_name)
|
||||
|
||||
def package_search(self, *keywords: str, pacman: Pacman) -> List[AURPackage]:
|
||||
def package_search(self, *keywords: str, pacman: Pacman) -> list[AURPackage]:
|
||||
"""
|
||||
search package in AUR web
|
||||
|
||||
@ -154,6 +154,6 @@ class AUR(Remote):
|
||||
pacman(Pacman): alpm wrapper instance
|
||||
|
||||
Returns:
|
||||
List[AURPackage]: list of packages which match the criteria
|
||||
list[AURPackage]: list of packages which match the criteria
|
||||
"""
|
||||
return self.make_request("search", *keywords, by="name-desc")
|
||||
|
@ -19,7 +19,7 @@
|
||||
#
|
||||
import requests
|
||||
|
||||
from typing import Any, Dict, List, Type
|
||||
from typing import Any
|
||||
|
||||
from ahriman.core.alpm.pacman import Pacman
|
||||
from ahriman.core.alpm.remote import Remote
|
||||
@ -34,7 +34,7 @@ class Official(Remote):
|
||||
|
||||
Attributes:
|
||||
DEFAULT_ARCHLINUX_URL(str): (class attribute) default archlinux url
|
||||
DEFAULT_SEARCH_REPOSITORIES(List[str]): (class attribute) default list of repositories to search
|
||||
DEFAULT_SEARCH_REPOSITORIES(list[str]): (class attribute) default list of repositories to search
|
||||
DEFAULT_RPC_URL(str): (class attribute) default archlinux repositories RPC url
|
||||
DEFAULT_TIMEOUT(int): (class attribute) HTTP request timeout in seconds
|
||||
"""
|
||||
@ -45,15 +45,15 @@ class Official(Remote):
|
||||
DEFAULT_TIMEOUT = 30
|
||||
|
||||
@staticmethod
|
||||
def parse_response(response: Dict[str, Any]) -> List[AURPackage]:
|
||||
def parse_response(response: dict[str, Any]) -> list[AURPackage]:
|
||||
"""
|
||||
parse RPC response to package list
|
||||
|
||||
Args:
|
||||
response(Dict[str, Any]): RPC response json
|
||||
response(dict[str, Any]): RPC response json
|
||||
|
||||
Returns:
|
||||
List[AURPackage]: list of parsed packages
|
||||
list[AURPackage]: list of parsed packages
|
||||
|
||||
Raises:
|
||||
InvalidPackageInfo: for error API response
|
||||
@ -63,7 +63,7 @@ class Official(Remote):
|
||||
return [AURPackage.from_repo(package) for package in response["results"]]
|
||||
|
||||
@classmethod
|
||||
def remote_git_url(cls: Type[Remote], package_base: str, repository: str) -> str:
|
||||
def remote_git_url(cls: type[Remote], package_base: str, repository: str) -> str:
|
||||
"""
|
||||
generate remote git url from the package base
|
||||
|
||||
@ -79,7 +79,7 @@ class Official(Remote):
|
||||
return "https://github.com/archlinux/svntogit-community.git"
|
||||
|
||||
@classmethod
|
||||
def remote_web_url(cls: Type[Remote], package_base: str) -> str:
|
||||
def remote_web_url(cls: type[Remote], package_base: str) -> str:
|
||||
"""
|
||||
generate remote web url from the package base
|
||||
|
||||
@ -91,7 +91,7 @@ class Official(Remote):
|
||||
"""
|
||||
return f"{Official.DEFAULT_ARCHLINUX_URL}/packages/{package_base}"
|
||||
|
||||
def make_request(self, *args: str, by: str) -> List[AURPackage]:
|
||||
def make_request(self, *args: str, by: str) -> list[AURPackage]:
|
||||
"""
|
||||
perform request to official repositories RPC
|
||||
|
||||
@ -100,7 +100,7 @@ class Official(Remote):
|
||||
by(str): search by the field
|
||||
|
||||
Returns:
|
||||
List[AURPackage]: response parsed to package list
|
||||
list[AURPackage]: response parsed to package list
|
||||
"""
|
||||
try:
|
||||
response = requests.get(
|
||||
@ -133,7 +133,7 @@ class Official(Remote):
|
||||
except StopIteration:
|
||||
raise UnknownPackageError(package_name)
|
||||
|
||||
def package_search(self, *keywords: str, pacman: Pacman) -> List[AURPackage]:
|
||||
def package_search(self, *keywords: str, pacman: Pacman) -> list[AURPackage]:
|
||||
"""
|
||||
search package in AUR web
|
||||
|
||||
@ -142,6 +142,6 @@ class Official(Remote):
|
||||
pacman(Pacman): alpm wrapper instance
|
||||
|
||||
Returns:
|
||||
List[AURPackage]: list of packages which match the criteria
|
||||
list[AURPackage]: list of packages which match the criteria
|
||||
"""
|
||||
return self.make_request(*keywords, by="q")
|
||||
|
@ -19,8 +19,6 @@
|
||||
#
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Dict, List, Type
|
||||
|
||||
from ahriman.core.alpm.pacman import Pacman
|
||||
from ahriman.core.log import LazyLogging
|
||||
from ahriman.models.aur_package import AURPackage
|
||||
@ -44,7 +42,7 @@ class Remote(LazyLogging):
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def info(cls: Type[Remote], package_name: str, *, pacman: Pacman) -> AURPackage:
|
||||
def info(cls: type[Remote], package_name: str, *, pacman: Pacman) -> AURPackage:
|
||||
"""
|
||||
get package info by its name
|
||||
|
||||
@ -58,7 +56,7 @@ class Remote(LazyLogging):
|
||||
return cls().package_info(package_name, pacman=pacman)
|
||||
|
||||
@classmethod
|
||||
def multisearch(cls: Type[Remote], *keywords: str, pacman: Pacman) -> List[AURPackage]:
|
||||
def multisearch(cls: type[Remote], *keywords: str, pacman: Pacman) -> list[AURPackage]:
|
||||
"""
|
||||
search in remote repository by using API with multiple words. This method is required in order to handle
|
||||
https://bugs.archlinux.org/task/49133. In addition, short words will be dropped
|
||||
@ -68,10 +66,10 @@ class Remote(LazyLogging):
|
||||
pacman(Pacman): alpm wrapper instance
|
||||
|
||||
Returns:
|
||||
List[AURPackage]: list of packages each of them matches all search terms
|
||||
list[AURPackage]: list of packages each of them matches all search terms
|
||||
"""
|
||||
instance = cls()
|
||||
packages: Dict[str, AURPackage] = {}
|
||||
packages: dict[str, AURPackage] = {}
|
||||
for term in filter(lambda word: len(word) >= 3, keywords):
|
||||
portion = instance.search(term, pacman=pacman)
|
||||
packages = {
|
||||
@ -82,7 +80,7 @@ class Remote(LazyLogging):
|
||||
return list(packages.values())
|
||||
|
||||
@classmethod
|
||||
def remote_git_url(cls: Type[Remote], package_base: str, repository: str) -> str:
|
||||
def remote_git_url(cls: type[Remote], package_base: str, repository: str) -> str:
|
||||
"""
|
||||
generate remote git url from the package base
|
||||
|
||||
@ -99,7 +97,7 @@ class Remote(LazyLogging):
|
||||
raise NotImplementedError
|
||||
|
||||
@classmethod
|
||||
def remote_web_url(cls: Type[Remote], package_base: str) -> str:
|
||||
def remote_web_url(cls: type[Remote], package_base: str) -> str:
|
||||
"""
|
||||
generate remote web url from the package base
|
||||
|
||||
@ -115,7 +113,7 @@ class Remote(LazyLogging):
|
||||
raise NotImplementedError
|
||||
|
||||
@classmethod
|
||||
def search(cls: Type[Remote], *keywords: str, pacman: Pacman) -> List[AURPackage]:
|
||||
def search(cls: type[Remote], *keywords: str, pacman: Pacman) -> list[AURPackage]:
|
||||
"""
|
||||
search package in AUR web
|
||||
|
||||
@ -124,7 +122,7 @@ class Remote(LazyLogging):
|
||||
pacman(Pacman): alpm wrapper instance
|
||||
|
||||
Returns:
|
||||
List[AURPackage]: list of packages which match the criteria
|
||||
list[AURPackage]: list of packages which match the criteria
|
||||
"""
|
||||
return cls().package_search(*keywords, pacman=pacman)
|
||||
|
||||
@ -144,7 +142,7 @@ class Remote(LazyLogging):
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def package_search(self, *keywords: str, pacman: Pacman) -> List[AURPackage]:
|
||||
def package_search(self, *keywords: str, pacman: Pacman) -> list[AURPackage]:
|
||||
"""
|
||||
search package in AUR web
|
||||
|
||||
@ -153,7 +151,7 @@ class Remote(LazyLogging):
|
||||
pacman(Pacman): alpm wrapper instance
|
||||
|
||||
Returns:
|
||||
List[AURPackage]: list of packages which match the criteria
|
||||
list[AURPackage]: list of packages which match the criteria
|
||||
|
||||
Raises:
|
||||
NotImplementedError: not implemented method
|
||||
|
@ -18,7 +18,6 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
from pathlib import Path
|
||||
from typing import List
|
||||
|
||||
from ahriman.core.exceptions import BuildError
|
||||
from ahriman.core.log import LazyLogging
|
||||
@ -33,20 +32,20 @@ class Repo(LazyLogging):
|
||||
Attributes:
|
||||
name(str): repository name
|
||||
paths(RepositoryPaths): repository paths instance
|
||||
sign_args(List[str]): additional args which have to be used to sign repository archive
|
||||
sign_args(list[str]): additional args which have to be used to sign repository archive
|
||||
uid(int): uid of the repository owner user
|
||||
"""
|
||||
|
||||
_check_output = check_output
|
||||
|
||||
def __init__(self, name: str, paths: RepositoryPaths, sign_args: List[str]) -> None:
|
||||
def __init__(self, name: str, paths: RepositoryPaths, sign_args: list[str]) -> None:
|
||||
"""
|
||||
default constructor
|
||||
|
||||
Args:
|
||||
name(str): repository name
|
||||
paths(RepositoryPaths): repository paths instance
|
||||
sign_args(List[str]): additional args which have to be used to sign repository archive
|
||||
sign_args(list[str]): additional args which have to be used to sign repository archive
|
||||
"""
|
||||
self.name = name
|
||||
self.paths = paths
|
||||
|
@ -19,8 +19,6 @@
|
||||
#
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Optional, Type
|
||||
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.database import SQLite
|
||||
from ahriman.core.log import LazyLogging
|
||||
@ -65,7 +63,7 @@ class Auth(LazyLogging):
|
||||
return """<button type="button" class="btn btn-link" data-bs-toggle="modal" data-bs-target="#login-modal" style="text-decoration: none"><i class="bi bi-box-arrow-in-right"></i> login</button>"""
|
||||
|
||||
@classmethod
|
||||
def load(cls: Type[Auth], configuration: Configuration, database: SQLite) -> Auth:
|
||||
def load(cls: type[Auth], configuration: Configuration, database: SQLite) -> Auth:
|
||||
"""
|
||||
load authorization module from settings
|
||||
|
||||
@ -85,13 +83,13 @@ class Auth(LazyLogging):
|
||||
return OAuth(configuration, database)
|
||||
return cls(configuration)
|
||||
|
||||
async def check_credentials(self, username: Optional[str], password: Optional[str]) -> bool:
|
||||
async def check_credentials(self, username: str | None, password: str | None) -> bool:
|
||||
"""
|
||||
validate user password
|
||||
|
||||
Args:
|
||||
username(Optional[str]): username
|
||||
password(Optional[str]): entered password
|
||||
username(str | None): username
|
||||
password(str | None): entered password
|
||||
|
||||
Returns:
|
||||
bool: True in case if password matches, False otherwise
|
||||
@ -99,12 +97,12 @@ class Auth(LazyLogging):
|
||||
del username, password
|
||||
return True
|
||||
|
||||
async def known_username(self, username: Optional[str]) -> bool:
|
||||
async def known_username(self, username: str | None) -> bool:
|
||||
"""
|
||||
check if user is known
|
||||
|
||||
Args:
|
||||
username(Optional[str]): username
|
||||
username(str | None): username
|
||||
|
||||
Returns:
|
||||
bool: True in case if user is known and can be authorized and False otherwise
|
||||
@ -112,14 +110,14 @@ class Auth(LazyLogging):
|
||||
del username
|
||||
return True
|
||||
|
||||
async def verify_access(self, username: str, required: UserAccess, context: Optional[str]) -> bool:
|
||||
async def verify_access(self, username: str, required: UserAccess, context: str | None) -> bool:
|
||||
"""
|
||||
validate if user has access to requested resource
|
||||
|
||||
Args:
|
||||
username(str): username
|
||||
required(UserAccess): required access level
|
||||
context(Optional[str]): URI request path
|
||||
context(str | None): URI request path
|
||||
|
||||
Returns:
|
||||
bool: True in case if user is allowed to do this request and False otherwise
|
||||
|
@ -17,8 +17,6 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
from typing import Optional
|
||||
|
||||
from ahriman.core.auth import Auth
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.database import SQLite
|
||||
@ -50,13 +48,13 @@ class Mapping(Auth):
|
||||
self.database = database
|
||||
self.salt = configuration.get("auth", "salt")
|
||||
|
||||
async def check_credentials(self, username: Optional[str], password: Optional[str]) -> bool:
|
||||
async def check_credentials(self, username: str | None, password: str | None) -> bool:
|
||||
"""
|
||||
validate user password
|
||||
|
||||
Args:
|
||||
username(Optional[str]): username
|
||||
password(Optional[str]): entered password
|
||||
username(str | None): username
|
||||
password(str | None): entered password
|
||||
|
||||
Returns:
|
||||
bool: True in case if password matches, False otherwise
|
||||
@ -66,7 +64,7 @@ class Mapping(Auth):
|
||||
user = self.get_user(username)
|
||||
return user is not None and user.check_credentials(password, self.salt)
|
||||
|
||||
def get_user(self, username: str) -> Optional[User]:
|
||||
def get_user(self, username: str) -> User | None:
|
||||
"""
|
||||
retrieve user from in-memory mapping
|
||||
|
||||
@ -74,30 +72,30 @@ class Mapping(Auth):
|
||||
username(str): username
|
||||
|
||||
Returns:
|
||||
Optional[User]: user descriptor if username is known and None otherwise
|
||||
User | None: user descriptor if username is known and None otherwise
|
||||
"""
|
||||
return self.database.user_get(username)
|
||||
|
||||
async def known_username(self, username: Optional[str]) -> bool:
|
||||
async def known_username(self, username: str | None) -> bool:
|
||||
"""
|
||||
check if user is known
|
||||
|
||||
Args:
|
||||
username(Optional[str]): username
|
||||
username(str | None): username
|
||||
|
||||
Returns:
|
||||
bool: True in case if user is known and can be authorized and False otherwise
|
||||
"""
|
||||
return username is not None and self.get_user(username) is not None
|
||||
|
||||
async def verify_access(self, username: str, required: UserAccess, context: Optional[str]) -> bool:
|
||||
async def verify_access(self, username: str, required: UserAccess, context: str | None) -> bool:
|
||||
"""
|
||||
validate if user has access to requested resource
|
||||
|
||||
Args:
|
||||
username(str): username
|
||||
required(UserAccess): required access level
|
||||
context(Optional[str]): URI request path
|
||||
context(str | None): URI request path
|
||||
|
||||
Returns:
|
||||
bool: True in case if user is allowed to do this request and False otherwise
|
||||
|
@ -19,8 +19,6 @@
|
||||
#
|
||||
import aioauth_client
|
||||
|
||||
from typing import Optional, Type
|
||||
|
||||
from ahriman.core.auth.mapping import Mapping
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.database import SQLite
|
||||
@ -72,7 +70,7 @@ class OAuth(Mapping):
|
||||
return """<a class="nav-link" href="/api/v1/login" title="login via OAuth2"><i class="bi bi-google"></i> login</a>"""
|
||||
|
||||
@staticmethod
|
||||
def get_provider(name: str) -> Type[aioauth_client.OAuth2Client]:
|
||||
def get_provider(name: str) -> type[aioauth_client.OAuth2Client]:
|
||||
"""
|
||||
load OAuth2 provider by name
|
||||
|
||||
@ -80,12 +78,12 @@ class OAuth(Mapping):
|
||||
name(str): name of the provider. Must be valid class defined in aioauth-client library
|
||||
|
||||
Returns:
|
||||
Type[aioauth_client.OAuth2Client]: loaded provider type
|
||||
type[aioauth_client.OAuth2Client]: loaded provider type
|
||||
|
||||
Raises:
|
||||
InvalidOption: in case if invalid OAuth provider name supplied
|
||||
"""
|
||||
provider: Type[aioauth_client.OAuth2Client] = getattr(aioauth_client, name)
|
||||
provider: type[aioauth_client.OAuth2Client] = getattr(aioauth_client, name)
|
||||
try:
|
||||
is_oauth2_client = issubclass(provider, aioauth_client.OAuth2Client)
|
||||
except TypeError: # what if it is random string?
|
||||
@ -114,7 +112,7 @@ class OAuth(Mapping):
|
||||
uri: str = client.get_authorize_url(scope=self.scopes, redirect_uri=self.redirect_uri)
|
||||
return uri
|
||||
|
||||
async def get_oauth_username(self, code: str) -> Optional[str]:
|
||||
async def get_oauth_username(self, code: str) -> str | None:
|
||||
"""
|
||||
extract OAuth username from remote
|
||||
|
||||
@ -122,7 +120,7 @@ class OAuth(Mapping):
|
||||
code(str): authorization code provided by external service
|
||||
|
||||
Returns:
|
||||
Optional[str]: username as is in OAuth provider
|
||||
str | None: username as is in OAuth provider
|
||||
"""
|
||||
try:
|
||||
client = self.get_client()
|
||||
|
@ -20,7 +20,6 @@
|
||||
import shutil
|
||||
|
||||
from pathlib import Path
|
||||
from typing import List, Optional
|
||||
|
||||
from ahriman.core.log import LazyLogging
|
||||
from ahriman.core.util import check_output, utcnow, walk
|
||||
@ -44,7 +43,7 @@ class Sources(LazyLogging):
|
||||
_check_output = check_output
|
||||
|
||||
@staticmethod
|
||||
def extend_architectures(sources_dir: Path, architecture: str) -> List[PkgbuildPatch]:
|
||||
def extend_architectures(sources_dir: Path, architecture: str) -> list[PkgbuildPatch]:
|
||||
"""
|
||||
extend existing PKGBUILD with repository architecture
|
||||
|
||||
@ -53,7 +52,7 @@ class Sources(LazyLogging):
|
||||
architecture(str): repository architecture
|
||||
|
||||
Returns:
|
||||
List[PkgbuildPatch]: generated patch for PKGBUILD architectures if required
|
||||
list[PkgbuildPatch]: generated patch for PKGBUILD architectures if required
|
||||
"""
|
||||
architectures = Package.supported_architectures(sources_dir)
|
||||
if "any" in architectures: # makepkg does not like when there is any other arch except for any
|
||||
@ -62,13 +61,13 @@ class Sources(LazyLogging):
|
||||
return [PkgbuildPatch("arch", list(architectures))]
|
||||
|
||||
@staticmethod
|
||||
def fetch(sources_dir: Path, remote: Optional[RemoteSource]) -> None:
|
||||
def fetch(sources_dir: Path, remote: RemoteSource | None) -> None:
|
||||
"""
|
||||
either clone repository or update it to origin/``remote.branch``
|
||||
|
||||
Args:
|
||||
sources_dir(Path): local path to fetch
|
||||
remote(Optional[RemoteSource]): remote target (from where to fetch)
|
||||
remote(RemoteSource | None): remote target (from where to fetch)
|
||||
"""
|
||||
instance = Sources()
|
||||
# local directory exists and there is .git directory
|
||||
@ -127,14 +126,14 @@ class Sources(LazyLogging):
|
||||
cwd=sources_dir, logger=instance.logger)
|
||||
|
||||
@staticmethod
|
||||
def load(sources_dir: Path, package: Package, patches: List[PkgbuildPatch], paths: RepositoryPaths) -> None:
|
||||
def load(sources_dir: Path, package: Package, patches: list[PkgbuildPatch], paths: RepositoryPaths) -> None:
|
||||
"""
|
||||
fetch sources from remote and apply patches
|
||||
|
||||
Args:
|
||||
sources_dir(Path): local path to fetch
|
||||
package(Package): package definitions
|
||||
patches(List[PkgbuildPatch]): optional patch to be applied
|
||||
patches(list[PkgbuildPatch]): optional patch to be applied
|
||||
paths(RepositoryPaths): repository paths instance
|
||||
"""
|
||||
instance = Sources()
|
||||
@ -165,7 +164,7 @@ class Sources(LazyLogging):
|
||||
return f"{diff}\n" # otherwise, patch will be broken
|
||||
|
||||
@staticmethod
|
||||
def push(sources_dir: Path, remote: RemoteSource, *pattern: str, commit_author: Optional[str] = None) -> None:
|
||||
def push(sources_dir: Path, remote: RemoteSource, *pattern: str, commit_author: str | None = None) -> None:
|
||||
"""
|
||||
commit selected changes and push files to the remote repository
|
||||
|
||||
@ -173,7 +172,7 @@ class Sources(LazyLogging):
|
||||
sources_dir(Path): local path to git repository
|
||||
remote(RemoteSource): remote target, branch and url
|
||||
*pattern(str): glob patterns
|
||||
commit_author(Optional[str], optional): commit author in form of git config (i.e. ``user <user@host>``)
|
||||
commit_author(str | None, optional): commit author in form of git config (i.e. ``user <user@host>``)
|
||||
(Default value = None)
|
||||
"""
|
||||
instance = Sources()
|
||||
@ -192,7 +191,7 @@ class Sources(LazyLogging):
|
||||
--intent-to-add git flag (Default value = False)
|
||||
"""
|
||||
# glob directory to find files which match the specified patterns
|
||||
found_files: List[Path] = []
|
||||
found_files: list[Path] = []
|
||||
for glob in pattern:
|
||||
found_files.extend(sources_dir.glob(glob))
|
||||
if not found_files:
|
||||
@ -203,15 +202,15 @@ class Sources(LazyLogging):
|
||||
Sources._check_output("git", "add", *args, *[str(fn.relative_to(sources_dir)) for fn in found_files],
|
||||
cwd=sources_dir, logger=self.logger)
|
||||
|
||||
def commit(self, sources_dir: Path, message: Optional[str] = None, author: Optional[str] = None) -> None:
|
||||
def commit(self, sources_dir: Path, message: str | None = None, author: str | None = None) -> None:
|
||||
"""
|
||||
commit changes
|
||||
|
||||
Args:
|
||||
sources_dir(Path): local path to git repository
|
||||
message(Optional[str], optional): optional commit message if any. If none set, message will be generated
|
||||
message(str | None, optional): optional commit message if any. If none set, message will be generated
|
||||
according to the current timestamp (Default value = None)
|
||||
author(Optional[str], optional): optional commit author if any (Default value = None)
|
||||
author(str | None, optional): optional commit author if any (Default value = None)
|
||||
"""
|
||||
if message is None:
|
||||
message = f"Autogenerated commit at {utcnow()}"
|
||||
|
@ -18,7 +18,6 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
from pathlib import Path
|
||||
from typing import List
|
||||
|
||||
from ahriman.core.build_tools.sources import Sources
|
||||
from ahriman.core.configuration import Configuration
|
||||
@ -60,7 +59,7 @@ class Task(LazyLogging):
|
||||
self.makepkg_flags = configuration.getlist("build", "makepkg_flags", fallback=[])
|
||||
self.makechrootpkg_flags = configuration.getlist("build", "makechrootpkg_flags", fallback=[])
|
||||
|
||||
def build(self, sources_dir: Path) -> List[Path]:
|
||||
def build(self, sources_dir: Path) -> list[Path]:
|
||||
"""
|
||||
run package build
|
||||
|
||||
@ -68,7 +67,7 @@ class Task(LazyLogging):
|
||||
sources_dir(Path): path to where sources are
|
||||
|
||||
Returns:
|
||||
List[Path]: paths of produced packages
|
||||
list[Path]: paths of produced packages
|
||||
"""
|
||||
command = [self.build_command, "-r", str(self.paths.chroot)]
|
||||
command.extend(self.archbuild_flags)
|
||||
|
@ -23,8 +23,9 @@ import configparser
|
||||
import shlex
|
||||
import sys
|
||||
|
||||
from collections.abc import Callable
|
||||
from pathlib import Path
|
||||
from typing import Any, Callable, Dict, List, Optional, Tuple, Type
|
||||
from typing import Any
|
||||
|
||||
from ahriman.core.exceptions import InitializeError
|
||||
from ahriman.models.repository_paths import RepositoryPaths
|
||||
@ -35,11 +36,11 @@ class Configuration(configparser.RawConfigParser):
|
||||
extension for built-in configuration parser
|
||||
|
||||
Attributes:
|
||||
ARCHITECTURE_SPECIFIC_SECTIONS(List[str]): (class attribute) known sections which can be architecture specific.
|
||||
ARCHITECTURE_SPECIFIC_SECTIONS(list[str]): (class attribute) known sections which can be architecture specific.
|
||||
Required by dump and merging functions
|
||||
SYSTEM_CONFIGURATION_PATH(Path): (class attribute) default system configuration path distributed by package
|
||||
architecture(Optional[str]): repository architecture
|
||||
path(Optional[Path]): path to root configuration file
|
||||
architecture(str | None): repository architecture
|
||||
path(Path | None): path to root configuration file
|
||||
|
||||
Examples:
|
||||
Configuration class provides additional method in order to handle application configuration. Since this class is
|
||||
@ -63,7 +64,7 @@ class Configuration(configparser.RawConfigParser):
|
||||
|
||||
ARCHITECTURE_SPECIFIC_SECTIONS = ["alpm", "build", "sign", "web"]
|
||||
SYSTEM_CONFIGURATION_PATH = Path(sys.prefix) / "share" / "ahriman" / "settings" / "ahriman.ini"
|
||||
converters: Dict[str, Callable[[str], Any]] # typing guard
|
||||
converters: dict[str, Callable[[str], Any]] # typing guard
|
||||
|
||||
def __init__(self, allow_no_value: bool = False) -> None:
|
||||
"""
|
||||
@ -77,8 +78,8 @@ class Configuration(configparser.RawConfigParser):
|
||||
"list": shlex.split,
|
||||
"path": self._convert_path,
|
||||
})
|
||||
self.architecture: Optional[str] = None
|
||||
self.path: Optional[Path] = None
|
||||
self.architecture: str | None = None
|
||||
self.path: Path | None = None
|
||||
|
||||
@property
|
||||
def include(self) -> Path:
|
||||
@ -112,7 +113,7 @@ class Configuration(configparser.RawConfigParser):
|
||||
return RepositoryPaths(self.getpath("repository", "root"), architecture)
|
||||
|
||||
@classmethod
|
||||
def from_path(cls: Type[Configuration], path: Path, architecture: str) -> Configuration:
|
||||
def from_path(cls: type[Configuration], path: Path, architecture: str) -> Configuration:
|
||||
"""
|
||||
constructor with full object initialization
|
||||
|
||||
@ -157,12 +158,12 @@ class Configuration(configparser.RawConfigParser):
|
||||
return path
|
||||
return self.path.parent / path
|
||||
|
||||
def check_loaded(self) -> Tuple[Path, str]:
|
||||
def check_loaded(self) -> tuple[Path, str]:
|
||||
"""
|
||||
check if service was actually loaded
|
||||
|
||||
Returns:
|
||||
Tuple[Path, str]: configuration root path and architecture if loaded
|
||||
tuple[Path, str]: configuration root path and architecture if loaded
|
||||
|
||||
Raises:
|
||||
InitializeError: in case if architecture and/or path are not set
|
||||
@ -171,12 +172,12 @@ class Configuration(configparser.RawConfigParser):
|
||||
raise InitializeError("Configuration path and/or architecture are not set")
|
||||
return self.path, self.architecture
|
||||
|
||||
def dump(self) -> Dict[str, Dict[str, str]]:
|
||||
def dump(self) -> dict[str, dict[str, str]]:
|
||||
"""
|
||||
dump configuration to dictionary
|
||||
|
||||
Returns:
|
||||
Dict[str, Dict[str, str]]: configuration dump for specific architecture
|
||||
dict[str, dict[str, str]]: configuration dump for specific architecture
|
||||
"""
|
||||
return {
|
||||
section: dict(self[section])
|
||||
@ -185,11 +186,11 @@ class Configuration(configparser.RawConfigParser):
|
||||
|
||||
# pylint and mypy are too stupid to find these methods
|
||||
# pylint: disable=missing-function-docstring,multiple-statements,unused-argument
|
||||
def getlist(self, *args: Any, **kwargs: Any) -> List[str]: ... # type: ignore
|
||||
def getlist(self, *args: Any, **kwargs: Any) -> list[str]: ... # type: ignore
|
||||
|
||||
def getpath(self, *args: Any, **kwargs: Any) -> Path: ... # type: ignore
|
||||
|
||||
def gettype(self, section: str, architecture: str, *, fallback: Optional[str] = None) -> Tuple[str, str]:
|
||||
def gettype(self, section: str, architecture: str, *, fallback: str | None = None) -> tuple[str, str]:
|
||||
"""
|
||||
get type variable with fallback to old logic. Despite the fact that it has same semantics as other get* methods,
|
||||
but it has different argument list
|
||||
@ -197,11 +198,11 @@ class Configuration(configparser.RawConfigParser):
|
||||
Args:
|
||||
section(str): section name
|
||||
architecture(str): repository architecture
|
||||
fallback(Optional[str], optional): optional fallback type if any. If set, second element of the tuple will
|
||||
fallback(str | None, optional): optional fallback type if any. If set, second element of the tuple will
|
||||
be always set to this value (Default value = None)
|
||||
|
||||
Returns:
|
||||
Tuple[str, str]: section name and found type name
|
||||
tuple[str, str]: section name and found type name
|
||||
|
||||
Raises:
|
||||
configparser.NoSectionError: in case if no section found
|
||||
|
@ -17,13 +17,13 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
from typing import Any, Dict
|
||||
from typing import Any
|
||||
|
||||
|
||||
__all__ = ["CONFIGURATION_SCHEMA", "ConfigurationSchema"]
|
||||
|
||||
|
||||
ConfigurationSchema = Dict[str, Dict[str, Any]]
|
||||
ConfigurationSchema = dict[str, dict[str, Any]]
|
||||
|
||||
|
||||
CONFIGURATION_SCHEMA: ConfigurationSchema = {
|
||||
|
@ -21,7 +21,7 @@ import ipaddress
|
||||
|
||||
from cerberus import TypeDefinition, Validator as RootValidator # type: ignore
|
||||
from pathlib import Path
|
||||
from typing import Any, List
|
||||
from typing import Any
|
||||
from urllib.parse import urlparse
|
||||
|
||||
from ahriman.core.configuration import Configuration
|
||||
@ -90,7 +90,7 @@ class Validator(RootValidator):
|
||||
del self
|
||||
return int(value)
|
||||
|
||||
def _normalize_coerce_list(self, value: str) -> List[str]:
|
||||
def _normalize_coerce_list(self, value: str) -> list[str]:
|
||||
"""
|
||||
extract string list from string value
|
||||
|
||||
@ -98,17 +98,17 @@ class Validator(RootValidator):
|
||||
value(str): converting value
|
||||
|
||||
Returns:
|
||||
List[str]: value converted to string list instance according to configuration rules
|
||||
list[str]: value converted to string list instance according to configuration rules
|
||||
"""
|
||||
converted: List[str] = self.configuration.converters["list"](value)
|
||||
converted: list[str] = self.configuration.converters["list"](value)
|
||||
return converted
|
||||
|
||||
def _validate_is_ip_address(self, constraint: List[str], field: str, value: str) -> None:
|
||||
def _validate_is_ip_address(self, constraint: list[str], field: str, value: str) -> None:
|
||||
"""
|
||||
check if the specified value is valid ip address
|
||||
|
||||
Args:
|
||||
constraint(List[str]): optional list of allowed special words (e.g. ``localhost``)
|
||||
constraint(list[str]): optional list of allowed special words (e.g. ``localhost``)
|
||||
field(str): field name to be checked
|
||||
value(Path): value to be checked
|
||||
|
||||
@ -123,12 +123,12 @@ class Validator(RootValidator):
|
||||
except ValueError:
|
||||
self._error(field, f"Value {value} must be valid IP address")
|
||||
|
||||
def _validate_is_url(self, constraint: List[str], field: str, value: str) -> None:
|
||||
def _validate_is_url(self, constraint: list[str], field: str, value: str) -> None:
|
||||
"""
|
||||
check if the specified value is a valid url
|
||||
|
||||
Args:
|
||||
constraint(List[str]): optional list of supported schemas. If empty, no schema validation will be performed
|
||||
constraint(list[str]): optional list of supported schemas. If empty, no schema validation will be performed
|
||||
field(str): field name to be checked
|
||||
value(str): value to be checked
|
||||
|
||||
|
@ -17,11 +17,11 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
from collections.abc import Callable
|
||||
from importlib import import_module
|
||||
from pathlib import Path
|
||||
from pkgutil import iter_modules
|
||||
from sqlite3 import Connection, Cursor
|
||||
from typing import Callable, List
|
||||
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.log import LazyLogging
|
||||
@ -83,22 +83,22 @@ class Migrations(LazyLogging):
|
||||
"data migration %s at index %s has been performed",
|
||||
migration.name, migration.index)
|
||||
|
||||
def migrations(self) -> List[Migration]:
|
||||
def migrations(self) -> list[Migration]:
|
||||
"""
|
||||
extract all migrations from the current package
|
||||
idea comes from https://julienharbulot.com/python-dynamical-import.html
|
||||
|
||||
Returns:
|
||||
List[Migration]: list of found migrations
|
||||
list[Migration]: list of found migrations
|
||||
"""
|
||||
migrations: List[Migration] = []
|
||||
migrations: list[Migration] = []
|
||||
package_dir = Path(__file__).resolve().parent
|
||||
modules = [module_name for (_, module_name, _) in iter_modules([str(package_dir)])]
|
||||
|
||||
for index, module_name in enumerate(sorted(modules)):
|
||||
module = import_module(f"{__name__}.{module_name}")
|
||||
|
||||
steps: List[str] = getattr(module, "steps", [])
|
||||
steps: list[str] = getattr(module, "steps", [])
|
||||
self.logger.debug("found migration %s at index %s with steps count %s", module_name, index, len(steps))
|
||||
|
||||
migrate_data: Callable[[Connection, Configuration], None] = \
|
||||
|
@ -18,7 +18,6 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
from sqlite3 import Connection
|
||||
from typing import List, Optional
|
||||
|
||||
from ahriman.core.database.operations import Operations
|
||||
from ahriman.models.user import User
|
||||
@ -30,7 +29,7 @@ class AuthOperations(Operations):
|
||||
authorization operations
|
||||
"""
|
||||
|
||||
def user_get(self, username: str) -> Optional[User]:
|
||||
def user_get(self, username: str) -> User | None:
|
||||
"""
|
||||
get user by username
|
||||
|
||||
@ -38,25 +37,25 @@ class AuthOperations(Operations):
|
||||
username(str): username
|
||||
|
||||
Returns:
|
||||
Optional[User]: user if it was found
|
||||
User | None: user if it was found
|
||||
"""
|
||||
return next(iter(self.user_list(username, None)), None)
|
||||
|
||||
def user_list(self, username: Optional[str], access: Optional[UserAccess]) -> List[User]:
|
||||
def user_list(self, username: str | None, access: UserAccess | None) -> list[User]:
|
||||
"""
|
||||
get users by filter
|
||||
|
||||
Args:
|
||||
username(Optional[str]): optional filter by username
|
||||
access(Optional[UserAccess]): optional filter by role
|
||||
username(str | None): optional filter by username
|
||||
access(UserAccess | None): optional filter by role
|
||||
|
||||
Returns:
|
||||
List[User]: list of users who match criteria
|
||||
list[User]: list of users who match criteria
|
||||
"""
|
||||
username_filter = username.lower() if username is not None else username
|
||||
access_filter = access.value if access is not None else access
|
||||
|
||||
def run(connection: Connection) -> List[User]:
|
||||
def run(connection: Connection) -> list[User]:
|
||||
return [
|
||||
User(username=cursor["username"], password=cursor["password"], access=UserAccess(cursor["access"]))
|
||||
for cursor in connection.execute(
|
||||
|
@ -18,7 +18,6 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
from sqlite3 import Connection
|
||||
from typing import List, Optional
|
||||
|
||||
from ahriman.core.database.operations import Operations
|
||||
from ahriman.models.package import Package
|
||||
@ -29,12 +28,12 @@ class BuildOperations(Operations):
|
||||
operations for build queue functions
|
||||
"""
|
||||
|
||||
def build_queue_clear(self, package_base: Optional[str]) -> None:
|
||||
def build_queue_clear(self, package_base: str | None) -> None:
|
||||
"""
|
||||
remove packages from build queue
|
||||
|
||||
Args:
|
||||
package_base(Optional[str]): optional filter by package base
|
||||
package_base(str | None): optional filter by package base
|
||||
"""
|
||||
def run(connection: Connection) -> None:
|
||||
connection.execute(
|
||||
@ -46,14 +45,14 @@ class BuildOperations(Operations):
|
||||
|
||||
return self.with_connection(run, commit=True)
|
||||
|
||||
def build_queue_get(self) -> List[Package]:
|
||||
def build_queue_get(self) -> list[Package]:
|
||||
"""
|
||||
retrieve packages from build queue
|
||||
|
||||
Return:
|
||||
List[Package]: list of packages to be built
|
||||
list[Package]: list of packages to be built
|
||||
"""
|
||||
def run(connection: Connection) -> List[Package]:
|
||||
def run(connection: Connection) -> list[Package]:
|
||||
return [
|
||||
Package.from_json(row["properties"])
|
||||
for row in connection.execute("""select * from build_queue""")
|
||||
|
@ -18,7 +18,6 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
from sqlite3 import Connection
|
||||
from typing import List, Optional
|
||||
|
||||
from ahriman.core.database.operations import Operations
|
||||
from ahriman.core.util import pretty_datetime
|
||||
@ -40,7 +39,7 @@ class LogsOperations(Operations):
|
||||
Return:
|
||||
str: full package log
|
||||
"""
|
||||
def run(connection: Connection) -> List[str]:
|
||||
def run(connection: Connection) -> list[str]:
|
||||
return [
|
||||
f"""[{pretty_datetime(row["created"])}] {row["record"]}"""
|
||||
for row in connection.execute(
|
||||
@ -81,13 +80,13 @@ class LogsOperations(Operations):
|
||||
|
||||
return self.with_connection(run, commit=True)
|
||||
|
||||
def logs_remove(self, package_base: str, current_process_id: Optional[int]) -> None:
|
||||
def logs_remove(self, package_base: str, current_process_id: int | None) -> None:
|
||||
"""
|
||||
remove log records for the specified package
|
||||
|
||||
Args:
|
||||
package_base(str): package base to remove logs
|
||||
current_process_id(Optional[int]): current process id. If set it will remove only logs belonging to another
|
||||
current_process_id(int | None): current process id. If set it will remove only logs belonging to another
|
||||
process
|
||||
"""
|
||||
def run(connection: Connection) -> None:
|
||||
|
@ -19,8 +19,9 @@
|
||||
#
|
||||
import sqlite3
|
||||
|
||||
from collections.abc import Callable
|
||||
from pathlib import Path
|
||||
from typing import Any, Callable, Dict, Tuple, TypeVar
|
||||
from typing import Any, TypeVar
|
||||
|
||||
from ahriman.core.log import LazyLogging
|
||||
|
||||
@ -46,16 +47,16 @@ class Operations(LazyLogging):
|
||||
self.path = path
|
||||
|
||||
@staticmethod
|
||||
def factory(cursor: sqlite3.Cursor, row: Tuple[Any, ...]) -> Dict[str, Any]:
|
||||
def factory(cursor: sqlite3.Cursor, row: tuple[Any, ...]) -> dict[str, Any]:
|
||||
"""
|
||||
dictionary factory based on official documentation
|
||||
|
||||
Args:
|
||||
cursor(Cursor): cursor descriptor
|
||||
row(Tuple[Any, ...]): fetched row
|
||||
row(tuple[Any, ...]): fetched row
|
||||
|
||||
Returns:
|
||||
Dict[str, Any]: row converted to dictionary
|
||||
dict[str, Any]: row converted to dictionary
|
||||
"""
|
||||
result = {}
|
||||
for index, column in enumerate(cursor.description):
|
||||
|
@ -17,8 +17,8 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
from collections.abc import Generator, Iterable
|
||||
from sqlite3 import Connection
|
||||
from typing import Dict, Generator, Iterable, List, Tuple
|
||||
|
||||
from ahriman.core.database.operations import Operations
|
||||
from ahriman.models.build_status import BuildStatus
|
||||
@ -148,7 +148,7 @@ class PackageOperations(Operations):
|
||||
{"package_base": package_base, "status": status.status.value, "last_updated": status.timestamp})
|
||||
|
||||
@staticmethod
|
||||
def _packages_get_select_package_bases(connection: Connection) -> Dict[str, Package]:
|
||||
def _packages_get_select_package_bases(connection: Connection) -> dict[str, Package]:
|
||||
"""
|
||||
select package bases from the table
|
||||
|
||||
@ -156,7 +156,7 @@ class PackageOperations(Operations):
|
||||
connection(Connection): database connection
|
||||
|
||||
Returns:
|
||||
Dict[str, Package]: map of the package base to its descriptor (without packages themselves)
|
||||
dict[str, Package]: map of the package base to its descriptor (without packages themselves)
|
||||
"""
|
||||
return {
|
||||
row["package_base"]: Package(
|
||||
@ -168,16 +168,16 @@ class PackageOperations(Operations):
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def _packages_get_select_packages(connection: Connection, packages: Dict[str, Package]) -> Dict[str, Package]:
|
||||
def _packages_get_select_packages(connection: Connection, packages: dict[str, Package]) -> dict[str, Package]:
|
||||
"""
|
||||
select packages from the table
|
||||
|
||||
Args:
|
||||
connection(Connection): database connection
|
||||
packages(Dict[str, Package]): packages descriptor map
|
||||
packages(dict[str, Package]): packages descriptor map
|
||||
|
||||
Returns:
|
||||
Dict[str, Package]: map of the package base to its descriptor including individual packages
|
||||
dict[str, Package]: map of the package base to its descriptor including individual packages
|
||||
"""
|
||||
for row in connection.execute("""select * from packages"""):
|
||||
if row["package_base"] not in packages:
|
||||
@ -186,7 +186,7 @@ class PackageOperations(Operations):
|
||||
return packages
|
||||
|
||||
@staticmethod
|
||||
def _packages_get_select_statuses(connection: Connection) -> Dict[str, BuildStatus]:
|
||||
def _packages_get_select_statuses(connection: Connection) -> dict[str, BuildStatus]:
|
||||
"""
|
||||
select package build statuses from the table
|
||||
|
||||
@ -194,7 +194,7 @@ class PackageOperations(Operations):
|
||||
connection(Connection): database connection
|
||||
|
||||
Returns:
|
||||
Dict[str, BuildStatus]: map of the package base to its status
|
||||
dict[str, BuildStatus]: map of the package base to its status
|
||||
"""
|
||||
return {
|
||||
row["package_base"]: BuildStatus.from_json({"status": row["status"], "timestamp": row["last_updated"]})
|
||||
@ -230,14 +230,14 @@ class PackageOperations(Operations):
|
||||
|
||||
return self.with_connection(run, commit=True)
|
||||
|
||||
def packages_get(self) -> List[Tuple[Package, BuildStatus]]:
|
||||
def packages_get(self) -> list[tuple[Package, BuildStatus]]:
|
||||
"""
|
||||
get package list and their build statuses from database
|
||||
|
||||
Return:
|
||||
List[Tuple[Package, BuildStatus]]: list of package properties and their statuses
|
||||
list[tuple[Package, BuildStatus]]: list of package properties and their statuses
|
||||
"""
|
||||
def run(connection: Connection) -> Generator[Tuple[Package, BuildStatus], None, None]:
|
||||
def run(connection: Connection) -> Generator[tuple[Package, BuildStatus], None, None]:
|
||||
packages = self._packages_get_select_package_bases(connection)
|
||||
statuses = self._packages_get_select_statuses(connection)
|
||||
for package_base, package in self._packages_get_select_packages(connection, packages).items():
|
||||
@ -256,12 +256,12 @@ class PackageOperations(Operations):
|
||||
lambda connection: self._package_update_insert_base(connection, package),
|
||||
commit=True)
|
||||
|
||||
def remotes_get(self) -> Dict[str, RemoteSource]:
|
||||
def remotes_get(self) -> dict[str, RemoteSource]:
|
||||
"""
|
||||
get packages remotes based on current settings
|
||||
|
||||
Returns:
|
||||
Dict[str, RemoteSource]: map of package base to its remote sources
|
||||
dict[str, RemoteSource]: map of package base to its remote sources
|
||||
"""
|
||||
packages = self.with_connection(self._packages_get_select_package_bases)
|
||||
return {
|
||||
|
@ -20,7 +20,6 @@
|
||||
from collections import defaultdict
|
||||
|
||||
from sqlite3 import Connection
|
||||
from typing import Dict, List, Optional, Tuple
|
||||
|
||||
from ahriman.core.database.operations import Operations
|
||||
from ahriman.models.pkgbuild_patch import PkgbuildPatch
|
||||
@ -31,7 +30,7 @@ class PatchOperations(Operations):
|
||||
operations for patches
|
||||
"""
|
||||
|
||||
def patches_get(self, package_base: str) -> List[PkgbuildPatch]:
|
||||
def patches_get(self, package_base: str) -> list[PkgbuildPatch]:
|
||||
"""
|
||||
retrieve patches for the package
|
||||
|
||||
@ -39,7 +38,7 @@ class PatchOperations(Operations):
|
||||
package_base(str): package base to search for patches
|
||||
|
||||
Returns:
|
||||
List[PkgbuildPatch]: plain text patch for the package
|
||||
list[PkgbuildPatch]: plain text patch for the package
|
||||
"""
|
||||
return self.patches_list(package_base, []).get(package_base, [])
|
||||
|
||||
@ -65,18 +64,18 @@ class PatchOperations(Operations):
|
||||
|
||||
return self.with_connection(run, commit=True)
|
||||
|
||||
def patches_list(self, package_base: Optional[str], variables: List[str]) -> Dict[str, List[PkgbuildPatch]]:
|
||||
def patches_list(self, package_base: str | None, variables: list[str]) -> dict[str, list[PkgbuildPatch]]:
|
||||
"""
|
||||
extract all patches
|
||||
|
||||
Args:
|
||||
package_base(Optional[str]): optional filter by package base
|
||||
variables(List[str]): extract patches only for specified PKGBUILD variables
|
||||
package_base(str | None): optional filter by package base
|
||||
variables(list[str]): extract patches only for specified PKGBUILD variables
|
||||
|
||||
Returns:
|
||||
Dict[str, List[PkgbuildPatch]]: map of package base to patch content
|
||||
dict[str, list[PkgbuildPatch]]: map of package base to patch content
|
||||
"""
|
||||
def run(connection: Connection) -> List[Tuple[str, PkgbuildPatch]]:
|
||||
def run(connection: Connection) -> list[tuple[str, PkgbuildPatch]]:
|
||||
return [
|
||||
(cursor["package_base"], PkgbuildPatch(cursor["variable"], cursor["patch"]))
|
||||
for cursor in connection.execute(
|
||||
@ -85,20 +84,20 @@ class PatchOperations(Operations):
|
||||
]
|
||||
|
||||
# we could use itertools & operator but why?
|
||||
patches: Dict[str, List[PkgbuildPatch]] = defaultdict(list)
|
||||
patches: dict[str, list[PkgbuildPatch]] = defaultdict(list)
|
||||
for package, patch in self.with_connection(run):
|
||||
if variables and patch.key not in variables:
|
||||
continue
|
||||
patches[package].append(patch)
|
||||
return dict(patches)
|
||||
|
||||
def patches_remove(self, package_base: str, variables: List[str]) -> None:
|
||||
def patches_remove(self, package_base: str, variables: list[str]) -> None:
|
||||
"""
|
||||
remove patch set
|
||||
|
||||
Args:
|
||||
package_base(str): package base to clear patches
|
||||
variables(List[str]): remove patches only for specified PKGBUILD variables
|
||||
variables(list[str]): remove patches only for specified PKGBUILD variables
|
||||
"""
|
||||
def run_many(connection: Connection) -> None:
|
||||
connection.executemany(
|
||||
|
@ -23,7 +23,6 @@ import json
|
||||
import sqlite3
|
||||
|
||||
from pathlib import Path
|
||||
from typing import Type
|
||||
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.database.migrations import Migrations
|
||||
@ -47,7 +46,7 @@ class SQLite(AuthOperations, BuildOperations, LogsOperations, PackageOperations,
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def load(cls: Type[SQLite], configuration: Configuration) -> SQLite:
|
||||
def load(cls: type[SQLite], configuration: Configuration) -> SQLite:
|
||||
"""
|
||||
construct instance from configuration
|
||||
|
||||
|
@ -17,8 +17,6 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
from typing import List
|
||||
|
||||
from ahriman.core.formatters import StringPrinter
|
||||
from ahriman.core.util import pretty_datetime
|
||||
from ahriman.models.aur_package import AURPackage
|
||||
@ -43,12 +41,12 @@ class AurPrinter(StringPrinter):
|
||||
StringPrinter.__init__(self, f"{package.name} {package.version} ({package.num_votes})")
|
||||
self.package = package
|
||||
|
||||
def properties(self) -> List[Property]:
|
||||
def properties(self) -> list[Property]:
|
||||
"""
|
||||
convert content into printable data
|
||||
|
||||
Returns:
|
||||
List[Property]: list of content properties
|
||||
list[Property]: list of content properties
|
||||
"""
|
||||
return [
|
||||
Property("Package base", self.package.package_base),
|
||||
|
@ -17,8 +17,6 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
from typing import Dict, List
|
||||
|
||||
from ahriman.core.formatters import StringPrinter
|
||||
from ahriman.models.property import Property
|
||||
|
||||
@ -28,9 +26,9 @@ class ConfigurationPrinter(StringPrinter):
|
||||
print content of the configuration section
|
||||
|
||||
Attributes:
|
||||
HIDE_KEYS(List[str]): (class attribute) hide values for mentioned keys. This list must be used in order to hide
|
||||
HIDE_KEYS(list[str]): (class attribute) hide values for mentioned keys. This list must be used in order to hide
|
||||
passwords from outputs
|
||||
values(Dict[str, str]): configuration values dictionary
|
||||
values(dict[str, str]): configuration values dictionary
|
||||
"""
|
||||
|
||||
HIDE_KEYS = [
|
||||
@ -42,23 +40,23 @@ class ConfigurationPrinter(StringPrinter):
|
||||
"secret_key", # aws secret key
|
||||
]
|
||||
|
||||
def __init__(self, section: str, values: Dict[str, str]) -> None:
|
||||
def __init__(self, section: str, values: dict[str, str]) -> None:
|
||||
"""
|
||||
default constructor
|
||||
|
||||
Args:
|
||||
section(str): section name
|
||||
values(Dict[str, str]): configuration values dictionary
|
||||
values(dict[str, str]): configuration values dictionary
|
||||
"""
|
||||
StringPrinter.__init__(self, f"[{section}]")
|
||||
self.values = values
|
||||
|
||||
def properties(self) -> List[Property]:
|
||||
def properties(self) -> list[Property]:
|
||||
"""
|
||||
convert content into printable data
|
||||
|
||||
Returns:
|
||||
List[Property]: list of content properties
|
||||
list[Property]: list of content properties
|
||||
"""
|
||||
return [
|
||||
Property(key, value, is_required=key not in self.HIDE_KEYS)
|
||||
|
@ -17,8 +17,6 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
from typing import List
|
||||
|
||||
from ahriman.core.formatters import StringPrinter
|
||||
from ahriman.models.build_status import BuildStatus
|
||||
from ahriman.models.package import Package
|
||||
@ -46,12 +44,12 @@ class PackagePrinter(StringPrinter):
|
||||
self.package = package
|
||||
self.status = status
|
||||
|
||||
def properties(self) -> List[Property]:
|
||||
def properties(self) -> list[Property]:
|
||||
"""
|
||||
convert content into printable data
|
||||
|
||||
Returns:
|
||||
List[Property]: list of content properties
|
||||
list[Property]: list of content properties
|
||||
"""
|
||||
return [
|
||||
Property("Version", self.package.version, is_required=True),
|
||||
|
@ -17,8 +17,6 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
from typing import List
|
||||
|
||||
from ahriman.core.formatters import StringPrinter
|
||||
from ahriman.models.pkgbuild_patch import PkgbuildPatch
|
||||
from ahriman.models.property import Property
|
||||
@ -29,26 +27,26 @@ class PatchPrinter(StringPrinter):
|
||||
print content of the PKGBUILD patch
|
||||
|
||||
Attributes:
|
||||
patches(List[PkgbuildPatch]): PKGBUILD patch object
|
||||
patches(list[PkgbuildPatch]): PKGBUILD patch object
|
||||
"""
|
||||
|
||||
def __init__(self, package_base: str, patches: List[PkgbuildPatch]) -> None:
|
||||
def __init__(self, package_base: str, patches: list[PkgbuildPatch]) -> None:
|
||||
"""
|
||||
default constructor
|
||||
|
||||
Args:
|
||||
package_base(str): package base
|
||||
patches(List[PkgbuildPatch]): PKGBUILD patch object
|
||||
patches(list[PkgbuildPatch]): PKGBUILD patch object
|
||||
"""
|
||||
StringPrinter.__init__(self, package_base)
|
||||
self.patches = patches
|
||||
|
||||
def properties(self) -> List[Property]:
|
||||
def properties(self) -> list[Property]:
|
||||
"""
|
||||
convert content into printable data
|
||||
|
||||
Returns:
|
||||
List[Property]: list of content properties
|
||||
list[Property]: list of content properties
|
||||
"""
|
||||
return [
|
||||
Property(patch.key or "Full source diff", patch.value, is_required=True)
|
||||
|
@ -17,7 +17,7 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
from typing import Callable, List, Optional
|
||||
from collections.abc import Callable
|
||||
|
||||
from ahriman.models.property import Property
|
||||
|
||||
@ -44,19 +44,19 @@ class Printer:
|
||||
indent = "\t" * prop.indent
|
||||
log_fn(f"{indent}{prop.name}{separator}{prop.value}")
|
||||
|
||||
def properties(self) -> List[Property]:
|
||||
def properties(self) -> list[Property]:
|
||||
"""
|
||||
convert content into printable data
|
||||
|
||||
Returns:
|
||||
List[Property]: list of content properties
|
||||
list[Property]: list of content properties
|
||||
"""
|
||||
return []
|
||||
|
||||
def title(self) -> Optional[str]:
|
||||
def title(self) -> str | None:
|
||||
"""
|
||||
generate entry title from content
|
||||
|
||||
Returns:
|
||||
Optional[str]: content title if it can be generated and None otherwise
|
||||
str | None: content title if it can be generated and None otherwise
|
||||
"""
|
||||
|
@ -17,8 +17,6 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
from typing import Optional
|
||||
|
||||
from ahriman.core.formatters import Printer
|
||||
|
||||
|
||||
@ -39,11 +37,11 @@ class StringPrinter(Printer):
|
||||
"""
|
||||
self.content = content
|
||||
|
||||
def title(self) -> Optional[str]:
|
||||
def title(self) -> str | None:
|
||||
"""
|
||||
generate entry title from content
|
||||
|
||||
Returns:
|
||||
Optional[str]: content title if it can be generated and None otherwise
|
||||
str | None: content title if it can be generated and None otherwise
|
||||
"""
|
||||
return self.content
|
||||
|
@ -17,8 +17,6 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
from typing import Iterable, List
|
||||
|
||||
from ahriman.core.formatters import StringPrinter
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.property import Property
|
||||
@ -29,25 +27,25 @@ class TreePrinter(StringPrinter):
|
||||
print content of the package tree level
|
||||
|
||||
Attributes:
|
||||
packages(Iterable[Package]): packages which belong to this level
|
||||
packages(list[Package]): packages which belong to this level
|
||||
"""
|
||||
|
||||
def __init__(self, level: int, packages: Iterable[Package]) -> None:
|
||||
def __init__(self, level: int, packages: list[Package]) -> None:
|
||||
"""
|
||||
default constructor
|
||||
|
||||
Args:
|
||||
level(int): dependencies tree level
|
||||
packages(Iterable[Package]): packages which belong to this level
|
||||
packages(list[Package]): packages which belong to this level
|
||||
"""
|
||||
StringPrinter.__init__(self, f"level {level}")
|
||||
self.packages = packages
|
||||
|
||||
def properties(self) -> List[Property]:
|
||||
def properties(self) -> list[Property]:
|
||||
"""
|
||||
convert content into printable data
|
||||
|
||||
Returns:
|
||||
List[Property]: list of content properties
|
||||
list[Property]: list of content properties
|
||||
"""
|
||||
return [Property(package.base, package.version, is_required=True) for package in self.packages]
|
||||
|
@ -17,8 +17,6 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
from typing import List, Optional
|
||||
|
||||
from ahriman.core.formatters import StringPrinter
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.property import Property
|
||||
@ -30,26 +28,26 @@ class UpdatePrinter(StringPrinter):
|
||||
|
||||
Attributes:
|
||||
package(Package): remote (new) package object
|
||||
local_version(Optional[str]): local version of the package if any
|
||||
local_version(str | None): local version of the package if any
|
||||
"""
|
||||
|
||||
def __init__(self, remote: Package, local_version: Optional[str]) -> None:
|
||||
def __init__(self, remote: Package, local_version: str | None) -> None:
|
||||
"""
|
||||
default constructor
|
||||
|
||||
Args:
|
||||
remote(Package): remote (new) package object
|
||||
local_version(Optional[str]): local version of the package if any
|
||||
local_version(str | None): local version of the package if any
|
||||
"""
|
||||
StringPrinter.__init__(self, remote.base)
|
||||
self.package = remote
|
||||
self.local_version = local_version or "N/A"
|
||||
|
||||
def properties(self) -> List[Property]:
|
||||
def properties(self) -> list[Property]:
|
||||
"""
|
||||
convert content into printable data
|
||||
|
||||
Returns:
|
||||
List[Property]: list of content properties
|
||||
list[Property]: list of content properties
|
||||
"""
|
||||
return [Property(self.local_version, self.package.version, is_required=True)]
|
||||
|
@ -17,8 +17,6 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
from typing import List
|
||||
|
||||
from ahriman.core.formatters import StringPrinter
|
||||
from ahriman.models.property import Property
|
||||
from ahriman.models.user import User
|
||||
@ -42,11 +40,11 @@ class UserPrinter(StringPrinter):
|
||||
StringPrinter.__init__(self, user.username)
|
||||
self.user = user
|
||||
|
||||
def properties(self) -> List[Property]:
|
||||
def properties(self) -> list[Property]:
|
||||
"""
|
||||
convert content into printable data
|
||||
|
||||
Returns:
|
||||
List[Property]: list of content properties
|
||||
list[Property]: list of content properties
|
||||
"""
|
||||
return [Property("role", self.user.access.value, is_required=True)]
|
||||
|
@ -17,7 +17,8 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
from typing import Any, Dict, Generator, List, Union
|
||||
from collections.abc import Generator
|
||||
from typing import Any
|
||||
|
||||
from ahriman.core.formatters import StringPrinter
|
||||
from ahriman.models.property import Property
|
||||
@ -29,30 +30,30 @@ class ValidationPrinter(StringPrinter):
|
||||
|
||||
Attributes:
|
||||
node(str): root level name
|
||||
errors(List[Union[str, Dict[str, Any]]]): validation errors
|
||||
errors(list[str | dict[str, Any]]): validation errors
|
||||
"""
|
||||
|
||||
def __init__(self, node: str, errors: List[Union[str, Dict[str, Any]]]) -> None:
|
||||
def __init__(self, node: str, errors: list[str | dict[str, Any]]) -> None:
|
||||
"""
|
||||
default constructor
|
||||
|
||||
Args:
|
||||
node(str): root level name
|
||||
errors(List[Union[str, Dict[str, Any]]]): validation errors
|
||||
errors(list[str | dict[str, Any]]): validation errors
|
||||
"""
|
||||
StringPrinter.__init__(self, node)
|
||||
self.node = node
|
||||
self.errors = errors
|
||||
|
||||
@staticmethod
|
||||
def get_error_messages(node: str, errors: List[Union[str, Dict[str, Any]]],
|
||||
def get_error_messages(node: str, errors: list[str | dict[str, Any]],
|
||||
current_level: int = 1) -> Generator[Property, None, None]:
|
||||
"""
|
||||
extract default error message from cerberus class
|
||||
|
||||
Args:
|
||||
node(str): current node level name
|
||||
errors(List[Union[str, Dict[str, Any]]]): current node validation errors
|
||||
errors(list[str | dict[str, Any]]): current node validation errors
|
||||
current_level(int, optional): current level number (Default value = 1)
|
||||
|
||||
Yields:
|
||||
@ -67,11 +68,11 @@ class ValidationPrinter(StringPrinter):
|
||||
else: # current node errors
|
||||
yield Property(node, error, is_required=True, indent=current_level)
|
||||
|
||||
def properties(self) -> List[Property]:
|
||||
def properties(self) -> list[Property]:
|
||||
"""
|
||||
convert content into printable data
|
||||
|
||||
Returns:
|
||||
List[Property]: list of content properties
|
||||
list[Property]: list of content properties
|
||||
"""
|
||||
return list(self.get_error_messages(self.node, self.errors))
|
||||
|
@ -17,8 +17,6 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
from typing import Dict, List
|
||||
|
||||
from ahriman.core.formatters import StringPrinter
|
||||
from ahriman.models.property import Property
|
||||
|
||||
@ -28,26 +26,26 @@ class VersionPrinter(StringPrinter):
|
||||
print content of the python package versions
|
||||
|
||||
Attributes:
|
||||
packages(Dict[str, str]): map of package name to its version
|
||||
packages(dict[str, str]): map of package name to its version
|
||||
"""
|
||||
|
||||
def __init__(self, title: str, packages: Dict[str, str]) -> None:
|
||||
def __init__(self, title: str, packages: dict[str, str]) -> None:
|
||||
"""
|
||||
default constructor
|
||||
|
||||
Args:
|
||||
title(str): title of the message
|
||||
packages(Dict[str, str]): map of package name to its version
|
||||
packages(dict[str, str]): map of package name to its version
|
||||
"""
|
||||
StringPrinter.__init__(self, title)
|
||||
self.packages = packages
|
||||
|
||||
def properties(self) -> List[Property]:
|
||||
def properties(self) -> list[Property]:
|
||||
"""
|
||||
convert content into printable data
|
||||
|
||||
Returns:
|
||||
List[Property]: list of content properties
|
||||
list[Property]: list of content properties
|
||||
"""
|
||||
return [
|
||||
Property(package, version, is_required=True)
|
||||
|
@ -17,8 +17,6 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
from typing import List, Type
|
||||
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.gitremote.remote_pull import RemotePull
|
||||
from ahriman.core.triggers import Trigger
|
||||
@ -29,7 +27,7 @@ class RemotePullTrigger(Trigger):
|
||||
trigger based on pulling PKGBUILDs before the actions
|
||||
|
||||
Attributes:
|
||||
targets(List[str]): git remote target list
|
||||
targets(list[str]): git remote target list
|
||||
"""
|
||||
|
||||
CONFIGURATION_SCHEMA = {
|
||||
@ -70,7 +68,7 @@ class RemotePullTrigger(Trigger):
|
||||
self.targets = self.configuration_sections(configuration)
|
||||
|
||||
@classmethod
|
||||
def configuration_sections(cls: Type[Trigger], configuration: Configuration) -> List[str]:
|
||||
def configuration_sections(cls: type[Trigger], configuration: Configuration) -> list[str]:
|
||||
"""
|
||||
extract configuration sections from configuration
|
||||
|
||||
@ -78,7 +76,7 @@ class RemotePullTrigger(Trigger):
|
||||
configuration(Configuration): configuration instance
|
||||
|
||||
Returns:
|
||||
List[str]: read configuration sections belong to this trigger
|
||||
list[str]: read configuration sections belong to this trigger
|
||||
"""
|
||||
return configuration.getlist("remote-pull", "target", fallback=[])
|
||||
|
||||
|
@ -19,9 +19,9 @@
|
||||
#
|
||||
import shutil
|
||||
|
||||
from collections.abc import Generator
|
||||
from pathlib import Path
|
||||
from tempfile import TemporaryDirectory
|
||||
from typing import Generator
|
||||
|
||||
from ahriman.core.build_tools.sources import Sources
|
||||
from ahriman.core.configuration import Configuration
|
||||
@ -39,7 +39,7 @@ class RemotePush(LazyLogging):
|
||||
sync PKGBUILDs to remote repository after actions
|
||||
|
||||
Attributes:
|
||||
commit_author(Optional[str]): optional commit author in form of git config (i.e. ``user <user@host>``)
|
||||
commit_author(str | None): optional commit author in form of git config (i.e. ``user <user@host>``)
|
||||
database(SQLite): database instance
|
||||
remote_source(RemoteSource): repository remote source (remote pull url and branch)
|
||||
"""
|
||||
|
@ -17,8 +17,6 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
from typing import Iterable, List, Type
|
||||
|
||||
from ahriman.core import context
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.database import SQLite
|
||||
@ -34,7 +32,7 @@ class RemotePushTrigger(Trigger):
|
||||
trigger for syncing PKGBUILDs to remote repository
|
||||
|
||||
Attributes:
|
||||
targets(List[str]): git remote target list
|
||||
targets(list[str]): git remote target list
|
||||
"""
|
||||
|
||||
CONFIGURATION_SCHEMA = {
|
||||
@ -78,7 +76,7 @@ class RemotePushTrigger(Trigger):
|
||||
self.targets = self.configuration_sections(configuration)
|
||||
|
||||
@classmethod
|
||||
def configuration_sections(cls: Type[Trigger], configuration: Configuration) -> List[str]:
|
||||
def configuration_sections(cls: type[Trigger], configuration: Configuration) -> list[str]:
|
||||
"""
|
||||
extract configuration sections from configuration
|
||||
|
||||
@ -86,17 +84,17 @@ class RemotePushTrigger(Trigger):
|
||||
configuration(Configuration): configuration instance
|
||||
|
||||
Returns:
|
||||
List[str]: read configuration sections belong to this trigger
|
||||
list[str]: read configuration sections belong to this trigger
|
||||
"""
|
||||
return configuration.getlist("remote-push", "target", fallback=[])
|
||||
|
||||
def on_result(self, result: Result, packages: Iterable[Package]) -> None:
|
||||
def on_result(self, result: Result, packages: list[Package]) -> None:
|
||||
"""
|
||||
trigger action which will be called after build process with process result
|
||||
|
||||
Args:
|
||||
result(Result): build result
|
||||
packages(Iterable[Package]): list of all available packages
|
||||
packages(list[Package]): list of all available packages
|
||||
|
||||
Raises:
|
||||
GitRemoteError: if database is not set in context
|
||||
|
@ -20,7 +20,8 @@
|
||||
import contextlib
|
||||
import logging
|
||||
|
||||
from typing import Any, Generator
|
||||
from collections.abc import Generator
|
||||
from typing import Any
|
||||
|
||||
|
||||
class LazyLogging:
|
||||
|
@ -17,8 +17,6 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
from typing import Iterable
|
||||
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.formatters import BuildPrinter
|
||||
from ahriman.core.report.report import Report
|
||||
@ -46,12 +44,12 @@ class Console(Report):
|
||||
Report.__init__(self, architecture, configuration)
|
||||
self.use_utf = configuration.getboolean(section, "use_utf", fallback=True)
|
||||
|
||||
def generate(self, packages: Iterable[Package], result: Result) -> None:
|
||||
def generate(self, packages: list[Package], result: Result) -> None:
|
||||
"""
|
||||
generate report for the specified packages
|
||||
|
||||
Args:
|
||||
packages(Iterable[Package]): list of packages to generate report
|
||||
packages(list[Package]): list of packages to generate report
|
||||
result(Result): build result
|
||||
"""
|
||||
for package in result.success:
|
||||
|
@ -21,7 +21,6 @@ import smtplib
|
||||
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
from email.mime.text import MIMEText
|
||||
from typing import Dict, Iterable
|
||||
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.report.jinja_template import JinjaTemplate
|
||||
@ -40,13 +39,13 @@ class Email(Report, JinjaTemplate):
|
||||
full_template_path(Path): path to template for full package list
|
||||
host(str): SMTP host to connect
|
||||
no_empty_report(bool): skip empty report generation
|
||||
password(Optional[str]): password to authenticate via SMTP
|
||||
password(str | None): password to authenticate via SMTP
|
||||
port(int): SMTP port to connect
|
||||
receivers(List[str]): list of receivers emails
|
||||
receivers(list[str]): list of receivers emails
|
||||
sender(str): sender email address
|
||||
ssl(SmtpSSLSettings): SSL mode for SMTP connection
|
||||
template_path(Path): path to template for built packages
|
||||
user(Optional[str]): username to authenticate via SMTP
|
||||
user(str | None): username to authenticate via SMTP
|
||||
"""
|
||||
|
||||
def __init__(self, architecture: str, configuration: Configuration, section: str) -> None:
|
||||
@ -74,13 +73,13 @@ class Email(Report, JinjaTemplate):
|
||||
self.ssl = SmtpSSLSettings.from_option(configuration.get(section, "ssl", fallback="disabled"))
|
||||
self.user = configuration.get(section, "user", fallback=None)
|
||||
|
||||
def _send(self, text: str, attachment: Dict[str, str]) -> None:
|
||||
def _send(self, text: str, attachment: dict[str, str]) -> None:
|
||||
"""
|
||||
send email callback
|
||||
|
||||
Args:
|
||||
text(str): email body text
|
||||
attachment(Dict[str, str]): map of attachment filename to attachment content
|
||||
attachment(dict[str, str]): map of attachment filename to attachment content
|
||||
"""
|
||||
message = MIMEMultipart()
|
||||
message["From"] = self.sender
|
||||
@ -104,12 +103,12 @@ class Email(Report, JinjaTemplate):
|
||||
session.sendmail(self.sender, self.receivers, message.as_string())
|
||||
session.quit()
|
||||
|
||||
def generate(self, packages: Iterable[Package], result: Result) -> None:
|
||||
def generate(self, packages: list[Package], result: Result) -> None:
|
||||
"""
|
||||
generate report for the specified packages
|
||||
|
||||
Args:
|
||||
packages(Iterable[Package]): list of packages to generate report
|
||||
packages(list[Package]): list of packages to generate report
|
||||
result(Result): build result
|
||||
"""
|
||||
if self.no_empty_report and not result.success:
|
||||
|
@ -17,8 +17,6 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
from typing import Iterable
|
||||
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.report.jinja_template import JinjaTemplate
|
||||
from ahriman.core.report.report import Report
|
||||
@ -50,12 +48,12 @@ class HTML(Report, JinjaTemplate):
|
||||
self.report_path = configuration.getpath(section, "path")
|
||||
self.template_path = configuration.getpath(section, "template_path")
|
||||
|
||||
def generate(self, packages: Iterable[Package], result: Result) -> None:
|
||||
def generate(self, packages: list[Package], result: Result) -> None:
|
||||
"""
|
||||
generate report for the specified packages
|
||||
|
||||
Args:
|
||||
packages(Iterable[Package]): list of packages to generate report
|
||||
packages(list[Package]): list of packages to generate report
|
||||
result(Result): build result
|
||||
"""
|
||||
html = self.make_html(Result(success=packages), self.template_path)
|
||||
|
@ -19,8 +19,8 @@
|
||||
#
|
||||
import jinja2
|
||||
|
||||
from collections.abc import Callable
|
||||
from pathlib import Path
|
||||
from typing import Callable, Dict
|
||||
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.sign.gpg import GPG
|
||||
@ -56,11 +56,11 @@ class JinjaTemplate:
|
||||
* repository - repository name, string, required
|
||||
|
||||
Attributes:
|
||||
homepage(Optional[str]): homepage link if any (for footer)
|
||||
homepage(str | None): homepage link if any (for footer)
|
||||
link_path(str): prefix fo packages to download
|
||||
name(str): repository name
|
||||
default_pgp_key(Optional[str]): default PGP key
|
||||
sign_targets(Set[SignSettings]): targets to sign enabled in configuration
|
||||
default_pgp_key(str | None): default PGP key
|
||||
sign_targets(set[SignSettings]): targets to sign enabled in configuration
|
||||
"""
|
||||
|
||||
def __init__(self, section: str, configuration: Configuration) -> None:
|
||||
@ -108,7 +108,7 @@ class JinjaTemplate:
|
||||
"version": base.version
|
||||
} for base in result.success for package, properties in base.packages.items()
|
||||
]
|
||||
comparator: Callable[[Dict[str, str]], str] = lambda item: item["filename"]
|
||||
comparator: Callable[[dict[str, str]], str] = lambda item: item["filename"]
|
||||
|
||||
return template.render(
|
||||
homepage=self.homepage,
|
||||
|
@ -19,8 +19,6 @@
|
||||
#
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Iterable, Type
|
||||
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.exceptions import ReportError
|
||||
from ahriman.core.log import LazyLogging
|
||||
@ -69,7 +67,7 @@ class Report(LazyLogging):
|
||||
self.configuration = configuration
|
||||
|
||||
@classmethod
|
||||
def load(cls: Type[Report], architecture: str, configuration: Configuration, target: str) -> Report:
|
||||
def load(cls: type[Report], architecture: str, configuration: Configuration, target: str) -> Report:
|
||||
"""
|
||||
load client from settings
|
||||
|
||||
@ -97,22 +95,22 @@ class Report(LazyLogging):
|
||||
return Telegram(architecture, configuration, section)
|
||||
return cls(architecture, configuration) # should never happen
|
||||
|
||||
def generate(self, packages: Iterable[Package], result: Result) -> None:
|
||||
def generate(self, packages: list[Package], result: Result) -> None:
|
||||
"""
|
||||
generate report for the specified packages
|
||||
|
||||
Args:
|
||||
packages(Iterable[Package]): list of packages to generate report
|
||||
packages(list[Package]): list of packages to generate report
|
||||
result(Result): build result
|
||||
"""
|
||||
|
||||
def run(self, result: Result, packages: Iterable[Package]) -> None:
|
||||
def run(self, result: Result, packages: list[Package]) -> None:
|
||||
"""
|
||||
run report generation
|
||||
|
||||
Args:
|
||||
result(Result): build result
|
||||
packages(Iterable[Package]): list of packages to generate report
|
||||
packages(list[Package]): list of packages to generate report
|
||||
|
||||
Raises:
|
||||
ReportFailed: in case of any report unmatched exception
|
||||
|
@ -17,8 +17,6 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
from typing import Iterable, List, Type
|
||||
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.triggers import Trigger
|
||||
from ahriman.core.report.report import Report
|
||||
@ -31,7 +29,7 @@ class ReportTrigger(Trigger):
|
||||
report trigger
|
||||
|
||||
Attributes:
|
||||
targets(List[str]): report target list
|
||||
targets(list[str]): report target list
|
||||
"""
|
||||
|
||||
CONFIGURATION_SCHEMA = {
|
||||
@ -207,7 +205,7 @@ class ReportTrigger(Trigger):
|
||||
self.targets = self.configuration_sections(configuration)
|
||||
|
||||
@classmethod
|
||||
def configuration_sections(cls: Type[Trigger], configuration: Configuration) -> List[str]:
|
||||
def configuration_sections(cls: type[Trigger], configuration: Configuration) -> list[str]:
|
||||
"""
|
||||
extract configuration sections from configuration
|
||||
|
||||
@ -215,17 +213,17 @@ class ReportTrigger(Trigger):
|
||||
configuration(Configuration): configuration instance
|
||||
|
||||
Returns:
|
||||
List[str]: read configuration sections belong to this trigger
|
||||
list[str]: read configuration sections belong to this trigger
|
||||
"""
|
||||
return configuration.getlist("report", "target", fallback=[])
|
||||
|
||||
def on_result(self, result: Result, packages: Iterable[Package]) -> None:
|
||||
def on_result(self, result: Result, packages: list[Package]) -> None:
|
||||
"""
|
||||
run trigger
|
||||
|
||||
Args:
|
||||
result(Result): build result
|
||||
packages(Iterable[Package]): list of all available packages
|
||||
packages(list[Package]): list of all available packages
|
||||
"""
|
||||
for target in self.targets:
|
||||
runner = Report.load(self.architecture, self.configuration, target)
|
||||
|
@ -19,8 +19,6 @@
|
||||
#
|
||||
import requests # technically we could use python-telegram-bot, but it is just a single request, c'mon
|
||||
|
||||
from typing import Iterable
|
||||
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.report.jinja_template import JinjaTemplate
|
||||
from ahriman.core.report.report import Report
|
||||
@ -84,12 +82,12 @@ class Telegram(Report, JinjaTemplate):
|
||||
self.logger.exception("could not perform request")
|
||||
raise
|
||||
|
||||
def generate(self, packages: Iterable[Package], result: Result) -> None:
|
||||
def generate(self, packages: list[Package], result: Result) -> None:
|
||||
"""
|
||||
generate report for the specified packages
|
||||
|
||||
Args:
|
||||
packages(Iterable[Package]): list of packages to generate report
|
||||
packages(list[Package]): list of packages to generate report
|
||||
result(Result): build result
|
||||
"""
|
||||
if not result.success:
|
||||
|
@ -20,7 +20,6 @@
|
||||
import shutil
|
||||
|
||||
from pathlib import Path
|
||||
from typing import List
|
||||
|
||||
from ahriman.core.repository.repository_properties import RepositoryProperties
|
||||
|
||||
@ -69,12 +68,12 @@ class Cleaner(RepositoryProperties):
|
||||
self.logger.info("clear build queue")
|
||||
self.database.build_queue_clear(None)
|
||||
|
||||
def packages_built(self) -> List[Path]:
|
||||
def packages_built(self) -> list[Path]:
|
||||
"""
|
||||
get list of files in built packages directory
|
||||
|
||||
Returns:
|
||||
List[Path]: list of filenames from the directory
|
||||
list[Path]: list of filenames from the directory
|
||||
|
||||
Raises:
|
||||
NotImplementedError: not implemented method
|
||||
|
@ -19,9 +19,9 @@
|
||||
#
|
||||
import shutil
|
||||
|
||||
from collections.abc import Iterable
|
||||
from pathlib import Path
|
||||
from tempfile import TemporaryDirectory
|
||||
from typing import Dict, Iterable, List, Optional
|
||||
|
||||
from ahriman.core.build_tools.task import Task
|
||||
from ahriman.core.repository.cleaner import Cleaner
|
||||
@ -36,7 +36,7 @@ class Executor(Cleaner):
|
||||
trait for common repository update processes
|
||||
"""
|
||||
|
||||
def load_archives(self, packages: Iterable[Path]) -> List[Package]:
|
||||
def load_archives(self, packages: Iterable[Path]) -> list[Package]:
|
||||
"""
|
||||
load packages from list of archives
|
||||
|
||||
@ -44,19 +44,19 @@ class Executor(Cleaner):
|
||||
packages(Iterable[Path]): paths to package archives
|
||||
|
||||
Returns:
|
||||
List[Package]: list of read packages
|
||||
list[Package]: list of read packages
|
||||
|
||||
Raises:
|
||||
NotImplementedError: not implemented method
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def packages(self) -> List[Package]:
|
||||
def packages(self) -> list[Package]:
|
||||
"""
|
||||
generate list of repository packages
|
||||
|
||||
Returns:
|
||||
List[Package]: list of packages properties
|
||||
list[Package]: list of packages properties
|
||||
|
||||
Raises:
|
||||
NotImplementedError: not implemented method
|
||||
@ -122,8 +122,8 @@ class Executor(Cleaner):
|
||||
except Exception:
|
||||
self.logger.exception("could not remove %s", package)
|
||||
|
||||
packages_to_remove: Dict[str, Path] = {}
|
||||
bases_to_remove: List[str] = []
|
||||
packages_to_remove: dict[str, Path] = {}
|
||||
bases_to_remove: list[str] = []
|
||||
|
||||
# build package list based on user input
|
||||
requested = set(packages)
|
||||
@ -177,7 +177,7 @@ class Executor(Cleaner):
|
||||
shutil.move(self.paths.packages / archive.filename, self.paths.packages / safe)
|
||||
archive.filename = safe
|
||||
|
||||
def update_single(name: Optional[str], package_base: str) -> None:
|
||||
def update_single(name: str | None, package_base: str) -> None:
|
||||
if name is None:
|
||||
self.logger.warning("received empty package name for base %s", package_base)
|
||||
return # suppress type checking, it never can be none actually
|
||||
@ -191,7 +191,7 @@ class Executor(Cleaner):
|
||||
self.repo.add(package_path)
|
||||
|
||||
current_packages = self.packages()
|
||||
removed_packages: List[str] = [] # list of packages which have been removed from the base
|
||||
removed_packages: list[str] = [] # list of packages which have been removed from the base
|
||||
updates = self.load_archives(packages)
|
||||
|
||||
result = Result()
|
||||
|
@ -19,8 +19,8 @@
|
||||
#
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Iterable
|
||||
from pathlib import Path
|
||||
from typing import Dict, Iterable, List, Optional, Type
|
||||
|
||||
from ahriman.core import _Context, context
|
||||
from ahriman.core.alpm.pacman import Pacman
|
||||
@ -58,7 +58,7 @@ class Repository(Executor, UpdateHandler):
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def load(cls: Type[Repository], architecture: str, configuration: Configuration, database: SQLite, *,
|
||||
def load(cls: type[Repository], architecture: str, configuration: Configuration, database: SQLite, *,
|
||||
report: bool, unsafe: bool, refresh_pacman_database: int = 0) -> Repository:
|
||||
"""
|
||||
load instance from argument list
|
||||
@ -99,7 +99,7 @@ class Repository(Executor, UpdateHandler):
|
||||
|
||||
context.set(ctx)
|
||||
|
||||
def load_archives(self, packages: Iterable[Path]) -> List[Package]:
|
||||
def load_archives(self, packages: Iterable[Path]) -> list[Package]:
|
||||
"""
|
||||
load packages from list of archives
|
||||
|
||||
@ -107,11 +107,11 @@ class Repository(Executor, UpdateHandler):
|
||||
packages(Iterable[Path]): paths to package archives
|
||||
|
||||
Returns:
|
||||
List[Package]: list of read packages
|
||||
list[Package]: list of read packages
|
||||
"""
|
||||
sources = self.database.remotes_get()
|
||||
|
||||
result: Dict[str, Package] = {}
|
||||
result: dict[str, Package] = {}
|
||||
# we are iterating over bases, not single packages
|
||||
for full_path in packages:
|
||||
try:
|
||||
@ -130,34 +130,34 @@ class Repository(Executor, UpdateHandler):
|
||||
self.logger.exception("could not load package from %s", full_path)
|
||||
return list(result.values())
|
||||
|
||||
def packages(self) -> List[Package]:
|
||||
def packages(self) -> list[Package]:
|
||||
"""
|
||||
generate list of repository packages
|
||||
|
||||
Returns:
|
||||
List[Package]: list of packages properties
|
||||
list[Package]: list of packages properties
|
||||
"""
|
||||
return self.load_archives(filter(package_like, self.paths.repository.iterdir()))
|
||||
|
||||
def packages_built(self) -> List[Path]:
|
||||
def packages_built(self) -> list[Path]:
|
||||
"""
|
||||
get list of files in built packages directory
|
||||
|
||||
Returns:
|
||||
List[Path]: list of filenames from the directory
|
||||
list[Path]: list of filenames from the directory
|
||||
"""
|
||||
return list(filter(package_like, self.paths.packages.iterdir()))
|
||||
|
||||
def packages_depend_on(self, packages: List[Package], depends_on: Optional[Iterable[str]]) -> List[Package]:
|
||||
def packages_depend_on(self, packages: list[Package], depends_on: Iterable[str] | None) -> list[Package]:
|
||||
"""
|
||||
extract list of packages which depends on specified package
|
||||
|
||||
Args:
|
||||
packages(List[Package]): list of packages to be filtered
|
||||
depends_on(Optional[Iterable[str]]): dependencies of the packages
|
||||
packages(list[Package]): list of packages to be filtered
|
||||
depends_on(Iterable[str] | None): dependencies of the packages
|
||||
|
||||
Returns:
|
||||
List[Package]: list of repository packages which depend on specified packages
|
||||
list[Package]: list of repository packages which depend on specified packages
|
||||
"""
|
||||
if depends_on is None:
|
||||
return packages # no list provided extract everything by default
|
||||
|
@ -37,7 +37,7 @@ class RepositoryProperties(LazyLogging):
|
||||
architecture(str): repository architecture
|
||||
configuration(Configuration): configuration instance
|
||||
database(SQLite): database instance
|
||||
ignore_list(List[str]): package bases which will be ignored during auto updates
|
||||
ignore_list(list[str]): package bases which will be ignored during auto updates
|
||||
name(str): repository name
|
||||
pacman(Pacman): alpm wrapper instance
|
||||
paths(RepositoryPaths): repository paths instance
|
||||
|
@ -17,7 +17,7 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
from typing import Iterable, List
|
||||
from collections.abc import Iterable
|
||||
|
||||
from ahriman.core.build_tools.sources import Sources
|
||||
from ahriman.core.repository.cleaner import Cleaner
|
||||
@ -30,19 +30,19 @@ class UpdateHandler(Cleaner):
|
||||
trait to get package update list
|
||||
"""
|
||||
|
||||
def packages(self) -> List[Package]:
|
||||
def packages(self) -> list[Package]:
|
||||
"""
|
||||
generate list of repository packages
|
||||
|
||||
Returns:
|
||||
List[Package]: list of packages properties
|
||||
list[Package]: list of packages properties
|
||||
|
||||
Raises:
|
||||
NotImplementedError: not implemented method
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def updates_aur(self, filter_packages: Iterable[str], *, vcs: bool) -> List[Package]:
|
||||
def updates_aur(self, filter_packages: Iterable[str], *, vcs: bool) -> list[Package]:
|
||||
"""
|
||||
check AUR for updates
|
||||
|
||||
@ -51,9 +51,9 @@ class UpdateHandler(Cleaner):
|
||||
vcs(bool): enable or disable checking of VCS packages
|
||||
|
||||
Returns:
|
||||
List[Package]: list of packages which are out-of-dated
|
||||
list[Package]: list of packages which are out-of-dated
|
||||
"""
|
||||
result: List[Package] = []
|
||||
result: list[Package] = []
|
||||
|
||||
for local in self.packages():
|
||||
with self.in_package_context(local.base):
|
||||
@ -81,7 +81,7 @@ class UpdateHandler(Cleaner):
|
||||
|
||||
return result
|
||||
|
||||
def updates_local(self, *, vcs: bool) -> List[Package]:
|
||||
def updates_local(self, *, vcs: bool) -> list[Package]:
|
||||
"""
|
||||
check local packages for updates
|
||||
|
||||
@ -89,9 +89,9 @@ class UpdateHandler(Cleaner):
|
||||
vcs(bool): enable or disable checking of VCS packages
|
||||
|
||||
Returns:
|
||||
List[Package]: list of local packages which are out-of-dated
|
||||
list[Package]: list of local packages which are out-of-dated
|
||||
"""
|
||||
result: List[Package] = []
|
||||
result: list[Package] = []
|
||||
packages = {local.base: local for local in self.packages()}
|
||||
|
||||
for cache_dir in self.paths.cache.iterdir():
|
||||
@ -114,14 +114,14 @@ class UpdateHandler(Cleaner):
|
||||
|
||||
return result
|
||||
|
||||
def updates_manual(self) -> List[Package]:
|
||||
def updates_manual(self) -> list[Package]:
|
||||
"""
|
||||
check for packages for which manual update has been requested
|
||||
|
||||
Returns:
|
||||
List[Package]: list of packages which are out-of-dated
|
||||
list[Package]: list of packages which are out-of-dated
|
||||
"""
|
||||
result: List[Package] = []
|
||||
result: list[Package] = []
|
||||
known_bases = {package.base for package in self.packages()}
|
||||
|
||||
try:
|
||||
|
@ -20,7 +20,6 @@
|
||||
import requests
|
||||
|
||||
from pathlib import Path
|
||||
from typing import List, Optional, Set, Tuple
|
||||
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.exceptions import BuildError
|
||||
@ -37,8 +36,8 @@ class GPG(LazyLogging):
|
||||
DEFAULT_TIMEOUT(int): (class attribute) HTTP request timeout in seconds
|
||||
architecture(str): repository architecture
|
||||
configuration(Configuration): configuration instance
|
||||
default_key(Optional[str]): default PGP key ID to use
|
||||
targets(Set[SignSettings]): list of targets to sign (repository, package etc)
|
||||
default_key(str | None): default PGP key ID to use
|
||||
targets(set[SignSettings]): list of targets to sign (repository, package etc)
|
||||
"""
|
||||
|
||||
_check_output = check_output
|
||||
@ -57,12 +56,12 @@ class GPG(LazyLogging):
|
||||
self.targets, self.default_key = self.sign_options(configuration)
|
||||
|
||||
@property
|
||||
def repository_sign_args(self) -> List[str]:
|
||||
def repository_sign_args(self) -> list[str]:
|
||||
"""
|
||||
get command line arguments based on settings
|
||||
|
||||
Returns:
|
||||
List[str]: command line arguments for repo-add command to sign database
|
||||
list[str]: command line arguments for repo-add command to sign database
|
||||
"""
|
||||
if SignSettings.Repository not in self.targets:
|
||||
return []
|
||||
@ -72,7 +71,7 @@ class GPG(LazyLogging):
|
||||
return ["--sign", "--key", self.default_key]
|
||||
|
||||
@staticmethod
|
||||
def sign_command(path: Path, key: str) -> List[str]:
|
||||
def sign_command(path: Path, key: str) -> list[str]:
|
||||
"""
|
||||
gpg command to run
|
||||
|
||||
@ -81,12 +80,12 @@ class GPG(LazyLogging):
|
||||
key(str): PGP key ID
|
||||
|
||||
Returns:
|
||||
List[str]: gpg command with all required arguments
|
||||
list[str]: gpg command with all required arguments
|
||||
"""
|
||||
return ["gpg", "-u", key, "-b", str(path)]
|
||||
|
||||
@staticmethod
|
||||
def sign_options(configuration: Configuration) -> Tuple[Set[SignSettings], Optional[str]]:
|
||||
def sign_options(configuration: Configuration) -> tuple[set[SignSettings], str | None]:
|
||||
"""
|
||||
extract default sign options from configuration
|
||||
|
||||
@ -94,9 +93,9 @@ class GPG(LazyLogging):
|
||||
configuration(Configuration): configuration instance
|
||||
|
||||
Returns:
|
||||
Tuple[Set[SignSettings], Optional[str]]: tuple of sign targets and default PGP key
|
||||
tuple[set[SignSettings], str | None]: tuple of sign targets and default PGP key
|
||||
"""
|
||||
targets: Set[SignSettings] = set()
|
||||
targets: set[SignSettings] = set()
|
||||
for option in configuration.getlist("sign", "target", fallback=[]):
|
||||
target = SignSettings.from_option(option)
|
||||
if target == SignSettings.Disabled:
|
||||
@ -140,7 +139,7 @@ class GPG(LazyLogging):
|
||||
key_body = self.key_download(server, key)
|
||||
GPG._check_output("gpg", "--import", input_data=key_body, logger=self.logger)
|
||||
|
||||
def process(self, path: Path, key: str) -> List[Path]:
|
||||
def process(self, path: Path, key: str) -> list[Path]:
|
||||
"""
|
||||
gpg command wrapper
|
||||
|
||||
@ -149,7 +148,7 @@ class GPG(LazyLogging):
|
||||
key(str): PGP key ID
|
||||
|
||||
Returns:
|
||||
List[Path]: list of generated files including original file
|
||||
list[Path]: list of generated files including original file
|
||||
"""
|
||||
GPG._check_output(
|
||||
*GPG.sign_command(path, key),
|
||||
@ -157,7 +156,7 @@ class GPG(LazyLogging):
|
||||
logger=self.logger)
|
||||
return [path, path.parent / f"{path.name}.sig"]
|
||||
|
||||
def process_sign_package(self, path: Path, package_base: str) -> List[Path]:
|
||||
def process_sign_package(self, path: Path, package_base: str) -> list[Path]:
|
||||
"""
|
||||
sign package if required by configuration
|
||||
|
||||
@ -166,7 +165,7 @@ class GPG(LazyLogging):
|
||||
package_base(str): package base required to check for key overrides
|
||||
|
||||
Returns:
|
||||
List[Path]: list of generated files including original file
|
||||
list[Path]: list of generated files including original file
|
||||
"""
|
||||
if SignSettings.Packages not in self.targets:
|
||||
return [path]
|
||||
@ -176,7 +175,7 @@ class GPG(LazyLogging):
|
||||
return [path]
|
||||
return self.process(path, key)
|
||||
|
||||
def process_sign_repository(self, path: Path) -> List[Path]:
|
||||
def process_sign_repository(self, path: Path) -> list[Path]:
|
||||
"""
|
||||
sign repository if required by configuration
|
||||
|
||||
@ -187,7 +186,7 @@ class GPG(LazyLogging):
|
||||
path(Path): path to repository database
|
||||
|
||||
Returns:
|
||||
List[Path]: list of generated files including original file
|
||||
list[Path]: list of generated files including original file
|
||||
"""
|
||||
if SignSettings.Repository not in self.targets:
|
||||
return [path]
|
||||
|
@ -22,9 +22,9 @@ from __future__ import annotations
|
||||
import argparse
|
||||
import uuid
|
||||
|
||||
from collections.abc import Callable, Iterable
|
||||
from multiprocessing import Process, Queue
|
||||
from threading import Lock, Thread
|
||||
from typing import Callable, Dict, Iterable, Optional, Tuple
|
||||
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.log import LazyLogging
|
||||
@ -37,10 +37,10 @@ class Spawn(Thread, LazyLogging):
|
||||
MUST NOT be used directly, the only one usage allowed is to spawn process from web services
|
||||
|
||||
Attributes:
|
||||
active(Dict[str, Process]): map of active child processes required to avoid zombies
|
||||
active(dict[str, Process]): map of active child processes required to avoid zombies
|
||||
architecture(str): repository architecture
|
||||
configuration(Configuration): configuration instance
|
||||
queue(Queue[Tuple[str, bool]]): multiprocessing queue to read updates from processes
|
||||
queue(Queue[tuple[str, bool]]): multiprocessing queue to read updates from processes
|
||||
"""
|
||||
|
||||
def __init__(self, args_parser: argparse.ArgumentParser, architecture: str, configuration: Configuration) -> None:
|
||||
@ -58,13 +58,13 @@ class Spawn(Thread, LazyLogging):
|
||||
self.configuration = configuration
|
||||
|
||||
self.lock = Lock()
|
||||
self.active: Dict[str, Process] = {}
|
||||
self.active: dict[str, Process] = {}
|
||||
# stupid pylint does not know that it is possible
|
||||
self.queue: Queue[Tuple[str, bool] | None] = Queue() # pylint: disable=unsubscriptable-object
|
||||
self.queue: Queue[tuple[str, bool] | None] = Queue() # pylint: disable=unsubscriptable-object
|
||||
|
||||
@staticmethod
|
||||
def process(callback: Callable[[argparse.Namespace, str], bool], args: argparse.Namespace, architecture: str,
|
||||
process_id: str, queue: Queue[Tuple[str, bool]]) -> None: # pylint: disable=unsubscriptable-object
|
||||
process_id: str, queue: Queue[tuple[str, bool]]) -> None: # pylint: disable=unsubscriptable-object
|
||||
"""
|
||||
helper to run external process
|
||||
|
||||
@ -73,7 +73,7 @@ class Spawn(Thread, LazyLogging):
|
||||
args(argparse.Namespace): command line arguments
|
||||
architecture(str): repository architecture
|
||||
process_id(str): process unique identifier
|
||||
queue(Queue[Tuple[str, bool]]): output queue
|
||||
queue(Queue[tuple[str, bool]]): output queue
|
||||
"""
|
||||
result = callback(args, architecture)
|
||||
queue.put((process_id, result))
|
||||
@ -113,13 +113,13 @@ class Spawn(Thread, LazyLogging):
|
||||
with self.lock:
|
||||
self.active[process_id] = process
|
||||
|
||||
def key_import(self, key: str, server: Optional[str]) -> None:
|
||||
def key_import(self, key: str, server: str | None) -> None:
|
||||
"""
|
||||
import key to service cache
|
||||
|
||||
Args:
|
||||
key(str): key to import
|
||||
server(str): PGP key server
|
||||
server(str | None): PGP key server
|
||||
"""
|
||||
kwargs = {} if server is None else {"key-server": server}
|
||||
self._spawn_process("service-key-import", key, **kwargs)
|
||||
@ -155,7 +155,7 @@ class Spawn(Thread, LazyLogging):
|
||||
"""
|
||||
self._spawn_process("package-remove", *packages)
|
||||
|
||||
def packages_update(self, ) -> None:
|
||||
def packages_update(self) -> None:
|
||||
"""
|
||||
run full repository update
|
||||
"""
|
||||
|
@ -21,8 +21,6 @@ from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
from typing import List, Optional, Tuple, Type
|
||||
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.models.build_status import BuildStatus, BuildStatusEnum
|
||||
from ahriman.models.internal_status import InternalStatus
|
||||
@ -35,7 +33,7 @@ class Client:
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def load(cls: Type[Client], configuration: Configuration, *, report: bool) -> Client:
|
||||
def load(cls: type[Client], configuration: Configuration, *, report: bool) -> Client:
|
||||
"""
|
||||
load client from settings
|
||||
|
||||
@ -71,15 +69,15 @@ class Client:
|
||||
status(BuildStatusEnum): current package build status
|
||||
"""
|
||||
|
||||
def get(self, package_base: Optional[str]) -> List[Tuple[Package, BuildStatus]]:
|
||||
def get(self, package_base: str | None) -> list[tuple[Package, BuildStatus]]:
|
||||
"""
|
||||
get package status
|
||||
|
||||
Args:
|
||||
package_base(Optional[str]): package base to get
|
||||
package_base(str | None): package base to get
|
||||
|
||||
Returns:
|
||||
List[Tuple[Package, BuildStatus]]: list of current package description and status if it has been found
|
||||
list[tuple[Package, BuildStatus]]: list of current package description and status if it has been found
|
||||
"""
|
||||
del package_base
|
||||
return []
|
||||
|
@ -19,8 +19,6 @@
|
||||
#
|
||||
import os
|
||||
|
||||
from typing import Dict, List, Optional, Tuple
|
||||
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.database import SQLite
|
||||
from ahriman.core.exceptions import UnknownPackageError
|
||||
@ -38,7 +36,7 @@ class Watcher(LazyLogging):
|
||||
Attributes:
|
||||
architecture(str): repository architecture
|
||||
database(SQLite): database instance
|
||||
known(Dict[str, Tuple[Package, BuildStatus]]): list of known packages. For the most cases ``packages`` should
|
||||
known(dict[str, tuple[Package, BuildStatus]]): list of known packages. For the most cases ``packages`` should
|
||||
be used instead
|
||||
repository(Repository): repository object
|
||||
status(BuildStatus): daemon status
|
||||
@ -57,23 +55,23 @@ class Watcher(LazyLogging):
|
||||
self.database = database
|
||||
self.repository = Repository.load(architecture, configuration, database, report=False, unsafe=False)
|
||||
|
||||
self.known: Dict[str, Tuple[Package, BuildStatus]] = {}
|
||||
self.known: dict[str, tuple[Package, BuildStatus]] = {}
|
||||
self.status = BuildStatus()
|
||||
|
||||
# special variables for updating logs
|
||||
self._last_log_record_id = LogRecordId("", os.getpid())
|
||||
|
||||
@property
|
||||
def packages(self) -> List[Tuple[Package, BuildStatus]]:
|
||||
def packages(self) -> list[tuple[Package, BuildStatus]]:
|
||||
"""
|
||||
get current known packages list
|
||||
|
||||
Returns:
|
||||
List[Tuple[Package, BuildStatus]]: list of packages together with their statuses
|
||||
list[tuple[Package, BuildStatus]]: list of packages together with their statuses
|
||||
"""
|
||||
return list(self.known.values())
|
||||
|
||||
def get(self, package_base: str) -> Tuple[Package, BuildStatus]:
|
||||
def get(self, package_base: str) -> tuple[Package, BuildStatus]:
|
||||
"""
|
||||
get current package base build status
|
||||
|
||||
@ -81,7 +79,7 @@ class Watcher(LazyLogging):
|
||||
package_base(str): package base
|
||||
|
||||
Returns:
|
||||
Tuple[Package, BuildStatus]: package and its status
|
||||
tuple[Package, BuildStatus]: package and its status
|
||||
|
||||
Raises:
|
||||
UnknownPackage: if no package found
|
||||
@ -130,24 +128,24 @@ class Watcher(LazyLogging):
|
||||
self.database.package_remove(package_base)
|
||||
self.remove_logs(package_base, None)
|
||||
|
||||
def remove_logs(self, package_base: str, current_process_id: Optional[int]) -> None:
|
||||
def remove_logs(self, package_base: str, current_process_id: int | None) -> None:
|
||||
"""
|
||||
remove package related logs
|
||||
|
||||
Args:
|
||||
package_base(str): package base
|
||||
current_process_id(int): current process id
|
||||
current_process_id(int | None): current process id
|
||||
"""
|
||||
self.database.logs_remove(package_base, current_process_id)
|
||||
|
||||
def update(self, package_base: str, status: BuildStatusEnum, package: Optional[Package]) -> None:
|
||||
def update(self, package_base: str, status: BuildStatusEnum, package: Package | None) -> None:
|
||||
"""
|
||||
update package status and description
|
||||
|
||||
Args:
|
||||
package_base(str): package base to update
|
||||
status(BuildStatusEnum): new build status
|
||||
package(Optional[Package]): optional new package description. In case if not set current properties will be used
|
||||
package(Package | None): optional package description. In case if not set current properties will be used
|
||||
|
||||
Raises:
|
||||
UnknownPackage: if no package found
|
||||
|
@ -21,7 +21,7 @@ import contextlib
|
||||
import logging
|
||||
import requests
|
||||
|
||||
from typing import Generator, List, Optional, Tuple
|
||||
from collections.abc import Generator
|
||||
from urllib.parse import quote_plus as urlencode
|
||||
|
||||
from ahriman.core.configuration import Configuration
|
||||
@ -40,7 +40,7 @@ class WebClient(Client, LazyLogging):
|
||||
|
||||
Attributes:
|
||||
address(str): address of the web service
|
||||
user(Optional[User]): web service user descriptor
|
||||
user(User | None): web service user descriptor
|
||||
"""
|
||||
|
||||
def __init__(self, configuration: Configuration) -> None:
|
||||
@ -78,7 +78,7 @@ class WebClient(Client, LazyLogging):
|
||||
return f"{self.address}/api/v1/status"
|
||||
|
||||
@staticmethod
|
||||
def parse_address(configuration: Configuration) -> Tuple[str, bool]:
|
||||
def parse_address(configuration: Configuration) -> tuple[str, bool]:
|
||||
"""
|
||||
parse address from configuration
|
||||
|
||||
@ -86,7 +86,7 @@ class WebClient(Client, LazyLogging):
|
||||
configuration(Configuration): configuration instance
|
||||
|
||||
Returns:
|
||||
Tuple[str, bool]: tuple of server address and socket flag (True in case if unix socket must be used)
|
||||
tuple[str, bool]: tuple of server address and socket flag (True in case if unix socket must be used)
|
||||
"""
|
||||
if (unix_socket := configuration.get("web", "unix_socket", fallback=None)) is not None:
|
||||
# special pseudo-protocol which is used for unix sockets
|
||||
@ -190,15 +190,15 @@ class WebClient(Client, LazyLogging):
|
||||
response = self.__session.post(self._package_url(package.base), json=payload)
|
||||
response.raise_for_status()
|
||||
|
||||
def get(self, package_base: Optional[str]) -> List[Tuple[Package, BuildStatus]]:
|
||||
def get(self, package_base: str | None) -> list[tuple[Package, BuildStatus]]:
|
||||
"""
|
||||
get package status
|
||||
|
||||
Args:
|
||||
package_base(Optional[str]): package base to get
|
||||
package_base(str | None): package base to get
|
||||
|
||||
Returns:
|
||||
List[Tuple[Package, BuildStatus]]: list of current package description and status if it has been found
|
||||
list[tuple[Package, BuildStatus]]: list of current package description and status if it has been found
|
||||
"""
|
||||
with self.__execute_request():
|
||||
response = self.__session.get(self._package_url(package_base or ""))
|
||||
|
@ -21,7 +21,7 @@ from __future__ import annotations
|
||||
|
||||
import functools
|
||||
|
||||
from typing import Callable, Iterable, List
|
||||
from collections.abc import Callable, Iterable
|
||||
|
||||
from ahriman.core.util import partition
|
||||
from ahriman.models.package import Package
|
||||
@ -32,7 +32,7 @@ class Leaf:
|
||||
tree leaf implementation
|
||||
|
||||
Attributes:
|
||||
dependencies(Set[str]): list of package dependencies
|
||||
dependencies(set[str]): list of package dependencies
|
||||
package(Package): leaf package properties
|
||||
"""
|
||||
|
||||
@ -92,7 +92,7 @@ class Tree:
|
||||
dependency tree implementation
|
||||
|
||||
Attributes:
|
||||
leaves[List[Leaf]): list of tree leaves
|
||||
leaves[list[Leaf]): list of tree leaves
|
||||
|
||||
Examples:
|
||||
The most important feature here is to generate tree levels one by one which can be achieved by using class
|
||||
@ -119,17 +119,17 @@ class Tree:
|
||||
>>> tree = Tree(leaves)
|
||||
"""
|
||||
|
||||
def __init__(self, leaves: List[Leaf]) -> None:
|
||||
def __init__(self, leaves: list[Leaf]) -> None:
|
||||
"""
|
||||
default constructor
|
||||
|
||||
Args:
|
||||
leaves(List[Leaf]): leaves to build the tree
|
||||
leaves(list[Leaf]): leaves to build the tree
|
||||
"""
|
||||
self.leaves = leaves
|
||||
|
||||
@staticmethod
|
||||
def resolve(packages: Iterable[Package]) -> List[List[Package]]:
|
||||
def resolve(packages: Iterable[Package]) -> list[list[Package]]:
|
||||
"""
|
||||
resolve dependency tree
|
||||
|
||||
@ -137,20 +137,20 @@ class Tree:
|
||||
packages(Iterable[Package]): packages list
|
||||
|
||||
Returns:
|
||||
List[List[Package]]: list of packages lists based on their dependencies
|
||||
list[list[Package]]: list of packages lists based on their dependencies
|
||||
"""
|
||||
leaves = [Leaf(package) for package in packages]
|
||||
instance = Tree(leaves)
|
||||
return instance.levels()
|
||||
|
||||
def levels(self) -> List[List[Package]]:
|
||||
def levels(self) -> list[list[Package]]:
|
||||
"""
|
||||
get build levels starting from the packages which do not require any other package to build
|
||||
|
||||
Returns:
|
||||
List[List[Package]]: sorted list of packages lists based on their dependencies
|
||||
list[list[Package]]: sorted list of packages lists based on their dependencies
|
||||
"""
|
||||
unsorted: List[List[Leaf]] = []
|
||||
unsorted: list[list[Leaf]] = []
|
||||
|
||||
# build initial tree
|
||||
unprocessed = self.leaves[:]
|
||||
|
@ -19,8 +19,6 @@
|
||||
#
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Iterable, List, Optional, Type
|
||||
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.configuration.schema import ConfigurationSchema
|
||||
from ahriman.core.log import LazyLogging
|
||||
@ -34,7 +32,7 @@ class Trigger(LazyLogging):
|
||||
|
||||
Attributes:
|
||||
CONFIGURATION_SCHEMA(ConfigurationSchema): (class attribute) configuration schema template
|
||||
CONFIGURATION_SCHEMA_FALLBACK(Optional[str]): (class attribute) optional fallback option for defining
|
||||
CONFIGURATION_SCHEMA_FALLBACK(str | None): (class attribute) optional fallback option for defining
|
||||
configuration schema type used
|
||||
architecture(str): repository architecture
|
||||
configuration(Configuration): configuration instance
|
||||
@ -43,7 +41,7 @@ class Trigger(LazyLogging):
|
||||
This class must be used in order to create own extension. Basically idea is the following::
|
||||
|
||||
>>> class CustomTrigger(Trigger):
|
||||
>>> def on_result(self, result: Result, packages: Iterable[Package]) -> None:
|
||||
>>> def on_result(self, result: Result, packages: list[Package]) -> None:
|
||||
>>> perform_some_action()
|
||||
|
||||
Having this class you can pass it to ``configuration`` and it will be run on action::
|
||||
@ -58,7 +56,7 @@ class Trigger(LazyLogging):
|
||||
"""
|
||||
|
||||
CONFIGURATION_SCHEMA: ConfigurationSchema = {}
|
||||
CONFIGURATION_SCHEMA_FALLBACK: Optional[str] = None
|
||||
CONFIGURATION_SCHEMA_FALLBACK: str | None = None
|
||||
|
||||
def __init__(self, architecture: str, configuration: Configuration) -> None:
|
||||
"""
|
||||
@ -72,8 +70,8 @@ class Trigger(LazyLogging):
|
||||
self.configuration = configuration
|
||||
|
||||
@classmethod
|
||||
def configuration_schema(cls: Type[Trigger], architecture: str,
|
||||
configuration: Optional[Configuration]) -> ConfigurationSchema:
|
||||
def configuration_schema(cls: type[Trigger], architecture: str,
|
||||
configuration: Configuration | None) -> ConfigurationSchema:
|
||||
"""
|
||||
configuration schema based on supplied service configuration
|
||||
|
||||
@ -82,7 +80,7 @@ class Trigger(LazyLogging):
|
||||
|
||||
Args:
|
||||
architecture(str): repository architecture
|
||||
configuration(Optional[Configuration]): configuration instance. If set to None, the default schema
|
||||
configuration(Configuration | None): configuration instance. If set to None, the default schema
|
||||
should be returned
|
||||
|
||||
Returns:
|
||||
@ -104,7 +102,7 @@ class Trigger(LazyLogging):
|
||||
return result
|
||||
|
||||
@classmethod
|
||||
def configuration_sections(cls: Type[Trigger], configuration: Configuration) -> List[str]:
|
||||
def configuration_sections(cls: type[Trigger], configuration: Configuration) -> list[str]:
|
||||
"""
|
||||
extract configuration sections from configuration
|
||||
|
||||
@ -112,26 +110,26 @@ class Trigger(LazyLogging):
|
||||
configuration(Configuration): configuration instance
|
||||
|
||||
Returns:
|
||||
List[str]: read configuration sections belong to this trigger
|
||||
list[str]: read configuration sections belong to this trigger
|
||||
|
||||
Examples:
|
||||
This method can be used in order to extract specific configuration sections which are set by user, e.g.
|
||||
from sources::
|
||||
|
||||
>>> @staticmethod
|
||||
>>> def configuration_sections(cls: Type[Trigger], configuration: Configuration) -> List[str]:
|
||||
>>> def configuration_sections(cls: type[Trigger], configuration: Configuration) -> list[str]:
|
||||
>>> return configuration.getlist("report", "target", fallback=[])
|
||||
"""
|
||||
del configuration
|
||||
return []
|
||||
|
||||
def on_result(self, result: Result, packages: Iterable[Package]) -> None:
|
||||
def on_result(self, result: Result, packages: list[Package]) -> None:
|
||||
"""
|
||||
trigger action which will be called after build process with process result
|
||||
|
||||
Args:
|
||||
result(Result): build result
|
||||
packages(Iterable[Package]): list of all available packages
|
||||
packages(list[Package]): list of all available packages
|
||||
"""
|
||||
if (run := getattr(self, "run", None)) is not None:
|
||||
run(result, packages) # compatibility with old triggers
|
||||
|
@ -23,9 +23,9 @@ import contextlib
|
||||
import importlib
|
||||
import os
|
||||
|
||||
from collections.abc import Generator
|
||||
from pathlib import Path
|
||||
from types import ModuleType
|
||||
from typing import Generator, Iterable, List, Type
|
||||
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.exceptions import ExtensionError
|
||||
@ -40,7 +40,7 @@ class TriggerLoader(LazyLogging):
|
||||
trigger loader class
|
||||
|
||||
Attributes:
|
||||
triggers(List[Trigger]): list of loaded triggers according to the configuration
|
||||
triggers(list[Trigger]): list of loaded triggers according to the configuration
|
||||
|
||||
Examples:
|
||||
This class more likely must not be used directly, but the usual workflow is the following::
|
||||
@ -63,10 +63,10 @@ class TriggerLoader(LazyLogging):
|
||||
default constructor
|
||||
"""
|
||||
self._on_stop_requested = False
|
||||
self.triggers: List[Trigger] = []
|
||||
self.triggers: list[Trigger] = []
|
||||
|
||||
@classmethod
|
||||
def load(cls: Type[TriggerLoader], architecture: str, configuration: Configuration) -> TriggerLoader:
|
||||
def load(cls: type[TriggerLoader], architecture: str, configuration: Configuration) -> TriggerLoader:
|
||||
"""
|
||||
create instance from configuration
|
||||
|
||||
@ -86,7 +86,7 @@ class TriggerLoader(LazyLogging):
|
||||
return instance
|
||||
|
||||
@staticmethod
|
||||
def selected_triggers(configuration: Configuration) -> List[str]:
|
||||
def selected_triggers(configuration: Configuration) -> list[str]:
|
||||
"""
|
||||
read configuration and return triggers which are set by settings
|
||||
|
||||
@ -94,7 +94,7 @@ class TriggerLoader(LazyLogging):
|
||||
configuration(Configuration): configuration instance
|
||||
|
||||
Returns:
|
||||
List[str]: list of triggers according to configuration
|
||||
list[str]: list of triggers according to configuration
|
||||
"""
|
||||
return configuration.getlist("build", "triggers", fallback=[])
|
||||
|
||||
@ -176,7 +176,7 @@ class TriggerLoader(LazyLogging):
|
||||
|
||||
return trigger
|
||||
|
||||
def load_trigger_class(self, module_path: str) -> Type[Trigger]:
|
||||
def load_trigger_class(self, module_path: str) -> type[Trigger]:
|
||||
"""
|
||||
load trigger class by module path
|
||||
|
||||
@ -184,7 +184,7 @@ class TriggerLoader(LazyLogging):
|
||||
module_path(str): module import path to load
|
||||
|
||||
Returns:
|
||||
Type[Trigger]: loaded trigger type by module path
|
||||
type[Trigger]: loaded trigger type by module path
|
||||
|
||||
Raises:
|
||||
InvalidExtension: in case if module cannot be loaded from the specified module path or is not a trigger
|
||||
@ -208,13 +208,13 @@ class TriggerLoader(LazyLogging):
|
||||
self.logger.info("loaded type %s of package %s", class_name, package_or_path)
|
||||
return trigger_type
|
||||
|
||||
def on_result(self, result: Result, packages: Iterable[Package]) -> None:
|
||||
def on_result(self, result: Result, packages: list[Package]) -> None:
|
||||
"""
|
||||
run trigger with result of application run
|
||||
|
||||
Args:
|
||||
result(Result): build result
|
||||
packages(Iterable[Package]): list of all available packages
|
||||
packages(list[Package]): list of all available packages
|
||||
"""
|
||||
self.logger.debug("executing triggers on result")
|
||||
for trigger in self.triggers:
|
||||
|
@ -21,7 +21,7 @@ import mimetypes
|
||||
import requests
|
||||
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, Iterable, Optional
|
||||
from typing import Any
|
||||
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.upload.http_upload import HttpUpload
|
||||
@ -51,12 +51,12 @@ class Github(HttpUpload):
|
||||
self.github_owner = configuration.get(section, "owner")
|
||||
self.github_repository = configuration.get(section, "repository")
|
||||
|
||||
def asset_remove(self, release: Dict[str, Any], name: str) -> None:
|
||||
def asset_remove(self, release: dict[str, Any], name: str) -> None:
|
||||
"""
|
||||
remove asset from the release by name
|
||||
|
||||
Args:
|
||||
release(Dict[str, Any]): release object
|
||||
release(dict[str, Any]): release object
|
||||
name(str): asset name
|
||||
"""
|
||||
try:
|
||||
@ -65,12 +65,12 @@ class Github(HttpUpload):
|
||||
except StopIteration:
|
||||
self.logger.info("no asset %s found in release %s", name, release["name"])
|
||||
|
||||
def asset_upload(self, release: Dict[str, Any], path: Path) -> None:
|
||||
def asset_upload(self, release: dict[str, Any], path: Path) -> None:
|
||||
"""
|
||||
upload asset to the release
|
||||
|
||||
Args:
|
||||
release(Dict[str, Any]): release object
|
||||
release(dict[str, Any]): release object
|
||||
path(Path): path to local file
|
||||
"""
|
||||
exists = any(path.name == asset["name"] for asset in release["assets"])
|
||||
@ -81,7 +81,7 @@ class Github(HttpUpload):
|
||||
headers = {"Content-Type": mime} if mime is not None else {"Content-Type": "application/octet-stream"}
|
||||
self._request("POST", url, params={"name": path.name}, data=path.open("rb"), headers=headers)
|
||||
|
||||
def get_local_files(self, path: Path) -> Dict[Path, str]:
|
||||
def get_local_files(self, path: Path) -> dict[Path, str]:
|
||||
"""
|
||||
get all local files and their calculated checksums
|
||||
|
||||
@ -89,21 +89,21 @@ class Github(HttpUpload):
|
||||
path(Path): local path to sync
|
||||
|
||||
Returns:
|
||||
Dict[Path, str]: map of path objects to its checksum
|
||||
dict[Path, str]: map of path objects to its checksum
|
||||
"""
|
||||
return {
|
||||
local_file: self.calculate_hash(local_file)
|
||||
for local_file in walk(path)
|
||||
}
|
||||
|
||||
def files_remove(self, release: Dict[str, Any], local_files: Dict[Path, str], remote_files: Dict[str, str]) -> None:
|
||||
def files_remove(self, release: dict[str, Any], local_files: dict[Path, str], remote_files: dict[str, str]) -> None:
|
||||
"""
|
||||
remove files from github
|
||||
|
||||
Args:
|
||||
release(Dict[str, Any]): release object
|
||||
local_files(Dict[Path, str]): map of local file paths to its checksum
|
||||
remote_files(Dict[str, str]): map of the remote files and its checksum
|
||||
release(dict[str, Any]): release object
|
||||
local_files(dict[Path, str]): map of local file paths to its checksum
|
||||
remote_files(dict[str, str]): map of the remote files and its checksum
|
||||
"""
|
||||
local_filenames = {local_file.name for local_file in local_files}
|
||||
for remote_file in remote_files:
|
||||
@ -111,14 +111,14 @@ class Github(HttpUpload):
|
||||
continue
|
||||
self.asset_remove(release, remote_file)
|
||||
|
||||
def files_upload(self, release: Dict[str, Any], local_files: Dict[Path, str], remote_files: Dict[str, str]) -> None:
|
||||
def files_upload(self, release: dict[str, Any], local_files: dict[Path, str], remote_files: dict[str, str]) -> None:
|
||||
"""
|
||||
upload files to github
|
||||
|
||||
Args:
|
||||
release(Dict[str, Any]): release object
|
||||
local_files(Dict[Path, str]): map of local file paths to its checksum
|
||||
remote_files(Dict[str, str]): map of the remote files and its checksum
|
||||
release(dict[str, Any]): release object
|
||||
local_files(dict[Path, str]): map of local file paths to its checksum
|
||||
remote_files(dict[str, str]): map of the remote files and its checksum
|
||||
"""
|
||||
for local_file, checksum in local_files.items():
|
||||
remote_checksum = remote_files.get(local_file.name)
|
||||
@ -126,29 +126,29 @@ class Github(HttpUpload):
|
||||
continue
|
||||
self.asset_upload(release, local_file)
|
||||
|
||||
def release_create(self) -> Dict[str, Any]:
|
||||
def release_create(self) -> dict[str, Any]:
|
||||
"""
|
||||
create empty release
|
||||
|
||||
Returns:
|
||||
Dict[str, Any]: github API release object for the new release
|
||||
dict[str, Any]: github API release object for the new release
|
||||
"""
|
||||
url = f"https://api.github.com/repos/{self.github_owner}/{self.github_repository}/releases"
|
||||
response = self._request("POST", url, json={"tag_name": self.architecture, "name": self.architecture})
|
||||
release: Dict[str, Any] = response.json()
|
||||
release: dict[str, Any] = response.json()
|
||||
return release
|
||||
|
||||
def release_get(self) -> Optional[Dict[str, Any]]:
|
||||
def release_get(self) -> dict[str, Any] | None:
|
||||
"""
|
||||
get release object if any
|
||||
|
||||
Returns:
|
||||
Optional[Dict[str, Any]]: github API release object if release found and None otherwise
|
||||
dict[str, Any] | None: github API release object if release found and None otherwise
|
||||
"""
|
||||
url = f"https://api.github.com/repos/{self.github_owner}/{self.github_repository}/releases/tags/{self.architecture}"
|
||||
try:
|
||||
response = self._request("GET", url)
|
||||
release: Dict[str, Any] = response.json()
|
||||
release: dict[str, Any] = response.json()
|
||||
return release
|
||||
except requests.HTTPError as e:
|
||||
status_code = e.response.status_code if e.response is not None else None
|
||||
@ -156,23 +156,23 @@ class Github(HttpUpload):
|
||||
return None
|
||||
raise
|
||||
|
||||
def release_update(self, release: Dict[str, Any], body: str) -> None:
|
||||
def release_update(self, release: dict[str, Any], body: str) -> None:
|
||||
"""
|
||||
update release
|
||||
|
||||
Args:
|
||||
release(Dict[str, Any]): release object
|
||||
release(dict[str, Any]): release object
|
||||
body(str): new release body
|
||||
"""
|
||||
self._request("POST", release["url"], json={"body": body})
|
||||
|
||||
def sync(self, path: Path, built_packages: Iterable[Package]) -> None:
|
||||
def sync(self, path: Path, built_packages: list[Package]) -> None:
|
||||
"""
|
||||
sync data to remote server
|
||||
|
||||
Args:
|
||||
path(Path): local path to sync
|
||||
built_packages(Iterable[Package]): list of packages which has just been built
|
||||
built_packages(list[Package]): list of packages which has just been built
|
||||
"""
|
||||
release = self.release_get()
|
||||
if release is None:
|
||||
|
@ -21,7 +21,7 @@ import hashlib
|
||||
import requests
|
||||
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict
|
||||
from typing import Any
|
||||
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.upload.upload import Upload
|
||||
@ -33,7 +33,7 @@ class HttpUpload(Upload):
|
||||
helper for the http based uploads
|
||||
|
||||
Attributes:
|
||||
auth(Optional[Tuple[str, str]]): HTTP auth object if set
|
||||
auth(tuple[str, str] | None): HTTP auth object if set
|
||||
timeout(int): HTTP request timeout in seconds
|
||||
"""
|
||||
|
||||
@ -68,12 +68,12 @@ class HttpUpload(Upload):
|
||||
return md5.hexdigest()
|
||||
|
||||
@staticmethod
|
||||
def get_body(local_files: Dict[Path, str]) -> str:
|
||||
def get_body(local_files: dict[Path, str]) -> str:
|
||||
"""
|
||||
generate release body from the checksums as returned from HttpUpload.get_hashes method
|
||||
|
||||
Args:
|
||||
local_files(Dict[Path, str]): map of the paths to its checksum
|
||||
local_files(dict[Path, str]): map of the paths to its checksum
|
||||
|
||||
Returns:
|
||||
str: body to be inserted into release
|
||||
@ -81,7 +81,7 @@ class HttpUpload(Upload):
|
||||
return "\n".join(f"{file.name} {md5}" for file, md5 in sorted(local_files.items()))
|
||||
|
||||
@staticmethod
|
||||
def get_hashes(body: str) -> Dict[str, str]:
|
||||
def get_hashes(body: str) -> dict[str, str]:
|
||||
"""
|
||||
get checksums of the content from the repository
|
||||
|
||||
@ -89,7 +89,7 @@ class HttpUpload(Upload):
|
||||
body(str): release string body object
|
||||
|
||||
Returns:
|
||||
Dict[str, str]: map of the filename to its checksum as it is written in body
|
||||
dict[str, str]: map of the filename to its checksum as it is written in body
|
||||
"""
|
||||
files = {}
|
||||
for line in body.splitlines():
|
||||
|
@ -18,7 +18,6 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
from pathlib import Path
|
||||
from typing import Iterable
|
||||
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.upload.upload import Upload
|
||||
@ -31,7 +30,7 @@ class Rsync(Upload):
|
||||
rsync wrapper
|
||||
|
||||
Attributes:
|
||||
command(List[str]): command arguments for sync
|
||||
command(list[str]): command arguments for sync
|
||||
remote(str): remote address to sync
|
||||
"""
|
||||
|
||||
@ -50,12 +49,12 @@ class Rsync(Upload):
|
||||
self.command = configuration.getlist(section, "command")
|
||||
self.remote = configuration.get(section, "remote")
|
||||
|
||||
def sync(self, path: Path, built_packages: Iterable[Package]) -> None:
|
||||
def sync(self, path: Path, built_packages: list[Package]) -> None:
|
||||
"""
|
||||
sync data to remote server
|
||||
|
||||
Args:
|
||||
path(Path): local path to sync
|
||||
built_packages(Iterable[Package]): list of packages which has just been built
|
||||
built_packages(list[Package]): list of packages which has just been built
|
||||
"""
|
||||
Rsync._check_output(*self.command, str(path), self.remote, logger=self.logger)
|
||||
|
@ -22,7 +22,7 @@ import hashlib
|
||||
import mimetypes
|
||||
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, Iterable
|
||||
from typing import Any
|
||||
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.upload.upload import Upload
|
||||
@ -97,27 +97,27 @@ class S3(Upload):
|
||||
return client.Bucket(configuration.get(section, "bucket"))
|
||||
|
||||
@staticmethod
|
||||
def files_remove(local_files: Dict[Path, str], remote_objects: Dict[Path, Any]) -> None:
|
||||
def files_remove(local_files: dict[Path, str], remote_objects: dict[Path, Any]) -> None:
|
||||
"""
|
||||
remove files which have been removed locally
|
||||
|
||||
Args:
|
||||
local_files(Dict[Path, str]): map of local path object to its checksum
|
||||
remote_objects(Dict[Path, Any]): map of remote path object to the remote s3 object
|
||||
local_files(dict[Path, str]): map of local path object to its checksum
|
||||
remote_objects(dict[Path, Any]): map of remote path object to the remote s3 object
|
||||
"""
|
||||
for local_file, remote_object in remote_objects.items():
|
||||
if local_file in local_files:
|
||||
continue
|
||||
remote_object.delete()
|
||||
|
||||
def files_upload(self, path: Path, local_files: Dict[Path, str], remote_objects: Dict[Path, Any]) -> None:
|
||||
def files_upload(self, path: Path, local_files: dict[Path, str], remote_objects: dict[Path, Any]) -> None:
|
||||
"""
|
||||
upload changed files to s3
|
||||
|
||||
Args:
|
||||
path(Path): local path to sync
|
||||
local_files(Dict[Path, str]): map of local path object to its checksum
|
||||
remote_objects(Dict[Path, Any]): map of remote path object to the remote s3 object
|
||||
local_files(dict[Path, str]): map of local path object to its checksum
|
||||
remote_objects(dict[Path, Any]): map of remote path object to the remote s3 object
|
||||
"""
|
||||
for local_file, checksum in local_files.items():
|
||||
remote_object = remote_objects.get(local_file)
|
||||
@ -133,7 +133,7 @@ class S3(Upload):
|
||||
|
||||
self.bucket.upload_file(Filename=str(local_path), Key=str(remote_path), ExtraArgs=extra_args)
|
||||
|
||||
def get_local_files(self, path: Path) -> Dict[Path, str]:
|
||||
def get_local_files(self, path: Path) -> dict[Path, str]:
|
||||
"""
|
||||
get all local files and their calculated checksums
|
||||
|
||||
@ -141,30 +141,30 @@ class S3(Upload):
|
||||
path(Path): local path to sync
|
||||
|
||||
Returns:
|
||||
Dict[Path, str]: map of path object to its checksum
|
||||
dict[Path, str]: map of path object to its checksum
|
||||
"""
|
||||
return {
|
||||
local_file.relative_to(path): self.calculate_etag(local_file, self.chunk_size)
|
||||
for local_file in walk(path)
|
||||
}
|
||||
|
||||
def get_remote_objects(self) -> Dict[Path, Any]:
|
||||
def get_remote_objects(self) -> dict[Path, Any]:
|
||||
"""
|
||||
get all remote objects and their checksums
|
||||
|
||||
Returns:
|
||||
Dict[Path, Any]: map of path object to the remote s3 object
|
||||
dict[Path, Any]: map of path object to the remote s3 object
|
||||
"""
|
||||
objects = self.bucket.objects.filter(Prefix=self.architecture)
|
||||
return {Path(item.key).relative_to(self.architecture): item for item in objects}
|
||||
|
||||
def sync(self, path: Path, built_packages: Iterable[Package]) -> None:
|
||||
def sync(self, path: Path, built_packages: list[Package]) -> None:
|
||||
"""
|
||||
sync data to remote server
|
||||
|
||||
Args:
|
||||
path(Path): local path to sync
|
||||
built_packages(Iterable[Package]): list of packages which has just been built
|
||||
built_packages(list[Package]): list of packages which has just been built
|
||||
"""
|
||||
remote_objects = self.get_remote_objects()
|
||||
local_files = self.get_local_files(path)
|
||||
|
@ -20,7 +20,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
from typing import Iterable, Type
|
||||
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.exceptions import SynchronizationError
|
||||
@ -68,7 +67,7 @@ class Upload(LazyLogging):
|
||||
self.configuration = configuration
|
||||
|
||||
@classmethod
|
||||
def load(cls: Type[Upload], architecture: str, configuration: Configuration, target: str) -> Upload:
|
||||
def load(cls: type[Upload], architecture: str, configuration: Configuration, target: str) -> Upload:
|
||||
"""
|
||||
load client from settings
|
||||
|
||||
@ -93,13 +92,13 @@ class Upload(LazyLogging):
|
||||
return Github(architecture, configuration, section)
|
||||
return cls(architecture, configuration) # should never happen
|
||||
|
||||
def run(self, path: Path, built_packages: Iterable[Package]) -> None:
|
||||
def run(self, path: Path, built_packages: list[Package]) -> None:
|
||||
"""
|
||||
run remote sync
|
||||
|
||||
Args:
|
||||
path(Path): local path to sync
|
||||
built_packages(Iterable[Package]): list of packages which has just been built
|
||||
built_packages(list[Package]): list of packages which has just been built
|
||||
|
||||
Raises:
|
||||
SyncFailed: in case of any synchronization unmatched exception
|
||||
@ -110,11 +109,11 @@ class Upload(LazyLogging):
|
||||
self.logger.exception("remote sync failed")
|
||||
raise SynchronizationError()
|
||||
|
||||
def sync(self, path: Path, built_packages: Iterable[Package]) -> None:
|
||||
def sync(self, path: Path, built_packages: list[Package]) -> None:
|
||||
"""
|
||||
sync data to remote server
|
||||
|
||||
Args:
|
||||
path(Path): local path to sync
|
||||
built_packages(Iterable[Package]): list of packages which has just been built
|
||||
built_packages(list[Package]): list of packages which has just been built
|
||||
"""
|
||||
|
@ -17,8 +17,6 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
from typing import Iterable, List, Type
|
||||
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.triggers import Trigger
|
||||
from ahriman.core.upload.upload import Upload
|
||||
@ -31,7 +29,7 @@ class UploadTrigger(Trigger):
|
||||
synchronization trigger
|
||||
|
||||
Attributes:
|
||||
targets(List[str]): upload target list
|
||||
targets(list[str]): upload target list
|
||||
"""
|
||||
|
||||
CONFIGURATION_SCHEMA = {
|
||||
@ -138,7 +136,7 @@ class UploadTrigger(Trigger):
|
||||
self.targets = self.configuration_sections(configuration)
|
||||
|
||||
@classmethod
|
||||
def configuration_sections(cls: Type[Trigger], configuration: Configuration) -> List[str]:
|
||||
def configuration_sections(cls: type[Trigger], configuration: Configuration) -> list[str]:
|
||||
"""
|
||||
extract configuration sections from configuration
|
||||
|
||||
@ -146,17 +144,17 @@ class UploadTrigger(Trigger):
|
||||
configuration(Configuration): configuration instance
|
||||
|
||||
Returns:
|
||||
List[str]: read configuration sections belong to this trigger
|
||||
list[str]: read configuration sections belong to this trigger
|
||||
"""
|
||||
return configuration.getlist("upload", "target", fallback=[])
|
||||
|
||||
def on_result(self, result: Result, packages: Iterable[Package]) -> None:
|
||||
def on_result(self, result: Result, packages: list[Package]) -> None:
|
||||
"""
|
||||
run trigger
|
||||
|
||||
Args:
|
||||
result(Result): build result
|
||||
packages(Iterable[Package]): list of all available packages
|
||||
packages(list[Package]): list of all available packages
|
||||
"""
|
||||
for target in self.targets:
|
||||
runner = Upload.load(self.architecture, self.configuration, target)
|
||||
|
@ -26,10 +26,11 @@ import re
|
||||
import requests
|
||||
import subprocess
|
||||
|
||||
from collections.abc import Callable, Generator, Iterable
|
||||
from enum import Enum
|
||||
from pathlib import Path
|
||||
from pwd import getpwuid
|
||||
from typing import Any, Callable, Dict, Generator, IO, Iterable, List, Optional, Tuple, Type, TypeVar, Union
|
||||
from typing import Any, IO, TypeVar
|
||||
|
||||
from ahriman.core.exceptions import OptionError, UnsafeRunError
|
||||
from ahriman.models.repository_paths import RepositoryPaths
|
||||
@ -56,20 +57,19 @@ __all__ = [
|
||||
T = TypeVar("T")
|
||||
|
||||
|
||||
def check_output(*args: str, exception: Optional[Exception] = None, cwd: Optional[Path] = None,
|
||||
input_data: Optional[str] = None, logger: Optional[logging.Logger] = None,
|
||||
user: Optional[int] = None) -> str:
|
||||
def check_output(*args: str, exception: Exception | None = None, cwd: Path | None = None, input_data: str | None = None,
|
||||
logger: logging.Logger | None = None, user: int | None = None) -> str:
|
||||
"""
|
||||
subprocess wrapper
|
||||
|
||||
Args:
|
||||
*args(str): command line arguments
|
||||
exception(Optional[Exception], optional): exception which has to be reraised instead of default subprocess
|
||||
exception(Exception | None, optional): exception which has to be reraised instead of default subprocess
|
||||
exception (Default value = None)
|
||||
cwd(Optional[Path], optional): current working directory (Default value = None)
|
||||
input_data(Optional[str], optional): data which will be written to command stdin (Default value = None)
|
||||
logger(Optional[logging.Logger], optional): logger to log command result if required (Default value = None)
|
||||
user(Optional[int], optional): run process as specified user (Default value = None)
|
||||
cwd(Path | None, optional): current working directory (Default value = None)
|
||||
input_data(str | None, optional): data which will be written to command stdin (Default value = None)
|
||||
logger(logging.Logger | None, optional): logger to log command result if required (Default value = None)
|
||||
user(int | None, optional): run process as specified user (Default value = None)
|
||||
|
||||
Returns:
|
||||
str: command output
|
||||
@ -94,9 +94,9 @@ def check_output(*args: str, exception: Optional[Exception] = None, cwd: Optiona
|
||||
|
||||
>>> check_output("false", exception=RuntimeError("An exception occurred"))
|
||||
"""
|
||||
# hack for Optional[IO[str]] handle
|
||||
# hack for IO[str] handle
|
||||
def get_io(proc: subprocess.Popen[str], channel_name: str) -> IO[str]:
|
||||
channel: Optional[IO[str]] = getattr(proc, channel_name, None)
|
||||
channel: IO[str] | None = getattr(proc, channel_name, None)
|
||||
return channel if channel is not None else io.StringIO()
|
||||
|
||||
def log(single: str) -> None:
|
||||
@ -114,7 +114,7 @@ def check_output(*args: str, exception: Optional[Exception] = None, cwd: Optiona
|
||||
input_channel.close()
|
||||
|
||||
# read stdout and append to output result
|
||||
result: List[str] = []
|
||||
result: list[str] = []
|
||||
for line in iter(get_io(process, "stdout").readline, ""):
|
||||
line = line.strip()
|
||||
if not line: # skip empty lines
|
||||
@ -162,15 +162,15 @@ def check_user(paths: RepositoryPaths, *, unsafe: bool) -> None:
|
||||
raise UnsafeRunError(current_uid, root_uid)
|
||||
|
||||
|
||||
def enum_values(enum: Type[Enum]) -> List[str]:
|
||||
def enum_values(enum: type[Enum]) -> list[str]:
|
||||
"""
|
||||
generate list of enumeration values from the source
|
||||
|
||||
Args:
|
||||
enum(Type[Enum]): source enumeration class
|
||||
enum(type[Enum]): source enumeration class
|
||||
|
||||
Returns:
|
||||
List[str]: available enumeration values as string
|
||||
list[str]: available enumeration values as string
|
||||
"""
|
||||
return [str(key.value) for key in enum] # explicit str conversion for typing
|
||||
|
||||
@ -189,16 +189,16 @@ def exception_response_text(exception: requests.exceptions.HTTPError) -> str:
|
||||
return result
|
||||
|
||||
|
||||
def filter_json(source: Dict[str, Any], known_fields: Iterable[str]) -> Dict[str, Any]:
|
||||
def filter_json(source: dict[str, Any], known_fields: Iterable[str]) -> dict[str, Any]:
|
||||
"""
|
||||
filter json object by fields used for json-to-object conversion
|
||||
|
||||
Args:
|
||||
source(Dict[str, Any]): raw json object
|
||||
source(dict[str, Any]): raw json object
|
||||
known_fields(Iterable[str]): list of fields which have to be known for the target object
|
||||
|
||||
Returns:
|
||||
Dict[str, Any]: json object without unknown and empty fields
|
||||
dict[str, Any]: json object without unknown and empty fields
|
||||
|
||||
Examples:
|
||||
This wrapper is mainly used for the dataclasses, thus the flow must be something like this::
|
||||
@ -213,12 +213,12 @@ def filter_json(source: Dict[str, Any], known_fields: Iterable[str]) -> Dict[str
|
||||
return {key: value for key, value in source.items() if key in known_fields and value is not None}
|
||||
|
||||
|
||||
def full_version(epoch: Union[str, int, None], pkgver: str, pkgrel: str) -> str:
|
||||
def full_version(epoch: str | int | None, pkgver: str, pkgrel: str) -> str:
|
||||
"""
|
||||
generate full version from components
|
||||
|
||||
Args:
|
||||
epoch(Union[str, int, None]): package epoch if any
|
||||
epoch(str | int | None): package epoch if any
|
||||
pkgver(str): package version
|
||||
pkgrel(str): package release version (arch linux specific)
|
||||
|
||||
@ -243,27 +243,27 @@ def package_like(filename: Path) -> bool:
|
||||
return ".pkg." in name and not name.endswith(".sig")
|
||||
|
||||
|
||||
def partition(source: List[T], predicate: Callable[[T], bool]) -> Tuple[List[T], List[T]]:
|
||||
def partition(source: list[T], predicate: Callable[[T], bool]) -> tuple[list[T], list[T]]:
|
||||
"""
|
||||
partition list into two based on predicate, based on # https://docs.python.org/dev/library/itertools.html#itertools-recipes
|
||||
|
||||
Args:
|
||||
source(List[T]): source list to be partitioned
|
||||
source(list[T]): source list to be partitioned
|
||||
predicate(Callable[[T], bool]): filter function
|
||||
|
||||
Returns:
|
||||
Tuple[List[T], List[T]]: two lists, first is which ``predicate`` is ``True``, second is ``False``
|
||||
tuple[list[T], list[T]]: two lists, first is which ``predicate`` is ``True``, second is ``False``
|
||||
"""
|
||||
first_iter, second_iter = itertools.tee(source)
|
||||
return list(filter(predicate, first_iter)), list(itertools.filterfalse(predicate, second_iter))
|
||||
|
||||
|
||||
def pretty_datetime(timestamp: Optional[Union[datetime.datetime, float, int]]) -> str:
|
||||
def pretty_datetime(timestamp: datetime.datetime | float | int | None) -> str:
|
||||
"""
|
||||
convert datetime object to string
|
||||
|
||||
Args:
|
||||
timestamp(Optional[Union[datetime.datetime, float, int]]): datetime to convert
|
||||
timestamp(datetime.datetime | float | int | None): datetime to convert
|
||||
|
||||
Returns:
|
||||
str: pretty printable datetime as string
|
||||
@ -275,12 +275,12 @@ def pretty_datetime(timestamp: Optional[Union[datetime.datetime, float, int]]) -
|
||||
return timestamp.strftime("%Y-%m-%d %H:%M:%S")
|
||||
|
||||
|
||||
def pretty_size(size: Optional[float], level: int = 0) -> str:
|
||||
def pretty_size(size: float | None, level: int = 0) -> str:
|
||||
"""
|
||||
convert size to string
|
||||
|
||||
Args:
|
||||
size(Optional[float]): size to convert
|
||||
size(float | None): size to convert
|
||||
level(int, optional): represents current units, 0 is B, 1 is KiB, etc (Default value = 0)
|
||||
|
||||
Returns:
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user