Re-upload: CI infrastructure issue resolved, all tests verified passing
This commit is contained in:
153
envschema/validators.py
Normal file
153
envschema/validators.py
Normal file
@@ -0,0 +1,153 @@
|
||||
"""Type validators for environment variable values."""
|
||||
|
||||
import re
|
||||
from typing import Optional
|
||||
|
||||
from envschema.schema import EnvVarType
|
||||
|
||||
|
||||
class ValidationError:
|
||||
"""Represents a validation error."""
|
||||
|
||||
def __init__(self, message: str, value: Optional[str] = None):
|
||||
self.message = message
|
||||
self.value = value
|
||||
|
||||
def __str__(self) -> str:
|
||||
if self.value is not None:
|
||||
return f"{self.message} (got: {self.value!r})"
|
||||
return self.message
|
||||
|
||||
|
||||
class StringValidator:
|
||||
"""Validator for string type - always passes."""
|
||||
|
||||
@staticmethod
|
||||
def validate(value: Optional[str]) -> tuple[bool, Optional[ValidationError]]:
|
||||
if value is None:
|
||||
return True, None
|
||||
return True, None
|
||||
|
||||
|
||||
class IntegerValidator:
|
||||
"""Validator for integer type."""
|
||||
|
||||
@staticmethod
|
||||
def validate(value: Optional[str]) -> tuple[bool, Optional[ValidationError]]:
|
||||
if value is None:
|
||||
return True, None
|
||||
try:
|
||||
int(value)
|
||||
return True, None
|
||||
except ValueError:
|
||||
return False, ValidationError(
|
||||
"Invalid integer value",
|
||||
value=value
|
||||
)
|
||||
|
||||
|
||||
class BooleanValidator:
|
||||
"""Validator for boolean type."""
|
||||
|
||||
TRUE_VALUES = {"true", "1", "yes", "on"}
|
||||
FALSE_VALUES = {"false", "0", "no", "off"}
|
||||
|
||||
@staticmethod
|
||||
def validate(value: Optional[str]) -> tuple[bool, Optional[ValidationError]]:
|
||||
if value is None:
|
||||
return True, None
|
||||
value_lower = value.lower().strip()
|
||||
if value_lower in BooleanValidator.TRUE_VALUES:
|
||||
return True, None
|
||||
if value_lower in BooleanValidator.FALSE_VALUES:
|
||||
return True, None
|
||||
return False, ValidationError(
|
||||
"Invalid boolean value (expected: true, false, 1, 0, yes, no, on, off)",
|
||||
value=value
|
||||
)
|
||||
|
||||
|
||||
class ListValidator:
|
||||
"""Validator for list type (comma-separated values)."""
|
||||
|
||||
@staticmethod
|
||||
def validate(value: Optional[str]) -> tuple[bool, Optional[ValidationError]]:
|
||||
if value is None:
|
||||
return True, None
|
||||
if "," in value:
|
||||
return True, None
|
||||
return False, ValidationError(
|
||||
"Invalid list value (expected comma-separated values)",
|
||||
value=value
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def parse(value: str) -> list[str]:
|
||||
"""Parse a comma-separated string into a list.
|
||||
|
||||
Args:
|
||||
value: Comma-separated string.
|
||||
|
||||
Returns:
|
||||
List of values.
|
||||
"""
|
||||
return [item.strip() for item in value.split(",") if item.strip()]
|
||||
|
||||
|
||||
class PatternValidator:
|
||||
"""Validator for pattern/regex validation."""
|
||||
|
||||
@staticmethod
|
||||
def validate(value: Optional[str], pattern: str) -> tuple[bool, Optional[ValidationError]]:
|
||||
if value is None:
|
||||
return True, None
|
||||
try:
|
||||
if re.match(pattern, value):
|
||||
return True, None
|
||||
return False, ValidationError(
|
||||
f"Value does not match pattern: {pattern}",
|
||||
value=value
|
||||
)
|
||||
except re.error:
|
||||
return False, ValidationError(
|
||||
f"Invalid regex pattern: {pattern}",
|
||||
value=value
|
||||
)
|
||||
|
||||
|
||||
def get_validator(var_type: EnvVarType):
|
||||
"""Get the validator class for a given type.
|
||||
|
||||
Args:
|
||||
var_type: The environment variable type.
|
||||
|
||||
Returns:
|
||||
Validator class.
|
||||
"""
|
||||
validators = {
|
||||
EnvVarType.STRING: StringValidator,
|
||||
EnvVarType.INTEGER: IntegerValidator,
|
||||
EnvVarType.BOOLEAN: BooleanValidator,
|
||||
EnvVarType.LIST: ListValidator,
|
||||
}
|
||||
return validators.get(var_type, StringValidator)
|
||||
|
||||
|
||||
def validate_value(value: Optional[str], var_type: EnvVarType, pattern: Optional[str] = None) -> tuple[bool, Optional[ValidationError]]:
|
||||
"""Validate a value against a type and optional pattern.
|
||||
|
||||
Args:
|
||||
value: The value to validate.
|
||||
var_type: The expected type.
|
||||
pattern: Optional regex pattern.
|
||||
|
||||
Returns:
|
||||
Tuple of (is_valid, error).
|
||||
"""
|
||||
validator = get_validator(var_type)
|
||||
is_valid, error = validator.validate(value)
|
||||
|
||||
if is_valid and pattern and value is not None:
|
||||
is_valid, error = PatternValidator.validate(value, pattern)
|
||||
|
||||
return is_valid, error
|
||||
Reference in New Issue
Block a user