Skip to content

Commit

Permalink
Merge branch 'v/2.0.0' into 119-refactor-docs
Browse files Browse the repository at this point in the history
  • Loading branch information
Galtozzy committed Sep 22, 2024
2 parents 064546b + eeb1c5c commit d12627b
Show file tree
Hide file tree
Showing 18 changed files with 853 additions and 205 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ wheels/
*.egg-info/
.installed.cfg
*.egg
pyrightconfig.json
.zed

# PyInstaller
# Usually these files are written by a python script from a template
Expand Down
278 changes: 150 additions & 128 deletions poetry.lock

Large diffs are not rendered by default.

8 changes: 6 additions & 2 deletions py_cachify/__init__.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
from . import asyncio, sync
from .backend.cached import cached
from .backend.exceptions import CachifyInitError, CachifyLockError
from .backend.helpers import Decoder, Encoder
from .backend.lib import init_cachify
from .backend.lock import once
from .backend.lock import lock, once
from .backend.types import Decoder, Encoder


__version__ = '2.0.0'

__all__ = [
'CachifyInitError',
'CachifyLockError',
'init_cachify',
'lock',
'Encoder',
'Decoder',
'cached',
Expand Down
4 changes: 2 additions & 2 deletions py_cachify/asyncio.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from .backend.cached import async_cached
from .backend.lock import async_lock, async_once
from .backend.lock import async_once
from .backend.types import AsyncClient


__all__ = ['async_once', 'async_lock', 'async_cached', 'AsyncClient']
__all__ = ['async_once', 'async_cached', 'AsyncClient']
40 changes: 29 additions & 11 deletions py_cachify/backend/cached.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,45 @@

from .helpers import a_reset, encode_decode_value, get_full_key_from_signature, is_coroutine, reset
from .lib import get_cachify
from .types import AsyncWithResetProtocol, Decoder, Encoder, SyncOrAsync, SyncWithResetProtocol
from .types import AsyncWithResetProto, Decoder, Encoder, SyncOrAsyncReset, SyncWithResetProto


R = TypeVar('R')
P = ParamSpec('P')


def cached(key: str, ttl: Union[int, None] = None, enc_dec: Union[Tuple[Encoder, Decoder], None] = None) -> SyncOrAsync:
def cached(
key: str, ttl: Union[int, None] = None, enc_dec: Union[Tuple[Encoder, Decoder], None] = None
) -> SyncOrAsyncReset:
"""
Decorator that caches the result of a function based on the specified key, time-to-live (ttl),
and encoding/decoding functions.
Args:
key (str): The key used to identify the cached result, could be a format string.
ttl (Union[int, None], optional): The time-to-live for the cached result.
Defaults to None, means indefinitely.
enc_dec (Union[Tuple[Encoder, Decoder], None], optional): The encoding and decoding functions for the cached value.
Defaults to None.
Returns:
WrappedFunction: Either a synchronous or asynchronous function with reset method attached to it,
reset(*args, **kwargs) matches the type of original function and could be used to reset the cache.
"""

@overload
def _cached_inner( # type: ignore[overload-overlap]
_func: Callable[P, Awaitable[R]],
) -> AsyncWithResetProtocol[P, R]: ...
) -> AsyncWithResetProto[P, R]: ...

@overload
def _cached_inner(
_func: Callable[P, R],
) -> SyncWithResetProtocol[P, R]: ...
) -> SyncWithResetProto[P, R]: ...

def _cached_inner(
_func: Union[Callable[P, R], Callable[P, Awaitable[R]]],
) -> Union[AsyncWithResetProtocol[P, R], SyncWithResetProtocol[P, R]]:
) -> Union[AsyncWithResetProto[P, R], SyncWithResetProto[P, R]]:
signature = inspect.signature(_func)

enc, dec = None, None
Expand All @@ -49,7 +67,7 @@ async def _async_wrapper(*args: P.args, **kwargs: P.kwargs) -> R:

setattr(_async_wrapper, 'reset', partial(a_reset, signature=signature, key=key))

return cast(AsyncWithResetProtocol[P, R], _async_wrapper)
return cast(AsyncWithResetProto[P, R], _async_wrapper)
else:

@wraps(_func) # type: ignore[unreachable]
Expand All @@ -65,20 +83,20 @@ def _sync_wrapper(*args: P.args, **kwargs: P.kwargs) -> R:

setattr(_sync_wrapper, 'reset', partial(reset, signature=signature, key=key))

return cast(SyncWithResetProtocol[P, R], _sync_wrapper)
return cast(SyncWithResetProto[P, R], _sync_wrapper)

return _cached_inner


@deprecated('sync_cached is deprecated, use cached instead. Scheduled for removal in 1.3.0')
@deprecated('sync_cached is deprecated, use cached instead. Scheduled for removal in 3.0.0')
def sync_cached(
key: str, ttl: Union[int, None] = None, enc_dec: Union[Tuple[Encoder, Decoder], None] = None
) -> SyncOrAsync:
) -> SyncOrAsyncReset:
return cached(key=key, ttl=ttl, enc_dec=enc_dec)


@deprecated('async_cached is deprecated, use cached instead. Scheduled for removal in 1.3.0')
@deprecated('async_cached is deprecated, use cached instead. Scheduled for removal in 3.0.0')
def async_cached(
key: str, ttl: Union[int, None] = None, enc_dec: Union[Tuple[Encoder, Decoder], None] = None
) -> SyncOrAsync:
) -> SyncOrAsyncReset:
return cached(key=key, ttl=ttl, enc_dec=enc_dec)
14 changes: 14 additions & 0 deletions py_cachify/backend/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,17 @@ async def a_reset(*args: Any, key: str, signature: inspect.Signature, **kwargs:
await cachify.a_delete(key=_key)

return None


async def is_alocked(*args: Any, key: str, signature: inspect.Signature, **kwargs: Any) -> bool:
cachify = get_cachify()
_key = get_full_key_from_signature(bound_args=signature.bind(*args, **kwargs), key=key)

return bool(await cachify.a_get(key=_key))


def is_locked(*args: Any, key: str, signature: inspect.Signature, **kwargs: Any) -> bool:
cachify = get_cachify()
_key = get_full_key_from_signature(bound_args=signature.bind(*args, **kwargs), key=key)

return bool(cachify.get(key=_key))
20 changes: 19 additions & 1 deletion py_cachify/backend/lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@ def __init__(
self,
sync_client: Union[SyncClient, MemoryCache],
async_client: Union[AsyncClient, AsyncWrapper],
default_expiration: Optional[int],
prefix: str,
) -> None:
self._sync_client = sync_client
self._async_client = async_client
self._prefix = prefix
self.default_expiration = default_expiration

def set(self, key: str, val: Any, ttl: Union[int, None] = None) -> Any:
self._sync_client.set(name=f'{self._prefix}{key}', value=pickle.dumps(val), ex=ttl)
Expand All @@ -42,10 +44,26 @@ async def a_delete(self, key: str) -> Any:
def init_cachify(
sync_client: SyncClient = (mc := MemoryCache()),
async_client: AsyncClient = AsyncWrapper(cache=mc),
default_lock_expiration: Optional[int] = 30,
prefix: str = 'PYC-',
) -> None:
"""
Initialize the Cachify instance with the specified clients and settings.
Args:
sync_client (Union[SyncClient, MemoryCache], optional): The synchronous client to use.
Defaults to MemoryCache().
async_client (Union[AsyncClient, AsyncWrapper], optional): The asynchronous client to use.
Defaults to AsyncWrapper(cache=MemoryCache()).
default_lock_expiration (Optional[int], optional): The default expiration time for locks.
Defaults to 30.
prefix (str, optional): The prefix to use for keys. Defaults to 'PYC-'.
"""

global _cachify
_cachify = Cachify(sync_client=sync_client, async_client=async_client, prefix=prefix)
_cachify = Cachify(
sync_client=sync_client, async_client=async_client, prefix=prefix, default_expiration=default_lock_expiration
)


def get_cachify() -> Cachify:
Expand Down
Loading

0 comments on commit d12627b

Please sign in to comment.