varve 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.
- varve-0.1.0/.github/workflows/ci.yml +53 -0
- varve-0.1.0/.github/workflows/release.yml +96 -0
- varve-0.1.0/.gitignore +6 -0
- varve-0.1.0/.pre-commit-config.yaml +9 -0
- varve-0.1.0/.release-please-manifest.json +3 -0
- varve-0.1.0/AGENTS.md +21 -0
- varve-0.1.0/ARCHITECTURE.md +107 -0
- varve-0.1.0/CHANGELOG.md +62 -0
- varve-0.1.0/CONTRIBUTING.md +37 -0
- varve-0.1.0/LICENSE +21 -0
- varve-0.1.0/PKG-INFO +193 -0
- varve-0.1.0/README.md +161 -0
- varve-0.1.0/pyproject.toml +67 -0
- varve-0.1.0/release-please-config.json +10 -0
- varve-0.1.0/src/varve/__init__.py +16 -0
- varve-0.1.0/src/varve/branch.py +92 -0
- varve-0.1.0/src/varve/branch_config.py +172 -0
- varve-0.1.0/src/varve/cli/app.py +297 -0
- varve-0.1.0/src/varve/cli/argmap.py +226 -0
- varve-0.1.0/src/varve/cli/clean.py +118 -0
- varve-0.1.0/src/varve/context.py +164 -0
- varve-0.1.0/src/varve/dashboard/cli.py +139 -0
- varve-0.1.0/src/varve/dashboard/discovery.py +89 -0
- varve-0.1.0/src/varve/dashboard/models.py +50 -0
- varve-0.1.0/src/varve/dashboard/render.py +136 -0
- varve-0.1.0/src/varve/dashboard/state.py +162 -0
- varve-0.1.0/src/varve/decorators.py +102 -0
- varve-0.1.0/src/varve/engine/runner.py +549 -0
- varve-0.1.0/src/varve/engine/state.py +114 -0
- varve-0.1.0/src/varve/keying/astkey.py +76 -0
- varve-0.1.0/src/varve/keying/fingerprint.py +106 -0
- varve-0.1.0/src/varve/keying/keys.py +258 -0
- varve-0.1.0/src/varve/keyspec.py +23 -0
- varve-0.1.0/src/varve/log.py +15 -0
- varve-0.1.0/src/varve/models.py +86 -0
- varve-0.1.0/src/varve/pipeline.py +127 -0
- varve-0.1.0/src/varve/py.typed +1 -0
- varve-0.1.0/src/varve/store/lock.py +79 -0
- varve-0.1.0/src/varve/store/store.py +143 -0
- varve-0.1.0/tests/test_argmap.py +194 -0
- varve-0.1.0/tests/test_astkey.py +56 -0
- varve-0.1.0/tests/test_branch.py +16 -0
- varve-0.1.0/tests/test_branch_config.py +55 -0
- varve-0.1.0/tests/test_clean.py +221 -0
- varve-0.1.0/tests/test_cli.py +640 -0
- varve-0.1.0/tests/test_collection.py +79 -0
- varve-0.1.0/tests/test_context.py +191 -0
- varve-0.1.0/tests/test_dashboard_cli.py +500 -0
- varve-0.1.0/tests/test_dashboard_discovery.py +145 -0
- varve-0.1.0/tests/test_dashboard_state.py +204 -0
- varve-0.1.0/tests/test_experiment.py +63 -0
- varve-0.1.0/tests/test_fingerprint.py +53 -0
- varve-0.1.0/tests/test_keys.py +411 -0
- varve-0.1.0/tests/test_lock.py +33 -0
- varve-0.1.0/tests/test_runner.py +451 -0
- varve-0.1.0/tests/test_runner_branch.py +70 -0
- varve-0.1.0/tests/test_runner_log.py +35 -0
- varve-0.1.0/tests/test_state.py +236 -0
- varve-0.1.0/tests/test_store.py +86 -0
- varve-0.1.0/uv.lock +508 -0
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
push:
|
|
6
|
+
branches:
|
|
7
|
+
- main
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
concurrency:
|
|
13
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
14
|
+
cancel-in-progress: true
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
test:
|
|
18
|
+
name: Python ${{ matrix.python-version }}
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
strategy:
|
|
21
|
+
fail-fast: false
|
|
22
|
+
matrix:
|
|
23
|
+
python-version: ["3.10", "3.11", "3.12", "3.13"]
|
|
24
|
+
|
|
25
|
+
steps:
|
|
26
|
+
- name: Check out repository
|
|
27
|
+
uses: actions/checkout@v6
|
|
28
|
+
with:
|
|
29
|
+
persist-credentials: false
|
|
30
|
+
|
|
31
|
+
- name: Set up Python
|
|
32
|
+
uses: actions/setup-python@v6
|
|
33
|
+
with:
|
|
34
|
+
python-version: ${{ matrix.python-version }}
|
|
35
|
+
|
|
36
|
+
- name: Set up uv
|
|
37
|
+
uses: astral-sh/setup-uv@v7
|
|
38
|
+
|
|
39
|
+
- name: Install dependencies
|
|
40
|
+
run: uv sync --extra dev
|
|
41
|
+
|
|
42
|
+
- name: Ruff lint
|
|
43
|
+
run: uv run ruff check .
|
|
44
|
+
|
|
45
|
+
- name: Ruff format
|
|
46
|
+
run: uv run ruff format --check .
|
|
47
|
+
|
|
48
|
+
- name: Tests
|
|
49
|
+
run: uv run pytest
|
|
50
|
+
|
|
51
|
+
- name: Pyright pre-flight
|
|
52
|
+
continue-on-error: true
|
|
53
|
+
run: uv run pyright
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
concurrency:
|
|
13
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
14
|
+
cancel-in-progress: false
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
release-please:
|
|
18
|
+
name: Release PR
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
if: github.event_name == 'push'
|
|
21
|
+
permissions:
|
|
22
|
+
contents: write
|
|
23
|
+
issues: write
|
|
24
|
+
pull-requests: write
|
|
25
|
+
outputs:
|
|
26
|
+
release_created: ${{ steps.release.outputs.release_created }}
|
|
27
|
+
tag_name: ${{ steps.release.outputs.tag_name }}
|
|
28
|
+
version: ${{ steps.release.outputs.version }}
|
|
29
|
+
|
|
30
|
+
steps:
|
|
31
|
+
- name: Create or finalize release PR
|
|
32
|
+
id: release
|
|
33
|
+
uses: googleapis/release-please-action@v4
|
|
34
|
+
with:
|
|
35
|
+
token: ${{ secrets.RELEASE_PLEASE_TOKEN || github.token }}
|
|
36
|
+
config-file: release-please-config.json
|
|
37
|
+
manifest-file: .release-please-manifest.json
|
|
38
|
+
|
|
39
|
+
build:
|
|
40
|
+
name: Build distribution
|
|
41
|
+
needs: release-please
|
|
42
|
+
if: ${{ always() && (github.event_name == 'workflow_dispatch' || needs.release-please.outputs.release_created == 'true') }}
|
|
43
|
+
runs-on: ubuntu-latest
|
|
44
|
+
|
|
45
|
+
steps:
|
|
46
|
+
- name: Check out repository
|
|
47
|
+
uses: actions/checkout@v6
|
|
48
|
+
with:
|
|
49
|
+
persist-credentials: false
|
|
50
|
+
|
|
51
|
+
- name: Set up Python
|
|
52
|
+
uses: actions/setup-python@v6
|
|
53
|
+
with:
|
|
54
|
+
python-version: "3.x"
|
|
55
|
+
|
|
56
|
+
- name: Set up uv
|
|
57
|
+
uses: astral-sh/setup-uv@v7
|
|
58
|
+
|
|
59
|
+
- name: Build source and wheel distributions
|
|
60
|
+
run: uv build --no-sources
|
|
61
|
+
|
|
62
|
+
- name: Smoke install from sdist
|
|
63
|
+
run: |
|
|
64
|
+
python -m venv /tmp/varve-smoke
|
|
65
|
+
/tmp/varve-smoke/bin/python -m pip install dist/*.tar.gz
|
|
66
|
+
/tmp/varve-smoke/bin/python -c "import varve; varve.Pipeline"
|
|
67
|
+
|
|
68
|
+
- name: Store distribution packages
|
|
69
|
+
uses: actions/upload-artifact@v5
|
|
70
|
+
with:
|
|
71
|
+
name: python-package-distributions
|
|
72
|
+
path: dist/
|
|
73
|
+
|
|
74
|
+
publish-to-pypi:
|
|
75
|
+
name: Publish to PyPI
|
|
76
|
+
needs:
|
|
77
|
+
- release-please
|
|
78
|
+
- build
|
|
79
|
+
runs-on: ubuntu-latest
|
|
80
|
+
if: needs.release-please.outputs.release_created == 'true'
|
|
81
|
+
environment:
|
|
82
|
+
name: pypi
|
|
83
|
+
url: https://pypi.org/p/varve
|
|
84
|
+
permissions:
|
|
85
|
+
contents: read
|
|
86
|
+
id-token: write
|
|
87
|
+
|
|
88
|
+
steps:
|
|
89
|
+
- name: Download distribution packages
|
|
90
|
+
uses: actions/download-artifact@v6
|
|
91
|
+
with:
|
|
92
|
+
name: python-package-distributions
|
|
93
|
+
path: dist/
|
|
94
|
+
|
|
95
|
+
- name: Publish distribution to PyPI
|
|
96
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
varve-0.1.0/.gitignore
ADDED
varve-0.1.0/AGENTS.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
## Read First
|
|
4
|
+
|
|
5
|
+
- User-facing positioning and examples: `README.md`.
|
|
6
|
+
- Package layout, dependency direction, cache/store, CLI/config, clean, and dashboard boundaries: `ARCHITECTURE.md`.
|
|
7
|
+
- Contributor setup, public API policy, style, and Conventional Commits: `CONTRIBUTING.md`.
|
|
8
|
+
|
|
9
|
+
## Agent Rules
|
|
10
|
+
|
|
11
|
+
`varve` is an independent Python infrastructure submodule. Documentation, comments, examples, and user-facing messages in this submodule must be English.
|
|
12
|
+
|
|
13
|
+
Keep the public import surface small:
|
|
14
|
+
|
|
15
|
+
```python
|
|
16
|
+
from varve import Ctx, Pipeline, JSON, KeySpec, StageSpec, batch_stage, stage
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Prefer compact pre-1.0 APIs over compatibility shims. If an old public name is awkward and there are no external users, update current callers and docs instead of keeping deprecated aliases.
|
|
20
|
+
|
|
21
|
+
When changing author-facing behavior, update `README.md` and `ARCHITECTURE.md` in the same change. Release/version/changelog design lives in the workspace spec, not in this submodule.
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# varve Architecture
|
|
2
|
+
|
|
3
|
+
`varve` is a small single-machine runner for Python-defined experiment pipelines with a materialized, content-addressed cache. Users define `Pipeline` classes and stages; varve owns branch-aware output roots, cache keys, store records, generated CLI commands, and clean/status behavior.
|
|
4
|
+
|
|
5
|
+
## Package Layout
|
|
6
|
+
|
|
7
|
+
```text
|
|
8
|
+
src/varve/
|
|
9
|
+
├── __init__.py # public re-export surface
|
|
10
|
+
├── pipeline.py # Pipeline base class, stage collection, CLI hook
|
|
11
|
+
├── decorators.py # @stage, @batch_stage, StageSpec
|
|
12
|
+
├── context.py # Ctx passed to stage methods
|
|
13
|
+
├── branch.py # varve.yaml and override branch helpers
|
|
14
|
+
├── branch_config.py # Config construction and output-root selection
|
|
15
|
+
├── keyspec.py # JSON and KeySpec declarations
|
|
16
|
+
├── models.py # persisted pydantic store models
|
|
17
|
+
├── keying/ # source/file/config/upstream key components
|
|
18
|
+
├── store/ # file lock and latest-wins Store
|
|
19
|
+
├── engine/ # cache-state decisions and runner
|
|
20
|
+
├── cli/ # generated Pipeline.cli() commands
|
|
21
|
+
└── dashboard/ # varve ls/show/refresh over existing stores
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Public Surface
|
|
25
|
+
|
|
26
|
+
Only these names are exported from `varve.__all__`:
|
|
27
|
+
|
|
28
|
+
```python
|
|
29
|
+
from varve import Ctx, Pipeline, JSON, KeySpec, StageSpec, batch_stage, stage
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Everything else is internal unless this document or `README.md` says otherwise. `Store`, persisted models, keying helpers, runner helpers, and dashboard models may be used by internal code and tests through full module paths, but they are not public API.
|
|
33
|
+
|
|
34
|
+
## Dependency Direction
|
|
35
|
+
|
|
36
|
+
- Low-level packages: `keying`, `store`, and `engine.state`. They depend only on leaf modules such as `models`, `log`, and `keyspec`.
|
|
37
|
+
- Middle layer: `branch_config` and `engine.runner`.
|
|
38
|
+
- Top layers: `cli` and `dashboard`.
|
|
39
|
+
- Public-facing modules such as `pipeline`, `decorators`, and `context` may use internals to keep the user API small.
|
|
40
|
+
- The only intentional reverse edge is the lazy import inside `Pipeline.cli()`: `from varve.cli.app import main`.
|
|
41
|
+
|
|
42
|
+
There is no import-direction tool. Keep the graph boring by review.
|
|
43
|
+
|
|
44
|
+
## Cache And Store
|
|
45
|
+
|
|
46
|
+
The store lives under `<output_root>/.varve/` and is latest-wins, not append-only:
|
|
47
|
+
|
|
48
|
+
```text
|
|
49
|
+
.varve/
|
|
50
|
+
├── manifest.json
|
|
51
|
+
├── lock
|
|
52
|
+
├── stages/<stage>.json
|
|
53
|
+
├── attempts/<stage>.json
|
|
54
|
+
└── partial/<stage>/<run_key>/
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
`content_key` includes stage source, discovered project callables, full `Config`, declared `KeySpec.files`, declared `KeySpec.values`, and upstream content keys. `run_key` adds batch partition values.
|
|
58
|
+
|
|
59
|
+
Recorded artifact paths are output-root-relative. Stage bodies should write through `ctx.out`.
|
|
60
|
+
|
|
61
|
+
Stage bodies read upstream outputs through `ctx.input(stage)` for exactly one path or `ctx.inputs(stage)` for a list of paths. Both helpers require `stage` to be declared in the current stage's `needs=` list, because only declared upstreams are folded into the content key.
|
|
62
|
+
|
|
63
|
+
Known cache states are `dirty`, `hit`, `artifact-missing`, `stale`, `no-cache`, `resume`, and `unrecoverable`.
|
|
64
|
+
|
|
65
|
+
## Output Roots And Branches
|
|
66
|
+
|
|
67
|
+
`Pipeline.default_output_root(config)` returns the base output root. The CLI can override that with `--out`. Varve then appends the selected branch:
|
|
68
|
+
|
|
69
|
+
```text
|
|
70
|
+
base/<branch> # persistent branches
|
|
71
|
+
base/.tmp/<branch> # temporary override branches
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
`varve.yaml` is discovered next to the pipeline module. Missing `varve.yaml` is allowed for `main`.
|
|
75
|
+
|
|
76
|
+
## CLI And Config
|
|
77
|
+
|
|
78
|
+
`Pipeline.cli(argv)` delegates to `varve.cli.app.main` and provides `run`, `status`, `plan`, `list`, and `clean`.
|
|
79
|
+
|
|
80
|
+
`argparse` parses commands and generated `Args` flags. `pydantic-settings` builds semantic `Config` values from branch/override values, environment variables, `.env`, and model defaults.
|
|
81
|
+
|
|
82
|
+
Config priority:
|
|
83
|
+
|
|
84
|
+
```text
|
|
85
|
+
branch or override value > env > dotenv (.env) > field default
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Do not add Click or Typer. The strict `argparse` behavior is intentional.
|
|
89
|
+
|
|
90
|
+
## Clean Safety
|
|
91
|
+
|
|
92
|
+
All clean operations require a valid `.varve/manifest.json` anchor under the selected output root.
|
|
93
|
+
|
|
94
|
+
Full clean removes the whole output root after rejecting dangerous roots such as empty paths, `/`, the home directory, and the current working directory. Pipelines can narrow allowed full-clean roots by overriding `Pipeline.clean_roots(config)`.
|
|
95
|
+
|
|
96
|
+
Per-stage clean only deletes recorded artifacts and store records for the selected downstream closure. It does not use `allowed_roots`; its boundary is the manifest anchor plus recorded artifact paths.
|
|
97
|
+
|
|
98
|
+
## Dashboard
|
|
99
|
+
|
|
100
|
+
The top-level `varve` console script reads existing stores.
|
|
101
|
+
|
|
102
|
+
Temporary branches under `out/.tmp` are filtered by default and included only with `--include-temp`. Discovery is zero-import; state rendering imports stored manifest modules only after discovery. `refresh` runs branches whose evaluated status is executable: `artifact-missing`, `dirty`, `no-cache`, `resume`, or `stale`.
|
|
103
|
+
|
|
104
|
+
## Known Limitations
|
|
105
|
+
|
|
106
|
+
- Source fingerprints use `ast.dump`; a CPython minor-version upgrade may invalidate caches.
|
|
107
|
+
- Windows is not supported yet because locking uses `fcntl`.
|
varve-0.1.0/CHANGELOG.md
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.0 (2026-07-05)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### ⚠ BREAKING CHANGES
|
|
7
|
+
|
|
8
|
+
* ctx.input now requires exactly one output; use ctx.inputs for upstream stages with zero or multiple outputs.
|
|
9
|
+
* rename Experiment to Pipeline
|
|
10
|
+
* removes file_set, __version__, the Ctx ledger alias, the corrupt-store status, KeySpec.coerce, and the top-level dashboard --include-temp compatibility path.
|
|
11
|
+
* **keying:** enable automatic source uses
|
|
12
|
+
* **dashboard:** evaluate status through engine
|
|
13
|
+
* **cli:** redesign generated commands
|
|
14
|
+
* **core:** rename branches.yaml to varve.yaml
|
|
15
|
+
* **core:** KeySpec.config is removed and the full Config now enters the content key; Experiment.output_root gained branch/is_temporary and resolve_output_root is gone; `--config` now points to branches.yaml and semantic flags are replaced by --branch/--override/--name.
|
|
16
|
+
* **cli:** own output root resolution
|
|
17
|
+
|
|
18
|
+
### Features
|
|
19
|
+
|
|
20
|
+
* add file set key helper ([ab1046a](https://github.com/moeakwak/varve/commit/ab1046a069a354e5553717ce732272948d77235f))
|
|
21
|
+
* **cli:** own output root resolution ([04b93ff](https://github.com/moeakwak/varve/commit/04b93fff8a97f1315dc82dc6bad9924bc1ef2ea3))
|
|
22
|
+
* **cli:** redesign generated commands ([cf5b729](https://github.com/moeakwak/varve/commit/cf5b72941550defd09806e9d2e70d1fc9c1c6bb9))
|
|
23
|
+
* **cli:** support `refresh --prefix` ([adb2a06](https://github.com/moeakwak/varve/commit/adb2a06664ca44cf990f136d8feb3292018afa85))
|
|
24
|
+
* **cli:** support Literal/Enum choices, null, help, and lighter clean ([53879bf](https://github.com/moeakwak/varve/commit/53879bffda1daadeca809b63a85e02b22c2f6f9f))
|
|
25
|
+
* **context:** default tqdm progress bar for resumed batch stages ([62b33f2](https://github.com/moeakwak/varve/commit/62b33f21a8991befb604401e6833e4486a87148e))
|
|
26
|
+
* **core:** branch-scoped runs with Args/Config split and full-config keying ([13dfb0f](https://github.com/moeakwak/varve/commit/13dfb0f54a377bd5f11f468af8670fe33c6854ee))
|
|
27
|
+
* **dashboard:** add `refresh` command ([eebf01e](https://github.com/moeakwak/varve/commit/eebf01ebced024db197531f2bcdd33695c8b91c3))
|
|
28
|
+
* **dashboard:** add read-only store dashboard ([1f32834](https://github.com/moeakwak/varve/commit/1f32834b8f256c055135d9cc8e7230c17f4bd981))
|
|
29
|
+
* **dashboard:** evaluate status through engine ([c0df1b9](https://github.com/moeakwak/varve/commit/c0df1b9269c159e51e434254e1a5a67d87c329c3))
|
|
30
|
+
* **dashboard:** include temporary branches ([733673a](https://github.com/moeakwak/varve/commit/733673a30631c944479364ce312e8f3fbef0d7b5))
|
|
31
|
+
* **dashboard:** show persisted stage duration ([6ce520f](https://github.com/moeakwak/varve/commit/6ce520f45614c260a6ca2ed8360c601489d6f301))
|
|
32
|
+
* **keying:** enable automatic source uses ([2d05a8f](https://github.com/moeakwak/varve/commit/2d05a8f8d37fb0bf04cdeb3c86bc6f3f0cedc1e4))
|
|
33
|
+
* split upstream output helpers ([805cd7d](https://github.com/moeakwak/varve/commit/805cd7d8ab557e8031f4588c6655f3751909a605))
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
### Bug Fixes
|
|
37
|
+
|
|
38
|
+
* **cli:** refresh executable dashboard stores ([024ce71](https://github.com/moeakwak/varve/commit/024ce719dcd3e243d62a27c5c0ae40485f4e8a07))
|
|
39
|
+
* **engine:** harden output-root path and lock handling ([d4c481d](https://github.com/moeakwak/varve/commit/d4c481d292bd70333d6753637cda44712c1b1ff4))
|
|
40
|
+
* **keying:** stabilize `__main__` helper labels ([96916ea](https://github.com/moeakwak/varve/commit/96916eab1af66c05841fd05a7a978f8d00f5250b))
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
### Documentation
|
|
44
|
+
|
|
45
|
+
* sync docs with current behavior ([c9dcfb0](https://github.com/moeakwak/varve/commit/c9dcfb0df9fc1da777768ec5ddc02d4c0e11321c))
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
### Code Refactoring
|
|
49
|
+
|
|
50
|
+
* **core:** rename branches.yaml to varve.yaml ([4b1a369](https://github.com/moeakwak/varve/commit/4b1a3692b3631a5120bd32f9e1584820f8637390))
|
|
51
|
+
* rename Experiment to Pipeline ([e994f79](https://github.com/moeakwak/varve/commit/e994f7955b011d39216fde5b5402891164a8e710))
|
|
52
|
+
* simplify varve surface and tests ([07649ba](https://github.com/moeakwak/varve/commit/07649ba03a6f5ec218e1a144a7e481ec0440d27e))
|
|
53
|
+
|
|
54
|
+
## Changelog
|
|
55
|
+
|
|
56
|
+
All notable changes to this project will be documented in this file.
|
|
57
|
+
|
|
58
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
59
|
+
|
|
60
|
+
Varve is in the 0.x phase. Minor releases may include breaking API or store schema changes; read this changelog before upgrading.
|
|
61
|
+
|
|
62
|
+
Release entries are generated by release-please from Conventional Commits.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Varve is still alpha-stage. Keep changes small, tested, and easy to review.
|
|
4
|
+
|
|
5
|
+
## Setup
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
uv sync --extra dev
|
|
9
|
+
uv run ruff check .
|
|
10
|
+
uv run ruff format --check .
|
|
11
|
+
uv run pytest
|
|
12
|
+
uv run pyright
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
`pyright` is currently a pre-flight signal, not a blocking quality bar.
|
|
16
|
+
|
|
17
|
+
## Public API
|
|
18
|
+
|
|
19
|
+
The public import surface is intentionally small:
|
|
20
|
+
|
|
21
|
+
```python
|
|
22
|
+
from varve import Ctx, JSON, KeySpec, Pipeline, StageSpec, batch_stage, stage
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Do not re-export internal store, keying, runner, or dashboard types from `varve.__all__`. Treat public API and `.varve/` store schema changes as breaking.
|
|
26
|
+
|
|
27
|
+
## Style
|
|
28
|
+
|
|
29
|
+
- User-facing docs, examples, comments, and messages are English.
|
|
30
|
+
- Follow the package boundaries in `ARCHITECTURE.md`.
|
|
31
|
+
- Do not add Click, Typer, import-linter, or release tooling beyond what is already documented.
|
|
32
|
+
- Use Conventional Commits: `<type>(<scope>)<!>: <subject>`.
|
|
33
|
+
- Append `!` for public API or store schema breaks.
|
|
34
|
+
|
|
35
|
+
## Releases
|
|
36
|
+
|
|
37
|
+
Do not hand-edit versions or release changelog entries; release-please owns them.
|
varve-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Bob Wang
|
|
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.
|
varve-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: varve
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A small Python library for experiment pipelines with code-aware materialized caching.
|
|
5
|
+
Project-URL: Repository, https://github.com/moeakwak/varve
|
|
6
|
+
Project-URL: Issues, https://github.com/moeakwak/varve/issues
|
|
7
|
+
Project-URL: Changelog, https://github.com/moeakwak/varve/blob/main/CHANGELOG.md
|
|
8
|
+
Author: Bob Wang
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Intended Audience :: Science/Research
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Operating System :: POSIX
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Typing :: Typed
|
|
22
|
+
Requires-Python: >=3.10
|
|
23
|
+
Requires-Dist: pydantic-settings[yaml]>=2.0.0
|
|
24
|
+
Requires-Dist: pydantic>=2.0.0
|
|
25
|
+
Requires-Dist: rich>=13.0.0
|
|
26
|
+
Requires-Dist: tqdm>=4.66.0
|
|
27
|
+
Provides-Extra: dev
|
|
28
|
+
Requires-Dist: pyright>=1.1.0; extra == 'dev'
|
|
29
|
+
Requires-Dist: pytest>=8.0.0; extra == 'dev'
|
|
30
|
+
Requires-Dist: ruff>=0.1.0; extra == 'dev'
|
|
31
|
+
Description-Content-Type: text/markdown
|
|
32
|
+
|
|
33
|
+
# varve
|
|
34
|
+
|
|
35
|
+
[](https://pypi.org/project/varve/) [](LICENSE)
|
|
36
|
+
|
|
37
|
+
Varve is a small Python library for running experiment pipelines as code. Each stage is a Python method, the run/status/plan/list/clean CLI is generated for you, and every output is cached under a key derived automatically from your code, config, and pinned inputs, so re-runs only re-execute what actually changed. Single machine, no daemon, no pipeline YAML.
|
|
38
|
+
|
|
39
|
+
A varve is an annual layer of lake sediment: thin, ordered, and datable. This library uses the same idea for pipeline outputs: materialized layers whose keys record the code, config, inputs, and upstream layers that produced them.
|
|
40
|
+
|
|
41
|
+
For the package layout, cache model, and edge-case behavior, see [ARCHITECTURE.md](ARCHITECTURE.md). For contribution guidance, see [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
42
|
+
|
|
43
|
+
## Quick start
|
|
44
|
+
|
|
45
|
+
```python
|
|
46
|
+
from pydantic import BaseModel
|
|
47
|
+
from varve import Pipeline, stage
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class Config(BaseModel):
|
|
51
|
+
seed: int = 1
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class Demo(Pipeline):
|
|
55
|
+
Config = Config
|
|
56
|
+
|
|
57
|
+
@stage(produces="sample.txt")
|
|
58
|
+
def sample(self, ctx):
|
|
59
|
+
(ctx.out / "sample.txt").write_text(str(ctx.config.seed))
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
if __name__ == "__main__":
|
|
63
|
+
raise SystemExit(Demo.cli())
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Run the pipeline:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
python demo.py run
|
|
70
|
+
python demo.py status
|
|
71
|
+
python demo.py plan
|
|
72
|
+
python demo.py list
|
|
73
|
+
python demo.py clean --yes
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
By default, outputs are written next to the pipeline module under `out/main/`. Use `--out PATH` to choose a different output base.
|
|
77
|
+
|
|
78
|
+
## Batch stages
|
|
79
|
+
|
|
80
|
+
Use `@batch_stage` for resumable batch work. The stage iterates through `ctx.resume(...)`, writes one or more files per item, and yields the paths it produced. If a run fails halfway through, the next run skips completed batch indexes and continues from the remaining items.
|
|
81
|
+
|
|
82
|
+
```python
|
|
83
|
+
from pathlib import Path
|
|
84
|
+
|
|
85
|
+
from pydantic import BaseModel
|
|
86
|
+
from varve import Ctx, Pipeline, batch_stage, stage
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
class Config(BaseModel):
|
|
90
|
+
batch_size: int = 100
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
class Args(BaseModel):
|
|
94
|
+
progress: bool = True
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
class Demo(Pipeline):
|
|
98
|
+
Config = Config
|
|
99
|
+
Args = Args
|
|
100
|
+
|
|
101
|
+
@stage(produces="items.txt")
|
|
102
|
+
def prepare(self, ctx: Ctx[Config, Args]) -> None:
|
|
103
|
+
(ctx.out / "items.txt").write_text("alpha\nbeta\ngamma\n")
|
|
104
|
+
|
|
105
|
+
@batch_stage(needs="prepare", partition_key=("batch_size",))
|
|
106
|
+
async def process(self, ctx: Ctx[Config, Args]):
|
|
107
|
+
items = ctx.input("prepare").read_text().splitlines()
|
|
108
|
+
async for index, item in ctx.resume(items, progress=ctx.args.progress):
|
|
109
|
+
path = ctx.out / "parts" / f"{index:04d}.txt"
|
|
110
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
111
|
+
path.write_text(item.upper())
|
|
112
|
+
yield path
|
|
113
|
+
|
|
114
|
+
@stage(needs="process", produces="summary.txt")
|
|
115
|
+
def summarize(self, ctx: Ctx[Config, Args]) -> None:
|
|
116
|
+
parts = [path.read_text() for path in ctx.inputs("process")]
|
|
117
|
+
(ctx.out / "summary.txt").write_text("\n".join(parts))
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
`ctx.input("stage")` returns exactly one upstream output path and fails if the stage produced zero or many paths. `ctx.inputs("stage")` always returns `list[Path]`. Both require the upstream stage to be declared in `needs=`, so the upstream content key is part of the downstream cache key.
|
|
121
|
+
|
|
122
|
+
## Why varve
|
|
123
|
+
|
|
124
|
+
Varve is for research and data-analysis pipelines where Python code is already the best source of truth. It is intentionally closer to a small library such as redun, Hamilton, or pydoit than to a workflow platform.
|
|
125
|
+
|
|
126
|
+
Unlike DVC, varve is not data version control. Unlike Snakemake, it does not introduce a separate DSL. Unlike Prefect, Dagster, or Airflow, it has no scheduler service, worker fleet, or deployment model.
|
|
127
|
+
|
|
128
|
+
The core design choices are:
|
|
129
|
+
|
|
130
|
+
- **Pipelines are Python code.** Stages are instance methods, dependencies are declared with `needs=`, and semantic configuration is a pydantic model.
|
|
131
|
+
- **Cache keys are code-aware by default.** Varve fingerprints stage source, automatically discovered project callables, full Config values, declared input files, declared JSON values, and upstream content keys.
|
|
132
|
+
- **Outputs are materialized.** Successful stage records point at durable files under the output root, so missing artifacts are detected instead of silently treated as cache hits.
|
|
133
|
+
- **Single machine, no service.** Varve uses an in-process runner and a file-system store. There is no daemon, database, or remote backend.
|
|
134
|
+
|
|
135
|
+
## Features
|
|
136
|
+
|
|
137
|
+
- Public API: `Pipeline`, `@stage`, `@batch_stage`, `KeySpec`, `Ctx`, `JSON`, and `StageSpec`.
|
|
138
|
+
- Generated pipeline commands:
|
|
139
|
+
- `run [--branch NAME] [--override JSON] [--upto STAGE | --downstream STAGE] [--force] [--out PATH]`
|
|
140
|
+
- `status [--branch NAME] [--upto STAGE | --downstream STAGE] [--out PATH]`
|
|
141
|
+
- `plan [--upto STAGE | --downstream STAGE]`
|
|
142
|
+
- `list`
|
|
143
|
+
- `clean [--branch NAME] [--downstream STAGE] [--out PATH] [--yes]`
|
|
144
|
+
- `run`, `status`, and `clean` also accept generated flags from the pipeline's `Args` model.
|
|
145
|
+
- Cache states for hits, stale records, missing artifacts, dirty attempts, resumable batches, and unrecoverable partition changes.
|
|
146
|
+
- `ctx.input(...)`, `ctx.inputs(...)`, and `ctx.resume(...)` for stage bodies.
|
|
147
|
+
- `KeySpec.files` for pinning input file contents into the content key.
|
|
148
|
+
|
|
149
|
+
## Branches
|
|
150
|
+
|
|
151
|
+
`varve.yaml` lives next to the pipeline module. The `main` branch is the default and may rely entirely on Config defaults when the file is missing.
|
|
152
|
+
|
|
153
|
+
Varve resolves the output root from `--out` or `Pipeline.default_output_root(config)`, then appends the selected branch:
|
|
154
|
+
|
|
155
|
+
```text
|
|
156
|
+
out/<branch> # persistent branches
|
|
157
|
+
out/.tmp/<branch> # temporary override branches
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Use `run --override '{"field": "value"}'` to deep-merge JSON over `main` and create a temporary branch. `status` and `clean` locate that branch later with `--branch NAME`.
|
|
161
|
+
|
|
162
|
+
## Dashboard
|
|
163
|
+
|
|
164
|
+
The top-level `varve` command discovers existing stores without requiring a custom dashboard entrypoint:
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
varve ls [--root DIR] [--include-temp]
|
|
168
|
+
varve show <pipeline_id> [--root DIR] [--branch NAME] [--include-temp]
|
|
169
|
+
varve refresh [--root DIR] [--prefix MODULE_PREFIX] [--include-temp]
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Dashboard commands are secondary tooling. The primary interface remains each pipeline's generated CLI.
|
|
173
|
+
|
|
174
|
+
## Platform support
|
|
175
|
+
|
|
176
|
+
Varve is currently Unix-only. The output-root lock uses `fcntl`, so Windows support requires a future lock implementation.
|
|
177
|
+
|
|
178
|
+
Source fingerprints use `ast.dump`. A CPython minor-version upgrade may invalidate stage source hashes and rebuild caches.
|
|
179
|
+
|
|
180
|
+
## API stability
|
|
181
|
+
|
|
182
|
+
Varve follows SemVer, but 0.x releases are alpha releases. Minor releases may include breaking changes to the public API or to the `.varve/` store schema. Read `CHANGELOG.md` before upgrading.
|
|
183
|
+
|
|
184
|
+
## Non-goals
|
|
185
|
+
|
|
186
|
+
- Remote storage or data version control.
|
|
187
|
+
- Distributed scheduling or cluster execution.
|
|
188
|
+
- Workflow platform, server, or DAG visualization service.
|
|
189
|
+
- Cross-pipeline lineage or observability platform.
|
|
190
|
+
|
|
191
|
+
## License
|
|
192
|
+
|
|
193
|
+
MIT. See [LICENSE](LICENSE).
|