persistent-function-cache 0.1.0__tar.gz → 0.1.1__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 (39) hide show
  1. {persistent_function_cache-0.1.0/src/persistent_function_cache.egg-info → persistent_function_cache-0.1.1}/PKG-INFO +3 -3
  2. {persistent_function_cache-0.1.0 → persistent_function_cache-0.1.1}/README.md +1 -1
  3. {persistent_function_cache-0.1.0 → persistent_function_cache-0.1.1}/pyproject.toml +2 -4
  4. persistent_function_cache-0.1.1/src/persistent_cache/__init__.py +2 -0
  5. persistent_function_cache-0.1.1/src/persistent_cache/caches/deep_learning.py +18 -0
  6. persistent_function_cache-0.1.1/src/persistent_cache/caches/speedup_deep_learning.py +18 -0
  7. {persistent_function_cache-0.1.0 → persistent_function_cache-0.1.1}/src/persistent_cache/main/decorator.py +24 -5
  8. {persistent_function_cache-0.1.0 → persistent_function_cache-0.1.1}/src/persistent_cache/main/hashing.py +21 -10
  9. persistent_function_cache-0.1.1/src/persistent_cache/models/__init__.py +2 -0
  10. persistent_function_cache-0.1.1/src/persistent_cache/models/function.py +4 -0
  11. persistent_function_cache-0.1.1/src/persistent_cache/reducers/__init__.py +1 -0
  12. {persistent_function_cache-0.1.0 → persistent_function_cache-0.1.1}/src/persistent_cache/reducers/speedup_deep_learning.py +1 -1
  13. {persistent_function_cache-0.1.0 → persistent_function_cache-0.1.1/src/persistent_function_cache.egg-info}/PKG-INFO +3 -3
  14. {persistent_function_cache-0.1.0 → persistent_function_cache-0.1.1}/src/persistent_function_cache.egg-info/SOURCES.txt +3 -2
  15. persistent_function_cache-0.1.1/tests/test_cache.py +33 -0
  16. persistent_function_cache-0.1.1/tests/test_deep_learning_cache.py +34 -0
  17. persistent_function_cache-0.1.0/src/persistent_cache/__init__.py +0 -1
  18. persistent_function_cache-0.1.0/src/persistent_cache/caches/base.py +0 -4
  19. persistent_function_cache-0.1.0/src/persistent_cache/caches/deep_learning.py +0 -4
  20. persistent_function_cache-0.1.0/src/persistent_cache/caches/speedup_deep_learning.py +0 -4
  21. persistent_function_cache-0.1.0/src/persistent_cache/models/__init__.py +0 -1
  22. persistent_function_cache-0.1.0/src/persistent_cache/reducers/__init__.py +0 -0
  23. persistent_function_cache-0.1.0/tests/test_cache.py +0 -26
  24. {persistent_function_cache-0.1.0 → persistent_function_cache-0.1.1}/LICENSE +0 -0
  25. {persistent_function_cache-0.1.0 → persistent_function_cache-0.1.1}/setup.cfg +0 -0
  26. {persistent_function_cache-0.1.0 → persistent_function_cache-0.1.1}/src/persistent_cache/caches/__init__.py +0 -0
  27. {persistent_function_cache-0.1.0 → persistent_function_cache-0.1.1}/src/persistent_cache/cli/__init__.py +0 -0
  28. {persistent_function_cache-0.1.0 → persistent_function_cache-0.1.1}/src/persistent_cache/cli/clear_cache.py +0 -0
  29. {persistent_function_cache-0.1.0 → persistent_function_cache-0.1.1}/src/persistent_cache/main/__init__.py +0 -0
  30. {persistent_function_cache-0.1.0 → persistent_function_cache-0.1.1}/src/persistent_cache/main/cacheslot.py +0 -0
  31. {persistent_function_cache-0.1.0 → persistent_function_cache-0.1.1}/src/persistent_cache/models/path.py +0 -0
  32. {persistent_function_cache-0.1.0 → persistent_function_cache-0.1.1}/src/persistent_cache/py.typed +0 -0
  33. {persistent_function_cache-0.1.0 → persistent_function_cache-0.1.1}/src/persistent_cache/reducers/base.py +0 -0
  34. {persistent_function_cache-0.1.0 → persistent_function_cache-0.1.1}/src/persistent_cache/reducers/deep_learning.py +0 -0
  35. {persistent_function_cache-0.1.0 → persistent_function_cache-0.1.1}/src/persistent_function_cache.egg-info/dependency_links.txt +0 -0
  36. {persistent_function_cache-0.1.0 → persistent_function_cache-0.1.1}/src/persistent_function_cache.egg-info/entry_points.txt +0 -0
  37. {persistent_function_cache-0.1.0 → persistent_function_cache-0.1.1}/src/persistent_function_cache.egg-info/requires.txt +0 -0
  38. {persistent_function_cache-0.1.0 → persistent_function_cache-0.1.1}/src/persistent_function_cache.egg-info/top_level.txt +0 -0
  39. {persistent_function_cache-0.1.0 → persistent_function_cache-0.1.1}/tests/test_clear_cache.py +0 -0
@@ -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.1.1
4
4
  Summary: Persistent cache for expensive functions
5
5
  Author-email: Quinten Roets <qdr2104@columbia.edu>
6
6
  License: MIT
@@ -22,7 +22,7 @@ Requires-Dist: torch<3,>=1.26.0; extra == "dev"
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
@@ -3,7 +3,7 @@
3
3
  ![PyPI downloads](https://img.shields.io/pypi/dm/persistent-function-cache)
4
4
  ![Python version](https://img.shields.io/badge/python-3.10--3.12-brightgreen)
5
5
  ![Operating system](https://img.shields.io/badge/os-linux%20%7c%20macOS%20%7c%20windows-brightgreen)
6
- ![Coverage](https://img.shields.io/badge/coverage-88%25-brightgreen)
6
+ ![Coverage](https://img.shields.io/badge/coverage-100%25-brightgreen)
7
7
 
8
8
  ## Usage
9
9
  Use
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "persistent-function-cache"
3
- version = "0.1.0"
3
+ version = "0.1.1"
4
4
  description = "Persistent cache for expensive functions"
5
5
  authors = [{name = "Quinten Roets", email = "qdr2104@columbia.edu"}]
6
6
  license = {text = "MIT"}
@@ -35,7 +35,7 @@ command_line = "-m pytest tests"
35
35
 
36
36
  [tool.coverage.report]
37
37
  precision = 4
38
- fail_under = 80
38
+ fail_under = 100
39
39
 
40
40
  [tool.mypy]
41
41
  strict = true
@@ -52,8 +52,6 @@ fix = true
52
52
  [tool.ruff.lint]
53
53
  select = ["ALL"]
54
54
  ignore = [
55
- "ANN101", # annotate self
56
- "ANN102", # annotate cls
57
55
  "ANN401", # annotated with Any
58
56
  "D", # docstrings
59
57
  "G004", # logging f-string
@@ -0,0 +1,2 @@
1
+ from .caches import deep_learning, speedup_deep_learning
2
+ from .main.decorator import cache
@@ -0,0 +1,18 @@
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)
@@ -0,0 +1,18 @@
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,20 +1,37 @@
1
1
  from collections.abc import Callable
2
2
  from functools import wraps
3
- from typing import Any, TypeVar, cast
3
+ from typing import Any, cast, overload
4
4
 
5
- from persistent_cache.models import Path
5
+ from persistent_cache.models import F, Path
6
6
  from persistent_cache.reducers.base import Reducer
7
7
 
8
8
  from .cacheslot import CacheSlot
9
9
 
10
- T = TypeVar("T")
11
- F = TypeVar("F", bound=Callable[..., Any])
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]: ...
12
27
 
13
28
 
14
29
  def cache(
30
+ function: F | None = None,
31
+ *,
15
32
  key_reducer: type[Reducer] = Reducer,
16
33
  cache_path: Path = Path.cache,
17
- ) -> Callable[[F], F]:
34
+ ) -> F | Callable[[F], F]:
18
35
  """A decorator to cache function results. Decorated functions are only executed if
19
36
  result is not present in cache. The arguments of the function can be any nested
20
37
  complex object.
@@ -41,4 +58,6 @@ def cache(
41
58
 
42
59
  return cast(F, wrapped_function)
43
60
 
61
+ if function is not None:
62
+ cache_decorator = cache_decorator(function)
44
63
  return cache_decorator
@@ -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
@@ -0,0 +1,2 @@
1
+ from .function import F
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.1.1
4
4
  Summary: Persistent cache for expensive functions
5
5
  Author-email: Quinten Roets <qdr2104@columbia.edu>
6
6
  License: MIT
@@ -22,7 +22,7 @@ Requires-Dist: torch<3,>=1.26.0; extra == "dev"
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
@@ -4,7 +4,6 @@ pyproject.toml
4
4
  src/persistent_cache/__init__.py
5
5
  src/persistent_cache/py.typed
6
6
  src/persistent_cache/caches/__init__.py
7
- src/persistent_cache/caches/base.py
8
7
  src/persistent_cache/caches/deep_learning.py
9
8
  src/persistent_cache/caches/speedup_deep_learning.py
10
9
  src/persistent_cache/cli/__init__.py
@@ -14,6 +13,7 @@ src/persistent_cache/main/cacheslot.py
14
13
  src/persistent_cache/main/decorator.py
15
14
  src/persistent_cache/main/hashing.py
16
15
  src/persistent_cache/models/__init__.py
16
+ src/persistent_cache/models/function.py
17
17
  src/persistent_cache/models/path.py
18
18
  src/persistent_cache/reducers/__init__.py
19
19
  src/persistent_cache/reducers/base.py
@@ -26,4 +26,5 @@ src/persistent_function_cache.egg-info/entry_points.txt
26
26
  src/persistent_function_cache.egg-info/requires.txt
27
27
  src/persistent_function_cache.egg-info/top_level.txt
28
28
  tests/test_cache.py
29
- tests/test_clear_cache.py
29
+ tests/test_clear_cache.py
30
+ tests/test_deep_learning_cache.py
@@ -0,0 +1,33 @@
1
+ import io
2
+ import math
3
+ from collections.abc import Callable
4
+ from typing import Any
5
+
6
+ import cli
7
+ import pytest
8
+
9
+ from persistent_cache import cache, deep_learning, speedup_deep_learning
10
+
11
+ caches = [cache, deep_learning.cache, speedup_deep_learning.cache]
12
+
13
+
14
+ def calculate(*args: Any, **kwargs: Any) -> None:
15
+ cli.console.print("calculation started")
16
+ cli.console.print(args, kwargs)
17
+
18
+
19
+ def verify_cached_function(function: Callable[..., Any]) -> None:
20
+ with io.BytesIO() as fp:
21
+ function(fp, lambda x: x, math, {})
22
+
23
+
24
+ @pytest.mark.parametrize("cache_decorator", caches)
25
+ def test_cache_with_argument_combination(cache_decorator: Callable[..., Any]) -> None:
26
+ cached_function = cache_decorator(calculate)
27
+ verify_cached_function(cached_function)
28
+
29
+
30
+ @pytest.mark.parametrize("cache_decorator", caches)
31
+ def test_cache_as_function(cache_decorator: Callable[..., Any]) -> None:
32
+ cached_function = cache_decorator()(calculate)
33
+ verify_cached_function(cached_function)
@@ -0,0 +1,34 @@
1
+ from collections.abc import Callable
2
+ from typing import Any
3
+
4
+ import cli
5
+ import numpy as np
6
+ import pytest
7
+ import torch
8
+ from torch.utils.data import TensorDataset
9
+
10
+ from persistent_cache import deep_learning, speedup_deep_learning
11
+ from persistent_cache.reducers.speedup_deep_learning import LARGE_DIMENSION
12
+
13
+ caches = [deep_learning.cache, speedup_deep_learning.cache]
14
+
15
+
16
+ def calculate(*args: Any, **kwargs: Any) -> None:
17
+ cli.console.print("calculation started")
18
+ cli.console.print(args, kwargs)
19
+
20
+
21
+ def verify_cached_function(function: Callable[..., Any]) -> None:
22
+ array = np.zeros(10)
23
+ large_array = np.zeros((10, LARGE_DIMENSION))
24
+ tensor = torch.tensor(array)
25
+ module = torch.nn.Linear(10, 2)
26
+ dataset = TensorDataset(tensor)
27
+ labeled_dataset = TensorDataset(tensor, tensor)
28
+ function(array, tensor, module, dataset, large_array, labeled_dataset)
29
+
30
+
31
+ @pytest.mark.parametrize("cache_decorator", caches)
32
+ def test_cache_with_argument_combination(cache_decorator: Callable[..., Any]) -> None:
33
+ cached_function = cache_decorator(calculate)
34
+ verify_cached_function(cached_function)
@@ -1 +0,0 @@
1
- from .caches.base import cache
@@ -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,4 +0,0 @@
1
- from persistent_cache.main import decorator
2
- from persistent_cache.reducers.deep_learning import Reducer
3
-
4
- cache = decorator.cache(Reducer)
@@ -1,4 +0,0 @@
1
- from persistent_cache.main import decorator
2
- from persistent_cache.reducers.speedup_deep_learning import Reducer
3
-
4
- cache = decorator.cache(Reducer)
@@ -1 +0,0 @@
1
- from .path import Path
@@ -1,26 +0,0 @@
1
- import io
2
- import math
3
- from collections.abc import Callable
4
- from typing import Any, TypeVar
5
-
6
- import cli
7
- import pytest
8
-
9
- from persistent_cache.caches import base, deep_learning, speedup_deep_learning
10
-
11
- F = TypeVar("F", bound=Callable) # type: ignore[type-arg]
12
-
13
-
14
- def calculate(*args: Any, **kwargs: Any) -> None:
15
- cli.console.print("calculation started")
16
- cli.console.print(args, kwargs)
17
-
18
-
19
- caches = [base.cache, deep_learning.cache, speedup_deep_learning.cache]
20
-
21
-
22
- @pytest.mark.parametrize("cache", caches)
23
- def test_cache_with_argument_combination(cache: Callable) -> None: # type: ignore[type-arg]
24
- cached_function = cache(calculate)
25
- with io.BytesIO() as fp:
26
- cached_function(fp, lambda x: x, math, {})