cachify 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.
cachify/__init__.py CHANGED
@@ -1,22 +1,24 @@
1
- from .features.never_die import clear_never_die_registry
2
- from .memory_cache import cache
3
- from .redis import DEFAULT_KEY_PREFIX, get_redis_config, reset_redis_config, setup_redis_config
4
- from .redis_cache import redis_cache
5
- from .types import CacheKwargs
6
-
7
- __version__ = "0.1.0"
8
-
9
- rcache = redis_cache
10
-
11
- __all__ = [
12
- "__version__",
13
- "cache",
14
- "rcache",
15
- "redis_cache",
16
- "setup_redis_config",
17
- "get_redis_config",
18
- "reset_redis_config",
19
- "DEFAULT_KEY_PREFIX",
20
- "CacheKwargs",
21
- "clear_never_die_registry",
22
- ]
1
+ from importlib.metadata import version
2
+
3
+ from .features.never_die import clear_never_die_registry
4
+ from .memory_cache import cache
5
+ from .redis import DEFAULT_KEY_PREFIX, get_redis_config, reset_redis_config, setup_redis_config
6
+ from .redis_cache import redis_cache
7
+ from .types import CacheKwargs
8
+
9
+ __version__ = version("cachify")
10
+
11
+ rcache = redis_cache
12
+
13
+ __all__ = [
14
+ "__version__",
15
+ "cache",
16
+ "rcache",
17
+ "redis_cache",
18
+ "setup_redis_config",
19
+ "get_redis_config",
20
+ "reset_redis_config",
21
+ "DEFAULT_KEY_PREFIX",
22
+ "CacheKwargs",
23
+ "clear_never_die_registry",
24
+ ]
cachify/cache.py CHANGED
@@ -1,116 +1,116 @@
1
- import functools
2
- import inspect
3
- from typing import Any, Callable, cast
4
-
5
- from cachify.features.never_die import register_never_die_function
6
- from cachify.types import CacheConfig, CacheKeyFunction, F, Number
7
- from cachify.utils.arguments import create_cache_key
8
-
9
-
10
- def _async_decorator(
11
- function: F,
12
- ttl: Number,
13
- never_die: bool,
14
- cache_key_func: CacheKeyFunction | None,
15
- ignore_fields: tuple[str, ...],
16
- config: CacheConfig,
17
- ) -> F:
18
- @functools.wraps(function)
19
- async def async_wrapper(*args: Any, **kwargs: Any) -> Any:
20
- skip_cache = kwargs.pop("skip_cache", False)
21
- cache_key = create_cache_key(function, cache_key_func, ignore_fields, args, kwargs)
22
-
23
- if cache_entry := await config.storage.aget(cache_key, skip_cache):
24
- return cache_entry.result
25
-
26
- async with config.async_lock(cache_key):
27
- if cache_entry := await config.storage.aget(cache_key, skip_cache):
28
- return cache_entry.result
29
-
30
- result = await function(*args, **kwargs)
31
- await config.storage.aset(cache_key, result, None if never_die else ttl)
32
-
33
- if never_die:
34
- register_never_die_function(function, ttl, args, kwargs, cache_key_func, ignore_fields, config)
35
-
36
- return result
37
-
38
- return cast(F, async_wrapper)
39
-
40
-
41
- def _sync_decorator(
42
- function: F,
43
- ttl: Number,
44
- never_die: bool,
45
- cache_key_func: CacheKeyFunction | None,
46
- ignore_fields: tuple[str, ...],
47
- config: CacheConfig,
48
- ) -> F:
49
- @functools.wraps(function)
50
- def sync_wrapper(*args: Any, **kwargs: Any) -> Any:
51
- skip_cache = kwargs.pop("skip_cache", False)
52
- cache_key = create_cache_key(function, cache_key_func, ignore_fields, args, kwargs)
53
-
54
- if cache_entry := config.storage.get(cache_key, skip_cache):
55
- return cache_entry.result
56
-
57
- with config.sync_lock(cache_key):
58
- if cache_entry := config.storage.get(cache_key, skip_cache):
59
- return cache_entry.result
60
-
61
- result = function(*args, **kwargs)
62
- config.storage.set(cache_key, result, None if never_die else ttl)
63
-
64
- if never_die:
65
- register_never_die_function(function, ttl, args, kwargs, cache_key_func, ignore_fields, config)
66
-
67
- return result
68
-
69
- return cast(F, sync_wrapper)
70
-
71
-
72
- def base_cache(
73
- ttl: Number,
74
- never_die: bool,
75
- cache_key_func: CacheKeyFunction | None,
76
- ignore_fields: tuple[str, ...],
77
- config: CacheConfig,
78
- ) -> Callable[[F], F]:
79
- """
80
- Base cache decorator factory used by both memory and Redis cache implementations.
81
-
82
- Args:
83
- ttl: Time to live for cached items in seconds
84
- never_die: If True, the cache will never expire and will be recalculated based on the ttl
85
- 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
- config: Cache configuration specifying storage, locks, and never_die registration
88
-
89
- Features:
90
- - Works for both sync and async functions
91
- - Only allows one execution at a time per function+args
92
- - Makes subsequent calls wait for the first call to complete
93
- """
94
- if cache_key_func and ignore_fields:
95
- raise ValueError("Either cache_key_func or ignore_fields can be provided, but not both")
96
-
97
- def decorator(function: F) -> F:
98
- if inspect.iscoroutinefunction(function):
99
- return _async_decorator(
100
- function=function,
101
- ttl=ttl,
102
- never_die=never_die,
103
- cache_key_func=cache_key_func,
104
- ignore_fields=ignore_fields,
105
- config=config,
106
- )
107
- return _sync_decorator(
108
- function=function,
109
- ttl=ttl,
110
- never_die=never_die,
111
- cache_key_func=cache_key_func,
112
- ignore_fields=ignore_fields,
113
- config=config,
114
- )
115
-
116
- return decorator
1
+ import functools
2
+ import inspect
3
+ from typing import Any, Callable, cast
4
+
5
+ from cachify.features.never_die import register_never_die_function
6
+ from cachify.types import CacheConfig, CacheKeyFunction, F, Number
7
+ from cachify.utils.arguments import create_cache_key
8
+
9
+
10
+ def _async_decorator(
11
+ function: F,
12
+ ttl: Number,
13
+ never_die: bool,
14
+ cache_key_func: CacheKeyFunction | None,
15
+ ignore_fields: tuple[str, ...],
16
+ config: CacheConfig,
17
+ ) -> F:
18
+ @functools.wraps(function)
19
+ async def async_wrapper(*args: Any, **kwargs: Any) -> Any:
20
+ skip_cache = kwargs.pop("skip_cache", False)
21
+ cache_key = create_cache_key(function, cache_key_func, ignore_fields, args, kwargs)
22
+
23
+ if cache_entry := await config.storage.aget(cache_key, skip_cache):
24
+ return cache_entry.result
25
+
26
+ async with config.async_lock(cache_key):
27
+ if cache_entry := await config.storage.aget(cache_key, skip_cache):
28
+ return cache_entry.result
29
+
30
+ result = await function(*args, **kwargs)
31
+ await config.storage.aset(cache_key, result, None if never_die else ttl)
32
+
33
+ if never_die:
34
+ register_never_die_function(function, ttl, args, kwargs, cache_key_func, ignore_fields, config)
35
+
36
+ return result
37
+
38
+ return cast(F, async_wrapper)
39
+
40
+
41
+ def _sync_decorator(
42
+ function: F,
43
+ ttl: Number,
44
+ never_die: bool,
45
+ cache_key_func: CacheKeyFunction | None,
46
+ ignore_fields: tuple[str, ...],
47
+ config: CacheConfig,
48
+ ) -> F:
49
+ @functools.wraps(function)
50
+ def sync_wrapper(*args: Any, **kwargs: Any) -> Any:
51
+ skip_cache = kwargs.pop("skip_cache", False)
52
+ cache_key = create_cache_key(function, cache_key_func, ignore_fields, args, kwargs)
53
+
54
+ if cache_entry := config.storage.get(cache_key, skip_cache):
55
+ return cache_entry.result
56
+
57
+ with config.sync_lock(cache_key):
58
+ if cache_entry := config.storage.get(cache_key, skip_cache):
59
+ return cache_entry.result
60
+
61
+ result = function(*args, **kwargs)
62
+ config.storage.set(cache_key, result, None if never_die else ttl)
63
+
64
+ if never_die:
65
+ register_never_die_function(function, ttl, args, kwargs, cache_key_func, ignore_fields, config)
66
+
67
+ return result
68
+
69
+ return cast(F, sync_wrapper)
70
+
71
+
72
+ def base_cache(
73
+ ttl: Number,
74
+ never_die: bool,
75
+ cache_key_func: CacheKeyFunction | None,
76
+ ignore_fields: tuple[str, ...],
77
+ config: CacheConfig,
78
+ ) -> Callable[[F], F]:
79
+ """
80
+ Base cache decorator factory used by both memory and Redis cache implementations.
81
+
82
+ Args:
83
+ ttl: Time to live for cached items in seconds
84
+ never_die: If True, the cache will never expire and will be recalculated based on the ttl
85
+ 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
+ config: Cache configuration specifying storage, locks, and never_die registration
88
+
89
+ Features:
90
+ - Works for both sync and async functions
91
+ - Only allows one execution at a time per function+args
92
+ - Makes subsequent calls wait for the first call to complete
93
+ """
94
+ if cache_key_func and ignore_fields:
95
+ raise ValueError("Either cache_key_func or ignore_fields can be provided, but not both")
96
+
97
+ def decorator(function: F) -> F:
98
+ if inspect.iscoroutinefunction(function):
99
+ return _async_decorator(
100
+ function=function,
101
+ ttl=ttl,
102
+ never_die=never_die,
103
+ cache_key_func=cache_key_func,
104
+ ignore_fields=ignore_fields,
105
+ config=config,
106
+ )
107
+ return _sync_decorator(
108
+ function=function,
109
+ ttl=ttl,
110
+ never_die=never_die,
111
+ cache_key_func=cache_key_func,
112
+ ignore_fields=ignore_fields,
113
+ config=config,
114
+ )
115
+
116
+ return decorator
@@ -1,4 +1,4 @@
1
- import logging
2
-
3
- logger = logging.getLogger("cachify")
4
- logger.addHandler(logging.NullHandler())
1
+ import logging
2
+
3
+ logger = logging.getLogger("cachify")
4
+ logger.addHandler(logging.NullHandler())