Add formatters, utils, schemas and version
Some checks failed
CI / test (3.10) (push) Has been cancelled
CI / test (3.11) (push) Has been cancelled
CI / test (3.12) (push) Has been cancelled
CI / test (3.8) (push) Has been cancelled
CI / test (3.9) (push) Has been cancelled
CI / lint (push) Has been cancelled
CI / typecheck (push) Has been cancelled
CI / build-package (push) Has been cancelled
Some checks failed
CI / test (3.10) (push) Has been cancelled
CI / test (3.11) (push) Has been cancelled
CI / test (3.12) (push) Has been cancelled
CI / test (3.8) (push) Has been cancelled
CI / test (3.9) (push) Has been cancelled
CI / lint (push) Has been cancelled
CI / typecheck (push) Has been cancelled
CI / build-package (push) Has been cancelled
This commit is contained in:
99
configforge/utils/formatters.py
Normal file
99
configforge/utils/formatters.py
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
"""Output formatting utilities for ConfigForge."""
|
||||||
|
|
||||||
|
import json
|
||||||
|
from typing import Any, Dict, List, Optional
|
||||||
|
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
|
||||||
|
class Formatters:
|
||||||
|
"""Collection of output formatters for different output formats."""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def json(data: Any, indent: int = 2) -> str:
|
||||||
|
"""Format data as JSON."""
|
||||||
|
return json.dumps(data, indent=indent, ensure_ascii=False)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def yaml(data: Any) -> str:
|
||||||
|
"""Format data as YAML."""
|
||||||
|
return yaml.safe_dump(data, default_flow_style=False, allow_unicode=True)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def table(data: List[Dict[str, Any]], columns: Optional[List[str]] = None) -> str:
|
||||||
|
"""Format data as a table."""
|
||||||
|
if not data:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
if columns is None:
|
||||||
|
columns = list(data[0].keys()) if data else []
|
||||||
|
|
||||||
|
if not columns:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
col_widths = {col: len(col) for col in columns}
|
||||||
|
for row in data:
|
||||||
|
for col in columns:
|
||||||
|
if col in row:
|
||||||
|
col_widths[col] = max(col_widths[col], len(str(row.get(col, ""))))
|
||||||
|
|
||||||
|
header = " ".join(col.ljust(col_widths[col]) for col in columns)
|
||||||
|
separator = " ".join("-" * col_widths[col] for col in columns)
|
||||||
|
rows = []
|
||||||
|
|
||||||
|
for row in data:
|
||||||
|
row_str = " ".join(
|
||||||
|
str(row.get(col, "")).ljust(col_widths[col]) for col in columns
|
||||||
|
)
|
||||||
|
rows.append(row_str)
|
||||||
|
|
||||||
|
return "\n".join([header, separator] + rows)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def validation_error(error: Dict[str, Any], verbose: bool = False) -> str:
|
||||||
|
"""Format a validation error."""
|
||||||
|
path = error.get("path", [])
|
||||||
|
path_str = ".".join(path) if path else "root"
|
||||||
|
|
||||||
|
message = error.get("message", "Unknown error")
|
||||||
|
severity = error.get("severity", "error")
|
||||||
|
|
||||||
|
lines = []
|
||||||
|
lines.append(f"[{severity.upper()}] {path_str}")
|
||||||
|
lines.append(f" Message: {message}")
|
||||||
|
|
||||||
|
if verbose:
|
||||||
|
if "validator" in error:
|
||||||
|
lines.append(f" Validator: {error['validator']}")
|
||||||
|
if "validator_value" in error:
|
||||||
|
lines.append(f" Value: {error['validator_value']}")
|
||||||
|
if "constraint" in error:
|
||||||
|
lines.append(f" Constraint: {error['constraint']}")
|
||||||
|
|
||||||
|
return "\n".join(lines)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def summary(
|
||||||
|
total: int,
|
||||||
|
passed: int,
|
||||||
|
failed: int,
|
||||||
|
errors: Optional[List[Dict[str, Any]]] = None,
|
||||||
|
) -> str:
|
||||||
|
"""Format a validation summary."""
|
||||||
|
lines = []
|
||||||
|
lines.append("=" * 50)
|
||||||
|
lines.append("Validation Summary")
|
||||||
|
lines.append("=" * 50)
|
||||||
|
lines.append(f"Total: {total}")
|
||||||
|
lines.append(f"Passed: {passed}")
|
||||||
|
lines.append(f"Failed: {failed}")
|
||||||
|
lines.append("-" * 50)
|
||||||
|
|
||||||
|
if failed > 0 and errors:
|
||||||
|
lines.append("\nValidation Errors:")
|
||||||
|
lines.append("-" * 50)
|
||||||
|
for i, error in enumerate(errors, 1):
|
||||||
|
lines.append(f"{i}. {Formatters.validation_error(error)}")
|
||||||
|
lines.append("")
|
||||||
|
|
||||||
|
return "\n".join(lines)
|
||||||
Reference in New Issue
Block a user