calkit-python 0.26.11__tar.gz → 0.27.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.
- {calkit_python-0.26.11 → calkit_python-0.27.0}/PKG-INFO +3 -1
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/__init__.py +1 -1
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/cli/check.py +20 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/cli/main.py +31 -3
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/cli/notebooks.py +101 -17
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/core.py +11 -4
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/models/pipeline.py +12 -3
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/notebooks.py +9 -3
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/tests/cli/test_main.py +1 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/tests/models/test_pipeline.py +15 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/tests/test_core.py +19 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/tests/test_pipeline.py +56 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/calkit-yaml.md +1 -1
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/dependencies.md +8 -8
- calkit_python-0.27.0/docs/img/jupyterlab-params.png +0 -0
- calkit_python-0.27.0/docs/img/vscode-nb-params.png +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/notebooks.md +87 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/pyproject.toml +3 -1
- calkit_python-0.27.0/uv.lock +4776 -0
- calkit_python-0.26.11/uv.lock +0 -4406
- {calkit_python-0.26.11 → calkit_python-0.27.0}/.github/FUNDING.yml +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/.github/workflows/docs.yml +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/.github/workflows/format.yml +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/.github/workflows/publish-test.yml +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/.github/workflows/publish.yml +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/.github/workflows/test.yml +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/.gitignore +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/.pre-commit-config.yaml +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/.python-version +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/CITATION.cff +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/CONTRIBUTING.md +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/LICENSE +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/Makefile +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/README.md +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/__main__.py +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/calc.py +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/check.py +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/cli/__init__.py +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/cli/cloud.py +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/cli/config.py +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/cli/core.py +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/cli/describe.py +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/cli/import_.py +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/cli/list.py +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/cli/new.py +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/cli/office.py +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/cli/overleaf.py +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/cli/update.py +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/cloud.py +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/conda.py +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/config.py +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/datasets.py +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/docker.py +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/dvc.py +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/environments.py +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/git.py +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/github.py +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/gui.py +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/jupyter.py +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/magics.py +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/matlab.py +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/models/__init__.py +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/models/core.py +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/models/io.py +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/models/iteration.py +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/office.py +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/ops.py +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/pipeline.py +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/releases.py +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/server.py +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/templates/__init__.py +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/templates/core.py +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/templates/latex/__init__.py +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/templates/latex/article/paper.tex +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/templates/latex/core.py +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/templates/latex/jfm/jfm.bst +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/templates/latex/jfm/jfm.cls +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/templates/latex/jfm/lineno-FLM.sty +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/templates/latex/jfm/paper.tex +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/templates/latex/jfm/upmath.sty +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/tests/__init__.py +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/tests/cli/__init__.py +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/tests/cli/test_check.py +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/tests/cli/test_config.py +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/tests/cli/test_list.py +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/tests/cli/test_new.py +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/tests/cli/test_notebooks.py +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/tests/models/__init__.py +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/tests/test_calc.py +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/tests/test_check.py +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/tests/test_conda.py +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/tests/test_dvc.py +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/tests/test_jupyter.py +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/tests/test_magics.py +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/tests/test_notebooks.py +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/tests/test_templates.py +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/calkit/zenodo.py +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/CNAME +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/apps.md +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/calculations.md +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/cli-reference.md +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/cloud-integration.md +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/datasets.md +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/environments.md +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/examples.md +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/help.md +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/img/c-to-the-k-white.svg +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/img/calkit-no-bg.png +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/img/connect-zenodo.png +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/index.md +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/installation.md +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/local-server.md +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/overleaf.md +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/pipeline/index.md +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/pipeline/manual-steps.md +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/pipeline/running-and-logging.md +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/quickstart.md +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/references.md +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/releases.md +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/tutorials/adding-latex-pub-docker.md +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/tutorials/conda-envs.md +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/tutorials/existing-project.md +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/tutorials/first-project.md +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/tutorials/img/latex-codespaces/building-codespace.png +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/tutorials/img/latex-codespaces/codespaces-secrets-2.png +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/tutorials/img/latex-codespaces/editor-split.png +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/tutorials/img/latex-codespaces/go-to-linked-code.png +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/tutorials/img/latex-codespaces/issue-from-selection.png +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/tutorials/img/latex-codespaces/new-project.png +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/tutorials/img/latex-codespaces/new-pub-2.png +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/tutorials/img/latex-codespaces/new-token.png +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/tutorials/img/latex-codespaces/paper.tex.png +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/tutorials/img/latex-codespaces/project-home-3.png +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/tutorials/img/latex-codespaces/push.png +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/tutorials/img/latex-codespaces/stage.png +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/tutorials/img/office/anakin-excel.jpg +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/tutorials/img/office/chart-more-rows.png +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/tutorials/img/office/create-project.png +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/tutorials/img/office/elsevier-research-data-guidelines.png +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/tutorials/img/office/excel-chart.png +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/tutorials/img/office/excel-data.png +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/tutorials/img/office/insert-link-to-file.png +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/tutorials/img/office/needs-clone.png +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/tutorials/img/office/new-stage.png +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/tutorials/img/office/phd-comics-version-control.webp +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/tutorials/img/office/pipeline-out-of-date.png +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/tutorials/img/office/status-more-rows.png +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/tutorials/img/office/uncommitted-changes.png +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/tutorials/img/office/untracked-data.png +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/tutorials/img/office/updated-publication.png +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/tutorials/img/office/word-to-pdf-stage-2.png +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/tutorials/img/office/workflow-page.png +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/tutorials/img/openfoam/clone.png +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/tutorials/img/openfoam/create-project.png +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/tutorials/img/openfoam/datasets-page.png +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/tutorials/img/openfoam/figure-on-website-updated.png +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/tutorials/img/openfoam/figure-on-website.png +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/tutorials/img/openfoam/new-token.png +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/tutorials/img/openfoam/reclone.png +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/tutorials/img/openfoam/status-after-import-dataset.png +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/tutorials/img/run-proc.png +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/tutorials/index.md +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/tutorials/latex-codespaces.md +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/tutorials/matlab.md +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/tutorials/notebook-pipeline.md +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/tutorials/office.md +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/tutorials/openfoam.md +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/tutorials/procedures.md +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/docs/version-control.md +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/mkdocs.yml +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/scripts/install.ps1 +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/scripts/install.sh +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/test/pipeline.ipynb +0 -0
- {calkit_python-0.26.11 → calkit_python-0.27.0}/test/test-log.log +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: calkit-python
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.27.0
|
|
4
4
|
Summary: Reproducibility simplified.
|
|
5
5
|
Project-URL: Homepage, https://calkit.org
|
|
6
6
|
Project-URL: Issues, https://github.com/calkit/calkit/issues
|
|
@@ -18,8 +18,10 @@ Requires-Dist: docx2pdf
|
|
|
18
18
|
Requires-Dist: dvc==3.61.0
|
|
19
19
|
Requires-Dist: fastapi
|
|
20
20
|
Requires-Dist: gitpython
|
|
21
|
+
Requires-Dist: jupyterlab>=4.4.5
|
|
21
22
|
Requires-Dist: keyring
|
|
22
23
|
Requires-Dist: nbconvert
|
|
24
|
+
Requires-Dist: papermill>=2.6.0
|
|
23
25
|
Requires-Dist: pillow
|
|
24
26
|
Requires-Dist: psutil>=7.0.0
|
|
25
27
|
Requires-Dist: pydantic-settings
|
|
@@ -544,6 +544,26 @@ def check_matlab_env(
|
|
|
544
544
|
)
|
|
545
545
|
|
|
546
546
|
|
|
547
|
+
@check_app.command(name="dependencies")
|
|
548
|
+
@check_app.command(name="deps")
|
|
549
|
+
def check_dependencies(
|
|
550
|
+
verbose: Annotated[
|
|
551
|
+
bool, typer.Option("--verbose", "-v", help="Print verbose output")
|
|
552
|
+
] = False,
|
|
553
|
+
):
|
|
554
|
+
"""Check that a project's system-level dependencies are set up
|
|
555
|
+
correctly.
|
|
556
|
+
"""
|
|
557
|
+
typer.echo("Checking project dependencies")
|
|
558
|
+
dotenv.load_dotenv(dotenv_path=".env", verbose=verbose)
|
|
559
|
+
try:
|
|
560
|
+
calkit.check_system_deps()
|
|
561
|
+
except Exception as e:
|
|
562
|
+
raise_error(str(e))
|
|
563
|
+
message = "✅ All set!"
|
|
564
|
+
typer.echo(message.encode("utf-8", errors="replace"))
|
|
565
|
+
|
|
566
|
+
|
|
547
567
|
@check_app.command(name="env-vars")
|
|
548
568
|
def check_env_vars(
|
|
549
569
|
verbose: Annotated[
|
|
@@ -380,7 +380,12 @@ def add(
|
|
|
380
380
|
else:
|
|
381
381
|
commit_message = f"Add {paths[0]}"
|
|
382
382
|
if to is not None:
|
|
383
|
-
|
|
383
|
+
if to == "git":
|
|
384
|
+
subprocess.call(["git", "add"] + paths)
|
|
385
|
+
elif to == "dvc":
|
|
386
|
+
subprocess.call([sys.executable, "-m", "dvc", "add"] + paths)
|
|
387
|
+
else:
|
|
388
|
+
raise_error(f"Invalid option for 'to': {to}")
|
|
384
389
|
else:
|
|
385
390
|
if "." in paths:
|
|
386
391
|
paths.remove(".")
|
|
@@ -388,8 +393,14 @@ def add(
|
|
|
388
393
|
for dvc_uncommitted in dvc_status["uncommitted"].get(
|
|
389
394
|
"modified", []
|
|
390
395
|
):
|
|
391
|
-
|
|
392
|
-
|
|
396
|
+
if os.path.exists(dvc_uncommitted):
|
|
397
|
+
typer.echo(f"Adding {dvc_uncommitted} to DVC")
|
|
398
|
+
dvc_repo.commit(dvc_uncommitted, force=True)
|
|
399
|
+
else:
|
|
400
|
+
warn(
|
|
401
|
+
f"DVC uncommitted '{dvc_uncommitted}' does not exist; "
|
|
402
|
+
"skipping"
|
|
403
|
+
)
|
|
393
404
|
if not disable_auto_ignore:
|
|
394
405
|
for untracked_file in untracked_git_files:
|
|
395
406
|
if (
|
|
@@ -1779,3 +1790,20 @@ def call_dvc(
|
|
|
1779
1790
|
"""
|
|
1780
1791
|
process = subprocess.run([sys.executable, "-m", "dvc"] + sys.argv[2:])
|
|
1781
1792
|
sys.exit(process.returncode)
|
|
1793
|
+
|
|
1794
|
+
|
|
1795
|
+
@app.command(
|
|
1796
|
+
name="jupyter",
|
|
1797
|
+
add_help_option=False,
|
|
1798
|
+
context_settings={
|
|
1799
|
+
"ignore_unknown_options": True,
|
|
1800
|
+
"allow_extra_args": True,
|
|
1801
|
+
},
|
|
1802
|
+
)
|
|
1803
|
+
def run_jupyter(
|
|
1804
|
+
ctx: typer.Context,
|
|
1805
|
+
help: Annotated[bool, typer.Option("-h", "--help")] = False,
|
|
1806
|
+
):
|
|
1807
|
+
"""Run a command with the Jupyter CLI."""
|
|
1808
|
+
process = subprocess.run([sys.executable, "-m", "jupyter"] + sys.argv[2:])
|
|
1809
|
+
sys.exit(process.returncode)
|
|
@@ -6,7 +6,9 @@ import os
|
|
|
6
6
|
import subprocess
|
|
7
7
|
import sys
|
|
8
8
|
from pathlib import PurePosixPath
|
|
9
|
+
from typing import Any
|
|
9
10
|
|
|
11
|
+
import papermill
|
|
10
12
|
import typer
|
|
11
13
|
from typing_extensions import Annotated
|
|
12
14
|
|
|
@@ -45,6 +47,70 @@ def clean_notebook_outputs(path: str):
|
|
|
45
47
|
)
|
|
46
48
|
|
|
47
49
|
|
|
50
|
+
def _parse_params(params: list[str]) -> dict[str, Any]:
|
|
51
|
+
"""Parse parameters from command line arguments."""
|
|
52
|
+
parameters = {}
|
|
53
|
+
for param in params:
|
|
54
|
+
if "=" not in param:
|
|
55
|
+
raise ValueError(f"Parameter must be in key=value format: {param}")
|
|
56
|
+
key, value = param.split("=", 1)
|
|
57
|
+
# Try to convert to appropriate types
|
|
58
|
+
try:
|
|
59
|
+
if "." in value:
|
|
60
|
+
parameters[key] = float(value)
|
|
61
|
+
elif value.isdigit() or (
|
|
62
|
+
value.startswith("-") and value[1:].isdigit()
|
|
63
|
+
):
|
|
64
|
+
parameters[key] = int(value)
|
|
65
|
+
elif value.lower() in ("true", "false"):
|
|
66
|
+
parameters[key] = value.lower() == "true"
|
|
67
|
+
else:
|
|
68
|
+
parameters[key] = value
|
|
69
|
+
except ValueError:
|
|
70
|
+
parameters[key] = value
|
|
71
|
+
return parameters
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
@notebooks_app.command("check-env-kernel")
|
|
75
|
+
def check_env_kernel(
|
|
76
|
+
env_name: Annotated[
|
|
77
|
+
str,
|
|
78
|
+
typer.Option(
|
|
79
|
+
"--environment",
|
|
80
|
+
"-e",
|
|
81
|
+
help="Environment name in which to run the notebook.",
|
|
82
|
+
),
|
|
83
|
+
],
|
|
84
|
+
no_check: Annotated[
|
|
85
|
+
bool,
|
|
86
|
+
typer.Option(
|
|
87
|
+
"--no-check", help="Do not check environment before executing."
|
|
88
|
+
),
|
|
89
|
+
] = False,
|
|
90
|
+
verbose: Annotated[
|
|
91
|
+
bool, typer.Option("--verbose", "-v", help="Print verbose output.")
|
|
92
|
+
] = False,
|
|
93
|
+
):
|
|
94
|
+
"""Check that an environment has a registered kernel."""
|
|
95
|
+
from calkit.cli.main import run_in_env
|
|
96
|
+
|
|
97
|
+
project_name = calkit.detect_project_name(prepend_owner=False)
|
|
98
|
+
kernel_name = calkit.to_kebab_case(f"{project_name}-{env_name}")
|
|
99
|
+
cmd = [
|
|
100
|
+
"python",
|
|
101
|
+
"-m",
|
|
102
|
+
"ipykernel",
|
|
103
|
+
"install",
|
|
104
|
+
"--user",
|
|
105
|
+
"--name",
|
|
106
|
+
kernel_name,
|
|
107
|
+
"--display-name",
|
|
108
|
+
f"{project_name}: {env_name}",
|
|
109
|
+
]
|
|
110
|
+
run_in_env(cmd=cmd, env_name=env_name, no_check=no_check, verbose=verbose)
|
|
111
|
+
return kernel_name
|
|
112
|
+
|
|
113
|
+
|
|
48
114
|
@notebooks_app.command("execute")
|
|
49
115
|
def execute_notebook(
|
|
50
116
|
path: str,
|
|
@@ -66,6 +132,14 @@ def execute_notebook(
|
|
|
66
132
|
"--no-check", help="Do not check environment before executing."
|
|
67
133
|
),
|
|
68
134
|
] = False,
|
|
135
|
+
params: Annotated[
|
|
136
|
+
list[str],
|
|
137
|
+
typer.Option(
|
|
138
|
+
"--param",
|
|
139
|
+
"-p",
|
|
140
|
+
help="Parameter to pass to the notebook in key=value format.",
|
|
141
|
+
),
|
|
142
|
+
] = [],
|
|
69
143
|
verbose: Annotated[
|
|
70
144
|
bool, typer.Option("--verbose", "-v", help="Print verbose output.")
|
|
71
145
|
] = False,
|
|
@@ -79,33 +153,41 @@ def execute_notebook(
|
|
|
79
153
|
|
|
80
154
|
if os.path.isabs(path):
|
|
81
155
|
raise ValueError("Path must be relative")
|
|
82
|
-
# First,
|
|
156
|
+
# First, ensure the specified environment has a kernel we can use
|
|
157
|
+
kernel_name = check_env_kernel(
|
|
158
|
+
env_name=env_name, no_check=no_check, verbose=verbose
|
|
159
|
+
)
|
|
160
|
+
# Parse parameters
|
|
161
|
+
if params:
|
|
162
|
+
try:
|
|
163
|
+
parsed_params = _parse_params(params)
|
|
164
|
+
except ValueError as e:
|
|
165
|
+
raise_error(str(e))
|
|
166
|
+
else:
|
|
167
|
+
parsed_params = {}
|
|
168
|
+
# Next, always execute the notebook and save as ipynb
|
|
83
169
|
fpath_out_exec = calkit.notebooks.get_executed_notebook_path(
|
|
84
|
-
notebook_path=path,
|
|
170
|
+
notebook_path=path,
|
|
171
|
+
to="notebook",
|
|
172
|
+
as_posix=True,
|
|
173
|
+
parameters=parsed_params,
|
|
85
174
|
)
|
|
86
175
|
folder = os.path.dirname(fpath_out_exec)
|
|
87
176
|
os.makedirs(folder, exist_ok=True)
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
"--to",
|
|
96
|
-
"notebook",
|
|
97
|
-
"--output-dir",
|
|
98
|
-
PurePosixPath(folder).as_posix(),
|
|
99
|
-
"--output",
|
|
100
|
-
fname,
|
|
101
|
-
]
|
|
102
|
-
run_in_env(cmd=cmd, env_name=env_name, no_check=no_check, verbose=verbose)
|
|
177
|
+
papermill.execute_notebook(
|
|
178
|
+
input_path=path,
|
|
179
|
+
output_path=fpath_out_exec,
|
|
180
|
+
kernel_name=kernel_name,
|
|
181
|
+
log_output=True,
|
|
182
|
+
parameters=parsed_params,
|
|
183
|
+
)
|
|
103
184
|
for to_fmt in to:
|
|
104
185
|
if to_fmt != "notebook":
|
|
105
186
|
try:
|
|
106
187
|
fpath_out = calkit.notebooks.get_executed_notebook_path(
|
|
107
188
|
notebook_path=path,
|
|
108
189
|
to=to_fmt, # type: ignore
|
|
190
|
+
parameters=parsed_params,
|
|
109
191
|
)
|
|
110
192
|
except ValueError:
|
|
111
193
|
raise_error(f"Invalid output format: '{to}'")
|
|
@@ -114,6 +196,8 @@ def execute_notebook(
|
|
|
114
196
|
fname_out = os.path.basename(fpath_out)
|
|
115
197
|
# Now convert without executing or checking the environment
|
|
116
198
|
cmd = [
|
|
199
|
+
sys.executable,
|
|
200
|
+
"-m",
|
|
117
201
|
"jupyter",
|
|
118
202
|
"nbconvert",
|
|
119
203
|
fpath_out_exec,
|
|
@@ -318,11 +318,12 @@ def check_system_deps(
|
|
|
318
318
|
raise ValueError(f"Malformed dependency: {dep}")
|
|
319
319
|
if len(keys) == 1:
|
|
320
320
|
dep_name = keys[0]
|
|
321
|
+
dep_kind = dep[dep_name].get("kind", "app")
|
|
321
322
|
elif "name" in keys:
|
|
322
323
|
dep_name = dep["name"]
|
|
324
|
+
dep_kind = dep.get("kind", "app")
|
|
323
325
|
else:
|
|
324
326
|
raise ValueError(f"Malformed dependency: {dep}")
|
|
325
|
-
dep_kind = dep[dep_name].get("kind", "app")
|
|
326
327
|
else:
|
|
327
328
|
dep_name = re.split("[=<>]", dep)[0]
|
|
328
329
|
dep_kind = "app"
|
|
@@ -478,12 +479,16 @@ def get_latest_project_status(wdir: str | None = None) -> ProjectStatus | None:
|
|
|
478
479
|
return statuses[-1] # type: ignore
|
|
479
480
|
|
|
480
481
|
|
|
481
|
-
def detect_project_name(
|
|
482
|
+
def detect_project_name(
|
|
483
|
+
wdir: str | None = None, prepend_owner: bool = True
|
|
484
|
+
) -> str:
|
|
482
485
|
"""Detect a Calkit project owner and name."""
|
|
483
486
|
ck_info = load_calkit_info(wdir=wdir)
|
|
484
487
|
name = ck_info.get("name")
|
|
488
|
+
if name is not None and not prepend_owner:
|
|
489
|
+
return name
|
|
485
490
|
owner = ck_info.get("owner")
|
|
486
|
-
if name is None
|
|
491
|
+
if name is None and owner is None:
|
|
487
492
|
try:
|
|
488
493
|
url = Repo(path=wdir).remote().url
|
|
489
494
|
except ValueError:
|
|
@@ -494,7 +499,9 @@ def detect_project_name(wdir: str | None = None) -> str:
|
|
|
494
499
|
name = project_name
|
|
495
500
|
if owner is None:
|
|
496
501
|
owner = owner_name
|
|
497
|
-
|
|
502
|
+
if prepend_owner:
|
|
503
|
+
return f"{owner}/{name}"
|
|
504
|
+
return name
|
|
498
505
|
|
|
499
506
|
|
|
500
507
|
def get_dep_version(dep_name: str) -> str | None:
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
from pathlib import PurePosixPath
|
|
6
|
-
from typing import Literal
|
|
6
|
+
from typing import Any, Literal
|
|
7
7
|
|
|
8
8
|
from pydantic import BaseModel, ConfigDict, Discriminator
|
|
9
9
|
from typing_extensions import Annotated
|
|
@@ -273,6 +273,7 @@ class JupyterNotebookStage(Stage):
|
|
|
273
273
|
cleaned_ipynb_storage: Literal["git", "dvc"] | None = "git"
|
|
274
274
|
executed_ipynb_storage: Literal["git", "dvc"] | None = "dvc"
|
|
275
275
|
html_storage: Literal["git", "dvc"] | None = "dvc"
|
|
276
|
+
parameters: dict[str, Any] = {}
|
|
276
277
|
|
|
277
278
|
@property
|
|
278
279
|
def cleaned_notebook_path(self) -> str:
|
|
@@ -281,13 +282,19 @@ class JupyterNotebookStage(Stage):
|
|
|
281
282
|
@property
|
|
282
283
|
def executed_notebook_path(self) -> str:
|
|
283
284
|
return get_executed_notebook_path(
|
|
284
|
-
self.notebook_path,
|
|
285
|
+
self.notebook_path,
|
|
286
|
+
to="notebook",
|
|
287
|
+
as_posix=True,
|
|
288
|
+
parameters=self.parameters,
|
|
285
289
|
)
|
|
286
290
|
|
|
287
291
|
@property
|
|
288
292
|
def html_path(self) -> str:
|
|
289
293
|
return get_executed_notebook_path(
|
|
290
|
-
self.notebook_path,
|
|
294
|
+
self.notebook_path,
|
|
295
|
+
to="html",
|
|
296
|
+
as_posix=True,
|
|
297
|
+
parameters=self.parameters,
|
|
291
298
|
)
|
|
292
299
|
|
|
293
300
|
@property
|
|
@@ -299,6 +306,8 @@ class JupyterNotebookStage(Stage):
|
|
|
299
306
|
cmd = f"calkit nb execute --environment {self.environment} --no-check"
|
|
300
307
|
if self.html_storage:
|
|
301
308
|
cmd += " --to html"
|
|
309
|
+
for k, v in self.parameters.items():
|
|
310
|
+
cmd += f" -p {k}={v}"
|
|
302
311
|
cmd += f' "{self.notebook_path}"'
|
|
303
312
|
return cmd
|
|
304
313
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import os
|
|
4
4
|
from pathlib import PurePosixPath
|
|
5
|
-
from typing import Literal
|
|
5
|
+
from typing import Any, Literal
|
|
6
6
|
|
|
7
7
|
import git
|
|
8
8
|
|
|
@@ -11,16 +11,22 @@ from calkit.models.io import InputsFromStageOutputs, PathOutput
|
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
def get_executed_notebook_path(
|
|
14
|
-
notebook_path: str,
|
|
14
|
+
notebook_path: str,
|
|
15
|
+
to: Literal["html", "notebook"],
|
|
16
|
+
as_posix: bool = True,
|
|
17
|
+
parameters: dict[str, Any] | None = None,
|
|
15
18
|
) -> str:
|
|
16
19
|
"""Return the path of an executed notebook."""
|
|
17
20
|
nb_dir = os.path.dirname(notebook_path)
|
|
18
21
|
nb_fname = os.path.basename(notebook_path)
|
|
22
|
+
# If we have any parameters, add these to the notebook name
|
|
23
|
+
if parameters:
|
|
24
|
+
params_txt = "-".join(f"{k}-{v}" for k, v in parameters.items())
|
|
25
|
+
nb_fname = f"{nb_fname.removesuffix('.ipynb')}-{params_txt}.ipynb"
|
|
19
26
|
if to == "html":
|
|
20
27
|
fname_out = nb_fname.removesuffix(".ipynb") + ".html"
|
|
21
28
|
else:
|
|
22
29
|
fname_out = nb_fname
|
|
23
|
-
# Different output types go to different subdirectories
|
|
24
30
|
subdirs = {"html": "html", "notebook": "executed"}
|
|
25
31
|
p = os.path.join(".calkit", "notebooks", subdirs[to], nb_dir, fname_out)
|
|
26
32
|
if as_posix:
|
|
@@ -322,6 +322,7 @@ def test_add(tmp_dir):
|
|
|
322
322
|
f.write(os.urandom(2_000_000))
|
|
323
323
|
subprocess.check_call(["calkit", "add", "data2", "-M"])
|
|
324
324
|
assert repo.head.commit.message.strip() == "Add data2"
|
|
325
|
+
subprocess.check_call(["calkit", "add", "--to", "dvc", "large.bin"])
|
|
325
326
|
|
|
326
327
|
|
|
327
328
|
def test_status(tmp_dir):
|
|
@@ -87,3 +87,18 @@ def test_jupyternotebookstage():
|
|
|
87
87
|
assert s.html_path not in outs
|
|
88
88
|
assert s.executed_notebook_path in outs
|
|
89
89
|
assert "html" not in dvc_stage["cmd"]
|
|
90
|
+
# Test with parameters
|
|
91
|
+
s = JupyterNotebookStage(
|
|
92
|
+
environment="main",
|
|
93
|
+
notebook_path="something.ipynb",
|
|
94
|
+
inputs=["file.txt"],
|
|
95
|
+
html_storage=None,
|
|
96
|
+
parameters={"param1": "value1", "param2": "value2"},
|
|
97
|
+
)
|
|
98
|
+
dvc_stage = s.to_dvc()
|
|
99
|
+
outs = dvc_outs_to_str_list(dvc_stage)
|
|
100
|
+
assert s.html_path not in outs
|
|
101
|
+
assert s.executed_notebook_path in outs
|
|
102
|
+
assert "html" not in dvc_stage["cmd"]
|
|
103
|
+
assert " -p param1=value1 " in dvc_stage["cmd"]
|
|
104
|
+
assert " -p param2=value2 " in dvc_stage["cmd"]
|
|
@@ -4,6 +4,7 @@ import os
|
|
|
4
4
|
import subprocess
|
|
5
5
|
|
|
6
6
|
import git
|
|
7
|
+
import pytest
|
|
7
8
|
|
|
8
9
|
import calkit
|
|
9
10
|
|
|
@@ -78,3 +79,21 @@ def test_get_env_var_dep_names():
|
|
|
78
79
|
"MY_ENV_VAR",
|
|
79
80
|
"MY_OTHER_ENV_VAR",
|
|
80
81
|
]
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def test_check_system_deps(tmp_dir):
|
|
85
|
+
ck_info = {
|
|
86
|
+
"dependencies": [
|
|
87
|
+
"uv",
|
|
88
|
+
{"kind": "env-var", "name": "MY_ENV_VAR"},
|
|
89
|
+
{"MY_ENV_VAR2": {"kind": "env-var"}},
|
|
90
|
+
]
|
|
91
|
+
}
|
|
92
|
+
with open("calkit.yaml", "w") as f:
|
|
93
|
+
calkit.ryaml.dump(ck_info, f)
|
|
94
|
+
subprocess.check_call(
|
|
95
|
+
["calkit", "check", "dependencies"],
|
|
96
|
+
env=os.environ.copy() | {"MY_ENV_VAR": "5", "MY_ENV_VAR2": "55"},
|
|
97
|
+
)
|
|
98
|
+
with pytest.raises(ValueError):
|
|
99
|
+
calkit.check_system_deps()
|
|
@@ -219,6 +219,62 @@ def test_to_dvc_notebook_stage():
|
|
|
219
219
|
found_html = True
|
|
220
220
|
assert out[p]["cache"]
|
|
221
221
|
assert found_html
|
|
222
|
+
# Test we can use parameters and iterations in notebook stages
|
|
223
|
+
ck_info = {
|
|
224
|
+
"parameters": {
|
|
225
|
+
"param1": [{"range": {"start": 5, "stop": 23, "step": 2}}],
|
|
226
|
+
"param2": ["s", "m", "l"],
|
|
227
|
+
"param3": [
|
|
228
|
+
{"range": {"start": 0.1, "stop": 1.1, "step": 0.11}},
|
|
229
|
+
55,
|
|
230
|
+
"something",
|
|
231
|
+
],
|
|
232
|
+
},
|
|
233
|
+
"pipeline": {
|
|
234
|
+
"stages": {
|
|
235
|
+
"notebook-1": {
|
|
236
|
+
"kind": "jupyter-notebook",
|
|
237
|
+
"environment": "something",
|
|
238
|
+
"notebook_path": nb_path,
|
|
239
|
+
"outputs": [
|
|
240
|
+
"figures/fig1.png",
|
|
241
|
+
],
|
|
242
|
+
"html_storage": "dvc",
|
|
243
|
+
"cleaned_ipynb_storage": "git",
|
|
244
|
+
"executed_ipynb_storage": None,
|
|
245
|
+
"parameters": {
|
|
246
|
+
"param1": "{param1}",
|
|
247
|
+
"param2": "{param2}",
|
|
248
|
+
"param3": "{param3}",
|
|
249
|
+
},
|
|
250
|
+
"iterate_over": [
|
|
251
|
+
{
|
|
252
|
+
"arg_name": "param1",
|
|
253
|
+
"values": [{"parameter": "param1"}],
|
|
254
|
+
},
|
|
255
|
+
{
|
|
256
|
+
"arg_name": "param2",
|
|
257
|
+
"values": [{"parameter": "param2"}],
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
"arg_name": "param3",
|
|
261
|
+
"values": [{"parameter": "param3"}],
|
|
262
|
+
},
|
|
263
|
+
],
|
|
264
|
+
},
|
|
265
|
+
}
|
|
266
|
+
},
|
|
267
|
+
}
|
|
268
|
+
dvc_stages = calkit.pipeline.to_dvc(ck_info=ck_info, write=False)
|
|
269
|
+
print(dvc_stages)
|
|
270
|
+
stage = dvc_stages["notebook-1"]
|
|
271
|
+
assert stage["cmd"].startswith("calkit nb execute")
|
|
272
|
+
assert " -p param1=${item.param1} " in stage["cmd"]
|
|
273
|
+
assert " -p param2=${item.param2} " in stage["cmd"]
|
|
274
|
+
assert " -p param3=${item.param3} " in stage["cmd"]
|
|
275
|
+
assert stage["matrix"]["param1"][0] == 5.0
|
|
276
|
+
assert "m" in stage["matrix"]["param2"]
|
|
277
|
+
assert "something" in stage["matrix"]["param3"]
|
|
222
278
|
|
|
223
279
|
|
|
224
280
|
def test_remove_stage(tmp_dir):
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
The `calkit.yaml` file serves as a small "database"
|
|
4
4
|
for the project's important metadata, which includes its:
|
|
5
5
|
|
|
6
|
-
- Global or system-level dependencies
|
|
6
|
+
- Global or system-level [dependencies](dependencies.md)
|
|
7
7
|
(applications, libraries, environmental variables)
|
|
8
8
|
- Questions the project seeks to answer
|
|
9
9
|
- [Environments](environments.md)
|
|
@@ -40,14 +40,14 @@ changing anything.
|
|
|
40
40
|
```yaml
|
|
41
41
|
dependencies:
|
|
42
42
|
- docker
|
|
43
|
-
- STRAVA_CLIENT_ID
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
- STRAVA_CLIENT_SECRET
|
|
50
|
-
|
|
43
|
+
- name: STRAVA_CLIENT_ID
|
|
44
|
+
kind: env-var
|
|
45
|
+
notes: >
|
|
46
|
+
The STRAVA_CLIENT_ID and STRAVA_CLIENT_SECRET environmental
|
|
47
|
+
variables can be set in the .env file after creating a Strava
|
|
48
|
+
application at https://www.strava.com/settings/api
|
|
49
|
+
- name: STRAVA_CLIENT_SECRET
|
|
50
|
+
kind: env-var
|
|
51
51
|
```
|
|
52
52
|
|
|
53
53
|
As we can see in the notes for `STRAVA_CLIENT_ID`,
|
|
Binary file
|
|
Binary file
|
|
@@ -236,3 +236,90 @@ about that cell's code or environment has changed.
|
|
|
236
236
|
|
|
237
237
|
For a more in-depth look at using the `%%stage` cell magic,
|
|
238
238
|
see [this tutorial](tutorials/notebook-pipeline.md).
|
|
239
|
+
|
|
240
|
+
## Parameterizing notebooks
|
|
241
|
+
|
|
242
|
+
Thanks to [Papermill](https://github.com/nteract/papermill),
|
|
243
|
+
Calkit can run notebooks that have been parameterized,
|
|
244
|
+
and executed versions will be saved with parameters in their names.
|
|
245
|
+
To parameterize a notebook,
|
|
246
|
+
first add a cell with the "parameters" tag and add your parameters there
|
|
247
|
+
as variable declarations, e.g.,
|
|
248
|
+
|
|
249
|
+
```python
|
|
250
|
+
param1 = 5
|
|
251
|
+
param2 = "something"
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
In JupyterLab, you can use the property inspector to edit cell tags:
|
|
255
|
+
|
|
256
|
+

|
|
257
|
+
|
|
258
|
+
In VS Code, the cell context menu can be used to mark the cell as parameters:
|
|
259
|
+
|
|
260
|
+

|
|
261
|
+
|
|
262
|
+
Then, in the Calkit pipeline, add `parameters` to the notebook stage:
|
|
263
|
+
|
|
264
|
+
```yaml
|
|
265
|
+
# In calkit.yaml
|
|
266
|
+
environments:
|
|
267
|
+
main:
|
|
268
|
+
kind: uv-venv
|
|
269
|
+
path: requirements.txt
|
|
270
|
+
prefix: .venv
|
|
271
|
+
python: "3.13"
|
|
272
|
+
pipeline:
|
|
273
|
+
stages:
|
|
274
|
+
notebook-56-a:
|
|
275
|
+
kind: jupyter-notebook
|
|
276
|
+
notebook_path: notebook.ipynb
|
|
277
|
+
environment: main
|
|
278
|
+
parameters:
|
|
279
|
+
param1: 56
|
|
280
|
+
param2: a
|
|
281
|
+
notebook-58-b:
|
|
282
|
+
kind: jupyter-notebook
|
|
283
|
+
notebook_path: notebook.ipynb
|
|
284
|
+
environment: main
|
|
285
|
+
parameters:
|
|
286
|
+
param1: 58
|
|
287
|
+
param2: b
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
### Iterating over parameterized notebooks
|
|
291
|
+
|
|
292
|
+
The example below shows project-level parameters used to iterate over a
|
|
293
|
+
notebook stage:
|
|
294
|
+
|
|
295
|
+
```yaml
|
|
296
|
+
parameters:
|
|
297
|
+
param1:
|
|
298
|
+
- range:
|
|
299
|
+
start: 0
|
|
300
|
+
stop: 10
|
|
301
|
+
step: 2
|
|
302
|
+
param2:
|
|
303
|
+
- random-forest
|
|
304
|
+
- lightgbm
|
|
305
|
+
pipeline:
|
|
306
|
+
stages:
|
|
307
|
+
my-notebook-with-params:
|
|
308
|
+
kind: jupyter-notebook
|
|
309
|
+
environment: my-env
|
|
310
|
+
notebook_path: notebook.ipynb
|
|
311
|
+
iterate_over:
|
|
312
|
+
- arg_name: param1
|
|
313
|
+
values:
|
|
314
|
+
- parameter: param1 # Args and params can be named differently
|
|
315
|
+
- arg_name: param2
|
|
316
|
+
values:
|
|
317
|
+
- parameter: param2
|
|
318
|
+
parameters:
|
|
319
|
+
param1: "{param1}" # Notebook params can also be named differently
|
|
320
|
+
param2: "{param2}"
|
|
321
|
+
outputs:
|
|
322
|
+
- results/param1={param1}/param2={param2}/results.csv
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
For more information, see [pipeline iteration](/pipeline#iteration).
|
|
@@ -32,6 +32,8 @@ dependencies = [
|
|
|
32
32
|
"uvicorn",
|
|
33
33
|
"tqdm>=4.67.1",
|
|
34
34
|
"psutil>=7.0.0",
|
|
35
|
+
"papermill>=2.6.0",
|
|
36
|
+
"jupyterlab>=4.4.5",
|
|
35
37
|
]
|
|
36
38
|
description = "Reproducibility simplified."
|
|
37
39
|
dynamic = ["version"]
|
|
@@ -94,7 +96,7 @@ show_error_codes = true
|
|
|
94
96
|
target-version = "py310"
|
|
95
97
|
line-length = 79
|
|
96
98
|
fix = true
|
|
97
|
-
extend-select = ["I"]
|
|
99
|
+
lint.extend-select = ["I"]
|
|
98
100
|
|
|
99
101
|
[tool.pytest.ini_options]
|
|
100
102
|
env = ["CALKIT_ENV = test"]
|