persistent-function-cache 0.1.1__tar.gz → 0.2.0__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 (35) hide show
  1. {persistent_function_cache-0.1.1/src/persistent_function_cache.egg-info → persistent_function_cache-0.2.0}/PKG-INFO +1 -1
  2. {persistent_function_cache-0.1.1 → persistent_function_cache-0.2.0}/pyproject.toml +1 -1
  3. persistent_function_cache-0.2.0/src/persistent_cache/caches/deep_learning.py +5 -0
  4. persistent_function_cache-0.2.0/src/persistent_cache/caches/speedup_deep_learning.py +5 -0
  5. {persistent_function_cache-0.1.1 → persistent_function_cache-0.2.0}/src/persistent_cache/main/cacheslot.py +1 -2
  6. persistent_function_cache-0.2.0/src/persistent_cache/main/decorator.py +122 -0
  7. {persistent_function_cache-0.1.1 → persistent_function_cache-0.2.0/src/persistent_function_cache.egg-info}/PKG-INFO +1 -1
  8. {persistent_function_cache-0.1.1 → persistent_function_cache-0.2.0}/tests/test_cache.py +22 -0
  9. persistent_function_cache-0.1.1/src/persistent_cache/caches/deep_learning.py +0 -18
  10. persistent_function_cache-0.1.1/src/persistent_cache/caches/speedup_deep_learning.py +0 -18
  11. persistent_function_cache-0.1.1/src/persistent_cache/main/decorator.py +0 -63
  12. {persistent_function_cache-0.1.1 → persistent_function_cache-0.2.0}/LICENSE +0 -0
  13. {persistent_function_cache-0.1.1 → persistent_function_cache-0.2.0}/README.md +0 -0
  14. {persistent_function_cache-0.1.1 → persistent_function_cache-0.2.0}/setup.cfg +0 -0
  15. {persistent_function_cache-0.1.1 → persistent_function_cache-0.2.0}/src/persistent_cache/__init__.py +0 -0
  16. {persistent_function_cache-0.1.1 → persistent_function_cache-0.2.0}/src/persistent_cache/caches/__init__.py +0 -0
  17. {persistent_function_cache-0.1.1 → persistent_function_cache-0.2.0}/src/persistent_cache/cli/__init__.py +0 -0
  18. {persistent_function_cache-0.1.1 → persistent_function_cache-0.2.0}/src/persistent_cache/cli/clear_cache.py +0 -0
  19. {persistent_function_cache-0.1.1 → persistent_function_cache-0.2.0}/src/persistent_cache/main/__init__.py +0 -0
  20. {persistent_function_cache-0.1.1 → persistent_function_cache-0.2.0}/src/persistent_cache/main/hashing.py +0 -0
  21. {persistent_function_cache-0.1.1 → persistent_function_cache-0.2.0}/src/persistent_cache/models/__init__.py +0 -0
  22. {persistent_function_cache-0.1.1 → persistent_function_cache-0.2.0}/src/persistent_cache/models/function.py +0 -0
  23. {persistent_function_cache-0.1.1 → persistent_function_cache-0.2.0}/src/persistent_cache/models/path.py +0 -0
  24. {persistent_function_cache-0.1.1 → persistent_function_cache-0.2.0}/src/persistent_cache/py.typed +0 -0
  25. {persistent_function_cache-0.1.1 → persistent_function_cache-0.2.0}/src/persistent_cache/reducers/__init__.py +0 -0
  26. {persistent_function_cache-0.1.1 → persistent_function_cache-0.2.0}/src/persistent_cache/reducers/base.py +0 -0
  27. {persistent_function_cache-0.1.1 → persistent_function_cache-0.2.0}/src/persistent_cache/reducers/deep_learning.py +0 -0
  28. {persistent_function_cache-0.1.1 → persistent_function_cache-0.2.0}/src/persistent_cache/reducers/speedup_deep_learning.py +0 -0
  29. {persistent_function_cache-0.1.1 → persistent_function_cache-0.2.0}/src/persistent_function_cache.egg-info/SOURCES.txt +0 -0
  30. {persistent_function_cache-0.1.1 → persistent_function_cache-0.2.0}/src/persistent_function_cache.egg-info/dependency_links.txt +0 -0
  31. {persistent_function_cache-0.1.1 → persistent_function_cache-0.2.0}/src/persistent_function_cache.egg-info/entry_points.txt +0 -0
  32. {persistent_function_cache-0.1.1 → persistent_function_cache-0.2.0}/src/persistent_function_cache.egg-info/requires.txt +0 -0
  33. {persistent_function_cache-0.1.1 → persistent_function_cache-0.2.0}/src/persistent_function_cache.egg-info/top_level.txt +0 -0
  34. {persistent_function_cache-0.1.1 → persistent_function_cache-0.2.0}/tests/test_clear_cache.py +0 -0
  35. {persistent_function_cache-0.1.1 → persistent_function_cache-0.2.0}/tests/test_deep_learning_cache.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: persistent-function-cache
3
- Version: 0.1.1
3
+ Version: 0.2.0
4
4
  Summary: Persistent cache for expensive functions
5
5
  Author-email: Quinten Roets <qdr2104@columbia.edu>
6
6
  License: MIT
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "persistent-function-cache"
3
- version = "0.1.1"
3
+ version = "0.2.0"
4
4
  description = "Persistent cache for expensive functions"
5
5
  authors = [{name = "Quinten Roets", email = "qdr2104@columbia.edu"}]
6
6
  license = {text = "MIT"}
@@ -0,0 +1,5 @@
1
+ import functools
2
+
3
+ from persistent_cache.main import decorator
4
+
5
+ cache = functools.partial(decorator.cache, deep_learning=True)
@@ -0,0 +1,5 @@
1
+ import functools
2
+
3
+ from persistent_cache.main import decorator
4
+
5
+ cache = functools.partial(decorator.cache, speedup_deep_learning=True)
@@ -15,12 +15,11 @@ class CacheSlot(Generic[T]):
15
15
  self,
16
16
  function: Callable[..., T],
17
17
  args: tuple[Any, ...],
18
- kwargs: Any,
19
18
  key_reducer: type[Reducer] = Reducer,
20
19
  cache_path: Path = Path.cache,
21
20
  ) -> None:
22
21
  # change cache key when implementation changes
23
- cache_keys = (function, args, kwargs)
22
+ cache_keys = (function, args)
24
23
  self.location = (
25
24
  cache_path
26
25
  / function.__module__.replace(".", "_")
@@ -0,0 +1,122 @@
1
+ import inspect
2
+ from collections.abc import Callable, Iterator
3
+ from functools import wraps
4
+ from typing import Any, cast, overload
5
+
6
+ from persistent_cache.models import F, Path
7
+ from persistent_cache.reducers.base import Reducer
8
+
9
+ from .cacheslot import CacheSlot
10
+
11
+
12
+ @overload
13
+ def cache(
14
+ function: F,
15
+ *,
16
+ cache_path: Path = Path.cache,
17
+ cache_key_arguments: tuple[str, ...] | str | None = None,
18
+ key_reducer: type[Reducer] = Reducer,
19
+ deep_learning: bool = False,
20
+ speedup_deep_learning: bool = False,
21
+ ) -> F: ...
22
+
23
+
24
+ @overload
25
+ def cache(
26
+ function: None = None,
27
+ *,
28
+ cache_path: Path = Path.cache,
29
+ cache_key_arguments: tuple[str, ...] | str | None = None,
30
+ key_reducer: type[Reducer] = Reducer,
31
+ deep_learning: bool = False,
32
+ speedup_deep_learning: bool = False,
33
+ ) -> Callable[[F], F]: ...
34
+
35
+
36
+ def cache( # noqa: PLR0913
37
+ function: F | None = None,
38
+ *,
39
+ cache_path: Path = Path.cache,
40
+ cache_key_arguments: tuple[str, ...] | str | None = None,
41
+ key_reducer: type[Reducer] | None = None,
42
+ deep_learning: bool = False,
43
+ speedup_deep_learning: bool = False,
44
+ ) -> F | Callable[[F], F]:
45
+ """A decorator to cache function results. Decorated functions are only executed if
46
+ result is not present in cache. The arguments of the function can be any nested
47
+ complex object.
48
+
49
+ Use as:
50
+
51
+ from persistent_cache import cache
52
+
53
+ @cache
54
+ def long_function(complex_object):
55
+ ...
56
+ """
57
+
58
+ reducer = extract_reducer(
59
+ key_reducer,
60
+ deep_learning=deep_learning,
61
+ speedup_deep_learning=speedup_deep_learning,
62
+ )
63
+
64
+ def cache_decorator(function: F) -> F:
65
+ @wraps(function)
66
+ def wrapped_function(*args: Any, **kwargs: Any) -> Any:
67
+ arguments = tuple(
68
+ extract_argument_values(function, args, kwargs, cache_key_arguments),
69
+ )
70
+ cache_slot = CacheSlot(function, arguments, reducer, cache_path)
71
+ try:
72
+ value = cache_slot.value
73
+ except KeyError:
74
+ value = function(*args, **kwargs)
75
+ cache_slot.value = value
76
+ return value
77
+
78
+ return cast(F, wrapped_function)
79
+
80
+ if function is not None:
81
+ cache_decorator = cache_decorator(function)
82
+ return cache_decorator
83
+
84
+
85
+ def extract_argument_values(
86
+ function: F,
87
+ args: tuple[Any, ...],
88
+ kwargs: dict[str, Any],
89
+ cache_key_arguments: tuple[str, ...] | str | None = None,
90
+ ) -> Iterator[Any]:
91
+ if cache_key_arguments is None:
92
+ yield from (args, kwargs)
93
+ else:
94
+ arguments = inspect.signature(function).bind(*args, **kwargs)
95
+ arguments.apply_defaults()
96
+ if isinstance(cache_key_arguments, str):
97
+ yield arguments.arguments.get(cache_key_arguments)
98
+ else:
99
+ for name in cache_key_arguments:
100
+ yield arguments.arguments.get(name)
101
+
102
+
103
+ def extract_reducer(
104
+ reducer: type[Reducer] | None,
105
+ *,
106
+ deep_learning: bool,
107
+ speedup_deep_learning: bool,
108
+ ) -> type[Reducer]:
109
+ if reducer is None:
110
+ if deep_learning:
111
+ from persistent_cache.reducers.deep_learning import Reducer as Reducer_
112
+
113
+ reducer = Reducer_
114
+ elif speedup_deep_learning:
115
+ from persistent_cache.reducers.speedup_deep_learning import (
116
+ Reducer as Reducer_,
117
+ )
118
+
119
+ reducer = Reducer_
120
+ else:
121
+ reducer = Reducer
122
+ return reducer
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: persistent-function-cache
3
- Version: 0.1.1
3
+ Version: 0.2.0
4
4
  Summary: Persistent cache for expensive functions
5
5
  Author-email: Quinten Roets <qdr2104@columbia.edu>
6
6
  License: MIT
@@ -11,6 +11,10 @@ from persistent_cache import cache, deep_learning, speedup_deep_learning
11
11
  caches = [cache, deep_learning.cache, speedup_deep_learning.cache]
12
12
 
13
13
 
14
+ def calculate_with_name(value: str) -> None:
15
+ cli.console.print(value)
16
+
17
+
14
18
  def calculate(*args: Any, **kwargs: Any) -> None:
15
19
  cli.console.print("calculation started")
16
20
  cli.console.print(args, kwargs)
@@ -31,3 +35,21 @@ def test_cache_with_argument_combination(cache_decorator: Callable[..., Any]) ->
31
35
  def test_cache_as_function(cache_decorator: Callable[..., Any]) -> None:
32
36
  cached_function = cache_decorator()(calculate)
33
37
  verify_cached_function(cached_function)
38
+
39
+
40
+ @pytest.mark.parametrize("cache_decorator", caches)
41
+ def test_cache_with_argument_name(
42
+ cache_decorator: Callable[..., Any],
43
+ ) -> None:
44
+ cached_function = cache_decorator(calculate_with_name, cache_key_arguments="value")
45
+ cached_function("test")
46
+
47
+
48
+ @pytest.mark.parametrize("cache_decorator", caches)
49
+ def test_cache_with_argument_names(cache_decorator: Callable[..., Any]) -> None:
50
+ cache_key_arguments = ("value",)
51
+ cached_function = cache_decorator(
52
+ calculate_with_name,
53
+ cache_key_arguments=cache_key_arguments,
54
+ )
55
+ cached_function("test")
@@ -1,18 +0,0 @@
1
- from collections.abc import Callable
2
-
3
- from persistent_cache.main import decorator
4
- from persistent_cache.models import F, Path
5
- from persistent_cache.reducers import Reducer
6
-
7
-
8
- def cache(
9
- function: F | None = None,
10
- *,
11
- key_reducer: type[Reducer] | None = None,
12
- cache_path: Path = Path.cache,
13
- ) -> Callable[[F], F]:
14
- if key_reducer is None:
15
- from persistent_cache.reducers import deep_learning
16
-
17
- key_reducer = deep_learning.Reducer
18
- return decorator.cache(function, key_reducer=key_reducer, cache_path=cache_path)
@@ -1,18 +0,0 @@
1
- from collections.abc import Callable
2
-
3
- from persistent_cache.main import decorator
4
- from persistent_cache.models import F, Path
5
- from persistent_cache.reducers import Reducer
6
-
7
-
8
- def cache(
9
- function: F | None = None,
10
- *,
11
- key_reducer: type[Reducer] | None = None,
12
- cache_path: Path = Path.cache,
13
- ) -> Callable[[F], F]:
14
- if key_reducer is None:
15
- from persistent_cache.reducers import speedup_deep_learning
16
-
17
- key_reducer = speedup_deep_learning.Reducer
18
- return decorator.cache(function, key_reducer=key_reducer, cache_path=cache_path)
@@ -1,63 +0,0 @@
1
- from collections.abc import Callable
2
- from functools import wraps
3
- from typing import Any, cast, overload
4
-
5
- from persistent_cache.models import F, Path
6
- from persistent_cache.reducers.base import Reducer
7
-
8
- from .cacheslot import CacheSlot
9
-
10
-
11
- @overload
12
- def cache(
13
- function: F,
14
- *,
15
- key_reducer: type[Reducer] = Reducer,
16
- cache_path: Path = Path.cache,
17
- ) -> F: ...
18
-
19
-
20
- @overload
21
- def cache(
22
- function: None = None,
23
- *,
24
- key_reducer: type[Reducer] = Reducer,
25
- cache_path: Path = Path.cache,
26
- ) -> Callable[[F], F]: ...
27
-
28
-
29
- def cache(
30
- function: F | None = None,
31
- *,
32
- key_reducer: type[Reducer] = Reducer,
33
- cache_path: Path = Path.cache,
34
- ) -> F | Callable[[F], F]:
35
- """A decorator to cache function results. Decorated functions are only executed if
36
- result is not present in cache. The arguments of the function can be any nested
37
- complex object.
38
-
39
- Use as:
40
-
41
- from persistent_cache import cache
42
-
43
- @cache
44
- def long_function(complex_object):
45
- ...
46
- """
47
-
48
- def cache_decorator(function: F) -> F:
49
- @wraps(function)
50
- def wrapped_function(*args: Any, **kwargs: Any) -> Any:
51
- cache_slot = CacheSlot(function, args, kwargs, key_reducer, cache_path)
52
- try:
53
- value = cache_slot.value
54
- except KeyError:
55
- value = function(*args, **kwargs)
56
- cache_slot.value = value
57
- return value
58
-
59
- return cast(F, wrapped_function)
60
-
61
- if function is not None:
62
- cache_decorator = cache_decorator(function)
63
- return cache_decorator