Skip to content

Commit

Permalink
Merge branch 'dev'
Browse files Browse the repository at this point in the history
  • Loading branch information
umarbutler committed Mar 21, 2024
2 parents 1a71d54 + 4383196 commit c035eff
Show file tree
Hide file tree
Showing 5 changed files with 23 additions and 11 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
## Changelog 🔄
All notable changes to `persist-cache` will be documented here. This project adheres to [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.3.2] - 2024-03-21
### Changed
- Began hashing the names of caches with `XXH3` to ensure caches may be assigned any arbitrary name, regardless of whether it is compatible with the local file system.

## [0.3.1] - 2024-03-20
### Fixed
- Fixed a bug causing `cache()` to raise a `TypeError` when attempting to cache a function call that contains an argument that is a list containing a dictionary ([#4](https://github.com/umarbutler/persist-cache/issues/4)) ([ec07874](https://github.com/umarbutler/persist-cache/commit/ec07874)).
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,9 @@ def cache(

The function to be cached must accept and return [dillable](https://dill.readthedocs.io/en/latest/) objects only (with the exception of methods' `self` argument, which is always ignored). Additionally, for consistent caching across subsequent sessions, arguments and returns should also be hashable.

`name` represents the name of the cache (or, if `cache()` is being called as an argument-less decorator (ie, as `@cache` instead of `@cache(...)`), the function to be cached). It defaults to the hash of the qualified name of the function. If `dir` is set, `name` will be ignored.
`name` represents the name of the cache (or, if `cache()` is being called as an argument-less decorator (ie, as `@cache` instead of `@cache(...)`), the function to be cached). It defaults to the qualified name of the function. If `dir` is set, `name` will be ignored.

`dir` represents the directory in which the cache should be stored. It defaults to a subdirectory bearing the name of the cache in a parent folder called '.persist_cache' in the current working directory.
`dir` represents the directory in which the cache should be stored. It defaults to a subdirectory named after the hash of the cache's name in a parent folder named '.persist_cache' in the current working directory.

`expiry` represents how long, in seconds or as a `timedelta`, function calls should persist in the cache. It defaults to `None`.

Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "hatchling.build"

[project]
name = "persist-cache"
version = "0.3.1"
version = "0.3.2"
authors = [
{name="Umar Butler", email="umar@umar.au"},
]
Expand Down
11 changes: 10 additions & 1 deletion src/persist_cache/caching.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from typing import Any, Union

from filelock import FileLock
from xxhash import xxh3_128_hexdigest
from xxhash import xxh3_64_hexdigest, xxh3_128_hexdigest

from .serialization import deserialize, serialize

Expand Down Expand Up @@ -58,6 +58,15 @@ def hash(data: Any) -> str:
# Hash the data and affix its length, preceded by a hyphen (to reduce the likelihood of collisions).
return f'{xxh3_128_hexdigest(data)}{len(data)}'

def shorthash(data: Any) -> str:
"""Hash the given data."""

# Serialise the data.
data = serialize(data)

# Hash the data and affix its length, preceded by a hyphen (to reduce the likelihood of collisions).
return f'{xxh3_64_hexdigest(data)}{len(data)}'

def delete(dir: str) -> None:
"""Delete the provided cache."""

Expand Down
13 changes: 6 additions & 7 deletions src/persist_cache/persist_cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ def cache(
The function to be cached must accept and return dillable objects only (with the exception of methods' `self` argument, which is always ignored). Additionally, for consistent caching across subsequent sessions, arguments and returns should also be hashable.
Arguments:
name (`str | Callable`, optional): The name of the cache (or, if `cache()` is being called as an argument-less decorator (ie, as `@cache` instead of `@cache(...)`), the function to be cached). Defaults to the hash of the qualified name of the function. If `dir` is set, this argument will be ignored.
name (`str | Callable`, optional): The name of the cache (or, if `cache()` is being called as an argument-less decorator (ie, as `@cache` instead of `@cache(...)`), the function to be cached). Defaults to the qualified name of the function. If `dir` is set, this argument will be ignored.
dir (`str`, optional): The directory in which the cache should be stored. Defaults to a subdirectory bearing the name of the cache in a parent folder called '.persist_cache' in the current working directory.
dir (`str`, optional): The directory in which the cache should be stored. Defaults to a subdirectory named after the hash of the cache's name in a parent folder named '.persist_cache' in the current working directory.
expiry (`int | float | timedelta`, optional): How long, in seconds or as a `timedelta`, function calls should persist in the cache. Defaults to `None`.
Expand All @@ -35,12 +35,11 @@ def cache(
def decorator(func: Callable) -> Callable:
nonlocal name, dir, expiry

# If the cache directory has not been set, and the name of the cache has, set it to a subdirectory by that name in a directory called '.persist_cache' in the current working directory, or, if the name of the cache has not been set, set the name of that subdirectory to the hash of the qualified name of the function.
# If the cache directory has not been set, and the name of the cache has, set it to a subdirectory by the name of the hash of that name in a directory named '.persist_cache' in the current working directory, or, if the name of the cache has not been set, set the name of that subdirectory to the hash of the qualified name of the function.
if dir is None:
if name is not None:
dir = f'.persist_cache/{name}'
else:
dir = f'.persist_cache/{caching.hash(func.__qualname__)}'
name = name if name is not None else func.__qualname__

dir = f'.persist_cache/{caching.shorthash(name)}'

# Create the cache directory and any other necessary directories if it does not exist.
if not os.path.exists(dir):
Expand Down

0 comments on commit c035eff

Please sign in to comment.