diff --git a/CHANGELOG.md b/CHANGELOG.md index ec7bb70..97d7784 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,8 @@ # Changelog +## 6.0.1 +### Fixes +- Improve error messages when loading fails + ## 6.0.0 ### Breaking changes - Remove support for Python 3.8 diff --git a/configue/configue_loader.py b/configue/configue_loader.py index 7cb4414..d034d37 100644 --- a/configue/configue_loader.py +++ b/configue/configue_loader.py @@ -2,7 +2,7 @@ import os import re from collections.abc import Hashable -from typing import Any, List, Mapping, Union +from typing import Any, List, Mapping, Optional, Union import yaml from yaml.constructor import ConstructorError @@ -25,6 +25,7 @@ def construct_yaml_map(self, node: yaml.MappingNode) -> Any: path = mapping.pop(CONSTRUCTOR_KEY) object_path_elements = path.split(".") remaining_path_elements: List[str] = [] + exceptions: list[Optional[str]] = [] while object_path_elements: try: cls = self.find_python_name( @@ -33,10 +34,13 @@ def construct_yaml_map(self, node: yaml.MappingNode) -> Any: unsafe=True, ) break - except ConstructorError: + except ConstructorError as error: + exceptions.append(error.problem) remaining_path_elements.insert(0, object_path_elements.pop(-1)) else: - raise NotFoundError(f"Could not load element {path} {node.start_mark}") + raise NotFoundError( + f"Could not load element {path} {node.start_mark}, exceptions encountered: {exceptions!r}" + ) from None for path_element in remaining_path_elements: cls = getattr(cls, path_element) diff --git a/configue/file_loader.py b/configue/file_loader.py index aeec7b3..4e53283 100644 --- a/configue/file_loader.py +++ b/configue/file_loader.py @@ -120,6 +120,7 @@ def _load_ext(self, loader: ConfigueLoader, node: ScalarNode) -> Any: path = loader.construct_scalar(node) object_path_elements = path.split(".") remaining_path_elements: List[str] = [] + exceptions: list[Optional[str]] = [] while object_path_elements: try: loaded_object = loader.find_python_name( @@ -128,10 +129,13 @@ def _load_ext(self, loader: ConfigueLoader, node: ScalarNode) -> Any: unsafe=True, ) break - except ConstructorError: + except ConstructorError as error: + exceptions.append(error.problem) remaining_path_elements.insert(0, object_path_elements.pop(-1)) else: - raise NotFoundError(f"Could not load element {path} {node.start_mark}") + raise NotFoundError( + f"Could not load element {path} {node.start_mark}, encountered exceptions: {exceptions!r}" + ) from None remaining_path = ".".join(remaining_path_elements) if remaining_path: return self._get_element_at_sub_path(remaining_path, loaded_object) diff --git a/tests/test_configue.py b/tests/test_configue.py index 507c981..f5fdad7 100644 --- a/tests/test_configue.py +++ b/tests/test_configue.py @@ -3,7 +3,7 @@ from unittest import TestCase import configue -from configue.exceptions import NonCallableError, SubPathNotFound, NotFoundError +from configue.exceptions import ConfigueError, NonCallableError, SubPathNotFound, NotFoundError from tests.external_module import CONSTANT, MyObject, Color @@ -178,11 +178,11 @@ def test_ext_raises_exception_on_submodule_not_found(self): configue.load(self._get_path("test_file_2.yml"), "invalid_ext.wrong_sub_module") def test_ext_raises_exception_on_element_not_found(self): - with self.assertRaises(NotFoundError): + with self.assertRaises(ConfigueError): configue.load(self._get_path("test_file_2.yml"), "invalid_ext.wrong_element") def test_ext_raises_exception_on_property_not_found(self): - with self.assertRaises(NotFoundError): + with self.assertRaises(KeyError): configue.load(self._get_path("test_file_2.yml"), "invalid_ext.wrong_property") def test_loading_empty_file(self): diff --git a/tests/test_file_2.yml b/tests/test_file_2.yml index 500f53b..e0dc538 100644 --- a/tests/test_file_2.yml +++ b/tests/test_file_2.yml @@ -37,8 +37,8 @@ enum_loading: !ext tests.external_module.Color.RED invalid_ext: wrong_module: !ext invalid.test.Color.RED wrong_sub_module: !ext tests.invalid.Color.RED - wrong_element: !ext tests.invalid.Invalid.RED - wrong_property: !ext tests.invalid.Color.GREEN + wrong_element: !ext tests.external_module.Invalid.RED + wrong_property: !ext tests.external_module.Color.GREEN static_loading: (): tests.external_module.Static.get_static_value