Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 32 additions & 2 deletions src/cachier/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import os
import pickle
import threading
from dataclasses import dataclass, replace
from dataclasses import dataclass, field, replace
from datetime import datetime, timedelta
from typing import Any, Optional, Union

Expand All @@ -18,6 +18,36 @@
return hashlib.sha256(serialized).hexdigest()


def _default_cache_dir():
"""Return default cache directory based on XDG specification.

Uses $XDG_CACHE_HOME if defined, otherwise falls back to ~/.cachier/

"""
xdg_cache_home = os.environ.get("XDG_CACHE_HOME")
if xdg_cache_home:
# Use XDG-compliant cache directory
return os.path.join(xdg_cache_home, "cachier")

Check warning on line 30 in src/cachier/config.py

View check run for this annotation

Codecov / codecov/patch

src/cachier/config.py#L30

Added line #L30 was not covered by tests
# Default fallback if XDG is not set
return os.path.expanduser("~/.cachier/")


class LazyCacheDir:
"""Lazily resolve the default cache directory using $XDG_CACHE_HOME."""

def __str__(self):
"""Return the resolved cache directory path as a string."""
return _default_cache_dir()

def __fspath__(self):
"""Return the path for filesystem operations."""
return self.__str__()

def __eq__(self, other):
"""Compare the resolved path to another path."""
return str(self) == str(other)

Check warning on line 48 in src/cachier/config.py

View check run for this annotation

Codecov / codecov/patch

src/cachier/config.py#L48

Added line #L48 was not covered by tests


@dataclass
class Params:
"""Default definition for cachier parameters."""
Expand All @@ -28,7 +58,7 @@
mongetter: Optional[Mongetter] = None
stale_after: timedelta = timedelta.max
next_time: bool = False
cache_dir: Union[str, os.PathLike] = "~/.cachier/"
cache_dir: Union[str, os.PathLike] = field(default_factory=LazyCacheDir)
pickle_reload: bool = True
separate_files: bool = False
wait_for_calc_timeout: int = 0
Expand Down
37 changes: 37 additions & 0 deletions tests/test_defaults.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,43 @@ def global_test_2():
assert global_test_2.cache_dpath() == str(tmpdir / "2")


def test_cache_dir_respects_xdg(monkeypatch, tmpdir):
xdg_path = str(tmpdir / "xdg_home")
monkeypatch.setenv("XDG_CACHE_HOME", xdg_path)

expected_path = os.path.join(xdg_path, "cachier")

@cachier.cachier(backend="pickle")
def my_func():
return 123

actual_path = my_func.cache_dpath()
assert str(actual_path) == expected_path

my_func() # Create cache file
assert os.path.exists(expected_path)
files = os.listdir(expected_path) if os.path.exists(expected_path) else []
assert any(os.path.isfile(os.path.join(expected_path, f)) for f in files)


def test_cache_dir_default_fallback(monkeypatch):
monkeypatch.delenv("XDG_CACHE_HOME", raising=False)

@cachier.cachier()
def my_func():
return 123

expected_path = os.path.expanduser("~/.cachier/")
assert my_func.cache_dpath().startswith(expected_path)


def test_lazy_cache_dir_eq_triggered():
default_dir = cachier.get_global_params().cache_dir

assert default_dir == str(default_dir)
assert default_dir != "/some/random/path"


def test_separate_files_default_param(tmpdir):
cachier.set_global_params(separate_files=True)

Expand Down
Loading