relib 1.3.4__tar.gz → 1.3.6__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.
@@ -0,0 +1 @@
1
+ 3.10
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: relib
3
- Version: 1.3.4
3
+ Version: 1.3.6
4
4
  Project-URL: Repository, https://github.com/Reddan/relib.git
5
5
  Author: Hampus Hallman
6
6
  License: Copyright 2018-2025 Hampus Hallman
@@ -11,4 +11,4 @@ License: Copyright 2018-2025 Hampus Hallman
11
11
 
12
12
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
13
13
  License-File: LICENSE
14
- Requires-Python: >=3.12
14
+ Requires-Python: >=3.10
@@ -1,7 +1,7 @@
1
1
  [project]
2
2
  name = "relib"
3
- version = "1.3.4"
4
- requires-python = ">=3.12"
3
+ version = "1.3.6"
4
+ requires-python = ">=3.10"
5
5
  dependencies = []
6
6
  authors = [
7
7
  {name = "Hampus Hallman"}
@@ -0,0 +1,97 @@
1
+ from typing import Any, Callable, Iterable, overload
2
+ from .type_utils import as_any
3
+ from .types import K1, K2, K3, K4, K5, K6, K, T, U
4
+
5
+ __all__ = [
6
+ "deep_dict_pairs", "deepen_dict", "dict_by", "dict_firsts",
7
+ "flatten_dict",
8
+ "get_at", "group",
9
+ "key_of",
10
+ "map_dict", "merge_dicts",
11
+ "omit",
12
+ "pick",
13
+ "tuple_by",
14
+ ]
15
+
16
+ def merge_dicts(*dicts: dict[K, T]) -> dict[K, T]:
17
+ if len(dicts) == 1:
18
+ return dicts[0]
19
+ result = {}
20
+ for d in dicts:
21
+ result |= d
22
+ return result
23
+
24
+ def omit(d: dict[K, T], keys: Iterable[K]) -> dict[K, T]:
25
+ if keys:
26
+ d = dict(d)
27
+ for key in keys:
28
+ del d[key]
29
+ return d
30
+
31
+ def pick(d: dict[K, T], keys: Iterable[K]) -> dict[K, T]:
32
+ return {key: d[key] for key in keys}
33
+
34
+ def dict_by(keys: Iterable[K], values: Iterable[T]) -> dict[K, T]:
35
+ return dict(zip(keys, values))
36
+
37
+ def tuple_by(d: dict[K, T], keys: Iterable[K]) -> tuple[T, ...]:
38
+ return tuple(d[key] for key in keys)
39
+
40
+ def map_dict(fn: Callable[[T], U], d: dict[K, T]) -> dict[K, U]:
41
+ return {key: fn(value) for key, value in d.items()}
42
+
43
+ def key_of(dicts: Iterable[dict[T, U]], key: T) -> list[U]:
44
+ return [d[key] for d in dicts]
45
+
46
+ def get_at(d: dict, keys: Iterable[Any], default: T) -> T:
47
+ try:
48
+ for key in keys:
49
+ d = d[key]
50
+ except KeyError:
51
+ return default
52
+ return as_any(d)
53
+
54
+ def dict_firsts(pairs: Iterable[tuple[K, T]]) -> dict[K, T]:
55
+ result: dict[K, T] = {}
56
+ for key, value in pairs:
57
+ result.setdefault(key, value)
58
+ return result
59
+
60
+ def group(pairs: Iterable[tuple[K, T]]) -> dict[K, list[T]]:
61
+ values_by_key = {}
62
+ for key, value in pairs:
63
+ values_by_key.setdefault(key, []).append(value)
64
+ return values_by_key
65
+
66
+ def deep_dict_pairs(d, prefix=()):
67
+ for key, value in d.items():
68
+ if not isinstance(value, dict) or value == {}:
69
+ yield prefix + (key,), value
70
+ else:
71
+ yield from deep_dict_pairs(value, prefix + (key,))
72
+
73
+ def flatten_dict(deep_dict: dict, prefix=()) -> dict:
74
+ return dict(deep_dict_pairs(deep_dict, prefix))
75
+
76
+ @overload
77
+ def deepen_dict(d: dict[tuple[K1], U]) -> dict[K1, U]: ...
78
+ @overload
79
+ def deepen_dict(d: dict[tuple[K1, K2], U]) -> dict[K1, dict[K2, U]]: ...
80
+ @overload
81
+ def deepen_dict(d: dict[tuple[K1, K2, K3], U]) -> dict[K1, dict[K2, dict[K3, U]]]: ...
82
+ @overload
83
+ def deepen_dict(d: dict[tuple[K1, K2, K3, K4], U]) -> dict[K1, dict[K2, dict[K3, dict[K4, U]]]]: ...
84
+ @overload
85
+ def deepen_dict(d: dict[tuple[K1, K2, K3, K4, K5], U]) -> dict[K1, dict[K2, dict[K3, dict[K4, dict[K5, U]]]]]: ...
86
+ @overload
87
+ def deepen_dict(d: dict[tuple[K1, K2, K3, K4, K5, K6], U]) -> dict[K1, dict[K2, dict[K3, dict[K4, dict[K5, dict[K6, U]]]]]]: ...
88
+ def deepen_dict(d: dict[tuple[Any, ...], Any]) -> dict:
89
+ output = {}
90
+ if () in d:
91
+ return d[()]
92
+ for (*tail, head), value in d.items():
93
+ curr = output
94
+ for key in tail:
95
+ curr = curr.setdefault(key, {})
96
+ curr[head] = value
97
+ return output
@@ -1,9 +1,13 @@
1
+ from __future__ import annotations
1
2
  from contextlib import contextmanager
2
3
  from itertools import chain, islice
3
- from typing import Any, Iterable, Literal, Self, overload
4
+ from typing import Any, Generic, Iterable, Literal, Sequence, overload
4
5
  from .dict_utils import dict_firsts
6
+ from .types import T1, T2, T3, T4, T5, T, U
5
7
 
6
8
  __all__ = [
9
+ "as_list",
10
+ "at",
7
11
  "chunked",
8
12
  "distinct_by", "distinct", "drop_none",
9
13
  "first", "flatten",
@@ -16,43 +20,52 @@ __all__ = [
16
20
  "transpose",
17
21
  ]
18
22
 
19
- def first[T](iterable: Iterable[T]) -> T | None:
23
+ def as_list(iterable: Iterable[T]) -> list[T]:
24
+ return iterable if isinstance(iterable, list) else list(iterable)
25
+
26
+ def at(values: Sequence[T], index: int, default: U = None) -> T | U:
27
+ try:
28
+ return values[index]
29
+ except IndexError:
30
+ return default
31
+
32
+ def first(iterable: Iterable[T]) -> T | None:
20
33
  return next(iter(iterable), None)
21
34
 
22
- def drop_none[T](iterable: Iterable[T | None]) -> list[T]:
35
+ def drop_none(iterable: Iterable[T | None]) -> list[T]:
23
36
  return [x for x in iterable if x is not None]
24
37
 
25
- def distinct[T](iterable: Iterable[T]) -> list[T]:
38
+ def distinct(iterable: Iterable[T]) -> list[T]:
26
39
  return list(dict.fromkeys(iterable))
27
40
 
28
- def distinct_by[T](pairs: Iterable[tuple[object, T]]) -> list[T]:
41
+ def distinct_by(pairs: Iterable[tuple[object, T]]) -> list[T]:
29
42
  return list(dict_firsts(pairs).values())
30
43
 
31
- def sort_by[T](pairs: Iterable[tuple[Any, T]]) -> list[T]:
32
- pairs = sorted(pairs, key=lambda p: p[0])
44
+ def sort_by(pairs: Iterable[tuple[Any, T]], reverse=False) -> list[T]:
45
+ pairs = sorted(pairs, key=lambda p: p[0], reverse=reverse)
33
46
  return [v for _, v in pairs]
34
47
 
35
- def move_value[T](iterable: Iterable[T], from_i: int, to_i: int) -> list[T]:
48
+ def move_value(iterable: Iterable[T], from_i: int, to_i: int) -> list[T]:
36
49
  values = list(iterable)
37
50
  values.insert(to_i, values.pop(from_i))
38
51
  return values
39
52
 
40
- def reversed_enumerate[T](values: list[T] | tuple[T, ...]) -> Iterable[tuple[int, T]]:
53
+ def reversed_enumerate(values: Sequence[T] | tuple[T, ...]) -> Iterable[tuple[int, T]]:
41
54
  return zip(range(len(values))[::-1], reversed(values))
42
55
 
43
- def intersect[T](*iterables: Iterable[T]) -> list[T]:
56
+ def intersect(*iterables: Iterable[T]) -> list[T]:
44
57
  return list(set.intersection(*map(set, iterables)))
45
58
 
46
- def interleave[T](*iterables: Iterable[T]) -> list[T]:
59
+ def interleave(*iterables: Iterable[T]) -> list[T]:
47
60
  return flatten(zip(*iterables))
48
61
 
49
- def list_split[T](iterable: Iterable[T], sep: T) -> list[list[T]]:
62
+ def list_split(iterable: Iterable[T], sep: T) -> list[list[T]]:
50
63
  values = [sep, *iterable, sep]
51
64
  split_at = [i for i, x in enumerate(values) if x is sep]
52
65
  ranges = list(zip(split_at[0:-1], split_at[1:]))
53
66
  return [values[start + 1:end] for start, end in ranges]
54
67
 
55
- def partition[T](iterable: Iterable[tuple[bool, T]]) -> tuple[list[T], list[T]]:
68
+ def partition(iterable: Iterable[tuple[bool, T]]) -> tuple[list[T], list[T]]:
56
69
  true_values, false_values = [], []
57
70
  for predicate, value in iterable:
58
71
  if predicate:
@@ -61,7 +74,7 @@ def partition[T](iterable: Iterable[tuple[bool, T]]) -> tuple[list[T], list[T]]:
61
74
  false_values.append(value)
62
75
  return true_values, false_values
63
76
 
64
- class seekable[T]:
77
+ class seekable(Generic[T]):
65
78
  def __init__(self, iterable: Iterable[T]):
66
79
  self.index = 0
67
80
  self.source = iter(iterable)
@@ -86,14 +99,14 @@ class seekable[T]:
86
99
  self.sink[:self.index] = []
87
100
  self.index = 0
88
101
 
89
- def seek(self, index: int) -> Self:
102
+ def seek(self, index: int) -> seekable[T]:
90
103
  remainder = index - len(self.sink)
91
104
  if remainder > 0:
92
105
  next(islice(self, remainder, remainder), None)
93
106
  self.index = max(0, min(index, len(self.sink)))
94
107
  return self
95
108
 
96
- def step(self, count: int) -> Self:
109
+ def step(self, count: int) -> seekable[T]:
97
110
  return self.seek(self.index + count)
98
111
 
99
112
  @contextmanager
@@ -112,11 +125,11 @@ class seekable[T]:
112
125
  return list(islice(self, count))
113
126
 
114
127
  @overload
115
- def chunked[T](values: Iterable[T], *, num_chunks: int, chunk_size=None) -> list[list[T]]: ...
128
+ def chunked(values: Iterable[T], *, num_chunks: int, chunk_size=None) -> list[list[T]]: ...
116
129
  @overload
117
- def chunked[T](values: Iterable[T], *, num_chunks=None, chunk_size: int) -> list[list[T]]: ...
130
+ def chunked(values: Iterable[T], *, num_chunks=None, chunk_size: int) -> list[list[T]]: ...
118
131
  def chunked(values, *, num_chunks=None, chunk_size=None):
119
- values = values if isinstance(values, list) else list(values)
132
+ values = as_list(values)
120
133
  if isinstance(num_chunks, int):
121
134
  chunk_size = (len(values) / num_chunks).__ceil__()
122
135
  elif isinstance(chunk_size, int):
@@ -125,15 +138,15 @@ def chunked(values, *, num_chunks=None, chunk_size=None):
125
138
  return [values[i * chunk_size:(i + 1) * chunk_size] for i in range(num_chunks)]
126
139
 
127
140
  @overload
128
- def flatten[T](iterable: Iterable[T], depth: Literal[0]) -> list[T]: ...
141
+ def flatten(iterable: Iterable[T], depth: Literal[0]) -> list[T]: ...
129
142
  @overload
130
- def flatten[T](iterable: Iterable[Iterable[T]], depth: Literal[1] = 1) -> list[T]: ...
143
+ def flatten(iterable: Iterable[Iterable[T]], depth: Literal[1] = 1) -> list[T]: ...
131
144
  @overload
132
- def flatten[T](iterable: Iterable[Iterable[Iterable[T]]], depth: Literal[2]) -> list[T]: ...
145
+ def flatten(iterable: Iterable[Iterable[Iterable[T]]], depth: Literal[2]) -> list[T]: ...
133
146
  @overload
134
- def flatten[T](iterable: Iterable[Iterable[Iterable[Iterable[T]]]], depth: Literal[3]) -> list[T]: ...
147
+ def flatten(iterable: Iterable[Iterable[Iterable[Iterable[T]]]], depth: Literal[3]) -> list[T]: ...
135
148
  @overload
136
- def flatten[T](iterable: Iterable[Iterable[Iterable[Iterable[Iterable[T]]]]], depth: Literal[4]) -> list[T]: ...
149
+ def flatten(iterable: Iterable[Iterable[Iterable[Iterable[Iterable[T]]]]], depth: Literal[4]) -> list[T]: ...
137
150
  @overload
138
151
  def flatten(iterable: Iterable, depth: int) -> list: ...
139
152
  def flatten(iterable: Iterable, depth: int = 1) -> list:
@@ -142,15 +155,15 @@ def flatten(iterable: Iterable, depth: int = 1) -> list:
142
155
  return list(iterable)
143
156
 
144
157
  @overload
145
- def transpose[T1, T2](tuples: Iterable[tuple[T1, T2]], default_num_returns=0) -> tuple[list[T1], list[T2]]: ...
158
+ def transpose(tuples: Iterable[tuple[T1, T2]], default_num_returns=0) -> tuple[list[T1], list[T2]]: ...
146
159
  @overload
147
- def transpose[T1, T2, T3](tuples: Iterable[tuple[T1, T2, T3]], default_num_returns=0) -> tuple[list[T1], list[T2], list[T3]]: ...
160
+ def transpose(tuples: Iterable[tuple[T1, T2, T3]], default_num_returns=0) -> tuple[list[T1], list[T2], list[T3]]: ...
148
161
  @overload
149
- def transpose[T1, T2, T3, T4](tuples: Iterable[tuple[T1, T2, T3, T4]], default_num_returns=0) -> tuple[list[T1], list[T2], list[T3], list[T4]]: ...
162
+ def transpose(tuples: Iterable[tuple[T1, T2, T3, T4]], default_num_returns=0) -> tuple[list[T1], list[T2], list[T3], list[T4]]: ...
150
163
  @overload
151
- def transpose[T1, T2, T3, T4, T5](tuples: Iterable[tuple[T1, T2, T3, T4, T5]], default_num_returns=0) -> tuple[list[T1], list[T2], list[T3], list[T4], list[T5]]: ...
164
+ def transpose(tuples: Iterable[tuple[T1, T2, T3, T4, T5]], default_num_returns=0) -> tuple[list[T1], list[T2], list[T3], list[T4], list[T5]]: ...
152
165
  @overload
153
- def transpose[T](tuples: Iterable[tuple[T, ...]], default_num_returns=0) -> tuple[list[T], ...]: ...
166
+ def transpose(tuples: Iterable[tuple[T, ...]], default_num_returns=0) -> tuple[list[T], ...]: ...
154
167
  def transpose(tuples: Iterable[tuple], default_num_returns=0) -> tuple[list, ...]:
155
168
  output = tuple(zip(*tuples))
156
169
  if not output:
@@ -1,5 +1,6 @@
1
1
  import re
2
2
  from typing import Any, Callable, Iterable, overload
3
+ from .types import T
3
4
 
4
5
  __all__ = [
5
6
  "clamp",
@@ -12,7 +13,7 @@ __all__ = [
12
13
  def noop() -> None:
13
14
  pass
14
15
 
15
- def for_each[T](func: Callable[[T], Any], iterable: Iterable[T]) -> None:
16
+ def for_each(func: Callable[[T], Any], iterable: Iterable[T]) -> None:
16
17
  for item in iterable:
17
18
  func(item)
18
19
 
@@ -6,7 +6,9 @@ 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
11
+ from .types import T
10
12
 
11
13
  __all__ = [
12
14
  "as_async", "async_limit",
@@ -33,19 +35,19 @@ def clear_console() -> None:
33
35
  def console_link(text: str, url: str) -> str:
34
36
  return f"\033]8;;{url}\033\\{text}\033]8;;\033\\"
35
37
 
36
- async def worker[T](task: Coro[T], semaphore: asyncio.Semaphore, update=noop) -> T:
38
+ async def worker(task: Coro[T], semaphore: asyncio.Semaphore, update=noop) -> T:
37
39
  async with semaphore:
38
40
  result = await task
39
41
  update()
40
42
  return result
41
43
 
42
- async def roll_tasks[T](tasks: Iterable[Coro[T]], workers=default_workers, progress=False) -> list[T]:
44
+ async def roll_tasks(tasks: Iterable[Coro[T]], workers=default_workers, progress=False) -> list[T]:
43
45
  semaphore = asyncio.Semaphore(workers)
44
46
  if not progress:
45
47
  return await asyncio.gather(*[worker(task, semaphore) for task in tasks])
46
48
 
47
49
  from tqdm import tqdm
48
- tasks = tasks if isinstance(tasks, list) else list(tasks)
50
+ tasks = as_list(tasks)
49
51
  with tqdm(total=len(tasks)) as pbar:
50
52
  update = partial(pbar.update, 1)
51
53
  return await asyncio.gather(*[worker(task, semaphore, update) for task in tasks])
@@ -1,4 +1,5 @@
1
1
  from typing import Any
2
+ from .types import T
2
3
 
3
4
  __all__ = [
4
5
  "as_any",
@@ -9,9 +10,9 @@ __all__ = [
9
10
  def as_any(obj: Any) -> Any:
10
11
  return obj
11
12
 
12
- def non_none[T](obj: T | None) -> T:
13
+ def non_none(obj: T | None) -> T:
13
14
  assert obj is not None
14
15
  return obj
15
16
 
16
- def ensure_tuple[T](value: T | tuple[T, ...]) -> tuple[T, ...]:
17
+ def ensure_tuple(value: T | tuple[T, ...]) -> tuple[T, ...]:
17
18
  return value if isinstance(value, tuple) else (value,)
@@ -0,0 +1,16 @@
1
+ from typing import TypeVar
2
+
3
+ T = TypeVar("T")
4
+ U = TypeVar("U")
5
+ K = TypeVar("K")
6
+ T1 = TypeVar("T1")
7
+ T2 = TypeVar("T2")
8
+ T3 = TypeVar("T3")
9
+ T4 = TypeVar("T4")
10
+ T5 = TypeVar("T5")
11
+ K1 = TypeVar("K1")
12
+ K2 = TypeVar("K2")
13
+ K3 = TypeVar("K3")
14
+ K4 = TypeVar("K4")
15
+ K5 = TypeVar("K5")
16
+ K6 = TypeVar("K6")
@@ -1,6 +1,11 @@
1
1
  version = 1
2
2
  revision = 1
3
- requires-python = ">=3.12"
3
+ requires-python = ">=3.10"
4
+ resolution-markers = [
5
+ "python_full_version >= '3.12'",
6
+ "python_full_version == '3.11.*'",
7
+ "python_full_version < '3.11'",
8
+ ]
4
9
 
5
10
  [[package]]
6
11
  name = "colorama"
@@ -17,6 +22,26 @@ version = "2.1.3"
17
22
  source = { registry = "https://pypi.org/simple" }
18
23
  sdist = { url = "https://files.pythonhosted.org/packages/25/ca/1166b75c21abd1da445b97bf1fa2f14f423c6cfb4fc7c4ef31dccf9f6a94/numpy-2.1.3.tar.gz", hash = "sha256:aa08e04e08aaf974d4458def539dece0d28146d866a39da5639596f4921fd761", size = 20166090 }
19
24
  wheels = [
25
+ { url = "https://files.pythonhosted.org/packages/f1/80/d572a4737626372915bca41c3afbfec9d173561a39a0a61bacbbfd1dafd4/numpy-2.1.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c894b4305373b9c5576d7a12b473702afdf48ce5369c074ba304cc5ad8730dff", size = 21152472 },
26
+ { url = "https://files.pythonhosted.org/packages/6f/bb/7bfba10c791ae3bb6716da77ad85a82d5fac07fc96fb0023ef0571df9d20/numpy-2.1.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b47fbb433d3260adcd51eb54f92a2ffbc90a4595f8970ee00e064c644ac788f5", size = 13747967 },
27
+ { url = "https://files.pythonhosted.org/packages/da/d6/2df7bde35f0478455f0be5934877b3e5a505f587b00230f54a519a6b55a5/numpy-2.1.3-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:825656d0743699c529c5943554d223c021ff0494ff1442152ce887ef4f7561a1", size = 5354921 },
28
+ { url = "https://files.pythonhosted.org/packages/d1/bb/75b945874f931494891eac6ca06a1764d0e8208791f3addadb2963b83527/numpy-2.1.3-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:6a4825252fcc430a182ac4dee5a505053d262c807f8a924603d411f6718b88fd", size = 6888603 },
29
+ { url = "https://files.pythonhosted.org/packages/68/a7/fde73636f6498dbfa6d82fc336164635fe592f1ad0d13285fcb6267fdc1c/numpy-2.1.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e711e02f49e176a01d0349d82cb5f05ba4db7d5e7e0defd026328e5cfb3226d3", size = 13889862 },
30
+ { url = "https://files.pythonhosted.org/packages/05/db/5d9c91b2e1e2e72be1369278f696356d44975befcae830daf2e667dcb54f/numpy-2.1.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78574ac2d1a4a02421f25da9559850d59457bac82f2b8d7a44fe83a64f770098", size = 16328151 },
31
+ { url = "https://files.pythonhosted.org/packages/3e/6a/7eb732109b53ae64a29e25d7e68eb9d6611037f6354875497008a49e74d3/numpy-2.1.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c7662f0e3673fe4e832fe07b65c50342ea27d989f92c80355658c7f888fcc83c", size = 16704107 },
32
+ { url = "https://files.pythonhosted.org/packages/88/cc/278113b66a1141053cbda6f80e4200c6da06b3079c2d27bda1fde41f2c1f/numpy-2.1.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:fa2d1337dc61c8dc417fbccf20f6d1e139896a30721b7f1e832b2bb6ef4eb6c4", size = 14385789 },
33
+ { url = "https://files.pythonhosted.org/packages/f5/69/eb20f5e1bfa07449bc67574d2f0f7c1e6b335fb41672e43861a7727d85f2/numpy-2.1.3-cp310-cp310-win32.whl", hash = "sha256:72dcc4a35a8515d83e76b58fdf8113a5c969ccd505c8a946759b24e3182d1f23", size = 6536706 },
34
+ { url = "https://files.pythonhosted.org/packages/8e/8b/1c131ab5a94c1086c289c6e1da1d843de9dbd95fe5f5ee6e61904c9518e2/numpy-2.1.3-cp310-cp310-win_amd64.whl", hash = "sha256:ecc76a9ba2911d8d37ac01de72834d8849e55473457558e12995f4cd53e778e0", size = 12864165 },
35
+ { url = "https://files.pythonhosted.org/packages/ad/81/c8167192eba5247593cd9d305ac236847c2912ff39e11402e72ae28a4985/numpy-2.1.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4d1167c53b93f1f5d8a139a742b3c6f4d429b54e74e6b57d0eff40045187b15d", size = 21156252 },
36
+ { url = "https://files.pythonhosted.org/packages/da/74/5a60003fc3d8a718d830b08b654d0eea2d2db0806bab8f3c2aca7e18e010/numpy-2.1.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c80e4a09b3d95b4e1cac08643f1152fa71a0a821a2d4277334c88d54b2219a41", size = 13784119 },
37
+ { url = "https://files.pythonhosted.org/packages/47/7c/864cb966b96fce5e63fcf25e1e4d957fe5725a635e5f11fe03f39dd9d6b5/numpy-2.1.3-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:576a1c1d25e9e02ed7fa5477f30a127fe56debd53b8d2c89d5578f9857d03ca9", size = 5352978 },
38
+ { url = "https://files.pythonhosted.org/packages/09/ac/61d07930a4993dd9691a6432de16d93bbe6aa4b1c12a5e573d468eefc1ca/numpy-2.1.3-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:973faafebaae4c0aaa1a1ca1ce02434554d67e628b8d805e61f874b84e136b09", size = 6892570 },
39
+ { url = "https://files.pythonhosted.org/packages/27/2f/21b94664f23af2bb52030653697c685022119e0dc93d6097c3cb45bce5f9/numpy-2.1.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:762479be47a4863e261a840e8e01608d124ee1361e48b96916f38b119cfda04a", size = 13896715 },
40
+ { url = "https://files.pythonhosted.org/packages/7a/f0/80811e836484262b236c684a75dfc4ba0424bc670e765afaa911468d9f39/numpy-2.1.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc6f24b3d1ecc1eebfbf5d6051faa49af40b03be1aaa781ebdadcbc090b4539b", size = 16339644 },
41
+ { url = "https://files.pythonhosted.org/packages/fa/81/ce213159a1ed8eb7d88a2a6ef4fbdb9e4ffd0c76b866c350eb4e3c37e640/numpy-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:17ee83a1f4fef3c94d16dc1802b998668b5419362c8a4f4e8a491de1b41cc3ee", size = 16712217 },
42
+ { url = "https://files.pythonhosted.org/packages/7d/84/4de0b87d5a72f45556b2a8ee9fc8801e8518ec867fc68260c1f5dcb3903f/numpy-2.1.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:15cb89f39fa6d0bdfb600ea24b250e5f1a3df23f901f51c8debaa6a5d122b2f0", size = 14399053 },
43
+ { url = "https://files.pythonhosted.org/packages/7e/1c/e5fabb9ad849f9d798b44458fd12a318d27592d4bc1448e269dec070ff04/numpy-2.1.3-cp311-cp311-win32.whl", hash = "sha256:d9beb777a78c331580705326d2367488d5bc473b49a9bc3036c154832520aca9", size = 6534741 },
44
+ { url = "https://files.pythonhosted.org/packages/1e/48/a9a4b538e28f854bfb62e1dea3c8fea12e90216a276c7777ae5345ff29a7/numpy-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:d89dd2b6da69c4fff5e39c28a382199ddedc3a5be5390115608345dec660b9e2", size = 12869487 },
20
45
  { url = "https://files.pythonhosted.org/packages/8a/f0/385eb9970309643cbca4fc6eebc8bb16e560de129c91258dfaa18498da8b/numpy-2.1.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f55ba01150f52b1027829b50d70ef1dafd9821ea82905b63936668403c3b471e", size = 20849658 },
21
46
  { url = "https://files.pythonhosted.org/packages/54/4a/765b4607f0fecbb239638d610d04ec0a0ded9b4951c56dc68cef79026abf/numpy-2.1.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:13138eadd4f4da03074851a698ffa7e405f41a0845a6b1ad135b81596e4e9958", size = 13492258 },
22
47
  { url = "https://files.pythonhosted.org/packages/bd/a7/2332679479c70b68dccbf4a8eb9c9b5ee383164b161bee9284ac141fbd33/numpy-2.1.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:a6b46587b14b888e95e4a24d7b13ae91fa22386c199ee7b418f449032b2fa3b8", size = 5090249 },
@@ -47,6 +72,10 @@ wheels = [
47
72
  { url = "https://files.pythonhosted.org/packages/ef/62/1d3204313357591c913c32132a28f09a26357e33ea3c4e2fe81269e0dca1/numpy-2.1.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:14e253bd43fc6b37af4921b10f6add6925878a42a0c5fe83daee390bca80bc17", size = 14067180 },
48
73
  { url = "https://files.pythonhosted.org/packages/24/d7/78a40ed1d80e23a774cb8a34ae8a9493ba1b4271dde96e56ccdbab1620ef/numpy-2.1.3-cp313-cp313t-win32.whl", hash = "sha256:08788d27a5fd867a663f6fc753fd7c3ad7e92747efc73c53bca2f19f8bc06f48", size = 6291907 },
49
74
  { url = "https://files.pythonhosted.org/packages/86/09/a5ab407bd7f5f5599e6a9261f964ace03a73e7c6928de906981c31c38082/numpy-2.1.3-cp313-cp313t-win_amd64.whl", hash = "sha256:2564fbdf2b99b3f815f2107c1bbc93e2de8ee655a69c261363a1172a79a257d4", size = 12644098 },
75
+ { url = "https://files.pythonhosted.org/packages/00/e7/8d8bb791b62586cc432ecbb70632b4f23b7b7c88df41878de7528264f6d7/numpy-2.1.3-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:4f2015dfe437dfebbfce7c85c7b53d81ba49e71ba7eadbf1df40c915af75979f", size = 20983893 },
76
+ { url = "https://files.pythonhosted.org/packages/5e/f3/cb8118a044b5007586245a650360c9f5915b2f4232dd7658bb7a63dd1d02/numpy-2.1.3-pp310-pypy310_pp73-macosx_14_0_x86_64.whl", hash = "sha256:3522b0dfe983a575e6a9ab3a4a4dfe156c3e428468ff08ce582b9bb6bd1d71d4", size = 6752501 },
77
+ { url = "https://files.pythonhosted.org/packages/53/f5/365b46439b518d2ec6ebb880cc0edf90f225145dfd4db7958334f7164530/numpy-2.1.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c006b607a865b07cd981ccb218a04fc86b600411d83d6fc261357f1c0966755d", size = 16142601 },
78
+ { url = "https://files.pythonhosted.org/packages/03/c2/d1fee6ba999aa7cd41ca6856937f2baaf604c3eec1565eae63451ec31e5e/numpy-2.1.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:e14e26956e6f1696070788252dcdff11b4aca4c3e8bd166e0df1bb8f315a67cb", size = 12771397 },
50
79
  ]
51
80
 
52
81
  [[package]]
@@ -73,6 +102,20 @@ dependencies = [
73
102
  ]
74
103
  sdist = { url = "https://files.pythonhosted.org/packages/9c/d6/9f8431bacc2e19dca897724cd097b1bb224a6ad5433784a44b587c7c13af/pandas-2.2.3.tar.gz", hash = "sha256:4f18ba62b61d7e192368b84517265a99b4d7ee8912f8708660fb4a366cc82667", size = 4399213 }
75
104
  wheels = [
105
+ { url = "https://files.pythonhosted.org/packages/aa/70/c853aec59839bceed032d52010ff5f1b8d87dc3114b762e4ba2727661a3b/pandas-2.2.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1948ddde24197a0f7add2bdc4ca83bf2b1ef84a1bc8ccffd95eda17fd836ecb5", size = 12580827 },
106
+ { url = "https://files.pythonhosted.org/packages/99/f2/c4527768739ffa4469b2b4fff05aa3768a478aed89a2f271a79a40eee984/pandas-2.2.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:381175499d3802cde0eabbaf6324cce0c4f5d52ca6f8c377c29ad442f50f6348", size = 11303897 },
107
+ { url = "https://files.pythonhosted.org/packages/ed/12/86c1747ea27989d7a4064f806ce2bae2c6d575b950be087837bdfcabacc9/pandas-2.2.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d9c45366def9a3dd85a6454c0e7908f2b3b8e9c138f5dc38fed7ce720d8453ed", size = 66480908 },
108
+ { url = "https://files.pythonhosted.org/packages/44/50/7db2cd5e6373ae796f0ddad3675268c8d59fb6076e66f0c339d61cea886b/pandas-2.2.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86976a1c5b25ae3f8ccae3a5306e443569ee3c3faf444dfd0f41cda24667ad57", size = 13064210 },
109
+ { url = "https://files.pythonhosted.org/packages/61/61/a89015a6d5536cb0d6c3ba02cebed51a95538cf83472975275e28ebf7d0c/pandas-2.2.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b8661b0238a69d7aafe156b7fa86c44b881387509653fdf857bebc5e4008ad42", size = 16754292 },
110
+ { url = "https://files.pythonhosted.org/packages/ce/0d/4cc7b69ce37fac07645a94e1d4b0880b15999494372c1523508511b09e40/pandas-2.2.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:37e0aced3e8f539eccf2e099f65cdb9c8aa85109b0be6e93e2baff94264bdc6f", size = 14416379 },
111
+ { url = "https://files.pythonhosted.org/packages/31/9e/6ebb433de864a6cd45716af52a4d7a8c3c9aaf3a98368e61db9e69e69a9c/pandas-2.2.3-cp310-cp310-win_amd64.whl", hash = "sha256:56534ce0746a58afaf7942ba4863e0ef81c9c50d3f0ae93e9497d6a41a057645", size = 11598471 },
112
+ { url = "https://files.pythonhosted.org/packages/a8/44/d9502bf0ed197ba9bf1103c9867d5904ddcaf869e52329787fc54ed70cc8/pandas-2.2.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:66108071e1b935240e74525006034333f98bcdb87ea116de573a6a0dccb6c039", size = 12602222 },
113
+ { url = "https://files.pythonhosted.org/packages/52/11/9eac327a38834f162b8250aab32a6781339c69afe7574368fffe46387edf/pandas-2.2.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7c2875855b0ff77b2a64a0365e24455d9990730d6431b9e0ee18ad8acee13dbd", size = 11321274 },
114
+ { url = "https://files.pythonhosted.org/packages/45/fb/c4beeb084718598ba19aa9f5abbc8aed8b42f90930da861fcb1acdb54c3a/pandas-2.2.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cd8d0c3be0515c12fed0bdbae072551c8b54b7192c7b1fda0ba56059a0179698", size = 15579836 },
115
+ { url = "https://files.pythonhosted.org/packages/cd/5f/4dba1d39bb9c38d574a9a22548c540177f78ea47b32f99c0ff2ec499fac5/pandas-2.2.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c124333816c3a9b03fbeef3a9f230ba9a737e9e5bb4060aa2107a86cc0a497fc", size = 13058505 },
116
+ { url = "https://files.pythonhosted.org/packages/b9/57/708135b90391995361636634df1f1130d03ba456e95bcf576fada459115a/pandas-2.2.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:63cc132e40a2e084cf01adf0775b15ac515ba905d7dcca47e9a251819c575ef3", size = 16744420 },
117
+ { url = "https://files.pythonhosted.org/packages/86/4a/03ed6b7ee323cf30404265c284cee9c65c56a212e0a08d9ee06984ba2240/pandas-2.2.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:29401dbfa9ad77319367d36940cd8a0b3a11aba16063e39632d98b0e931ddf32", size = 14440457 },
118
+ { url = "https://files.pythonhosted.org/packages/ed/8c/87ddf1fcb55d11f9f847e3c69bb1c6f8e46e2f40ab1a2d2abadb2401b007/pandas-2.2.3-cp311-cp311-win_amd64.whl", hash = "sha256:3fc6873a41186404dad67245896a6e440baacc92f5b716ccd1bc9ed2995ab2c5", size = 11617166 },
76
119
  { url = "https://files.pythonhosted.org/packages/17/a3/fb2734118db0af37ea7433f57f722c0a56687e14b14690edff0cdb4b7e58/pandas-2.2.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b1d432e8d08679a40e2a6d8b2f9770a5c21793a6f9f47fdd52c5ce1948a5a8a9", size = 12529893 },
77
120
  { url = "https://files.pythonhosted.org/packages/e1/0c/ad295fd74bfac85358fd579e271cded3ac969de81f62dd0142c426b9da91/pandas-2.2.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a5a1595fe639f5988ba6a8e5bc9649af3baf26df3998a0abe56c02609392e0a4", size = 11363475 },
78
121
  { url = "https://files.pythonhosted.org/packages/c6/2a/4bba3f03f7d07207481fed47f5b35f556c7441acddc368ec43d6643c5777/pandas-2.2.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5de54125a92bb4d1c051c0659e6fcb75256bf799a732a87184e5ea503965bce3", size = 15188645 },
@@ -118,7 +161,7 @@ wheels = [
118
161
 
119
162
  [[package]]
120
163
  name = "relib"
121
- version = "1.3.4"
164
+ version = "1.3.6"
122
165
  source = { editable = "." }
123
166
 
124
167
  [package.dev-dependencies]
@@ -175,12 +218,20 @@ version = "6.0.0"
175
218
  source = { registry = "https://pypi.org/simple" }
176
219
  sdist = { url = "https://files.pythonhosted.org/packages/db/7d/7f3d619e951c88ed75c6037b246ddcf2d322812ee8ea189be89511721d54/watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282", size = 131220 }
177
220
  wheels = [
221
+ { url = "https://files.pythonhosted.org/packages/0c/56/90994d789c61df619bfc5ce2ecdabd5eeff564e1eb47512bd01b5e019569/watchdog-6.0.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d1cdb490583ebd691c012b3d6dae011000fe42edb7a82ece80965b42abd61f26", size = 96390 },
222
+ { url = "https://files.pythonhosted.org/packages/55/46/9a67ee697342ddf3c6daa97e3a587a56d6c4052f881ed926a849fcf7371c/watchdog-6.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bc64ab3bdb6a04d69d4023b29422170b74681784ffb9463ed4870cf2f3e66112", size = 88389 },
223
+ { url = "https://files.pythonhosted.org/packages/44/65/91b0985747c52064d8701e1075eb96f8c40a79df889e59a399453adfb882/watchdog-6.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c897ac1b55c5a1461e16dae288d22bb2e412ba9807df8397a635d88f671d36c3", size = 89020 },
224
+ { url = "https://files.pythonhosted.org/packages/e0/24/d9be5cd6642a6aa68352ded4b4b10fb0d7889cb7f45814fb92cecd35f101/watchdog-6.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6eb11feb5a0d452ee41f824e271ca311a09e250441c262ca2fd7ebcf2461a06c", size = 96393 },
225
+ { url = "https://files.pythonhosted.org/packages/63/7a/6013b0d8dbc56adca7fdd4f0beed381c59f6752341b12fa0886fa7afc78b/watchdog-6.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ef810fbf7b781a5a593894e4f439773830bdecb885e6880d957d5b9382a960d2", size = 88392 },
226
+ { url = "https://files.pythonhosted.org/packages/d1/40/b75381494851556de56281e053700e46bff5b37bf4c7267e858640af5a7f/watchdog-6.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:afd0fe1b2270917c5e23c2a65ce50c2a4abb63daafb0d419fde368e272a76b7c", size = 89019 },
178
227
  { url = "https://files.pythonhosted.org/packages/39/ea/3930d07dafc9e286ed356a679aa02d777c06e9bfd1164fa7c19c288a5483/watchdog-6.0.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdd4e6f14b8b18c334febb9c4425a878a2ac20efd1e0b231978e7b150f92a948", size = 96471 },
179
228
  { url = "https://files.pythonhosted.org/packages/12/87/48361531f70b1f87928b045df868a9fd4e253d9ae087fa4cf3f7113be363/watchdog-6.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c7c15dda13c4eb00d6fb6fc508b3c0ed88b9d5d374056b239c4ad1611125c860", size = 88449 },
180
229
  { url = "https://files.pythonhosted.org/packages/5b/7e/8f322f5e600812e6f9a31b75d242631068ca8f4ef0582dd3ae6e72daecc8/watchdog-6.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6f10cb2d5902447c7d0da897e2c6768bca89174d0c6e1e30abec5421af97a5b0", size = 89054 },
181
230
  { url = "https://files.pythonhosted.org/packages/68/98/b0345cabdce2041a01293ba483333582891a3bd5769b08eceb0d406056ef/watchdog-6.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:490ab2ef84f11129844c23fb14ecf30ef3d8a6abafd3754a6f75ca1e6654136c", size = 96480 },
182
231
  { url = "https://files.pythonhosted.org/packages/85/83/cdf13902c626b28eedef7ec4f10745c52aad8a8fe7eb04ed7b1f111ca20e/watchdog-6.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:76aae96b00ae814b181bb25b1b98076d5fc84e8a53cd8885a318b42b6d3a5134", size = 88451 },
183
232
  { url = "https://files.pythonhosted.org/packages/fe/c4/225c87bae08c8b9ec99030cd48ae9c4eca050a59bf5c2255853e18c87b50/watchdog-6.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a175f755fc2279e0b7312c0035d52e27211a5bc39719dd529625b1930917345b", size = 89057 },
233
+ { url = "https://files.pythonhosted.org/packages/30/ad/d17b5d42e28a8b91f8ed01cb949da092827afb9995d4559fd448d0472763/watchdog-6.0.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:c7ac31a19f4545dd92fc25d200694098f42c9a8e391bc00bdd362c5736dbf881", size = 87902 },
234
+ { url = "https://files.pythonhosted.org/packages/5c/ca/c3649991d140ff6ab67bfc85ab42b165ead119c9e12211e08089d763ece5/watchdog-6.0.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:9513f27a1a582d9808cf21a07dae516f0fab1cf2d7683a742c498b93eedabb11", size = 88380 },
184
235
  { url = "https://files.pythonhosted.org/packages/a9/c7/ca4bf3e518cb57a686b2feb4f55a1892fd9a3dd13f470fca14e00f80ea36/watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", size = 79079 },
185
236
  { url = "https://files.pythonhosted.org/packages/5c/51/d46dc9332f9a647593c947b4b88e2381c8dfc0942d15b8edc0310fa4abb1/watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", size = 79078 },
186
237
  { url = "https://files.pythonhosted.org/packages/d4/57/04edbf5e169cd318d5f07b4766fee38e825d64b6913ca157ca32d1a42267/watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e", size = 79076 },
@@ -1 +0,0 @@
1
- 3.12
@@ -1,96 +0,0 @@
1
- from typing import Any, Callable, Iterable, overload
2
- from .type_utils import as_any
3
-
4
- __all__ = [
5
- "deepen_dict", "dict_by", "dict_firsts",
6
- "flatten_dict_inner", "flatten_dict",
7
- "get_at", "group",
8
- "key_of",
9
- "map_dict", "merge_dicts",
10
- "omit",
11
- "pick",
12
- "tuple_by",
13
- ]
14
-
15
- def merge_dicts[T, K](*dicts: dict[K, T]) -> dict[K, T]:
16
- if len(dicts) == 1:
17
- return dicts[0]
18
- result = {}
19
- for d in dicts:
20
- result |= d
21
- return result
22
-
23
- def omit[T, K](d: dict[K, T], keys: Iterable[K]) -> dict[K, T]:
24
- if keys:
25
- d = dict(d)
26
- for key in keys:
27
- del d[key]
28
- return d
29
-
30
- def pick[T, K](d: dict[K, T], keys: Iterable[K]) -> dict[K, T]:
31
- return {key: d[key] for key in keys}
32
-
33
- def dict_by[T, K](keys: Iterable[K], values: Iterable[T]) -> dict[K, T]:
34
- return dict(zip(keys, values))
35
-
36
- def tuple_by[T, K](d: dict[K, T], keys: Iterable[K]) -> tuple[T, ...]:
37
- return tuple(d[key] for key in keys)
38
-
39
- def map_dict[T, U, K](fn: Callable[[T], U], d: dict[K, T]) -> dict[K, U]:
40
- return {key: fn(value) for key, value in d.items()}
41
-
42
- def key_of[T, U](dicts: Iterable[dict[T, U]], key: T) -> list[U]:
43
- return [d[key] for d in dicts]
44
-
45
- def get_at[T](d: dict, keys: Iterable[Any], default: T) -> T:
46
- try:
47
- for key in keys:
48
- d = d[key]
49
- except KeyError:
50
- return default
51
- return as_any(d)
52
-
53
- def dict_firsts[T, K](pairs: Iterable[tuple[K, T]]) -> dict[K, T]:
54
- result: dict[K, T] = {}
55
- for key, value in pairs:
56
- result.setdefault(key, value)
57
- return result
58
-
59
- def group[T, K](pairs: Iterable[tuple[K, T]]) -> dict[K, list[T]]:
60
- values_by_key = {}
61
- for key, value in pairs:
62
- values_by_key.setdefault(key, []).append(value)
63
- return values_by_key
64
-
65
- def flatten_dict_inner(d, prefix=()):
66
- for key, value in d.items():
67
- if not isinstance(value, dict) or value == {}:
68
- yield prefix + (key,), value
69
- else:
70
- yield from flatten_dict_inner(value, prefix + (key,))
71
-
72
- def flatten_dict(deep_dict: dict, prefix=()) -> dict:
73
- return dict(flatten_dict_inner(deep_dict, prefix))
74
-
75
- @overload
76
- def deepen_dict[K1, U](d: dict[tuple[K1], U]) -> dict[K1, U]: ...
77
- @overload
78
- def deepen_dict[K1, K2, U](d: dict[tuple[K1, K2], U]) -> dict[K1, dict[K2, U]]: ...
79
- @overload
80
- def deepen_dict[K1, K2, K3, U](d: dict[tuple[K1, K2, K3], U]) -> dict[K1, dict[K2, dict[K3, U]]]: ...
81
- @overload
82
- def deepen_dict[K1, K2, K3, K4, U](d: dict[tuple[K1, K2, K3, K4], U]) -> dict[K1, dict[K2, dict[K3, dict[K4, U]]]]: ...
83
- @overload
84
- def deepen_dict[K1, K2, K3, K4, K5, U](d: dict[tuple[K1, K2, K3, K4, K5], U]) -> dict[K1, dict[K2, dict[K3, dict[K4, dict[K5, U]]]]]: ...
85
- @overload
86
- def deepen_dict[K1, K2, K3, K4, K5, K6, U](d: dict[tuple[K1, K2, K3, K4, K5, K6], U]) -> dict[K1, dict[K2, dict[K3, dict[K4, dict[K5, dict[K6, U]]]]]]: ...
87
- def deepen_dict(d: dict[tuple[Any, ...], Any]) -> dict:
88
- output = {}
89
- if () in d:
90
- return d[()]
91
- for (*tail, head), value in d.items():
92
- curr = output
93
- for key in tail:
94
- curr = curr.setdefault(key, {})
95
- curr[head] = value
96
- return output
File without changes
File without changes
File without changes
File without changes
File without changes