flexlock 0.8.2__tar.gz → 0.9.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.
- flexlock-0.9.0/.github/scripts/check_version.py +35 -0
- flexlock-0.9.0/.github/workflows/ci.yml +66 -0
- flexlock-0.9.0/.github/workflows/docs.yml +55 -0
- flexlock-0.9.0/.github/workflows/release.yml +93 -0
- flexlock-0.9.0/CHANGELOG.md +53 -0
- flexlock-0.8.2/.claude/worktrees/dedup-deps/README.md → flexlock-0.9.0/PKG-INFO +34 -8
- flexlock-0.8.2/PKG-INFO → flexlock-0.9.0/README.md +18 -24
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/docs/api.rst +5 -0
- flexlock-0.9.0/docs/changelog.md +2 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/docs/cli_reference.md +100 -4
- flexlock-0.9.0/docs/dev_plan_pipeline_tasks.md +252 -0
- flexlock-0.9.0/docs/dev_plan_presets_records.md +408 -0
- {flexlock-0.8.2 → flexlock-0.9.0}/docs/hpc_integration.md +175 -17
- {flexlock-0.8.2 → flexlock-0.9.0}/docs/index.rst +1 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/docs/philosophy.md +49 -20
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/docs/python_api.md +10 -1
- {flexlock-0.8.2 → flexlock-0.9.0}/docs/resolvers.md +44 -2
- {flexlock-0.8.2 → flexlock-0.9.0}/docs/usage_guide.md +193 -13
- {flexlock-0.8.2 → flexlock-0.9.0}/flexlock/__init__.py +1 -1
- {flexlock-0.8.2 → flexlock-0.9.0}/flexlock/api.py +424 -21
- {flexlock-0.8.2 → flexlock-0.9.0}/flexlock/backends/slurm.py +17 -5
- {flexlock-0.8.2 → flexlock-0.9.0}/flexlock/cli.py +211 -17
- {flexlock-0.8.2 → flexlock-0.9.0}/flexlock/config.py +37 -0
- {flexlock-0.8.2 → flexlock-0.9.0}/flexlock/diff.py +31 -2
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/flexlock/diff_cli.py +40 -13
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/flexlock/export.py +5 -0
- {flexlock-0.8.2 → flexlock-0.9.0}/flexlock/fingerprint.py +78 -3
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/flexlock/git_utils.py +98 -0
- {flexlock-0.8.2 → flexlock-0.9.0}/flexlock/index.py +62 -26
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/flexlock/load_stage.py +6 -8
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/flexlock/mlflow.py +11 -11
- {flexlock-0.8.2 → flexlock-0.9.0}/flexlock/parallel.py +21 -4
- flexlock-0.9.0/flexlock/presets.py +515 -0
- {flexlock-0.8.2 → flexlock-0.9.0}/flexlock/query.py +23 -31
- flexlock-0.9.0/flexlock/record.py +171 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/flexlock/resolvers.py +39 -9
- {flexlock-0.8.2 → flexlock-0.9.0}/flexlock/run_record.py +145 -1
- {flexlock-0.8.2 → flexlock-0.9.0}/flexlock/runner.py +323 -55
- {flexlock-0.8.2 → flexlock-0.9.0}/flexlock/skills/flexlock-new-stage/SKILL.md +6 -0
- {flexlock-0.8.2 → flexlock-0.9.0}/flexlock/skills/flexlock-survey/SKILL.md +12 -1
- {flexlock-0.8.2 → flexlock-0.9.0}/flexlock/snapshot.py +48 -10
- {flexlock-0.8.2 → flexlock-0.9.0}/flexlock/taskdb.py +38 -3
- {flexlock-0.8.2 → flexlock-0.9.0}/flexlock/utils.py +234 -21
- flexlock-0.9.0/flexlock/worker.py +449 -0
- {flexlock-0.8.2 → flexlock-0.9.0}/pyproject.toml +3 -3
- flexlock-0.9.0/tests/test_code_drift.py +197 -0
- {flexlock-0.8.2 → flexlock-0.9.0}/tests/test_diff_cli.py +10 -0
- {flexlock-0.8.2 → flexlock-0.9.0}/tests/test_fingerprint.py +65 -0
- {flexlock-0.8.2 → flexlock-0.9.0}/tests/test_multistage_config.py +80 -3
- flexlock-0.9.0/tests/test_pipeline_tasks.py +564 -0
- flexlock-0.9.0/tests/test_presets.py +361 -0
- {flexlock-0.8.2 → flexlock-0.9.0}/tests/test_resolvers.py +10 -0
- flexlock-0.9.0/tests/test_single_task_runlock.py +268 -0
- flexlock-0.9.0/tests/test_swaps.py +126 -0
- flexlock-0.9.0/tests/test_task_records.py +255 -0
- flexlock-0.8.2/.claude/settings.local.json +0 -7
- flexlock-0.8.2/.claude/worktrees/dedup-deps/.claude/settings.local.json +0 -7
- flexlock-0.8.2/.claude/worktrees/dedup-deps/docs/debugging.md +0 -352
- flexlock-0.8.2/.claude/worktrees/dedup-deps/docs/hpc_integration.md +0 -712
- flexlock-0.8.2/.claude/worktrees/dedup-deps/docs/index.rst +0 -40
- flexlock-0.8.2/.claude/worktrees/dedup-deps/docs/resolvers.md +0 -445
- flexlock-0.8.2/.claude/worktrees/dedup-deps/docs/usage_guide.md +0 -1075
- flexlock-0.8.2/.claude/worktrees/dedup-deps/flexlock/__init__.py +0 -87
- flexlock-0.8.2/.claude/worktrees/dedup-deps/flexlock/api.py +0 -1362
- flexlock-0.8.2/.claude/worktrees/dedup-deps/flexlock/backends/slurm.py +0 -333
- flexlock-0.8.2/.claude/worktrees/dedup-deps/flexlock/cli.py +0 -953
- flexlock-0.8.2/.claude/worktrees/dedup-deps/flexlock/config.py +0 -107
- flexlock-0.8.2/.claude/worktrees/dedup-deps/flexlock/diff.py +0 -253
- flexlock-0.8.2/.claude/worktrees/dedup-deps/flexlock/fingerprint.py +0 -129
- flexlock-0.8.2/.claude/worktrees/dedup-deps/flexlock/index.py +0 -300
- flexlock-0.8.2/.claude/worktrees/dedup-deps/flexlock/parallel.py +0 -378
- flexlock-0.8.2/.claude/worktrees/dedup-deps/flexlock/query.py +0 -739
- flexlock-0.8.2/.claude/worktrees/dedup-deps/flexlock/run_record.py +0 -173
- flexlock-0.8.2/.claude/worktrees/dedup-deps/flexlock/runner.py +0 -560
- flexlock-0.8.2/.claude/worktrees/dedup-deps/flexlock/save_dir.py +0 -124
- flexlock-0.8.2/.claude/worktrees/dedup-deps/flexlock/skills/flexlock-new-stage/SKILL.md +0 -56
- flexlock-0.8.2/.claude/worktrees/dedup-deps/flexlock/skills/flexlock-run-and-watch/SKILL.md +0 -58
- flexlock-0.8.2/.claude/worktrees/dedup-deps/flexlock/skills/flexlock-survey/SKILL.md +0 -61
- flexlock-0.8.2/.claude/worktrees/dedup-deps/flexlock/snapshot.py +0 -245
- flexlock-0.8.2/.claude/worktrees/dedup-deps/flexlock/taskdb.py +0 -589
- flexlock-0.8.2/.claude/worktrees/dedup-deps/flexlock/utils.py +0 -710
- flexlock-0.8.2/.claude/worktrees/dedup-deps/flexlock/worker.py +0 -199
- flexlock-0.8.2/.claude/worktrees/dedup-deps/flexlock/worker_cli.py +0 -138
- flexlock-0.8.2/.claude/worktrees/dedup-deps/pixi.lock +0 -5793
- flexlock-0.8.2/.claude/worktrees/dedup-deps/pyproject.toml +0 -103
- flexlock-0.8.2/.claude/worktrees/dedup-deps/tests/test_api.py +0 -425
- flexlock-0.8.2/.claude/worktrees/dedup-deps/tests/test_diff_cli.py +0 -66
- flexlock-0.8.2/.claude/worktrees/dedup-deps/tests/test_fingerprint.py +0 -112
- flexlock-0.8.2/.claude/worktrees/dedup-deps/tests/test_multistage_config.py +0 -347
- flexlock-0.8.2/.claude/worktrees/dedup-deps/tests/test_resolvers.py +0 -421
- flexlock-0.8.2/.claude/worktrees/dedup-deps/tests/test_save_dir.py +0 -125
- flexlock-0.8.2/.claude/worktrees/dedup-deps/tests/test_utils.py +0 -923
- flexlock-0.8.2/.claude/worktrees/dedup-deps/tests/test_worker_preflight.py +0 -97
- flexlock-0.8.2/.gitattributes +0 -2
- flexlock-0.8.2/.gitignore +0 -16
- flexlock-0.8.2/FABLE_IMPLEMENTATION_PLAN.md +0 -368
- flexlock-0.8.2/README.md +0 -341
- flexlock-0.8.2/bench/taskdb_contention.py +0 -126
- flexlock-0.8.2/docs/README.md +0 -23
- flexlock-0.8.2/docs/agentic_workflows.md +0 -131
- flexlock-0.8.2/docs/api.rst +0 -127
- flexlock-0.8.2/docs/cli_reference.md +0 -811
- flexlock-0.8.2/docs/conf.py +0 -64
- flexlock-0.8.2/docs/dev_plan_task_tags.md +0 -181
- flexlock-0.8.2/docs/mlflow_integration.md +0 -960
- flexlock-0.8.2/docs/philosophy.md +0 -171
- flexlock-0.8.2/docs/python_api.md +0 -905
- flexlock-0.8.2/docs/quickstart.md +0 -175
- flexlock-0.8.2/docs/reference.md +0 -305
- flexlock-0.8.2/docs/requirements.txt +0 -10
- flexlock-0.8.2/docs/resolution_simplification_plan.md +0 -226
- flexlock-0.8.2/docs/upload_docs.sh +0 -17
- flexlock-0.8.2/flexlock/backends/__init__.py +0 -11
- flexlock-0.8.2/flexlock/backends/base.py +0 -41
- flexlock-0.8.2/flexlock/backends/pbs.py +0 -219
- flexlock-0.8.2/flexlock/context.py +0 -7
- flexlock-0.8.2/flexlock/data_hash.py +0 -310
- flexlock-0.8.2/flexlock/debug.py +0 -473
- flexlock-0.8.2/flexlock/diff_cli.py +0 -155
- flexlock-0.8.2/flexlock/exceptions.py +0 -50
- flexlock-0.8.2/flexlock/export.py +0 -134
- flexlock-0.8.2/flexlock/flexcli.py +0 -163
- flexlock-0.8.2/flexlock/freeze.py +0 -291
- flexlock-0.8.2/flexlock/git_utils.py +0 -196
- flexlock-0.8.2/flexlock/load_stage.py +0 -60
- flexlock-0.8.2/flexlock/mlflow.py +0 -192
- flexlock-0.8.2/flexlock/report.py +0 -78
- flexlock-0.8.2/flexlock/report_template.html +0 -246
- flexlock-0.8.2/flexlock/resolvers.py +0 -248
- flexlock-0.8.2/flexlock/run_cli.py +0 -44
- flexlock-0.8.2/flexlock/skills/flexlock-report/SKILL.md +0 -50
- flexlock-0.8.2/flexlock/status_cli.py +0 -299
- flexlock-0.8.2/flexlock/worker.py +0 -228
- flexlock-0.8.2/plan_ergonomics_fable.md +0 -200
- flexlock-0.8.2/suggested_improvements.md +0 -126
- flexlock-0.8.2/tests/test_chained_and_paths.py +0 -227
- flexlock-0.8.2/tests/test_check.py +0 -62
- flexlock-0.8.2/tests/test_cli.py +0 -488
- flexlock-0.8.2/tests/test_completion_marker.py +0 -154
- flexlock-0.8.2/tests/test_data_hash.py +0 -244
- flexlock-0.8.2/tests/test_debug_enhanced.py +0 -403
- flexlock-0.8.2/tests/test_debug_integration.py +0 -105
- flexlock-0.8.2/tests/test_deferred.py +0 -98
- flexlock-0.8.2/tests/test_diff.py +0 -559
- flexlock-0.8.2/tests/test_dump_enqueue.py +0 -274
- flexlock-0.8.2/tests/test_flexcli.py +0 -89
- flexlock-0.8.2/tests/test_flexcli_jupyter.py +0 -201
- flexlock-0.8.2/tests/test_git_utils.py +0 -181
- flexlock-0.8.2/tests/test_index.py +0 -202
- flexlock-0.8.2/tests/test_load_stage.py +0 -176
- flexlock-0.8.2/tests/test_mlflowlink.py +0 -246
- flexlock-0.8.2/tests/test_node_selection.py +0 -524
- flexlock-0.8.2/tests/test_parallel.py +0 -584
- flexlock-0.8.2/tests/test_progressive_framework.py +0 -136
- flexlock-0.8.2/tests/test_query.py +0 -371
- flexlock-0.8.2/tests/test_report.py +0 -104
- flexlock-0.8.2/tests/test_run_record.py +0 -120
- flexlock-0.8.2/tests/test_runner.py +0 -293
- flexlock-0.8.2/tests/test_skills.py +0 -72
- flexlock-0.8.2/tests/test_slurm_validation.py +0 -250
- flexlock-0.8.2/tests/test_snapshot.py +0 -437
- flexlock-0.8.2/tests/test_submit_params.py +0 -377
- flexlock-0.8.2/tests/test_sweep_semantics.py +0 -312
- flexlock-0.8.2/tests/test_target_includes.py +0 -135
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/.gitattributes +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/.gitignore +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/FABLE_IMPLEMENTATION_PLAN.md +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/docs/README.md +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/docs/agentic_workflows.md +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/docs/conf.py +0 -0
- {flexlock-0.8.2 → flexlock-0.9.0}/docs/debugging.md +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/docs/mlflow_integration.md +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/docs/quickstart.md +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/docs/reference.md +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/docs/requirements.txt +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/docs/resolution_simplification_plan.md +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/docs/upload_docs.sh +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/flexlock/backends/__init__.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/flexlock/backends/base.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/flexlock/backends/pbs.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/flexlock/context.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/flexlock/data_hash.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/flexlock/debug.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/flexlock/exceptions.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/flexlock/flexcli.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/flexlock/freeze.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/flexlock/report.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/flexlock/report_template.html +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/flexlock/run_cli.py +0 -0
- {flexlock-0.8.2 → flexlock-0.9.0}/flexlock/save_dir.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/flexlock/skills/flexlock-report/SKILL.md +0 -0
- {flexlock-0.8.2 → flexlock-0.9.0}/flexlock/skills/flexlock-run-and-watch/SKILL.md +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/flexlock/status_cli.py +0 -0
- {flexlock-0.8.2 → flexlock-0.9.0}/flexlock/worker_cli.py +0 -0
- {flexlock-0.8.2 → flexlock-0.9.0}/pixi.lock +0 -0
- {flexlock-0.8.2 → flexlock-0.9.0}/tests/test_api.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/tests/test_chained_and_paths.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/tests/test_check.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/tests/test_cli.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/tests/test_completion_marker.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/tests/test_data_hash.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/tests/test_debug_enhanced.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/tests/test_debug_integration.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/tests/test_deferred.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/tests/test_diff.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/tests/test_dump_enqueue.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/tests/test_flexcli.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/tests/test_flexcli_jupyter.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/tests/test_git_utils.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/tests/test_index.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/tests/test_load_stage.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/tests/test_mlflowlink.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/tests/test_node_selection.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/tests/test_parallel.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/tests/test_progressive_framework.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/tests/test_query.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/tests/test_report.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/tests/test_run_record.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/tests/test_runner.py +0 -0
- {flexlock-0.8.2 → flexlock-0.9.0}/tests/test_save_dir.py +0 -0
- {flexlock-0.8.2 → flexlock-0.9.0}/tests/test_save_dir_guard.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/tests/test_skills.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/tests/test_slurm_validation.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/tests/test_snapshot.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/tests/test_submit_params.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/tests/test_sweep_semantics.py +0 -0
- {flexlock-0.8.2/.claude/worktrees/dedup-deps → flexlock-0.9.0}/tests/test_target_includes.py +0 -0
- {flexlock-0.8.2 → flexlock-0.9.0}/tests/test_utils.py +0 -0
- {flexlock-0.8.2 → flexlock-0.9.0}/tests/test_worker_preflight.py +0 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"""Check that the version declarations agree (and match the tag, if given).
|
|
2
|
+
|
|
3
|
+
The wheel version comes from ``flexlock/__init__.py`` (hatch dynamic version);
|
|
4
|
+
the conda package version from ``[tool.pixi.package] version`` in
|
|
5
|
+
pyproject.toml. Usage: ``python .github/scripts/check_version.py [vX.Y.Z]``.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import re
|
|
9
|
+
import sys
|
|
10
|
+
import tomllib
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
|
|
13
|
+
root = Path(__file__).resolve().parents[2]
|
|
14
|
+
init = (root / "flexlock" / "__init__.py").read_text()
|
|
15
|
+
m = re.search(r'^__version__\s*=\s*"([^"]+)"', init, re.M)
|
|
16
|
+
if not m:
|
|
17
|
+
sys.exit("could not find __version__ in flexlock/__init__.py")
|
|
18
|
+
py_version = m.group(1)
|
|
19
|
+
|
|
20
|
+
pixi_version = tomllib.loads((root / "pyproject.toml").read_text())["tool"]["pixi"]["package"]["version"]
|
|
21
|
+
|
|
22
|
+
errors = []
|
|
23
|
+
if py_version != pixi_version:
|
|
24
|
+
errors.append(
|
|
25
|
+
f"flexlock/__init__.py __version__={py_version!r} != "
|
|
26
|
+
f"[tool.pixi.package] version={pixi_version!r}"
|
|
27
|
+
)
|
|
28
|
+
if len(sys.argv) > 1:
|
|
29
|
+
tag = sys.argv[1].removeprefix("refs/tags/")
|
|
30
|
+
if tag != f"v{py_version}":
|
|
31
|
+
errors.append(f"tag {tag!r} does not match package version v{py_version}")
|
|
32
|
+
|
|
33
|
+
if errors:
|
|
34
|
+
sys.exit("\n".join(errors))
|
|
35
|
+
print(f"version OK: {py_version}")
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
concurrency:
|
|
13
|
+
group: ci-${{ github.ref }}
|
|
14
|
+
cancel-in-progress: true
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
tests:
|
|
18
|
+
name: tests (py${{ matrix.python-version }})
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
strategy:
|
|
21
|
+
fail-fast: false
|
|
22
|
+
matrix:
|
|
23
|
+
python-version: ["3.11", "3.12", "3.13"]
|
|
24
|
+
steps:
|
|
25
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
26
|
+
with:
|
|
27
|
+
fetch-depth: 0 # git_utils / snapshot tests inspect history
|
|
28
|
+
|
|
29
|
+
- uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
|
|
30
|
+
with:
|
|
31
|
+
python-version: ${{ matrix.python-version }}
|
|
32
|
+
activate-environment: true
|
|
33
|
+
|
|
34
|
+
- name: Install package and test deps
|
|
35
|
+
# Mirrors [tool.pixi.feature.test]; attrs is needed by test_utils.
|
|
36
|
+
run: uv pip install -e . "pytest>=8.3.2,<9" "pytest-mock>=3.14.0,<4" ipython attrs
|
|
37
|
+
|
|
38
|
+
- name: Git identity (tests create repos and commits)
|
|
39
|
+
run: |
|
|
40
|
+
git config --global user.name "flexlock-ci"
|
|
41
|
+
git config --global user.email "flexlock-ci@users.noreply.github.com"
|
|
42
|
+
|
|
43
|
+
- name: Run tests
|
|
44
|
+
run: pytest -q
|
|
45
|
+
|
|
46
|
+
build:
|
|
47
|
+
name: build sdist/wheel
|
|
48
|
+
runs-on: ubuntu-latest
|
|
49
|
+
steps:
|
|
50
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
51
|
+
|
|
52
|
+
- uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
|
|
53
|
+
with:
|
|
54
|
+
python-version: "3.11"
|
|
55
|
+
|
|
56
|
+
- name: Check version declarations agree
|
|
57
|
+
run: python .github/scripts/check_version.py
|
|
58
|
+
|
|
59
|
+
- run: uv build
|
|
60
|
+
|
|
61
|
+
- name: Wheel installs into a clean venv and imports
|
|
62
|
+
run: |
|
|
63
|
+
uv venv /tmp/wheelcheck
|
|
64
|
+
uv pip install --python /tmp/wheelcheck/bin/python dist/*.whl
|
|
65
|
+
cd /tmp && /tmp/wheelcheck/bin/python -c "import flexlock; print(flexlock.__version__)"
|
|
66
|
+
/tmp/wheelcheck/bin/flexlock --help > /dev/null
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
name: Docs
|
|
2
|
+
|
|
3
|
+
# Builds the Sphinx docs on every PR; deploys to GitHub Pages
|
|
4
|
+
# (https://quentinf00.github.io/flexlock/) on pushes to main.
|
|
5
|
+
# Requires Settings > Pages > Source = "GitHub Actions".
|
|
6
|
+
on:
|
|
7
|
+
push:
|
|
8
|
+
branches: [main]
|
|
9
|
+
pull_request:
|
|
10
|
+
workflow_dispatch:
|
|
11
|
+
|
|
12
|
+
permissions:
|
|
13
|
+
contents: read
|
|
14
|
+
|
|
15
|
+
concurrency:
|
|
16
|
+
group: pages-${{ github.ref }}
|
|
17
|
+
cancel-in-progress: false
|
|
18
|
+
|
|
19
|
+
jobs:
|
|
20
|
+
build:
|
|
21
|
+
runs-on: ubuntu-latest
|
|
22
|
+
steps:
|
|
23
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
24
|
+
|
|
25
|
+
- uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
|
|
26
|
+
with:
|
|
27
|
+
python-version: "3.11"
|
|
28
|
+
activate-environment: true
|
|
29
|
+
|
|
30
|
+
- name: Install docs deps
|
|
31
|
+
# Mirrors [tool.pixi.feature.docs]; conf.py imports flexlock.
|
|
32
|
+
run: uv pip install . sphinx myst-parser sphinx-rtd-theme
|
|
33
|
+
|
|
34
|
+
- name: Build HTML
|
|
35
|
+
run: |
|
|
36
|
+
sphinx-build -b html docs docs/_build/html
|
|
37
|
+
touch docs/_build/html/.nojekyll
|
|
38
|
+
|
|
39
|
+
- uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0
|
|
40
|
+
with:
|
|
41
|
+
path: docs/_build/html
|
|
42
|
+
|
|
43
|
+
deploy:
|
|
44
|
+
if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main'
|
|
45
|
+
needs: build
|
|
46
|
+
runs-on: ubuntu-latest
|
|
47
|
+
permissions:
|
|
48
|
+
pages: write
|
|
49
|
+
id-token: write
|
|
50
|
+
environment:
|
|
51
|
+
name: github-pages
|
|
52
|
+
url: ${{ steps.deployment.outputs.page_url }}
|
|
53
|
+
steps:
|
|
54
|
+
- id: deployment
|
|
55
|
+
uses: actions/deploy-pages@368f82528645a54fb793d4d04e342629a3f51346 # v5.0.1
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
# Push a tag vX.Y.Z (matching flexlock/__init__.py and [tool.pixi.package]
|
|
4
|
+
# version) to build and publish the PyPI and conda packages.
|
|
5
|
+
on:
|
|
6
|
+
push:
|
|
7
|
+
tags: ["v*"]
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
build-dist:
|
|
14
|
+
name: build sdist/wheel
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
18
|
+
|
|
19
|
+
- uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
|
|
20
|
+
with:
|
|
21
|
+
python-version: "3.11"
|
|
22
|
+
|
|
23
|
+
- name: Tag matches package versions
|
|
24
|
+
run: python .github/scripts/check_version.py "${GITHUB_REF_NAME}"
|
|
25
|
+
|
|
26
|
+
- run: uv build
|
|
27
|
+
|
|
28
|
+
- name: Wheel installs into a clean venv and imports
|
|
29
|
+
run: |
|
|
30
|
+
uv venv /tmp/wheelcheck
|
|
31
|
+
uv pip install --python /tmp/wheelcheck/bin/python dist/*.whl
|
|
32
|
+
cd /tmp && /tmp/wheelcheck/bin/python -c "import flexlock; print(flexlock.__version__)"
|
|
33
|
+
|
|
34
|
+
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
35
|
+
with:
|
|
36
|
+
name: dist
|
|
37
|
+
path: dist/
|
|
38
|
+
if-no-files-found: error
|
|
39
|
+
|
|
40
|
+
publish-pypi:
|
|
41
|
+
# Enable this repository variable after configuring the corresponding
|
|
42
|
+
# trusted publisher on PyPI. Local twine publishing works independently.
|
|
43
|
+
if: vars.PYPI_TRUSTED_PUBLISHING == 'true'
|
|
44
|
+
name: publish to PyPI (trusted publishing)
|
|
45
|
+
needs: build-dist
|
|
46
|
+
runs-on: ubuntu-latest
|
|
47
|
+
environment:
|
|
48
|
+
name: pypi
|
|
49
|
+
url: https://pypi.org/p/flexlock
|
|
50
|
+
permissions:
|
|
51
|
+
id-token: write # OIDC token for PyPI trusted publishing; no stored secret
|
|
52
|
+
steps:
|
|
53
|
+
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
|
54
|
+
with:
|
|
55
|
+
name: dist
|
|
56
|
+
path: dist/
|
|
57
|
+
|
|
58
|
+
- uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
|
|
59
|
+
|
|
60
|
+
conda:
|
|
61
|
+
name: build + upload conda package (anaconda.org/quentinf00)
|
|
62
|
+
runs-on: ubuntu-latest
|
|
63
|
+
env:
|
|
64
|
+
ANACONDA_API_TOKEN: ${{ secrets.ANACONDA_API_TOKEN }}
|
|
65
|
+
environment:
|
|
66
|
+
name: anaconda
|
|
67
|
+
url: https://anaconda.org/quentinf00/flexlock
|
|
68
|
+
steps:
|
|
69
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
70
|
+
|
|
71
|
+
- name: Tag matches package versions
|
|
72
|
+
run: python3 .github/scripts/check_version.py "${GITHUB_REF_NAME}"
|
|
73
|
+
|
|
74
|
+
- uses: prefix-dev/setup-pixi@d3f436a425481402e6a95a1d1fc10331c708cd9e # v0.10.2
|
|
75
|
+
with:
|
|
76
|
+
pixi-version: v0.73.0
|
|
77
|
+
run-install: false
|
|
78
|
+
|
|
79
|
+
- name: Build conda package ([tool.pixi.package], pixi-build-python)
|
|
80
|
+
run: pixi build --output-dir conda-out
|
|
81
|
+
|
|
82
|
+
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
83
|
+
with:
|
|
84
|
+
name: conda-package
|
|
85
|
+
path: conda-out/*.conda
|
|
86
|
+
if-no-files-found: error
|
|
87
|
+
|
|
88
|
+
- name: Upload to anaconda.org
|
|
89
|
+
if: env.ANACONDA_API_TOKEN != ''
|
|
90
|
+
run: |
|
|
91
|
+
pixi exec --spec "anaconda-client>=1.14" -- \
|
|
92
|
+
anaconda -s api.anaconda.org -t "$ANACONDA_API_TOKEN" \
|
|
93
|
+
upload --user quentinf00 --label main conda-out/*.conda
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.9.0 (2026-10-02)
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- Composite pipelines across sweeps, local/HPC workers, and enqueue/dequeue.
|
|
7
|
+
- Full per-stage run records in directories or the task DB, including upstream
|
|
8
|
+
references, code provenance, and code-drift detection.
|
|
9
|
+
- Environment lockfiles in run fingerprints.
|
|
10
|
+
- Preset tracking and `flexlock runs` / `flexlock presets`.
|
|
11
|
+
- `${run:...}` references to completed preset runs and `key=@name` config swaps.
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
- Composite task snapshots retain every executed stage instead of overwriting
|
|
15
|
+
earlier stage records. Exports include each stage's inherited code and environment.
|
|
16
|
+
|
|
17
|
+
### Release infrastructure
|
|
18
|
+
- CI on Python 3.11–3.13, wheel/sdist checks, tag-driven PyPI and conda publishing,
|
|
19
|
+
and GitHub Pages documentation.
|
|
20
|
+
|
|
21
|
+
The unreleased 0.8.3 fixes below are included in this release.
|
|
22
|
+
|
|
23
|
+
## 0.8.3 (unreleased)
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
- **Single HPC / `isolated=True` runs now get a full `run.lock`.** They used to
|
|
27
|
+
keep the submit-time placeholder (`config` = `save_dir` + `_snapshot_` only)
|
|
28
|
+
because the worker stored the real snapshot only in `run.lock.tasks.db`. That
|
|
29
|
+
broke `${run_lock:...}` (`KeyError`), made `flexlock-run -c run.lock` a
|
|
30
|
+
silent no-op, showed empty configs in `show`/`diff`/`ls`, linked no commits
|
|
31
|
+
on `tag`, and let `gc` delete the upstreams of a tagged run. The worker now
|
|
32
|
+
writes the full snapshot (config, fingerprint, git state, `note`) atomically
|
|
33
|
+
when its task owns the master dir. Sweep roots keep their placeholder.
|
|
34
|
+
- Readers (`${run_lock:...}`, `show`/`graph`/`why`/`report`, `flexlock-diff`,
|
|
35
|
+
`ls`/`gc`/`tag`, `load_stage`, lineage, `flexlock-run -c run.lock`) fall back
|
|
36
|
+
to the task-DB snapshot for placeholder `run.lock`s written by older versions.
|
|
37
|
+
- The worker refreshes `run.lock.tasks` when its queue drains, so it is no
|
|
38
|
+
longer left at `[]` after a `wait=False` submit.
|
|
39
|
+
- `force=True` on a single HPC / isolated submission deleted `run.complete` but
|
|
40
|
+
ran nothing: the old `done` row in the task DB was kept by `INSERT OR IGNORE`.
|
|
41
|
+
The task DB is now reset and the task re-executes. The reset also drops the
|
|
42
|
+
cached sqlite connection, which kept writing to the deleted DB file.
|
|
43
|
+
- Slurm backend: forkserver compatibility fix.
|
|
44
|
+
- `docs/hpc_integration.md`: the task DB lives inside `save_dir`, not in its
|
|
45
|
+
parent. The overview section, clobbered by an earlier edit, is restored.
|
|
46
|
+
|
|
47
|
+
### Added
|
|
48
|
+
- `flexlock.run_record.load_lock_data(run_dir)`: side-effect-free effective
|
|
49
|
+
`run.lock` (placeholder → task-DB snapshot).
|
|
50
|
+
- `flexlock.run_record.materialize_lock(run_dir)`: one-off rewrite of a
|
|
51
|
+
placeholder `run.lock` (keeps `run.lock.placeholder.bak`).
|
|
52
|
+
- `flexlock repair-locks <root> [-n]`: runs `materialize_lock` over a results tree.
|
|
53
|
+
- `flexlock.taskdb.reset_db(db_path)`.
|
|
@@ -1,3 +1,19 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: flexlock
|
|
3
|
+
Version: 0.9.0
|
|
4
|
+
Summary: A lightweight and painless SciOps library
|
|
5
|
+
Author-email: Quentin Febvre <quentin.febvre@gmail.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Requires-Python: >=3.11
|
|
8
|
+
Requires-Dist: cloudpickle<4,>=3.0.0
|
|
9
|
+
Requires-Dist: gitpython<4,>=3.1.46
|
|
10
|
+
Requires-Dist: joblib<2,>=1.5.2
|
|
11
|
+
Requires-Dist: loguru<0.8,>=0.7.3
|
|
12
|
+
Requires-Dist: omegaconf<3,>=2.3.0
|
|
13
|
+
Requires-Dist: pandas<3,>=2.3.0
|
|
14
|
+
Requires-Dist: xxhash<4,>=3.5.0
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
|
|
1
17
|
# FlexLock
|
|
2
18
|
|
|
3
19
|
**Reproducible, Composable, and Scalable Computational Experiments**
|
|
@@ -292,14 +308,24 @@ pip install -e .
|
|
|
292
308
|
|
|
293
309
|
## Comparison with Other Tools
|
|
294
310
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
311
|
+
FlexLock combines Hydra-style configuration (overrides, sweeps, callables as
|
|
312
|
+
config) with DVC-style provenance (runs traceable to code, config and data,
|
|
313
|
+
and skipped when unchanged). It grew out of
|
|
314
|
+
[ZenDag](https://github.com/quentinf00/zendag), which generated DVC pipelines
|
|
315
|
+
from Hydra configs. The key difference: the cache key belongs to each run,
|
|
316
|
+
not to a workspace lockfile, so sweeps and HPC jobs need no shared state
|
|
317
|
+
beyond the filesystem.
|
|
318
|
+
|
|
319
|
+
| | FlexLock | Hydra | DVC | redun | Snakemake |
|
|
320
|
+
|---|---|---|---|---|---|
|
|
321
|
+
| Overrides and sweeps | ✅ | ✅ | ✅ `dvc exp` | ❌ | ❌ |
|
|
322
|
+
| Skips unchanged runs | ✅ per run | ❌ | ✅ per stage | ✅ per call | ✅ per rule |
|
|
323
|
+
| Code identity in cache key | git tree of `_target_` modules | ❌ | listed deps | task source | rule code |
|
|
324
|
+
| Slurm / PBS | ✅ | ✅ submitit | ❌ | ❌ cloud only | ✅ |
|
|
325
|
+
| Remote output storage | ❌ | ❌ | ✅ | ✅ | ✅ |
|
|
326
|
+
|
|
327
|
+
See [Philosophy & Design](docs/philosophy.md#comparison-with-other-tools) for
|
|
328
|
+
the full comparison and when to pick another tool.
|
|
303
329
|
|
|
304
330
|
## Contributing
|
|
305
331
|
|
|
@@ -1,19 +1,3 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: flexlock
|
|
3
|
-
Version: 0.8.2
|
|
4
|
-
Summary: A lightweight and painless SciOps library
|
|
5
|
-
Author-email: Quentin Febvre <quentin.febvre@gmail.com>
|
|
6
|
-
License-Expression: MIT
|
|
7
|
-
Requires-Python: >=3.11
|
|
8
|
-
Requires-Dist: cloudpickle<4,>=3.0.0
|
|
9
|
-
Requires-Dist: gitpython<4,>=3.1.45
|
|
10
|
-
Requires-Dist: joblib<2,>=1.5.2
|
|
11
|
-
Requires-Dist: loguru<0.8,>=0.7.3
|
|
12
|
-
Requires-Dist: omegaconf<3,>=2.3.0
|
|
13
|
-
Requires-Dist: pandas<3,>=2.3.2
|
|
14
|
-
Requires-Dist: xxhash<4,>=3.5.0
|
|
15
|
-
Description-Content-Type: text/markdown
|
|
16
|
-
|
|
17
1
|
# FlexLock
|
|
18
2
|
|
|
19
3
|
**Reproducible, Composable, and Scalable Computational Experiments**
|
|
@@ -308,14 +292,24 @@ pip install -e .
|
|
|
308
292
|
|
|
309
293
|
## Comparison with Other Tools
|
|
310
294
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
295
|
+
FlexLock combines Hydra-style configuration (overrides, sweeps, callables as
|
|
296
|
+
config) with DVC-style provenance (runs traceable to code, config and data,
|
|
297
|
+
and skipped when unchanged). It grew out of
|
|
298
|
+
[ZenDag](https://github.com/quentinf00/zendag), which generated DVC pipelines
|
|
299
|
+
from Hydra configs. The key difference: the cache key belongs to each run,
|
|
300
|
+
not to a workspace lockfile, so sweeps and HPC jobs need no shared state
|
|
301
|
+
beyond the filesystem.
|
|
302
|
+
|
|
303
|
+
| | FlexLock | Hydra | DVC | redun | Snakemake |
|
|
304
|
+
|---|---|---|---|---|---|
|
|
305
|
+
| Overrides and sweeps | ✅ | ✅ | ✅ `dvc exp` | ❌ | ❌ |
|
|
306
|
+
| Skips unchanged runs | ✅ per run | ❌ | ✅ per stage | ✅ per call | ✅ per rule |
|
|
307
|
+
| Code identity in cache key | git tree of `_target_` modules | ❌ | listed deps | task source | rule code |
|
|
308
|
+
| Slurm / PBS | ✅ | ✅ submitit | ❌ | ❌ cloud only | ✅ |
|
|
309
|
+
| Remote output storage | ❌ | ❌ | ✅ | ✅ | ✅ |
|
|
310
|
+
|
|
311
|
+
See [Philosophy & Design](docs/philosophy.md#comparison-with-other-tools) for
|
|
312
|
+
the full comparison and when to pick another tool.
|
|
319
313
|
|
|
320
314
|
## Contributing
|
|
321
315
|
|
|
@@ -88,6 +88,22 @@ flexlock gc results/ -f --refs
|
|
|
88
88
|
|
|
89
89
|
---
|
|
90
90
|
|
|
91
|
+
### `flexlock repair-locks` — Rewrite Placeholder run.locks
|
|
92
|
+
|
|
93
|
+
Single HPC/isolated runs submitted with FlexLock < 0.8.3 kept their real
|
|
94
|
+
snapshot only in `run.lock.tasks.db`; their `run.lock` is a placeholder. The
|
|
95
|
+
readers fall back to the DB automatically. This command rewrites those files
|
|
96
|
+
once (see [HPC Integration](hpc_integration.md#runlock-of-a-single-hpc-run)).
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
flexlock repair-locks results/ -n # dry run: list the dirs that would change
|
|
100
|
+
flexlock repair-locks results/ # rewrite; keeps run.lock.placeholder.bak
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Sweep roots are left alone (they have no single config).
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
91
107
|
### `flexlock show` — Inspect One Run
|
|
92
108
|
|
|
93
109
|
Machine-readable status, metadata, lineage, and config for a single run. The
|
|
@@ -153,6 +169,35 @@ DEF=myproject.pipeline.cfg
|
|
|
153
169
|
flexlock-run -d "$DEF" -s "$(flexlock stages -d "$DEF" --format keys | fzf)"
|
|
154
170
|
```
|
|
155
171
|
|
|
172
|
+
### `flexlock runs` — Runs of a Preset
|
|
173
|
+
|
|
174
|
+
List the complete runs of a preset (the `-d` target + `-s` key they were
|
|
175
|
+
launched with), newest first. See the usage guide, §7 "Presets".
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
flexlock runs xps_glob.train_small_cloud_gap_compact # suffix match
|
|
179
|
+
flexlock runs pkg.starter.xps_glob:train_x -s main --limit 5
|
|
180
|
+
flexlock runs train_x --strict # only runs made with no -o/-O/-m/-M
|
|
181
|
+
flexlock runs train_x --format json # {path, preset, select, completed, note, overrides}
|
|
182
|
+
flexlock runs train_x --root results_old # also search results_old/.flexlock
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
Searched: the `.flexlock/` serving the current directory, any `.flexlock/` up
|
|
186
|
+
to two levels below it, and `--root` dirs. Links to deleted runs are pruned.
|
|
187
|
+
|
|
188
|
+
### `flexlock presets` — Catalogue of a Config Module
|
|
189
|
+
|
|
190
|
+
List the attributes of a config module that hold runnable stages, with the
|
|
191
|
+
comment block above each definition, the `-s` keys, and run counts.
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
flexlock presets sst_ml_mapping.starter.xps_glob # text
|
|
195
|
+
flexlock presets sst_ml_mapping.starter.xps_glob --format md # a generated index
|
|
196
|
+
flexlock presets configs/defaults.py --format json
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
The module is imported, as `flexlock-run -d` would.
|
|
200
|
+
|
|
156
201
|
### `flexlock report` — Static HTML Report
|
|
157
202
|
|
|
158
203
|
Render a self-contained, offline-openable HTML report (no CDN) of a results tree.
|
|
@@ -281,8 +326,23 @@ flexlock-run -d myproject.defaults -s train
|
|
|
281
326
|
|
|
282
327
|
# Select nested node
|
|
283
328
|
flexlock-run -d myproject.defaults -s experiments.baseline
|
|
329
|
+
|
|
330
|
+
# Multi-stage: run several stages in order as a pipeline (space- or
|
|
331
|
+
# comma-separated). Each sweep item becomes one composite pipeline task.
|
|
332
|
+
flexlock-run -d myproject.defaults -s train linear_probe -o pipeline_dir=results/xp
|
|
333
|
+
flexlock-run -d myproject.defaults -s train,linear_probe \
|
|
334
|
+
--sweep-target pipeline_dir --sweep results/xp1,results/xp2 --n_jobs 2
|
|
284
335
|
```
|
|
285
336
|
|
|
337
|
+
**Multi-stage (`-s` with more than one stage)** runs the stages sequentially as
|
|
338
|
+
a pipeline (a downstream stage sees the upstream stage's artifacts on disk). It
|
|
339
|
+
composes with `--sweep*`, `--slurm-config`/`--pbs-config`, and `--enqueue`:
|
|
340
|
+
each sweep item is merged into the root config before selection, then becomes
|
|
341
|
+
one composite `{_stages_: [...]}` task whose stages run in order on one worker,
|
|
342
|
+
while parallelism / array workers fan out across items. It is only incompatible
|
|
343
|
+
with `-O`/`-M` and `-e` (they target a single selected node). See usage guide
|
|
344
|
+
§14g. All stages of an item share one scheduler job (no per-stage HPC resources).
|
|
345
|
+
|
|
286
346
|
**Works with:**
|
|
287
347
|
- Python configs (dict keys)
|
|
288
348
|
- YAML configs (nested keys)
|
|
@@ -320,6 +380,11 @@ flexlock-run -d defaults -o base_dir=outputs seed=42
|
|
|
320
380
|
- Primitive types: `param=1`, `flag=true`, `name=model`
|
|
321
381
|
- Nested paths: `model.layers=12`
|
|
322
382
|
- Lists: `devices=[0,1,2]`
|
|
383
|
+
- Swaps: `model=@big_model` **replaces** the node with the config
|
|
384
|
+
`big_model` from the `-d` module (or `@pkg.module.attr`); `@@x` is the
|
|
385
|
+
literal `@x`. Overrides apply in order, so `model=@big_model model.width=16`
|
|
386
|
+
tweaks the swapped model. Also valid for `-O` and in `--sweep` values. See
|
|
387
|
+
the usage guide, "Swapping a subtree".
|
|
323
388
|
|
|
324
389
|
---
|
|
325
390
|
|
|
@@ -515,9 +580,30 @@ perturb caching or diffs. It surfaces in `flexlock show`/`graph`/`report`.
|
|
|
515
580
|
flexlock-run -d defaults -s train --note "baseline before lr sweep"
|
|
516
581
|
```
|
|
517
582
|
|
|
518
|
-
For sweeps the note lands on the **master** `run.lock
|
|
519
|
-
|
|
520
|
-
`-s a b` run, the same note is applied
|
|
583
|
+
For sweeps the note lands on the **master** `run.lock`; sweep items inherit it
|
|
584
|
+
(copied into each task's `run.lock` with `--task-record dir`, looked up through
|
|
585
|
+
the master otherwise). For a multi-stage `-s a b` run, the same note is applied
|
|
586
|
+
to each stage.
|
|
587
|
+
|
|
588
|
+
---
|
|
589
|
+
|
|
590
|
+
### `--task-record {dir,db}`
|
|
591
|
+
Where each sweep task's record (config, code tree, env, fingerprint) is kept.
|
|
592
|
+
|
|
593
|
+
- `dir` (default, or `$FLEXLOCK_TASK_RECORD`): a full `run.lock` in the task's
|
|
594
|
+
`save_dir`, like a serial run. The directory describes itself.
|
|
595
|
+
- `db`: only in the task DB (`<sweep_root>/run.lock.tasks.db`), with a
|
|
596
|
+
`.flexlock_marker` pointer in the task dir. Use it for sweeps over thousands
|
|
597
|
+
of items (e.g. `--sweep-file paths.txt`) to avoid one more file per item.
|
|
598
|
+
|
|
599
|
+
Either way `flexlock diff`/`show`/`graph`/`why`, `${run_lock:}`, lineage and the
|
|
600
|
+
cache find the record. Single runs, including Slurm/PBS ones, always get a
|
|
601
|
+
`run.lock`. Sweep items that share one `save_dir` can't each have a
|
|
602
|
+
`run.lock`; the first task keeps the file and the others stay in the DB.
|
|
603
|
+
|
|
604
|
+
```bash
|
|
605
|
+
flexlock-run -d configs.defaults -s extract --sweep-file paths.txt --task-record db
|
|
606
|
+
```
|
|
521
607
|
|
|
522
608
|
---
|
|
523
609
|
|
|
@@ -572,8 +658,18 @@ flexlock-run -d defaults -s train --sweep-file queue.yaml --slurm-config slurm.y
|
|
|
572
658
|
save_dir: results/exp
|
|
573
659
|
```
|
|
574
660
|
|
|
661
|
+
**With a sweep** (`--sweep`/`--sweep-key`/`--sweep-file`), `--enqueue` appends
|
|
662
|
+
**one entry per sweep item** — each merged at `--sweep-target` and frozen —
|
|
663
|
+
instead of a single config. Previously the sweep was silently dropped.
|
|
664
|
+
|
|
665
|
+
**With multi-stage** (`-s` with more than one stage), `--enqueue` appends **one
|
|
666
|
+
composite `{_stages_: [...]}` entry per sweep item** (or one for a no-sweep
|
|
667
|
+
pipeline). Composite entries in a `--sweep-file` run as-is; plain entries in the
|
|
668
|
+
same file are merged into the compiled node config and run as single-stage
|
|
669
|
+
pipelines.
|
|
670
|
+
|
|
575
671
|
**Notes:**
|
|
576
|
-
- The enqueued config is stored with interpolations **unresolved** so that resolvers like `${vinc:}` fire at run time and each task gets its own unique directory.
|
|
672
|
+
- The enqueued config is stored with interpolations **unresolved** so that resolvers like `${vinc:}`/`${run_lock:}`/`${latest:}` fire at run time and each task gets its own unique directory.
|
|
577
673
|
- Writes are atomic (temp-file + rename) so concurrent `--enqueue` calls from different terminals are safe.
|
|
578
674
|
- Re-running `--sweep-file queue.yaml` after adding new items is safe: tasks already completed are skipped via the `INSERT OR IGNORE` logic in the task DB.
|
|
579
675
|
|