calkit-python 0.31.4__tar.gz → 0.32.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.31.4 → calkit_python-0.32.0}/PKG-INFO +4 -2
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/__init__.py +1 -1
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/cli/check.py +29 -0
- calkit_python-0.32.0/calkit/cli/latex.py +206 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/cli/main.py +148 -46
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/cli/new.py +3 -1
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/cli/notebooks.py +34 -22
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/cli/overleaf.py +86 -274
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/cli/update.py +110 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/core.py +9 -21
- calkit_python-0.32.0/calkit/environments.py +400 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/git.py +6 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/models/pipeline.py +146 -32
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/notebooks.py +49 -3
- calkit_python-0.32.0/calkit/overleaf.py +518 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/pipeline.py +21 -28
- calkit_python-0.32.0/calkit/tests/cli/test_latex.py +118 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/tests/cli/test_main.py +37 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/tests/cli/test_new.py +2 -5
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/tests/cli/test_overleaf.py +54 -1
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/tests/models/test_pipeline.py +48 -2
- calkit_python-0.32.0/calkit/tests/test_environments.py +76 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/tests/test_pipeline.py +6 -13
- {calkit_python-0.31.4 → calkit_python-0.32.0}/pyproject.toml +4 -1
- {calkit_python-0.31.4 → calkit_python-0.32.0}/uv.lock +531 -470
- calkit_python-0.31.4/calkit/environments.py +0 -207
- calkit_python-0.31.4/calkit/overleaf.py +0 -15
- {calkit_python-0.31.4 → calkit_python-0.32.0}/.github/FUNDING.yml +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/.github/workflows/docs.yml +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/.github/workflows/format.yml +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/.github/workflows/publish-test.yml +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/.github/workflows/publish.yml +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/.github/workflows/test.yml +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/.gitignore +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/.pre-commit-config.yaml +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/.python-version +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/CITATION.cff +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/CONTRIBUTING.md +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/LICENSE +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/Makefile +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/README.md +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/__main__.py +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/calc.py +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/check.py +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/cli/__init__.py +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/cli/cloud.py +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/cli/config.py +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/cli/core.py +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/cli/describe.py +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/cli/import_.py +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/cli/list.py +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/cli/office.py +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/cli/slurm.py +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/cloud.py +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/conda.py +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/config.py +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/datasets.py +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/docker.py +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/dvc.py +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/github.py +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/gui.py +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/invenio.py +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/jupyter.py +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/licenses.py +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/magics.py +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/matlab.py +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/models/__init__.py +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/models/core.py +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/models/io.py +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/models/iteration.py +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/office.py +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/ops.py +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/releases.py +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/server.py +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/templates/__init__.py +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/templates/core.py +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/templates/latex/__init__.py +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/templates/latex/article/paper.tex +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/templates/latex/core.py +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/templates/latex/jfm/jfm.bst +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/templates/latex/jfm/jfm.cls +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/templates/latex/jfm/lineno-FLM.sty +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/templates/latex/jfm/paper.tex +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/templates/latex/jfm/upmath.sty +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/tests/__init__.py +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/tests/cli/__init__.py +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/tests/cli/test_check.py +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/tests/cli/test_config.py +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/tests/cli/test_list.py +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/tests/cli/test_notebooks.py +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/tests/models/__init__.py +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/tests/models/test_iteration.py +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/tests/test_calc.py +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/tests/test_check.py +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/tests/test_conda.py +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/tests/test_core.py +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/tests/test_dvc.py +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/tests/test_invenio.py +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/tests/test_jupyter.py +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/tests/test_magics.py +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/tests/test_notebooks.py +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/calkit/tests/test_templates.py +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/CNAME +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/apps.md +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/calculations.md +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/calkit-yaml.md +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/cli-reference.md +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/cloud-integration.md +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/datasets.md +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/dependencies.md +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/environments.md +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/examples.md +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/help.md +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/img/c-to-the-k-white.svg +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/img/calkit-no-bg.png +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/img/connect-zenodo.png +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/img/jupyterlab-params.png +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/img/vscode-nb-params.png +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/index.md +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/installation.md +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/local-server.md +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/notebooks.md +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/overleaf.md +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/pipeline/index.md +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/pipeline/manual-steps.md +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/pipeline/running-and-logging.md +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/pipeline/slurm.md +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/quickstart.md +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/references.md +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/releases.md +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/tutorials/adding-latex-pub-docker.md +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/tutorials/conda-envs.md +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/tutorials/existing-project.md +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/tutorials/first-project.md +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/tutorials/github-actions.md +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/tutorials/img/actions-repo-secrets.png +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/tutorials/img/latex-codespaces/building-codespace.png +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/tutorials/img/latex-codespaces/codespaces-secrets-2.png +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/tutorials/img/latex-codespaces/editor-split.png +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/tutorials/img/latex-codespaces/go-to-linked-code.png +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/tutorials/img/latex-codespaces/issue-from-selection.png +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/tutorials/img/latex-codespaces/new-project.png +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/tutorials/img/latex-codespaces/new-pub-2.png +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/tutorials/img/latex-codespaces/new-token.png +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/tutorials/img/latex-codespaces/paper.tex.png +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/tutorials/img/latex-codespaces/project-home-3.png +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/tutorials/img/latex-codespaces/push.png +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/tutorials/img/latex-codespaces/stage.png +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/tutorials/img/office/anakin-excel.jpg +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/tutorials/img/office/chart-more-rows.png +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/tutorials/img/office/create-project.png +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/tutorials/img/office/elsevier-research-data-guidelines.png +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/tutorials/img/office/excel-chart.png +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/tutorials/img/office/excel-data.png +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/tutorials/img/office/insert-link-to-file.png +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/tutorials/img/office/needs-clone.png +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/tutorials/img/office/new-stage.png +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/tutorials/img/office/phd-comics-version-control.webp +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/tutorials/img/office/pipeline-out-of-date.png +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/tutorials/img/office/status-more-rows.png +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/tutorials/img/office/uncommitted-changes.png +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/tutorials/img/office/untracked-data.png +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/tutorials/img/office/updated-publication.png +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/tutorials/img/office/word-to-pdf-stage-2.png +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/tutorials/img/office/workflow-page.png +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/tutorials/img/openfoam/clone.png +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/tutorials/img/openfoam/create-project.png +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/tutorials/img/openfoam/datasets-page.png +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/tutorials/img/openfoam/figure-on-website-updated.png +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/tutorials/img/openfoam/figure-on-website.png +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/tutorials/img/openfoam/new-token.png +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/tutorials/img/openfoam/reclone.png +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/tutorials/img/openfoam/status-after-import-dataset.png +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/tutorials/img/quick-actions.png +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/tutorials/img/run-proc.png +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/tutorials/index.md +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/tutorials/latex-codespaces.md +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/tutorials/matlab.md +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/tutorials/notebook-pipeline.md +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/tutorials/office.md +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/tutorials/openfoam.md +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/tutorials/procedures.md +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/docs/version-control.md +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/mkdocs.yml +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/scripts/install.ps1 +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/scripts/install.sh +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/test/nb-julia.ipynb +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/test/nb-params.ipynb +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/test/nb-subdir.ipynb +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/test/pipeline.ipynb +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.0}/test/script.py +0 -0
- {calkit_python-0.31.4 → calkit_python-0.32.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.32.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,9 +15,10 @@ 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.64.0
|
|
19
19
|
Requires-Dist: fastapi
|
|
20
20
|
Requires-Dist: gitpython
|
|
21
|
+
Requires-Dist: json2latex>=0.0.2
|
|
21
22
|
Requires-Dist: jupyterlab>=4.4.5
|
|
22
23
|
Requires-Dist: keyring
|
|
23
24
|
Requires-Dist: nbconvert
|
|
@@ -30,6 +31,7 @@ Requires-Dist: pyjwt
|
|
|
30
31
|
Requires-Dist: python-dotenv>=1
|
|
31
32
|
Requires-Dist: pywin32; platform_system == 'Windows'
|
|
32
33
|
Requires-Dist: requests
|
|
34
|
+
Requires-Dist: sqlitedict>=2.1.0
|
|
33
35
|
Requires-Dist: tqdm>=4.67.1
|
|
34
36
|
Requires-Dist: typer==0.20.0
|
|
35
37
|
Requires-Dist: uvicorn
|
|
@@ -208,6 +208,35 @@ def check_environment(
|
|
|
208
208
|
return get_env_lock_fpath(env=env, env_name=env_name, as_posix=False)
|
|
209
209
|
|
|
210
210
|
|
|
211
|
+
@check_app.command(
|
|
212
|
+
name="envs",
|
|
213
|
+
help="Check that all environments are up-to-date.",
|
|
214
|
+
)
|
|
215
|
+
@check_app.command(name="environments")
|
|
216
|
+
def check_environments(
|
|
217
|
+
verbose: Annotated[
|
|
218
|
+
bool, typer.Option("--verbose", help="Print verbose output.")
|
|
219
|
+
] = False,
|
|
220
|
+
) -> str | None:
|
|
221
|
+
ck_info = calkit.load_calkit_info(process_includes="environments")
|
|
222
|
+
envs = ck_info.get("environments", {})
|
|
223
|
+
if not envs:
|
|
224
|
+
typer.echo("No environments defined in calkit.yaml")
|
|
225
|
+
return
|
|
226
|
+
failures = []
|
|
227
|
+
for env_name in envs.keys():
|
|
228
|
+
typer.echo(f"Checking environment: '{env_name}'")
|
|
229
|
+
try:
|
|
230
|
+
check_environment(env_name=env_name, verbose=verbose)
|
|
231
|
+
except Exception as e:
|
|
232
|
+
warn(f"Error checking environment '{env_name}': {e}")
|
|
233
|
+
failures.append(env_name)
|
|
234
|
+
if failures:
|
|
235
|
+
raise_error(
|
|
236
|
+
f"Failed to check the following environments: {', '.join(failures)}"
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
|
|
211
240
|
@check_app.command(name="docker-env")
|
|
212
241
|
def check_docker_env(
|
|
213
242
|
tag: Annotated[str, typer.Argument(help="Image tag.")],
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
"""Commands for working with LaTeX."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import os
|
|
7
|
+
import string
|
|
8
|
+
import subprocess
|
|
9
|
+
from copy import deepcopy
|
|
10
|
+
|
|
11
|
+
import typer
|
|
12
|
+
from typing_extensions import Annotated
|
|
13
|
+
|
|
14
|
+
import calkit
|
|
15
|
+
from calkit.cli import raise_error
|
|
16
|
+
|
|
17
|
+
latex_app = typer.Typer(no_args_is_help=True)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@latex_app.command(name="from-json")
|
|
21
|
+
def from_json(
|
|
22
|
+
input_fpaths: Annotated[
|
|
23
|
+
list[str], typer.Argument(help="Input JSON file path(s).")
|
|
24
|
+
],
|
|
25
|
+
output_fpaths: Annotated[
|
|
26
|
+
list[str],
|
|
27
|
+
typer.Option("--output", "-o", help="Output LaTeX file path(s)."),
|
|
28
|
+
],
|
|
29
|
+
command_name: Annotated[
|
|
30
|
+
str | None,
|
|
31
|
+
typer.Option("--command", help="Command name to use in LaTeX output."),
|
|
32
|
+
] = None,
|
|
33
|
+
fmt_json: Annotated[
|
|
34
|
+
str | None,
|
|
35
|
+
typer.Option(
|
|
36
|
+
"--format-json",
|
|
37
|
+
help=(
|
|
38
|
+
"Additional JSON input to use for formatting. "
|
|
39
|
+
"Can be used to add extra keys with simple expressions, etc."
|
|
40
|
+
),
|
|
41
|
+
),
|
|
42
|
+
] = None,
|
|
43
|
+
):
|
|
44
|
+
"""Convert a JSON file to LaTeX.
|
|
45
|
+
|
|
46
|
+
This is useful for referencing calculated values in LaTeX documents.
|
|
47
|
+
"""
|
|
48
|
+
import arithmetic_eval
|
|
49
|
+
import json2latex
|
|
50
|
+
|
|
51
|
+
def tokens_from_format_string(fmt: str):
|
|
52
|
+
return [
|
|
53
|
+
field.strip()
|
|
54
|
+
for _, field, _, _ in string.Formatter().parse(fmt)
|
|
55
|
+
if field
|
|
56
|
+
]
|
|
57
|
+
|
|
58
|
+
# Validate some stuff
|
|
59
|
+
if fmt_json is not None:
|
|
60
|
+
try:
|
|
61
|
+
fmt_dict = json.loads(fmt_json)
|
|
62
|
+
except json.JSONDecodeError:
|
|
63
|
+
raise_error("Format JSON is not valid JSON")
|
|
64
|
+
else:
|
|
65
|
+
fmt_dict = {}
|
|
66
|
+
data = {}
|
|
67
|
+
for input_fpath in input_fpaths:
|
|
68
|
+
if not os.path.isfile(input_fpath):
|
|
69
|
+
raise_error(f"Input file {input_fpath} does not exist")
|
|
70
|
+
if not input_fpath.endswith(".json"):
|
|
71
|
+
raise_error("Input file must be a JSON file")
|
|
72
|
+
with open(input_fpath) as f:
|
|
73
|
+
try:
|
|
74
|
+
data_i = json.load(f)
|
|
75
|
+
data.update(data_i)
|
|
76
|
+
except json.JSONDecodeError:
|
|
77
|
+
raise_error("Input JSON file is not valid JSON")
|
|
78
|
+
for output_fpath in output_fpaths:
|
|
79
|
+
if not output_fpath.endswith(".tex"):
|
|
80
|
+
raise_error("Output file must be a .tex file")
|
|
81
|
+
# Format the data
|
|
82
|
+
formatted = deepcopy(data)
|
|
83
|
+
for tex_var_name, fmt_string in fmt_dict.items():
|
|
84
|
+
fmt_string = str(fmt_string)
|
|
85
|
+
data_for_formatting = deepcopy(data)
|
|
86
|
+
# Do any relevant evals and add them to the data for formatting
|
|
87
|
+
tokens = tokens_from_format_string(fmt_string)
|
|
88
|
+
for t in tokens:
|
|
89
|
+
try:
|
|
90
|
+
data_for_formatting[t] = arithmetic_eval.evaluate(t, data)
|
|
91
|
+
except Exception:
|
|
92
|
+
raise_error(
|
|
93
|
+
f"Error evaluating expression '{t}' for formatting"
|
|
94
|
+
)
|
|
95
|
+
formatted[tex_var_name] = fmt_string.format(**data_for_formatting)
|
|
96
|
+
for out_path in output_fpaths:
|
|
97
|
+
# If no command is provided, use the output file name without extension
|
|
98
|
+
if command_name is None:
|
|
99
|
+
cmd_name = os.path.splitext(os.path.basename(out_path))[0]
|
|
100
|
+
else:
|
|
101
|
+
cmd_name = command_name
|
|
102
|
+
# Create output directory if it doesn't exist
|
|
103
|
+
outdir = os.path.dirname(out_path)
|
|
104
|
+
if outdir:
|
|
105
|
+
os.makedirs(outdir, exist_ok=True)
|
|
106
|
+
with open(out_path, "w") as f:
|
|
107
|
+
json2latex.dump(cmd_name, formatted, f)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
@latex_app.command(name="build")
|
|
111
|
+
def build(
|
|
112
|
+
tex_file: Annotated[str, typer.Argument(help="The .tex file to compile.")],
|
|
113
|
+
environment: Annotated[
|
|
114
|
+
str | None,
|
|
115
|
+
typer.Option(
|
|
116
|
+
"--env",
|
|
117
|
+
"-e",
|
|
118
|
+
help=("Environment in which to run latexmk, if applicable."),
|
|
119
|
+
),
|
|
120
|
+
] = None,
|
|
121
|
+
no_check: Annotated[
|
|
122
|
+
bool,
|
|
123
|
+
typer.Option(
|
|
124
|
+
"--no-check",
|
|
125
|
+
help=(
|
|
126
|
+
"Don't check the environment is valid before running latexmk."
|
|
127
|
+
),
|
|
128
|
+
),
|
|
129
|
+
] = False,
|
|
130
|
+
latexmk_rc_path: Annotated[
|
|
131
|
+
str | None,
|
|
132
|
+
typer.Option(
|
|
133
|
+
"--latexmk-rc",
|
|
134
|
+
"-r",
|
|
135
|
+
help="Path to a latexmkrc file to use for compilation.",
|
|
136
|
+
),
|
|
137
|
+
] = None,
|
|
138
|
+
no_synctex: Annotated[
|
|
139
|
+
bool,
|
|
140
|
+
typer.Option(
|
|
141
|
+
"--no-synctex",
|
|
142
|
+
help="Don't generate synctex file for source-to-pdf mapping.",
|
|
143
|
+
),
|
|
144
|
+
] = False,
|
|
145
|
+
force: Annotated[
|
|
146
|
+
bool,
|
|
147
|
+
typer.Option(
|
|
148
|
+
"--force",
|
|
149
|
+
"-f",
|
|
150
|
+
help=(
|
|
151
|
+
"Force latexmk to recompile all files, even if they are up to "
|
|
152
|
+
"date."
|
|
153
|
+
),
|
|
154
|
+
),
|
|
155
|
+
] = False,
|
|
156
|
+
verbose: Annotated[
|
|
157
|
+
bool, typer.Option("--verbose", "-v", help="Print verbose output.")
|
|
158
|
+
] = False,
|
|
159
|
+
):
|
|
160
|
+
"""Build a PDF of a LaTeX document with latexmk.
|
|
161
|
+
|
|
162
|
+
If a Calkit environment is not specified, latexmk will be run in the
|
|
163
|
+
system environment if available. If not available, a TeX Live Docker
|
|
164
|
+
container will be used.
|
|
165
|
+
"""
|
|
166
|
+
# Now formulate the command
|
|
167
|
+
latexmk_cmd = ["latexmk", "-pdf", "-cd"]
|
|
168
|
+
if latexmk_rc_path is not None:
|
|
169
|
+
latexmk_cmd += ["-r", latexmk_rc_path]
|
|
170
|
+
if not no_synctex:
|
|
171
|
+
latexmk_cmd.append("-synctex=1")
|
|
172
|
+
if not verbose:
|
|
173
|
+
latexmk_cmd.append("-silent")
|
|
174
|
+
if force:
|
|
175
|
+
latexmk_cmd.append("-f")
|
|
176
|
+
latexmk_cmd += ["-interaction=nonstopmode", tex_file]
|
|
177
|
+
if environment is not None:
|
|
178
|
+
if no_check:
|
|
179
|
+
check_cmd = ["--no-check"]
|
|
180
|
+
else:
|
|
181
|
+
check_cmd = []
|
|
182
|
+
cmd = (
|
|
183
|
+
["calkit", "xenv", "--name", environment]
|
|
184
|
+
+ check_cmd
|
|
185
|
+
+ ["--"]
|
|
186
|
+
+ latexmk_cmd
|
|
187
|
+
)
|
|
188
|
+
if verbose:
|
|
189
|
+
typer.echo(f"Running command: {cmd}")
|
|
190
|
+
elif calkit.check_dep_exists("latexmk"):
|
|
191
|
+
cmd = latexmk_cmd
|
|
192
|
+
else:
|
|
193
|
+
cmd = [
|
|
194
|
+
"docker",
|
|
195
|
+
"run",
|
|
196
|
+
"--rm",
|
|
197
|
+
"-v",
|
|
198
|
+
f"{os.getcwd()}:/work",
|
|
199
|
+
"-w",
|
|
200
|
+
"/work",
|
|
201
|
+
"texlive/texlive:latest-full",
|
|
202
|
+
] + latexmk_cmd
|
|
203
|
+
try:
|
|
204
|
+
subprocess.check_call(cmd)
|
|
205
|
+
except subprocess.CalledProcessError:
|
|
206
|
+
raise_error("latexmk failed")
|
|
@@ -16,7 +16,7 @@ import time
|
|
|
16
16
|
import uuid
|
|
17
17
|
from copy import deepcopy
|
|
18
18
|
from datetime import datetime
|
|
19
|
-
from pathlib import
|
|
19
|
+
from pathlib import Path
|
|
20
20
|
|
|
21
21
|
import dotenv
|
|
22
22
|
import git
|
|
@@ -40,6 +40,7 @@ from calkit.cli.cloud import cloud_app
|
|
|
40
40
|
from calkit.cli.config import config_app
|
|
41
41
|
from calkit.cli.describe import describe_app
|
|
42
42
|
from calkit.cli.import_ import import_app
|
|
43
|
+
from calkit.cli.latex import latex_app
|
|
43
44
|
from calkit.cli.list import list_app
|
|
44
45
|
from calkit.cli.new import new_app
|
|
45
46
|
from calkit.cli.notebooks import notebooks_app
|
|
@@ -70,6 +71,7 @@ app.add_typer(import_app, name="import", help="Import objects.")
|
|
|
70
71
|
app.add_typer(office_app, name="office", help="Work with Microsoft Office.")
|
|
71
72
|
app.add_typer(update_app, name="update", help="Update objects.")
|
|
72
73
|
app.add_typer(check_app, name="check", help="Check things.")
|
|
74
|
+
app.add_typer(latex_app, name="latex", help="Work with LaTeX.")
|
|
73
75
|
app.add_typer(overleaf_app, name="overleaf", help="Interact with Overleaf.")
|
|
74
76
|
app.add_typer(cloud_app, name="cloud", help="Interact with a Calkit Cloud.")
|
|
75
77
|
app.add_typer(slurm_app, name="slurm", help="Work with SLURM.")
|
|
@@ -264,6 +266,11 @@ def get_status():
|
|
|
264
266
|
calkit.pipeline.to_dvc(ck_info=ck_info, write=True)
|
|
265
267
|
except Exception as e:
|
|
266
268
|
warn(f"Failed to compile pipeline: {e.__class__.__name__}: {e}")
|
|
269
|
+
# Clean all notebooks in the pipeline
|
|
270
|
+
try:
|
|
271
|
+
calkit.notebooks.clean_all_in_pipeline(ck_info=ck_info)
|
|
272
|
+
except Exception as e:
|
|
273
|
+
warn(f"Failed to clean notebooks: {e.__class__.__name__}: {e}")
|
|
267
274
|
print_sep("Project")
|
|
268
275
|
# Print latest status
|
|
269
276
|
status = calkit.get_latest_project_status()
|
|
@@ -287,7 +294,7 @@ def get_status():
|
|
|
287
294
|
print_sep("Data (DVC)")
|
|
288
295
|
run_cmd([sys.executable, "-m", "dvc", "data", "status"])
|
|
289
296
|
typer.echo()
|
|
290
|
-
print_sep("Pipeline
|
|
297
|
+
print_sep("Pipeline")
|
|
291
298
|
run_cmd([sys.executable, "-m", "dvc", "status"])
|
|
292
299
|
|
|
293
300
|
|
|
@@ -769,7 +776,7 @@ def ignore(
|
|
|
769
776
|
"""Ignore a file, i.e., keep it out of version control."""
|
|
770
777
|
repo = git.Repo()
|
|
771
778
|
# Ensure path makes it into .gitignore as a POSIX path
|
|
772
|
-
path =
|
|
779
|
+
path = Path(path).as_posix()
|
|
773
780
|
if repo.ignored(path):
|
|
774
781
|
typer.echo(f"{path} is already ignored")
|
|
775
782
|
return
|
|
@@ -1022,6 +1029,9 @@ def run(
|
|
|
1022
1029
|
import dvc.ui
|
|
1023
1030
|
from dvc.cli import main as dvc_cli_main
|
|
1024
1031
|
|
|
1032
|
+
import calkit.environments
|
|
1033
|
+
import calkit.pipeline
|
|
1034
|
+
|
|
1025
1035
|
if (target_inputs or target_outputs) and targets:
|
|
1026
1036
|
raise_error("Cannot specify both targets and inputs")
|
|
1027
1037
|
os.environ["CALKIT_PIPELINE_RUNNING"] = "1"
|
|
@@ -1029,8 +1039,14 @@ def run(
|
|
|
1029
1039
|
ck_info = calkit.load_calkit_info()
|
|
1030
1040
|
# Set env vars
|
|
1031
1041
|
calkit.set_env_vars(ck_info=ck_info)
|
|
1042
|
+
# Clean all notebooks in the pipeline
|
|
1043
|
+
try:
|
|
1044
|
+
calkit.notebooks.clean_all_in_pipeline(ck_info=ck_info)
|
|
1045
|
+
except Exception as e:
|
|
1046
|
+
raise_error(f"Failed to clean notebooks: {e.__class__.__name__}: {e}")
|
|
1032
1047
|
if not quiet:
|
|
1033
1048
|
typer.echo("Getting system information")
|
|
1049
|
+
# Get system information
|
|
1034
1050
|
system_info = calkit.get_system_info()
|
|
1035
1051
|
if save_log:
|
|
1036
1052
|
# Save the system to .calkit/systems
|
|
@@ -1047,11 +1063,23 @@ def run(
|
|
|
1047
1063
|
if not quiet:
|
|
1048
1064
|
typer.echo("Checking system-level dependencies")
|
|
1049
1065
|
try:
|
|
1050
|
-
calkit.check_system_deps(system_info=system_info)
|
|
1066
|
+
calkit.check_system_deps(ck_info=ck_info, system_info=system_info)
|
|
1051
1067
|
except Exception as e:
|
|
1052
1068
|
os.environ.pop("CALKIT_PIPELINE_RUNNING", None)
|
|
1053
1069
|
raise_error(str(e))
|
|
1054
|
-
#
|
|
1070
|
+
# Check all environments in the pipeline (with caching)
|
|
1071
|
+
# If any failed, warn the user that we might have problems running
|
|
1072
|
+
typer.echo("Checking environments")
|
|
1073
|
+
env_check_results = calkit.environments.check_all_in_pipeline(
|
|
1074
|
+
ck_info=ck_info, targets=targets, force=force
|
|
1075
|
+
)
|
|
1076
|
+
for env_name, result in env_check_results.items():
|
|
1077
|
+
if verbose:
|
|
1078
|
+
typer.echo(f"{env_name}: {result}")
|
|
1079
|
+
failed = not result.get("success", False)
|
|
1080
|
+
if failed:
|
|
1081
|
+
warn(f"Failed to check environment '{env_name}'")
|
|
1082
|
+
# Compile the DVC pipeline
|
|
1055
1083
|
dvc_stages = None
|
|
1056
1084
|
if ck_info.get("pipeline", {}):
|
|
1057
1085
|
if not quiet:
|
|
@@ -2013,49 +2041,123 @@ def run_jupyter(
|
|
|
2013
2041
|
sys.exit(process.returncode)
|
|
2014
2042
|
|
|
2015
2043
|
|
|
2016
|
-
@app.command(name="
|
|
2017
|
-
def
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
str | None,
|
|
2044
|
+
@app.command(name="map-paths")
|
|
2045
|
+
def map_paths(
|
|
2046
|
+
file_to_file: Annotated[
|
|
2047
|
+
list[str],
|
|
2021
2048
|
typer.Option(
|
|
2022
|
-
"--
|
|
2023
|
-
|
|
2024
|
-
|
|
2049
|
+
"--file-to-file",
|
|
2050
|
+
help=(
|
|
2051
|
+
"Map a file to another file, e.g., "
|
|
2052
|
+
"--file-to-file 'results.tex->paper/results.tex'."
|
|
2053
|
+
),
|
|
2025
2054
|
),
|
|
2026
|
-
] =
|
|
2055
|
+
] = [],
|
|
2056
|
+
file_to_dir: Annotated[
|
|
2057
|
+
list[str],
|
|
2058
|
+
typer.Option(
|
|
2059
|
+
"--file-to-dir",
|
|
2060
|
+
help=(
|
|
2061
|
+
"Map a file into a directory, e.g., "
|
|
2062
|
+
"--file-to-dir 'results.tex->paper/results'."
|
|
2063
|
+
),
|
|
2064
|
+
),
|
|
2065
|
+
] = [],
|
|
2066
|
+
dir_to_dir_replace: Annotated[
|
|
2067
|
+
list[str],
|
|
2068
|
+
typer.Option(
|
|
2069
|
+
"--dir-to-dir-replace",
|
|
2070
|
+
help=(
|
|
2071
|
+
"Copy directory to another directory and replace it, "
|
|
2072
|
+
"e.g., --dir-to-dir-replace 'figures->paper/figures'."
|
|
2073
|
+
),
|
|
2074
|
+
),
|
|
2075
|
+
] = [],
|
|
2076
|
+
dir_to_dir_merge: Annotated[
|
|
2077
|
+
list[str],
|
|
2078
|
+
typer.Option(
|
|
2079
|
+
"--dir-to-dir-merge",
|
|
2080
|
+
help=(
|
|
2081
|
+
"Merge directory into another directory. "
|
|
2082
|
+
"This is useful for merging contents of one directory into "
|
|
2083
|
+
"another, e.g., --dir-to-dir-merge 'figures->paper/figures'."
|
|
2084
|
+
),
|
|
2085
|
+
),
|
|
2086
|
+
] = [],
|
|
2027
2087
|
):
|
|
2028
|
-
"""
|
|
2088
|
+
"""Map paths in a project.
|
|
2029
2089
|
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
container will be used.
|
|
2090
|
+
Currently this is done with copying. Outputs are ensured to be ignored by
|
|
2091
|
+
Git.
|
|
2033
2092
|
"""
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
]
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2093
|
+
repo = git.Repo()
|
|
2094
|
+
|
|
2095
|
+
def ensure_path_is_ignored(path):
|
|
2096
|
+
if not repo.ignored(path):
|
|
2097
|
+
typer.echo(f"Adding {path} to .gitignore")
|
|
2098
|
+
with open(".gitignore", "a") as f:
|
|
2099
|
+
f.write(f"\n{path}\n")
|
|
2100
|
+
|
|
2101
|
+
def validate_and_split(mapping: str) -> tuple[str, str]:
|
|
2102
|
+
if "->" not in mapping:
|
|
2103
|
+
raise_error(
|
|
2104
|
+
f"Invalid path mapping format: '{mapping}'; "
|
|
2105
|
+
"Expected format: 'src->dest'"
|
|
2106
|
+
)
|
|
2107
|
+
parts = mapping.split("->")
|
|
2108
|
+
if len(parts) != 2:
|
|
2109
|
+
raise_error(
|
|
2110
|
+
f"Invalid path mapping format: '{mapping}'; "
|
|
2111
|
+
"Expected exactly one '->' separator"
|
|
2112
|
+
)
|
|
2113
|
+
return parts[0].strip(), parts[1].strip()
|
|
2114
|
+
|
|
2115
|
+
for copy_file in file_to_file:
|
|
2116
|
+
src_path, dest_path = validate_and_split(copy_file)
|
|
2117
|
+
if os.path.isdir(dest_path):
|
|
2118
|
+
raise_error(f"Destination path '{dest_path}' is a directory")
|
|
2119
|
+
parent_dir = os.path.dirname(dest_path)
|
|
2120
|
+
if parent_dir:
|
|
2121
|
+
os.makedirs(parent_dir, exist_ok=True)
|
|
2122
|
+
shutil.copy2(src_path, dest_path)
|
|
2123
|
+
ensure_path_is_ignored(dest_path)
|
|
2124
|
+
for copy_file in file_to_dir:
|
|
2125
|
+
src_path, dest_dir = validate_and_split(copy_file)
|
|
2126
|
+
if os.path.isfile(dest_dir):
|
|
2127
|
+
raise_error(f"Destination path '{dest_dir}' is a file")
|
|
2128
|
+
if not os.path.isdir(dest_dir):
|
|
2129
|
+
os.makedirs(dest_dir, exist_ok=True)
|
|
2130
|
+
dest_path = os.path.join(dest_dir, os.path.basename(src_path))
|
|
2131
|
+
shutil.copy2(src_path, dest_path)
|
|
2132
|
+
ensure_path_is_ignored(dest_path)
|
|
2133
|
+
for replace_dir_with_dir in dir_to_dir_replace:
|
|
2134
|
+
src_dir, dest_dir = validate_and_split(replace_dir_with_dir)
|
|
2135
|
+
if os.path.isfile(dest_dir):
|
|
2136
|
+
raise_error(f"Destination path '{dest_dir}' is a file")
|
|
2137
|
+
if os.path.isfile(src_dir):
|
|
2138
|
+
raise_error(f"Source path '{src_dir}' is a file")
|
|
2139
|
+
if os.path.isdir(dest_dir):
|
|
2140
|
+
shutil.rmtree(dest_dir)
|
|
2141
|
+
parent_dir = os.path.dirname(dest_dir)
|
|
2142
|
+
if parent_dir:
|
|
2143
|
+
os.makedirs(parent_dir, exist_ok=True)
|
|
2144
|
+
shutil.copytree(src_dir, dest_dir)
|
|
2145
|
+
ensure_path_is_ignored(dest_dir)
|
|
2146
|
+
for merge_dir_to_dir in dir_to_dir_merge:
|
|
2147
|
+
src_dir, dest_dir = validate_and_split(merge_dir_to_dir)
|
|
2148
|
+
if os.path.isfile(dest_dir):
|
|
2149
|
+
raise_error(f"Destination path '{dest_dir}' is a file")
|
|
2150
|
+
if os.path.isfile(src_dir):
|
|
2151
|
+
raise_error(f"Source path '{src_dir}' is a file")
|
|
2152
|
+
if not os.path.isdir(dest_dir):
|
|
2153
|
+
os.makedirs(dest_dir, exist_ok=True)
|
|
2154
|
+
for item in os.listdir(src_dir):
|
|
2155
|
+
if item.startswith("."):
|
|
2156
|
+
continue
|
|
2157
|
+
src_item = os.path.join(src_dir, item)
|
|
2158
|
+
dest_item = os.path.join(dest_dir, item)
|
|
2159
|
+
if os.path.isdir(src_item):
|
|
2160
|
+
shutil.copytree(src_item, dest_item, dirs_exist_ok=True)
|
|
2161
|
+
else:
|
|
2162
|
+
shutil.copy2(src_item, dest_item)
|
|
2163
|
+
ensure_path_is_ignored(dest_item)
|
|
@@ -2838,7 +2838,9 @@ def new_stage(
|
|
|
2838
2838
|
if kind.value == "python-script":
|
|
2839
2839
|
cmd += f"python {target}"
|
|
2840
2840
|
elif kind.value == "latex":
|
|
2841
|
-
cmd
|
|
2841
|
+
cmd = f"calkit latex build {target}"
|
|
2842
|
+
if environment is not None:
|
|
2843
|
+
cmd += f" --environment {environment}"
|
|
2842
2844
|
out_target = target.removesuffix(".tex") + ".pdf"
|
|
2843
2845
|
if out_target not in (
|
|
2844
2846
|
outs + outs_no_cache + outs_persist + outs_persist_no_cache
|
|
@@ -7,12 +7,13 @@ import json
|
|
|
7
7
|
import os
|
|
8
8
|
import subprocess
|
|
9
9
|
import sys
|
|
10
|
-
from pathlib import
|
|
10
|
+
from pathlib import Path
|
|
11
11
|
from typing import Any
|
|
12
12
|
|
|
13
13
|
import typer
|
|
14
14
|
from typing_extensions import Annotated
|
|
15
15
|
|
|
16
|
+
import calkit
|
|
16
17
|
import calkit.notebooks
|
|
17
18
|
from calkit.cli.core import raise_error
|
|
18
19
|
|
|
@@ -20,32 +21,43 @@ notebooks_app = typer.Typer(no_args_is_help=True)
|
|
|
20
21
|
|
|
21
22
|
|
|
22
23
|
@notebooks_app.command("clean")
|
|
23
|
-
def clean_notebook_outputs(
|
|
24
|
+
def clean_notebook_outputs(
|
|
25
|
+
path: str,
|
|
26
|
+
quiet: Annotated[
|
|
27
|
+
bool, typer.Option("--quiet", "-q", help="Do not print output.")
|
|
28
|
+
] = False,
|
|
29
|
+
):
|
|
24
30
|
"""Clean notebook and place a copy in the cleaned notebooks directory.
|
|
25
31
|
|
|
26
32
|
This can be useful to use as a preprocessing DVC stage to use a clean
|
|
27
33
|
notebook as a dependency for a stage that caches and executed notebook.
|
|
28
34
|
"""
|
|
29
35
|
if os.path.isabs(path):
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
36
|
+
raise_error("Path must be relative")
|
|
37
|
+
if not quiet:
|
|
38
|
+
typer.echo(f"Cleaning notebook: {path}")
|
|
39
|
+
try:
|
|
40
|
+
calkit.notebooks.clean_notebook_outputs(path)
|
|
41
|
+
except Exception as e:
|
|
42
|
+
raise_error(str(e))
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@notebooks_app.command("clean-all")
|
|
46
|
+
def clean_all_in_pipeline(
|
|
47
|
+
quiet: Annotated[
|
|
48
|
+
bool, typer.Option("--quiet", "-q", help="Do not print output.")
|
|
49
|
+
] = False,
|
|
50
|
+
):
|
|
51
|
+
"""Clean all notebooks in the pipeline."""
|
|
52
|
+
if not quiet:
|
|
53
|
+
typer.echo("Cleaning all notebooks in pipeline")
|
|
54
|
+
try:
|
|
55
|
+
cleaned = calkit.notebooks.clean_all_in_pipeline()
|
|
56
|
+
if not quiet:
|
|
57
|
+
for path in cleaned:
|
|
58
|
+
typer.echo(f"Cleaned: {path}")
|
|
59
|
+
except Exception as e:
|
|
60
|
+
raise_error(str(e))
|
|
49
61
|
|
|
50
62
|
|
|
51
63
|
def _parse_params(params: list[str]) -> dict[str, Any]:
|
|
@@ -379,7 +391,7 @@ def execute_notebook(
|
|
|
379
391
|
"--to",
|
|
380
392
|
to_fmt,
|
|
381
393
|
"--output-dir",
|
|
382
|
-
|
|
394
|
+
Path(folder).as_posix(),
|
|
383
395
|
"--output",
|
|
384
396
|
fname_out,
|
|
385
397
|
]
|