From: Aleš Mrázek Date: Mon, 16 Feb 2026 18:11:28 +0000 (+0100) Subject: python: modeling: added error classes X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=89ada6e90586bcd5e94846925fbb1251e96b5e56;p=thirdparty%2Fknot-resolver.git python: modeling: added error classes --- diff --git a/python/knot_resolver/utils/modeling/errors.py b/python/knot_resolver/utils/modeling/errors.py new file mode 100644 index 000000000..133ec005d --- /dev/null +++ b/python/knot_resolver/utils/modeling/errors.py @@ -0,0 +1,115 @@ +from __future__ import annotations + +from knot_resolver.errors import BaseKresError + + +class DataModelingError(BaseKresError): + """Base exception class for all data modeling errors.""" + + def __init__(self, msg: str, error_pointer: str = "") -> None: + super().__init__() + self._msg = f"[{error_pointer}] {msg}" if error_pointer else msg + self._error_pointer = error_pointer + + def __str__(self) -> str: + return self._msg + + +class DataDescriptionError(DataModelingError): + """Exception class for data description errors.""" + + def __init__(self, msg: str, error_pointer: str = "") -> None: + msg = f"description error: {msg}" + super().__init__(msg, error_pointer) + + +class DataAnnotationError(DataModelingError): + """Exception class for data annotation errors.""" + + def __init__(self, msg: str, error_pointer: str = "") -> None: + msg = f"annotation error: {msg}" + super().__init__(msg, error_pointer) + + +class DataParsingError(DataModelingError): + """Exception class for data parsing errors.""" + + def __init__(self, msg: str, error_pointer: str = "") -> None: + msg = f"parsing error: {msg}" + super().__init__(msg, error_pointer) + + +class DataTypeError(DataModelingError): + """Exception class for data type errors.""" + + def __init__(self, msg: str, error_pointer: str = "") -> None: + msg = f"type error: {msg}" + super().__init__(msg, error_pointer) + + +class DataValueError(DataModelingError): + """Exception class for data value errors.""" + + def __init__(self, msg: str, error_pointer: str = "") -> None: + msg = f"value error: {msg}" + super().__init__(msg, error_pointer) + + +class DataValidationError(DataModelingError): + """Exception class for data validation errors. + + This exception is used as parent for other data modeling errors. + """ + + def __init__(self, msg: str, error_pointer: str, child_errors: list[DataModelingError] | None = None) -> None: + super().__init__(msg, error_pointer) + + if child_errors is None: + child_errors = [] + self._child_errors = child_errors + + def recursive_msg(self, indentation: int = 0) -> str: + parts: list[str] = [] + + if indentation == 0: + indentation += 1 + parts.append("Data validation error detected:") + + indent = " " * indentation + parts.append(f"{indent}{self._msg}") + + if self._child_errors: + for error in self._child_errors: + if isinstance(error, DataValidationError): + parts.append(error.recursive_msg(indentation + 1)) + else: + parts.append(indent + f" {error}") + return "\n".join(parts) + + def __str__(self) -> str: + return self.recursive_msg() + + +class AggrDataValidationError(DataValidationError): + """Exception class for aggregation of data validation errors. + + This exception is used to aggregate other data modeling errors. + """ + + def __init__(self, error_pointer: str, child_errors: list[DataModelingError]) -> None: + super().__init__("error due to lower level error", error_pointer, child_errors) + + def recursive_msg(self, indentation: int = 0) -> str: + inc = 0 + parts: list[str] = [] + + if indentation == 0: + inc = 1 + parts.append("Data validation errors detected:") + + for error in self._child_errors: + if isinstance(error, DataValidationError): + parts.append(error.recursive_msg(indentation + inc)) + else: + parts.append(f" {error}") + return "\n".join(parts) diff --git a/tests/python/knot_resolver/utils/modeling/test_errors.py b/tests/python/knot_resolver/utils/modeling/test_errors.py new file mode 100644 index 000000000..0486ff744 --- /dev/null +++ b/tests/python/knot_resolver/utils/modeling/test_errors.py @@ -0,0 +1,46 @@ +import pytest + +from knot_resolver.utils.modeling.errors import ( + AggrDataValidationError, + DataAnnotationError, + DataDescriptionError, + DataModelingError, + DataTypeError, + DataValidationError, + DataValueError, +) + +errors = [ + DataModelingError("this is data modeling error message", "/error"), + DataAnnotationError("this is annotation error message", "/annotation"), + DataDescriptionError("this is description error message", "/description"), + DataTypeError("this is type error message", "/type"), + DataValueError("this is value error message", "/value"), +] + + +def test_data_validation_error() -> None: + error_msg = """Data validation error detected: + [/validation] this is validation error message + [/error] this is data modeling error message + [/annotation] annotation error: this is annotation error message + [/description] description error: this is description error message + [/type] type error: this is type error message + [/value] value error: this is value error message""" + + with pytest.raises(DataValidationError) as error: + raise DataValidationError("this is validation error message", "/validation", errors) + assert str(error.value) == error_msg + + +def test_aggregate_data_validation_error() -> None: + error_msg = """Data validation errors detected: + [/error] this is data modeling error message + [/annotation] annotation error: this is annotation error message + [/description] description error: this is description error message + [/type] type error: this is type error message + [/value] value error: this is value error message""" + + with pytest.raises(AggrDataValidationError) as error: + raise AggrDataValidationError("/", errors) + assert str(error.value) == error_msg