omlish 0.0.0.dev164__py3-none-any.whl → 0.0.0.dev166__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- omlish/.manifests.json +30 -2
- omlish/__about__.py +2 -2
- omlish/codecs/__init__.py +3 -0
- omlish/codecs/base.py +4 -0
- omlish/codecs/funcs.py +11 -0
- omlish/codecs/text.py +2 -2
- omlish/formats/cloudpickle.py +31 -0
- omlish/formats/json/codecs.py +0 -4
- omlish/formats/json/delimted.py +4 -0
- omlish/formats/yaml.py +7 -0
- omlish/funcs/pairs.py +0 -281
- omlish/io/compress/codecs.py +20 -0
- omlish/io/generators/__init__.py +3 -0
- omlish/io/generators/stepped.py +19 -3
- omlish/iterators/__init__.py +24 -0
- omlish/iterators/iterators.py +132 -0
- omlish/iterators/recipes.py +18 -0
- omlish/iterators/tools.py +96 -0
- omlish/iterators/unique.py +67 -0
- {omlish-0.0.0.dev164.dist-info → omlish-0.0.0.dev166.dist-info}/METADATA +1 -1
- {omlish-0.0.0.dev164.dist-info → omlish-0.0.0.dev166.dist-info}/RECORD +25 -19
- omlish/iterators.py +0 -300
- {omlish-0.0.0.dev164.dist-info → omlish-0.0.0.dev166.dist-info}/LICENSE +0 -0
- {omlish-0.0.0.dev164.dist-info → omlish-0.0.0.dev166.dist-info}/WHEEL +0 -0
- {omlish-0.0.0.dev164.dist-info → omlish-0.0.0.dev166.dist-info}/entry_points.txt +0 -0
- {omlish-0.0.0.dev164.dist-info → omlish-0.0.0.dev166.dist-info}/top_level.txt +0 -0
omlish/iterators.py
DELETED
@@ -1,300 +0,0 @@
|
|
1
|
-
import collections
|
2
|
-
import dataclasses as dc
|
3
|
-
import functools
|
4
|
-
import heapq
|
5
|
-
import itertools
|
6
|
-
import typing as ta
|
7
|
-
|
8
|
-
# from . import check
|
9
|
-
from . import lang
|
10
|
-
|
11
|
-
|
12
|
-
T = ta.TypeVar('T')
|
13
|
-
U = ta.TypeVar('U')
|
14
|
-
|
15
|
-
_MISSING = object()
|
16
|
-
|
17
|
-
|
18
|
-
class PeekIterator(ta.Iterator[T]):
|
19
|
-
|
20
|
-
def __init__(self, it: ta.Iterable[T]) -> None:
|
21
|
-
super().__init__()
|
22
|
-
|
23
|
-
self._it = iter(it)
|
24
|
-
self._pos = -1
|
25
|
-
self._next_item: ta.Any = _MISSING
|
26
|
-
|
27
|
-
_item: T
|
28
|
-
|
29
|
-
def __iter__(self) -> ta.Self:
|
30
|
-
return self
|
31
|
-
|
32
|
-
@property
|
33
|
-
def done(self) -> bool:
|
34
|
-
try:
|
35
|
-
self.peek()
|
36
|
-
except StopIteration:
|
37
|
-
return True
|
38
|
-
else:
|
39
|
-
return False
|
40
|
-
|
41
|
-
def __next__(self) -> T:
|
42
|
-
if self._next_item is not _MISSING:
|
43
|
-
self._item = ta.cast(T, self._next_item)
|
44
|
-
self._next_item = _MISSING
|
45
|
-
else:
|
46
|
-
self._item = next(self._it)
|
47
|
-
self._pos += 1
|
48
|
-
return self._item
|
49
|
-
|
50
|
-
def peek(self) -> T:
|
51
|
-
if self._next_item is not _MISSING:
|
52
|
-
return ta.cast(T, self._next_item)
|
53
|
-
self._next_item = next(self._it)
|
54
|
-
return self._next_item
|
55
|
-
|
56
|
-
def next_peek(self) -> T:
|
57
|
-
next(self)
|
58
|
-
return self.peek()
|
59
|
-
|
60
|
-
def takewhile(self, fn: ta.Callable[[T], bool]) -> ta.Iterator[T]:
|
61
|
-
while fn(self.peek()):
|
62
|
-
yield next(self)
|
63
|
-
|
64
|
-
def skipwhile(self, fn: ta.Callable[[T], bool]) -> None:
|
65
|
-
while fn(self.peek()):
|
66
|
-
next(self)
|
67
|
-
|
68
|
-
def takeuntil(self, fn: ta.Callable[[T], bool]) -> ta.Iterator[T]:
|
69
|
-
return self.takewhile(lambda e: not fn(e))
|
70
|
-
|
71
|
-
def skipuntil(self, fn: ta.Callable[[T], bool]) -> None:
|
72
|
-
self.skipwhile(lambda e: not fn(e))
|
73
|
-
|
74
|
-
def takethrough(self, pos: int) -> ta.Iterator[T]:
|
75
|
-
return self.takewhile(lambda _: self._pos < pos)
|
76
|
-
|
77
|
-
def skipthrough(self, pos: int) -> None:
|
78
|
-
self.skipwhile(lambda _: self._pos < pos)
|
79
|
-
|
80
|
-
def taketo(self, pos: int) -> ta.Iterator[T]:
|
81
|
-
return self.takethrough(pos - 1)
|
82
|
-
|
83
|
-
def skipto(self, pos: int) -> None:
|
84
|
-
self.skipthrough(pos - 1)
|
85
|
-
|
86
|
-
|
87
|
-
class ProxyIterator(ta.Iterator[T]):
|
88
|
-
|
89
|
-
def __init__(self, fn: ta.Callable[[], T]) -> None:
|
90
|
-
self._fn = fn
|
91
|
-
|
92
|
-
def __iter__(self) -> ta.Self:
|
93
|
-
return self
|
94
|
-
|
95
|
-
def __next__(self) -> T:
|
96
|
-
return self._fn()
|
97
|
-
|
98
|
-
|
99
|
-
class PrefetchIterator(ta.Iterator[T]):
|
100
|
-
|
101
|
-
def __init__(self, fn: ta.Callable[[], T] | None = None) -> None:
|
102
|
-
super().__init__()
|
103
|
-
|
104
|
-
self._fn = fn
|
105
|
-
self._deque: collections.deque[T] = collections.deque()
|
106
|
-
|
107
|
-
def __iter__(self) -> ta.Self:
|
108
|
-
return self
|
109
|
-
|
110
|
-
def push(self, item) -> None:
|
111
|
-
self._deque.append(item)
|
112
|
-
|
113
|
-
def __next__(self) -> T:
|
114
|
-
try:
|
115
|
-
return self._deque.popleft()
|
116
|
-
except IndexError:
|
117
|
-
if self._fn is None:
|
118
|
-
raise StopIteration from None
|
119
|
-
return self._fn()
|
120
|
-
|
121
|
-
|
122
|
-
class RetainIterator(ta.Iterator[T]):
|
123
|
-
|
124
|
-
def __init__(self, fn: ta.Callable[[], T]) -> None:
|
125
|
-
super().__init__()
|
126
|
-
|
127
|
-
self._fn = fn
|
128
|
-
self._deque: collections.deque[T] = collections.deque()
|
129
|
-
|
130
|
-
def __iter__(self) -> ta.Self:
|
131
|
-
return self
|
132
|
-
|
133
|
-
def pop(self) -> None:
|
134
|
-
self._deque.popleft()
|
135
|
-
|
136
|
-
def __next__(self) -> T:
|
137
|
-
item = self._fn()
|
138
|
-
self._deque.append(item)
|
139
|
-
return item
|
140
|
-
|
141
|
-
|
142
|
-
def unzip(it: ta.Iterable[T], width: int | None = None) -> list:
|
143
|
-
if width is None:
|
144
|
-
if not isinstance(it, PeekIterator):
|
145
|
-
it = PeekIterator(iter(it))
|
146
|
-
try:
|
147
|
-
width = len(it.peek())
|
148
|
-
except StopIteration:
|
149
|
-
return []
|
150
|
-
|
151
|
-
its: list[PrefetchIterator[T]] = []
|
152
|
-
running = True
|
153
|
-
|
154
|
-
def next_fn(idx):
|
155
|
-
nonlocal running
|
156
|
-
if not running:
|
157
|
-
raise StopIteration
|
158
|
-
try:
|
159
|
-
items = next(it) # type: ignore
|
160
|
-
except StopIteration:
|
161
|
-
running = False
|
162
|
-
raise
|
163
|
-
for item_idx, item in enumerate(items):
|
164
|
-
its[item_idx].push(item)
|
165
|
-
return next(its[idx])
|
166
|
-
|
167
|
-
its.extend(PrefetchIterator(functools.partial(next_fn, idx)) for idx in range(width))
|
168
|
-
return its
|
169
|
-
|
170
|
-
|
171
|
-
def take(n: int, iterable: ta.Iterable[T]) -> list[T]:
|
172
|
-
return list(itertools.islice(iterable, n))
|
173
|
-
|
174
|
-
|
175
|
-
def chunk(n: int, iterable: ta.Iterable[T], strict: bool = False) -> ta.Iterator[list[T]]:
|
176
|
-
iterator = iter(functools.partial(take, n, iter(iterable)), [])
|
177
|
-
if strict:
|
178
|
-
def ret():
|
179
|
-
for chunk in iterator:
|
180
|
-
if len(chunk) != n:
|
181
|
-
raise ValueError('iterable is not divisible by n.')
|
182
|
-
yield chunk
|
183
|
-
return iter(ret())
|
184
|
-
else:
|
185
|
-
return iterator
|
186
|
-
|
187
|
-
|
188
|
-
def merge_on(
|
189
|
-
function: ta.Callable[[T], U],
|
190
|
-
*its: ta.Iterable[T],
|
191
|
-
) -> ta.Iterator[tuple[U, list[tuple[int, T]]]]:
|
192
|
-
indexed_its = [
|
193
|
-
(
|
194
|
-
(function(item), it_idx, item)
|
195
|
-
for it_idx, item in zip(itertools.repeat(it_idx), it)
|
196
|
-
)
|
197
|
-
for it_idx, it in enumerate(its)
|
198
|
-
]
|
199
|
-
|
200
|
-
grouped_indexed_its = itertools.groupby(
|
201
|
-
heapq.merge(*indexed_its),
|
202
|
-
key=lambda item_tuple: item_tuple[0],
|
203
|
-
)
|
204
|
-
|
205
|
-
return (
|
206
|
-
(fn_item, [(it_idx, item) for _, it_idx, item in grp])
|
207
|
-
for fn_item, grp in grouped_indexed_its
|
208
|
-
)
|
209
|
-
|
210
|
-
|
211
|
-
def expand_indexed_pairs(
|
212
|
-
seq: ta.Iterable[tuple[int, T]],
|
213
|
-
default: T,
|
214
|
-
*,
|
215
|
-
width: int | None = None,
|
216
|
-
) -> list[T]:
|
217
|
-
width_ = width
|
218
|
-
if width_ is None:
|
219
|
-
width_ = (max(idx for idx, _ in seq) + 1) if seq else 0
|
220
|
-
result = [default] * width_
|
221
|
-
for idx, value in seq:
|
222
|
-
if idx < width_:
|
223
|
-
result[idx] = value
|
224
|
-
return result
|
225
|
-
|
226
|
-
|
227
|
-
##
|
228
|
-
# https://docs.python.org/3/library/itertools.html#itertools-recipes
|
229
|
-
|
230
|
-
|
231
|
-
def sliding_window(it: ta.Iterable[T], n: int) -> ta.Iterator[tuple[T, ...]]:
|
232
|
-
# sliding_window('ABCDEFG', 4) -> ABCD BCDE CDEF DEFG
|
233
|
-
iterator = iter(it)
|
234
|
-
window = collections.deque(itertools.islice(iterator, n - 1), maxlen=n)
|
235
|
-
for x in iterator:
|
236
|
-
window.append(x)
|
237
|
-
yield tuple(window)
|
238
|
-
|
239
|
-
|
240
|
-
##
|
241
|
-
|
242
|
-
|
243
|
-
@dc.dataclass()
|
244
|
-
class UniqueStats:
|
245
|
-
key: ta.Any
|
246
|
-
num_seen: int
|
247
|
-
first_idx: int
|
248
|
-
last_idx: int
|
249
|
-
|
250
|
-
|
251
|
-
@dc.dataclass(frozen=True)
|
252
|
-
class UniqueItem(ta.Generic[T]):
|
253
|
-
idx: int
|
254
|
-
item: T
|
255
|
-
stats: UniqueStats
|
256
|
-
out: lang.Maybe[T]
|
257
|
-
|
258
|
-
|
259
|
-
class UniqueIterator(ta.Iterator[UniqueItem[T]]):
|
260
|
-
def __init__(
|
261
|
-
self,
|
262
|
-
it: ta.Iterable[T],
|
263
|
-
keyer: ta.Callable[[T], ta.Any] = lang.identity,
|
264
|
-
) -> None:
|
265
|
-
super().__init__()
|
266
|
-
self._it = enumerate(it)
|
267
|
-
self._keyer = keyer
|
268
|
-
|
269
|
-
self.stats: dict[ta.Any, UniqueStats] = {}
|
270
|
-
|
271
|
-
def __next__(self) -> UniqueItem[T]:
|
272
|
-
idx, item = next(self._it)
|
273
|
-
key = self._keyer(item)
|
274
|
-
|
275
|
-
try:
|
276
|
-
stats = self.stats[key]
|
277
|
-
|
278
|
-
except KeyError:
|
279
|
-
stats = self.stats[key] = UniqueStats(
|
280
|
-
key,
|
281
|
-
num_seen=1,
|
282
|
-
first_idx=idx,
|
283
|
-
last_idx=idx,
|
284
|
-
)
|
285
|
-
return UniqueItem(
|
286
|
-
idx,
|
287
|
-
item,
|
288
|
-
stats,
|
289
|
-
lang.just(item),
|
290
|
-
)
|
291
|
-
|
292
|
-
else:
|
293
|
-
stats.num_seen += 1
|
294
|
-
stats.last_idx = idx
|
295
|
-
return UniqueItem(
|
296
|
-
idx,
|
297
|
-
item,
|
298
|
-
stats,
|
299
|
-
lang.empty(),
|
300
|
-
)
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|