Skip to content

Commit 79e0fc5

Browse files
2 parents 93950bc + 834fbe8 commit 79e0fc5

File tree

4 files changed

+64
-11
lines changed

4 files changed

+64
-11
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
log*
33
!logger.py
44
weights*
5+
.cache/
56
*.txt
67
*.csv
78
*.root

src/spine/config/README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,14 +109,16 @@ model:
109109
```
110110

111111
The `!download` tag automatically downloads and caches remote files:
112-
- **Caching**: Files downloaded to `weights/` directory (or `$SPINE_CACHE_DIR`)
112+
- **Caching**: Files cached in `.cache/weights/` under `$SPINE_PROD_BASEDIR` or `$SPINE_BASEDIR`
113+
- **Centralized**: Single cache location regardless of execution directory
113114
- **Smart reuse**: Existing files with matching hash aren't re-downloaded
114115
- **Hash validation**: Optional SHA256 verification ensures file integrity
115116
- **Production ready**: Ideal for model weights and large reference files
117+
- **Override**: Set `$SPINE_CACHE_DIR` to use a custom cache location
116118

117119
Benefits for production:
118120
- Fully reproducible: exact weight URLs in version control
119-
- No manual downloads: users run configs directly
121+
- No manual downloads: users run configs directly
120122
- Cache efficient: download once, reuse everywhere
121123
- Integrity verified: hash validation prevents corruption
122124

src/spine/config/download.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@
1717
def get_cache_dir() -> Path:
1818
"""Get the directory for caching downloaded files.
1919
20-
By default, creates a 'weights/' directory in the current working directory.
20+
By default, creates a '.cache/weights/' directory in SPINE_BASEDIR or
21+
SPINE_PROD_BASEDIR (if running from spine-prod). This ensures downloads
22+
are cached centrally regardless of execution directory.
23+
2124
Can be overridden with the SPINE_CACHE_DIR environment variable.
2225
2326
Returns
@@ -28,6 +31,23 @@ def get_cache_dir() -> Path:
2831
cache_dir = os.environ.get("SPINE_CACHE_DIR")
2932
if cache_dir:
3033
return Path(cache_dir)
34+
35+
# Try SPINE_PROD_BASEDIR first (if running from spine-prod)
36+
spine_prod_base = os.environ.get("SPINE_PROD_BASEDIR")
37+
if spine_prod_base:
38+
return Path(spine_prod_base) / ".cache" / "weights"
39+
40+
# Fall back to SPINE_BASEDIR
41+
spine_base = os.environ.get("SPINE_BASEDIR")
42+
if spine_base:
43+
return Path(spine_base) / ".cache" / "weights"
44+
45+
# Last resort: use current directory (with warning)
46+
print(
47+
"WARNING: SPINE_BASEDIR and SPINE_PROD_BASEDIR not set. "
48+
"Using current directory for cache. "
49+
"Please source configure.sh for proper caching."
50+
)
3151
return Path.cwd() / "weights"
3252

3353

test/test_download.py

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,47 @@
2222
class TestDownloadUtilities:
2323
"""Test suite for download utility functions."""
2424

25-
def test_get_cache_dir_default(self):
26-
"""Test default cache directory."""
27-
with patch.dict(os.environ, {}, clear=True):
25+
def test_get_cache_dir_default(self, monkeypatch):
26+
"""Test default cache directory with warning when env vars not set."""
27+
# Clear environment
28+
monkeypatch.delenv("SPINE_CACHE_DIR", raising=False)
29+
monkeypatch.delenv("SPINE_PROD_BASEDIR", raising=False)
30+
monkeypatch.delenv("SPINE_BASEDIR", raising=False)
31+
32+
with patch("builtins.print") as mock_print:
2833
cache_dir = get_cache_dir()
34+
# Should warn about missing env vars
35+
mock_print.assert_called_once()
36+
assert "WARNING" in str(mock_print.call_args)
2937
assert cache_dir == Path.cwd() / "weights"
3038

31-
def test_get_cache_dir_env_override(self):
32-
"""Test cache directory from environment variable."""
33-
with patch.dict(os.environ, {"SPINE_CACHE_DIR": "/custom/cache"}):
34-
cache_dir = get_cache_dir()
35-
assert cache_dir == Path("/custom/cache")
39+
def test_get_cache_dir_spine_prod(self, monkeypatch):
40+
"""Test cache directory from SPINE_PROD_BASEDIR."""
41+
monkeypatch.delenv("SPINE_CACHE_DIR", raising=False)
42+
monkeypatch.setenv("SPINE_PROD_BASEDIR", "/opt/spine-prod")
43+
monkeypatch.setenv("SPINE_BASEDIR", "/opt/spine")
44+
45+
cache_dir = get_cache_dir()
46+
# Should prefer SPINE_PROD_BASEDIR
47+
assert cache_dir == Path("/opt/spine-prod") / ".cache" / "weights"
48+
49+
def test_get_cache_dir_spine_basedir(self, monkeypatch):
50+
"""Test cache directory from SPINE_BASEDIR."""
51+
monkeypatch.delenv("SPINE_CACHE_DIR", raising=False)
52+
monkeypatch.delenv("SPINE_PROD_BASEDIR", raising=False)
53+
monkeypatch.setenv("SPINE_BASEDIR", "/opt/spine")
54+
55+
cache_dir = get_cache_dir()
56+
assert cache_dir == Path("/opt/spine") / ".cache" / "weights"
57+
58+
def test_get_cache_dir_env_override(self, monkeypatch):
59+
"""Test cache directory from environment variable override."""
60+
monkeypatch.setenv("SPINE_CACHE_DIR", "/custom/cache")
61+
monkeypatch.setenv("SPINE_PROD_BASEDIR", "/opt/spine-prod")
62+
63+
cache_dir = get_cache_dir()
64+
# SPINE_CACHE_DIR should take precedence
65+
assert cache_dir == Path("/custom/cache")
3666

3767
def test_url_to_filename(self):
3868
"""Test URL to filename conversion."""

0 commit comments

Comments
 (0)