persistent-function-cache 0.1.0__py3-none-any.whl → 0.2.0__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.
@@ -1 +1,2 @@
1
- from .caches.base import cache
1
+ from .caches import deep_learning, speedup_deep_learning
2
+ from .main.decorator import cache
@@ -1,4 +1,5 @@
1
+ import functools
2
+
1
3
  from persistent_cache.main import decorator
2
- from persistent_cache.reducers.deep_learning import Reducer
3
4
 
4
- cache = decorator.cache(Reducer)
5
+ cache = functools.partial(decorator.cache, deep_learning=True)
@@ -1,4 +1,5 @@
1
+ import functools
2
+
1
3
  from persistent_cache.main import decorator
2
- from persistent_cache.reducers.speedup_deep_learning import Reducer
3
4
 
4
- cache = decorator.cache(Reducer)
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(".", "_")
@@ -1,20 +1,47 @@
1
- from collections.abc import Callable
1
+ import inspect
2
+ from collections.abc import Callable, Iterator
2
3
  from functools import wraps
3
- from typing import Any, TypeVar, cast
4
+ from typing import Any, cast, overload
4
5
 
5
- from persistent_cache.models import Path
6
+ from persistent_cache.models import F, Path
6
7
  from persistent_cache.reducers.base import Reducer
7
8
 
8
9
  from .cacheslot import CacheSlot
9
10
 
10
- T = TypeVar("T")
11
- F = TypeVar("F", bound=Callable[..., Any])
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: ...
12
22
 
13
23
 
24
+ @overload
14
25
  def cache(
26
+ function: None = None,
27
+ *,
28
+ cache_path: Path = Path.cache,
29
+ cache_key_arguments: tuple[str, ...] | str | None = None,
15
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
+ *,
16
39
  cache_path: Path = Path.cache,
17
- ) -> Callable[[F], F]:
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]:
18
45
  """A decorator to cache function results. Decorated functions are only executed if
19
46
  result is not present in cache. The arguments of the function can be any nested
20
47
  complex object.
@@ -28,10 +55,19 @@ def cache(
28
55
  ...
29
56
  """
30
57
 
58
+ reducer = extract_reducer(
59
+ key_reducer,
60
+ deep_learning=deep_learning,
61
+ speedup_deep_learning=speedup_deep_learning,
62
+ )
63
+
31
64
  def cache_decorator(function: F) -> F:
32
65
  @wraps(function)
33
66
  def wrapped_function(*args: Any, **kwargs: Any) -> Any:
34
- cache_slot = CacheSlot(function, args, kwargs, key_reducer, cache_path)
67
+ arguments = tuple(
68
+ extract_argument_values(function, args, kwargs, cache_key_arguments),
69
+ )
70
+ cache_slot = CacheSlot(function, arguments, reducer, cache_path)
35
71
  try:
36
72
  value = cache_slot.value
37
73
  except KeyError:
@@ -41,4 +77,46 @@ def cache(
41
77
 
42
78
  return cast(F, wrapped_function)
43
79
 
80
+ if function is not None:
81
+ cache_decorator = cache_decorator(function)
44
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
@@ -4,13 +4,28 @@ import hashlib
4
4
  import inspect
5
5
  import io
6
6
  import pickle
7
- from typing import TYPE_CHECKING, Any, get_args, get_type_hints
7
+ from types import UnionType
8
+ from typing import TYPE_CHECKING, Any, get_args, get_origin, get_type_hints
8
9
 
9
10
  from persistent_cache.reducers.base import Reducer
10
11
 
11
12
  if TYPE_CHECKING:
12
- from collections.abc import Callable, Iterator
13
- from typing import BinaryIO
13
+ from collections.abc import Callable, Iterator # pragma: nocover
14
+ from typing import BinaryIO # pragma: nocover
15
+
16
+
17
+ def extract_types(method: Callable[[Any], Any]) -> Iterator[type]:
18
+ type_hints = get_type_hints(method).values()
19
+ if type_hints:
20
+ argument_type = next(iter(type_hints))
21
+ origin = get_origin(argument_type)
22
+ arguments = get_args(argument_type)
23
+ if origin is UnionType:
24
+ yield from arguments
25
+ elif origin is not None:
26
+ yield origin
27
+ else:
28
+ yield argument_type
14
29
 
15
30
 
16
31
  class HashPickler(pickle.Pickler):
@@ -23,13 +38,9 @@ class HashPickler(pickle.Pickler):
23
38
  self.reducer = reducer
24
39
  self.reducers = {}
25
40
  for _, method in inspect.getmembers(reducer, predicate=inspect.ismethod):
26
- type_hints = get_type_hints(method).values()
27
- if type_hints:
28
- argument_type = next(iter(type_hints))
29
- argument_types = get_args(argument_type) or (argument_type,)
30
- for argument_type in argument_types:
31
- self.reducers[argument_type] = method
32
- self.reducers.pop(Any, None)
41
+ argument_types = extract_types(method)
42
+ for argument_type in argument_types:
43
+ self.reducers[argument_type] = method
33
44
 
34
45
  def reducer_override(self, obj: Any) -> Any:
35
46
  """The goal of this pickler is to create hashes of complex objects, not to
@@ -1 +1,2 @@
1
+ from .function import F
1
2
  from .path import Path
@@ -0,0 +1,4 @@
1
+ from collections.abc import Callable
2
+ from typing import Any, TypeVar
3
+
4
+ F = TypeVar("F", bound=Callable[..., Any])
@@ -0,0 +1 @@
1
+ from .base import Reducer
@@ -51,7 +51,7 @@ class Reducer(deep_learning.Reducer):
51
51
 
52
52
  # only use part of dataset for speedup
53
53
  data = dataset[13**17 % length] if length > 0 else []
54
- if isinstance(data, tuple):
54
+ if isinstance(data, tuple) and len(data) == 2: # noqa: PLR2004
55
55
  data, label = data
56
56
  else:
57
57
  label = None
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: persistent-function-cache
3
- Version: 0.1.0
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
@@ -8,21 +8,21 @@ Project-URL: Source Code, https://github.com/quintenroets/persistent-cache
8
8
  Requires-Python: <3.13,>=3.10
9
9
  Description-Content-Type: text/markdown
10
10
  License-File: LICENSE
11
- Requires-Dist: package-utils <1,>=0.6.7
12
- Requires-Dist: powercli <1,>=0.3.2
13
- Requires-Dist: superpathlib <3,>=2.0.9
11
+ Requires-Dist: package-utils<1,>=0.6.7
12
+ Requires-Dist: powercli<1,>=0.3.2
13
+ Requires-Dist: superpathlib<3,>=2.0.9
14
14
  Provides-Extra: dev
15
- Requires-Dist: package-dev-tools <1,>=0.5.11 ; extra == 'dev'
16
- Requires-Dist: package-dev-utils <1,>=0.1.6 ; extra == 'dev'
17
- Requires-Dist: numpy <3,>=1.26.0 ; extra == 'dev'
18
- Requires-Dist: torch <3,>=1.26.0 ; extra == 'dev'
15
+ Requires-Dist: package-dev-tools<1,>=0.5.11; extra == "dev"
16
+ Requires-Dist: package-dev-utils<1,>=0.1.6; extra == "dev"
17
+ Requires-Dist: numpy<3,>=1.26.0; extra == "dev"
18
+ Requires-Dist: torch<3,>=1.26.0; extra == "dev"
19
19
 
20
20
  # Cache
21
21
  [![PyPI version](https://badge.fury.io/py/persistent-function-cache.svg)](https://badge.fury.io/py/persistent-function-cache)
22
22
  ![PyPI downloads](https://img.shields.io/pypi/dm/persistent-function-cache)
23
23
  ![Python version](https://img.shields.io/badge/python-3.10--3.12-brightgreen)
24
24
  ![Operating system](https://img.shields.io/badge/os-linux%20%7c%20macOS%20%7c%20windows-brightgreen)
25
- ![Coverage](https://img.shields.io/badge/coverage-88%25-brightgreen)
25
+ ![Coverage](https://img.shields.io/badge/coverage-100%25-brightgreen)
26
26
 
27
27
  ## Usage
28
28
  Use
@@ -0,0 +1,24 @@
1
+ persistent_cache/__init__.py,sha256=VUq2BaLpsu66LXVBmRSBHGspctti2qavBqJNyja2yf8,91
2
+ persistent_cache/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
+ persistent_cache/caches/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
+ persistent_cache/caches/deep_learning.py,sha256=tJQrRJK2Sbv7tIGwnrnFAn8nP-Fh7ZgugocKcXeiMnU,126
5
+ persistent_cache/caches/speedup_deep_learning.py,sha256=bywNXeEZsg8Rs2A1_w-ZrJi9Ew2TvNCz59YryGyV0NI,134
6
+ persistent_cache/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
+ persistent_cache/cli/clear_cache.py,sha256=YbKfqzUB9IyEpU-2n0h5BrK9kZKjbayqiMTzjPbDl3s,1541
8
+ persistent_cache/main/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
+ persistent_cache/main/cacheslot.py,sha256=6jNF6B1aEW185aPJ7Wd7tzLIOcwqyNr2p9tkxUHhk5E,1217
10
+ persistent_cache/main/decorator.py,sha256=ojMDckrv5Fwhh8RvUCeZwQl06I1Q61olvs1HSz-jtVY,3457
11
+ persistent_cache/main/hashing.py,sha256=YP_HO9nJe2_ZkiQf-unM6W9y_k5TJW1JvWeZfPIXtug,2650
12
+ persistent_cache/models/__init__.py,sha256=No2WagrzFJdeQE3hTIeFd2H8hhvvAFcdVH6z07D1vmI,47
13
+ persistent_cache/models/function.py,sha256=C1w0rVOhUkqvpPkXNj85rc4GSJDqT0oIZLsZvhVwn58,113
14
+ persistent_cache/models/path.py,sha256=-HRJ4yqqmBPlax4H0KS8guhndBXNwCnl7WZXhtaWmGQ,441
15
+ persistent_cache/reducers/__init__.py,sha256=hCozFuvrAb_gXLcqMMq92v4KdwBbQugwGwCmyLGt5RE,26
16
+ persistent_cache/reducers/base.py,sha256=HsodcuE8Id5oV93_b_RN18I69UWsJ21yazXCwT1f6YU,1428
17
+ persistent_cache/reducers/deep_learning.py,sha256=cyVolwmwm_ZN2gRxPtfJFqiNQlNuq_CrehO7ZSVWeVw,800
18
+ persistent_cache/reducers/speedup_deep_learning.py,sha256=kMkr1467zUsQUPOi_N8tWKWAtKUcFgsk3rh94QhETg0,1970
19
+ persistent_function_cache-0.2.0.dist-info/LICENSE,sha256=ENpNaBSvIV7ifD7iNz_-lBhImbiYowqPzBc5V5R8IhM,1070
20
+ persistent_function_cache-0.2.0.dist-info/METADATA,sha256=thXWcG0Xy3rs1wV86vs7GcRcIYL8c_zAdwLitFoknNs,2164
21
+ persistent_function_cache-0.2.0.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
22
+ persistent_function_cache-0.2.0.dist-info/entry_points.txt,sha256=fSZfuL6Wn42mZldojgGyg7dzSPCRVAuZox3w6dLd2ZI,88
23
+ persistent_function_cache-0.2.0.dist-info/top_level.txt,sha256=Jj-Z9wxHRlRyDUxrfC9GeaV5-8hAf8R4LclQFZesxi8,17
24
+ persistent_function_cache-0.2.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.2.0)
2
+ Generator: setuptools (75.8.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,4 +0,0 @@
1
- from persistent_cache.main import decorator
2
- from persistent_cache.reducers.base import Reducer
3
-
4
- cache = decorator.cache(Reducer)
@@ -1,24 +0,0 @@
1
- persistent_cache/__init__.py,sha256=_FBWL489shwwqfZXVPYVEL5kflvjp7R5vjpsfOOWu-M,31
2
- persistent_cache/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
- persistent_cache/caches/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
- persistent_cache/caches/base.py,sha256=En-iJjKx4qdVaLJdFholxLvSDtemnOMWGmBblS4cPak,129
5
- persistent_cache/caches/deep_learning.py,sha256=IcQ0JgtRt-Ke3XMplzn5W5rfjMx6l3fEmF4xxfQYzYQ,138
6
- persistent_cache/caches/speedup_deep_learning.py,sha256=qJzFMkSJh08jbyKjzhwC1aeLxvEekhSOB-tTicn7arY,146
7
- persistent_cache/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
- persistent_cache/cli/clear_cache.py,sha256=YbKfqzUB9IyEpU-2n0h5BrK9kZKjbayqiMTzjPbDl3s,1541
9
- persistent_cache/main/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
- persistent_cache/main/cacheslot.py,sha256=XIobyDDtMx1KpVxcz9dKo6-QEsFmK9Xej5j6dFieXk4,1246
11
- persistent_cache/main/decorator.py,sha256=wzyqdcjAL-dnMAaDO7qWGUg0glSfdM0a2INEwmRV8ak,1209
12
- persistent_cache/main/hashing.py,sha256=XrWahhJ0XTzo7tPMz5Tr1mGUF7pDTqRLV10aiALs5pc,2342
13
- persistent_cache/models/__init__.py,sha256=1OeLZ6FZ5gAjlerAjc69Vx0AqWLSx6OSqNCpuzkCZQg,23
14
- persistent_cache/models/path.py,sha256=-HRJ4yqqmBPlax4H0KS8guhndBXNwCnl7WZXhtaWmGQ,441
15
- persistent_cache/reducers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
- persistent_cache/reducers/base.py,sha256=HsodcuE8Id5oV93_b_RN18I69UWsJ21yazXCwT1f6YU,1428
17
- persistent_cache/reducers/deep_learning.py,sha256=cyVolwmwm_ZN2gRxPtfJFqiNQlNuq_CrehO7ZSVWeVw,800
18
- persistent_cache/reducers/speedup_deep_learning.py,sha256=CJBW92UvAOdZcWXBRN8NPp5DbDzeRTJ9-Yri6RsoTx8,1934
19
- persistent_function_cache-0.1.0.dist-info/LICENSE,sha256=ENpNaBSvIV7ifD7iNz_-lBhImbiYowqPzBc5V5R8IhM,1070
20
- persistent_function_cache-0.1.0.dist-info/METADATA,sha256=6LshL16QqQ1S-DNk52BUhHXpIdFWdqSmIpiO-ZeWNRI,2174
21
- persistent_function_cache-0.1.0.dist-info/WHEEL,sha256=OVMc5UfuAQiSplgO0_WdW7vXVGAt9Hdd6qtN4HotdyA,91
22
- persistent_function_cache-0.1.0.dist-info/entry_points.txt,sha256=fSZfuL6Wn42mZldojgGyg7dzSPCRVAuZox3w6dLd2ZI,88
23
- persistent_function_cache-0.1.0.dist-info/top_level.txt,sha256=Jj-Z9wxHRlRyDUxrfC9GeaV5-8hAf8R4LclQFZesxi8,17
24
- persistent_function_cache-0.1.0.dist-info/RECORD,,