calkit-python 0.28.2__tar.gz → 0.28.4__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.
- {calkit_python-0.28.2 → calkit_python-0.28.4}/PKG-INFO +1 -1
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/__init__.py +1 -1
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/cli/new.py +31 -3
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/cli/notebooks.py +39 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/models/iteration.py +25 -1
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/models/pipeline.py +48 -4
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/notebooks.py +21 -1
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/pipeline.py +27 -13
- calkit_python-0.28.4/calkit/tests/cli/test_notebooks.py +137 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/tests/models/test_pipeline.py +4 -2
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/tests/test_pipeline.py +1 -3
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/notebooks.md +1 -1
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/quickstart.md +1 -1
- calkit_python-0.28.4/docs/tutorials/github-actions.md +83 -0
- calkit_python-0.28.4/docs/tutorials/img/actions-repo-secrets.png +0 -0
- calkit_python-0.28.4/docs/tutorials/img/latex-codespaces/new-token.png +0 -0
- calkit_python-0.28.4/docs/tutorials/img/quick-actions.png +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/tutorials/index.md +1 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/mkdocs.yml +1 -0
- calkit_python-0.28.4/test/nb-params.ipynb +56 -0
- calkit_python-0.28.2/calkit/tests/cli/test_notebooks.py +0 -47
- calkit_python-0.28.2/docs/tutorials/img/latex-codespaces/new-token.png +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/.github/FUNDING.yml +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/.github/workflows/docs.yml +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/.github/workflows/format.yml +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/.github/workflows/publish-test.yml +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/.github/workflows/publish.yml +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/.github/workflows/test.yml +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/.gitignore +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/.pre-commit-config.yaml +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/.python-version +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/CITATION.cff +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/CONTRIBUTING.md +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/LICENSE +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/Makefile +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/README.md +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/__main__.py +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/calc.py +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/check.py +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/cli/__init__.py +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/cli/check.py +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/cli/cloud.py +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/cli/config.py +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/cli/core.py +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/cli/describe.py +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/cli/import_.py +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/cli/list.py +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/cli/main.py +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/cli/office.py +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/cli/overleaf.py +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/cli/update.py +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/cloud.py +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/conda.py +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/config.py +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/core.py +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/datasets.py +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/docker.py +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/dvc.py +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/environments.py +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/git.py +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/github.py +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/gui.py +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/jupyter.py +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/magics.py +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/matlab.py +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/models/__init__.py +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/models/core.py +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/models/io.py +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/office.py +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/ops.py +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/releases.py +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/server.py +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/templates/__init__.py +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/templates/core.py +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/templates/latex/__init__.py +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/templates/latex/article/paper.tex +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/templates/latex/core.py +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/templates/latex/jfm/jfm.bst +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/templates/latex/jfm/jfm.cls +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/templates/latex/jfm/lineno-FLM.sty +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/templates/latex/jfm/paper.tex +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/templates/latex/jfm/upmath.sty +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/tests/__init__.py +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/tests/cli/__init__.py +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/tests/cli/test_check.py +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/tests/cli/test_config.py +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/tests/cli/test_list.py +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/tests/cli/test_main.py +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/tests/cli/test_new.py +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/tests/models/__init__.py +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/tests/models/test_iteration.py +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/tests/test_calc.py +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/tests/test_check.py +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/tests/test_conda.py +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/tests/test_core.py +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/tests/test_dvc.py +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/tests/test_jupyter.py +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/tests/test_magics.py +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/tests/test_notebooks.py +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/tests/test_templates.py +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/calkit/zenodo.py +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/CNAME +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/apps.md +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/calculations.md +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/calkit-yaml.md +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/cli-reference.md +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/cloud-integration.md +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/datasets.md +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/dependencies.md +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/environments.md +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/examples.md +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/help.md +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/img/c-to-the-k-white.svg +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/img/calkit-no-bg.png +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/img/connect-zenodo.png +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/img/jupyterlab-params.png +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/img/vscode-nb-params.png +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/index.md +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/installation.md +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/local-server.md +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/overleaf.md +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/pipeline/index.md +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/pipeline/manual-steps.md +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/pipeline/running-and-logging.md +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/references.md +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/releases.md +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/tutorials/adding-latex-pub-docker.md +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/tutorials/conda-envs.md +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/tutorials/existing-project.md +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/tutorials/first-project.md +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/tutorials/img/latex-codespaces/building-codespace.png +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/tutorials/img/latex-codespaces/codespaces-secrets-2.png +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/tutorials/img/latex-codespaces/editor-split.png +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/tutorials/img/latex-codespaces/go-to-linked-code.png +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/tutorials/img/latex-codespaces/issue-from-selection.png +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/tutorials/img/latex-codespaces/new-project.png +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/tutorials/img/latex-codespaces/new-pub-2.png +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/tutorials/img/latex-codespaces/paper.tex.png +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/tutorials/img/latex-codespaces/project-home-3.png +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/tutorials/img/latex-codespaces/push.png +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/tutorials/img/latex-codespaces/stage.png +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/tutorials/img/office/anakin-excel.jpg +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/tutorials/img/office/chart-more-rows.png +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/tutorials/img/office/create-project.png +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/tutorials/img/office/elsevier-research-data-guidelines.png +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/tutorials/img/office/excel-chart.png +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/tutorials/img/office/excel-data.png +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/tutorials/img/office/insert-link-to-file.png +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/tutorials/img/office/needs-clone.png +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/tutorials/img/office/new-stage.png +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/tutorials/img/office/phd-comics-version-control.webp +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/tutorials/img/office/pipeline-out-of-date.png +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/tutorials/img/office/status-more-rows.png +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/tutorials/img/office/uncommitted-changes.png +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/tutorials/img/office/untracked-data.png +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/tutorials/img/office/updated-publication.png +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/tutorials/img/office/word-to-pdf-stage-2.png +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/tutorials/img/office/workflow-page.png +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/tutorials/img/openfoam/clone.png +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/tutorials/img/openfoam/create-project.png +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/tutorials/img/openfoam/datasets-page.png +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/tutorials/img/openfoam/figure-on-website-updated.png +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/tutorials/img/openfoam/figure-on-website.png +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/tutorials/img/openfoam/new-token.png +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/tutorials/img/openfoam/reclone.png +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/tutorials/img/openfoam/status-after-import-dataset.png +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/tutorials/img/run-proc.png +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/tutorials/latex-codespaces.md +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/tutorials/matlab.md +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/tutorials/notebook-pipeline.md +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/tutorials/office.md +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/tutorials/openfoam.md +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/tutorials/procedures.md +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/docs/version-control.md +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/pyproject.toml +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/scripts/install.ps1 +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/scripts/install.sh +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/test/nb-subdir.ipynb +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/test/pipeline.ipynb +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/test/test-log.log +0 -0
- {calkit_python-0.28.2 → calkit_python-0.28.4}/uv.lock +0 -0
|
@@ -157,10 +157,16 @@ def new_project(
|
|
|
157
157
|
repo.git.commit(["-m", "Initialize DVC"])
|
|
158
158
|
ck_info_fpath = os.path.join(abs_path, "calkit.yaml")
|
|
159
159
|
if os.path.isfile(ck_info_fpath) and not overwrite:
|
|
160
|
-
|
|
160
|
+
ck_info = calkit.load_calkit_info(wdir=abs_path)
|
|
161
|
+
name = ck_info.get("name", name)
|
|
162
|
+
title = ck_info.get("title", title)
|
|
163
|
+
description = ck_info.get("description", description)
|
|
164
|
+
typer.echo(
|
|
161
165
|
"Destination is already a Calkit project; "
|
|
162
|
-
"use
|
|
166
|
+
"will use existing project info where possible"
|
|
163
167
|
)
|
|
168
|
+
else:
|
|
169
|
+
ck_info = {}
|
|
164
170
|
if os.path.isdir(abs_path) and os.listdir(abs_path) and repo is None:
|
|
165
171
|
warn(f"{abs_path} is not empty")
|
|
166
172
|
if name is None:
|
|
@@ -224,7 +230,29 @@ def new_project(
|
|
|
224
230
|
)
|
|
225
231
|
repo.git.add("calkit.yaml")
|
|
226
232
|
if not no_commit:
|
|
227
|
-
repo.git.commit(
|
|
233
|
+
repo.git.commit(
|
|
234
|
+
["calkit.yaml", "-m", "Create calkit.yaml"]
|
|
235
|
+
)
|
|
236
|
+
else:
|
|
237
|
+
# Merge with existing project info in calkit.yaml
|
|
238
|
+
typer.echo("Updating existing calkit.yaml file")
|
|
239
|
+
ck_info = (
|
|
240
|
+
dict(
|
|
241
|
+
owner=resp["owner_account_name"],
|
|
242
|
+
name=resp["name"],
|
|
243
|
+
title=resp["title"],
|
|
244
|
+
description=resp["description"],
|
|
245
|
+
git_repo_url=resp["git_repo_url"],
|
|
246
|
+
)
|
|
247
|
+
| ck_info
|
|
248
|
+
)
|
|
249
|
+
with open(calkit_fpath, "w") as f:
|
|
250
|
+
ryaml.dump(ck_info, f)
|
|
251
|
+
repo.git.add("calkit.yaml")
|
|
252
|
+
if not no_commit and repo.git.diff("--staged"):
|
|
253
|
+
repo.git.commit(
|
|
254
|
+
["calkit.yaml", "-m", "Update calkit.yaml"]
|
|
255
|
+
)
|
|
228
256
|
try:
|
|
229
257
|
calkit.dvc.configure_remote(wdir=abs_path)
|
|
230
258
|
except Exception:
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
import base64
|
|
6
|
+
import json
|
|
5
7
|
import os
|
|
6
8
|
import subprocess
|
|
7
9
|
import sys
|
|
@@ -140,6 +142,27 @@ def execute_notebook(
|
|
|
140
142
|
help="Parameter to pass to the notebook in key=value format.",
|
|
141
143
|
),
|
|
142
144
|
] = [],
|
|
145
|
+
params_json: Annotated[
|
|
146
|
+
str | None,
|
|
147
|
+
typer.Option(
|
|
148
|
+
"--params-json",
|
|
149
|
+
"-j",
|
|
150
|
+
help=(
|
|
151
|
+
"JSON string to parse as parameters to pass to the notebook."
|
|
152
|
+
),
|
|
153
|
+
),
|
|
154
|
+
] = None,
|
|
155
|
+
params_base64: Annotated[
|
|
156
|
+
str | None,
|
|
157
|
+
typer.Option(
|
|
158
|
+
"--params-base64",
|
|
159
|
+
"-b",
|
|
160
|
+
help=(
|
|
161
|
+
"Base64-encoded JSON string to parse as parameters to pass to "
|
|
162
|
+
"the notebook."
|
|
163
|
+
),
|
|
164
|
+
),
|
|
165
|
+
] = None,
|
|
143
166
|
verbose: Annotated[
|
|
144
167
|
bool, typer.Option("--verbose", "-v", help="Print verbose output.")
|
|
145
168
|
] = False,
|
|
@@ -165,6 +188,17 @@ def execute_notebook(
|
|
|
165
188
|
raise_error(str(e))
|
|
166
189
|
else:
|
|
167
190
|
parsed_params = {}
|
|
191
|
+
# Parse JSON parameters
|
|
192
|
+
if params_json is not None:
|
|
193
|
+
parsed_params_json = json.loads(params_json)
|
|
194
|
+
parsed_params |= parsed_params_json
|
|
195
|
+
# Parse base64 parameters
|
|
196
|
+
if params_base64 is not None:
|
|
197
|
+
try:
|
|
198
|
+
decoded_json = base64.b64decode(params_base64).decode("utf-8")
|
|
199
|
+
parsed_params |= json.loads(decoded_json)
|
|
200
|
+
except Exception as e:
|
|
201
|
+
raise_error(f"Failed to parse base64 parameters: {e}")
|
|
168
202
|
# Next, always execute the notebook and save as ipynb
|
|
169
203
|
fpath_out_exec = calkit.notebooks.get_executed_notebook_path(
|
|
170
204
|
notebook_path=path,
|
|
@@ -175,6 +209,11 @@ def execute_notebook(
|
|
|
175
209
|
folder = os.path.dirname(fpath_out_exec)
|
|
176
210
|
os.makedirs(folder, exist_ok=True)
|
|
177
211
|
notebook_dir = os.path.dirname(path) or None
|
|
212
|
+
if verbose:
|
|
213
|
+
typer.echo(f"Executing notebook {path} with params: {parsed_params}")
|
|
214
|
+
typer.echo(f"Using kernel: {kernel_name}")
|
|
215
|
+
typer.echo(f"Running with cwd: {notebook_dir}")
|
|
216
|
+
typer.echo(f"Output will be saved to: {fpath_out_exec}")
|
|
178
217
|
papermill.execute_notebook(
|
|
179
218
|
input_path=path,
|
|
180
219
|
output_path=fpath_out_exec,
|
|
@@ -60,11 +60,15 @@ ParametersType = dict[
|
|
|
60
60
|
int | float | str | list[int | float | str | RangeIteration],
|
|
61
61
|
]
|
|
62
62
|
|
|
63
|
+
ExpandedParametersType = dict[str, int | float | str | list[int | float | str]]
|
|
64
|
+
|
|
63
65
|
|
|
64
66
|
class ParameterIteration(BaseModel):
|
|
65
67
|
parameter: str
|
|
66
68
|
|
|
67
|
-
def values_from_params(
|
|
69
|
+
def values_from_params(
|
|
70
|
+
self, params: ParametersType | ExpandedParametersType
|
|
71
|
+
) -> list:
|
|
68
72
|
"""Convert parameters from calkit.yaml into a list of values."""
|
|
69
73
|
if self.parameter not in params:
|
|
70
74
|
raise ValueError(f"'{self.parameter}' not found in parameters")
|
|
@@ -79,3 +83,23 @@ class ParameterIteration(BaseModel):
|
|
|
79
83
|
else:
|
|
80
84
|
vals.append(val)
|
|
81
85
|
return vals
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def expand_project_parameters(
|
|
89
|
+
params: ParametersType,
|
|
90
|
+
) -> ExpandedParametersType:
|
|
91
|
+
"""Expand any range iterations in project parameters."""
|
|
92
|
+
expanded = {}
|
|
93
|
+
for key, value in params.items():
|
|
94
|
+
if isinstance(value, list):
|
|
95
|
+
expanded_list = []
|
|
96
|
+
for item in value:
|
|
97
|
+
try:
|
|
98
|
+
range_iter = RangeIteration.model_validate(item)
|
|
99
|
+
expanded_list.extend(range_iter.values)
|
|
100
|
+
except Exception:
|
|
101
|
+
expanded_list.append(item)
|
|
102
|
+
expanded[key] = expanded_list
|
|
103
|
+
else:
|
|
104
|
+
expanded[key] = value
|
|
105
|
+
return expanded
|
|
@@ -2,14 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
import base64
|
|
6
|
+
import json
|
|
5
7
|
from pathlib import PurePosixPath
|
|
6
8
|
from typing import Any, Literal
|
|
7
9
|
|
|
8
|
-
from pydantic import
|
|
10
|
+
from pydantic import (
|
|
11
|
+
BaseModel,
|
|
12
|
+
ConfigDict,
|
|
13
|
+
Discriminator,
|
|
14
|
+
ValidationError,
|
|
15
|
+
field_validator,
|
|
16
|
+
)
|
|
9
17
|
from typing_extensions import Annotated
|
|
10
18
|
|
|
11
19
|
from calkit.models.io import InputsFromStageOutputs, PathOutput
|
|
12
20
|
from calkit.models.iteration import (
|
|
21
|
+
ExpandedParametersType,
|
|
13
22
|
ParameterIteration,
|
|
14
23
|
ParametersType,
|
|
15
24
|
RangeIteration,
|
|
@@ -69,7 +78,7 @@ class StageIteration(BaseModel):
|
|
|
69
78
|
return v
|
|
70
79
|
|
|
71
80
|
def expand_values(
|
|
72
|
-
self, params: ParametersType
|
|
81
|
+
self, params: ParametersType | ExpandedParametersType
|
|
73
82
|
) -> list[int | float | str | dict[str, int | float | str]]:
|
|
74
83
|
vals = []
|
|
75
84
|
if isinstance(self.arg_name, list):
|
|
@@ -365,6 +374,34 @@ class JupyterNotebookStage(Stage):
|
|
|
365
374
|
html_storage: Literal["git", "dvc"] | None = "dvc"
|
|
366
375
|
parameters: dict[str, Any] = {}
|
|
367
376
|
|
|
377
|
+
def update_parameters(self, params: dict) -> None:
|
|
378
|
+
"""If we have any templated parameters, update those, e.g., from
|
|
379
|
+
project-level parameters.
|
|
380
|
+
|
|
381
|
+
This needs to happen before writing a DVC stage, so we can properly
|
|
382
|
+
create JSON for the notebook.
|
|
383
|
+
"""
|
|
384
|
+
updated_params = {}
|
|
385
|
+
for k, v in self.parameters.items():
|
|
386
|
+
# If we have something like {var_name} in v, replace it with the
|
|
387
|
+
# value from params
|
|
388
|
+
if isinstance(v, str) and v.startswith("{") and v.endswith("}"):
|
|
389
|
+
var_name = v[1:-1]
|
|
390
|
+
if var_name in params:
|
|
391
|
+
updated_params[k] = params[var_name]
|
|
392
|
+
else:
|
|
393
|
+
updated_params[k] = v
|
|
394
|
+
else:
|
|
395
|
+
updated_params[k] = v
|
|
396
|
+
# Try parsing as a RangeIteration and expanding
|
|
397
|
+
try:
|
|
398
|
+
updated_params[k] = RangeIteration.model_validate(
|
|
399
|
+
updated_params[k]
|
|
400
|
+
).values
|
|
401
|
+
except ValidationError:
|
|
402
|
+
pass
|
|
403
|
+
self.parameters = updated_params
|
|
404
|
+
|
|
368
405
|
@property
|
|
369
406
|
def cleaned_notebook_path(self) -> str:
|
|
370
407
|
return get_cleaned_notebook_path(self.notebook_path, as_posix=True)
|
|
@@ -396,8 +433,15 @@ class JupyterNotebookStage(Stage):
|
|
|
396
433
|
cmd = f"calkit nb execute --environment {self.environment} --no-check"
|
|
397
434
|
if self.html_storage:
|
|
398
435
|
cmd += " --to html"
|
|
399
|
-
|
|
400
|
-
|
|
436
|
+
if self.parameters:
|
|
437
|
+
# If we have parameters, we need to pass them as JSON, escaping
|
|
438
|
+
# double quotes
|
|
439
|
+
params_json = json.dumps(self.parameters)
|
|
440
|
+
# Now base64 encode
|
|
441
|
+
params_base64 = base64.b64encode(
|
|
442
|
+
params_json.encode("utf-8")
|
|
443
|
+
).decode("utf-8")
|
|
444
|
+
cmd += f' --params-base64 "{params_base64}"'
|
|
401
445
|
cmd += f' "{self.notebook_path}"'
|
|
402
446
|
return cmd
|
|
403
447
|
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
"""Functionality for working with notebooks."""
|
|
2
2
|
|
|
3
|
+
import hashlib
|
|
4
|
+
import json
|
|
3
5
|
import os
|
|
4
6
|
from pathlib import PurePosixPath
|
|
5
7
|
from typing import Any, Literal
|
|
@@ -21,7 +23,25 @@ def get_executed_notebook_path(
|
|
|
21
23
|
nb_fname = os.path.basename(notebook_path)
|
|
22
24
|
# If we have any parameters, add these to the notebook name
|
|
23
25
|
if parameters:
|
|
24
|
-
|
|
26
|
+
parameters_cleaned = {}
|
|
27
|
+
for k, v in parameters.items():
|
|
28
|
+
if isinstance(v, list):
|
|
29
|
+
if len(v) == 0:
|
|
30
|
+
v = "empty"
|
|
31
|
+
elif len(v) < 5:
|
|
32
|
+
v = ",".join(map(str, v))
|
|
33
|
+
else:
|
|
34
|
+
v = hashlib.md5(
|
|
35
|
+
json.dumps(v, sort_keys=True).encode()
|
|
36
|
+
).hexdigest()[:7]
|
|
37
|
+
elif isinstance(v, dict):
|
|
38
|
+
v = hashlib.md5(
|
|
39
|
+
json.dumps(v, sort_keys=True).encode()
|
|
40
|
+
).hexdigest()[:7]
|
|
41
|
+
parameters_cleaned[k] = v
|
|
42
|
+
params_txt = "-".join(
|
|
43
|
+
f"{k}-{v}" for k, v in parameters_cleaned.items()
|
|
44
|
+
)
|
|
25
45
|
nb_fname = f"{nb_fname.removesuffix('.ipynb')}-{params_txt}.ipynb"
|
|
26
46
|
if to == "html":
|
|
27
47
|
fname_out = nb_fname.removesuffix(".ipynb") + ".html"
|
|
@@ -8,6 +8,7 @@ import typer
|
|
|
8
8
|
|
|
9
9
|
import calkit
|
|
10
10
|
from calkit.environments import get_env_lock_fpath
|
|
11
|
+
from calkit.models.iteration import expand_project_parameters
|
|
11
12
|
from calkit.models.pipeline import (
|
|
12
13
|
InputsFromStageOutputs,
|
|
13
14
|
PathOutput,
|
|
@@ -92,8 +93,13 @@ def to_dvc(
|
|
|
92
93
|
)
|
|
93
94
|
dvc_stages[f"_check-env-{env_name}"] = stage
|
|
94
95
|
env_lock_fpaths[env_name] = lock_fpath
|
|
96
|
+
project_params = expand_project_parameters(ck_info.get("parameters", {}))
|
|
95
97
|
# Now convert Calkit stages into DVC stages
|
|
96
98
|
for stage_name, stage in pipeline.stages.items():
|
|
99
|
+
# If this stage is a Jupyter notebook stage, we need to update its
|
|
100
|
+
# parameters if any reference project-level parameters
|
|
101
|
+
if stage.kind == "jupyter-notebook":
|
|
102
|
+
stage.update_parameters(params=project_params)
|
|
97
103
|
dvc_stage = stage.to_dvc()
|
|
98
104
|
# Add environment lock file to deps
|
|
99
105
|
env_lock_fpath = env_lock_fpaths.get(stage.environment)
|
|
@@ -112,9 +118,7 @@ def to_dvc(
|
|
|
112
118
|
format_dict = {}
|
|
113
119
|
for n, iteration in enumerate(stage.iterate_over):
|
|
114
120
|
arg_name = iteration.arg_name
|
|
115
|
-
exp_vals = iteration.expand_values(
|
|
116
|
-
params=ck_info.get("parameters", {})
|
|
117
|
-
)
|
|
121
|
+
exp_vals = iteration.expand_values(params=project_params)
|
|
118
122
|
if isinstance(arg_name, list):
|
|
119
123
|
dvc_arg_name = f"_arg{n}"
|
|
120
124
|
for arg_name_i in arg_name:
|
|
@@ -143,21 +147,31 @@ def to_dvc(
|
|
|
143
147
|
except Exception as e:
|
|
144
148
|
raise ValueError(
|
|
145
149
|
(
|
|
146
|
-
f"Failed to format dep '{dep}'
|
|
150
|
+
f"Failed to format dep '{dep}' with "
|
|
151
|
+
f"'{format_dict}': "
|
|
147
152
|
f"{e.__class__.__name__}: {e}"
|
|
148
153
|
)
|
|
149
154
|
)
|
|
150
155
|
for out in dvc_stage.get("outs", []):
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
156
|
+
try:
|
|
157
|
+
if isinstance(out, dict):
|
|
158
|
+
formatted_outs.append(
|
|
159
|
+
{
|
|
160
|
+
str(list(out.keys())[0]).format(
|
|
161
|
+
**format_dict
|
|
162
|
+
): dict(list(out.values())[0])
|
|
163
|
+
}
|
|
164
|
+
)
|
|
165
|
+
else:
|
|
166
|
+
formatted_outs.append(out.format(**format_dict))
|
|
167
|
+
except Exception as e:
|
|
168
|
+
raise ValueError(
|
|
169
|
+
(
|
|
170
|
+
f"Failed to format out '{out}' with "
|
|
171
|
+
f"'{format_dict}': "
|
|
172
|
+
f"{e.__class__.__name__}: {e}"
|
|
173
|
+
)
|
|
158
174
|
)
|
|
159
|
-
else:
|
|
160
|
-
formatted_outs.append(out.format(**format_dict))
|
|
161
175
|
dvc_stage["deps"] = formatted_deps
|
|
162
176
|
dvc_stage["outs"] = formatted_outs
|
|
163
177
|
dvc_stage["matrix"] = dvc_matrix
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"""Tests for ``calkit.cli.notebooks``."""
|
|
2
|
+
|
|
3
|
+
import base64
|
|
4
|
+
import json
|
|
5
|
+
import os
|
|
6
|
+
import shutil
|
|
7
|
+
import subprocess
|
|
8
|
+
|
|
9
|
+
import calkit
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def test_clean_notebook_outputs(tmp_dir):
|
|
13
|
+
# Copy in a test notebook and clean it
|
|
14
|
+
nb_fpath = os.path.join(
|
|
15
|
+
os.path.dirname(__file__), "..", "..", "..", "test", "pipeline.ipynb"
|
|
16
|
+
)
|
|
17
|
+
shutil.copy(nb_fpath, "notebook.ipynb")
|
|
18
|
+
subprocess.check_call(["calkit", "nb", "clean", "notebook.ipynb"])
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def test_execute_notebook(tmp_dir):
|
|
22
|
+
subprocess.check_call(
|
|
23
|
+
[
|
|
24
|
+
"calkit",
|
|
25
|
+
"new",
|
|
26
|
+
"project",
|
|
27
|
+
".",
|
|
28
|
+
"-n",
|
|
29
|
+
"cool-project",
|
|
30
|
+
"--title",
|
|
31
|
+
"Cool project",
|
|
32
|
+
]
|
|
33
|
+
)
|
|
34
|
+
subprocess.check_call(
|
|
35
|
+
["calkit", "new", "uv-venv", "-n", "main", "ipykernel"]
|
|
36
|
+
)
|
|
37
|
+
nb_fpath = os.path.join(
|
|
38
|
+
os.path.dirname(__file__), "..", "..", "..", "test", "nb-subdir.ipynb"
|
|
39
|
+
)
|
|
40
|
+
os.makedirs("notebooks/results")
|
|
41
|
+
shutil.copy(nb_fpath, "notebooks/main.ipynb")
|
|
42
|
+
subprocess.check_call(
|
|
43
|
+
["calkit", "nb", "execute", "notebooks/main.ipynb", "-e", "main"]
|
|
44
|
+
)
|
|
45
|
+
assert os.path.isfile("notebooks/results/something.txt")
|
|
46
|
+
os.makedirs("results")
|
|
47
|
+
shutil.copy("notebooks/main.ipynb", "main.ipynb")
|
|
48
|
+
subprocess.check_call(
|
|
49
|
+
["calkit", "nb", "execute", "main.ipynb", "-e", "main"]
|
|
50
|
+
)
|
|
51
|
+
assert os.path.isfile("results/something.txt")
|
|
52
|
+
# Test we can execute with parameters
|
|
53
|
+
nb_fpath = os.path.join(
|
|
54
|
+
os.path.dirname(__file__), "..", "..", "..", "test", "nb-params.ipynb"
|
|
55
|
+
)
|
|
56
|
+
shutil.copy(nb_fpath, "nb-params.ipynb")
|
|
57
|
+
params1 = {
|
|
58
|
+
"my_value": 5,
|
|
59
|
+
"my_list": [1, 2, 3],
|
|
60
|
+
}
|
|
61
|
+
params2 = {
|
|
62
|
+
"my_dict": {"something": 55.5, "else": "b"},
|
|
63
|
+
}
|
|
64
|
+
subprocess.check_call(
|
|
65
|
+
[
|
|
66
|
+
"calkit",
|
|
67
|
+
"nb",
|
|
68
|
+
"execute",
|
|
69
|
+
"nb-params.ipynb",
|
|
70
|
+
"-e",
|
|
71
|
+
"main",
|
|
72
|
+
"--params-json",
|
|
73
|
+
json.dumps(params1),
|
|
74
|
+
"--params-base64",
|
|
75
|
+
base64.b64encode(json.dumps(params2).encode("utf-8")).decode(
|
|
76
|
+
"utf-8"
|
|
77
|
+
),
|
|
78
|
+
"--verbose",
|
|
79
|
+
]
|
|
80
|
+
)
|
|
81
|
+
params = params1 | params2
|
|
82
|
+
with open("params-out.json") as f:
|
|
83
|
+
params_out = json.load(f)
|
|
84
|
+
assert params_out["my_value"] == params["my_value"]
|
|
85
|
+
assert params_out["my_list"] == params["my_list"]
|
|
86
|
+
assert params_out["my_dict"] == params["my_dict"]
|
|
87
|
+
# Test we can execute in the pipeline with params
|
|
88
|
+
pipeline = {
|
|
89
|
+
"stages": {
|
|
90
|
+
"nb-params": {
|
|
91
|
+
"kind": "jupyter-notebook",
|
|
92
|
+
"notebook_path": "nb-params.ipynb",
|
|
93
|
+
"environment": "main",
|
|
94
|
+
"parameters": params,
|
|
95
|
+
"html_storage": None,
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
ck_info = calkit.load_calkit_info()
|
|
100
|
+
ck_info["pipeline"] = pipeline
|
|
101
|
+
with open("calkit.yaml", "w") as f:
|
|
102
|
+
calkit.ryaml.dump(ck_info, f)
|
|
103
|
+
subprocess.check_call(["calkit", "run"])
|
|
104
|
+
with open("params-out.json") as f:
|
|
105
|
+
params_out = json.load(f)
|
|
106
|
+
assert params_out["my_value"] == params["my_value"]
|
|
107
|
+
assert params_out["my_list"] == params["my_list"]
|
|
108
|
+
assert params_out["my_dict"] == params["my_dict"]
|
|
109
|
+
# Test we can patch in a range iteration from project parameters
|
|
110
|
+
project_params = {
|
|
111
|
+
"my_range": {"range": {"start": 1, "stop": 6, "step": 1}},
|
|
112
|
+
"my_project_value": 77,
|
|
113
|
+
}
|
|
114
|
+
pipeline = {
|
|
115
|
+
"stages": {
|
|
116
|
+
"nb-params": {
|
|
117
|
+
"kind": "jupyter-notebook",
|
|
118
|
+
"notebook_path": "nb-params.ipynb",
|
|
119
|
+
"environment": "main",
|
|
120
|
+
"parameters": params
|
|
121
|
+
| {"my_list": "{my_range}", "my_value": "{my_project_value}"},
|
|
122
|
+
"html_storage": None,
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
ck_info = calkit.load_calkit_info()
|
|
127
|
+
ck_info["parameters"] = project_params
|
|
128
|
+
ck_info["pipeline"] = pipeline
|
|
129
|
+
with open("calkit.yaml", "w") as f:
|
|
130
|
+
calkit.ryaml.dump(ck_info, f)
|
|
131
|
+
os.remove("params-out.json")
|
|
132
|
+
subprocess.check_call(["calkit", "run"])
|
|
133
|
+
with open("params-out.json") as f:
|
|
134
|
+
params_out = json.load(f)
|
|
135
|
+
assert params_out["my_value"] == project_params["my_project_value"]
|
|
136
|
+
assert params_out["my_list"] == list(range(1, 6))
|
|
137
|
+
assert params_out["my_dict"] == params["my_dict"]
|
|
@@ -105,8 +105,10 @@ def test_jupyternotebookstage():
|
|
|
105
105
|
assert s.html_path not in outs
|
|
106
106
|
assert s.executed_notebook_path in outs
|
|
107
107
|
assert "html" not in dvc_stage["cmd"]
|
|
108
|
-
assert
|
|
109
|
-
|
|
108
|
+
assert (
|
|
109
|
+
" --params-base64 "
|
|
110
|
+
'"eyJwYXJhbTEiOiAidmFsdWUxIiwgInBhcmFtMiI6ICJ2YWx1ZTIifQ==" '
|
|
111
|
+
) in dvc_stage["cmd"]
|
|
110
112
|
|
|
111
113
|
|
|
112
114
|
def test_stageiteration():
|
|
@@ -269,9 +269,7 @@ def test_to_dvc_notebook_stage():
|
|
|
269
269
|
print(dvc_stages)
|
|
270
270
|
stage = dvc_stages["notebook-1"]
|
|
271
271
|
assert stage["cmd"].startswith("calkit nb execute")
|
|
272
|
-
assert "
|
|
273
|
-
assert " -p param2=${item.param2} " in stage["cmd"]
|
|
274
|
-
assert " -p param3=${item.param3} " in stage["cmd"]
|
|
272
|
+
assert "--params-base64" in stage["cmd"]
|
|
275
273
|
assert stage["matrix"]["param1"][0] == 5.0
|
|
276
274
|
assert "m" in stage["matrix"]["param2"]
|
|
277
275
|
assert "something" in stage["matrix"]["param3"]
|
|
@@ -25,7 +25,7 @@ If you're using Conda for environment management,
|
|
|
25
25
|
e.g., with an `environment.yml` file,
|
|
26
26
|
you can use the `calkit new conda-env` command.
|
|
27
27
|
|
|
28
|
-
Next, we can start building our [pipeline](pipeline.md).
|
|
28
|
+
Next, we can start building our [pipeline](pipeline/index.md).
|
|
29
29
|
Let's say we have a Jupyter notebook called `collect-data.ipynb`
|
|
30
30
|
that produces raw data at `data/raw.h5`.
|
|
31
31
|
We can add a pipeline stage to run this notebook in the `main` environment
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# Running Calkit in GitHub Actions
|
|
2
|
+
|
|
3
|
+
A project can be set up to automatically run the pipeline every time a
|
|
4
|
+
change is pushed, either to the main branch or on a pull request,
|
|
5
|
+
using GitHub Actions.
|
|
6
|
+
The latter allows for inspection of outputs before merging into main.
|
|
7
|
+
|
|
8
|
+
To get started, generate a DVC token and set it in your GitHub Actions
|
|
9
|
+
secrets as `CALKIT_DVC_TOKEN`,
|
|
10
|
+
either at your account or project level.
|
|
11
|
+
On calkit.io, there are shortcuts on the project page for managing both
|
|
12
|
+
Calkit tokens and GitHub Actions secrets:
|
|
13
|
+
|
|
14
|
+

|
|
15
|
+
|
|
16
|
+

|
|
17
|
+
|
|
18
|
+

|
|
19
|
+
|
|
20
|
+
Next, add a workflow to the project in the `.github/workflows` folder.
|
|
21
|
+
For example, we can put the content below into `.github/workflows/run.yml`:
|
|
22
|
+
|
|
23
|
+
```yaml
|
|
24
|
+
name: Run pipeline
|
|
25
|
+
|
|
26
|
+
on:
|
|
27
|
+
push:
|
|
28
|
+
branches:
|
|
29
|
+
- main
|
|
30
|
+
pull_request:
|
|
31
|
+
|
|
32
|
+
permissions:
|
|
33
|
+
contents: write
|
|
34
|
+
|
|
35
|
+
# Make sure we only ever run one per branch so we don't have issues pushing
|
|
36
|
+
# after running the pipeline
|
|
37
|
+
concurrency:
|
|
38
|
+
group: calkit-run-${{ github.ref }}
|
|
39
|
+
cancel-in-progress: false
|
|
40
|
+
|
|
41
|
+
jobs:
|
|
42
|
+
main:
|
|
43
|
+
name: Run
|
|
44
|
+
runs-on: ubuntu-latest
|
|
45
|
+
steps:
|
|
46
|
+
- uses: actions/checkout@v4
|
|
47
|
+
with:
|
|
48
|
+
# For PRs, checkout the head ref to avoid detached HEAD
|
|
49
|
+
ref: ${{ github.head_ref || github.ref_name }}
|
|
50
|
+
token: ${{ secrets.GITHUB_TOKEN }}
|
|
51
|
+
- name: Configure Git credentials
|
|
52
|
+
run: |
|
|
53
|
+
git config user.name github-actions[bot]
|
|
54
|
+
git config user.email 41898282+github-actions[bot]@users.noreply.github.com
|
|
55
|
+
- name: Setup uv
|
|
56
|
+
uses: astral-sh/setup-uv@v5
|
|
57
|
+
- name: Install Calkit
|
|
58
|
+
run: uv tool install calkit-python
|
|
59
|
+
- name: Run Calkit
|
|
60
|
+
uses: calkit/run-action@v1
|
|
61
|
+
with:
|
|
62
|
+
dvc_token: ${{ secrets.CALKIT_DVC_TOKEN }}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
This particular example installs Calkit with uv,
|
|
66
|
+
meaning `uv` and `uv-venv` environment types will work without any additional
|
|
67
|
+
configuration.
|
|
68
|
+
Docker is also installed by default on the `ubuntu-latest` machine.
|
|
69
|
+
If other environment types are used in the project,
|
|
70
|
+
setup steps may be necessary for those, e.g.,
|
|
71
|
+
[`setup-miniconda`](https://github.com/marketplace/actions/setup-miniconda)
|
|
72
|
+
or [`install-juliaup`](https://github.com/marketplace/actions/install-juliaup).
|
|
73
|
+
|
|
74
|
+
By default, the Calkit GitHub Action will run the pipeline and save results.
|
|
75
|
+
This is why the workflow needs write permissions and configures Git
|
|
76
|
+
credentials to act as the GitHub Actions bot.
|
|
77
|
+
The workflow also limits concurrency so multiple jobs don't attempt to push
|
|
78
|
+
to the same branch at the same time.
|
|
79
|
+
|
|
80
|
+
It's possible to configure the action to not save results, e.g., if you
|
|
81
|
+
just want to check that the pipeline can run without errors.
|
|
82
|
+
See the [documentation](https://github.com/marketplace/actions/run-calkit)
|
|
83
|
+
for all available options.
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -10,3 +10,4 @@
|
|
|
10
10
|
- [Adding a new LaTeX-based publication with its own Docker build environment](adding-latex-pub-docker.md)
|
|
11
11
|
- [A reproducible workflow using Microsoft Office (Word and Excel)](office.md)
|
|
12
12
|
- [Using Calkit with MATLAB](matlab.md)
|
|
13
|
+
- [Automation with GitHub Actions](github-actions.md)
|