Source code for varlord.exceptions

"""
Varlord exception hierarchy.

All Varlord exceptions inherit from :class:`VarlordError` for consistent error handling.
Each exception has an error code for programmatic handling.
"""

from typing import Optional


[docs] class VarlordError(Exception): """Base exception for all Varlord errors. All exceptions raised by Varlord inherit from this class, allowing users to: - Catch all Varlord errors with ``except VarlordError`` - Identify error types programmatically using the ``code`` attribute Attributes: message: Human-readable error message code: Machine-readable error code (e.g., "CONFIG_LOAD_FAILED") Example: >>> try: ... cfg.load() ... except VarlordError as e: ... print(f"Error {e.code}: {e.message}") """
[docs] def __init__(self, message: str, code: Optional[str] = None): """Initialize VarlordError. Args: message: Human-readable error message code: Machine-readable error code (defaults to class name) """ self.message = message self.code = code or self.__class__.__name__ super().__init__(self.message)
[docs] def __repr__(self) -> str: """Return string representation.""" return f"{self.__class__.__name__}(code={self.code!r}, message={self.message!r})"
[docs] def __str__(self) -> str: """Return user-friendly string representation.""" return self.message
[docs] class ConfigError(VarlordError): """Base exception for configuration-related errors.""" pass
[docs] class ConfigLoadError(ConfigError): """Raised when configuration loading fails. This can occur when: - A source fails to load (e.g., file not found, permission denied) - Type conversion fails (e.g., invalid int value) - Validation fails (e.g., missing required field) Attributes: source_name: Name of the source that failed (if applicable) """
[docs] def __init__( self, message: str, source_name: Optional[str] = None, code: str = "CONFIG_LOAD_FAILED", ): """Initialize ConfigLoadError. Args: message: Human-readable error message source_name: Name of the source that failed (e.g., "yaml", "env") code: Machine-readable error code """ self.source_name = source_name if source_name: message = f"[{source_name}] {message}" super().__init__(message, code=code)
[docs] class SourceLoadError(ConfigLoadError): """Raised when a configuration source fails to load. This is a subclass of :class:`ConfigLoadError` for backward compatibility. """ pass
[docs] class ValidationError(ConfigError): """Raised when configuration validation fails. This can occur when: - Required fields are missing - Field values fail custom validation - Model definition is invalid """
[docs] def __init__( self, message: str, field_name: Optional[str] = None, code: str = "VALIDATION_FAILED", ): """Initialize ValidationError. Args: message: Human-readable error message field_name: Name of the field that failed validation (if applicable) code: Machine-readable error code """ self.field_name = field_name if field_name: message = f"Field '{field_name}': {message}" super().__init__(message, code=code)
[docs] class RequiredFieldError(ValidationError): """Raised when a required field is missing. Attributes: field_name: Name of the missing required field """
[docs] def __init__(self, message: str, field_name: Optional[str] = None): """Initialize RequiredFieldError. Args: message: Human-readable error message field_name: Name of the missing required field """ if field_name is None: # Extract field name from message if possible if "field" in message.lower(): # Try to extract field name from message import re match = re.search(r"field\s+['\"]?(\w+)['\"]?", message, re.IGNORECASE) if match: field_name = match.group(1) super().__init__(message, field_name=field_name, code="MISSING_REQUIRED_FIELD")
[docs] class ModelDefinitionError(ValidationError): """Raised when model definition is invalid. This can occur when: - Fields are missing required metadata - Field types are unsupported - Field names conflict with reserved names """
[docs] def __init__(self, message: str) -> None: """Initialize ModelDefinitionError. Args: message: Human-readable error message """ super().__init__(message, code="INVALID_MODEL_DEFINITION")
[docs] class ResolverError(ConfigError): """Raised when source resolution fails. This can occur when: - Priority policy is invalid - Source merge fails - Circular dependencies detected """
[docs] def __init__(self, message: str, code: str = "RESOLVER_FAILED") -> None: """Initialize ResolverError. Args: message: Human-readable error message code: Machine-readable error code """ super().__init__(message, code=code)
[docs] class ConversionError(ConfigError): """Raised when type conversion fails. This can occur when: - String value cannot be converted to target type - Invalid boolean value (not "true"/"false"/"1"/"0") - Invalid numeric value (not an integer/float) """
[docs] def __init__( self, message: str, field_name: Optional[str] = None, field_type: Optional[str] = None, value: Optional[str] = None, ) -> None: """Initialize ConversionError. Args: message: Human-readable error message field_name: Name of the field that failed conversion field_type: Target type name (e.g., "int", "bool") value: The value that failed to convert """ self.field_name = field_name self.field_type = field_type self.value = value details = [] if field_name: details.append(f"field={field_name}") if field_type: details.append(f"type={field_type}") if value: details.append(f"value={value!r}") if details: message = f"{message} ({', '.join(details)})" super().__init__(message, code="TYPE_CONVERSION_FAILED")
# Error code registry (for documentation) ERROR_CODES = { "CONFIG_LOAD_FAILED": ConfigLoadError, "SOURCE_LOAD_FAILED": SourceLoadError, "VALIDATION_FAILED": ValidationError, "MISSING_REQUIRED_FIELD": RequiredFieldError, "INVALID_MODEL_DEFINITION": ModelDefinitionError, "RESOLVER_FAILED": ResolverError, "TYPE_CONVERSION_FAILED": ConversionError, } def get_error_class(code: str) -> Optional[type]: """Get exception class by error code. Args: code: Error code (e.g., "CONFIG_LOAD_FAILED") Returns: Exception class or None if code not found Example: >>> cls = get_error_class("CONFIG_LOAD_FAILED") >>> cls # doctest: +SKIP <class 'varlord.exceptions.ConfigLoadError'> """ return ERROR_CODES.get(code)