|
1 | | -from typing import Generator, List, Optional, Tuple, cast, overload |
2 | | - |
3 | | -from ..utils.context_managed_generator import ContextManagedGenerator |
4 | | - |
5 | | -from .scripture_ref import ScriptureRef |
| 1 | +from queue import SimpleQueue |
| 2 | +from typing import Any, Generator, List, Optional, Tuple, cast, ContextManager |
6 | 3 |
|
7 | 4 | from ..scripture.verse_ref import Versification |
| 5 | +from .scripture_ref import EMPTY_SCRIPTURE_REF, ScriptureRef |
8 | 6 | from .text_row import TextRow, TextRowFlags |
9 | 7 |
|
10 | 8 |
|
11 | | -class _TextCorpusEnumerator(ContextManagedGenerator[TextRow, None, None]): |
| 9 | +class _TextCorpusEnumerator(ContextManager["_TextCorpusEnumerator"], Generator[TextRow, None, None]): |
12 | 10 | def __init__( |
13 | | - self, enumerator: Generator[TextRow, None, None], ref_versification: Versification, versification: Versification |
| 11 | + self, generator: Generator[TextRow, None, None], ref_versification: Versification, versification: Versification |
14 | 12 | ): |
15 | | - self._enumerator = enumerator |
| 13 | + self._generator = generator |
16 | 14 | self._ref_versification = ref_versification |
17 | 15 | self._is_scripture = ( |
18 | 16 | ref_versification is not None and versification is not None and ref_versification != versification |
19 | 17 | ) |
20 | | - self._verse_rows: List[TextRow] = [] |
21 | 18 | self._is_enumerating = False |
22 | | - self._enumerator_has_more_data = True |
23 | | - self._current: Optional[TextRow] = None |
24 | | - |
25 | | - def __iter__(self): |
26 | | - return self |
27 | | - |
28 | | - def __next__(self) -> TextRow: |
29 | | - if not self.move_next() or self._current is None: |
30 | | - raise StopIteration |
31 | | - return self._current |
32 | | - |
33 | | - @property |
34 | | - def current(self): |
35 | | - return self._current |
| 19 | + self._verse_rows: SimpleQueue[TextRow] = SimpleQueue() |
| 20 | + self._row: Optional[TextRow] = None |
36 | 21 |
|
37 | | - def move_next(self) -> bool: |
| 22 | + def send(self, value: None) -> TextRow: |
38 | 23 | if self._is_scripture: |
39 | 24 | if not self._is_enumerating: |
40 | | - self._current = self._enumerator.__next__() |
| 25 | + self._row = next(self._generator, None) |
41 | 26 | self._is_enumerating = True |
42 | | - if len(self._verse_rows) == 0 and self._current is not None and self._enumerator_has_more_data: |
| 27 | + if self._verse_rows.empty() and self._row is not None: |
43 | 28 | self._collect_verses() |
44 | | - if len(self._verse_rows) > 0: |
45 | | - self._current = self._verse_rows.pop(0) |
46 | | - return True |
47 | | - self._current = None |
48 | | - return False |
| 29 | + if not self._verse_rows.empty(): |
| 30 | + return self._verse_rows.get() |
| 31 | + raise StopIteration |
| 32 | + |
| 33 | + self._row = next(self._generator, None) |
| 34 | + if self._row is not None: |
| 35 | + return self._row |
| 36 | + raise StopIteration |
| 37 | + |
| 38 | + def throw(self, type: Any, value: Any = None, traceback: Any = None) -> TextRow: |
| 39 | + raise StopIteration |
49 | 40 |
|
50 | | - self._current = self._enumerator.__next__() |
51 | | - self._enumerator_has_more_data = self._current != None |
52 | | - return self._enumerator_has_more_data |
| 41 | + def close(self) -> None: |
| 42 | + super().close() |
| 43 | + self._generator.close() |
53 | 44 |
|
54 | | - # Not porting reset() since it is unused |
| 45 | + def __enter__(self) -> "_TextCorpusEnumerator": |
| 46 | + return self |
| 47 | + |
| 48 | + def __exit__(self, type: Any, value: Any, traceback: Any) -> None: |
| 49 | + self.close() |
55 | 50 |
|
56 | 51 | def _collect_verses(self): |
| 52 | + assert self._ref_versification is not None |
57 | 53 | rows: List[Tuple[ScriptureRef, TextRow]] = [] |
58 | | - out_of_order: bool = False |
59 | | - prev_ref = ScriptureRef._empty |
60 | | - range_start_offset: int = -1 |
61 | | - while True: |
62 | | - row = cast(TextRow, self._current) |
| 54 | + out_of_order = False |
| 55 | + prev_ref = EMPTY_SCRIPTURE_REF |
| 56 | + range_start_offset = -1 |
| 57 | + while self._row is not None: |
| 58 | + row = cast(TextRow, self._row) |
63 | 59 | ref = cast(ScriptureRef, row.ref) |
64 | | - if prev_ref is not None and not prev_ref.is_empty and ref.book_num != prev_ref.book_num: |
| 60 | + if not prev_ref.is_empty and ref.book_num != prev_ref.book_num: |
65 | 61 | break |
66 | 62 |
|
67 | 63 | ref = ref.change_versification(self._ref_versification) |
| 64 | + # convert one-to-many mapping to a verse range |
68 | 65 | if ref == prev_ref: |
69 | | - range_start_ref, range_start_row = rows[len(rows) + range_start_offset] |
| 66 | + range_start_ref, range_start_row = rows[range_start_offset] |
70 | 67 | flags = TextRowFlags.IN_RANGE |
71 | 68 | if range_start_row.is_sentence_start: |
72 | 69 | flags |= TextRowFlags.SENTENCE_START |
73 | 70 | if range_start_offset == -1 and (not range_start_row.is_in_range or range_start_row.is_range_start): |
74 | 71 | flags |= TextRowFlags.RANGE_START |
75 | | - new_text_row = TextRow(range_start_row.text_id, range_start_row.ref) |
76 | | - new_text_row.segment = list(range_start_row.segment) + list(row.segment) |
77 | | - new_text_row.flags = flags |
78 | | - rows[len(rows) + range_start_offset] = range_start_ref, new_text_row |
| 72 | + new_text_row = TextRow( |
| 73 | + range_start_row.text_id, |
| 74 | + range_start_row.ref, |
| 75 | + segment=list(range_start_row.segment) + list(row.segment), |
| 76 | + flags=flags, |
| 77 | + ) |
| 78 | + rows[range_start_offset] = range_start_ref, new_text_row |
| 79 | + row = TextRow(row.text_id, row.ref, flags=TextRowFlags.IN_RANGE) |
79 | 80 | range_start_offset -= 1 |
80 | 81 | else: |
81 | 82 | range_start_offset = -1 |
82 | 83 | rows.append((ref, row)) |
83 | | - if not out_of_order and ref.compare_to(prev_ref) < 0: |
| 84 | + if not out_of_order and ref < prev_ref: |
84 | 85 | out_of_order = True |
85 | 86 | prev_ref = ref |
86 | | - self._enumerator_has_more_data = bool(self._enumerator.__next__()) |
87 | | - if not self._enumerator_has_more_data: |
88 | | - break |
| 87 | + self._row = next(self._generator, None) |
89 | 88 |
|
90 | 89 | if out_of_order: |
91 | | - rows.sort(key=lambda tup: tup[0]) |
| 90 | + rows.sort(key=lambda t: t[0]) |
92 | 91 |
|
93 | 92 | for _, row in rows: |
94 | | - self._verse_rows.append(row) |
| 93 | + self._verse_rows.put(row) |
0 commit comments