"""AssertionState class."""
from collections.abc import Iterable
from typing import TYPE_CHECKING, List, Match, Sequence, Union
from text_lint.exceptions.assertions import (
AssertionLogicError,
AssertionViolation,
)
from text_lint.utilities.translations import _
from .bases.state_base import StateBase
if TYPE_CHECKING: # no cover
from text_lint.linter import Linter
from text_lint.operations.assertions.bases.assertion_base import (
AssertionBase,
)
[Doku]
class AssertionState(StateBase):
"""State for assertion operations."""
operation: "AssertionBase"
msg_fmt_logic_error_rewind = _(
"An assertion may not rewind the text file twice."
)
[Doku]
def __init__(self, linter: "Linter") -> None:
"""Initialize AssertionState instances.
:param linter: The linter instance being encapsulated.
"""
super().__init__(linter)
self.rewound = -1
self.operation = linter.assertions.last
[Doku]
def fail(self, expected: str) -> None:
"""Raise an exception indicating this operation has failed.
:param expected: The value the assertion operation was expecting.
"""
raise AssertionViolation(
assertion=self.operation,
expected=expected,
textfile=self._linter.textfile,
)
[Doku]
def loop(self, assertions: List["AssertionBase"], count: int) -> None:
"""Start a looped sequence of assertions after the current operation.
:param assertions: A list of assertion operations to loop over.
:param count: The number of times to repeat these operations.
"""
self._linter.assertions.insert(assertions, count)
[Doku]
def next(self) -> str:
"""Read the next line from the text file.
:returns: The next line from the text file.
"""
return next(self._linter.textfile)
[Doku]
def rewind(self) -> str:
"""Rewind the text file so another assertion can try matching.
:returns: The previous line the text file has been rewound to.
:raises: AssertionLogicError (if invoked twice in a row)
"""
if self._linter.textfile.index == self.rewound:
raise AssertionLogicError(
assertion=self.operation,
hint=self.msg_fmt_logic_error_rewind,
textfile=self._linter.textfile,
)
self._linter.textfile.index -= 1
self.rewound = self._linter.textfile.index
return self._linter.textfile.current
[Doku]
def save(self, matches: Union[Match[str], Sequence[Match[str]]]) -> None:
"""Save the given regex match group(s).
:param matches: A list or individual regex match object to save.
"""
if self.operation.save and matches:
if not isinstance(matches, Iterable):
matches = [matches]
result_tree = self.operation.create_result_tree(matches)
self._linter.forest.add(result_tree)