Skip to content

Commit ca7f1ad

Browse files
Add support for XDG-compliant cache directory (#286)
* feat: Add XDG base directory support for cache path - Default cache dir now respects - Falls back to ~/.cachier/ if not set - Updated Params and set_global_params to support dynamic cache_dir - Added tests for XDG compliance and fallback behavior * Remove extrac spaces * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Discarded previous implementation using @Property and _cache_dir indirection, Introduced LazyCacheDir class to delay evaluation of * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * docs(config): add concise docstrings to LazyCacheDir class and methods * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Rephrased method docstrings to use imperative mood (e.g., Return instead of Returns) * test: add coverage for LazyCacheDir.__eq__ via indirect cache_dir comparison * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent 8bc7bec commit ca7f1ad

2 files changed

Lines changed: 69 additions & 2 deletions

File tree

src/cachier/config.py

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import os
33
import pickle
44
import threading
5-
from dataclasses import dataclass, replace
5+
from dataclasses import dataclass, field, replace
66
from datetime import datetime, timedelta
77
from typing import Any, Optional, Union
88

@@ -18,6 +18,36 @@ def _default_hash_func(args, kwds):
1818
return hashlib.sha256(serialized).hexdigest()
1919

2020

21+
def _default_cache_dir():
22+
"""Return default cache directory based on XDG specification.
23+
24+
Uses $XDG_CACHE_HOME if defined, otherwise falls back to ~/.cachier/
25+
26+
"""
27+
xdg_cache_home = os.environ.get("XDG_CACHE_HOME")
28+
if xdg_cache_home:
29+
# Use XDG-compliant cache directory
30+
return os.path.join(xdg_cache_home, "cachier")
31+
# Default fallback if XDG is not set
32+
return os.path.expanduser("~/.cachier/")
33+
34+
35+
class LazyCacheDir:
36+
"""Lazily resolve the default cache directory using $XDG_CACHE_HOME."""
37+
38+
def __str__(self):
39+
"""Return the resolved cache directory path as a string."""
40+
return _default_cache_dir()
41+
42+
def __fspath__(self):
43+
"""Return the path for filesystem operations."""
44+
return self.__str__()
45+
46+
def __eq__(self, other):
47+
"""Compare the resolved path to another path."""
48+
return str(self) == str(other)
49+
50+
2151
@dataclass
2252
class Params:
2353
"""Default definition for cachier parameters."""
@@ -28,7 +58,7 @@ class Params:
2858
mongetter: Optional[Mongetter] = None
2959
stale_after: timedelta = timedelta.max
3060
next_time: bool = False
31-
cache_dir: Union[str, os.PathLike] = "~/.cachier/"
61+
cache_dir: Union[str, os.PathLike] = field(default_factory=LazyCacheDir)
3262
pickle_reload: bool = True
3363
separate_files: bool = False
3464
wait_for_calc_timeout: int = 0

tests/test_defaults.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,43 @@ def global_test_2():
9797
assert global_test_2.cache_dpath() == str(tmpdir / "2")
9898

9999

100+
def test_cache_dir_respects_xdg(monkeypatch, tmpdir):
101+
xdg_path = str(tmpdir / "xdg_home")
102+
monkeypatch.setenv("XDG_CACHE_HOME", xdg_path)
103+
104+
expected_path = os.path.join(xdg_path, "cachier")
105+
106+
@cachier.cachier(backend="pickle")
107+
def my_func():
108+
return 123
109+
110+
actual_path = my_func.cache_dpath()
111+
assert str(actual_path) == expected_path
112+
113+
my_func() # Create cache file
114+
assert os.path.exists(expected_path)
115+
files = os.listdir(expected_path) if os.path.exists(expected_path) else []
116+
assert any(os.path.isfile(os.path.join(expected_path, f)) for f in files)
117+
118+
119+
def test_cache_dir_default_fallback(monkeypatch):
120+
monkeypatch.delenv("XDG_CACHE_HOME", raising=False)
121+
122+
@cachier.cachier()
123+
def my_func():
124+
return 123
125+
126+
expected_path = os.path.expanduser("~/.cachier/")
127+
assert my_func.cache_dpath().startswith(expected_path)
128+
129+
130+
def test_lazy_cache_dir_eq_triggered():
131+
default_dir = cachier.get_global_params().cache_dir
132+
133+
assert default_dir == str(default_dir)
134+
assert default_dir != "/some/random/path"
135+
136+
100137
def test_separate_files_default_param(tmpdir):
101138
cachier.set_global_params(separate_files=True)
102139

0 commit comments

Comments
 (0)