This module provides the foundational error classes used across the Building Blocks framework.
It defines structured, debuggable, and composable error types that can be raised,
caught, and combined in a uniform way throughout all architectural layers.
Error:
Base class for all structured errors in the system. Inherits from Exception and Debuggable, allowing it to be raised and logged like
a standard exception while carrying structured metadata.
NoneNotAllowedError
Specialized Error indicating that a None value was provided where it
is not allowed.
FieldErrors
Represents validation or constraint errors associated with a single field.
Provides iterable access to individual Error instances for that field.
CombinedErrors
Aggregates multiple Error (or subclass) instances into one. Useful for
collecting and raising multiple failures together (e.g., validation errors).
This module provides the foundational error classes used across the Building Blocks framework.
It defines structured, debuggable, and composable error types that can be raised,
caught, and combined in a uniform way throughout all architectural layers.
Base class for all structured errors in the system. Inherits from Exception and Debuggable, allowing it to be raised and logged like
a standard exception while carrying structured metadata.
NoneNotAllowedError
Specialized Error indicating that a None value was provided where it
is not allowed.
FieldErrors
Represents validation or constraint errors associated with a single field.
Provides iterable access to individual Error instances for that field.
CombinedErrors
Aggregates multiple Error (or subclass) instances into one. Useful for
collecting and raising multiple failures together (e.g., validation errors).
classError(Exception,Debuggable):"""Base class for all structured errors that can be raised like standard Exceptions."""def__init__(self,message:ErrorMessage,metadata:ErrorMetadata|None=None)->None:super().__init__(message.value)self._message=messageself._metadata=metadataorErrorMetadata(context={})def__str__(self)->str:context_str=(f" | Context: {self._metadata.context}"ifself._metadata.contextelse"")returnf"{self.__class__.__name__}: {self._message.value}{context_str}"def__repr__(self)->str:return(f"<{self.__class__.__name__} message={self._message.value!r} "f"context={self._metadata.context!r}>")@propertydefmessage(self)->ErrorMessage:"""Structured error message."""returnself._message@propertydefmetadata(self)->ErrorMetadata:"""Structured metadata with additional context."""returnself._metadata@propertydefcontext(self)->dict[str,Any]:"""Shortcut for accessing the metadata context."""returnself._metadata.contextdefas_debug_string(self)->str:"""Return a detailed, multi-line string for debugging."""return(f"{self.__class__.__name__}(\n"f" message={repr(self._message)},\n"f" metadata={repr(self._metadata)}\n"")")
defas_debug_string(self)->str:"""Return a detailed, multi-line string for debugging."""return(f"{self.__class__.__name__}(\n"f" message={repr(self._message)},\n"f" metadata={repr(self._metadata)}\n"")")
classFieldErrors(Error):"""Base class for errors associated with a specific field."""def__init__(self,field:FieldReference,errors:Iterable[Error])->None:self._field=fieldself._errors:Sequence[Error]=tuple(errors)ifnoterrorsornotfield:raiseValueError("FieldErrors must contain at least one error and field defined.")message=ErrorMessage(f"{len(self._errors)} error(s) for field '{field}'.")super().__init__(message=message)def__repr__(self)->str:"""Return a concise string representation of the field errors."""return(f"<{self._get_title_prefix()} field={self._field.value!r} "f"errors={len(self._errors)}>")def__str__(self)->str:"""Return a human-readable string representation of the field errors."""error_messages="\n".join(f" - {str(error)}"forerrorinself._errors)return(f"{self._get_title_prefix()} for field '{self._field.value}':\n"f"{error_messages}")def__iter__(self)->Iterator[Error]:"""Iterate over the errors associated with the field."""returniter(self._errors)def__len__(self)->int:"""Return the number of errors associated with the field."""returnlen(self._errors)@propertydeffield(self)->FieldReference:"""The field associated with these errors."""returnself._field@propertydeferrors(self)->Sequence[Error]:"""The collection of errors associated with the field."""returnself._errorsdefas_debug_string(self)->str:"""Return detailed, multi-line string of this field error collection for debugging."""error_strings=[f" {err.as_debug_string()}"forerrinself._errors]return(f"{self._get_title_prefix()}(\n"f" field={repr(self._field)},\n"f" errors=[\n"+(""ifnoterror_stringselse"\n".join(error_strings)+"\n")+" ]\n"")")def_get_title_prefix(self)->str:"""Get the title prefix for this field error type."""returnself.__class__.__name__
def__repr__(self)->str:"""Return a concise string representation of the field errors."""return(f"<{self._get_title_prefix()} field={self._field.value!r} "f"errors={len(self._errors)}>")
def__str__(self)->str:"""Return a human-readable string representation of the field errors."""error_messages="\n".join(f" - {str(error)}"forerrorinself._errors)return(f"{self._get_title_prefix()} for field '{self._field.value}':\n"f"{error_messages}")
defas_debug_string(self)->str:"""Return detailed, multi-line string of this field error collection for debugging."""error_strings=[f" {err.as_debug_string()}"forerrinself._errors]return(f"{self._get_title_prefix()}(\n"f" field={repr(self._field)},\n"f" errors=[\n"+(""ifnoterror_stringselse"\n".join(error_strings)+"\n")+" ]\n"")")
classCombinedErrors(Error,Generic[ErrorType]):"""Base class for combining multiple errors into one."""def__init__(self,errors:Iterable[ErrorType])->None:self._errors:Sequence[ErrorType]=tuple(errors)combined_message=f"{len(self._errors)} errors occurred."super().__init__(message=ErrorMessage(combined_message))def__repr__(self)->str:"""Return a concise string representation of the combined errors."""returnf"<{self._get_title_prefix()} errors={len(self._errors)}>"def__str__(self)->str:"""Return a human-readable string representation of the combined errors."""error_details="\n".join(f"- {str(error)}"forerrorinself._errors)returnf"{self._get_title_prefix()}:\n{error_details}"def__iter__(self)->Iterator[ErrorType]:"""Iterate over the combined errors."""returniter(self._errors)def__len__(self)->int:"""Return the number of combined errors."""returnlen(self._errors)@propertydeferrors(self)->Sequence[ErrorType]:"""The collection of combined errors."""returnself._errorsdefas_debug_string(self)->str:"""Return a detailed, multi-line string for debugging, showing all contained errors."""error_strings=[f" {e.as_debug_string().replace(chr(10),chr(10)+' ')}"foreinself._errors]return(f"{self._get_title_prefix()}(\n"f" errors=[\n"+(""ifnoterror_stringselse"\n".join(error_strings)+"\n")+" ]\n"")")def_get_title_prefix(self)->str:"""Get the title prefix for this combined error type."""returnself.__class__.__name__
def__repr__(self)->str:"""Return a concise string representation of the combined errors."""returnf"<{self._get_title_prefix()} errors={len(self._errors)}>"
def__str__(self)->str:"""Return a human-readable string representation of the combined errors."""error_details="\n".join(f"- {str(error)}"forerrorinself._errors)returnf"{self._get_title_prefix()}:\n{error_details}"
defas_debug_string(self)->str:"""Return a detailed, multi-line string for debugging, showing all contained errors."""error_strings=[f" {e.as_debug_string().replace(chr(10),chr(10)+' ')}"foreinself._errors]return(f"{self._get_title_prefix()}(\n"f" errors=[\n"+(""ifnoterror_stringselse"\n".join(error_strings)+"\n")+" ]\n"")")