feat: detect dependencies resolution error

This commit is contained in:
arcanis committed 2026-10-13 10:31:11 +03:00
1 parent 16afb50c19
commit 19ca1ac797
3 files changed
+27 -2

No files matched your search

@@ -83,6 +83,15 @@ Process stderr:
{self.stderr}""" {self.stderr}"""
class DependencyResolutionError(RuntimeError):
"""
exception raised when package dependencies cannot be resolved
"""
def __init__(self, unprocessed: list[str]) -> None:
RuntimeError.__init__(self, f"Could not process dependencies. Unresolved packages: {unprocessed}")
class DuplicateRunError(RuntimeError): class DuplicateRunError(RuntimeError):
""" """
exception which will be raised if there is another application instance exception which will be raised if there is another application instance
+6 -1
View File
@@ -22,7 +22,7 @@ from __future__ import annotations
from collections.abc import Iterable from collections.abc import Iterable
from functools import partial from functools import partial
from ahriman.core.exceptions import PartitionError from ahriman.core.exceptions import DependencyResolutionError, PartitionError
from ahriman.core.utils import minmax, partition from ahriman.core.utils import minmax, partition
from ahriman.models.package import Package from ahriman.models.package import Package
@@ -226,6 +226,9 @@ class Tree:
Returns: 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
Raises:
DependencyResolutionError: dependency cycle prevents ordering packages
""" """
unsorted: list[list[Leaf]] = [] unsorted: list[list[Leaf]] = []
@@ -235,6 +238,8 @@ class Tree:
# additional workaround with partial in order to hide cell-var-from-loop pylint warning # additional workaround with partial in order to hide cell-var-from-loop pylint warning
predicate = partial(Leaf.is_root, packages=unprocessed) predicate = partial(Leaf.is_root, packages=unprocessed)
new_level, unprocessed = partition(unprocessed, predicate) new_level, unprocessed = partition(unprocessed, predicate)
if not new_level:
raise DependencyResolutionError([leaf.package.base for leaf in unprocessed])
unsorted.append(new_level) unsorted.append(new_level)
# move leaves to the end if they are not required at the next level # move leaves to the end if they are not required at the next level
+12 -1
View File
@@ -1,6 +1,6 @@
import pytest import pytest
from ahriman.core.exceptions import PartitionError from ahriman.core.exceptions import DependencyResolutionError, PartitionError
from ahriman.core.tree import Leaf, Tree from ahriman.core.tree import Leaf, Tree
from ahriman.models.package import Package from ahriman.models.package import Package
from ahriman.models.package_description import PackageDescription from ahriman.models.package_description import PackageDescription
@@ -270,3 +270,14 @@ def test_tree_partitions() -> None:
first, second = tree.partitions(count=3) first, second = tree.partitions(count=3)
assert first == [leaf1.package, leaf2.package, leaf3.package, leaf5.package] assert first == [leaf1.package, leaf2.package, leaf3.package, leaf5.package]
assert second == [leaf4.package] assert second == [leaf4.package]
def test_tree_levels_cycle(leaf_ahriman: Leaf, leaf_python_schedule: Leaf) -> None:
"""
must raise an exception if dependencies contain a cycle
"""
leaf_ahriman.dependencies = set(leaf_python_schedule.items)
leaf_python_schedule.dependencies = set(leaf_ahriman.items)
with pytest.raises(DependencyResolutionError):
Tree([leaf_ahriman, leaf_python_schedule]).levels()