relib 1.3.3__py3-none-any.whl → 1.3.5__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.
- relib/dict_utils.py +5 -5
- relib/io_utils.py +21 -1
- relib/iter_utils.py +16 -5
- relib/runtime_tools.py +3 -2
- {relib-1.3.3.dist-info → relib-1.3.5.dist-info}/METADATA +1 -1
- relib-1.3.5.dist-info/RECORD +11 -0
- relib-1.3.3.dist-info/RECORD +0 -11
- {relib-1.3.3.dist-info → relib-1.3.5.dist-info}/WHEEL +0 -0
- {relib-1.3.3.dist-info → relib-1.3.5.dist-info}/licenses/LICENSE +0 -0
relib/dict_utils.py
CHANGED
@@ -2,8 +2,8 @@ from typing import Any, Callable, Iterable, overload
|
|
2
2
|
from .type_utils import as_any
|
3
3
|
|
4
4
|
__all__ = [
|
5
|
-
"deepen_dict", "dict_by", "dict_firsts",
|
6
|
-
"
|
5
|
+
"deep_dict_pairs", "deepen_dict", "dict_by", "dict_firsts",
|
6
|
+
"flatten_dict",
|
7
7
|
"get_at", "group",
|
8
8
|
"key_of",
|
9
9
|
"map_dict", "merge_dicts",
|
@@ -62,15 +62,15 @@ def group[T, K](pairs: Iterable[tuple[K, T]]) -> dict[K, list[T]]:
|
|
62
62
|
values_by_key.setdefault(key, []).append(value)
|
63
63
|
return values_by_key
|
64
64
|
|
65
|
-
def
|
65
|
+
def deep_dict_pairs(d, prefix=()):
|
66
66
|
for key, value in d.items():
|
67
67
|
if not isinstance(value, dict) or value == {}:
|
68
68
|
yield prefix + (key,), value
|
69
69
|
else:
|
70
|
-
yield from
|
70
|
+
yield from deep_dict_pairs(value, prefix + (key,))
|
71
71
|
|
72
72
|
def flatten_dict(deep_dict: dict, prefix=()) -> dict:
|
73
|
-
return dict(
|
73
|
+
return dict(deep_dict_pairs(deep_dict, prefix))
|
74
74
|
|
75
75
|
@overload
|
76
76
|
def deepen_dict[K1, U](d: dict[tuple[K1], U]) -> dict[K1, U]: ...
|
relib/io_utils.py
CHANGED
@@ -1,8 +1,10 @@
|
|
1
1
|
import json
|
2
2
|
from pathlib import Path
|
3
|
-
from typing import Any
|
3
|
+
from typing import Any, Iterable
|
4
4
|
|
5
5
|
__all__ = [
|
6
|
+
"clear_directory",
|
7
|
+
"empty_dirs",
|
6
8
|
"read_json",
|
7
9
|
"write_json",
|
8
10
|
]
|
@@ -19,3 +21,21 @@ def write_json(path: Path, obj: object, indent: None | int = None) -> None:
|
|
19
21
|
with path.open("w") as f:
|
20
22
|
separators = (",", ":") if indent is None else None
|
21
23
|
return json.dump(obj, f, indent=indent, separators=separators)
|
24
|
+
|
25
|
+
def empty_dirs(path: Path) -> Iterable[Path]:
|
26
|
+
nonempty_count = 0
|
27
|
+
for child in path.iterdir():
|
28
|
+
nonempty_count += 1
|
29
|
+
if child.is_dir():
|
30
|
+
for grand_child in empty_dirs(child):
|
31
|
+
yield grand_child
|
32
|
+
nonempty_count -= child == grand_child
|
33
|
+
if nonempty_count == 0:
|
34
|
+
yield path
|
35
|
+
|
36
|
+
def clear_directory(path: Path):
|
37
|
+
if path.is_dir():
|
38
|
+
for file in path.glob("**/.DS_Store"):
|
39
|
+
file.unlink()
|
40
|
+
for directory in empty_dirs(path):
|
41
|
+
directory.rmdir()
|
relib/iter_utils.py
CHANGED
@@ -1,9 +1,11 @@
|
|
1
1
|
from contextlib import contextmanager
|
2
2
|
from itertools import chain, islice
|
3
|
-
from typing import Any, Iterable, Literal, Self, overload
|
3
|
+
from typing import Any, Iterable, Literal, Self, Sequence, overload
|
4
4
|
from .dict_utils import dict_firsts
|
5
5
|
|
6
6
|
__all__ = [
|
7
|
+
"as_list",
|
8
|
+
"at",
|
7
9
|
"chunked",
|
8
10
|
"distinct_by", "distinct", "drop_none",
|
9
11
|
"first", "flatten",
|
@@ -16,6 +18,15 @@ __all__ = [
|
|
16
18
|
"transpose",
|
17
19
|
]
|
18
20
|
|
21
|
+
def as_list[T](iterable: Iterable[T]) -> list[T]:
|
22
|
+
return iterable if isinstance(iterable, list) else list(iterable)
|
23
|
+
|
24
|
+
def at[T, U](values: Sequence[T], index: int, default: U = None) -> T | U:
|
25
|
+
try:
|
26
|
+
return values[index]
|
27
|
+
except IndexError:
|
28
|
+
return default
|
29
|
+
|
19
30
|
def first[T](iterable: Iterable[T]) -> T | None:
|
20
31
|
return next(iter(iterable), None)
|
21
32
|
|
@@ -28,8 +39,8 @@ def distinct[T](iterable: Iterable[T]) -> list[T]:
|
|
28
39
|
def distinct_by[T](pairs: Iterable[tuple[object, T]]) -> list[T]:
|
29
40
|
return list(dict_firsts(pairs).values())
|
30
41
|
|
31
|
-
def sort_by[T](pairs: Iterable[tuple[Any, T]]) -> list[T]:
|
32
|
-
pairs = sorted(pairs, key=lambda p: p[0])
|
42
|
+
def sort_by[T](pairs: Iterable[tuple[Any, T]], reverse=False) -> list[T]:
|
43
|
+
pairs = sorted(pairs, key=lambda p: p[0], reverse=reverse)
|
33
44
|
return [v for _, v in pairs]
|
34
45
|
|
35
46
|
def move_value[T](iterable: Iterable[T], from_i: int, to_i: int) -> list[T]:
|
@@ -37,7 +48,7 @@ def move_value[T](iterable: Iterable[T], from_i: int, to_i: int) -> list[T]:
|
|
37
48
|
values.insert(to_i, values.pop(from_i))
|
38
49
|
return values
|
39
50
|
|
40
|
-
def reversed_enumerate[T](values:
|
51
|
+
def reversed_enumerate[T](values: Sequence[T] | tuple[T, ...]) -> Iterable[tuple[int, T]]:
|
41
52
|
return zip(range(len(values))[::-1], reversed(values))
|
42
53
|
|
43
54
|
def intersect[T](*iterables: Iterable[T]) -> list[T]:
|
@@ -116,7 +127,7 @@ def chunked[T](values: Iterable[T], *, num_chunks: int, chunk_size=None) -> list
|
|
116
127
|
@overload
|
117
128
|
def chunked[T](values: Iterable[T], *, num_chunks=None, chunk_size: int) -> list[list[T]]: ...
|
118
129
|
def chunked(values, *, num_chunks=None, chunk_size=None):
|
119
|
-
values =
|
130
|
+
values = as_list(values)
|
120
131
|
if isinstance(num_chunks, int):
|
121
132
|
chunk_size = (len(values) / num_chunks).__ceil__()
|
122
133
|
elif isinstance(chunk_size, int):
|
relib/runtime_tools.py
CHANGED
@@ -6,6 +6,7 @@ from concurrent.futures import ThreadPoolExecutor
|
|
6
6
|
from functools import partial, wraps
|
7
7
|
from time import time
|
8
8
|
from typing import Callable, Coroutine, Iterable, ParamSpec, TypeVar
|
9
|
+
from .iter_utils import as_list
|
9
10
|
from .processing_utils import noop
|
10
11
|
|
11
12
|
__all__ = [
|
@@ -25,7 +26,7 @@ default_executor = ThreadPoolExecutor(max_workers=default_workers)
|
|
25
26
|
|
26
27
|
def raise_if_interrupt():
|
27
28
|
if sys.exc_info()[0] in (KeyboardInterrupt, SystemExit):
|
28
|
-
|
29
|
+
raise
|
29
30
|
|
30
31
|
def clear_console() -> None:
|
31
32
|
os.system("cls" if os.name == "nt" else "clear")
|
@@ -45,7 +46,7 @@ async def roll_tasks[T](tasks: Iterable[Coro[T]], workers=default_workers, progr
|
|
45
46
|
return await asyncio.gather(*[worker(task, semaphore) for task in tasks])
|
46
47
|
|
47
48
|
from tqdm import tqdm
|
48
|
-
tasks =
|
49
|
+
tasks = as_list(tasks)
|
49
50
|
with tqdm(total=len(tasks)) as pbar:
|
50
51
|
update = partial(pbar.update, 1)
|
51
52
|
return await asyncio.gather(*[worker(task, semaphore, update) for task in tasks])
|
@@ -0,0 +1,11 @@
|
|
1
|
+
relib/__init__.py,sha256=WerjUaM_sNvudjXFudLRtXB7viZWEW1RSinkDjrh4nE,163
|
2
|
+
relib/dict_utils.py,sha256=zuUkPI1uiElWUgt3ETdajG7S2grP5mX1qM0t2Cc1zy4,2968
|
3
|
+
relib/io_utils.py,sha256=cUyUFhrMCUDfkINhYo32QPaVGz3chqDO3ElymSCoWEg,1086
|
4
|
+
relib/iter_utils.py,sha256=xQOyNwYCc9fyKScyd56vx4CVCzZBDDROKVfnJuaInCM,5774
|
5
|
+
relib/processing_utils.py,sha256=eMzjlxsEmfvtKafDITBWSp9D5RwegSWsUsvj1FpmBM0,1893
|
6
|
+
relib/runtime_tools.py,sha256=50zfIXZwXXU6tGKM-1iS3FEax82vthgp-KNmvmIGlqE,2964
|
7
|
+
relib/type_utils.py,sha256=oY96cAAux1JwhXgWFFyqEv_f-wwyPc_Hm6I9Yeisu_M,323
|
8
|
+
relib-1.3.5.dist-info/METADATA,sha256=adnaXzA56Yff2cXRK79hAopNMnPs_rfwBBKs95l3neY,1295
|
9
|
+
relib-1.3.5.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
10
|
+
relib-1.3.5.dist-info/licenses/LICENSE,sha256=9xVsdtv_-uSyY9Xl9yujwAPm4-mjcCLeVy-ljwXEWbo,1059
|
11
|
+
relib-1.3.5.dist-info/RECORD,,
|
relib-1.3.3.dist-info/RECORD
DELETED
@@ -1,11 +0,0 @@
|
|
1
|
-
relib/__init__.py,sha256=WerjUaM_sNvudjXFudLRtXB7viZWEW1RSinkDjrh4nE,163
|
2
|
-
relib/dict_utils.py,sha256=jqW6bYSaQMt2AC2KFzDJKyl88idyMttWxXDu3t-fA5I,2980
|
3
|
-
relib/io_utils.py,sha256=EtnIGQmLXjoHUPFteB5yPXDD3wGLvH4O3CahlCebXDQ,555
|
4
|
-
relib/iter_utils.py,sha256=r9tus9F_obwXsHE8Jk8H9_ZPdOgtBI6WnpDxI6La-to,5477
|
5
|
-
relib/processing_utils.py,sha256=eMzjlxsEmfvtKafDITBWSp9D5RwegSWsUsvj1FpmBM0,1893
|
6
|
-
relib/runtime_tools.py,sha256=9N8gn3WCfqyS6D3Qs4l2nDja_NxDVVF-7hHIVrXA7Fc,2968
|
7
|
-
relib/type_utils.py,sha256=oY96cAAux1JwhXgWFFyqEv_f-wwyPc_Hm6I9Yeisu_M,323
|
8
|
-
relib-1.3.3.dist-info/METADATA,sha256=3z1-dTnOlkjYiy54JQ2VQOs0zy5_kyP4Bk33l1YuAoQ,1295
|
9
|
-
relib-1.3.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
10
|
-
relib-1.3.3.dist-info/licenses/LICENSE,sha256=9xVsdtv_-uSyY9Xl9yujwAPm4-mjcCLeVy-ljwXEWbo,1059
|
11
|
-
relib-1.3.3.dist-info/RECORD,,
|
File without changes
|
File without changes
|