cachify 0.2.1__py3-none-any.whl → 0.3.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.
cachify/__init__.py CHANGED
@@ -12,12 +12,13 @@ rcache = redis_cache
12
12
 
13
13
  __all__ = [
14
14
  "__version__",
15
- "cache",
16
15
  "rcache",
17
- "redis_cache",
18
- "setup_redis_config",
16
+ "clear_never_die_registry",
17
+ "cache",
18
+ "DEFAULT_KEY_PREFIX",
19
19
  "get_redis_config",
20
20
  "reset_redis_config",
21
- "DEFAULT_KEY_PREFIX",
21
+ "setup_redis_config",
22
+ "redis_cache",
22
23
  "CacheKwargs",
23
24
  ]
cachify/cache.py CHANGED
@@ -1,6 +1,6 @@
1
1
  import functools
2
2
  import inspect
3
- from typing import Any, Callable, cast
3
+ from typing import Any, Callable, Sequence, cast
4
4
 
5
5
  from cachify.features.never_die import register_never_die_function
6
6
  from cachify.types import CacheConfig, CacheKeyFunction, F, Number
@@ -73,7 +73,8 @@ def base_cache(
73
73
  ttl: Number,
74
74
  never_die: bool,
75
75
  cache_key_func: CacheKeyFunction | None,
76
- ignore_fields: tuple[str, ...],
76
+ ignore_fields: Sequence[str],
77
+ no_self: bool,
77
78
  config: CacheConfig,
78
79
  ) -> Callable[[F], F]:
79
80
  """
@@ -83,7 +84,8 @@ def base_cache(
83
84
  ttl: Time to live for cached items in seconds
84
85
  never_die: If True, the cache will never expire and will be recalculated based on the ttl
85
86
  cache_key_func: Custom cache key function, used for more complex cache scenarios
86
- ignore_fields: Tuple of strings with the function params to ignore when creating the cache key
87
+ ignore_fields: Sequence of strings with the function params to ignore when creating the cache key
88
+ no_self: if True, the first parameter (typically 'self' for methods) will be ignored when creating the cache key
87
89
  config: Cache configuration specifying storage, locks, and never_die registration
88
90
 
89
91
  Features:
@@ -91,17 +93,23 @@ def base_cache(
91
93
  - Only allows one execution at a time per function+args
92
94
  - Makes subsequent calls wait for the first call to complete
93
95
  """
94
- if cache_key_func and ignore_fields:
96
+
97
+ if cache_key_func and (ignore_fields or no_self):
95
98
  raise ValueError("Either cache_key_func or ignore_fields can be provided, but not both")
96
99
 
97
100
  def decorator(function: F) -> F:
101
+ ignore = tuple(ignore_fields)
102
+
103
+ if no_self:
104
+ ignore += function.__code__.co_varnames[:1]
105
+
98
106
  if inspect.iscoroutinefunction(function):
99
107
  return _async_decorator(
100
108
  function=function,
101
109
  ttl=ttl,
102
110
  never_die=never_die,
103
111
  cache_key_func=cache_key_func,
104
- ignore_fields=ignore_fields,
112
+ ignore_fields=ignore,
105
113
  config=config,
106
114
  )
107
115
  return _sync_decorator(
@@ -109,7 +117,7 @@ def base_cache(
109
117
  ttl=ttl,
110
118
  never_die=never_die,
111
119
  cache_key_func=cache_key_func,
112
- ignore_fields=ignore_fields,
120
+ ignore_fields=ignore,
113
121
  config=config,
114
122
  )
115
123
 
@@ -140,19 +140,19 @@ def _refresh_never_die_caches():
140
140
 
141
141
  if entry.loop.is_closed():
142
142
  logger.debug(
143
- f"Loop is closed, skipping future creation",
143
+ "Loop is closed, skipping future creation",
144
144
  extra={"function": entry.function.__qualname__},
145
145
  exc_info=True,
146
146
  )
147
147
  continue
148
148
 
149
+ coroutine = _run_async_function_and_cache(entry)
149
150
  try:
150
- coroutine = _run_async_function_and_cache(entry)
151
151
  future = asyncio.run_coroutine_threadsafe(coroutine, entry.loop)
152
152
  except RuntimeError:
153
153
  coroutine.close()
154
154
  logger.debug(
155
- f"Loop is closed, skipping future creation",
155
+ "Loop is closed, skipping future creation",
156
156
  extra={"function": entry.function.__qualname__},
157
157
  exc_info=True,
158
158
  )
cachify/memory_cache.py CHANGED
@@ -1,18 +1,22 @@
1
+ import asyncio
1
2
  import threading
2
- from typing import Callable
3
+ from collections import defaultdict
4
+ from typing import Callable, Sequence
3
5
 
4
6
  from cachify.cache import base_cache
5
7
  from cachify.storage.memory_storage import MemoryStorage
6
8
  from cachify.types import CacheConfig, CacheKeyFunction, F, Number
7
- from cachify.utils.locks import ASYNC_LOCKS, SYNC_LOCKS
8
9
 
9
10
  _CACHE_CLEAR_THREAD: threading.Thread | None = None
10
11
  _CACHE_CLEAR_LOCK: threading.Lock = threading.Lock()
11
12
 
13
+ _ASYNC_LOCKS: defaultdict[str, asyncio.Lock] = defaultdict(asyncio.Lock)
14
+ _SYNC_LOCKS: defaultdict[str, threading.Lock] = defaultdict(threading.Lock)
15
+
12
16
  _MEMORY_CONFIG = CacheConfig(
13
17
  storage=MemoryStorage,
14
- sync_lock=lambda cache_key: SYNC_LOCKS[cache_key],
15
- async_lock=lambda cache_key: ASYNC_LOCKS[cache_key],
18
+ sync_lock=_SYNC_LOCKS.__getitem__,
19
+ async_lock=_ASYNC_LOCKS.__getitem__,
16
20
  )
17
21
 
18
22
 
@@ -30,8 +34,9 @@ def cache(
30
34
  ttl: Number = 300,
31
35
  never_die: bool = False,
32
36
  cache_key_func: CacheKeyFunction | None = None,
33
- ignore_fields: tuple[str, ...] = (),
37
+ ignore_fields: Sequence[str] = (),
38
+ no_self: bool = False,
34
39
  ) -> Callable[[F], F]:
35
40
  """In-memory cache decorator. See `base_cache` for full documentation."""
36
41
  _start_cache_clear_thread()
37
- return base_cache(ttl, never_die, cache_key_func, ignore_fields, _MEMORY_CONFIG)
42
+ return base_cache(ttl, never_die, cache_key_func, ignore_fields, no_self, _MEMORY_CONFIG)
cachify/redis/config.py CHANGED
@@ -1,15 +1,20 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from dataclasses import dataclass
4
- from typing import TYPE_CHECKING, Literal, get_args, overload
4
+ from typing import TYPE_CHECKING, Literal, TypeAlias, get_args, overload
5
5
 
6
6
  if TYPE_CHECKING:
7
7
  from redis import Redis
8
8
  from redis.asyncio import Redis as AsyncRedis
9
+ from redis.cluster import RedisCluster
10
+ from redis.asyncio.cluster import RedisCluster as AsyncRedisCluster
11
+
12
+ SyncRedisClient: TypeAlias = "Redis | RedisCluster"
13
+ AsyncRedisClient: TypeAlias = "AsyncRedis | AsyncRedisCluster"
9
14
 
10
15
  OnErrorType = Literal["silent", "raise"]
11
16
 
12
- DEFAULT_KEY_PREFIX = "cachify"
17
+ DEFAULT_KEY_PREFIX = "{cachify}"
13
18
  DEFAULT_LOCK_TIMEOUT = 10
14
19
 
15
20
 
@@ -17,19 +22,19 @@ DEFAULT_LOCK_TIMEOUT = 10
17
22
  class RedisConfig:
18
23
  """Configuration for Redis cache backend."""
19
24
 
20
- sync_client: Redis | None
21
- async_client: AsyncRedis | None
25
+ sync_client: SyncRedisClient | None
26
+ async_client: AsyncRedisClient | None
22
27
  key_prefix: str
23
28
  lock_timeout: int
24
29
  on_error: OnErrorType
25
30
 
26
31
  @overload
27
- def get_client(self, is_async: Literal[True]) -> AsyncRedis: ...
32
+ def get_client(self, is_async: Literal[True]) -> AsyncRedisClient: ...
28
33
 
29
34
  @overload
30
- def get_client(self, is_async: Literal[False]) -> Redis: ...
35
+ def get_client(self, is_async: Literal[False]) -> SyncRedisClient: ...
31
36
 
32
- def get_client(self, is_async: bool) -> Redis | AsyncRedis:
37
+ def get_client(self, is_async: bool) -> SyncRedisClient | AsyncRedisClient:
33
38
  """Get the appropriate Redis client based on is_async flag."""
34
39
  if is_async:
35
40
  client = self.async_client
@@ -49,8 +54,8 @@ _redis_config: RedisConfig | None = None
49
54
 
50
55
 
51
56
  def setup_redis_config(
52
- sync_client: Redis | None = None,
53
- async_client: AsyncRedis | None = None,
57
+ sync_client: SyncRedisClient | None = None,
58
+ async_client: AsyncRedisClient | None = None,
54
59
  key_prefix: str = DEFAULT_KEY_PREFIX,
55
60
  lock_timeout: int = DEFAULT_LOCK_TIMEOUT,
56
61
  on_error: OnErrorType = "silent",
@@ -64,7 +69,7 @@ def setup_redis_config(
64
69
  Args:
65
70
  sync_client: Redis sync client instance (redis.Redis)
66
71
  async_client: Redis async client instance (redis.asyncio.Redis)
67
- key_prefix: Prefix for all cache keys in Redis (default: "cache")
72
+ key_prefix: Prefix for all cache keys in Redis (default: "{cachify}")
68
73
  lock_timeout: Timeout in seconds for distributed locks (default: 10)
69
74
  on_error: Error handling mode - "silent" treats errors as cache miss,
70
75
  "raise" propagates exceptions (default: "silent")
cachify/redis_cache.py CHANGED
@@ -1,4 +1,4 @@
1
- from typing import Callable
1
+ from typing import Callable, Sequence
2
2
 
3
3
  from cachify.cache import base_cache
4
4
  from cachify.redis.lock import RedisLockManager
@@ -16,7 +16,8 @@ def redis_cache(
16
16
  ttl: Number = 300,
17
17
  never_die: bool = False,
18
18
  cache_key_func: CacheKeyFunction | None = None,
19
- ignore_fields: tuple[str, ...] = (),
19
+ ignore_fields: Sequence[str] = (),
20
+ no_self: bool = False,
20
21
  ) -> Callable[[F], F]:
21
22
  """
22
23
  Redis cache decorator. See `base_cache` for full documentation.
@@ -24,4 +25,4 @@ def redis_cache(
24
25
  Requires setup_redis_config() to be called before use.
25
26
  Uses Redis for distributed caching across multiple processes/machines.
26
27
  """
27
- return base_cache(ttl, never_die, cache_key_func, ignore_fields, _REDIS_CONFIG)
28
+ return base_cache(ttl, never_die, cache_key_func, ignore_fields, no_self, _REDIS_CONFIG)
@@ -1,17 +1,12 @@
1
- import hashlib
2
1
  import inspect
3
- import pickle
4
2
  from collections.abc import Callable, Generator
5
3
  from inspect import Signature
6
4
  from typing import Any
7
5
 
8
6
  from cachify.types import CacheKeyFunction
7
+ from cachify.utils.errors import CacheKeyError
9
8
  from cachify.utils.functions import get_function_id
10
-
11
-
12
- def _cache_key_fingerprint(value: object) -> str:
13
- payload = pickle.dumps(value, protocol=pickle.HIGHEST_PROTOCOL)
14
- return hashlib.blake2b(payload, digest_size=16).hexdigest()
9
+ from cachify.utils.hash import object_hash
15
10
 
16
11
 
17
12
  def _iter_arguments(
@@ -54,12 +49,12 @@ def create_cache_key(
54
49
  if not cache_key_func:
55
50
  function_signature = inspect.signature(function)
56
51
  items = tuple(_iter_arguments(function_signature, args, kwargs, ignore_fields))
57
- return f"{function_id}:{_cache_key_fingerprint(items)}"
52
+ return f"{function_id}:{object_hash(items)}"
58
53
 
59
54
  cache_key = cache_key_func(args, kwargs)
60
55
  try:
61
- return f"{function_id}:{_cache_key_fingerprint(cache_key)}"
56
+ return f"{function_id}:{object_hash(cache_key)}"
62
57
  except TypeError as exc:
63
- raise ValueError(
58
+ raise CacheKeyError(
64
59
  "Cache key function must return a hashable cache key - be careful with mutable types (list, dict, set) and non built-in types"
65
60
  ) from exc
@@ -0,0 +1,2 @@
1
+ class CacheKeyError(ValueError):
2
+ pass
cachify/utils/hash.py ADDED
@@ -0,0 +1,18 @@
1
+ import hashlib
2
+ import pickle
3
+ from typing import Any
4
+
5
+ from cachify.utils.errors import CacheKeyError
6
+
7
+
8
+ def object_hash(value: Any) -> str:
9
+ try:
10
+ payload = pickle.dumps(value, protocol=pickle.HIGHEST_PROTOCOL)
11
+
12
+ except Exception as exc:
13
+ raise CacheKeyError(
14
+ "Unable to serialize object for hashing - ensure all parts of the object are pickleable. "
15
+ "Hint: create a custom __reduce__ method for the suspected object if necessary."
16
+ ) from exc
17
+
18
+ return hashlib.blake2b(payload, digest_size=16).hexdigest()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cachify
3
- Version: 0.2.1
3
+ Version: 0.3.1
4
4
  Summary: A simple cache library with sync/async support, Memory and Redis backend
5
5
  License: MIT
6
6
  License-File: LICENSE
@@ -86,12 +86,13 @@ async def another_calculation(url):
86
86
 
87
87
  ### Decorator Parameters
88
88
 
89
- | Parameter | Type | Default | Description |
90
- | ---------------- | ----------------- | ------- | ---------------------------------------------------- |
91
- | `ttl` | `int \| float` | `300` | Time to live for cached items in seconds |
92
- | `never_die` | `bool` | `False` | If True, cache refreshes automatically in background |
93
- | `cache_key_func` | `Callable` | `None` | Custom function to generate cache keys |
94
- | `ignore_fields` | `tuple[str, ...]` | `()` | Function parameters to exclude from cache key |
89
+ | Parameter | Type | Default | Description |
90
+ | ---------------- | --------------- | ------- | -------------------------------------------------------------- |
91
+ | `ttl` | `int \| float` | `300` | Time to live for cached items in seconds |
92
+ | `never_die` | `bool` | `False` | If True, cache refreshes automatically in background |
93
+ | `cache_key_func` | `Callable` | `None` | Custom function to generate cache keys |
94
+ | `ignore_fields` | `Sequence[str]` | `()` | Function parameters to exclude from cache key |
95
+ | `no_self` | `bool` | `False` | If True, ignores the first parameter (usually `self` or `cls`) |
95
96
 
96
97
  ### Custom Cache Key Function
97
98
 
@@ -134,7 +135,7 @@ from cachify import setup_redis_config, rcache
134
135
  # Configure Redis (call once at startup)
135
136
  setup_redis_config(
136
137
  sync_client=redis.from_url("redis://localhost:6379/0"),
137
- key_prefix="myapp", # default: "cachify", prefix searchable on redis "PREFIX:*"
138
+ key_prefix="{myapp}", # default: "{cachify}", prefix searchable on redis "PREFIX:*"
138
139
  lock_timeout=10, # default: 10, maximum lock lifetime in seconds
139
140
  on_error="silent", # "silent" (default) or "raise" in case of redis errors
140
141
  )
@@ -0,0 +1,24 @@
1
+ cachify/__init__.py,sha256=zzW2gPgLF6PNRMvUmGo-2V-vXsrpYFJitgRFPlp-RgU,582
2
+ cachify/cache.py,sha256=Dg-vHIQrlXOMR4ueiTdw6fZYbfsJo8b95aTetPK-MUE,4288
3
+ cachify/config/__init__.py,sha256=ZvLLEsprTbKai3-uUTbZ6Axbgf-xw-7sxmz8Y62YdT4,98
4
+ cachify/features/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ cachify/features/never_die.py,sha256=virRY8788D1fGmwQQYmbMhLIKRkWVYNPywR-kl18u9c,7105
6
+ cachify/memory_cache.py,sha256=Ge1yU6fJfv_o3aCgU7ky5pHxvDSmfQ0xBFnJeC61jLQ,1485
7
+ cachify/redis/__init__.py,sha256=geuYVjwJdddlhrnt45cHzkJ7Anrhttm2F3Q3r0TTMLk,410
8
+ cachify/redis/config.py,sha256=QUlsZS5vOXZzyGjN75Lq2kkszPrV1U6e_mRUgyC5JFM,3870
9
+ cachify/redis/lock.py,sha256=XbE5GHZIWUs9gqyfgle3Bur5CfKJ1pLhgtLctmZLB94,7281
10
+ cachify/redis_cache.py,sha256=s9Uf2DdBwoZAFSld0fK18S70gz7B4APUB701_mfL-2A,917
11
+ cachify/storage/__init__.py,sha256=8FJOYwjg8LHVoNkyupdgKOR61LPfX5Bpz_mvnn-T-oU,250
12
+ cachify/storage/memory_storage.py,sha256=rsQqoymWczzkfXisF-9Tc9UGQem936U6_vd9Uo-sWnU,1481
13
+ cachify/storage/redis_storage.py,sha256=wZaKg7h98cmESpqiOmh906D5wfNBxYN80x-LQDLtb-c,4767
14
+ cachify/types/__init__.py,sha256=OataAgBEQXxpc376uZFM6cmdzJLUkzkj_H8XiKq5zpU,2641
15
+ cachify/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
+ cachify/utils/arguments.py,sha256=UJhcC8erS9h8sJTNlILK3uvr6Mg1BWkaI-2esV7-LNs,1858
17
+ cachify/utils/errors.py,sha256=IuPQuOV0rfzeHUoLi5DrdmGSz3YnB1OF4URPdIy6qQI,42
18
+ cachify/utils/functions.py,sha256=AA1GXJEEBsIr2NX9h6AslAdmqKaWUcjnf1q5kA216uY,312
19
+ cachify/utils/hash.py,sha256=L95dFggFMKa-fQXXIwlRtPsJfWYKFlWzvbfTKlHR-o0,558
20
+ cachify-0.3.1.dist-info/METADATA,sha256=dFcWvVCi8X4SSOVvpSGm8s5VvM_gVX59-MvXvonk5IY,7598
21
+ cachify-0.3.1.dist-info/WHEEL,sha256=kJCRJT_g0adfAJzTx2GUMmS80rTJIVHRCfG0DQgLq3o,88
22
+ cachify-0.3.1.dist-info/entry_points.txt,sha256=a8B7GSYgDPfUClqct0o7yyBbJ61AWgSSy1idL6YZLUM,45
23
+ cachify-0.3.1.dist-info/licenses/LICENSE,sha256=zUzOFiuoPIQzGktjk4kL78hpi57iWD6-Kug_96OgUO0,1071
24
+ cachify-0.3.1.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 2.2.1
2
+ Generator: poetry-core 2.3.1
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,44 +0,0 @@
1
- import inspect
2
- from typing import Callable
3
-
4
- from cachify._async import async_decorator
5
- from cachify._sync import sync_decorator
6
- from cachify.types import CacheConfig, CacheKeyFunction, F, Number
7
-
8
-
9
- def create_cache_decorator(
10
- ttl: Number,
11
- never_die: bool,
12
- cache_key_func: CacheKeyFunction | None,
13
- ignore_fields: tuple[str, ...],
14
- config: CacheConfig,
15
- ) -> Callable[[F], F]:
16
- """
17
- Create a cache decorator with the given configuration.
18
-
19
- This is a shared factory used by both memory_cache and redis_cache
20
- to avoid code duplication.
21
- """
22
- if cache_key_func and ignore_fields:
23
- raise ValueError("Either cache_key_func or ignore_fields can be provided, but not both")
24
-
25
- def decorator(function: F) -> F:
26
- if inspect.iscoroutinefunction(function):
27
- return async_decorator(
28
- function=function,
29
- ttl=ttl,
30
- never_die=never_die,
31
- cache_key_func=cache_key_func,
32
- ignore_fields=ignore_fields,
33
- config=config,
34
- )
35
- return sync_decorator(
36
- function=function,
37
- ttl=ttl,
38
- never_die=never_die,
39
- cache_key_func=cache_key_func,
40
- ignore_fields=ignore_fields,
41
- config=config,
42
- )
43
-
44
- return decorator
cachify/utils/locks.py DELETED
@@ -1,6 +0,0 @@
1
- import asyncio
2
- import threading
3
- from collections import defaultdict
4
-
5
- ASYNC_LOCKS: defaultdict[str, asyncio.Lock] = defaultdict(asyncio.Lock)
6
- SYNC_LOCKS: defaultdict[str, threading.Lock] = defaultdict(threading.Lock)
@@ -1,24 +0,0 @@
1
- cachify/__init__.py,sha256=OvqM85Qq3rO6-KilFjq4MO0rm_NBdTfzAo2uhBVksdU,550
2
- cachify/cache.py,sha256=zJM9J4DdBXyGquQUTDJJ_voC51p-RM_CQcC-4DM92Gg,4021
3
- cachify/config/__init__.py,sha256=ZvLLEsprTbKai3-uUTbZ6Axbgf-xw-7sxmz8Y62YdT4,98
4
- cachify/features/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
- cachify/features/never_die.py,sha256=NJvCJhHMjxxaVZCC5xrUATcBBm4OXXHdipOg6wjOfV4,7111
6
- cachify/memory_cache.py,sha256=2UEnYXSJJ0XlqVM7sJ2GkPW1reU7DRtfifHEdbJQrYY,1328
7
- cachify/redis/__init__.py,sha256=geuYVjwJdddlhrnt45cHzkJ7Anrhttm2F3Q3r0TTMLk,410
8
- cachify/redis/config.py,sha256=Gvlj_hrUlsIGYqu50dghrv83R5UEOMJa4jVeK-nBAOs,3558
9
- cachify/redis/lock.py,sha256=XbE5GHZIWUs9gqyfgle3Bur5CfKJ1pLhgtLctmZLB94,7281
10
- cachify/redis_cache.py,sha256=WVc26EpAVSyQptD3guDD2LuPDgnuL72BCvhln-n84hc,873
11
- cachify/storage/__init__.py,sha256=8FJOYwjg8LHVoNkyupdgKOR61LPfX5Bpz_mvnn-T-oU,250
12
- cachify/storage/memory_storage.py,sha256=rsQqoymWczzkfXisF-9Tc9UGQem936U6_vd9Uo-sWnU,1481
13
- cachify/storage/redis_storage.py,sha256=wZaKg7h98cmESpqiOmh906D5wfNBxYN80x-LQDLtb-c,4767
14
- cachify/types/__init__.py,sha256=OataAgBEQXxpc376uZFM6cmdzJLUkzkj_H8XiKq5zpU,2641
15
- cachify/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
- cachify/utils/arguments.py,sha256=7NcuntqxK7G1UV4wrIaLNfxE0E7Gr-MmPWi9U-JyQ9o,2000
17
- cachify/utils/decorator_factory.py,sha256=brraPKR7ZJqdTbp8s5tEk6D517CKOlo9z1ZLoqhoz_s,1325
18
- cachify/utils/functions.py,sha256=AA1GXJEEBsIr2NX9h6AslAdmqKaWUcjnf1q5kA216uY,312
19
- cachify/utils/locks.py,sha256=7x-4XK27NiM_Eu04pftUgEgu91w8B3rE15jjAl0g1AE,216
20
- cachify-0.2.1.dist-info/METADATA,sha256=pl450wfErW4M_deswdy9thDYahuDHno6p1LfJ3kdmHU,7432
21
- cachify-0.2.1.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
22
- cachify-0.2.1.dist-info/entry_points.txt,sha256=a8B7GSYgDPfUClqct0o7yyBbJ61AWgSSy1idL6YZLUM,45
23
- cachify-0.2.1.dist-info/licenses/LICENSE,sha256=zUzOFiuoPIQzGktjk4kL78hpi57iWD6-Kug_96OgUO0,1071
24
- cachify-0.2.1.dist-info/RECORD,,