checkpointer 2.6.0__py3-none-any.whl → 2.6.1__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.
- checkpointer/checkpoint.py +11 -8
- checkpointer/fn_ident.py +2 -2
- checkpointer/storages/pickle_storage.py +1 -0
- checkpointer/utils.py +1 -1
- {checkpointer-2.6.0.dist-info → checkpointer-2.6.1.dist-info}/METADATA +3 -3
- {checkpointer-2.6.0.dist-info → checkpointer-2.6.1.dist-info}/RECORD +8 -8
- {checkpointer-2.6.0.dist-info → checkpointer-2.6.1.dist-info}/WHEEL +0 -0
- {checkpointer-2.6.0.dist-info → checkpointer-2.6.1.dist-info}/licenses/LICENSE +0 -0
checkpointer/checkpoint.py
CHANGED
@@ -22,10 +22,11 @@ class CheckpointerOpts(TypedDict, total=False):
|
|
22
22
|
format: Type[Storage] | Literal["pickle", "memory", "bcolz"]
|
23
23
|
root_path: Path | str | None
|
24
24
|
when: bool
|
25
|
-
verbosity: Literal[0, 1]
|
25
|
+
verbosity: Literal[0, 1, 2]
|
26
26
|
hash_by: Callable | None
|
27
27
|
should_expire: Callable[[datetime], bool] | None
|
28
28
|
capture: bool
|
29
|
+
fn_hash: str | None
|
29
30
|
|
30
31
|
class Checkpointer:
|
31
32
|
def __init__(self, **opts: Unpack[CheckpointerOpts]):
|
@@ -36,6 +37,7 @@ class Checkpointer:
|
|
36
37
|
self.hash_by = opts.get("hash_by")
|
37
38
|
self.should_expire = opts.get("should_expire")
|
38
39
|
self.capture = opts.get("capture", False)
|
40
|
+
self.fn_hash = opts.get("fn_hash")
|
39
41
|
|
40
42
|
@overload
|
41
43
|
def __call__(self, fn: Fn, **override_opts: Unpack[CheckpointerOpts]) -> CheckpointFn[Fn]: ...
|
@@ -66,9 +68,9 @@ class CheckpointFn(Generic[Fn]):
|
|
66
68
|
store_format = self.checkpointer.format
|
67
69
|
Storage = STORAGE_MAP[store_format] if isinstance(store_format, str) else store_format
|
68
70
|
deep_hashes = [child._set_ident().fn_hash_raw for child in iterate_checkpoint_fns(self)]
|
69
|
-
self.fn_hash = str(ObjectHash().write_text(self.fn_hash_raw,
|
71
|
+
self.fn_hash = self.checkpointer.fn_hash or str(ObjectHash().write_text(self.fn_hash_raw, *deep_hashes))
|
70
72
|
self.fn_subdir = f"{fn_file}/{fn_name}/{self.fn_hash[:16]}"
|
71
|
-
self.is_async = inspect.iscoroutinefunction(
|
73
|
+
self.is_async: bool = self.fn.is_async if isinstance(self.fn, CheckpointFn) else inspect.iscoroutinefunction(self.fn)
|
72
74
|
self.storage = Storage(self)
|
73
75
|
self.cleanup = self.storage.cleanup
|
74
76
|
|
@@ -80,12 +82,13 @@ class CheckpointFn(Generic[Fn]):
|
|
80
82
|
self._lazyinit()
|
81
83
|
return self._getattribute(name)
|
82
84
|
|
83
|
-
def reinit(self, recursive=False):
|
85
|
+
def reinit(self, recursive=False) -> CheckpointFn[Fn]:
|
84
86
|
pointfns = list(iterate_checkpoint_fns(self)) if recursive else [self]
|
85
87
|
for pointfn in pointfns:
|
86
88
|
pointfn._set_ident(True)
|
87
89
|
for pointfn in pointfns:
|
88
90
|
pointfn._lazyinit()
|
91
|
+
return self
|
89
92
|
|
90
93
|
def get_checkpoint_id(self, args: tuple, kw: dict) -> str:
|
91
94
|
hash_params = [self.checkpointer.hash_by(*args, **kw)] if self.checkpointer.hash_by else (args, kw)
|
@@ -95,13 +98,13 @@ class CheckpointFn(Generic[Fn]):
|
|
95
98
|
async def _store_on_demand(self, args: tuple, kw: dict, rerun: bool):
|
96
99
|
checkpoint_id = self.get_checkpoint_id(args, kw)
|
97
100
|
checkpoint_path = self.checkpointer.root_path / checkpoint_id
|
98
|
-
|
101
|
+
verbosity = self.checkpointer.verbosity
|
99
102
|
refresh = rerun \
|
100
103
|
or not self.storage.exists(checkpoint_path) \
|
101
104
|
or (self.checkpointer.should_expire and self.checkpointer.should_expire(self.storage.checkpoint_date(checkpoint_path)))
|
102
105
|
|
103
106
|
if refresh:
|
104
|
-
print_checkpoint(
|
107
|
+
print_checkpoint(verbosity >= 1, "MEMORIZING", checkpoint_id, "blue")
|
105
108
|
data = self.fn(*args, **kw)
|
106
109
|
if inspect.iscoroutine(data):
|
107
110
|
data = await data
|
@@ -110,11 +113,11 @@ class CheckpointFn(Generic[Fn]):
|
|
110
113
|
|
111
114
|
try:
|
112
115
|
data = self.storage.load(checkpoint_path)
|
113
|
-
print_checkpoint(
|
116
|
+
print_checkpoint(verbosity >= 2, "REMEMBERED", checkpoint_id, "green")
|
114
117
|
return data
|
115
118
|
except (EOFError, FileNotFoundError):
|
116
119
|
pass
|
117
|
-
print_checkpoint(
|
120
|
+
print_checkpoint(verbosity >= 1, "CORRUPTED", checkpoint_id, "yellow")
|
118
121
|
return await self._store_on_demand(args, kw, True)
|
119
122
|
|
120
123
|
def _call(self, args: tuple, kw: dict, rerun=False):
|
checkpointer/fn_ident.py
CHANGED
@@ -4,7 +4,7 @@ from collections.abc import Callable
|
|
4
4
|
from itertools import takewhile
|
5
5
|
from pathlib import Path
|
6
6
|
from types import CodeType, FunctionType, MethodType
|
7
|
-
from typing import Any,
|
7
|
+
from typing import Any, Iterable, Type, TypeGuard
|
8
8
|
from .object_hash import ObjectHash
|
9
9
|
from .utils import AttrDict, distinct, get_cell_contents, iterate_and_upcoming, transpose, unwrap_fn
|
10
10
|
|
@@ -33,7 +33,7 @@ def extract_classvars(code: CodeType, scope_vars: AttrDict) -> dict[str, dict[st
|
|
33
33
|
scope_obj = None
|
34
34
|
return classvars
|
35
35
|
|
36
|
-
def extract_scope_values(code: CodeType, scope_vars: AttrDict) ->
|
36
|
+
def extract_scope_values(code: CodeType, scope_vars: AttrDict) -> Iterable[tuple[tuple[str, ...], Any]]:
|
37
37
|
classvars = extract_classvars(code, scope_vars)
|
38
38
|
scope_vars = scope_vars.set({k: scope_vars[k].set(v) for k, v in classvars.items()})
|
39
39
|
for instr, upcoming_instrs in iterate_and_upcoming(dis.get_instructions(code)):
|
checkpointer/utils.py
CHANGED
@@ -23,7 +23,7 @@ def get_fn_body(fn: Callable) -> str:
|
|
23
23
|
ignore_types = (tokenize.COMMENT, tokenize.NL)
|
24
24
|
return "".join("\0" + token.string for token in tokens if token.type not in ignore_types)
|
25
25
|
|
26
|
-
def get_cell_contents(fn: Callable) ->
|
26
|
+
def get_cell_contents(fn: Callable) -> Iterable[tuple[str, Any]]:
|
27
27
|
for key, cell in zip(fn.__code__.co_freevars, fn.__closure__ or []):
|
28
28
|
try:
|
29
29
|
yield (key, cell.cell_contents)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: checkpointer
|
3
|
-
Version: 2.6.
|
3
|
+
Version: 2.6.1
|
4
4
|
Summary: A Python library for memoizing function results with support for multiple storage backends, async runtimes, and automatic cache invalidation
|
5
5
|
Project-URL: Repository, https://github.com/Reddan/checkpointer.git
|
6
6
|
Author: Hampus Hallman
|
@@ -17,7 +17,7 @@ Classifier: Programming Language :: Python :: 3.13
|
|
17
17
|
Requires-Python: >=3.12
|
18
18
|
Description-Content-Type: text/markdown
|
19
19
|
|
20
|
-
# checkpointer · [](https://github.com/Reddan/checkpointer/blob/master/LICENSE) [](https://pypi.org/project/checkpointer/) [](https://github.com/Reddan/checkpointer/blob/master/LICENSE) [](https://pypi.org/project/checkpointer/) [](https://pypi.org/project/checkpointer/)
|
21
21
|
|
22
22
|
`checkpointer` is a Python library for memoizing function results. It provides a decorator-based API with support for multiple storage backends. Use it for computationally expensive operations where caching can save time, or during development to avoid waiting for redundant computations.
|
23
23
|
|
@@ -225,7 +225,7 @@ Use a custom backend to integrate with databases, cloud storage, or specialized
|
|
225
225
|
| `format` | `"pickle"`, `"memory"`, `Storage` | `"pickle"` | Storage backend format. |
|
226
226
|
| `root_path` | `Path`, `str`, or `None` | ~/.cache/checkpoints | Root directory for storing checkpoints. |
|
227
227
|
| `when` | `bool` | `True` | Enable or disable checkpointing. |
|
228
|
-
| `verbosity` | `0` or `
|
228
|
+
| `verbosity` | `0`, `1` or `2` | `1` | Logging verbosity. |
|
229
229
|
| `should_expire` | `Callable[[datetime], bool]` | `None` | Custom expiration logic. |
|
230
230
|
| `hash_by` | `Callable[..., Any]` | `None` | Custom function that transforms arguments before hashing. |
|
231
231
|
|
@@ -1,16 +1,16 @@
|
|
1
1
|
checkpointer/__init__.py,sha256=ZJ6frUNgkklUi85b5uXTyTfRzMvZgQOJY-ZOnu7jh78,777
|
2
|
-
checkpointer/checkpoint.py,sha256=
|
3
|
-
checkpointer/fn_ident.py,sha256=
|
2
|
+
checkpointer/checkpoint.py,sha256=3ohNeAqzZLCT9IHJ7nsDbtZ8rjI0rdApbqp8KowDRtc,6332
|
3
|
+
checkpointer/fn_ident.py,sha256=SWaksNCTlskMom0ztqjECSRjZYPWXUA1p1ZCb-9tWo0,4297
|
4
4
|
checkpointer/object_hash.py,sha256=o7Qr9VViWPmG1Fy1S3RediCagRydEVgTVZrZ9nRN54E,7215
|
5
5
|
checkpointer/print_checkpoint.py,sha256=21aeqgM9CMjNAJyScqFmXCWWfh3jBIn7o7i5zJkZGaA,1369
|
6
6
|
checkpointer/test_checkpointer.py,sha256=uJ2Pg9Miq1W0l28eNlRhMjuT_R8c-ygYwp3KP3VW8Os,3600
|
7
|
-
checkpointer/utils.py,sha256=
|
7
|
+
checkpointer/utils.py,sha256=w1cAoKAERPIaJ1pYYINCTZWOgNTtCYa1_FTzeG5qh10,3034
|
8
8
|
checkpointer/storages/__init__.py,sha256=Kl4Og5jhYxn6m3tB_kTMsabf4_eWVLmFVAoC-pikNQE,301
|
9
9
|
checkpointer/storages/bcolz_storage.py,sha256=3QkSUSeG5s2kFuVV_LZpzMn1A5E7kqC7jk7w35c0NyQ,2314
|
10
10
|
checkpointer/storages/memory_storage.py,sha256=S5ayOZE_CyaFQJ-vSgObTanldPzG3gh3NksjNAc7vsk,1282
|
11
|
-
checkpointer/storages/pickle_storage.py,sha256=
|
11
|
+
checkpointer/storages/pickle_storage.py,sha256=idh9sBMdWuyvS220oa_7bAUpc9Xo9v6Ud9aYKGWasUs,1593
|
12
12
|
checkpointer/storages/storage.py,sha256=_m18Z8TKrdAbi6YYYQmuNOnhna4RB2sJDn1v3liaU3U,721
|
13
|
-
checkpointer-2.6.
|
14
|
-
checkpointer-2.6.
|
15
|
-
checkpointer-2.6.
|
16
|
-
checkpointer-2.6.
|
13
|
+
checkpointer-2.6.1.dist-info/METADATA,sha256=9RHScS2NKtNjtILIvcf5LEcjbA-BzvLyTN6L8WH_usE,10555
|
14
|
+
checkpointer-2.6.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
15
|
+
checkpointer-2.6.1.dist-info/licenses/LICENSE,sha256=9xVsdtv_-uSyY9Xl9yujwAPm4-mjcCLeVy-ljwXEWbo,1059
|
16
|
+
checkpointer-2.6.1.dist-info/RECORD,,
|
File without changes
|
File without changes
|