Coverage for src/evutils/io/stream.py: 100%
28 statements
« prev ^ index » next coverage.py v7.15.1, created at 2026-07-18 05:24 +0000
« prev ^ index » next coverage.py v7.15.1, created at 2026-07-18 05:24 +0000
1from typing import Iterator
3from evutils.io._source import make_source
4from evutils.io.decoders import resolve_decoder_cls
5from evutils.types import TriggerArray
7class EventStreamer:
8 """A low-level streamer that yields raw event blocks exactly as the parser outputs them.
9 It performs ZERO slicing or logic; it purely drives the decoder.
10 """
11 def __init__(self, file: "Path | str | bytes | io.BufferedIOBase", ext_trigger: bool = False, decoder_cls: "Type | None" = None, **kwargs) -> None:
12 self.source = make_source(file)
13 if decoder_cls is None:
14 decoder_cls = resolve_decoder_cls(self.source)
16 # Set the flag as an attribute after construction (as EventReader does)
17 # rather than forcing it through every decoder's __init__: several
18 # decoders (DAT/NPZ/HDF5/CSV) don't accept it as a constructor kwarg.
19 self.decoder = decoder_cls(self.source, **kwargs)
20 self.decoder.read_external_triggers = ext_trigger
21 self.ext_trigger = ext_trigger
23 def __iter__(self) -> "Iterator[EventArray]":
24 self.decoder.init()
25 while True:
26 chunk = self.decoder.read_chunk()
28 if self.ext_trigger:
29 if isinstance(chunk, tuple):
30 ev_chunk, tr_chunk = chunk
31 else:
32 ev_chunk = chunk
33 tr_chunk = TriggerArray.empty()
34 else:
35 ev_chunk = chunk[0] if isinstance(chunk, tuple) else chunk
36 tr_chunk = None
38 if len(ev_chunk) == 0 and (tr_chunk is None or len(tr_chunk) == 0):
39 break
41 if self.ext_trigger:
42 yield ev_chunk, tr_chunk
43 else:
44 yield ev_chunk