Initial upload: ConfDoc v0.1.0 - Config validation and documentation generator

This commit is contained in:
2026-01-31 07:10:13 +00:00
parent bab4f91da7
commit af95b69646

View File

@@ -0,0 +1,148 @@
from typing import Any, Dict, List, Optional
from enum import Enum
class ErrorSeverity(Enum):
"""Classification of validation error severity."""
CRITICAL = "critical"
ERROR = "error"
WARNING = "warning"
INFO = "info"
class ValidationError:
"""Represents a validation error with location and severity."""
def __init__(
self,
message: str,
path: Optional[str] = None,
line: Optional[int] = None,
column: Optional[int] = None,
severity: ErrorSeverity = ErrorSeverity.ERROR,
suggestion: Optional[str] = None,
validator: Optional[str] = None,
):
self.message = message
self.path = path
self.line = line
self.column = column
self.severity = severity
self.suggestion = suggestion
self.validator = validator
def to_dict(self) -> Dict[str, Any]:
"""Convert error to dictionary."""
return {
"message": self.message,
"path": self.path,
"line": self.line,
"column": self.column,
"severity": self.severity.value,
"suggestion": self.suggestion,
"validator": self.validator,
}
def __str__(self) -> str:
"""Format error as string."""
location = ""
if self.path:
location = f" in '{self.path}'"
elif self.line:
location = f" at line {self.line}"
if self.column:
location += f", column {self.column}"
result = f"{self.message}{location}"
if self.suggestion:
result += f". Suggestion: {self.suggestion}"
return result
def __repr__(self) -> str:
return f"ValidationError(message='{self.message}', path='{self.path}', severity={self.severity.value})"
class ErrorFormatter:
"""Formats validation errors for display."""
@staticmethod
def format_error(error: ValidationError, color: bool = True) -> str:
"""Format a single error."""
prefix = ""
if color:
if error.severity == ErrorSeverity.CRITICAL:
prefix = "[red][CRITICAL][/red] "
elif error.severity == ErrorSeverity.ERROR:
prefix = "[red]✗[/red] "
elif error.severity == ErrorSeverity.WARNING:
prefix = "[yellow]![/yellow] "
else:
prefix = "[blue]i[/blue] "
location = ""
if error.path:
location = f" [dim]({error.path})[/dim]"
elif error.line:
location = f" [dim](line {error.line})[/dim]"
suggestion = ""
if error.suggestion:
suggestion = f"\n [dim]→ {error.suggestion}[/dim]"
return f"{prefix}{error.message}{location}{suggestion}"
@staticmethod
def format_errors(errors: List[ValidationError], color: bool = True) -> str:
"""Format a list of errors."""
if not errors:
return ""
lines = []
for i, error in enumerate(errors, 1):
lines.append(f"{i}. {ErrorFormatter.format_error(error, color)}")
return "\n".join(lines)
@staticmethod
def classify_severity(validator_error: Dict[str, Any]) -> ErrorSeverity:
"""Classify the severity of a jsonschema error."""
validator = validator_error.get("validator", "")
if validator in ("required", "additionalProperties"):
return ErrorSeverity.CRITICAL
elif validator in ("type", "enum"):
return ErrorSeverity.ERROR
elif validator in ("minimum", "maximum", "minLength", "maxLength", "pattern"):
return ErrorSeverity.WARNING
else:
return ErrorSeverity.INFO
@staticmethod
def generate_suggestion(validator_error: Dict[str, Any]) -> Optional[str]:
"""Generate a suggestion for fixing a validation error."""
validator = validator_error.get("validator", "")
validator_value = validator_error.get("validator_value", "")
if validator == "required":
missing = validator_error.get("missing_property", "")
return f"Add the required property '{missing}' to your configuration."
elif validator == "type":
expected_type = validator_error.get("expected", "")
actual_type = validator_error.get("found", "")
return f"Expected type {expected_type}, but got {actual_type}."
elif validator == "enum":
allowed = ", ".join(validator_value) if isinstance(validator_value, list) else str(validator_value)
return f"Value must be one of: {allowed}"
elif validator == "minimum":
return f"Value must be greater than or equal to {validator_value}."
elif validator == "maximum":
return f"Value must be less than or equal to {validator_value}."
elif validator == "minLength":
return f"Value must have at least {validator_value} characters."
elif validator == "maxLength":
return f"Value must have at most {validator_value} characters."
elif validator == "pattern":
return f"Value must match the pattern: {validator_value}"
return None