pycasher 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pycasher-0.1.0/.gitignore +12 -0
- pycasher-0.1.0/LICENSE +21 -0
- pycasher-0.1.0/PKG-INFO +95 -0
- pycasher-0.1.0/README.md +76 -0
- pycasher-0.1.0/documentation/00-Introduction.md +75 -0
- pycasher-0.1.0/documentation/10-Quick-Start.md +98 -0
- pycasher-0.1.0/documentation/20-API-Reference.md +133 -0
- pycasher-0.1.0/documentation/_last-updated_.txt +1 -0
- pycasher-0.1.0/idea.txt +192 -0
- pycasher-0.1.0/pyproject.toml +47 -0
- pycasher-0.1.0/src/casher/__init__.py +5 -0
- pycasher-0.1.0/src/casher/_runner.py +70 -0
- pycasher-0.1.0/src/casher/acache.py +138 -0
- pycasher-0.1.0/src/casher/audit_hook.py +65 -0
- pycasher-0.1.0/src/casher/auto_cli.py +52 -0
- pycasher-0.1.0/src/casher/capture.py +29 -0
- pycasher-0.1.0/src/casher/config.py +42 -0
- pycasher-0.1.0/src/casher/decorator.py +438 -0
- pycasher-0.1.0/src/casher/deps.py +62 -0
- pycasher-0.1.0/src/casher/eviction.py +81 -0
- pycasher-0.1.0/src/casher/hasher.py +42 -0
- pycasher-0.1.0/src/casher/serializer.py +121 -0
- pycasher-0.1.0/src/casher/store.py +218 -0
- pycasher-0.1.0/src/casher/strace.py +118 -0
- pycasher-0.1.0/src/casher/tests/__init__.py +0 -0
- pycasher-0.1.0/src/casher/tests/config.py +10 -0
- pycasher-0.1.0/src/casher/tests/test_acache.py +222 -0
- pycasher-0.1.0/src/casher/tests/test_audit_hook.py +103 -0
- pycasher-0.1.0/src/casher/tests/test_auto_cli.py +108 -0
- pycasher-0.1.0/src/casher/tests/test_capture.py +88 -0
- pycasher-0.1.0/src/casher/tests/test_decorator.py +541 -0
- pycasher-0.1.0/src/casher/tests/test_deps.py +132 -0
- pycasher-0.1.0/src/casher/tests/test_eviction.py +149 -0
- pycasher-0.1.0/src/casher/tests/test_hasher.py +87 -0
- pycasher-0.1.0/src/casher/tests/test_serializer.py +92 -0
- pycasher-0.1.0/src/casher/tests/test_store.py +186 -0
- pycasher-0.1.0/src/casher/tests/test_strace.py +144 -0
- pycasher-0.1.0/upload_pypi.sh +18 -0
- pycasher-0.1.0/uv.lock +830 -0
pycasher-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 casher contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
pycasher-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pycasher
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Cache function results and side effects (stdout, stderr, file writes) with automatic file I/O discovery via strace or audit hooks
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
License-File: LICENSE
|
|
7
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
8
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
11
|
+
Requires-Python: >=3.12
|
|
12
|
+
Requires-Dist: loguru
|
|
13
|
+
Provides-Extra: pandas
|
|
14
|
+
Requires-Dist: pandas; extra == 'pandas'
|
|
15
|
+
Requires-Dist: pyarrow; extra == 'pandas'
|
|
16
|
+
Provides-Extra: polars
|
|
17
|
+
Requires-Dist: polars; extra == 'polars'
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
|
|
20
|
+
# pycasher
|
|
21
|
+
|
|
22
|
+
Cache Python function results **and their side effects** — stdout, stderr, and filesystem writes — with automatic invalidation.
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
pip install pycasher
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## What makes it different
|
|
29
|
+
|
|
30
|
+
Most caching libraries cache return values. casher also captures and replays:
|
|
31
|
+
|
|
32
|
+
- **stdout/stderr** printed during execution
|
|
33
|
+
- **Files written** by the function (restored from cache on hit)
|
|
34
|
+
- **Files read** by the function (used as cache keys — change an input file, cache auto-invalidates)
|
|
35
|
+
|
|
36
|
+
No manual file declarations needed. casher discovers file I/O automatically via `strace` (subprocess mode) or Python audit hooks (in-process mode).
|
|
37
|
+
|
|
38
|
+
## Usage
|
|
39
|
+
|
|
40
|
+
```python
|
|
41
|
+
from casher import cached
|
|
42
|
+
|
|
43
|
+
@cached
|
|
44
|
+
def train(data_path: str, output_path: str, lr: float = 0.01) -> dict:
|
|
45
|
+
df = read_csv(data_path)
|
|
46
|
+
model = fit(df, lr=lr)
|
|
47
|
+
save(model, output_path)
|
|
48
|
+
return {"accuracy": model.score}
|
|
49
|
+
|
|
50
|
+
# First call — runs function, traces file I/O, caches everything
|
|
51
|
+
result = train("train.csv", "model.pkl")
|
|
52
|
+
|
|
53
|
+
# Second call — instant replay from cache (model.pkl restored too)
|
|
54
|
+
result = train("train.csv", "model.pkl")
|
|
55
|
+
|
|
56
|
+
# Change train.csv — casher detects it, re-runs automatically
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Cache any shell command without code changes:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
acache -- python train.py --data train.csv
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Key features
|
|
66
|
+
|
|
67
|
+
- **Automatic file tracking**: strace (kernel-level, catches C extensions) or audit hooks (zero overhead, Python-only)
|
|
68
|
+
- **Dependency invalidation**: changes to imported `.py` files invalidate the cache
|
|
69
|
+
- **LRU eviction**: configurable via `max_cache_bytes` or `CASHER_MAX_CACHE_BYTES` env var (default 32 GB)
|
|
70
|
+
- **DataFrame support**: polars and pandas DataFrames serialized via Arrow IPC
|
|
71
|
+
- **Environment-aware**: include env vars in cache key with `env_vars=["MY_VAR"]`
|
|
72
|
+
- **Structured logging**: loguru INFO for every call — cache dir, hit/miss, mode, eviction
|
|
73
|
+
|
|
74
|
+
## Configuration
|
|
75
|
+
|
|
76
|
+
| Env var | Default | Description |
|
|
77
|
+
|---------|---------|-------------|
|
|
78
|
+
| `CASHER_CACHE_DIR` | `~/.cache/casher` | Cache storage directory |
|
|
79
|
+
| `CASHER_MAX_CACHE_BYTES` | `34359738368` (32 GB) | Max cache size before LRU eviction |
|
|
80
|
+
|
|
81
|
+
## Platform support
|
|
82
|
+
|
|
83
|
+
Full caching on **Linux** only (requires strace for subprocess mode, fcntl for locking). On macOS and Windows the decorator is a transparent pass-through — functions execute normally, caching is skipped with a one-time warning.
|
|
84
|
+
|
|
85
|
+
## Documentation
|
|
86
|
+
|
|
87
|
+
See [documentation/](documentation/) for detailed docs:
|
|
88
|
+
|
|
89
|
+
- [Introduction](documentation/00-Introduction.md) — architecture, limitations, in-process vs subprocess comparison
|
|
90
|
+
- [Quick Start](documentation/10-Quick-Start.md) — installation, decorator options, CLI usage
|
|
91
|
+
- [API Reference](documentation/20-API-Reference.md) — full API surface
|
|
92
|
+
|
|
93
|
+
## License
|
|
94
|
+
|
|
95
|
+
MIT
|
pycasher-0.1.0/README.md
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# pycasher
|
|
2
|
+
|
|
3
|
+
Cache Python function results **and their side effects** — stdout, stderr, and filesystem writes — with automatic invalidation.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
pip install pycasher
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## What makes it different
|
|
10
|
+
|
|
11
|
+
Most caching libraries cache return values. casher also captures and replays:
|
|
12
|
+
|
|
13
|
+
- **stdout/stderr** printed during execution
|
|
14
|
+
- **Files written** by the function (restored from cache on hit)
|
|
15
|
+
- **Files read** by the function (used as cache keys — change an input file, cache auto-invalidates)
|
|
16
|
+
|
|
17
|
+
No manual file declarations needed. casher discovers file I/O automatically via `strace` (subprocess mode) or Python audit hooks (in-process mode).
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
```python
|
|
22
|
+
from casher import cached
|
|
23
|
+
|
|
24
|
+
@cached
|
|
25
|
+
def train(data_path: str, output_path: str, lr: float = 0.01) -> dict:
|
|
26
|
+
df = read_csv(data_path)
|
|
27
|
+
model = fit(df, lr=lr)
|
|
28
|
+
save(model, output_path)
|
|
29
|
+
return {"accuracy": model.score}
|
|
30
|
+
|
|
31
|
+
# First call — runs function, traces file I/O, caches everything
|
|
32
|
+
result = train("train.csv", "model.pkl")
|
|
33
|
+
|
|
34
|
+
# Second call — instant replay from cache (model.pkl restored too)
|
|
35
|
+
result = train("train.csv", "model.pkl")
|
|
36
|
+
|
|
37
|
+
# Change train.csv — casher detects it, re-runs automatically
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Cache any shell command without code changes:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
acache -- python train.py --data train.csv
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Key features
|
|
47
|
+
|
|
48
|
+
- **Automatic file tracking**: strace (kernel-level, catches C extensions) or audit hooks (zero overhead, Python-only)
|
|
49
|
+
- **Dependency invalidation**: changes to imported `.py` files invalidate the cache
|
|
50
|
+
- **LRU eviction**: configurable via `max_cache_bytes` or `CASHER_MAX_CACHE_BYTES` env var (default 32 GB)
|
|
51
|
+
- **DataFrame support**: polars and pandas DataFrames serialized via Arrow IPC
|
|
52
|
+
- **Environment-aware**: include env vars in cache key with `env_vars=["MY_VAR"]`
|
|
53
|
+
- **Structured logging**: loguru INFO for every call — cache dir, hit/miss, mode, eviction
|
|
54
|
+
|
|
55
|
+
## Configuration
|
|
56
|
+
|
|
57
|
+
| Env var | Default | Description |
|
|
58
|
+
|---------|---------|-------------|
|
|
59
|
+
| `CASHER_CACHE_DIR` | `~/.cache/casher` | Cache storage directory |
|
|
60
|
+
| `CASHER_MAX_CACHE_BYTES` | `34359738368` (32 GB) | Max cache size before LRU eviction |
|
|
61
|
+
|
|
62
|
+
## Platform support
|
|
63
|
+
|
|
64
|
+
Full caching on **Linux** only (requires strace for subprocess mode, fcntl for locking). On macOS and Windows the decorator is a transparent pass-through — functions execute normally, caching is skipped with a one-time warning.
|
|
65
|
+
|
|
66
|
+
## Documentation
|
|
67
|
+
|
|
68
|
+
See [documentation/](documentation/) for detailed docs:
|
|
69
|
+
|
|
70
|
+
- [Introduction](documentation/00-Introduction.md) — architecture, limitations, in-process vs subprocess comparison
|
|
71
|
+
- [Quick Start](documentation/10-Quick-Start.md) — installation, decorator options, CLI usage
|
|
72
|
+
- [API Reference](documentation/20-API-Reference.md) — full API surface
|
|
73
|
+
|
|
74
|
+
## License
|
|
75
|
+
|
|
76
|
+
MIT
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# casher — Function Result Cache with Side-Effect Capture
|
|
2
|
+
|
|
3
|
+
`casher` caches Python function results **and** their side effects
|
|
4
|
+
(stdout, stderr, filesystem writes). It automatically discovers file I/O
|
|
5
|
+
via `strace` (subprocess mode) or `sys.addaudithook` (in-process mode),
|
|
6
|
+
so cache invalidation happens without explicit file declarations.
|
|
7
|
+
|
|
8
|
+
Install from PyPI: `pip install pycasher`
|
|
9
|
+
|
|
10
|
+
## What it provides
|
|
11
|
+
|
|
12
|
+
- A `@cached` decorator that transparently caches any Python function.
|
|
13
|
+
- Automatic file I/O tracking — reads become cache keys, writes are
|
|
14
|
+
restored on cache hit.
|
|
15
|
+
- Two-phase cache lookup: partial key (function + args) → full key
|
|
16
|
+
(partial + input file hashes).
|
|
17
|
+
- Dependency tracking — changes to imported modules invalidate the cache.
|
|
18
|
+
- LRU eviction with configurable `max_cache_bytes` (default 32 GB).
|
|
19
|
+
- `acache` CLI tool for caching arbitrary shell commands.
|
|
20
|
+
- `auto_cli` helper to generate argparse CLIs from decorated functions.
|
|
21
|
+
- Polars and pandas DataFrame serialization via Arrow IPC.
|
|
22
|
+
- Structured logging via loguru at INFO level.
|
|
23
|
+
|
|
24
|
+
## Configuration via environment variables
|
|
25
|
+
|
|
26
|
+
| Variable | Default | Description |
|
|
27
|
+
|----------|---------|-------------|
|
|
28
|
+
| `CASHER_CACHE_DIR` | `~/.cache/casher` | Cache storage directory |
|
|
29
|
+
| `CASHER_MAX_CACHE_BYTES` | `34359738368` (32 GB) | Max total cache size before LRU eviction |
|
|
30
|
+
|
|
31
|
+
These are used when no explicit value is passed to the `@cached` decorator
|
|
32
|
+
or the `acache` CLI.
|
|
33
|
+
|
|
34
|
+
## Cross-platform behavior
|
|
35
|
+
|
|
36
|
+
casher's full feature set (strace-based file tracking, `fcntl` locking)
|
|
37
|
+
requires Linux. On **macOS** and **Windows**, caching is automatically
|
|
38
|
+
disabled with a `logger.warning`. The decorated function still runs
|
|
39
|
+
normally — it just never caches.
|
|
40
|
+
|
|
41
|
+
## In-process vs. subprocess mode
|
|
42
|
+
|
|
43
|
+
| Aspect | `subprocess=True` (default) | `subprocess=False` |
|
|
44
|
+
|--------|----------------------------|---------------------|
|
|
45
|
+
| File tracking | strace — kernel-level, catches all I/O including from C extensions and child processes | `sys.addaudithook` — Python-level, catches only `open()` calls from Python code |
|
|
46
|
+
| Dynamic imports | Fully captured (subprocess loads fresh) | May be missed if imported after function entry |
|
|
47
|
+
| Isolation | Function runs in a separate process — no side effects on caller's globals | Function runs in the same process — shared state, faster startup |
|
|
48
|
+
| Overhead | ~5–15% from strace tracing | Near-zero |
|
|
49
|
+
| Requirements | strace installed, Linux | Python 3.12+, any OS (but caching only active on Linux) |
|
|
50
|
+
| Best for | Data pipelines, scripts with C extensions, shell commands | Pure-Python functions, fast inner loops, environments without strace |
|
|
51
|
+
|
|
52
|
+
**Why not always use in-process?** The audit hook only intercepts Python's
|
|
53
|
+
built-in `open()`. File I/O from C extensions (numpy, pandas, polars
|
|
54
|
+
native readers), subprocess calls, or `os.read()`/`os.write()` is
|
|
55
|
+
invisible to it. strace intercepts at the kernel level, so nothing escapes.
|
|
56
|
+
|
|
57
|
+
## Limitations
|
|
58
|
+
|
|
59
|
+
- **Linux only** for caching. On macOS/Windows the decorator is a
|
|
60
|
+
transparent pass-through with a one-time warning.
|
|
61
|
+
- **strace in Docker**: requires `--cap-add=SYS_PTRACE` or an equivalent
|
|
62
|
+
seccomp profile that allows the `ptrace` syscall.
|
|
63
|
+
- **Security**: cache entries use pickle. Never point `cache_dir` at a
|
|
64
|
+
shared or untrusted directory. Keep cache directories user-writable only.
|
|
65
|
+
- **strace overhead**: ~5–15% for typical data-processing functions.
|
|
66
|
+
Negligible for functions taking seconds or longer. For sub-millisecond
|
|
67
|
+
functions, use `subprocess=False`.
|
|
68
|
+
- **No exception caching.** Failed function calls are never cached.
|
|
69
|
+
- **No concurrent write safety** beyond `fcntl.flock`. Do not share
|
|
70
|
+
cache directories across networked filesystems.
|
|
71
|
+
|
|
72
|
+
## Runtime dependencies
|
|
73
|
+
|
|
74
|
+
Only `loguru`. Polars and pandas support is optional — detected at
|
|
75
|
+
runtime via `type(val).__module__`.
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# Quick Start
|
|
2
|
+
|
|
3
|
+
## Installation
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
pip install pycasher
|
|
7
|
+
# Optional DataFrame support:
|
|
8
|
+
pip install pycasher[polars]
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Decorator usage
|
|
12
|
+
|
|
13
|
+
```python
|
|
14
|
+
from casher import cached
|
|
15
|
+
|
|
16
|
+
@cached
|
|
17
|
+
def transform(input_path: str, output_path: str, threshold: float = 0.5) -> int:
|
|
18
|
+
import polars as pl
|
|
19
|
+
df = pl.read_csv(input_path)
|
|
20
|
+
df = df.filter(pl.col("score") > threshold)
|
|
21
|
+
df.write_parquet(output_path)
|
|
22
|
+
return len(df)
|
|
23
|
+
|
|
24
|
+
# First call — runs the function, caches result + side effects
|
|
25
|
+
result = transform("data.csv", "output.parquet", threshold=0.3)
|
|
26
|
+
|
|
27
|
+
# Second call — cache hit, restores output.parquet from cache
|
|
28
|
+
result = transform("data.csv", "output.parquet", threshold=0.3)
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Decorator options
|
|
32
|
+
|
|
33
|
+
```python
|
|
34
|
+
@cached(
|
|
35
|
+
cache_dir="~/.cache/casher", # default cache location
|
|
36
|
+
subprocess=True, # True=strace (default), False=audit hooks
|
|
37
|
+
enabled=True, # set False to bypass caching
|
|
38
|
+
dep_roots=None, # directories to scan for dependency changes
|
|
39
|
+
input_files=None, # extra files to include in cache key
|
|
40
|
+
ignore_files=None, # glob patterns to exclude from tracking
|
|
41
|
+
env_vars=None, # environment variables to include in cache key
|
|
42
|
+
max_cache_bytes=0, # 0=unlimited, default 32 GB via env var
|
|
43
|
+
)
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## In-process mode
|
|
47
|
+
|
|
48
|
+
When strace is unavailable or overhead matters, use audit hooks:
|
|
49
|
+
|
|
50
|
+
```python
|
|
51
|
+
@cached(subprocess=False)
|
|
52
|
+
def process(path: str) -> str:
|
|
53
|
+
with open(path) as f:
|
|
54
|
+
return f.read().upper()
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
File I/O is tracked via `sys.addaudithook`. No subprocess is spawned.
|
|
58
|
+
|
|
59
|
+
## CLI caching with acache
|
|
60
|
+
|
|
61
|
+
Cache any shell command:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
# First run — traces file I/O, caches result
|
|
65
|
+
acache -- python train.py --data train.csv
|
|
66
|
+
|
|
67
|
+
# Second run — cache hit if train.csv unchanged
|
|
68
|
+
acache -- python train.py --data train.csv
|
|
69
|
+
|
|
70
|
+
# Custom cache directory
|
|
71
|
+
acache --cache-dir /tmp/mycache -- python train.py --data train.csv
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Auto-CLI from decorated functions
|
|
75
|
+
|
|
76
|
+
```python
|
|
77
|
+
# transform.py
|
|
78
|
+
from casher import cached
|
|
79
|
+
from casher.auto_cli import run
|
|
80
|
+
|
|
81
|
+
@cached
|
|
82
|
+
def transform(input_path: str, output_path: str, threshold: float = 0.5) -> int:
|
|
83
|
+
...
|
|
84
|
+
|
|
85
|
+
if __name__ == "__main__":
|
|
86
|
+
run(transform)
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
python transform.py data.csv output.parquet --threshold 0.3
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Running tests
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
cd casher
|
|
97
|
+
./test.sh
|
|
98
|
+
```
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# API Reference
|
|
2
|
+
|
|
3
|
+
## `casher.cached`
|
|
4
|
+
|
|
5
|
+
```python
|
|
6
|
+
from casher import cached
|
|
7
|
+
|
|
8
|
+
@cached(
|
|
9
|
+
cache_dir: str | Path = "~/.cache/casher",
|
|
10
|
+
subprocess: bool = True,
|
|
11
|
+
enabled: bool = True,
|
|
12
|
+
dep_roots: list[str] | None = None,
|
|
13
|
+
input_files: list[str] | None = None,
|
|
14
|
+
ignore_files: list[str] | None = None,
|
|
15
|
+
env_vars: list[str] | None = None,
|
|
16
|
+
max_cache_bytes: int = 0,
|
|
17
|
+
)
|
|
18
|
+
def my_func(...) -> ...:
|
|
19
|
+
...
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
| Parameter | Description |
|
|
23
|
+
| ----------------- | ------------------------------------------------------------------------------------------------------ |
|
|
24
|
+
| `cache_dir` | Directory for cache storage. Default: `CASHER_CACHE_DIR` env var, then `~/.cache/casher`. |
|
|
25
|
+
| `subprocess` | `True`: run in subprocess with strace tracking. `False`: run in-process with audit hooks. |
|
|
26
|
+
| `enabled` | Set `False` to bypass caching entirely. Also auto-disabled on non-Linux. |
|
|
27
|
+
| `dep_roots` | Directories to scan for Python dependency changes. `None` = auto-detect from function module location. |
|
|
28
|
+
| `input_files` | Extra files to include in cache key beyond auto-discovered ones. |
|
|
29
|
+
| `ignore_files` | Glob patterns for files to exclude from cache key (e.g., `["*.log"]`). |
|
|
30
|
+
| `env_vars` | Environment variable names to include in cache key. |
|
|
31
|
+
| `max_cache_bytes` | Maximum total cache size in bytes. Default: `CASHER_MAX_CACHE_BYTES` env var, then 32 GB. `0` = unlimited. |
|
|
32
|
+
|
|
33
|
+
## Cache key computation
|
|
34
|
+
|
|
35
|
+
1. **Partial key** = `sha256(module + func_name + canonical_args + dep_hash + env_hash)`
|
|
36
|
+
2. **Full key** = `sha256(partial_key + input_file_hashes)`
|
|
37
|
+
|
|
38
|
+
Cache directory layout: `<cache_dir>/<partial_key>/<full_key>/meta.json`
|
|
39
|
+
|
|
40
|
+
## `casher.auto_cli.run`
|
|
41
|
+
|
|
42
|
+
```python
|
|
43
|
+
from casher.auto_cli import run
|
|
44
|
+
run(func)
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Generates an `argparse.ArgumentParser` from the function's signature and
|
|
48
|
+
type annotations, parses `sys.argv`, and calls the function.
|
|
49
|
+
|
|
50
|
+
| Annotation | argparse type |
|
|
51
|
+
| ---------- | ---------------------------- |
|
|
52
|
+
| `str` | `str` |
|
|
53
|
+
| `int` | `int` |
|
|
54
|
+
| `float` | `float` |
|
|
55
|
+
| `bool` | `store_true` / `store_false` |
|
|
56
|
+
| `Path` | `Path` |
|
|
57
|
+
|
|
58
|
+
## `acache` CLI
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
acache [--cache-dir DIR] [--max-cache-bytes N] -- command...
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Caches arbitrary CLI programs using strace for I/O tracking. Requires
|
|
65
|
+
strace to be installed.
|
|
66
|
+
|
|
67
|
+
## `casher.store`
|
|
68
|
+
|
|
69
|
+
```python
|
|
70
|
+
from casher.store import find_cached, store_result, invalidate, clear_cache
|
|
71
|
+
|
|
72
|
+
# Look up cache entry
|
|
73
|
+
result = find_cached(cache_dir, partial_key) # -> (CacheEntry, Path) | None
|
|
74
|
+
|
|
75
|
+
# Store a new entry
|
|
76
|
+
store_result(cache_dir, partial_key, file_hash, entry, max_bytes=0)
|
|
77
|
+
|
|
78
|
+
# Remove entries for a partial key
|
|
79
|
+
invalidate(cache_dir, partial_key) # -> bool
|
|
80
|
+
|
|
81
|
+
# Clear entire cache
|
|
82
|
+
clear_cache(cache_dir) # -> int (entries removed)
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## `casher.store.CacheEntry`
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
@dataclasses.dataclass
|
|
89
|
+
class CacheEntry:
|
|
90
|
+
return_value: object
|
|
91
|
+
stdout: str
|
|
92
|
+
stderr: str
|
|
93
|
+
output_files: dict[str, Path]
|
|
94
|
+
input_files: dict[str, str]
|
|
95
|
+
created_at: float
|
|
96
|
+
func_module: str
|
|
97
|
+
func_name: str
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## `casher.strace`
|
|
101
|
+
|
|
102
|
+
```python
|
|
103
|
+
from casher.strace import run_with_strace, is_strace_available
|
|
104
|
+
|
|
105
|
+
available = is_strace_available() # -> bool
|
|
106
|
+
result = run_with_strace(["python", "script.py"])
|
|
107
|
+
# result.read_files: list[Path]
|
|
108
|
+
# result.write_files: list[Path]
|
|
109
|
+
# result.stdout: str
|
|
110
|
+
# result.stderr: str
|
|
111
|
+
# result.returncode: int
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## `casher.audit_hook`
|
|
115
|
+
|
|
116
|
+
```python
|
|
117
|
+
from casher.audit_hook import track_file_io
|
|
118
|
+
|
|
119
|
+
with track_file_io() as tracker:
|
|
120
|
+
with open("data.txt") as f:
|
|
121
|
+
f.read()
|
|
122
|
+
# tracker.read_files: set[Path]
|
|
123
|
+
# tracker.write_files: set[Path]
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## `casher.eviction`
|
|
127
|
+
|
|
128
|
+
```python
|
|
129
|
+
from casher.eviction import evict_if_needed, get_cache_size
|
|
130
|
+
|
|
131
|
+
evicted = evict_if_needed(cache_dir, max_bytes) # -> int
|
|
132
|
+
total = get_cache_size(cache_dir) # -> int (bytes)
|
|
133
|
+
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
6ec95a80 # initial casher documentation
|