pythonwrench 0.4.3__tar.gz → 0.4.4__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.
Files changed (73) hide show
  1. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/LICENSE +1 -1
  2. {pythonwrench-0.4.3/src/pythonwrench.egg-info → pythonwrench-0.4.4}/PKG-INFO +4 -5
  3. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/README.md +1 -1
  4. pythonwrench-0.4.4/docs/requirements.txt +3 -0
  5. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/src/pythonwrench/__init__.py +2 -1
  6. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/src/pythonwrench/collections/__init__.py +1 -0
  7. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/src/pythonwrench/collections/collections.py +22 -1
  8. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/src/pythonwrench/concurrent.py +25 -10
  9. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/src/pythonwrench/disk_cache.py +13 -2
  10. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/src/pythonwrench/jsonl.py +9 -0
  11. {pythonwrench-0.4.3 → pythonwrench-0.4.4/src/pythonwrench.egg-info}/PKG-INFO +4 -5
  12. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/src/pythonwrench.egg-info/SOURCES.txt +1 -0
  13. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/tests/test_disk_cache.py +1 -1
  14. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/pyproject.toml +0 -0
  15. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/setup.cfg +0 -0
  16. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/setup.py +0 -0
  17. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/src/pythonwrench/__main__.py +0 -0
  18. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/src/pythonwrench/_core.py +0 -0
  19. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/src/pythonwrench/abc.py +0 -0
  20. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/src/pythonwrench/argparse.py +0 -0
  21. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/src/pythonwrench/cast.py +0 -0
  22. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/src/pythonwrench/checksum.py +0 -0
  23. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/src/pythonwrench/collections/prop.py +0 -0
  24. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/src/pythonwrench/collections/reducers.py +0 -0
  25. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/src/pythonwrench/csv.py +0 -0
  26. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/src/pythonwrench/dataclasses.py +0 -0
  27. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/src/pythonwrench/datetime.py +0 -0
  28. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/src/pythonwrench/difflib.py +0 -0
  29. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/src/pythonwrench/entries.py +0 -0
  30. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/src/pythonwrench/enum.py +0 -0
  31. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/src/pythonwrench/functools.py +0 -0
  32. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/src/pythonwrench/hashlib.py +0 -0
  33. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/src/pythonwrench/importlib.py +0 -0
  34. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/src/pythonwrench/inspect.py +0 -0
  35. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/src/pythonwrench/json.py +0 -0
  36. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/src/pythonwrench/logging.py +0 -0
  37. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/src/pythonwrench/math.py +0 -0
  38. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/src/pythonwrench/os.py +0 -0
  39. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/src/pythonwrench/pickle.py +0 -0
  40. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/src/pythonwrench/random.py +0 -0
  41. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/src/pythonwrench/re.py +0 -0
  42. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/src/pythonwrench/semver.py +0 -0
  43. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/src/pythonwrench/typing/__init__.py +0 -0
  44. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/src/pythonwrench/typing/checks.py +0 -0
  45. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/src/pythonwrench/typing/classes.py +0 -0
  46. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/src/pythonwrench/warnings.py +0 -0
  47. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/src/pythonwrench.egg-info/dependency_links.txt +0 -0
  48. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/src/pythonwrench.egg-info/entry_points.txt +0 -0
  49. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/src/pythonwrench.egg-info/requires.txt +0 -0
  50. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/src/pythonwrench.egg-info/top_level.txt +0 -0
  51. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/tests/test_abc.py +0 -0
  52. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/tests/test_argparse.py +0 -0
  53. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/tests/test_cast.py +0 -0
  54. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/tests/test_checksum.py +0 -0
  55. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/tests/test_collections.py +0 -0
  56. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/tests/test_csv.py +0 -0
  57. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/tests/test_dataclasses.py +0 -0
  58. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/tests/test_difflib.py +0 -0
  59. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/tests/test_entries.py +0 -0
  60. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/tests/test_enum.py +0 -0
  61. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/tests/test_functools.py +0 -0
  62. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/tests/test_hashlib.py +0 -0
  63. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/tests/test_importlib.py +0 -0
  64. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/tests/test_inspect.py +0 -0
  65. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/tests/test_json.py +0 -0
  66. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/tests/test_jsonl.py +0 -0
  67. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/tests/test_logging.py +0 -0
  68. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/tests/test_math.py +0 -0
  69. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/tests/test_os.py +0 -0
  70. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/tests/test_random.py +0 -0
  71. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/tests/test_readme.py +0 -0
  72. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/tests/test_semver.py +0 -0
  73. {pythonwrench-0.4.3 → pythonwrench-0.4.4}/tests/test_typing.py +0 -0
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2025 Labbeti
3
+ Copyright (c) 2026 Labbeti
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -1,12 +1,12 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.1
2
2
  Name: pythonwrench
3
- Version: 0.4.3
3
+ Version: 0.4.4
4
4
  Summary: Python library with tools for typing, manipulating collections, and more!
5
5
  Author-email: "Étienne Labbé (Labbeti)" <labbeti.pub@gmail.com>
6
6
  Maintainer-email: "Étienne Labbé (Labbeti)" <labbeti.pub@gmail.com>
7
7
  License: MIT License
8
8
 
9
- Copyright (c) 2025 Labbeti
9
+ Copyright (c) 2026 Labbeti
10
10
 
11
11
  Permission is hereby granted, free of charge, to any person obtaining a copy
12
12
  of this software and associated documentation files (the "Software"), to deal
@@ -52,7 +52,6 @@ Description-Content-Type: text/markdown
52
52
  License-File: LICENSE
53
53
  Requires-Dist: typing-extensions>=4.10.0
54
54
  Provides-Extra: dev
55
- Dynamic: license-file
56
55
 
57
56
  # pythonwrench
58
57
 
@@ -91,7 +90,7 @@ This library has been tested on all Python versions **3.8 - 3.14**, requires onl
91
90
 
92
91
  ### Typing
93
92
 
94
- Check generic types with ìsinstance_generic` :
93
+ Check generic types with `isinstance_generic` :
95
94
 
96
95
  ```python
97
96
  >>> import pythonwrench as pw
@@ -35,7 +35,7 @@ This library has been tested on all Python versions **3.8 - 3.14**, requires onl
35
35
 
36
36
  ### Typing
37
37
 
38
- Check generic types with ìsinstance_generic` :
38
+ Check generic types with `isinstance_generic` :
39
39
 
40
40
  ```python
41
41
  >>> import pythonwrench as pw
@@ -0,0 +1,3 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ sphinx-immaterial>=0.11.14
@@ -9,7 +9,7 @@ __author_email__ = "labbeti.pub@gmail.com"
9
9
  __license__ = "MIT"
10
10
  __maintainer__ = "Étienne Labbé (Labbeti)"
11
11
  __status__ = "Development"
12
- __version__ = "0.4.3"
12
+ __version__ = "0.4.4"
13
13
 
14
14
 
15
15
  # Re-import for language servers
@@ -18,6 +18,7 @@ from . import argparse as argparse
18
18
  from . import cast as cast
19
19
  from . import checksum as checksum
20
20
  from . import collections as collections
21
+ from . import concurrent as concurrent
21
22
  from . import csv as csv
22
23
  from . import dataclasses as dataclasses
23
24
  from . import datetime as datetime
@@ -2,6 +2,7 @@
2
2
  # -*- coding: utf-8 -*-
3
3
 
4
4
  from .collections import (
5
+ SizedGenerator,
5
6
  contained,
6
7
  dict_list_to_list_dict,
7
8
  dump_dict,
@@ -10,8 +10,10 @@ from typing import (
10
10
  Callable,
11
11
  Dict,
12
12
  Generator,
13
+ Generic,
13
14
  Hashable,
14
15
  Iterable,
16
+ Iterator,
15
17
  List,
16
18
  Literal,
17
19
  Mapping,
@@ -47,6 +49,21 @@ KeyMode = Literal["intersect", "same", "union"]
47
49
  Order = Literal["left", "right"]
48
50
 
49
51
 
52
+ class SizedGenerator(Generic[T]):
53
+ """Wraps a generator and size to provide a sized iterable object."""
54
+
55
+ def __init__(self, generator: Generator[T, None, None], size: int) -> None:
56
+ super().__init__()
57
+ self._generator = generator
58
+ self._size = size
59
+
60
+ def __iter__(self) -> Iterator[T]:
61
+ yield from self._generator
62
+
63
+ def __len__(self) -> int:
64
+ return self._size
65
+
66
+
50
67
  def contained(
51
68
  x: T,
52
69
  include: Optional[Iterable[T]] = None,
@@ -497,7 +514,7 @@ def list_dict_to_dict_list(
497
514
  """Convert list of dicts to dict of lists.
498
515
 
499
516
  Args:
500
- lst: The list of dict to merge.
517
+ lst: The list of dict to merge. Cannot be a Generator.
501
518
  key_mode: Can be "same" or "intersect". \
502
519
  - If "same", all the dictionaries must contains the same keys otherwise a ValueError will be raised. \
503
520
  - If "intersect", only the intersection of all keys will be used in output. \
@@ -507,6 +524,10 @@ def list_dict_to_dict_list(
507
524
  default_val_fn: Function to return the default value according to a specific key. defaults to None.
508
525
  list_fn: Optional function to build the values. defaults to identity.
509
526
  """
527
+ if isinstance(lst, Generator):
528
+ msg = f"Invalid argument type {type(lst)}. (expected any Iterable except Generator)"
529
+ raise TypeError(msg)
530
+
510
531
  try:
511
532
  item0 = next(iter(lst))
512
533
  except StopIteration:
@@ -3,7 +3,7 @@
3
3
 
4
4
  import logging
5
5
  from concurrent.futures import Future, ThreadPoolExecutor
6
- from typing import Callable, Generic, List, Optional, TypeVar
6
+ from typing import Any, Callable, Dict, Generic, Iterable, List, Optional, TypeVar
7
7
 
8
8
  from typing_extensions import ParamSpec
9
9
 
@@ -15,16 +15,32 @@ T = TypeVar("T")
15
15
 
16
16
 
17
17
  class ThreadPoolExecutorHelper(Generic[P, T]):
18
- def __init__(self, fn: Callable[P, T], **default_kwargs) -> None:
18
+ # Note: use commas for typing because Future is not generic in older python versions
19
+
20
+ def __init__(
21
+ self,
22
+ fn: Callable[P, T],
23
+ *,
24
+ executor_kwds: Optional[Dict[str, Any]] = None,
25
+ executor: Optional[ThreadPoolExecutor] = None,
26
+ futures: "Iterable[Future[T]]" = (),
27
+ **default_fn_kwds,
28
+ ) -> None:
29
+ futures = list(futures)
30
+
19
31
  super().__init__()
20
32
  self.fn = fn
21
- self.default_kwargs = default_kwargs
22
- self.executor: Optional[ThreadPoolExecutor] = None
23
- self.futures: list[Future[T]] = []
33
+ self.executor_kwds = executor_kwds
34
+ self.executor = executor
35
+ self.futures = futures
36
+ self.default_kwargs = default_fn_kwds
24
37
 
25
- def submit(self, *args: P.args, **kwargs: P.kwargs) -> Future[T]:
38
+ def submit(self, *args: P.args, **kwargs: P.kwargs) -> "Future[T]":
26
39
  if self.executor is None:
27
- self.executor = ThreadPoolExecutor()
40
+ executor_kwds = self.executor_kwds
41
+ if executor_kwds is None:
42
+ executor_kwds = {}
43
+ self.executor = ThreadPoolExecutor(**executor_kwds)
28
44
 
29
45
  kwargs = self.default_kwargs | kwargs # type: ignore
30
46
  future = self.executor.submit(self.fn, *args, **kwargs)
@@ -39,9 +55,8 @@ class ThreadPoolExecutorHelper(Generic[P, T]):
39
55
 
40
56
  futures = tqdm.tqdm(futures, disable=not verbose)
41
57
  except ImportError:
42
- logger.warning(
43
- "Cannot display verbose bar because tqdm is not installed."
44
- )
58
+ msg = "Cannot display verbose bar because tqdm is not installed."
59
+ logger.warning(msg)
45
60
 
46
61
  results = [future.result() for future in futures]
47
62
  self.futures.clear()
@@ -5,6 +5,7 @@ import logging
5
5
  import os
6
6
  import shutil
7
7
  import time
8
+ import warnings
8
9
  from functools import wraps
9
10
  from pathlib import Path
10
11
  from typing import (
@@ -25,7 +26,7 @@ from typing_extensions import ParamSpec
25
26
 
26
27
  from pythonwrench.checksum import checksum_any
27
28
  from pythonwrench.datetime import get_now
28
- from pythonwrench.inspect import get_fullname
29
+ from pythonwrench.inspect import get_argnames, get_fullname
29
30
 
30
31
  T = TypeVar("T")
31
32
  P = ParamSpec("P")
@@ -218,6 +219,10 @@ def _disk_cache_impl(
218
219
  ) -> Callable[[Callable[P, T]], Callable[P, T]]:
219
220
  # for backward compatibility
220
221
  if cache_fname_fmt is None:
222
+ warnings.warn(
223
+ f"Deprecated argument value {cache_fname_fmt=}. (use default instead)",
224
+ DeprecationWarning,
225
+ )
221
226
  cache_fname_fmt = "{fn_name}_{csum}{suffix}"
222
227
 
223
228
  if cache_saving_backend == "pickle":
@@ -270,13 +275,19 @@ def _disk_cache_impl(
270
275
  )
271
276
  load_start_msg = f"[{fn_name}] Loading cache..."
272
277
  load_end_msg = f"[{fn_name}] Cache loaded."
278
+ argnames = get_argnames(fn)
273
279
 
274
280
  @wraps(fn)
275
281
  def _disk_cache_wrapper(*args: P.args, **kwargs: P.kwargs) -> T:
276
282
  checksum_args = fn, args, kwargs
277
283
  csum = cache_checksum_fn(checksum_args)
284
+ inputs = dict(zip(argnames, args))
285
+ inputs.update(kwargs)
278
286
  cache_fname = cache_fname_fmt.format(
279
- fn_name=fn_name, csum=csum, suffix=suffix
287
+ fn_name=fn_name,
288
+ csum=csum,
289
+ suffix=suffix,
290
+ **inputs,
280
291
  )
281
292
  cache_fpath = cache_fn_dpath.joinpath(cache_fname)
282
293
 
@@ -18,6 +18,15 @@ from pythonwrench.json import (
18
18
  from pythonwrench.semver import Version
19
19
  from pythonwrench.warnings import warn_once
20
20
 
21
+ __all__ = [
22
+ "dump_jsonl",
23
+ "dumps_jsonl",
24
+ "save_jsonl",
25
+ "load_jsonl",
26
+ "loads_jsonl",
27
+ "read_jsonl",
28
+ ]
29
+
21
30
  # -- Dump / Save / Serialize content to JSONL --
22
31
 
23
32
 
@@ -1,12 +1,12 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.1
2
2
  Name: pythonwrench
3
- Version: 0.4.3
3
+ Version: 0.4.4
4
4
  Summary: Python library with tools for typing, manipulating collections, and more!
5
5
  Author-email: "Étienne Labbé (Labbeti)" <labbeti.pub@gmail.com>
6
6
  Maintainer-email: "Étienne Labbé (Labbeti)" <labbeti.pub@gmail.com>
7
7
  License: MIT License
8
8
 
9
- Copyright (c) 2025 Labbeti
9
+ Copyright (c) 2026 Labbeti
10
10
 
11
11
  Permission is hereby granted, free of charge, to any person obtaining a copy
12
12
  of this software and associated documentation files (the "Software"), to deal
@@ -52,7 +52,6 @@ Description-Content-Type: text/markdown
52
52
  License-File: LICENSE
53
53
  Requires-Dist: typing-extensions>=4.10.0
54
54
  Provides-Extra: dev
55
- Dynamic: license-file
56
55
 
57
56
  # pythonwrench
58
57
 
@@ -91,7 +90,7 @@ This library has been tested on all Python versions **3.8 - 3.14**, requires onl
91
90
 
92
91
  ### Typing
93
92
 
94
- Check generic types with ìsinstance_generic` :
93
+ Check generic types with `isinstance_generic` :
95
94
 
96
95
  ```python
97
96
  >>> import pythonwrench as pw
@@ -2,6 +2,7 @@ LICENSE
2
2
  README.md
3
3
  pyproject.toml
4
4
  setup.py
5
+ docs/requirements.txt
5
6
  src/pythonwrench/__init__.py
6
7
  src/pythonwrench/__main__.py
7
8
  src/pythonwrench/_core.py
@@ -23,7 +23,7 @@ class TestDiskCache(TestCase):
23
23
 
24
24
  def test_disk_cache_example_2(self) -> None:
25
25
  @pw.disk_cache_decorator(
26
- cache_fname_fmt="{fn_name}_{csum}.json",
26
+ cache_fname_fmt="{fn_name}_{csum}_x={x}.json",
27
27
  cache_load_fn=pw.load_json,
28
28
  cache_dump_fn=pw.dump_json,
29
29
  )
File without changes
File without changes