[docs]
class Configurable(Generic[_ConfigurationT]):
"""
Any configurable object.
"""
_configuration: _ConfigurationT
@property
def configuration(self) -> _ConfigurationT:
"""
The object's configuration.
"""
if not hasattr(self, "_configuration"):
raise RuntimeError(
f"{self} has no configuration. {type(self)}.__init__() must ensure it is set."
)
return self._configuration
[docs]
async def assert_configuration_file(
configuration: _ConfigurationT,
) -> AssertionChain[Path, _ConfigurationT]:
"""
Assert that configuration can be loaded from a file.
"""
available_formats = {
available_format: await FORMAT_REPOSITORY.new_target(available_format)
async for available_format in FORMAT_REPOSITORY
}
def _assert(configuration_file_path: Path) -> _ConfigurationT:
with (
AssertionFailedGroup().assert_valid() as errors,
# Change the working directory to allow relative paths to be resolved
# against the configuration file's directory path.
chdir(configuration_file_path.parent),
):
with open(configuration_file_path) as f:
read_configuration = f.read()
with errors.catch(plain(f"in {str(configuration_file_path.resolve())}")):
configuration_file_format = available_formats[
format_for(list(available_formats), configuration_file_path.suffix)
]
configuration.load(configuration_file_format.load(read_configuration))
return configuration
return assert_file_path() | _assert