calkit-python 0.28.4__tar.gz → 0.29.2__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.4 → calkit_python-0.29.2}/PKG-INFO +1 -1
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/__init__.py +1 -1
- calkit_python-0.29.2/calkit/cli/config.py +240 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/cli/main.py +65 -16
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/cli/notebooks.py +59 -14
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/dvc.py +23 -13
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/models/pipeline.py +39 -15
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/tests/models/test_pipeline.py +16 -0
- calkit_python-0.28.4/calkit/cli/config.py +0 -116
- {calkit_python-0.28.4 → calkit_python-0.29.2}/.github/FUNDING.yml +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/.github/workflows/docs.yml +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/.github/workflows/format.yml +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/.github/workflows/publish-test.yml +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/.github/workflows/publish.yml +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/.github/workflows/test.yml +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/.gitignore +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/.pre-commit-config.yaml +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/.python-version +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/CITATION.cff +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/CONTRIBUTING.md +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/LICENSE +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/Makefile +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/README.md +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/__main__.py +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/calc.py +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/check.py +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/cli/__init__.py +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/cli/check.py +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/cli/cloud.py +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/cli/core.py +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/cli/describe.py +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/cli/import_.py +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/cli/list.py +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/cli/new.py +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/cli/office.py +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/cli/overleaf.py +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/cli/update.py +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/cloud.py +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/conda.py +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/config.py +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/core.py +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/datasets.py +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/docker.py +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/environments.py +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/git.py +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/github.py +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/gui.py +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/jupyter.py +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/magics.py +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/matlab.py +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/models/__init__.py +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/models/core.py +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/models/io.py +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/models/iteration.py +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/notebooks.py +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/office.py +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/ops.py +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/pipeline.py +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/releases.py +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/server.py +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/templates/__init__.py +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/templates/core.py +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/templates/latex/__init__.py +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/templates/latex/article/paper.tex +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/templates/latex/core.py +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/templates/latex/jfm/jfm.bst +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/templates/latex/jfm/jfm.cls +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/templates/latex/jfm/lineno-FLM.sty +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/templates/latex/jfm/paper.tex +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/templates/latex/jfm/upmath.sty +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/tests/__init__.py +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/tests/cli/__init__.py +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/tests/cli/test_check.py +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/tests/cli/test_config.py +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/tests/cli/test_list.py +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/tests/cli/test_main.py +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/tests/cli/test_new.py +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/tests/cli/test_notebooks.py +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/tests/models/__init__.py +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/tests/models/test_iteration.py +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/tests/test_calc.py +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/tests/test_check.py +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/tests/test_conda.py +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/tests/test_core.py +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/tests/test_dvc.py +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/tests/test_jupyter.py +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/tests/test_magics.py +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/tests/test_notebooks.py +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/tests/test_pipeline.py +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/tests/test_templates.py +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/calkit/zenodo.py +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/CNAME +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/apps.md +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/calculations.md +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/calkit-yaml.md +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/cli-reference.md +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/cloud-integration.md +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/datasets.md +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/dependencies.md +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/environments.md +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/examples.md +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/help.md +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/img/c-to-the-k-white.svg +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/img/calkit-no-bg.png +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/img/connect-zenodo.png +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/img/jupyterlab-params.png +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/img/vscode-nb-params.png +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/index.md +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/installation.md +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/local-server.md +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/notebooks.md +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/overleaf.md +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/pipeline/index.md +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/pipeline/manual-steps.md +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/pipeline/running-and-logging.md +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/quickstart.md +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/references.md +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/releases.md +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/tutorials/adding-latex-pub-docker.md +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/tutorials/conda-envs.md +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/tutorials/existing-project.md +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/tutorials/first-project.md +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/tutorials/github-actions.md +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/tutorials/img/actions-repo-secrets.png +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/tutorials/img/latex-codespaces/building-codespace.png +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/tutorials/img/latex-codespaces/codespaces-secrets-2.png +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/tutorials/img/latex-codespaces/editor-split.png +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/tutorials/img/latex-codespaces/go-to-linked-code.png +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/tutorials/img/latex-codespaces/issue-from-selection.png +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/tutorials/img/latex-codespaces/new-project.png +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/tutorials/img/latex-codespaces/new-pub-2.png +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/tutorials/img/latex-codespaces/new-token.png +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/tutorials/img/latex-codespaces/paper.tex.png +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/tutorials/img/latex-codespaces/project-home-3.png +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/tutorials/img/latex-codespaces/push.png +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/tutorials/img/latex-codespaces/stage.png +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/tutorials/img/office/anakin-excel.jpg +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/tutorials/img/office/chart-more-rows.png +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/tutorials/img/office/create-project.png +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/tutorials/img/office/elsevier-research-data-guidelines.png +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/tutorials/img/office/excel-chart.png +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/tutorials/img/office/excel-data.png +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/tutorials/img/office/insert-link-to-file.png +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/tutorials/img/office/needs-clone.png +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/tutorials/img/office/new-stage.png +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/tutorials/img/office/phd-comics-version-control.webp +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/tutorials/img/office/pipeline-out-of-date.png +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/tutorials/img/office/status-more-rows.png +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/tutorials/img/office/uncommitted-changes.png +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/tutorials/img/office/untracked-data.png +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/tutorials/img/office/updated-publication.png +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/tutorials/img/office/word-to-pdf-stage-2.png +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/tutorials/img/office/workflow-page.png +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/tutorials/img/openfoam/clone.png +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/tutorials/img/openfoam/create-project.png +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/tutorials/img/openfoam/datasets-page.png +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/tutorials/img/openfoam/figure-on-website-updated.png +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/tutorials/img/openfoam/figure-on-website.png +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/tutorials/img/openfoam/new-token.png +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/tutorials/img/openfoam/reclone.png +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/tutorials/img/openfoam/status-after-import-dataset.png +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/tutorials/img/quick-actions.png +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/tutorials/img/run-proc.png +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/tutorials/index.md +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/tutorials/latex-codespaces.md +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/tutorials/matlab.md +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/tutorials/notebook-pipeline.md +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/tutorials/office.md +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/tutorials/openfoam.md +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/tutorials/procedures.md +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/docs/version-control.md +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/mkdocs.yml +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/pyproject.toml +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/scripts/install.ps1 +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/scripts/install.sh +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/test/nb-params.ipynb +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/test/nb-subdir.ipynb +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/test/pipeline.ipynb +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/test/test-log.log +0 -0
- {calkit_python-0.28.4 → calkit_python-0.29.2}/uv.lock +0 -0
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
"""Config CLI."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import glob
|
|
6
|
+
import os
|
|
7
|
+
import subprocess
|
|
8
|
+
|
|
9
|
+
import git
|
|
10
|
+
import typer
|
|
11
|
+
from git.exc import InvalidGitRepositoryError
|
|
12
|
+
from typing_extensions import Annotated
|
|
13
|
+
|
|
14
|
+
import calkit
|
|
15
|
+
from calkit import config
|
|
16
|
+
from calkit.cli.core import raise_error
|
|
17
|
+
from calkit.dvc import configure_remote, get_remotes, set_remote_auth
|
|
18
|
+
|
|
19
|
+
config_app = typer.Typer(no_args_is_help=True)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@config_app.command(name="set")
|
|
23
|
+
def set_config_value(key: str, value: str):
|
|
24
|
+
"""Set a value in the config."""
|
|
25
|
+
keys = config.Settings.model_fields.keys()
|
|
26
|
+
if key not in keys:
|
|
27
|
+
raise_error(
|
|
28
|
+
f"Invalid config key: '{key}'; Valid keys are: {list(keys)}"
|
|
29
|
+
)
|
|
30
|
+
try:
|
|
31
|
+
cfg = config.read()
|
|
32
|
+
cfg = config.Settings.model_validate(cfg.model_dump() | {key: value})
|
|
33
|
+
except Exception as e:
|
|
34
|
+
raise_error(f"Failed to set {key} in config: {e}")
|
|
35
|
+
cfg.write()
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@config_app.command(name="get")
|
|
39
|
+
def get_config_value(key: str) -> None:
|
|
40
|
+
"""Get and print a value from the config."""
|
|
41
|
+
cfg = config.read().model_dump()
|
|
42
|
+
if key not in cfg:
|
|
43
|
+
raise_error(
|
|
44
|
+
f"Invalid config key: '{key}'; Valid keys are: {list(cfg.keys())}"
|
|
45
|
+
)
|
|
46
|
+
val = cfg[key]
|
|
47
|
+
if val is not None:
|
|
48
|
+
print(val)
|
|
49
|
+
else:
|
|
50
|
+
print()
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@config_app.command(name="unset")
|
|
54
|
+
def unset_config_value(key: str):
|
|
55
|
+
"""Unset a value in the config, returning it to default."""
|
|
56
|
+
model_fields = config.Settings.model_fields
|
|
57
|
+
if key not in model_fields:
|
|
58
|
+
raise_error(
|
|
59
|
+
f"Invalid config key: '{key}'; "
|
|
60
|
+
f"Valid keys: {list(model_fields.keys())}"
|
|
61
|
+
)
|
|
62
|
+
try:
|
|
63
|
+
cfg = config.read()
|
|
64
|
+
setattr(cfg, key, model_fields[key].default)
|
|
65
|
+
except Exception as e:
|
|
66
|
+
raise_error(f"Failed to unset {key} in config: {e}")
|
|
67
|
+
cfg.write()
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
@config_app.command(name="setup-remote", help="Alias for 'remote'.")
|
|
71
|
+
@config_app.command(name="remote")
|
|
72
|
+
def setup_remote(
|
|
73
|
+
no_commit: Annotated[
|
|
74
|
+
bool,
|
|
75
|
+
typer.Option(
|
|
76
|
+
"--no-commit", help="Do not commit changes to DVC config."
|
|
77
|
+
),
|
|
78
|
+
] = False,
|
|
79
|
+
):
|
|
80
|
+
"""Setup the Calkit cloud as the default DVC remote and store a token in
|
|
81
|
+
the local config.
|
|
82
|
+
"""
|
|
83
|
+
try:
|
|
84
|
+
configure_remote()
|
|
85
|
+
set_remote_auth()
|
|
86
|
+
except subprocess.CalledProcessError:
|
|
87
|
+
if not os.path.isfile(".dvc/config"):
|
|
88
|
+
raise_error(
|
|
89
|
+
"DVC remote config failed; have you run `calkit init`?"
|
|
90
|
+
)
|
|
91
|
+
raise_error(
|
|
92
|
+
"Failed to configure DVC remote; check DVC config for errors"
|
|
93
|
+
)
|
|
94
|
+
except InvalidGitRepositoryError:
|
|
95
|
+
raise_error("Current directory is not a Git repository")
|
|
96
|
+
except (ValueError, RuntimeError) as e:
|
|
97
|
+
raise_error(f"Failed to set up DVC remote: {e}")
|
|
98
|
+
if not no_commit:
|
|
99
|
+
repo = git.Repo()
|
|
100
|
+
repo.git.add(".dvc/config")
|
|
101
|
+
if ".dvc/config" in calkit.git.get_staged_files():
|
|
102
|
+
typer.echo("Committing changes to DVC config")
|
|
103
|
+
repo.git.commit([".dvc/config", "-m", "Set DVC remote"])
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
@config_app.command(name="setup-remote-auth", help="Alias for 'remote-auth'.")
|
|
107
|
+
@config_app.command(name="remote-auth")
|
|
108
|
+
def setup_remote_auth():
|
|
109
|
+
"""Store a Calkit cloud token in the local DVC config for all Calkit
|
|
110
|
+
remotes.
|
|
111
|
+
"""
|
|
112
|
+
try:
|
|
113
|
+
remotes = get_remotes()
|
|
114
|
+
except Exception:
|
|
115
|
+
raise_error("Cannot list DVC remotes; check DVC config for errors")
|
|
116
|
+
for name, url in remotes.items():
|
|
117
|
+
if name == "calkit" or name.startswith("calkit:"):
|
|
118
|
+
typer.echo(f"Setting up authentication for DVC remote: {name}")
|
|
119
|
+
set_remote_auth(remote_name=name)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
@config_app.command(name="list")
|
|
123
|
+
def list_config_keys():
|
|
124
|
+
"""List keys in the config."""
|
|
125
|
+
cfg = config.read()
|
|
126
|
+
for key in cfg.model_dump():
|
|
127
|
+
typer.echo(key)
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
@config_app.command(name="github-ssh")
|
|
131
|
+
def config_github_ssh():
|
|
132
|
+
"""Walk through the process of adding an SSH key to GitHub."""
|
|
133
|
+
typer.echo("Checking if you can already connect to GitHub via SSH")
|
|
134
|
+
# First check if we can already connect to GitHub
|
|
135
|
+
ssh_test_cmd = ["ssh", "-T", "git@github.com"]
|
|
136
|
+
p = subprocess.run(ssh_test_cmd, capture_output=True, text=True)
|
|
137
|
+
if "successfully authenticated" in p.stderr:
|
|
138
|
+
typer.echo("You can already connect to GitHub via SSH")
|
|
139
|
+
go_on = typer.confirm("Do you want to add a new SSH key anyway?")
|
|
140
|
+
if not go_on:
|
|
141
|
+
raise typer.Exit()
|
|
142
|
+
# If we can, ask the user if they still want to add a new key
|
|
143
|
+
# First check if the user has any SSH keys
|
|
144
|
+
ssh_dir = os.path.expanduser("~/.ssh")
|
|
145
|
+
existing_pub_keys = glob.glob(os.path.join(ssh_dir, "*.pub"))
|
|
146
|
+
# If not run ssh-keygen
|
|
147
|
+
if existing_pub_keys:
|
|
148
|
+
# Ask the user if they want to use an existing key or create a new one
|
|
149
|
+
typer.echo("Existing SSH public keys found:")
|
|
150
|
+
for i, key in enumerate(existing_pub_keys):
|
|
151
|
+
typer.echo(f"{i + 1}: {key}")
|
|
152
|
+
use_existing = typer.confirm("Do you want to use one of these keys?")
|
|
153
|
+
if use_existing:
|
|
154
|
+
key_choice = typer.prompt(
|
|
155
|
+
"Enter the number of the key to use", type=int
|
|
156
|
+
)
|
|
157
|
+
if 1 <= key_choice <= len(existing_pub_keys):
|
|
158
|
+
key_path = existing_pub_keys[key_choice - 1][:-4]
|
|
159
|
+
else:
|
|
160
|
+
typer.echo("Invalid choice")
|
|
161
|
+
# Keep asking until they give a valid choice
|
|
162
|
+
while True:
|
|
163
|
+
key_choice = typer.prompt(
|
|
164
|
+
"Enter the number of the key to use", type=int
|
|
165
|
+
)
|
|
166
|
+
if 1 <= key_choice <= len(existing_pub_keys):
|
|
167
|
+
key_path = existing_pub_keys[key_choice - 1][:-4]
|
|
168
|
+
break
|
|
169
|
+
else:
|
|
170
|
+
typer.echo("Invalid choice, please try again.")
|
|
171
|
+
else:
|
|
172
|
+
key_path = typer.prompt(
|
|
173
|
+
"Enter the path to save the new SSH key",
|
|
174
|
+
default=os.path.join(ssh_dir, "id_ed25519"),
|
|
175
|
+
)
|
|
176
|
+
else:
|
|
177
|
+
typer.echo("No existing SSH keys found")
|
|
178
|
+
key_path = typer.prompt(
|
|
179
|
+
"Enter the path to save the new SSH key",
|
|
180
|
+
default=os.path.join(ssh_dir, "id_ed25519"),
|
|
181
|
+
)
|
|
182
|
+
# Get the user's email from their Git config, and ask them if they want to
|
|
183
|
+
# use that or a different one
|
|
184
|
+
try:
|
|
185
|
+
user_git_email = git.Git().config("--get", "user.email").strip()
|
|
186
|
+
except Exception:
|
|
187
|
+
user_git_email = typer.prompt(
|
|
188
|
+
"No email found in Git config; enter email for SSH key"
|
|
189
|
+
)
|
|
190
|
+
git.Git().config("--global", "user.email", user_git_email)
|
|
191
|
+
# Do the same for user name even though we don't need it
|
|
192
|
+
try:
|
|
193
|
+
user_git_name = git.Git().config("--get", "user.name").strip()
|
|
194
|
+
except Exception:
|
|
195
|
+
user_git_name = typer.prompt(
|
|
196
|
+
"No name found in Git config; enter name for SSH key"
|
|
197
|
+
)
|
|
198
|
+
git.Git().config("--global", "user.name", user_git_name)
|
|
199
|
+
keygen_cmd = [
|
|
200
|
+
"ssh-keygen",
|
|
201
|
+
"-t",
|
|
202
|
+
"ed25519",
|
|
203
|
+
"-C",
|
|
204
|
+
user_git_email,
|
|
205
|
+
"-f",
|
|
206
|
+
key_path,
|
|
207
|
+
]
|
|
208
|
+
subprocess.run(keygen_cmd)
|
|
209
|
+
# Start the SSH agent in the background
|
|
210
|
+
typer.echo("Checking that the SSH agent is running")
|
|
211
|
+
ssh_agent_cmd = subprocess.run(
|
|
212
|
+
["ssh-agent", "-s"], capture_output=True, text=True
|
|
213
|
+
).stdout
|
|
214
|
+
p = subprocess.run(ssh_agent_cmd, shell=True)
|
|
215
|
+
if p.returncode != 0:
|
|
216
|
+
raise_error("Failed to start ssh-agent")
|
|
217
|
+
# Add the SSH key to the ssh-agent
|
|
218
|
+
typer.echo(f"Adding SSH key to ssh-agent: {key_path}")
|
|
219
|
+
cmd = ["ssh-add", key_path]
|
|
220
|
+
p = subprocess.run(cmd)
|
|
221
|
+
if p.returncode != 0:
|
|
222
|
+
raise_error("Failed to add SSH key to ssh-agent; please try again")
|
|
223
|
+
# Now add to GitHub
|
|
224
|
+
gh_ssh_url = "https://github.com/settings/ssh/new"
|
|
225
|
+
typer.echo(
|
|
226
|
+
"Add the new SSH key to your GitHub account by visiting:\n"
|
|
227
|
+
f"{gh_ssh_url}"
|
|
228
|
+
)
|
|
229
|
+
with open(key_path + ".pub", "r") as f:
|
|
230
|
+
pub_key = f.read()
|
|
231
|
+
typer.echo(f"Paste this into the public key field:\n\n{pub_key}\n")
|
|
232
|
+
typer.confirm("Press Enter when done", default=True)
|
|
233
|
+
typer.echo("Testing SSH connection to GitHub")
|
|
234
|
+
p = subprocess.run(ssh_test_cmd, capture_output=True, text=True)
|
|
235
|
+
if "successfully authenticated" in p.stderr:
|
|
236
|
+
typer.echo("Successfully connected to GitHub via SSH!")
|
|
237
|
+
else:
|
|
238
|
+
raise_error(
|
|
239
|
+
"Failed to connect to GitHub via SSH; please check your setup"
|
|
240
|
+
)
|
|
@@ -981,22 +981,23 @@ def run(
|
|
|
981
981
|
except Exception as e:
|
|
982
982
|
os.environ.pop("CALKIT_PIPELINE_RUNNING", None)
|
|
983
983
|
raise_error(f"Pipeline compilation failed: {e}")
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
984
|
+
if save_log:
|
|
985
|
+
# Get status of Git repo before running
|
|
986
|
+
repo = git.Repo()
|
|
987
|
+
git_rev = repo.head.commit.hexsha
|
|
988
|
+
try:
|
|
989
|
+
git_branch = repo.active_branch.name
|
|
990
|
+
except TypeError:
|
|
991
|
+
# If no branch is checked out, we are in a detached HEAD state
|
|
992
|
+
git_branch = None
|
|
993
|
+
git_changed_files_before = calkit.git.get_changed_files(repo=repo)
|
|
994
|
+
git_staged_files_before = calkit.git.get_staged_files(repo=repo)
|
|
995
|
+
git_untracked_files_before = calkit.git.get_untracked_files(repo=repo)
|
|
996
|
+
# Get status of DVC repo before running
|
|
997
|
+
dvc_repo = dvc.repo.Repo()
|
|
998
|
+
dvc_status_before = dvc_repo.status()
|
|
999
|
+
dvc_data_status_before = dvc_repo.data_status()
|
|
1000
|
+
dvc_data_status_before.pop("git", None) # Remove git status
|
|
1000
1001
|
if targets is None:
|
|
1001
1002
|
targets = []
|
|
1002
1003
|
args = deepcopy(targets)
|
|
@@ -1855,3 +1856,51 @@ def run_jupyter(
|
|
|
1855
1856
|
"""Run a command with the Jupyter CLI."""
|
|
1856
1857
|
process = subprocess.run([sys.executable, "-m", "jupyter"] + sys.argv[2:])
|
|
1857
1858
|
sys.exit(process.returncode)
|
|
1859
|
+
|
|
1860
|
+
|
|
1861
|
+
@app.command(name="latexmk")
|
|
1862
|
+
def run_latexmk(
|
|
1863
|
+
tex_file: Annotated[str, typer.Argument(help="The .tex file to compile.")],
|
|
1864
|
+
environment: Annotated[
|
|
1865
|
+
str | None,
|
|
1866
|
+
typer.Option(
|
|
1867
|
+
"--env",
|
|
1868
|
+
"-e",
|
|
1869
|
+
help=("Environment in which to run latexmk, if applicable."),
|
|
1870
|
+
),
|
|
1871
|
+
] = None,
|
|
1872
|
+
):
|
|
1873
|
+
"""Compile a LaTeX document with latexmk.
|
|
1874
|
+
|
|
1875
|
+
If a Calkit environment is not specified, latexmk will be run in the
|
|
1876
|
+
system environment if available. If not available, a TeX Live Docker
|
|
1877
|
+
container will be used.
|
|
1878
|
+
"""
|
|
1879
|
+
latexmk_cmd = [
|
|
1880
|
+
"latexmk",
|
|
1881
|
+
"-pdf",
|
|
1882
|
+
"-cd",
|
|
1883
|
+
"-silent",
|
|
1884
|
+
"-synctex=1",
|
|
1885
|
+
"-interaction=nonstopmode",
|
|
1886
|
+
tex_file,
|
|
1887
|
+
]
|
|
1888
|
+
if environment is not None:
|
|
1889
|
+
cmd = ["calkit", "xenv", "--name", environment] + latexmk_cmd
|
|
1890
|
+
elif calkit.check_dep_exists("latexmk"):
|
|
1891
|
+
cmd = latexmk_cmd
|
|
1892
|
+
else:
|
|
1893
|
+
cmd = [
|
|
1894
|
+
"docker",
|
|
1895
|
+
"run",
|
|
1896
|
+
"--rm",
|
|
1897
|
+
"-v",
|
|
1898
|
+
f"{os.getcwd()}:/work",
|
|
1899
|
+
"-w",
|
|
1900
|
+
"/work",
|
|
1901
|
+
"texlive/texlive:latest-full",
|
|
1902
|
+
] + latexmk_cmd
|
|
1903
|
+
try:
|
|
1904
|
+
subprocess.check_call(cmd)
|
|
1905
|
+
except subprocess.CalledProcessError:
|
|
1906
|
+
raise_error("latexmk failed")
|
|
@@ -163,6 +163,17 @@ def execute_notebook(
|
|
|
163
163
|
),
|
|
164
164
|
),
|
|
165
165
|
] = None,
|
|
166
|
+
language: Annotated[
|
|
167
|
+
str,
|
|
168
|
+
typer.Option(
|
|
169
|
+
"--language",
|
|
170
|
+
"-l",
|
|
171
|
+
help=(
|
|
172
|
+
"Notebook language; if 'matlab', MATLAB kernel must be "
|
|
173
|
+
"available in environment."
|
|
174
|
+
),
|
|
175
|
+
),
|
|
176
|
+
] = "python",
|
|
166
177
|
verbose: Annotated[
|
|
167
178
|
bool, typer.Option("--verbose", "-v", help="Print verbose output.")
|
|
168
179
|
] = False,
|
|
@@ -176,10 +187,24 @@ def execute_notebook(
|
|
|
176
187
|
|
|
177
188
|
if os.path.isabs(path):
|
|
178
189
|
raise ValueError("Path must be relative")
|
|
190
|
+
if language.lower() not in ["python", "matlab", "julia"]:
|
|
191
|
+
raise ValueError(
|
|
192
|
+
"Language must be one of 'python', 'matlab', or 'julia'"
|
|
193
|
+
)
|
|
179
194
|
# First, ensure the specified environment has a kernel we can use
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
195
|
+
# We need to check the environment type and create the kernel if needed
|
|
196
|
+
if language.lower() == "python":
|
|
197
|
+
kernel_name = check_env_kernel(
|
|
198
|
+
env_name=env_name, no_check=no_check, verbose=verbose
|
|
199
|
+
)
|
|
200
|
+
elif language.lower() == "matlab":
|
|
201
|
+
kernel_name = "jupyter_matlab_kernel"
|
|
202
|
+
else:
|
|
203
|
+
raise_error(f"Language '{language}' not yet supported")
|
|
204
|
+
# We can't handle parameters unless language is Python
|
|
205
|
+
if language.lower() != "python":
|
|
206
|
+
if params or params_json is not None or params_base64 is not None:
|
|
207
|
+
raise_error("Parameters can only be passed to Python notebooks")
|
|
183
208
|
# Parse parameters
|
|
184
209
|
if params:
|
|
185
210
|
try:
|
|
@@ -214,14 +239,34 @@ def execute_notebook(
|
|
|
214
239
|
typer.echo(f"Using kernel: {kernel_name}")
|
|
215
240
|
typer.echo(f"Running with cwd: {notebook_dir}")
|
|
216
241
|
typer.echo(f"Output will be saved to: {fpath_out_exec}")
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
242
|
+
# If this is a Python or Julia notebook, we can use Papermill
|
|
243
|
+
# If it's a MATLAB notebook, we need to use the MATLAB kernel inside the
|
|
244
|
+
# specified environment
|
|
245
|
+
if language.lower() in ["python", "julia"]:
|
|
246
|
+
papermill.execute_notebook(
|
|
247
|
+
input_path=path,
|
|
248
|
+
output_path=fpath_out_exec,
|
|
249
|
+
kernel_name=kernel_name,
|
|
250
|
+
log_output=True,
|
|
251
|
+
parameters=parsed_params,
|
|
252
|
+
cwd=notebook_dir,
|
|
253
|
+
)
|
|
254
|
+
elif language.lower() == "matlab":
|
|
255
|
+
# Use nbconvert to execute the notebook with the MATLAB kernel
|
|
256
|
+
cmd = [
|
|
257
|
+
"python",
|
|
258
|
+
"-m",
|
|
259
|
+
"jupyter",
|
|
260
|
+
"nbconvert",
|
|
261
|
+
"--to",
|
|
262
|
+
"notebook",
|
|
263
|
+
"--execute",
|
|
264
|
+
f"--ExecutePreprocessor.kernel_name={kernel_name}",
|
|
265
|
+
"--output",
|
|
266
|
+
fpath_out_exec,
|
|
267
|
+
path,
|
|
268
|
+
]
|
|
269
|
+
run_in_env(cmd, env_name=env_name, no_check=no_check, verbose=verbose)
|
|
225
270
|
for to_fmt in to:
|
|
226
271
|
if to_fmt != "notebook":
|
|
227
272
|
try:
|
|
@@ -250,6 +295,6 @@ def execute_notebook(
|
|
|
250
295
|
fname_out,
|
|
251
296
|
]
|
|
252
297
|
typer.echo(f"Exporting {to_fmt}")
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
298
|
+
p = subprocess.run(cmd)
|
|
299
|
+
if p.returncode != 0:
|
|
300
|
+
raise_error(f"nbconvert failed for format '{to_fmt}'")
|
|
@@ -18,7 +18,7 @@ logger = logging.getLogger(__package__)
|
|
|
18
18
|
logger.setLevel(logging.INFO)
|
|
19
19
|
|
|
20
20
|
|
|
21
|
-
def configure_remote(wdir: str = None):
|
|
21
|
+
def configure_remote(wdir: str | None = None):
|
|
22
22
|
try:
|
|
23
23
|
project_name = calkit.detect_project_name(wdir=wdir)
|
|
24
24
|
except ValueError as e:
|
|
@@ -70,7 +70,9 @@ def configure_remote(wdir: str = None):
|
|
|
70
70
|
|
|
71
71
|
|
|
72
72
|
def set_remote_auth(
|
|
73
|
-
remote_name: str
|
|
73
|
+
remote_name: str | None = None,
|
|
74
|
+
always_auth: bool = False,
|
|
75
|
+
wdir: str | None = None,
|
|
74
76
|
):
|
|
75
77
|
"""Get a token and set it in the local DVC config so we can interact with
|
|
76
78
|
the cloud as an HTTP remote.
|
|
@@ -85,7 +87,7 @@ def set_remote_auth(
|
|
|
85
87
|
)["access_token"]
|
|
86
88
|
settings.dvc_token = token
|
|
87
89
|
settings.write()
|
|
88
|
-
subprocess.
|
|
90
|
+
p1 = subprocess.run(
|
|
89
91
|
[
|
|
90
92
|
sys.executable,
|
|
91
93
|
"-m",
|
|
@@ -99,7 +101,7 @@ def set_remote_auth(
|
|
|
99
101
|
],
|
|
100
102
|
cwd=wdir,
|
|
101
103
|
)
|
|
102
|
-
subprocess.
|
|
104
|
+
p2 = subprocess.run(
|
|
103
105
|
[
|
|
104
106
|
sys.executable,
|
|
105
107
|
"-m",
|
|
@@ -113,6 +115,10 @@ def set_remote_auth(
|
|
|
113
115
|
],
|
|
114
116
|
cwd=wdir,
|
|
115
117
|
)
|
|
118
|
+
if p1.returncode != 0 or p2.returncode != 0:
|
|
119
|
+
raise RuntimeError(
|
|
120
|
+
f"Failed to set DVC remote authentication for {remote_name}"
|
|
121
|
+
)
|
|
116
122
|
|
|
117
123
|
|
|
118
124
|
def add_external_remote(owner_name: str, project_name: str) -> dict:
|
|
@@ -159,13 +165,15 @@ def get_remotes(wdir: str | None = None) -> dict[str, str]:
|
|
|
159
165
|
"""Get a dictionary of DVC remotes, keyed by name, with URL as the
|
|
160
166
|
value.
|
|
161
167
|
"""
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
.strip()
|
|
168
|
+
p = subprocess.run(
|
|
169
|
+
[sys.executable, "-m", "dvc", "remote", "list"],
|
|
170
|
+
cwd=wdir,
|
|
171
|
+
capture_output=True,
|
|
172
|
+
text=True,
|
|
168
173
|
)
|
|
174
|
+
if p.returncode != 0:
|
|
175
|
+
raise RuntimeError(f"Error getting DVC remotes: {p.stderr.strip()}")
|
|
176
|
+
out = p.stdout.strip()
|
|
169
177
|
if not out:
|
|
170
178
|
return {}
|
|
171
179
|
resp = {}
|
|
@@ -182,12 +190,14 @@ def get_remotes(wdir: str | None = None) -> dict[str, str]:
|
|
|
182
190
|
return resp
|
|
183
191
|
|
|
184
192
|
|
|
185
|
-
def list_paths(wdir: str = None, recursive=False) -> list[str]:
|
|
193
|
+
def list_paths(wdir: str | None = None, recursive=False) -> list[str]:
|
|
186
194
|
"""List paths tracked with DVC."""
|
|
187
|
-
return [
|
|
195
|
+
return [
|
|
196
|
+
p.get("path", "") for p in list_files(wdir=wdir, recursive=recursive)
|
|
197
|
+
]
|
|
188
198
|
|
|
189
199
|
|
|
190
|
-
def list_files(wdir: str = None, recursive=True) -> list[dict]:
|
|
200
|
+
def list_files(wdir: str | None = None, recursive=True) -> list[dict]:
|
|
191
201
|
"""Return a list with all files in DVC, including their path and md5
|
|
192
202
|
checksum.
|
|
193
203
|
"""
|
|
@@ -113,6 +113,7 @@ class Stage(BaseModel):
|
|
|
113
113
|
"python-script",
|
|
114
114
|
"latex",
|
|
115
115
|
"matlab-script",
|
|
116
|
+
"matlab-command",
|
|
116
117
|
"docker-command",
|
|
117
118
|
"shell-command",
|
|
118
119
|
"shell-script",
|
|
@@ -164,7 +165,9 @@ class Stage(BaseModel):
|
|
|
164
165
|
|
|
165
166
|
@property
|
|
166
167
|
def xenv_cmd(self) -> str:
|
|
167
|
-
|
|
168
|
+
if self.environment == "_system":
|
|
169
|
+
return ""
|
|
170
|
+
return f"calkit xenv -n {self.environment} --no-check --"
|
|
168
171
|
|
|
169
172
|
def to_dvc(self) -> dict:
|
|
170
173
|
"""Convert to a DVC stage.
|
|
@@ -193,7 +196,7 @@ class PythonScriptStage(Stage):
|
|
|
193
196
|
|
|
194
197
|
@property
|
|
195
198
|
def dvc_cmd(self) -> str:
|
|
196
|
-
cmd = f"{self.xenv_cmd}
|
|
199
|
+
cmd = f"{self.xenv_cmd} python {self.script_path}"
|
|
197
200
|
for arg in self.args:
|
|
198
201
|
cmd += f" {arg}"
|
|
199
202
|
return cmd
|
|
@@ -212,7 +215,7 @@ class LatexStage(Stage):
|
|
|
212
215
|
|
|
213
216
|
@property
|
|
214
217
|
def dvc_cmd(self) -> str:
|
|
215
|
-
cmd = f"{self.xenv_cmd}
|
|
218
|
+
cmd = f"{self.xenv_cmd} latexmk -cd -interaction=nonstopmode"
|
|
216
219
|
if not self.verbose:
|
|
217
220
|
cmd += " -silent"
|
|
218
221
|
if self.force:
|
|
@@ -247,7 +250,26 @@ class MatlabScriptStage(Stage):
|
|
|
247
250
|
|
|
248
251
|
@property
|
|
249
252
|
def dvc_cmd(self) -> str:
|
|
250
|
-
|
|
253
|
+
cmd = self.xenv_cmd
|
|
254
|
+
if self.environment == "_system":
|
|
255
|
+
cmd += "matlab -batch"
|
|
256
|
+
cmd += f" \"run('{self.script_path}');\""
|
|
257
|
+
return cmd
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
class MatlabCommandStage(Stage):
|
|
261
|
+
kind: Literal["matlab-command"] = "matlab-command"
|
|
262
|
+
command: str
|
|
263
|
+
|
|
264
|
+
@property
|
|
265
|
+
def dvc_cmd(self) -> str:
|
|
266
|
+
# We need to escape quotes in the command
|
|
267
|
+
matlab_cmd = self.command.replace('"', '\\"')
|
|
268
|
+
cmd = self.xenv_cmd
|
|
269
|
+
if self.environment == "_system":
|
|
270
|
+
cmd += "matlab -batch"
|
|
271
|
+
cmd += f' "{matlab_cmd}"'
|
|
272
|
+
return cmd
|
|
251
273
|
|
|
252
274
|
|
|
253
275
|
class ShellCommandStage(Stage):
|
|
@@ -257,14 +279,13 @@ class ShellCommandStage(Stage):
|
|
|
257
279
|
|
|
258
280
|
@property
|
|
259
281
|
def dvc_cmd(self) -> str:
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
cmd = f"{self.xenv_cmd} -- "
|
|
282
|
+
shell_cmd = self.command.replace('"', '\\"')
|
|
283
|
+
cmd = self.xenv_cmd
|
|
263
284
|
if self.shell == "zsh":
|
|
264
285
|
norc_args = "-f"
|
|
265
286
|
else:
|
|
266
287
|
norc_args = "--noprofile --norc"
|
|
267
|
-
cmd += f'{self.shell} {norc_args} -c "{
|
|
288
|
+
cmd += f' {self.shell} {norc_args} -c "{shell_cmd}"'
|
|
268
289
|
return cmd
|
|
269
290
|
|
|
270
291
|
|
|
@@ -280,14 +301,12 @@ class ShellScriptStage(Stage):
|
|
|
280
301
|
|
|
281
302
|
@property
|
|
282
303
|
def dvc_cmd(self) -> str:
|
|
283
|
-
cmd =
|
|
284
|
-
if self.environment != "_system":
|
|
285
|
-
cmd = f"{self.xenv_cmd} -- "
|
|
304
|
+
cmd = self.xenv_cmd
|
|
286
305
|
if self.shell == "zsh":
|
|
287
306
|
norc_args = "-f"
|
|
288
307
|
else:
|
|
289
308
|
norc_args = "--noprofile --norc"
|
|
290
|
-
cmd += f"{self.shell} {norc_args} {self.script_path}"
|
|
309
|
+
cmd += f" {self.shell} {norc_args} {self.script_path}"
|
|
291
310
|
for arg in self.args:
|
|
292
311
|
cmd += f" {arg}"
|
|
293
312
|
return cmd
|
|
@@ -327,7 +346,7 @@ class JuliaScriptStage(Stage):
|
|
|
327
346
|
|
|
328
347
|
@property
|
|
329
348
|
def dvc_cmd(self) -> str:
|
|
330
|
-
cmd = f'{self.xenv_cmd}
|
|
349
|
+
cmd = f'{self.xenv_cmd} "include(\\"{self.script_path}\\")"'
|
|
331
350
|
return cmd
|
|
332
351
|
|
|
333
352
|
@property
|
|
@@ -343,7 +362,7 @@ class JuliaCommandStage(Stage):
|
|
|
343
362
|
def dvc_cmd(self) -> str:
|
|
344
363
|
# We need to escape quotes in the command
|
|
345
364
|
julia_cmd = self.command.replace('"', '\\"')
|
|
346
|
-
cmd = f'{self.xenv_cmd}
|
|
365
|
+
cmd = f'{self.xenv_cmd} "{julia_cmd}"'
|
|
347
366
|
return cmd
|
|
348
367
|
|
|
349
368
|
|
|
@@ -373,6 +392,7 @@ class JupyterNotebookStage(Stage):
|
|
|
373
392
|
executed_ipynb_storage: Literal["git", "dvc"] | None = "dvc"
|
|
374
393
|
html_storage: Literal["git", "dvc"] | None = "dvc"
|
|
375
394
|
parameters: dict[str, Any] = {}
|
|
395
|
+
language: Literal["python", "matlab", "julia"] = "python"
|
|
376
396
|
|
|
377
397
|
def update_parameters(self, params: dict) -> None:
|
|
378
398
|
"""If we have any templated parameters, update those, e.g., from
|
|
@@ -430,7 +450,10 @@ class JupyterNotebookStage(Stage):
|
|
|
430
450
|
|
|
431
451
|
@property
|
|
432
452
|
def dvc_cmd(self) -> str:
|
|
433
|
-
cmd =
|
|
453
|
+
cmd = (
|
|
454
|
+
f"calkit nb execute --environment {self.environment} "
|
|
455
|
+
f"--no-check --language {self.language}"
|
|
456
|
+
)
|
|
434
457
|
if self.html_storage:
|
|
435
458
|
cmd += " --to html"
|
|
436
459
|
if self.parameters:
|
|
@@ -533,6 +556,7 @@ class Pipeline(BaseModel):
|
|
|
533
556
|
PythonScriptStage
|
|
534
557
|
| LatexStage
|
|
535
558
|
| MatlabScriptStage
|
|
559
|
+
| MatlabCommandStage
|
|
536
560
|
| ShellCommandStage
|
|
537
561
|
| ShellScriptStage
|
|
538
562
|
| DockerCommandStage
|