Spaces:
Sleeping
Sleeping
| from __future__ import annotations | |
| from collections.abc import Iterator | |
| from typing import Protocol, runtime_checkable | |
| from redstack.domain.errors import DomainError | |
| from redstack.ports._types import SourceRecord | |
| class CandidateSourceError(DomainError): | |
| """Cannot open or decompress the source, or a low-level IO error occurred. | |
| Per-line decode failures are *not* this error — they surface as | |
| ``SourceMalformed`` records so the pipeline can apply skip-vs-abort policy. | |
| """ | |
| class CandidateSourcePort(Protocol): | |
| """Lazy, single-pass, order-preserving stream of raw candidate records.""" | |
| def stream(self) -> Iterator[SourceRecord]: | |
| """Yield records lazily in file order, one at a time. | |
| Each ``SourceOk`` carries the undecoded record plus ``source_index`` | |
| (enumeration order) and ``line_no``; each ``SourceMalformed`` carries | |
| ``line_no`` and an error string. Calling ``stream`` again starts a | |
| fresh, independent pass (a new iterator). | |
| Raises: | |
| CandidateSourceError: the source cannot be opened or decompressed, | |
| or an IO error occurs mid-stream. | |
| """ | |
| ... | |
| def count(self) -> int | None: | |
| """Return the record count, or ``None`` if unknown without a full pass.""" | |
| ... | |
| __all__: tuple[str, ...] = ("CandidateSourceError", "CandidateSourcePort") | |