Coverage for src/csv_schema_validator/field_validators/exceptions.py: 88%

48 statements  

« prev     ^ index     » next       coverage.py v7.10.6, created at 2025-12-23 15:34 +0100

1""" 

2Field validation exceptions for CSV field validation. 

3 

4This module defines specific exception classes for different types of field validation 

5errors that can occur during CSV field validation, providing better error handling and 

6more informative error messages. 

7""" 

8from __future__ import annotations 

9 

10from typing import Any 

11 

12 

13class FieldValidationError(Exception): 

14 """Base exception for field validation errors.""" 

15 

16 def __init__(self, message: str, field_name: str, row: int, 

17 value: Any, expected_type: str | None = None, 

18 details: dict[str, Any] | None = None): 

19 super().__init__(message) 

20 self.message = message 

21 self.field_name = field_name 

22 self.row = row 

23 self.value = value 

24 self.expected_type = expected_type 

25 self.details = details or {} 

26 

27 def to_dict(self) -> dict[str, Any]: 

28 """Convert exception to dictionary format for JSON serialization.""" 

29 return { 

30 "error_type": self.__class__.__name__, 

31 "error_message": self.message, 

32 "row": self.row, 

33 "column": self.field_name, 

34 "value": self.value, 

35 "details": self.details 

36 } 

37 

38 

39class TypeValidationError(FieldValidationError): 

40 """Raised when field type validation fails.""" 

41 

42 def __init__(self, field_name: str, row: int, value: Any, expected_type: str): 

43 message = f"Invalid type for field '{field_name}': expected {expected_type}, got {type(value).__name__}" 

44 super().__init__(message, field_name, row, value, expected_type) 

45 self.details = { 

46 "expected_type": expected_type, 

47 "actual_type": type(value).__name__ 

48 } 

49 

50 

51class PatternValidationError(FieldValidationError): 

52 """Raised when field pattern validation fails.""" 

53 

54 def __init__(self, field_name: str, row: int, value: Any, pattern: str): 

55 message = f"Field '{field_name}' does not match required pattern" 

56 super().__init__(message, field_name, row, value, details={"expected_pattern": pattern}) 

57 

58 

59class EnumValidationError(FieldValidationError): 

60 """Raised when field enum validation fails.""" 

61 

62 def __init__(self, field_name: str, row: int, value: Any, allowed_values: list[str]): 

63 message = f"Field '{field_name}' value '{value}' is not in allowed values" 

64 super().__init__(message, field_name, row, value, details={"allowed_values": allowed_values}) 

65 

66 

67class RangeValidationError(FieldValidationError): 

68 """Raised when field range validation fails.""" 

69 

70 def __init__(self, field_name: str, row: int, value: Any, min_value: float | None = None, 

71 max_value: float | None = None): 

72 if min_value is not None and max_value is not None: 

73 message = f"Field '{field_name}' value '{value}' is outside range [{min_value}, {max_value}]" 

74 details = {"min_value": min_value, "max_value": max_value} 

75 elif min_value is not None: 

76 message = f"Field '{field_name}' value '{value}' is below minimum {min_value}" 

77 details = {"min_value": min_value} 

78 else: 

79 message = f"Field '{field_name}' value '{value}' exceeds maximum {max_value}" 

80 details = {"max_value": max_value} 

81 

82 super().__init__(message, field_name, row, value, details=details) 

83 

84 

85class RequiredFieldError(FieldValidationError): 

86 """Raised when a required field is missing.""" 

87 

88 def __init__(self, field_name: str, row: int): 

89 message = f"Required field '{field_name}' is missing" 

90 super().__init__(message, field_name, row, None) 

91 

92 

93class ValidationConfigurationError(Exception): 

94 """Raised when there are configuration errors in validation setup.""" 

95 

96 def __init__(self, message: str, details: dict[str, Any] | None = None): 

97 super().__init__(message) 

98 self.message = message 

99 self.details = details or {} 

100 

101 def to_dict(self) -> dict[str, Any]: 

102 """Convert exception to dictionary format for JSON serialization.""" 

103 return { 

104 "error_type": self.__class__.__name__, 

105 "error_message": self.message, 

106 "row": None, 

107 "column": None, 

108 "value": None, 

109 "details": self.details 

110 }