Skip to content

Commit

Permalink
Add qualifier error tracing
Browse files Browse the repository at this point in the history
Enhance the errors raised by the qualifier manager to show the parent
(above in the dependency tree) spec.
  • Loading branch information
JulienBortolussiAda committed Jul 25, 2023
1 parent a5ac69c commit 3375f39
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 25 deletions.
31 changes: 18 additions & 13 deletions src/e3/anod/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
UploadSourceComponent,
)
from e3.anod.deps import Dependency
from e3.anod.error import AnodError
from e3.anod.error import AnodError, QualifierError
from e3.anod.package import UnmanagedSourceBuilder
from e3.anod.spec import has_primitive, fetch_attr
from e3.collection.dag import DAG
Expand Down Expand Up @@ -673,18 +673,23 @@ def add_dep(spec_instance: Anod, dep: Dependency, dep_instance: Anod) -> None:
)

continue

child_action = self.add_spec(
name=e.name,
env=e.env(spec, self.default_env),
primitive=e.kind if e.kind != "download" else "install",
qualifier=e.qualifier,
plan_args=None,
plan_line=plan_line,
sandbox=sandbox,
upload=upload,
force_download=e.kind == "download",
)
try:
child_action = self.add_spec(
name=e.name,
env=e.env(spec, self.default_env),
primitive=e.kind if e.kind != "download" else "install",
qualifier=e.qualifier,
plan_args=None,
plan_line=plan_line,
sandbox=sandbox,
upload=upload,
force_download=e.kind == "download",
)
except QualifierError as err:
raise QualifierError(
f"\nIn {e.name} ({e.qualifier if e.qualifier else ''}), "
"dependency of {name} ({qualifier}){err}"
) from err

add_dep(
spec_instance=spec, dep=e, dep_instance=child_action.anod_instance
Expand Down
4 changes: 4 additions & 0 deletions src/e3/anod/error.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,7 @@ def __init__(
):
super().__init__(message, origin)
self.process = process


class QualifierError(AnodError):
pass
5 changes: 2 additions & 3 deletions src/e3/anod/qualifiers_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from typing import TYPE_CHECKING, cast
from hashlib import sha1

from e3.anod.error import AnodError
from e3.anod.error import AnodError, QualifierError

import string

Expand Down Expand Up @@ -791,8 +791,7 @@ def build_space_name(self) -> str:

def __error(self, msg: str) -> None:
"""Raise an error and print the helper."""
print(self.__get_helper())
raise AnodError(msg)
raise QualifierError("\n" + msg + "\n" + self.__get_helper())

def __get_helper(self) -> str:
"""Return an helper for the current state of Qualifiers.
Expand Down
53 changes: 44 additions & 9 deletions tests/tests_e3/anod/test_qualifier_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ def test_qualifiers_manager_errors():
class AnodDummy(Anod):
enable_name_generator = True
base_name = "dummy"
name = "dummy"

anod_dummy = AnodDummy("", kind="build")

Expand Down Expand Up @@ -171,13 +172,20 @@ class AnodDummy(Anod):
with pytest.raises(AnodError) as err:
qualifiers_manager.parse({})
assert str(err.value) == (
"The foo qualifier was declared without a default value but not passed"
"""
The foo qualifier was declared without a default value but not passed
dummy accept the following qualifiers:
* foo=<value> : bar"""
)

# Use of undeclared qualifier
with pytest.raises(AnodError) as err:
AnodDummy("foo", kind="build")
assert str(err.value) == ('The qualifier "foo" is used but has not been declared')
assert str(err.value) == (
"""
The qualifier "foo" is used but has not been declared
dummy does not accept any qualifiers."""
)

# Pass a key_value qualifier with no value
qualifiers_manager = QualifiersManager(Anod("", kind="build"))
Expand All @@ -187,7 +195,13 @@ class AnodDummy(Anod):
)
with pytest.raises(AnodError) as err:
qualifiers_manager.parse({"foo": ""})
assert str(err.value) == 'The key-value qualifier "foo" must be passed with a value'
assert (
str(err.value)
== """
The key-value qualifier "foo" must be passed with a value
accept the following qualifiers:
* foo=<value> : foo"""
)

# Pass a key_value qualifier with a value not in choices
qualifiers_manager = QualifiersManager(Anod("", kind="build"))
Expand All @@ -199,7 +213,12 @@ class AnodDummy(Anod):
with pytest.raises(AnodError) as err:
qualifiers_manager.parse({"foo": "foo"})
assert (
str(err.value) == "The foo qualifier value must be in ['bar', 'baz']. Got foo"
str(err.value)
== """
The foo qualifier value must be in ['bar', 'baz']. Got foo
accept the following qualifiers:
* foo=<value> : foo
* choices: ['bar', 'baz']"""
)

# Pass a tag qualifier with a value
Expand All @@ -211,7 +230,10 @@ class AnodDummy(Anod):
with pytest.raises(AnodError) as err:
qualifiers_manager.parse({"foo": "bar"})
assert str(err.value) == (
'The foo qualifier is a tag and does not expect any values. Got "bar"'
"""
The foo qualifier is a tag and does not expect any values. Got "bar"
dummy accept the following qualifiers:
* foo : foo"""
)

# Try to build a component
Expand All @@ -226,7 +248,10 @@ class AnodDummy(Anod):
with pytest.raises(AnodError) as err:
qualifiers_manager.parse({"foo": "bar"})
assert str(err.value) == (
"The qualifier foo is test_only but the current anod kind is build"
"""
The qualifier foo is test_only but the current anod kind is build
dummy accept the following qualifiers:
* foo=<value> (test only) : bar"""
)

# use a not declared qualifier in component
Expand All @@ -238,7 +263,9 @@ class AnodDummy(Anod):
with pytest.raises(AnodError) as err:
qualifiers_manager.parse({})
assert str(err.value) == (
'In component "foo": The qualifier "bar" is used but has not been declared'
"""In component "foo":
The qualifier "bar" is used but has not been declared
dummy does not accept any qualifiers."""
)

# Incomplete use of a qualifier without default value
Expand All @@ -254,7 +281,10 @@ class AnodDummy(Anod):
with pytest.raises(AnodError) as err:
qualifiers_manager.parse({"foo": "baz"})
assert str(err.value) == (
'In component "bar": The key-value qualifier "foo" must be passed with a value'
"""In component "bar":
The key-value qualifier "foo" must be passed with a value
dummy accept the following qualifiers:
* foo=<value> : foo"""
)

# Reuse a qualifier configuration in a component
Expand Down Expand Up @@ -493,7 +523,12 @@ def declare_qualifiers_and_components(self, qualifiers_manager):
with pytest.raises(AnodError) as err:
anod_component_3 = AnodComponent("version=", kind="build")
assert str(err.value) == (
'The key-value qualifier "version" must be passed with a value'
"""
The key-value qualifier "version" must be passed with a value
accept the following qualifiers:
* debug : State if the build must be done in debug mode.
* version=<value> : State the version of the component to be build
* default: 1.2"""
)

# test_only qualifier
Expand Down

0 comments on commit 3375f39

Please sign in to comment.