relib 1.2.8__py3-none-any.whl → 1.2.9__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/__init__.py CHANGED
@@ -1,46 +1,4 @@
1
- from .utils import (
2
- noop,
3
- non_none,
4
- as_any,
5
- list_split,
6
- drop_none,
7
- distinct,
8
- first,
9
- move_value,
10
- transpose_dict,
11
- make_combinations_by_dict,
12
- merge_dicts,
13
- intersect,
14
- ensure_tuple,
15
- key_of,
16
- omit,
17
- pick,
18
- dict_by,
19
- tuple_by,
20
- flatten,
21
- transpose,
22
- map_dict,
23
- deepen_dict,
24
- flatten_dict_inner,
25
- flatten_dict,
26
- group,
27
- reversed_enumerate,
28
- get_at,
29
- for_each,
30
- sized_partitions,
31
- num_partitions,
32
- df_from_array,
33
- StrFilter,
34
- str_filterer,
35
- )
36
- from .system import (
37
- read_json,
38
- write_json,
39
- clear_console,
40
- console_link,
41
- roll_tasks,
42
- as_async,
43
- async_limit,
44
- )
1
+ from .utils import *
2
+ from .system import *
45
3
  from .hashing import hash, hash_obj
46
4
  from .measure_duration import measure_duration
relib/system.py CHANGED
@@ -8,18 +8,28 @@ from pathlib import Path
8
8
  from typing import Any, Awaitable, Callable, Iterable, ParamSpec, TypeVar
9
9
  from .utils import noop
10
10
 
11
+ __all__ = [
12
+ "read_json",
13
+ "write_json",
14
+ "clear_console",
15
+ "console_link",
16
+ "roll_tasks",
17
+ "as_async",
18
+ "async_limit",
19
+ ]
20
+
11
21
  P = ParamSpec("P")
12
22
  R = TypeVar("R")
13
- default_num_workers = min(32, (os.cpu_count() or 1) + 4)
14
- _default_json: Any = {}
23
+ default_workers = min(32, (os.cpu_count() or 1) + 4)
24
+ default_sentinel = object()
15
25
 
16
- def read_json(path: Path, default=_default_json) -> Any:
17
- if default is not _default_json and not path.exists():
26
+ def read_json(path: Path, default=default_sentinel) -> Any:
27
+ if default is not default_sentinel and not path.exists():
18
28
  return default
19
29
  with path.open("r") as f:
20
30
  return json.load(f)
21
31
 
22
- def write_json(path: Path, obj: Any, indent: None | int = None) -> None:
32
+ def write_json(path: Path, obj: object, indent: None | int = None) -> None:
23
33
  with path.open("w") as f:
24
34
  return json.dump(obj, f, indent=indent)
25
35
 
@@ -35,7 +45,7 @@ async def worker[T](task: Awaitable[T], semaphore: asyncio.Semaphore, update=noo
35
45
  update()
36
46
  return result
37
47
 
38
- async def roll_tasks[T](tasks: Iterable[Awaitable[T]], workers=default_num_workers, progress=False) -> list[T]:
48
+ async def roll_tasks[T](tasks: Iterable[Awaitable[T]], workers=default_workers, progress=False) -> list[T]:
39
49
  semaphore = asyncio.Semaphore(workers)
40
50
  if not progress:
41
51
  return await asyncio.gather(*[worker(task, semaphore) for task in tasks])
@@ -46,7 +56,7 @@ async def roll_tasks[T](tasks: Iterable[Awaitable[T]], workers=default_num_worke
46
56
  update = functools.partial(pbar.update, 1)
47
57
  return await asyncio.gather(*[worker(task, semaphore, update) for task in tasks])
48
58
 
49
- def as_async(workers=default_num_workers) -> Callable[[Callable[P, R]], Callable[P, Awaitable[R]]]:
59
+ def as_async(workers=default_workers) -> Callable[[Callable[P, R]], Callable[P, Awaitable[R]]]:
50
60
  executor = ThreadPoolExecutor(max_workers=workers)
51
61
 
52
62
  def on_fn(func: Callable[P, R]) -> Callable[P, Awaitable[R]]:
@@ -59,7 +69,7 @@ def as_async(workers=default_num_workers) -> Callable[[Callable[P, R]], Callable
59
69
  return wrapper
60
70
  return on_fn
61
71
 
62
- def async_limit(workers=default_num_workers) -> Callable[[Callable[P, Awaitable[R]]], Callable[P, Awaitable[R]]]:
72
+ def async_limit(workers=default_workers) -> Callable[[Callable[P, Awaitable[R]]], Callable[P, Awaitable[R]]]:
63
73
  semaphore = asyncio.Semaphore(workers)
64
74
 
65
75
  def on_fn(func: Callable[P, Awaitable[R]]) -> Callable[P, Awaitable[R]]:
relib/utils.py CHANGED
@@ -2,6 +2,44 @@ import re
2
2
  from itertools import chain
3
3
  from typing import Any, Callable, Iterable, overload
4
4
 
5
+ __all__ = [
6
+ "noop",
7
+ "non_none",
8
+ "as_any",
9
+ "list_split",
10
+ "drop_none",
11
+ "distinct",
12
+ "dict_firsts",
13
+ "distinct_by",
14
+ "first",
15
+ "move_value",
16
+ "transpose_dict",
17
+ "make_combinations_by_dict",
18
+ "merge_dicts",
19
+ "intersect",
20
+ "ensure_tuple",
21
+ "key_of",
22
+ "omit",
23
+ "pick",
24
+ "dict_by",
25
+ "tuple_by",
26
+ "flatten",
27
+ "transpose",
28
+ "map_dict",
29
+ "deepen_dict",
30
+ "flatten_dict_inner",
31
+ "flatten_dict",
32
+ "group",
33
+ "reversed_enumerate",
34
+ "get_at",
35
+ "for_each",
36
+ "sized_partitions",
37
+ "num_partitions",
38
+ "df_from_array",
39
+ "StrFilter",
40
+ "str_filterer",
41
+ ]
42
+
5
43
  def noop() -> None:
6
44
  pass
7
45
 
@@ -27,6 +65,16 @@ def drop_none[T](iterable: Iterable[T | None]) -> list[T]:
27
65
  def distinct[T](items: Iterable[T]) -> list[T]:
28
66
  return list(dict.fromkeys(items))
29
67
 
68
+ def dict_firsts[T, K](items: Iterable[tuple[K, T]]) -> dict[K, T]:
69
+ result: dict[K, T] = {}
70
+ for key, item in items:
71
+ if key not in result:
72
+ result[key] = item
73
+ return result
74
+
75
+ def distinct_by[T](items: Iterable[tuple[object, T]]) -> list[T]:
76
+ return list(dict_firsts(items).values())
77
+
30
78
  def first[T](iterable: Iterable[T]) -> T | None:
31
79
  return next(iter(iterable), None)
32
80
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: relib
3
- Version: 1.2.8
3
+ Version: 1.2.9
4
4
  Project-URL: Repository, https://github.com/Reddan/relib.git
5
5
  Author: Hampus Hallman
6
6
  License: Copyright 2018-2025 Hampus Hallman
@@ -0,0 +1,9 @@
1
+ relib/__init__.py,sha256=4_nmex7mRhCwdtLF8k0XLbxxPs-UeN2sP-EEImm5JGs,126
2
+ relib/hashing.py,sha256=DB_fnkj0ls01FgZbf4nPFHl4EBU8X_0OrmDvty4HlRE,6020
3
+ relib/measure_duration.py,sha256=LCTo_D_qReNprD3fhtJ0daeWycS6xQE_cwxeg2_h0xo,456
4
+ relib/system.py,sha256=JOqH4oBM8XMzCfG65um9gQz9CHhEQ4JOaTwywIRgS8Q,2654
5
+ relib/utils.py,sha256=QGAse1K_K9qaRyL7AOdkpNmATcUSNOcHECLiJKuMxgo,7803
6
+ relib-1.2.9.dist-info/METADATA,sha256=idOhfbgIelWndDu3mSpUINq5EOag0O18WbDDJy2d8rc,1295
7
+ relib-1.2.9.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
8
+ relib-1.2.9.dist-info/licenses/LICENSE,sha256=9xVsdtv_-uSyY9Xl9yujwAPm4-mjcCLeVy-ljwXEWbo,1059
9
+ relib-1.2.9.dist-info/RECORD,,
@@ -1,9 +0,0 @@
1
- relib/__init__.py,sha256=pypVcr0ctaSdFZmwMnZvtioTbms3MlWfAcrnPVdZxog,689
2
- relib/hashing.py,sha256=DB_fnkj0ls01FgZbf4nPFHl4EBU8X_0OrmDvty4HlRE,6020
3
- relib/measure_duration.py,sha256=LCTo_D_qReNprD3fhtJ0daeWycS6xQE_cwxeg2_h0xo,456
4
- relib/system.py,sha256=RO8pd5eUmucbAxgfFi7UWHH5Cdp0aM6O1oe5cylrc4k,2527
5
- relib/utils.py,sha256=4fM0zsAdfrM2w9Q1YKcTfFG5kDzoNgD2amkgfTG39OY,6933
6
- relib-1.2.8.dist-info/METADATA,sha256=b8RvpgbcT7Y9zq6r-kwnnCZgql_eAdG41Y83-q2YIXg,1295
7
- relib-1.2.8.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
8
- relib-1.2.8.dist-info/licenses/LICENSE,sha256=9xVsdtv_-uSyY9Xl9yujwAPm4-mjcCLeVy-ljwXEWbo,1059
9
- relib-1.2.8.dist-info/RECORD,,
File without changes