"""Error reporting utilities for CoNLL-U validation."""
from dataclasses import dataclass
from typing import Any
[docs]
class ValidationError(Exception):
"""Custom exception for validation errors."""
[docs]
@dataclass
class ErrorEntry:
"""Represents a single validation error."""
alt_id: str | None
testlevel: int
error_type: str
testid: str
msg: str
node_id: str | None
line_no: int | None
tree_counter: int | None
[docs]
def __str__(self) -> str:
"""Format the error as a string."""
line = f'Line {self.line_no}' if self.line_no else None
sentence = f'Sentence {self.alt_id}' if self.alt_id else None
output = line if line else ''
if sentence:
output += f' {sentence}: ' if output else f'{sentence}: '
else:
output += ': ' if output else ''
output += f'[L{self.testlevel} {self.error_type} {self.testid}] {self.msg}'
return output
[docs]
class ErrorReporter:
"""Manages error collection and reporting for validation."""
[docs]
def __init__(self) -> None:
"""Initialize the error reporter."""
self.errors: list[tuple[str | None, int, int, ErrorEntry]] = []
self.error_counter: dict[str, int] = {}
self.tree_counter = 0
self.sentence_id: str | None = None
self.sentence_mapid: dict[str, dict[str, Any]] = {}
[docs]
def reset(self) -> None:
"""Reset the error reporter state."""
self.errors.clear()
self.error_counter.clear()
self.tree_counter = 0
self.sentence_id = None
[docs]
def warn( # noqa: PLR0913
self,
msg: str,
error_type: str,
testlevel: int = 0,
testid: str = 'some-test',
line_no: int | None = None,
node_id: str | None = None,
) -> None:
"""Record a validation warning/error.
Arguments:
msg: Error message
error_type: Type/category of error
testlevel: Level of the test (1-5)
testid: Identifier for the test
line_no: Line number where error occurred
node_id: Node ID if applicable
"""
self.error_counter[error_type] = self.error_counter.get(error_type, 0) + 1
alt_id = self.sentence_mapid.get(self.sentence_id or '', {}).get('alt_id') if self.sentence_mapid else None
order = self.sentence_mapid.get(self.sentence_id or '', {}).get('order', 0) if self.sentence_mapid else 0
entry = ErrorEntry(
alt_id=alt_id,
testlevel=testlevel,
error_type=error_type,
testid=testid,
msg=msg,
node_id=node_id,
line_no=line_no,
tree_counter=self.tree_counter or None,
)
self.errors.append((self.sentence_id, order, testlevel, entry))
[docs]
def get_error_count(self) -> int:
"""Get the total number of errors."""
return len(self.errors)