iker-python-common 1.0.29__tar.gz → 1.0.31__tar.gz
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.
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/.github/workflows/pr.yml +3 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/.github/workflows/push.yml +1 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/PKG-INFO +2 -2
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/src/iker/common/utils/funcutils.py +5 -5
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/src/iker/common/utils/sequtils.py +60 -57
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/src/iker_python_common.egg-info/PKG-INFO +2 -2
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/test/iker_tests/common/utils/sequtils_test.py +121 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/.editorconfig +0 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/.gitignore +0 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/MANIFEST.in +0 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/README.md +0 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/VERSION +0 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/pyproject.toml +0 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/resources/unittest/config/config.cfg +0 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/resources/unittest/csv/data.csv +0 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/resources/unittest/csv/data.tsv +0 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/resources/unittest/shutils/dir.baz/file.bar.baz +0 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/resources/unittest/shutils/dir.baz/file.foo.bar +0 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/resources/unittest/shutils/dir.baz/file.foo.baz +0 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/resources/unittest/shutils/dir.foo/dir.foo.bar/dir.foo.bar.baz/file.foo.bar.baz +0 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/resources/unittest/shutils/dir.foo/dir.foo.bar/file.bar.baz +0 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/resources/unittest/shutils/dir.foo/dir.foo.bar/file.foo.bar +0 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/resources/unittest/shutils/dir.foo/dir.foo.bar/file.foo.baz +0 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/resources/unittest/shutils/dir.foo/file.bar +0 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/resources/unittest/shutils/dir.foo/file.baz +0 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/resources/unittest/shutils/dir.foo/file.foo +0 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/setup.cfg +0 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/setup.py +0 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/src/iker/common/__init__.py +0 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/src/iker/common/utils/__init__.py +0 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/src/iker/common/utils/argutils.py +0 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/src/iker/common/utils/config.py +0 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/src/iker/common/utils/csv.py +0 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/src/iker/common/utils/dbutils.py +0 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/src/iker/common/utils/dockerutils.py +0 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/src/iker/common/utils/dtutils.py +0 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/src/iker/common/utils/jsonutils.py +0 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/src/iker/common/utils/logger.py +0 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/src/iker/common/utils/numutils.py +0 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/src/iker/common/utils/randutils.py +0 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/src/iker/common/utils/retry.py +0 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/src/iker/common/utils/s3utils.py +0 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/src/iker/common/utils/shutils.py +0 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/src/iker/common/utils/span.py +0 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/src/iker/common/utils/strutils.py +0 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/src/iker/common/utils/testutils.py +0 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/src/iker_python_common.egg-info/SOURCES.txt +0 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/src/iker_python_common.egg-info/dependency_links.txt +0 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/src/iker_python_common.egg-info/not-zip-safe +0 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/src/iker_python_common.egg-info/requires.txt +0 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/src/iker_python_common.egg-info/top_level.txt +0 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/test/iker_test.py +0 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/test/iker_tests/__init__.py +0 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/test/iker_tests/common/utils/argutils_test.py +0 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/test/iker_tests/common/utils/config_test.py +0 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/test/iker_tests/common/utils/csv_test.py +0 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/test/iker_tests/common/utils/dbutils_test.py +0 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/test/iker_tests/common/utils/dockerutils_test.py +0 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/test/iker_tests/common/utils/dtutils_test.py +0 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/test/iker_tests/common/utils/funcutils_test.py +0 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/test/iker_tests/common/utils/jsonutils_test.py +0 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/test/iker_tests/common/utils/logger_test.py +0 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/test/iker_tests/common/utils/numutils_test.py +0 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/test/iker_tests/common/utils/randutils_test.py +0 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/test/iker_tests/common/utils/retry_test.py +0 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/test/iker_tests/common/utils/s3utils_test.py +0 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/test/iker_tests/common/utils/shutils_test.py +0 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/test/iker_tests/common/utils/span_test.py +0 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/test/iker_tests/common/utils/strutils_test.py +0 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/test/iker_tests/common/utils/testutils_test.py +0 -0
- {iker_python_common-1.0.29 → iker_python_common-1.0.31}/test/iker_tests/docker_fixtures.py +0 -0
|
@@ -21,6 +21,7 @@ jobs:
|
|
|
21
21
|
|
|
22
22
|
- name: Build and Test
|
|
23
23
|
run: |
|
|
24
|
+
sudo apt-get update
|
|
24
25
|
sudo apt-get install libxml2-dev libxslt1-dev llvm-14-dev
|
|
25
26
|
python -m pip install --upgrade pip
|
|
26
27
|
python -m pip install .[test]
|
|
@@ -39,6 +40,7 @@ jobs:
|
|
|
39
40
|
|
|
40
41
|
- name: Build and Test
|
|
41
42
|
run: |
|
|
43
|
+
sudo apt-get update
|
|
42
44
|
sudo apt-get install libxml2-dev libxslt1-dev llvm-14-dev
|
|
43
45
|
python -m pip install --upgrade pip
|
|
44
46
|
python -m pip install .[test]
|
|
@@ -57,6 +59,7 @@ jobs:
|
|
|
57
59
|
|
|
58
60
|
- name: Build and Test
|
|
59
61
|
run: |
|
|
62
|
+
sudo apt-get update
|
|
60
63
|
sudo apt-get install libxml2-dev libxslt1-dev llvm-14-dev
|
|
61
64
|
python -m pip install --upgrade pip
|
|
62
65
|
python -m pip install .[test]
|
|
@@ -9,10 +9,10 @@ __all__ = [
|
|
|
9
9
|
"unique_returns",
|
|
10
10
|
]
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
RT = TypeVar("RT")
|
|
13
13
|
|
|
14
14
|
|
|
15
|
-
def singleton(tar: Callable[...,
|
|
15
|
+
def singleton(tar: Callable[..., RT] = None):
|
|
16
16
|
def decorator(target):
|
|
17
17
|
if not callable(target):
|
|
18
18
|
raise TypeError("expected a callable")
|
|
@@ -30,7 +30,7 @@ def singleton(tar: Callable[..., R] = None):
|
|
|
30
30
|
return decorator if tar is None else decorator(tar)
|
|
31
31
|
|
|
32
32
|
|
|
33
|
-
def memorized(tar: Callable[...,
|
|
33
|
+
def memorized(tar: Callable[..., RT] = None, *, ordered: bool = False, typed: bool = False):
|
|
34
34
|
def decorator(target):
|
|
35
35
|
if not callable(target):
|
|
36
36
|
raise TypeError("expected a callable")
|
|
@@ -64,7 +64,7 @@ def memorized(tar: Callable[..., R] = None, *, ordered: bool = False, typed: boo
|
|
|
64
64
|
return decorator if tar is None else decorator(tar)
|
|
65
65
|
|
|
66
66
|
|
|
67
|
-
def lazy(tar: Callable[...,
|
|
67
|
+
def lazy(tar: Callable[..., RT] = None):
|
|
68
68
|
def decorator(target):
|
|
69
69
|
if not callable(target):
|
|
70
70
|
raise TypeError("expected a callable")
|
|
@@ -78,7 +78,7 @@ def lazy(tar: Callable[..., R] = None):
|
|
|
78
78
|
return decorator if tar is None else decorator(tar)
|
|
79
79
|
|
|
80
80
|
|
|
81
|
-
def unique_returns(tar: Callable[...,
|
|
81
|
+
def unique_returns(tar: Callable[..., RT] = None, *, max_trials: int | None = None):
|
|
82
82
|
def decorator(target):
|
|
83
83
|
if not callable(target):
|
|
84
84
|
raise TypeError("expected a callable")
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import functools
|
|
2
2
|
import itertools
|
|
3
3
|
from collections.abc import Callable, Generator, Iterable, Iterator, Sequence, Sized
|
|
4
|
-
from typing import Generic,
|
|
4
|
+
from typing import Generic, TypeVar
|
|
5
5
|
|
|
6
6
|
__all__ = [
|
|
7
7
|
"head",
|
|
@@ -22,9 +22,9 @@ __all__ = [
|
|
|
22
22
|
]
|
|
23
23
|
|
|
24
24
|
T = TypeVar("T")
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
KT = TypeVar("KT")
|
|
26
|
+
VT = TypeVar("VT")
|
|
27
|
+
TT = TypeVar("TT")
|
|
28
28
|
Tco = TypeVar("Tco", covariant=True)
|
|
29
29
|
|
|
30
30
|
|
|
@@ -61,10 +61,10 @@ def init(ms: Sequence[T]) -> Sequence[T]:
|
|
|
61
61
|
|
|
62
62
|
def grouped(
|
|
63
63
|
ms: Sequence[T],
|
|
64
|
-
key_func: Callable[[T],
|
|
64
|
+
key_func: Callable[[T], KT],
|
|
65
65
|
keys_ordered: bool = False,
|
|
66
66
|
values_only: bool = False,
|
|
67
|
-
) -> list[tuple[
|
|
67
|
+
) -> list[tuple[KT, list[T]]] | list[list[T]]:
|
|
68
68
|
"""
|
|
69
69
|
Groups the given list of elements according to key generator function
|
|
70
70
|
|
|
@@ -76,7 +76,7 @@ def grouped(
|
|
|
76
76
|
"""
|
|
77
77
|
if ms is None or len(ms) == 0:
|
|
78
78
|
return []
|
|
79
|
-
grouped_ms: dict[
|
|
79
|
+
grouped_ms: dict[KT, list[T]] = {}
|
|
80
80
|
for m in ms:
|
|
81
81
|
k = key_func(m)
|
|
82
82
|
grouped_ms.setdefault(k, []).append(m)
|
|
@@ -148,7 +148,7 @@ def chunk_between(ms: Sequence[T], chunk_func: Callable[[T, T], bool], exclusive
|
|
|
148
148
|
return chunk(ms, lambda x, y: chunk_func(last(x), y), exclusive_end)
|
|
149
149
|
|
|
150
150
|
|
|
151
|
-
def chunk_with_key(ms: Sequence[T], key_func: Callable[[T],
|
|
151
|
+
def chunk_with_key(ms: Sequence[T], key_func: Callable[[T], KT], exclusive_end: bool = False) -> list[list[T]]:
|
|
152
152
|
return chunk_between(ms, lambda x, y: key_func(x) != key_func(y), exclusive_end)
|
|
153
153
|
|
|
154
154
|
|
|
@@ -185,8 +185,11 @@ def merge_chunks(
|
|
|
185
185
|
return merged_chunks
|
|
186
186
|
|
|
187
187
|
|
|
188
|
+
SeqT = TypeVar("SeqT", bound="Seq")
|
|
189
|
+
|
|
190
|
+
|
|
188
191
|
class Seq(Generic[Tco], Sequence[Tco], Sized):
|
|
189
|
-
def __init__(self, data: Iterable[Tco] |
|
|
192
|
+
def __init__(self, data: Iterable[Tco] | SeqT):
|
|
190
193
|
if isinstance(data, Seq):
|
|
191
194
|
self.data = data.data
|
|
192
195
|
elif isinstance(data, Iterable):
|
|
@@ -202,14 +205,14 @@ class Seq(Generic[Tco], Sequence[Tco], Sized):
|
|
|
202
205
|
def empty(self) -> bool:
|
|
203
206
|
return self.size == 0
|
|
204
207
|
|
|
205
|
-
def __add__(self, other:
|
|
208
|
+
def __add__(self: SeqT, other: SeqT) -> SeqT:
|
|
206
209
|
return self.concat(other)
|
|
207
210
|
|
|
208
|
-
def __getitem__(self, item):
|
|
211
|
+
def __getitem__(self: SeqT, item) -> SeqT:
|
|
209
212
|
if isinstance(item, slice):
|
|
210
|
-
return
|
|
213
|
+
return type(self)(self.data[item])
|
|
211
214
|
elif isinstance(item, int):
|
|
212
|
-
return
|
|
215
|
+
return type(self)([self.data[item]])
|
|
213
216
|
raise ValueError("unsupported index type")
|
|
214
217
|
|
|
215
218
|
def __len__(self) -> int:
|
|
@@ -230,28 +233,28 @@ class Seq(Generic[Tco], Sequence[Tco], Sized):
|
|
|
230
233
|
def count_if(self, func: Callable[[Tco], bool]):
|
|
231
234
|
return sum(1 for item in self.data if func(item))
|
|
232
235
|
|
|
233
|
-
def concat(self, other:
|
|
234
|
-
return
|
|
236
|
+
def concat(self: SeqT, other: SeqT) -> SeqT:
|
|
237
|
+
return type(self)(self.data + other.data)
|
|
235
238
|
|
|
236
|
-
def take_left(self, n: int) ->
|
|
239
|
+
def take_left(self: SeqT, n: int) -> SeqT:
|
|
237
240
|
if n <= 0:
|
|
238
|
-
return
|
|
241
|
+
return type(self)([])
|
|
239
242
|
return self[:n]
|
|
240
243
|
|
|
241
|
-
def take_right(self, n: int) ->
|
|
244
|
+
def take_right(self: SeqT, n: int) -> SeqT:
|
|
242
245
|
if n <= 0:
|
|
243
|
-
return
|
|
246
|
+
return type(self)([])
|
|
244
247
|
return self[-n:]
|
|
245
248
|
|
|
246
249
|
take = take_left
|
|
247
250
|
|
|
248
|
-
def reverse(self) ->
|
|
249
|
-
return
|
|
251
|
+
def reverse(self: SeqT) -> SeqT:
|
|
252
|
+
return type(self)(reversed(self.data))
|
|
250
253
|
|
|
251
|
-
def distinct(self) ->
|
|
252
|
-
return
|
|
254
|
+
def distinct(self: SeqT) -> SeqT:
|
|
255
|
+
return type(self)(sorted(set(self.data)))
|
|
253
256
|
|
|
254
|
-
def scan_left(self, zero:
|
|
257
|
+
def scan_left(self, zero: TT | None, func: Callable[[TT, Tco], TT]) -> "Seq[TT]":
|
|
255
258
|
def scan():
|
|
256
259
|
accum = zero
|
|
257
260
|
for elem in self.data:
|
|
@@ -260,7 +263,7 @@ class Seq(Generic[Tco], Sequence[Tco], Sized):
|
|
|
260
263
|
|
|
261
264
|
return Seq(scan())
|
|
262
265
|
|
|
263
|
-
def scan_right(self, zero:
|
|
266
|
+
def scan_right(self, zero: TT | None, func: Callable[[TT, Tco], TT]) -> "Seq[TT]":
|
|
264
267
|
def scan():
|
|
265
268
|
accum = zero
|
|
266
269
|
for elem in reversed(self.data):
|
|
@@ -271,10 +274,10 @@ class Seq(Generic[Tco], Sequence[Tco], Sized):
|
|
|
271
274
|
|
|
272
275
|
scan = scan_left
|
|
273
276
|
|
|
274
|
-
def map(self, func: Callable[[Tco],
|
|
277
|
+
def map(self, func: Callable[[Tco], TT]) -> "Seq[TT]":
|
|
275
278
|
return self.scan(None, lambda x, y: func(y))
|
|
276
279
|
|
|
277
|
-
def fold_left(self, zero:
|
|
280
|
+
def fold_left(self, zero: TT | None, func: Callable[[TT, Tco], TT]) -> "Seq[TT]":
|
|
278
281
|
if self.empty:
|
|
279
282
|
return Seq([]) if zero is None else Seq([zero])
|
|
280
283
|
data = self.data if zero is None else [zero] + self.data
|
|
@@ -283,7 +286,7 @@ class Seq(Generic[Tco], Sequence[Tco], Sized):
|
|
|
283
286
|
accum = func(accum, elem)
|
|
284
287
|
return Seq([accum])
|
|
285
288
|
|
|
286
|
-
def fold_right(self, zero:
|
|
289
|
+
def fold_right(self, zero: TT | None, func: Callable[[TT, Tco], TT]) -> "Seq[TT]":
|
|
287
290
|
if self.empty:
|
|
288
291
|
return Seq([]) if zero is None else Seq([zero])
|
|
289
292
|
data = self.data if zero is None else self.data + [zero]
|
|
@@ -294,18 +297,18 @@ class Seq(Generic[Tco], Sequence[Tco], Sized):
|
|
|
294
297
|
|
|
295
298
|
fold = fold_left
|
|
296
299
|
|
|
297
|
-
def reduce(self, func: Callable[[Tco, Tco], Tco]) ->
|
|
298
|
-
return self.fold(None, lambda x, y: func(x, y))
|
|
300
|
+
def reduce(self: SeqT, func: Callable[[Tco, Tco], Tco]) -> SeqT:
|
|
301
|
+
return type(self)(self.fold(None, lambda x, y: func(x, y)))
|
|
299
302
|
|
|
300
|
-
def max(self, func: Callable[[Tco, Tco], bool] = None) ->
|
|
303
|
+
def max(self: SeqT, func: Callable[[Tco, Tco], bool] = None) -> SeqT:
|
|
301
304
|
func = func or (lambda x, y: x > y)
|
|
302
305
|
return self.reduce(lambda x, y: x if func(x, y) else y)
|
|
303
306
|
|
|
304
|
-
def min(self, func: Callable[[Tco, Tco], bool] = None) ->
|
|
307
|
+
def min(self: SeqT, func: Callable[[Tco, Tco], bool] = None) -> SeqT:
|
|
305
308
|
func = func or (lambda x, y: x < y)
|
|
306
309
|
return self.reduce(lambda x, y: x if func(x, y) else y)
|
|
307
310
|
|
|
308
|
-
def group(self, func: Callable[[Tco],
|
|
311
|
+
def group(self, func: Callable[[Tco], KT]) -> "Seq[tuple[KT, list[Tco]]]":
|
|
309
312
|
return Seq(grouped(self.data, key_func=func, keys_ordered=True))
|
|
310
313
|
|
|
311
314
|
def keys(self):
|
|
@@ -317,13 +320,13 @@ class Seq(Generic[Tco], Sequence[Tco], Sized):
|
|
|
317
320
|
def swap(self):
|
|
318
321
|
return Seq((value, key) for key, value in self.data)
|
|
319
322
|
|
|
320
|
-
def map_keys(self, func: Callable[[Tco],
|
|
323
|
+
def map_keys(self, func: Callable[[Tco], TT]):
|
|
321
324
|
return Seq((func(key), value) for key, value in self.data)
|
|
322
325
|
|
|
323
|
-
def map_values(self, func: Callable[[Tco],
|
|
326
|
+
def map_values(self, func: Callable[[Tco], TT]):
|
|
324
327
|
return Seq((key, func(value)) for key, value in self.data)
|
|
325
328
|
|
|
326
|
-
def flat_map(self, func: Callable[[Tco], Iterable[
|
|
329
|
+
def flat_map(self, func: Callable[[Tco], Iterable[TT]]) -> "Seq[TT]":
|
|
327
330
|
data = []
|
|
328
331
|
for d in self.data:
|
|
329
332
|
data.extend(func(d))
|
|
@@ -332,31 +335,31 @@ class Seq(Generic[Tco], Sequence[Tco], Sized):
|
|
|
332
335
|
def flatten(self):
|
|
333
336
|
return self.flat_map(lambda x: list(x))
|
|
334
337
|
|
|
335
|
-
def group_map(self, group_func: Callable[[Tco],
|
|
338
|
+
def group_map(self, group_func: Callable[[Tco], KT], map_func: Callable[[Tco], TT]) -> "Seq[tuple[KT, list[TT]]]":
|
|
336
339
|
return self.group(group_func).map_values(lambda x: list(map(map_func, x)))
|
|
337
340
|
|
|
338
|
-
def filter(self, func: Callable[[Tco], bool]) ->
|
|
339
|
-
return
|
|
341
|
+
def filter(self: SeqT, func: Callable[[Tco], bool]) -> SeqT:
|
|
342
|
+
return type(self)(filter(func, self.data))
|
|
340
343
|
|
|
341
|
-
def filter_not(self, func: Callable[[Tco], bool]) ->
|
|
344
|
+
def filter_not(self: SeqT, func: Callable[[Tco], bool]) -> SeqT:
|
|
342
345
|
return self.filter(lambda x: not func(x))
|
|
343
346
|
|
|
344
|
-
def sort(self, func: Callable[[Tco],
|
|
345
|
-
return
|
|
347
|
+
def sort(self: SeqT, func: Callable[[Tco], KT]) -> SeqT:
|
|
348
|
+
return type(self)(sorted(self.data, key=func))
|
|
346
349
|
|
|
347
|
-
def head(self) ->
|
|
348
|
-
return
|
|
350
|
+
def head(self: SeqT) -> SeqT:
|
|
351
|
+
return type(self)([head(self.data)])
|
|
349
352
|
|
|
350
|
-
def last(self) ->
|
|
351
|
-
return
|
|
353
|
+
def last(self: SeqT) -> SeqT:
|
|
354
|
+
return type(self)([last(self.data)])
|
|
352
355
|
|
|
353
|
-
def init(self) ->
|
|
354
|
-
return
|
|
356
|
+
def init(self: SeqT) -> SeqT:
|
|
357
|
+
return type(self)(init(self.data))
|
|
355
358
|
|
|
356
|
-
def tail(self) ->
|
|
357
|
-
return
|
|
359
|
+
def tail(self: SeqT) -> SeqT:
|
|
360
|
+
return type(self)(tail(self.data))
|
|
358
361
|
|
|
359
|
-
def foreach(self, func: Callable[[Tco], None]) ->
|
|
362
|
+
def foreach(self: SeqT, func: Callable[[Tco], None]) -> SeqT:
|
|
360
363
|
for elem in self.data:
|
|
361
364
|
func(elem)
|
|
362
365
|
return self
|
|
@@ -367,16 +370,16 @@ class Seq(Generic[Tco], Sequence[Tco], Sized):
|
|
|
367
370
|
def forall(self, func: Callable[[Tco], bool]) -> "Seq[bool]":
|
|
368
371
|
return Seq([all(map(func, self.data))])
|
|
369
372
|
|
|
370
|
-
def union(self, other:
|
|
371
|
-
return
|
|
373
|
+
def union(self: SeqT, other: SeqT) -> SeqT:
|
|
374
|
+
return type(self)(sorted(set(self.data).union(set(other.data))))
|
|
372
375
|
|
|
373
|
-
def intersect(self, other:
|
|
374
|
-
return
|
|
376
|
+
def intersect(self: SeqT, other: SeqT) -> SeqT:
|
|
377
|
+
return type(self)(sorted(set(self.data).intersection(set(other.data))))
|
|
375
378
|
|
|
376
|
-
def zip(self, other: "Seq[
|
|
379
|
+
def zip(self, other: "Seq[TT]") -> "Seq[tuple[Tco, TT]]":
|
|
377
380
|
return Seq(zip(self.data, other.data))
|
|
378
381
|
|
|
379
|
-
def zip_fill(self, other: "Seq[
|
|
382
|
+
def zip_fill(self, other: "Seq[TT]", fill: Tco | TT | None = None) -> "Seq[tuple[Tco, TT]]":
|
|
380
383
|
return Seq(itertools.zip_longest(self.data, other.data, fillvalue=fill))
|
|
381
384
|
|
|
382
385
|
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import unittest
|
|
2
|
+
from collections.abc import Iterable
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import Self
|
|
2
5
|
|
|
3
6
|
import ddt
|
|
4
7
|
|
|
8
|
+
from iker.common.utils.sequtils import Seq
|
|
5
9
|
from iker.common.utils.sequtils import batch_yield
|
|
6
10
|
from iker.common.utils.sequtils import chunk, chunk_between, chunk_with_key, merge_chunks
|
|
7
11
|
from iker.common.utils.sequtils import deduped, grouped
|
|
@@ -790,6 +794,26 @@ class SeqUtilsTest(unittest.TestCase):
|
|
|
790
794
|
self.assertEqual(expect, merge_chunks(data, merge_func=merge_func, drop_exclusive_end=True))
|
|
791
795
|
|
|
792
796
|
|
|
797
|
+
@dataclass(frozen=True, eq=True, order=True)
|
|
798
|
+
class Naming(object):
|
|
799
|
+
serial: int
|
|
800
|
+
name: str
|
|
801
|
+
gender: str
|
|
802
|
+
|
|
803
|
+
|
|
804
|
+
class NamingSeq(Seq[Naming]):
|
|
805
|
+
|
|
806
|
+
def __init__(self, data: Iterable[Naming]):
|
|
807
|
+
super(NamingSeq, self).__init__(data)
|
|
808
|
+
self.serials = list(map(lambda x: x.serial, self.data))
|
|
809
|
+
|
|
810
|
+
def identity(self) -> Self:
|
|
811
|
+
return self
|
|
812
|
+
|
|
813
|
+
def axis(self) -> list[int]:
|
|
814
|
+
return self.serials
|
|
815
|
+
|
|
816
|
+
|
|
793
817
|
@ddt.ddt
|
|
794
818
|
class SeqTest(unittest.TestCase):
|
|
795
819
|
|
|
@@ -1315,3 +1339,100 @@ class SeqTest(unittest.TestCase):
|
|
|
1315
1339
|
def test_zip_fill(self, a, b, fill, expect):
|
|
1316
1340
|
actual = seq(a).zip_fill(seq(b), fill)
|
|
1317
1341
|
self.assertEqual(actual.data, expect)
|
|
1342
|
+
|
|
1343
|
+
def test_naming_seq(self):
|
|
1344
|
+
names = [
|
|
1345
|
+
("Andrew", "M"),
|
|
1346
|
+
("Alice", "W"),
|
|
1347
|
+
("Benjamin", "M"),
|
|
1348
|
+
("Bella", "W"),
|
|
1349
|
+
("Charles", "M"),
|
|
1350
|
+
("Charlotte", "W"),
|
|
1351
|
+
("Daniel", "M"),
|
|
1352
|
+
("Diana", "W"),
|
|
1353
|
+
("Ethan", "M"),
|
|
1354
|
+
("Emily", "W"),
|
|
1355
|
+
("Felix", "M"),
|
|
1356
|
+
("Fiona", "W"),
|
|
1357
|
+
("George", "M"),
|
|
1358
|
+
("Grace", "W"),
|
|
1359
|
+
("Henry", "M"),
|
|
1360
|
+
("Hannah", "W"),
|
|
1361
|
+
("Isaac", "M"),
|
|
1362
|
+
("Isabella", "W"),
|
|
1363
|
+
("Jacob", "M"),
|
|
1364
|
+
("Julia", "W"),
|
|
1365
|
+
("Kevin", "M"),
|
|
1366
|
+
("Katherine", "W"),
|
|
1367
|
+
("Liam", "M"),
|
|
1368
|
+
("Lily", "W"),
|
|
1369
|
+
("Michael", "M"),
|
|
1370
|
+
("Madison", "W"),
|
|
1371
|
+
("Nathan", "M"),
|
|
1372
|
+
("Natalie", "W"),
|
|
1373
|
+
("Oliver", "M"),
|
|
1374
|
+
("Olivia", "W"),
|
|
1375
|
+
("Patrick", "M"),
|
|
1376
|
+
("Penelope", "W"),
|
|
1377
|
+
("Quentin", "M"),
|
|
1378
|
+
("Quinn", "W"),
|
|
1379
|
+
("Ryan", "M"),
|
|
1380
|
+
("Rebecca", "W"),
|
|
1381
|
+
("Samuel", "M"),
|
|
1382
|
+
("Sophia", "W"),
|
|
1383
|
+
("Thomas", "M"),
|
|
1384
|
+
("Tiffany", "W"),
|
|
1385
|
+
("Ulysses", "M"),
|
|
1386
|
+
("Ursula", "W"),
|
|
1387
|
+
("Victor", "M"),
|
|
1388
|
+
("Victoria", "W"),
|
|
1389
|
+
("William", "M"),
|
|
1390
|
+
("Wendy", "W"),
|
|
1391
|
+
("Xavier", "M"),
|
|
1392
|
+
("Xenia", "W"),
|
|
1393
|
+
("Yosef", "M"),
|
|
1394
|
+
("Yvonne", "W"),
|
|
1395
|
+
("Zachary", "M"),
|
|
1396
|
+
("Zoe", "W"),
|
|
1397
|
+
]
|
|
1398
|
+
naming_seq = NamingSeq(Naming(serial, name, gender) for serial, (name, gender) in enumerate(names))
|
|
1399
|
+
|
|
1400
|
+
self.assertEqual(naming_seq, naming_seq)
|
|
1401
|
+
self.assertEqual(naming_seq.concat(naming_seq).axis(), list(range(0, 52)) + list(range(0, 52)))
|
|
1402
|
+
self.assertEqual(naming_seq.take_left(26).axis(), list(range(0, 26)))
|
|
1403
|
+
self.assertEqual(naming_seq.take_right(26).axis(), list(range(26, 52)))
|
|
1404
|
+
self.assertEqual(naming_seq.reverse().axis(), list(reversed(range(0, 52))))
|
|
1405
|
+
self.assertEqual(naming_seq.distinct().axis(), list(range(0, 52)))
|
|
1406
|
+
self.assertEqual(naming_seq.reduce(lambda x, y: x).axis(), [0])
|
|
1407
|
+
self.assertEqual(naming_seq.reduce(lambda x, y: y).axis(), [51])
|
|
1408
|
+
self.assertEqual(naming_seq.min(lambda x, y: x.serial < y.serial).axis(), [0])
|
|
1409
|
+
self.assertEqual(naming_seq.max(lambda x, y: x.serial > y.serial).axis(), [51])
|
|
1410
|
+
self.assertEqual(naming_seq.filter(lambda x: x.gender == "M").axis(), list(range(0, 52, 2)))
|
|
1411
|
+
self.assertEqual(naming_seq.filter(lambda x: x.gender == "W").axis(), list(range(1, 52, 2)))
|
|
1412
|
+
self.assertEqual(naming_seq.filter_not(lambda x: x.gender == "M").axis(),
|
|
1413
|
+
naming_seq.filter(lambda x: x.gender == "W").axis())
|
|
1414
|
+
self.assertEqual(naming_seq.filter_not(lambda x: x.gender == "W").axis(),
|
|
1415
|
+
naming_seq.filter(lambda x: x.gender == "M").axis())
|
|
1416
|
+
self.assertEqual(naming_seq.sort(lambda x: -x.serial).axis(), naming_seq.reverse().axis())
|
|
1417
|
+
self.assertEqual(naming_seq.head().axis(), [0])
|
|
1418
|
+
self.assertEqual(naming_seq.last().axis(), [51])
|
|
1419
|
+
self.assertEqual(naming_seq.init().axis(), list(range(0, 51)))
|
|
1420
|
+
self.assertEqual(naming_seq.tail().axis(), list(range(1, 52)))
|
|
1421
|
+
self.assertEqual(naming_seq.foreach(lambda x: x).data, naming_seq.data)
|
|
1422
|
+
self.assertEqual(naming_seq.union(naming_seq).data, naming_seq.data)
|
|
1423
|
+
self.assertEqual(naming_seq.intersect(naming_seq).data, naming_seq.data)
|
|
1424
|
+
|
|
1425
|
+
self.assertEqual(naming_seq.scan_left(0, lambda x, y: x + y.serial).data,
|
|
1426
|
+
seq(range(0, 52)).scan_left(0, lambda x, y: x + y).data)
|
|
1427
|
+
self.assertEqual(naming_seq.scan_right(0, lambda x, y: x + y.serial).data,
|
|
1428
|
+
seq(range(0, 52)).scan_right(0, lambda x, y: x + y).data)
|
|
1429
|
+
self.assertEqual(naming_seq.map(lambda x: x.serial).data, list(range(0, 52)))
|
|
1430
|
+
|
|
1431
|
+
self.assertEqual(naming_seq.fold_left(0, lambda x, y: x + y.serial).data,
|
|
1432
|
+
seq(range(0, 52)).fold_left(0, lambda x, y: x + y).data)
|
|
1433
|
+
self.assertEqual(naming_seq.fold_right(0, lambda x, y: x + y.serial).data,
|
|
1434
|
+
seq(range(0, 52)).fold_right(0, lambda x, y: x + y).data)
|
|
1435
|
+
|
|
1436
|
+
self.assertEqual(naming_seq.group(lambda x: x.serial % 2).size, 2)
|
|
1437
|
+
self.assertEqual(naming_seq.group(lambda x: x.gender).size, 2)
|
|
1438
|
+
self.assertEqual(naming_seq.group(lambda x: x.name[0]).size, 26)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{iker_python_common-1.0.29 → iker_python_common-1.0.31}/resources/unittest/config/config.cfg
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{iker_python_common-1.0.29 → iker_python_common-1.0.31}/resources/unittest/shutils/dir.foo/file.bar
RENAMED
|
File without changes
|
{iker_python_common-1.0.29 → iker_python_common-1.0.31}/resources/unittest/shutils/dir.foo/file.baz
RENAMED
|
File without changes
|
{iker_python_common-1.0.29 → iker_python_common-1.0.31}/resources/unittest/shutils/dir.foo/file.foo
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{iker_python_common-1.0.29 → iker_python_common-1.0.31}/src/iker/common/utils/dockerutils.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{iker_python_common-1.0.29 → iker_python_common-1.0.31}/src/iker_python_common.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{iker_python_common-1.0.29 → iker_python_common-1.0.31}/src/iker_python_common.egg-info/not-zip-safe
RENAMED
|
File without changes
|
{iker_python_common-1.0.29 → iker_python_common-1.0.31}/src/iker_python_common.egg-info/requires.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{iker_python_common-1.0.29 → iker_python_common-1.0.31}/test/iker_tests/common/utils/config_test.py
RENAMED
|
File without changes
|
{iker_python_common-1.0.29 → iker_python_common-1.0.31}/test/iker_tests/common/utils/csv_test.py
RENAMED
|
File without changes
|
{iker_python_common-1.0.29 → iker_python_common-1.0.31}/test/iker_tests/common/utils/dbutils_test.py
RENAMED
|
File without changes
|
|
File without changes
|
{iker_python_common-1.0.29 → iker_python_common-1.0.31}/test/iker_tests/common/utils/dtutils_test.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{iker_python_common-1.0.29 → iker_python_common-1.0.31}/test/iker_tests/common/utils/logger_test.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{iker_python_common-1.0.29 → iker_python_common-1.0.31}/test/iker_tests/common/utils/retry_test.py
RENAMED
|
File without changes
|
{iker_python_common-1.0.29 → iker_python_common-1.0.31}/test/iker_tests/common/utils/s3utils_test.py
RENAMED
|
File without changes
|
{iker_python_common-1.0.29 → iker_python_common-1.0.31}/test/iker_tests/common/utils/shutils_test.py
RENAMED
|
File without changes
|
{iker_python_common-1.0.29 → iker_python_common-1.0.31}/test/iker_tests/common/utils/span_test.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|