calkit-python 0.27.3__tar.gz → 0.28.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.27.3 → calkit_python-0.28.0}/.github/workflows/test.yml +4 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/PKG-INFO +7 -4
- {calkit_python-0.27.3 → calkit_python-0.28.0}/README.md +4 -1
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/__init__.py +1 -1
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/cli/check.py +26 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/cli/main.py +33 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/cli/new.py +154 -13
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/core.py +4 -1
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/docker.py +12 -1
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/environments.py +14 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/models/pipeline.py +17 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/tests/cli/test_main.py +64 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/tests/cli/test_new.py +23 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/environments.md +22 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/index.md +4 -1
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/pipeline/index.md +4 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/pyproject.toml +2 -2
- {calkit_python-0.27.3 → calkit_python-0.28.0}/uv.lock +354 -351
- {calkit_python-0.27.3 → calkit_python-0.28.0}/.github/FUNDING.yml +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/.github/workflows/docs.yml +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/.github/workflows/format.yml +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/.github/workflows/publish-test.yml +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/.github/workflows/publish.yml +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/.gitignore +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/.pre-commit-config.yaml +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/.python-version +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/CITATION.cff +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/CONTRIBUTING.md +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/LICENSE +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/Makefile +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/__main__.py +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/calc.py +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/check.py +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/cli/__init__.py +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/cli/cloud.py +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/cli/config.py +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/cli/core.py +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/cli/describe.py +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/cli/import_.py +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/cli/list.py +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/cli/notebooks.py +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/cli/office.py +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/cli/overleaf.py +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/cli/update.py +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/cloud.py +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/conda.py +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/config.py +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/datasets.py +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/dvc.py +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/git.py +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/github.py +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/gui.py +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/jupyter.py +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/magics.py +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/matlab.py +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/models/__init__.py +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/models/core.py +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/models/io.py +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/models/iteration.py +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/notebooks.py +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/office.py +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/ops.py +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/pipeline.py +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/releases.py +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/server.py +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/templates/__init__.py +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/templates/core.py +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/templates/latex/__init__.py +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/templates/latex/article/paper.tex +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/templates/latex/core.py +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/templates/latex/jfm/jfm.bst +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/templates/latex/jfm/jfm.cls +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/templates/latex/jfm/lineno-FLM.sty +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/templates/latex/jfm/paper.tex +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/templates/latex/jfm/upmath.sty +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/tests/__init__.py +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/tests/cli/__init__.py +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/tests/cli/test_check.py +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/tests/cli/test_config.py +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/tests/cli/test_list.py +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/tests/cli/test_notebooks.py +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/tests/models/__init__.py +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/tests/models/test_iteration.py +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/tests/models/test_pipeline.py +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/tests/test_calc.py +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/tests/test_check.py +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/tests/test_conda.py +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/tests/test_core.py +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/tests/test_dvc.py +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/tests/test_jupyter.py +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/tests/test_magics.py +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/tests/test_notebooks.py +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/tests/test_pipeline.py +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/tests/test_templates.py +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/calkit/zenodo.py +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/CNAME +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/apps.md +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/calculations.md +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/calkit-yaml.md +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/cli-reference.md +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/cloud-integration.md +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/datasets.md +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/dependencies.md +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/examples.md +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/help.md +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/img/c-to-the-k-white.svg +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/img/calkit-no-bg.png +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/img/connect-zenodo.png +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/img/jupyterlab-params.png +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/img/vscode-nb-params.png +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/installation.md +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/local-server.md +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/notebooks.md +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/overleaf.md +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/pipeline/manual-steps.md +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/pipeline/running-and-logging.md +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/quickstart.md +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/references.md +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/releases.md +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/tutorials/adding-latex-pub-docker.md +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/tutorials/conda-envs.md +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/tutorials/existing-project.md +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/tutorials/first-project.md +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/tutorials/img/latex-codespaces/building-codespace.png +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/tutorials/img/latex-codespaces/codespaces-secrets-2.png +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/tutorials/img/latex-codespaces/editor-split.png +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/tutorials/img/latex-codespaces/go-to-linked-code.png +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/tutorials/img/latex-codespaces/issue-from-selection.png +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/tutorials/img/latex-codespaces/new-project.png +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/tutorials/img/latex-codespaces/new-pub-2.png +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/tutorials/img/latex-codespaces/new-token.png +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/tutorials/img/latex-codespaces/paper.tex.png +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/tutorials/img/latex-codespaces/project-home-3.png +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/tutorials/img/latex-codespaces/push.png +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/tutorials/img/latex-codespaces/stage.png +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/tutorials/img/office/anakin-excel.jpg +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/tutorials/img/office/chart-more-rows.png +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/tutorials/img/office/create-project.png +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/tutorials/img/office/elsevier-research-data-guidelines.png +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/tutorials/img/office/excel-chart.png +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/tutorials/img/office/excel-data.png +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/tutorials/img/office/insert-link-to-file.png +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/tutorials/img/office/needs-clone.png +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/tutorials/img/office/new-stage.png +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/tutorials/img/office/phd-comics-version-control.webp +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/tutorials/img/office/pipeline-out-of-date.png +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/tutorials/img/office/status-more-rows.png +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/tutorials/img/office/uncommitted-changes.png +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/tutorials/img/office/untracked-data.png +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/tutorials/img/office/updated-publication.png +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/tutorials/img/office/word-to-pdf-stage-2.png +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/tutorials/img/office/workflow-page.png +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/tutorials/img/openfoam/clone.png +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/tutorials/img/openfoam/create-project.png +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/tutorials/img/openfoam/datasets-page.png +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/tutorials/img/openfoam/figure-on-website-updated.png +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/tutorials/img/openfoam/figure-on-website.png +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/tutorials/img/openfoam/new-token.png +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/tutorials/img/openfoam/reclone.png +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/tutorials/img/openfoam/status-after-import-dataset.png +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/tutorials/img/run-proc.png +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/tutorials/index.md +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/tutorials/latex-codespaces.md +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/tutorials/matlab.md +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/tutorials/notebook-pipeline.md +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/tutorials/office.md +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/tutorials/openfoam.md +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/tutorials/procedures.md +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/docs/version-control.md +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/mkdocs.yml +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/scripts/install.ps1 +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/scripts/install.sh +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/test/nb-subdir.ipynb +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.0}/test/pipeline.ipynb +0 -0
- {calkit_python-0.27.3 → calkit_python-0.28.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.28.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
|
|
@@ -15,7 +15,7 @@ Requires-Dist: arithmeval
|
|
|
15
15
|
Requires-Dist: bibtexparser
|
|
16
16
|
Requires-Dist: checksumdir
|
|
17
17
|
Requires-Dist: docx2pdf
|
|
18
|
-
Requires-Dist: dvc==3.
|
|
18
|
+
Requires-Dist: dvc==3.62.0
|
|
19
19
|
Requires-Dist: fastapi
|
|
20
20
|
Requires-Dist: gitpython
|
|
21
21
|
Requires-Dist: jupyterlab>=4.4.5
|
|
@@ -31,7 +31,7 @@ Requires-Dist: python-dotenv>=1
|
|
|
31
31
|
Requires-Dist: pywin32; platform_system == 'Windows'
|
|
32
32
|
Requires-Dist: requests
|
|
33
33
|
Requires-Dist: tqdm>=4.67.1
|
|
34
|
-
Requires-Dist: typer
|
|
34
|
+
Requires-Dist: typer==0.16.0
|
|
35
35
|
Requires-Dist: uvicorn
|
|
36
36
|
Provides-Extra: data
|
|
37
37
|
Requires-Dist: pandas>=2.2.3; extra == 'data'
|
|
@@ -89,7 +89,10 @@ while guiding users away from common reproducibility pitfalls.
|
|
|
89
89
|
- A CLI to run the project's pipeline to verify it's reproducible,
|
|
90
90
|
regenerating outputs as needed and
|
|
91
91
|
ensuring all
|
|
92
|
-
computational environments
|
|
92
|
+
computational environments
|
|
93
|
+
(e.g., [Conda](https://docs.conda.io/en/latest/),
|
|
94
|
+
[Docker](https://docker.com), uv, Julia)
|
|
95
|
+
match their specification.
|
|
93
96
|
- A schema to store structured metadata describing the
|
|
94
97
|
project's important outputs (in its `calkit.yaml` file)
|
|
95
98
|
and how they are created
|
|
@@ -49,7 +49,10 @@ while guiding users away from common reproducibility pitfalls.
|
|
|
49
49
|
- A CLI to run the project's pipeline to verify it's reproducible,
|
|
50
50
|
regenerating outputs as needed and
|
|
51
51
|
ensuring all
|
|
52
|
-
computational environments
|
|
52
|
+
computational environments
|
|
53
|
+
(e.g., [Conda](https://docs.conda.io/en/latest/),
|
|
54
|
+
[Docker](https://docker.com), uv, Julia)
|
|
55
|
+
match their specification.
|
|
53
56
|
- A schema to store structured metadata describing the
|
|
54
57
|
project's important outputs (in its `calkit.yaml` file)
|
|
55
58
|
and how they are created
|
|
@@ -140,6 +140,32 @@ def check_environment(
|
|
|
140
140
|
env=env, env_name=env_name, as_posix=False
|
|
141
141
|
), # type: ignore
|
|
142
142
|
)
|
|
143
|
+
elif env["kind"] == "julia":
|
|
144
|
+
env_path = env.get("path")
|
|
145
|
+
if env_path is None:
|
|
146
|
+
raise_error(
|
|
147
|
+
"Julia environments require a path pointing to Project.toml"
|
|
148
|
+
)
|
|
149
|
+
env_fname = os.path.basename(env_path)
|
|
150
|
+
if not env_fname == "Project.toml":
|
|
151
|
+
raise_error(
|
|
152
|
+
"Julia environments require a path pointing to Project.toml"
|
|
153
|
+
)
|
|
154
|
+
env_dir = os.path.dirname(env_path)
|
|
155
|
+
if not env_dir:
|
|
156
|
+
env_dir = "."
|
|
157
|
+
cmd = [
|
|
158
|
+
"julia",
|
|
159
|
+
f"--project={env_dir}",
|
|
160
|
+
"-e",
|
|
161
|
+
"using Pkg; Pkg.instantiate();",
|
|
162
|
+
]
|
|
163
|
+
try:
|
|
164
|
+
subprocess.check_call(
|
|
165
|
+
cmd, env=os.environ.copy() | {"JULIA_LOAD_PATH": "@:@stdlib"}
|
|
166
|
+
)
|
|
167
|
+
except subprocess.CalledProcessError:
|
|
168
|
+
raise_error("Failed to check julia environment")
|
|
143
169
|
else:
|
|
144
170
|
raise_error(f"Environment kind '{env['kind']}' not supported")
|
|
145
171
|
return get_env_lock_fpath(env=env, env_name=env_name, as_posix=False)
|
|
@@ -38,6 +38,7 @@ from calkit.cli.check import (
|
|
|
38
38
|
check_app,
|
|
39
39
|
check_conda_env,
|
|
40
40
|
check_docker_env,
|
|
41
|
+
check_environment,
|
|
41
42
|
check_matlab_env,
|
|
42
43
|
check_venv,
|
|
43
44
|
)
|
|
@@ -1389,6 +1390,38 @@ def run_in_env(
|
|
|
1389
1390
|
subprocess.check_call(cmd, shell=True, cwd=wdir)
|
|
1390
1391
|
except subprocess.CalledProcessError:
|
|
1391
1392
|
raise_error(f"Failed to run in {kind}")
|
|
1393
|
+
elif env["kind"] == "julia":
|
|
1394
|
+
if not no_check:
|
|
1395
|
+
check_environment(env_name=env_name, verbose=verbose)
|
|
1396
|
+
env_path = env.get("path")
|
|
1397
|
+
if env_path is None:
|
|
1398
|
+
raise_error(
|
|
1399
|
+
"Julia environments require a path pointing to Project.toml"
|
|
1400
|
+
)
|
|
1401
|
+
env_fname = os.path.basename(env_path)
|
|
1402
|
+
if not env_fname == "Project.toml":
|
|
1403
|
+
raise_error(
|
|
1404
|
+
"Julia environments require a path pointing to Project.toml"
|
|
1405
|
+
)
|
|
1406
|
+
env_dir = os.path.dirname(env_path)
|
|
1407
|
+
if not env_dir:
|
|
1408
|
+
env_dir = "."
|
|
1409
|
+
julia_cmd = [
|
|
1410
|
+
"julia",
|
|
1411
|
+
"--project=" + env_dir,
|
|
1412
|
+
"-e",
|
|
1413
|
+
" ".join(cmd),
|
|
1414
|
+
]
|
|
1415
|
+
if verbose:
|
|
1416
|
+
typer.echo(f"Running command: {julia_cmd}")
|
|
1417
|
+
try:
|
|
1418
|
+
subprocess.check_call(
|
|
1419
|
+
julia_cmd,
|
|
1420
|
+
cwd=wdir,
|
|
1421
|
+
env=os.environ.copy() | {"JULIA_LOAD_PATH": "@:@stdlib"},
|
|
1422
|
+
)
|
|
1423
|
+
except subprocess.CalledProcessError:
|
|
1424
|
+
raise_error("Failed to run in julia environment")
|
|
1392
1425
|
elif env["kind"] == "ssh":
|
|
1393
1426
|
try:
|
|
1394
1427
|
host = os.path.expandvars(env["host"])
|
|
@@ -588,7 +588,8 @@ def new_docker_env(
|
|
|
588
588
|
layers: Annotated[
|
|
589
589
|
list[str],
|
|
590
590
|
typer.Option(
|
|
591
|
-
"--add-layer",
|
|
591
|
+
"--add-layer",
|
|
592
|
+
help="Add a layer (options: miniforge, foampy, uv, julia).",
|
|
592
593
|
),
|
|
593
594
|
] = [],
|
|
594
595
|
env_vars: Annotated[
|
|
@@ -703,11 +704,11 @@ def new_docker_env(
|
|
|
703
704
|
wdir=wdir,
|
|
704
705
|
)
|
|
705
706
|
if base is not None or path is not None:
|
|
706
|
-
env["path"] = path
|
|
707
|
+
env["path"] = path # type: ignore
|
|
707
708
|
if description is not None:
|
|
708
709
|
env["description"] = description
|
|
709
710
|
if layers:
|
|
710
|
-
env["layers"] = layers
|
|
711
|
+
env["layers"] = layers # type: ignore
|
|
711
712
|
if platform:
|
|
712
713
|
env["platform"] = platform
|
|
713
714
|
if user:
|
|
@@ -715,18 +716,18 @@ def new_docker_env(
|
|
|
715
716
|
if gpus:
|
|
716
717
|
env["gpus"] = gpus
|
|
717
718
|
if env_vars:
|
|
718
|
-
env["env_vars"] = {}
|
|
719
|
+
env["env_vars"] = {} # type: ignore
|
|
719
720
|
for var in env_vars:
|
|
720
721
|
if "=" not in var:
|
|
721
722
|
raise_error(f"Invalid environment variable format: {var}")
|
|
722
723
|
key, value = var.split("=", 1)
|
|
723
724
|
env["env_vars"][key] = value
|
|
724
725
|
if args:
|
|
725
|
-
env["args"] = args
|
|
726
|
+
env["args"] = args # type: ignore
|
|
726
727
|
if deps:
|
|
727
|
-
env["deps"] = deps
|
|
728
|
+
env["deps"] = deps # type: ignore
|
|
728
729
|
if ports:
|
|
729
|
-
env["ports"] = ports
|
|
730
|
+
env["ports"] = ports # type: ignore
|
|
730
731
|
envs[name] = env
|
|
731
732
|
ck_info["environments"] = envs
|
|
732
733
|
with open("calkit.yaml", "w") as f:
|
|
@@ -799,14 +800,14 @@ def new_dataset(
|
|
|
799
800
|
title: Annotated[str, typer.Option("--title")],
|
|
800
801
|
description: Annotated[str, typer.Option("--description")],
|
|
801
802
|
stage_name: Annotated[
|
|
802
|
-
str,
|
|
803
|
+
str | None,
|
|
803
804
|
typer.Option(
|
|
804
805
|
"--stage",
|
|
805
806
|
help="Name of the pipeline stage that generates this dataset.",
|
|
806
807
|
),
|
|
807
808
|
] = None,
|
|
808
809
|
cmd: Annotated[
|
|
809
|
-
str,
|
|
810
|
+
str | None,
|
|
810
811
|
typer.Option(
|
|
811
812
|
"--cmd", help="Command to add to the stage, if specified."
|
|
812
813
|
),
|
|
@@ -825,7 +826,7 @@ def new_dataset(
|
|
|
825
826
|
),
|
|
826
827
|
] = [],
|
|
827
828
|
outs_from_stage: Annotated[
|
|
828
|
-
str,
|
|
829
|
+
str | None,
|
|
829
830
|
typer.Option(
|
|
830
831
|
"--deps-from-stage-outs",
|
|
831
832
|
help="Stage name from which to add outputs as dependencies.",
|
|
@@ -1066,7 +1067,7 @@ def new_publication(
|
|
|
1066
1067
|
calkit.ryaml.dump(ck_info, f)
|
|
1067
1068
|
repo.git.add("calkit.yaml")
|
|
1068
1069
|
# Copy in template files if applicable
|
|
1069
|
-
if template_type == "latex":
|
|
1070
|
+
if template is not None and template_type == "latex":
|
|
1070
1071
|
if overwrite and os.path.exists(path):
|
|
1071
1072
|
shutil.rmtree(path)
|
|
1072
1073
|
calkit.templates.use_template(
|
|
@@ -1309,7 +1310,7 @@ def new_venv(
|
|
|
1309
1310
|
str, typer.Option("--prefix", help="Prefix for environment location.")
|
|
1310
1311
|
] = ".venv",
|
|
1311
1312
|
description: Annotated[
|
|
1312
|
-
str, typer.Option("--description", help="Description.")
|
|
1313
|
+
str | None, typer.Option("--description", help="Description.")
|
|
1313
1314
|
] = None,
|
|
1314
1315
|
overwrite: Annotated[
|
|
1315
1316
|
bool,
|
|
@@ -1390,7 +1391,7 @@ def new_pixi_env(
|
|
|
1390
1391
|
list[str], typer.Option("--pip", help="Packages to install with pip.")
|
|
1391
1392
|
] = [],
|
|
1392
1393
|
description: Annotated[
|
|
1393
|
-
str, typer.Option("--description", help="Description.")
|
|
1394
|
+
str | None, typer.Option("--description", help="Description.")
|
|
1394
1395
|
] = None,
|
|
1395
1396
|
platforms: Annotated[
|
|
1396
1397
|
list[str], typer.Option("--platform", "-p", help="Platform.")
|
|
@@ -1479,6 +1480,86 @@ def new_pixi_env(
|
|
|
1479
1480
|
repo.git.commit(["-m", f"Add pixi env {name}"])
|
|
1480
1481
|
|
|
1481
1482
|
|
|
1483
|
+
@new_app.command("julia-env")
|
|
1484
|
+
def new_julia_env(
|
|
1485
|
+
packages: Annotated[
|
|
1486
|
+
list[str],
|
|
1487
|
+
typer.Argument(help="Packages to include in the environment."),
|
|
1488
|
+
],
|
|
1489
|
+
name: Annotated[
|
|
1490
|
+
str, typer.Option("--name", "-n", help="Environment name.")
|
|
1491
|
+
],
|
|
1492
|
+
path: Annotated[
|
|
1493
|
+
str, typer.Option("--path", help="Path for Project.toml file.")
|
|
1494
|
+
] = "Project.toml",
|
|
1495
|
+
description: Annotated[
|
|
1496
|
+
str | None, typer.Option("--description", help="Description.")
|
|
1497
|
+
] = None,
|
|
1498
|
+
overwrite: Annotated[
|
|
1499
|
+
bool,
|
|
1500
|
+
typer.Option(
|
|
1501
|
+
"--overwrite",
|
|
1502
|
+
"-f",
|
|
1503
|
+
help="Overwrite any existing environment with this name.",
|
|
1504
|
+
),
|
|
1505
|
+
] = False,
|
|
1506
|
+
no_commit: Annotated[
|
|
1507
|
+
bool, typer.Option("--no-commit", help="Do not commit changes.")
|
|
1508
|
+
] = False,
|
|
1509
|
+
):
|
|
1510
|
+
"""Create a new Julia environment."""
|
|
1511
|
+
if not os.path.basename(path) == "Project.toml":
|
|
1512
|
+
raise_error(
|
|
1513
|
+
"Julia environment paths must point to a Project.toml file"
|
|
1514
|
+
)
|
|
1515
|
+
try:
|
|
1516
|
+
repo = git.Repo()
|
|
1517
|
+
except git.InvalidGitRepositoryError:
|
|
1518
|
+
raise_error(
|
|
1519
|
+
"Current directory is not a Git repository; run calkit init"
|
|
1520
|
+
)
|
|
1521
|
+
# Add environment to Calkit info
|
|
1522
|
+
ck_info = calkit.load_calkit_info()
|
|
1523
|
+
# If environments is a list instead of a dict, reformulate it
|
|
1524
|
+
envs = ck_info.get("environments", {})
|
|
1525
|
+
if isinstance(envs, list):
|
|
1526
|
+
typer.echo("Converting environments from list to dict")
|
|
1527
|
+
envs = {env.pop("name"): env for env in envs}
|
|
1528
|
+
if name in envs and not overwrite:
|
|
1529
|
+
raise_error(
|
|
1530
|
+
f"Environment with name {name} already exists "
|
|
1531
|
+
"(use -f to overwrite)"
|
|
1532
|
+
)
|
|
1533
|
+
# Create the environment now
|
|
1534
|
+
env_dir = os.path.dirname(path)
|
|
1535
|
+
if env_dir:
|
|
1536
|
+
os.makedirs(env_dir, exist_ok=True)
|
|
1537
|
+
else:
|
|
1538
|
+
env_dir = "."
|
|
1539
|
+
cmd = ["julia", f"--project={env_dir}", "-e"]
|
|
1540
|
+
install_cmd = "using Pkg;"
|
|
1541
|
+
for package in packages:
|
|
1542
|
+
install_cmd += f' Pkg.add("{package}");'
|
|
1543
|
+
cmd.append(install_cmd)
|
|
1544
|
+
try:
|
|
1545
|
+
subprocess.run(cmd, check=True)
|
|
1546
|
+
except subprocess.CalledProcessError:
|
|
1547
|
+
raise_error("Failed to create new Julia environment")
|
|
1548
|
+
typer.echo("Adding environment to calkit.yaml")
|
|
1549
|
+
env = dict(kind="julia", path=path, name=name)
|
|
1550
|
+
if description is not None:
|
|
1551
|
+
env["description"] = description
|
|
1552
|
+
envs[name] = env
|
|
1553
|
+
ck_info["environments"] = envs
|
|
1554
|
+
with open("calkit.yaml", "w") as f:
|
|
1555
|
+
ryaml.dump(ck_info, f)
|
|
1556
|
+
repo.git.add(path)
|
|
1557
|
+
repo.git.add(os.path.join(env_dir, "Manifest.toml"))
|
|
1558
|
+
repo.git.add("calkit.yaml")
|
|
1559
|
+
if not no_commit and repo.git.diff("--staged"):
|
|
1560
|
+
repo.git.commit(["-m", f"Add Julia env {name}"])
|
|
1561
|
+
|
|
1562
|
+
|
|
1482
1563
|
class Status(str, Enum):
|
|
1483
1564
|
in_progress = "in-progress"
|
|
1484
1565
|
on_hold = "on-hold"
|
|
@@ -1786,6 +1867,66 @@ def new_python_script_stage(
|
|
|
1786
1867
|
)
|
|
1787
1868
|
|
|
1788
1869
|
|
|
1870
|
+
@new_app.command(name="julia-script-stage")
|
|
1871
|
+
def new_julia_script_stage(
|
|
1872
|
+
name: StageArgs.name,
|
|
1873
|
+
environment: StageArgs.environment,
|
|
1874
|
+
script_path: StageArgs.script_path,
|
|
1875
|
+
inputs: StageArgs.inputs = [],
|
|
1876
|
+
outputs: StageArgs.outputs = [],
|
|
1877
|
+
outs_git: StageArgs.outs_git = [],
|
|
1878
|
+
outs_git_no_delete: StageArgs.outs_git_no_delete = [],
|
|
1879
|
+
outs_no_delete: StageArgs.outs_no_delete = [],
|
|
1880
|
+
outs_no_store: StageArgs.outs_no_store = [],
|
|
1881
|
+
outs_no_store_no_delete: StageArgs.outs_no_store_no_delete = [],
|
|
1882
|
+
iter_arg: Annotated[
|
|
1883
|
+
tuple[str, str] | None,
|
|
1884
|
+
typer.Option(
|
|
1885
|
+
"--iter",
|
|
1886
|
+
help=(
|
|
1887
|
+
"Iterate over an argument with a comma-separated list, e.g., "
|
|
1888
|
+
"--iter-arg var_name val1,val2,val3."
|
|
1889
|
+
),
|
|
1890
|
+
),
|
|
1891
|
+
] = None,
|
|
1892
|
+
overwrite: StageArgs.overwrite = False,
|
|
1893
|
+
no_check: StageArgs.no_check = False,
|
|
1894
|
+
no_commit: StageArgs.no_commit = False,
|
|
1895
|
+
) -> None:
|
|
1896
|
+
"""Add a stage to the pipeline that runs a Julia script."""
|
|
1897
|
+
ck_outs = _to_ck_outs(
|
|
1898
|
+
outputs=outputs,
|
|
1899
|
+
outs_git=outs_git,
|
|
1900
|
+
outs_git_no_delete=outs_git_no_delete,
|
|
1901
|
+
outs_no_delete=outs_no_delete,
|
|
1902
|
+
outs_no_store=outs_no_store,
|
|
1903
|
+
outs_no_store_no_delete=outs_no_store_no_delete,
|
|
1904
|
+
)
|
|
1905
|
+
try:
|
|
1906
|
+
if iter_arg is not None:
|
|
1907
|
+
arg_name, vals = iter_arg
|
|
1908
|
+
i = [StageIteration(arg_name=arg_name, values=vals.split(","))] # type: ignore
|
|
1909
|
+
else:
|
|
1910
|
+
i = None
|
|
1911
|
+
stage = calkit.models.pipeline.JuliaScriptStage(
|
|
1912
|
+
kind="julia-script",
|
|
1913
|
+
environment=environment,
|
|
1914
|
+
inputs=inputs, # type: ignore
|
|
1915
|
+
outputs=ck_outs,
|
|
1916
|
+
script_path=script_path,
|
|
1917
|
+
iterate_over=i,
|
|
1918
|
+
)
|
|
1919
|
+
except Exception as e:
|
|
1920
|
+
raise_error(f"Invalid stage specification: {e}")
|
|
1921
|
+
_save_stage(
|
|
1922
|
+
stage=stage,
|
|
1923
|
+
name=name,
|
|
1924
|
+
overwrite=overwrite,
|
|
1925
|
+
no_check=no_check,
|
|
1926
|
+
no_commit=no_commit,
|
|
1927
|
+
)
|
|
1928
|
+
|
|
1929
|
+
|
|
1789
1930
|
@new_app.command(name="matlab-script-stage")
|
|
1790
1931
|
def new_matlab_script_stage(
|
|
1791
1932
|
name: StageArgs.name,
|
|
@@ -309,6 +309,8 @@ def check_system_deps(
|
|
|
309
309
|
if "docker" not in deps:
|
|
310
310
|
deps.append("docker")
|
|
311
311
|
deps.append({"MATLAB_LICENSE_SERVER": {"kind": "env-var"}})
|
|
312
|
+
elif kind == "julia" and "julia" not in deps:
|
|
313
|
+
deps.append("julia")
|
|
312
314
|
for dep in deps:
|
|
313
315
|
if isinstance(dep, dict):
|
|
314
316
|
keys = list(dep.keys())
|
|
@@ -488,7 +490,7 @@ def detect_project_name(
|
|
|
488
490
|
if name is not None and not prepend_owner:
|
|
489
491
|
return name
|
|
490
492
|
owner = ck_info.get("owner")
|
|
491
|
-
if name is None
|
|
493
|
+
if name is None or owner is None:
|
|
492
494
|
try:
|
|
493
495
|
url = Repo(path=wdir).remote().url
|
|
494
496
|
except ValueError:
|
|
@@ -560,6 +562,7 @@ def get_system_info() -> dict:
|
|
|
560
562
|
"uv",
|
|
561
563
|
"pixi",
|
|
562
564
|
"Rscript",
|
|
565
|
+
"julia",
|
|
563
566
|
]:
|
|
564
567
|
system_info[f"{dep}_version"] = get_dep_version(dep)
|
|
565
568
|
system_info_str = json.dumps(system_info, sort_keys=True).encode()
|
|
@@ -47,7 +47,17 @@ RUN pip install --no-cache-dir numpy pandas matplotlib h5py \
|
|
|
47
47
|
""".strip()
|
|
48
48
|
|
|
49
49
|
UV_LAYER_TEXT = """
|
|
50
|
-
COPY --from=ghcr.io/astral-sh/uv:0.
|
|
50
|
+
COPY --from=ghcr.io/astral-sh/uv:0.8.5 /uv /uvx /bin/
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
JULIA_LAYER_TEXT = """
|
|
54
|
+
# Install Julia
|
|
55
|
+
# Ensure base image is a bullseye distribution
|
|
56
|
+
COPY --from=julia:1.11.6-bullseye /usr/local/julia /usr/local/julia
|
|
57
|
+
ENV JULIA_PATH=/usr/local/julia \
|
|
58
|
+
PATH=$PATH:/usr/local/julia/bin \
|
|
59
|
+
JULIA_GPG=3673DF529D9049477F76B37566E3C7DC03D6E495 \
|
|
60
|
+
JULIA_VERSION=1.11.6
|
|
51
61
|
"""
|
|
52
62
|
|
|
53
63
|
LAYERS = {
|
|
@@ -55,4 +65,5 @@ LAYERS = {
|
|
|
55
65
|
"miniforge": MINIFORGE_LAYER_TXT,
|
|
56
66
|
"foampy": FOAMPY_LAYER_TEXT,
|
|
57
67
|
"uv": UV_LAYER_TEXT,
|
|
68
|
+
"julia": JULIA_LAYER_TEXT,
|
|
58
69
|
}
|
|
@@ -28,6 +28,20 @@ def get_env_lock_fpath(
|
|
|
28
28
|
lock_fpath += ".yml"
|
|
29
29
|
elif env_kind == "matlab":
|
|
30
30
|
lock_fpath += ".json"
|
|
31
|
+
elif env_kind == "julia":
|
|
32
|
+
env_path = env.get("path")
|
|
33
|
+
if env_path is None:
|
|
34
|
+
raise ValueError(
|
|
35
|
+
"Julia environments require a path pointing to Project.toml"
|
|
36
|
+
)
|
|
37
|
+
env_fname = os.path.basename(env_path)
|
|
38
|
+
if not env_fname == "Project.toml":
|
|
39
|
+
raise ValueError(
|
|
40
|
+
"Julia environments require a path pointing to Project.toml"
|
|
41
|
+
)
|
|
42
|
+
# Simply replace Project.toml with Manifest.toml
|
|
43
|
+
env_dir = os.path.dirname(env_path)
|
|
44
|
+
lock_fpath = os.path.join(env_dir, "Manifest.toml")
|
|
31
45
|
else:
|
|
32
46
|
return
|
|
33
47
|
if as_posix:
|
|
@@ -109,6 +109,8 @@ class Stage(BaseModel):
|
|
|
109
109
|
"shell-script",
|
|
110
110
|
"jupyter-notebook",
|
|
111
111
|
"r-script",
|
|
112
|
+
"julia-script",
|
|
113
|
+
"word-to-pdf",
|
|
112
114
|
]
|
|
113
115
|
environment: str
|
|
114
116
|
wdir: str | None = None
|
|
@@ -309,6 +311,20 @@ class RScriptStage(Stage):
|
|
|
309
311
|
return cmd
|
|
310
312
|
|
|
311
313
|
|
|
314
|
+
class JuliaScriptStage(Stage):
|
|
315
|
+
kind: Literal["julia-script"] = "julia-script"
|
|
316
|
+
script_path: str
|
|
317
|
+
|
|
318
|
+
@property
|
|
319
|
+
def dvc_cmd(self) -> str:
|
|
320
|
+
cmd = f'{self.xenv_cmd} -- "include(\\"{self.script_path}\\")"'
|
|
321
|
+
return cmd
|
|
322
|
+
|
|
323
|
+
@property
|
|
324
|
+
def dvc_deps(self) -> list[str]:
|
|
325
|
+
return [self.script_path] + super().dvc_deps
|
|
326
|
+
|
|
327
|
+
|
|
312
328
|
class JupyterNotebookStage(Stage):
|
|
313
329
|
"""A stage that runs a Jupyter notebook.
|
|
314
330
|
|
|
@@ -466,6 +482,7 @@ class Pipeline(BaseModel):
|
|
|
466
482
|
| RScriptStage
|
|
467
483
|
| WordToPdfStage
|
|
468
484
|
| JupyterNotebookStage
|
|
485
|
+
| JuliaScriptStage
|
|
469
486
|
),
|
|
470
487
|
Discriminator("kind"),
|
|
471
488
|
],
|
|
@@ -234,6 +234,41 @@ def test_run_in_venv(tmp_dir):
|
|
|
234
234
|
assert out == "2.0.0"
|
|
235
235
|
|
|
236
236
|
|
|
237
|
+
def test_run_in_julia_env(tmp_dir):
|
|
238
|
+
subprocess.check_call("calkit init", shell=True)
|
|
239
|
+
subprocess.check_call(
|
|
240
|
+
[
|
|
241
|
+
"calkit",
|
|
242
|
+
"new",
|
|
243
|
+
"julia-env",
|
|
244
|
+
"-n",
|
|
245
|
+
"my-julia",
|
|
246
|
+
"--no-commit",
|
|
247
|
+
"Revise",
|
|
248
|
+
"PkgVersion",
|
|
249
|
+
]
|
|
250
|
+
)
|
|
251
|
+
out = (
|
|
252
|
+
subprocess.check_output(
|
|
253
|
+
[
|
|
254
|
+
"calkit",
|
|
255
|
+
"xenv",
|
|
256
|
+
"-n",
|
|
257
|
+
"my-julia",
|
|
258
|
+
"--",
|
|
259
|
+
(
|
|
260
|
+
"using Revise; using PkgVersion; "
|
|
261
|
+
"println(PkgVersion.Version(Revise))"
|
|
262
|
+
),
|
|
263
|
+
]
|
|
264
|
+
)
|
|
265
|
+
.decode()
|
|
266
|
+
.strip()
|
|
267
|
+
)
|
|
268
|
+
# TODO: Allow specifying version
|
|
269
|
+
assert out
|
|
270
|
+
|
|
271
|
+
|
|
237
272
|
def test_to_shell_cmd():
|
|
238
273
|
cmd = ["python", "-c", "import math; print('hello world')"]
|
|
239
274
|
subprocess.check_call(cmd)
|
|
@@ -420,6 +455,35 @@ def test_run(tmp_dir):
|
|
|
420
455
|
repo = git.Repo()
|
|
421
456
|
repo.git.checkout("HEAD^")
|
|
422
457
|
out = subprocess.check_output(["calkit", "run"], text=True)
|
|
458
|
+
# Test that we can run a Julia script
|
|
459
|
+
with open("julia_script.jl", "w") as f:
|
|
460
|
+
f.write('println("Hello from julia_script.jl")')
|
|
461
|
+
subprocess.check_call(
|
|
462
|
+
[
|
|
463
|
+
"calkit",
|
|
464
|
+
"new",
|
|
465
|
+
"julia-env",
|
|
466
|
+
"--name",
|
|
467
|
+
"j1",
|
|
468
|
+
"--path",
|
|
469
|
+
"something/Project.toml",
|
|
470
|
+
"PkgVersion",
|
|
471
|
+
]
|
|
472
|
+
)
|
|
473
|
+
subprocess.check_call(
|
|
474
|
+
[
|
|
475
|
+
"calkit",
|
|
476
|
+
"new",
|
|
477
|
+
"julia-script-stage",
|
|
478
|
+
"--name",
|
|
479
|
+
"stage-2",
|
|
480
|
+
"--script-path",
|
|
481
|
+
"julia_script.jl",
|
|
482
|
+
"-e",
|
|
483
|
+
"j1",
|
|
484
|
+
]
|
|
485
|
+
)
|
|
486
|
+
subprocess.check_call(["calkit", "run"])
|
|
423
487
|
|
|
424
488
|
|
|
425
489
|
def test_stage_run_info_from_log_content():
|
|
@@ -633,3 +633,26 @@ def test_new_matlab_script_stage(tmp_dir):
|
|
|
633
633
|
"results/output.txt",
|
|
634
634
|
"results/output2.txt",
|
|
635
635
|
]
|
|
636
|
+
|
|
637
|
+
|
|
638
|
+
def test_new_julia_env(tmp_dir):
|
|
639
|
+
subprocess.check_call(["calkit", "init"])
|
|
640
|
+
subprocess.check_call(
|
|
641
|
+
["calkit", "new", "julia-env", "--name", "j1", "WaterLily"]
|
|
642
|
+
)
|
|
643
|
+
assert os.path.isfile("Project.toml")
|
|
644
|
+
assert os.path.isfile("Manifest.toml")
|
|
645
|
+
subprocess.check_call(
|
|
646
|
+
[
|
|
647
|
+
"calkit",
|
|
648
|
+
"new",
|
|
649
|
+
"julia-env",
|
|
650
|
+
"--name",
|
|
651
|
+
"j2",
|
|
652
|
+
"Revise",
|
|
653
|
+
"--path",
|
|
654
|
+
"envs/my-env/Project.toml",
|
|
655
|
+
]
|
|
656
|
+
)
|
|
657
|
+
assert os.path.isfile("envs/my-env/Project.toml")
|
|
658
|
+
assert os.path.isfile("envs/my-env/Manifest.toml")
|
|
@@ -269,6 +269,28 @@ Again this highlights Calkit's declarative design philosophy.
|
|
|
269
269
|
Declare the environment and what command should be executed inside,
|
|
270
270
|
and Calkit will handle the rest.
|
|
271
271
|
|
|
272
|
+
### Julia
|
|
273
|
+
|
|
274
|
+
[Julia](https://julialang.org/) environments have paths that point to a
|
|
275
|
+
`Project.toml` file.
|
|
276
|
+
Creating a new Julia environment is similar to creating a Python environment:
|
|
277
|
+
|
|
278
|
+
```sh
|
|
279
|
+
calkit new julia-env \
|
|
280
|
+
--name my-julia-env \
|
|
281
|
+
--path ./envs/my-julia-env/Project.toml \
|
|
282
|
+
WaterLily \
|
|
283
|
+
Makie
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
Unlike Python environments, for which `xenv` runs a shell command,
|
|
287
|
+
`xenv` runs Julia commands in a Julia environment.
|
|
288
|
+
For example:
|
|
289
|
+
|
|
290
|
+
```sh
|
|
291
|
+
calkit xenv -n my-julia-env -- "println(\"hello world\");"
|
|
292
|
+
```
|
|
293
|
+
|
|
272
294
|
### SSH
|
|
273
295
|
|
|
274
296
|
It's possible to define a remote environment that uses `ssh` to connect
|
|
@@ -32,7 +32,10 @@ while guiding users away from common reproducibility pitfalls.
|
|
|
32
32
|
- A CLI to run the project's pipeline to verify it's reproducible,
|
|
33
33
|
regenerating outputs as needed and
|
|
34
34
|
ensuring all
|
|
35
|
-
computational environments
|
|
35
|
+
computational environments
|
|
36
|
+
(e.g., [Conda](https://docs.conda.io/en/latest/),
|
|
37
|
+
[Docker](https://docker.com), uv, Julia)
|
|
38
|
+
match their specification.
|
|
36
39
|
- A schema to store structured metadata describing the
|
|
37
40
|
project's important outputs (in its `calkit.yaml` file)
|
|
38
41
|
and how they are created
|