calkit-python 0.37.3__tar.gz → 0.37.5__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.37.3 → calkit_python-0.37.5}/PKG-INFO +1 -1
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/cli/check.py +19 -6
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/cli/main/core.py +8 -5
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/cli/new.py +2 -4
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/cli/notebooks.py +25 -6
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/conda.py +34 -12
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/fs.py +73 -25
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/tests/cli/test_check.py +36 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/tests/cli/test_new.py +1 -1
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/tests/test_conda.py +1 -1
- {calkit_python-0.37.3 → calkit_python-0.37.5}/.gitignore +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/.pre-commit-config.yaml +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/.prettierignore +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/.python-version +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/.vscode/launch.json +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/.vscode/tasks.json +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/.yarnrc.yml +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/CITATION.cff +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/CODE_OF_CONDUCT.md +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/CONTRIBUTING.md +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/LICENSE +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/Makefile +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/README.md +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/babel.config.js +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/__init__.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/__main__.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/calc.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/check.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/cli/__init__.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/cli/cloud.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/cli/config.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/cli/core.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/cli/describe.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/cli/import_.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/cli/latex.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/cli/list.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/cli/main/__init__.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/cli/main/xr.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/cli/office.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/cli/overleaf.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/cli/slurm.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/cli/update.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/cloud.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/config.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/core.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/datasets.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/detect.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/docker.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/dvc/__init__.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/dvc/core.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/dvc/zip.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/environments.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/git.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/github.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/gui.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/invenio.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/julia.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/jupyter.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/jupyterlab/__init__.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/jupyterlab/routes.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/labextension/package.json +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/labextension/schemas/calkit/package.json.orig +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/labextension/schemas/calkit/plugin.json +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/labextension/static/502.9a2c5772a15466e923ef.js +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/labextension/static/695.2c41003a452d43d2b358.js +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/labextension/static/867.a42a046aa5108f54f8fb.js +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/labextension/static/909.e3f9cc3408834a7fdcc3.js +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/labextension/static/946.050af2abf7845cfbdbd2.js +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/labextension/static/946.050af2abf7845cfbdbd2.js.LICENSE.txt +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/labextension/static/b2f1c3efe70cb539d121.png +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/labextension/static/remoteEntry.65469af996e7a96aa983.js +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/labextension/static/style.js +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/labextension/static/third-party-licenses.json +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/licenses.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/magics.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/matlab.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/models/__init__.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/models/core.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/models/io.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/models/iteration.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/models/pipeline.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/notebooks.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/office.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/ops.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/overleaf.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/pipeline.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/releases.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/server.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/templates/__init__.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/templates/core.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/templates/latex/__init__.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/templates/latex/article/paper.tex +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/templates/latex/core.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/templates/latex/jfm/jfm.bst +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/templates/latex/jfm/jfm.cls +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/templates/latex/jfm/lineno-FLM.sty +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/templates/latex/jfm/paper.tex +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/templates/latex/jfm/upmath.sty +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/tests/__init__.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/tests/cli/__init__.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/tests/cli/main/__init__.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/tests/cli/main/test_core.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/tests/cli/main/test_xr.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/tests/cli/test_config.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/tests/cli/test_import.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/tests/cli/test_latex.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/tests/cli/test_list.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/tests/cli/test_notebooks.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/tests/cli/test_overleaf.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/tests/cli/test_update.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/tests/dvc/__init__.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/tests/dvc/test_core.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/tests/dvc/test_zip.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/tests/jupyterlab/__init__.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/tests/jupyterlab/test_routes.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/tests/models/__init__.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/tests/models/test_iteration.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/tests/models/test_pipeline.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/tests/test_calc.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/tests/test_check.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/tests/test_core.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/tests/test_detect.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/tests/test_docker.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/tests/test_environments.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/tests/test_fs.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/tests/test_git.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/tests/test_invenio.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/tests/test_julia.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/tests/test_jupyter.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/tests/test_magics.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/tests/test_matlab.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/tests/test_notebooks.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/tests/test_pipeline.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/tests/test_releases.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/calkit/tests/test_templates.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/conftest.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/CNAME +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/apps.md +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/calculations.md +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/calkit-yaml.md +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/cli-reference.md +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/cloud-integration.md +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/datasets.md +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/dependencies.md +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/environments.md +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/examples.md +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/governance.md +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/help.md +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/img/c-to-the-k-white.svg +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/img/calkit-fragmentation-compendium.png +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/img/calkit-no-bg.png +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/img/connect-zenodo.png +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/img/jupyterlab/all-green.png +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/img/jupyterlab/collect-data-stale.png +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/img/jupyterlab/new-env.png +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/img/jupyterlab/new-notebook.png +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/img/jupyterlab/pipeline-badge.png +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/img/jupyterlab-params.png +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/img/plos-osi-code-2024-03.png +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/img/vscode-nb-params.png +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/index.md +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/installation.md +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/jupyterlab.md +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/local-server.md +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/notebooks.md +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/overleaf.md +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/pipeline/index.md +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/pipeline/manual-steps.md +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/pipeline/running-and-logging.md +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/pipeline/slurm.md +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/quickstart.md +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/references.md +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/releases.md +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/reproducibility.md +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/tutorials/adding-latex-pub-docker.md +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/tutorials/conda-envs.md +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/tutorials/existing-project.md +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/tutorials/first-project.md +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/tutorials/github-actions.md +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/tutorials/img/actions-repo-secrets.png +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/tutorials/img/latex-codespaces/building-codespace.png +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/tutorials/img/latex-codespaces/codespaces-secrets-2.png +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/tutorials/img/latex-codespaces/editor-split.png +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/tutorials/img/latex-codespaces/go-to-linked-code.png +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/tutorials/img/latex-codespaces/issue-from-selection.png +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/tutorials/img/latex-codespaces/new-project.png +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/tutorials/img/latex-codespaces/new-pub-2.png +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/tutorials/img/latex-codespaces/new-token.png +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/tutorials/img/latex-codespaces/paper.tex.png +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/tutorials/img/latex-codespaces/project-home-3.png +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/tutorials/img/latex-codespaces/push.png +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/tutorials/img/latex-codespaces/stage.png +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/tutorials/img/office/anakin-excel.jpg +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/tutorials/img/office/chart-more-rows.png +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/tutorials/img/office/create-project.png +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/tutorials/img/office/elsevier-research-data-guidelines.png +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/tutorials/img/office/excel-chart.png +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/tutorials/img/office/excel-data.png +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/tutorials/img/office/insert-link-to-file.png +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/tutorials/img/office/needs-clone.png +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/tutorials/img/office/new-stage.png +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/tutorials/img/office/phd-comics-version-control.webp +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/tutorials/img/office/pipeline-out-of-date.png +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/tutorials/img/office/status-more-rows.png +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/tutorials/img/office/uncommitted-changes.png +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/tutorials/img/office/untracked-data.png +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/tutorials/img/office/updated-publication.png +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/tutorials/img/office/word-to-pdf-stage-2.png +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/tutorials/img/office/workflow-page.png +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/tutorials/img/openfoam/clone.png +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/tutorials/img/openfoam/create-project.png +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/tutorials/img/openfoam/datasets-page.png +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/tutorials/img/openfoam/figure-on-website-updated.png +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/tutorials/img/openfoam/figure-on-website.png +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/tutorials/img/openfoam/new-token.png +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/tutorials/img/openfoam/reclone.png +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/tutorials/img/openfoam/status-after-import-dataset.png +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/tutorials/img/quick-actions.png +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/tutorials/img/run-proc.png +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/tutorials/img/vscode-slurm-notebook/create-calkit-env.png +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/tutorials/img/vscode-slurm-notebook/create-inner-env.png +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/tutorials/img/vscode-slurm-notebook/create-new-calkit-env.png +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/tutorials/img/vscode-slurm-notebook/select-calkit-env.png +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/tutorials/img/vscode-slurm-notebook/slurm-job-running.png +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/tutorials/img/vscode-slurm-notebook/slurm-launch-options.png +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/tutorials/img/vscode-slurm-notebook/starting-slurm-job.png +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/tutorials/index.md +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/tutorials/jupyterlab.md +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/tutorials/latex-codespaces.md +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/tutorials/matlab.md +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/tutorials/notebook-pipeline.md +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/tutorials/office.md +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/tutorials/openfoam.md +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/tutorials/procedures.md +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/tutorials/vscode-slurm-notebook.md +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/docs/version-control.md +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/install.json +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/jest.config.js +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/jupyter-config/server-config/calkit.json +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/mkdocs.yml +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/package.json +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/pyproject.toml +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/schema/plugin.json +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/scripts/generate-docs-references.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/scripts/install.ps1 +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/scripts/install.sh +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/scripts/make-calk9.sh +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/scripts/sync-docs.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/src/__tests__/useQueries.spec.ts +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/src/calkit-config.ts +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/src/cell-output-marker.ts +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/src/components/commit-dialog.tsx +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/src/components/environment-editor.tsx +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/src/components/notebook-registration.tsx +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/src/components/notebook-toolbar.tsx +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/src/components/pipeline-status-bar.tsx +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/src/components/project-info-editor.tsx +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/src/components/sidebar-settings.tsx +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/src/components/sidebar.tsx +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/src/components/stage-editor.tsx +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/src/feature-flags.ts +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/src/file-browser-menu.ts +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/src/hooks/__tests__/useQueries.test.tsx +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/src/hooks/useQueries.ts +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/src/icons.ts +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/src/index.ts +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/src/io-tracker.ts +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/src/pipeline-state.ts +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/src/queryClient.ts +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/src/request.ts +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/src/shims-mainmenu.d.ts +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/style/base.css +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/style/cell-output-marker.css +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/style/environment-editor.css +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/style/environment-selector.css +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/style/img/calkit-no-bg.png +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/style/index.css +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/style/index.js +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/style/notebook-toolbar.css +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/style/pipeline-status-bar.css +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/style/sidebar.css +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/test/dvc-md5-dir/osx-arm64.txt +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/test/nb-julia.ipynb +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/test/nb-params.ipynb +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/test/nb-subdir.ipynb +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/test/pipeline.ipynb +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/test/script.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/test/test-log.log +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/tsconfig.json +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/tsconfig.test.json +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/ui-tests/.gitignore +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/ui-tests/README.md +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/ui-tests/jupyter_server_test_config.py +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/ui-tests/package.json +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/ui-tests/playwright.config.js +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/ui-tests/tests/calkit.spec.ts +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/ui-tests/yarn.lock +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/uv.lock +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/vscode-ext/.gitignore +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/vscode-ext/.vscodeignore +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/vscode-ext/CHANGELOG.md +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/vscode-ext/LICENSE +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/vscode-ext/README.md +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/vscode-ext/images/calkit-no-bg.png +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/vscode-ext/package-lock.json +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/vscode-ext/package.json +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/vscode-ext/scripts/set-proposed-api.js +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/vscode-ext/src/environments.ts +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/vscode-ext/src/extension.ts +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/vscode-ext/src/notebooks.ts +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/vscode-ext/src/test/environments.test.ts +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/vscode-ext/src/test/notebooks.test.ts +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/vscode-ext/src/types.ts +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/vscode-ext/tsconfig.json +0 -0
- {calkit_python-0.37.3 → calkit_python-0.37.5}/yarn.lock +0 -0
|
@@ -876,15 +876,26 @@ def check_docker_env(
|
|
|
876
876
|
typer.echo(f"Found modified dependency: {dep}")
|
|
877
877
|
rebuild_or_pull = True
|
|
878
878
|
break
|
|
879
|
+
|
|
880
|
+
def delete_lock_on_failure() -> None:
|
|
881
|
+
if lock_fpath and os.path.exists(lock_fpath):
|
|
882
|
+
os.remove(lock_fpath)
|
|
883
|
+
|
|
879
884
|
if fpath is not None and rebuild_or_pull:
|
|
880
|
-
|
|
881
|
-
if not
|
|
882
|
-
|
|
883
|
-
cmd = ["docker", "build", "-t", tag, "-f",
|
|
885
|
+
dockerfile_dir, dockerfile_name = os.path.split(fpath)
|
|
886
|
+
if not dockerfile_dir:
|
|
887
|
+
dockerfile_dir = None
|
|
888
|
+
cmd = ["docker", "build", "-t", tag, "-f", dockerfile_name]
|
|
884
889
|
if platform is not None:
|
|
885
890
|
cmd += ["--platform", platform]
|
|
886
891
|
cmd.append(".")
|
|
887
|
-
|
|
892
|
+
try:
|
|
893
|
+
subprocess.check_output(cmd, cwd=dockerfile_dir)
|
|
894
|
+
except subprocess.CalledProcessError:
|
|
895
|
+
delete_lock_on_failure()
|
|
896
|
+
raise_error(
|
|
897
|
+
f"Failed to build Docker image with tag {tag} from {fpath}"
|
|
898
|
+
)
|
|
888
899
|
elif fpath is None and rebuild_or_pull:
|
|
889
900
|
# First try to pull by repo digest
|
|
890
901
|
pulled = False
|
|
@@ -901,6 +912,7 @@ def check_docker_env(
|
|
|
901
912
|
subprocess.check_output(tag_cmd)
|
|
902
913
|
pulled = True
|
|
903
914
|
except subprocess.CalledProcessError:
|
|
915
|
+
delete_lock_on_failure()
|
|
904
916
|
warn(
|
|
905
917
|
f"Failed to pull image by digest: {image_with_digest}; "
|
|
906
918
|
"falling back to pulling by tag"
|
|
@@ -912,6 +924,7 @@ def check_docker_env(
|
|
|
912
924
|
try:
|
|
913
925
|
subprocess.check_output(cmd)
|
|
914
926
|
except subprocess.CalledProcessError:
|
|
927
|
+
delete_lock_on_failure()
|
|
915
928
|
raise_error(f"Failed to pull image: {tag}")
|
|
916
929
|
# Write the lock file
|
|
917
930
|
inspect = get_docker_inspect()
|
|
@@ -993,7 +1006,7 @@ def check_conda_env(
|
|
|
993
1006
|
try:
|
|
994
1007
|
calkit.conda.check_env(
|
|
995
1008
|
env_fpath=env_fpath,
|
|
996
|
-
|
|
1009
|
+
lock_fpath=output_fpath,
|
|
997
1010
|
alt_lock_fpaths=alt_lock_fpaths,
|
|
998
1011
|
alt_lock_fpaths_delete=alt_lock_fpaths_delete,
|
|
999
1012
|
log_func=log_func,
|
|
@@ -958,10 +958,9 @@ def push(
|
|
|
958
958
|
):
|
|
959
959
|
"""Push with both Git and DVC."""
|
|
960
960
|
if not no_dvc:
|
|
961
|
-
|
|
961
|
+
remotes = calkit.dvc.get_remotes()
|
|
962
962
|
if not no_check_auth:
|
|
963
963
|
# Check that our dvc remotes all have our DVC token set for them
|
|
964
|
-
remotes = calkit.dvc.get_remotes()
|
|
965
964
|
ck_remote_name = calkit.config.get_app_name()
|
|
966
965
|
for name, url in remotes.items():
|
|
967
966
|
if (
|
|
@@ -972,9 +971,13 @@ def push(
|
|
|
972
971
|
f"Checking authentication for DVC remote: {name}"
|
|
973
972
|
)
|
|
974
973
|
calkit.dvc.set_remote_auth(remote_name=name)
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
974
|
+
if remotes:
|
|
975
|
+
typer.echo("Pushing to DVC remote")
|
|
976
|
+
result = run_dvc_command(["push"] + dvc_args)
|
|
977
|
+
if result != 0:
|
|
978
|
+
raise_error("DVC push failed")
|
|
979
|
+
else:
|
|
980
|
+
warn("No DVC remotes configured; skipping DVC push")
|
|
978
981
|
if not no_git:
|
|
979
982
|
typer.echo("Pushing to Git remote")
|
|
980
983
|
try:
|
|
@@ -1204,10 +1204,8 @@ def new_conda_env(
|
|
|
1204
1204
|
"(use -f to overwrite)"
|
|
1205
1205
|
)
|
|
1206
1206
|
if conda_name is None:
|
|
1207
|
-
project_name =
|
|
1208
|
-
|
|
1209
|
-
project_name = os.path.basename(os.getcwd())
|
|
1210
|
-
conda_name = calkit.to_kebab_case(project_name) + "-" + name
|
|
1207
|
+
project_name = calkit.detect_project_name(prepend_owner=False)
|
|
1208
|
+
conda_name = calkit.to_kebab_case(project_name) + "." + name
|
|
1211
1209
|
if packages is not None:
|
|
1212
1210
|
assert isinstance(packages, list)
|
|
1213
1211
|
# Write environment to path
|
|
@@ -5,6 +5,7 @@ from __future__ import annotations
|
|
|
5
5
|
import base64
|
|
6
6
|
import json
|
|
7
7
|
import os
|
|
8
|
+
import re
|
|
8
9
|
import subprocess
|
|
9
10
|
import sys
|
|
10
11
|
from pathlib import Path
|
|
@@ -122,6 +123,17 @@ def _check_ijulia_available(
|
|
|
122
123
|
return res.returncode == 0
|
|
123
124
|
|
|
124
125
|
|
|
126
|
+
def _sanitize_kernel_name_component(name: str, label: str) -> str:
|
|
127
|
+
"""Keep readable names while removing kernelspec-unfriendly characters."""
|
|
128
|
+
sanitized = re.sub(r"[^A-Za-z0-9._-]+", "-", name).strip("._-")
|
|
129
|
+
if not sanitized:
|
|
130
|
+
raise_error(
|
|
131
|
+
f"{label} cannot be empty after sanitizing for kernel name"
|
|
132
|
+
)
|
|
133
|
+
return "" # For typing analysis since raise_error exits
|
|
134
|
+
return sanitized
|
|
135
|
+
|
|
136
|
+
|
|
125
137
|
@notebooks_app.command("check-kernel")
|
|
126
138
|
def check_env_kernel(
|
|
127
139
|
env_name: Annotated[
|
|
@@ -191,8 +203,14 @@ def check_env_kernel(
|
|
|
191
203
|
project_name = calkit.detect_project_name(prepend_owner=False)
|
|
192
204
|
if not project_name:
|
|
193
205
|
raise_error("Project name cannot be empty")
|
|
194
|
-
kernel_name =
|
|
206
|
+
kernel_name = (
|
|
207
|
+
f"{_sanitize_kernel_name_component(project_name, 'Project name')}"
|
|
208
|
+
f".{_sanitize_kernel_name_component(env_name, 'Environment name')}"
|
|
209
|
+
)
|
|
195
210
|
display_name = f"{project_name}: {env_name}"
|
|
211
|
+
if verbose and not json_output:
|
|
212
|
+
typer.echo(f"Using kernel name: {kernel_name}")
|
|
213
|
+
typer.echo(f"Using display name: {display_name}")
|
|
196
214
|
if language == "python":
|
|
197
215
|
cmd = [
|
|
198
216
|
"python",
|
|
@@ -295,9 +313,10 @@ def check_env_kernel(
|
|
|
295
313
|
julia_cmd = (
|
|
296
314
|
"import IJulia;"
|
|
297
315
|
"kp=IJulia.installkernel("
|
|
298
|
-
f'"{
|
|
316
|
+
f'"{kernel_name}",'
|
|
299
317
|
f'"--project={env_dir_abs}",'
|
|
300
318
|
'"--startup-file=no",'
|
|
319
|
+
f'displayname="{display_name}",'
|
|
301
320
|
'env=Dict("JULIA_LOAD_PATH" => "@:@stdlib")'
|
|
302
321
|
");"
|
|
303
322
|
"println(kp);"
|
|
@@ -316,7 +335,7 @@ def check_env_kernel(
|
|
|
316
335
|
cmd = calkit.julia.ensure_startup_file_disabled_in_command(cmd)
|
|
317
336
|
res = subprocess.run(cmd, capture_output=True, text=True)
|
|
318
337
|
if res.returncode != 0:
|
|
319
|
-
raise_error(f"Failed to create kernel:\n{res.
|
|
338
|
+
raise_error(f"Failed to create kernel:\n{res.stderr}")
|
|
320
339
|
kernel_path = res.stdout.strip()
|
|
321
340
|
kernel_name = os.path.basename(kernel_path)
|
|
322
341
|
# Update display_name to include version for matching in VS Code
|
|
@@ -567,9 +586,9 @@ def execute_notebook(
|
|
|
567
586
|
run_in_env(cmd, env_name=env_name, no_check=no_check, verbose=verbose)
|
|
568
587
|
if not no_replace:
|
|
569
588
|
# Replace original notebook outputs with those from executed version
|
|
570
|
-
with open(fpath_out_exec, "r") as f:
|
|
589
|
+
with open(fpath_out_exec, "r", encoding="utf-8") as f:
|
|
571
590
|
executed_nb = json.load(f)
|
|
572
|
-
with open(path, "r") as f:
|
|
591
|
+
with open(path, "r", encoding="utf-8") as f:
|
|
573
592
|
original_nb = json.load(f)
|
|
574
593
|
for orig_cell, exec_cell in zip(
|
|
575
594
|
original_nb.get("cells", []), executed_nb.get("cells", [])
|
|
@@ -581,7 +600,7 @@ def execute_notebook(
|
|
|
581
600
|
and "execution_count" in exec_cell
|
|
582
601
|
):
|
|
583
602
|
orig_cell["execution_count"] = exec_cell["execution_count"]
|
|
584
|
-
with open(path, "w") as f:
|
|
603
|
+
with open(path, "w", encoding="utf-8") as f:
|
|
585
604
|
json.dump(original_nb, f, indent=1)
|
|
586
605
|
for to_fmt in to:
|
|
587
606
|
if to_fmt != "notebook":
|
|
@@ -262,7 +262,7 @@ class EnvCheckResult(BaseModel):
|
|
|
262
262
|
def check_env(
|
|
263
263
|
env_fpath: str = "environment.yml",
|
|
264
264
|
log_func=None,
|
|
265
|
-
|
|
265
|
+
lock_fpath: str | None = None,
|
|
266
266
|
alt_lock_fpaths: list[str] = [],
|
|
267
267
|
alt_lock_fpaths_delete: list[str] = [],
|
|
268
268
|
relaxed: bool = False,
|
|
@@ -284,7 +284,7 @@ def check_env(
|
|
|
284
284
|
# Determine which lock file to use for creating the environment
|
|
285
285
|
lock_to_use_for_creation = None
|
|
286
286
|
used_legacy_lock = None
|
|
287
|
-
if
|
|
287
|
+
if lock_fpath and not os.path.isfile(lock_fpath):
|
|
288
288
|
# Try alternative lock files first
|
|
289
289
|
for alt_fpath in alt_lock_fpaths:
|
|
290
290
|
if os.path.isfile(alt_fpath):
|
|
@@ -302,9 +302,31 @@ def check_env(
|
|
|
302
302
|
f"Using legacy lock file for creation: {legacy_fpath}"
|
|
303
303
|
)
|
|
304
304
|
break
|
|
305
|
-
elif
|
|
306
|
-
lock_to_use_for_creation =
|
|
307
|
-
log_func(f"Using existing lock file for creation: {
|
|
305
|
+
elif lock_fpath and os.path.isfile(lock_fpath):
|
|
306
|
+
lock_to_use_for_creation = lock_fpath
|
|
307
|
+
log_func(f"Using existing lock file for creation: {lock_fpath}")
|
|
308
|
+
# Make sure the lock file has the correct env name in it
|
|
309
|
+
if lock_to_use_for_creation:
|
|
310
|
+
with open(lock_to_use_for_creation) as f:
|
|
311
|
+
lock_spec = ryaml.load(f)
|
|
312
|
+
lock_env_name = lock_spec.get("name")
|
|
313
|
+
if lock_env_name is not None:
|
|
314
|
+
with open(env_fpath) as f:
|
|
315
|
+
env_spec = ryaml.load(f)
|
|
316
|
+
env_spec_env_name = env_spec.get("name")
|
|
317
|
+
if (
|
|
318
|
+
env_spec_env_name is not None
|
|
319
|
+
and lock_env_name != env_spec_env_name
|
|
320
|
+
):
|
|
321
|
+
log_func(
|
|
322
|
+
f"Lock file {lock_to_use_for_creation} has env name "
|
|
323
|
+
f"{lock_env_name}, which does not match env spec "
|
|
324
|
+
f"name {env_spec_env_name}; deleting mismatched lock file "
|
|
325
|
+
"and ignoring it for creation"
|
|
326
|
+
)
|
|
327
|
+
if os.path.isfile(lock_to_use_for_creation):
|
|
328
|
+
os.remove(lock_to_use_for_creation)
|
|
329
|
+
lock_to_use_for_creation = None
|
|
308
330
|
res = EnvCheckResult()
|
|
309
331
|
if verbose:
|
|
310
332
|
log_func("Getting conda info")
|
|
@@ -538,15 +560,15 @@ def check_env(
|
|
|
538
560
|
)
|
|
539
561
|
with open(env_check_fpath, "w") as f:
|
|
540
562
|
ryaml.dump(env_check, f)
|
|
541
|
-
if
|
|
563
|
+
if lock_fpath is None:
|
|
542
564
|
fname, ext = os.path.splitext(env_fpath)
|
|
543
|
-
|
|
565
|
+
lock_fpath = fname + "-lock" + ext
|
|
544
566
|
if (
|
|
545
567
|
not res.env_exists
|
|
546
568
|
or res.env_needs_rebuild
|
|
547
|
-
or not os.path.isfile(
|
|
569
|
+
or not os.path.isfile(lock_fpath)
|
|
548
570
|
):
|
|
549
|
-
log_func(f"Exporting lock file to {
|
|
571
|
+
log_func(f"Exporting lock file to {lock_fpath}")
|
|
550
572
|
env_export = json.loads(
|
|
551
573
|
subprocess.check_output(
|
|
552
574
|
[a for a in export_cmd if a != "--no-builds"]
|
|
@@ -584,16 +606,16 @@ def check_env(
|
|
|
584
606
|
dep_name = re.split("[=<>]+", dep, maxsplit=1)[0]
|
|
585
607
|
if dep_name in editable_pip_deps:
|
|
586
608
|
path_rel_to_project_root = editable_pip_deps[dep_name]
|
|
587
|
-
lock_dir = os.path.dirname(
|
|
609
|
+
lock_dir = os.path.dirname(lock_fpath)
|
|
588
610
|
path_rel_to_lock = os.path.relpath(
|
|
589
611
|
path_rel_to_project_root, start=lock_dir
|
|
590
612
|
)
|
|
591
613
|
export_pip_deps[i] = (
|
|
592
614
|
"-e " + Path(path_rel_to_lock).as_posix()
|
|
593
615
|
)
|
|
594
|
-
out_dir = os.path.dirname(
|
|
616
|
+
out_dir = os.path.dirname(lock_fpath)
|
|
595
617
|
if out_dir:
|
|
596
618
|
os.makedirs(out_dir, exist_ok=True)
|
|
597
|
-
with open(
|
|
619
|
+
with open(lock_fpath, "w") as f:
|
|
598
620
|
ryaml.dump(env_export, f)
|
|
599
621
|
return res
|
|
@@ -298,10 +298,45 @@ class CalkitFileSystem(AbstractFileSystem):
|
|
|
298
298
|
operation_info: dict[str, Any],
|
|
299
299
|
operation: str,
|
|
300
300
|
data: bytes | None = None,
|
|
301
|
+
file_obj: Any = None,
|
|
302
|
+
file_size: int | None = None,
|
|
301
303
|
headers: dict | None = None,
|
|
302
304
|
callback=DEFAULT_CALLBACK,
|
|
303
305
|
) -> requests.Response:
|
|
304
|
-
"""Execute a file operation using the provided operation info.
|
|
306
|
+
"""Execute a file operation using the provided operation info.
|
|
307
|
+
|
|
308
|
+
Exactly one of ``data`` or ``file_obj`` should be provided for put
|
|
309
|
+
operations. When ``file_obj`` is given it must be a seekable binary
|
|
310
|
+
file-like object and ``file_size`` must be set; part/chunk bodies are
|
|
311
|
+
streamed from it instead of being held in memory, which keeps memory
|
|
312
|
+
bounded for large uploads.
|
|
313
|
+
"""
|
|
314
|
+
if data is not None and file_obj is not None:
|
|
315
|
+
raise ValueError("Provide data or file_obj, not both")
|
|
316
|
+
if file_obj is not None:
|
|
317
|
+
if not callable(getattr(file_obj, "seek", None)):
|
|
318
|
+
raise TypeError(
|
|
319
|
+
"file_obj must be a seekable binary file-like object"
|
|
320
|
+
)
|
|
321
|
+
if file_size is None:
|
|
322
|
+
raise ValueError(
|
|
323
|
+
"file_size must be provided when file_obj is given"
|
|
324
|
+
)
|
|
325
|
+
# Total payload size for progress reporting.
|
|
326
|
+
payload_size = len(data) if data is not None else (file_size or 0)
|
|
327
|
+
|
|
328
|
+
def _prepare_stream(request_headers: dict) -> Any:
|
|
329
|
+
"""Return the request body, setting Content-Length if streaming."""
|
|
330
|
+
if data is not None:
|
|
331
|
+
return data
|
|
332
|
+
if file_obj is None:
|
|
333
|
+
return None
|
|
334
|
+
file_obj.seek(0)
|
|
335
|
+
# Explicit Content-Length avoids chunked transfer-encoding, which
|
|
336
|
+
# presigned URL signatures typically reject.
|
|
337
|
+
request_headers.setdefault("Content-Length", str(file_size))
|
|
338
|
+
return file_obj
|
|
339
|
+
|
|
305
340
|
# Extract access info from the operation info
|
|
306
341
|
access = operation_info.get("access")
|
|
307
342
|
if not access:
|
|
@@ -322,16 +357,17 @@ class CalkitFileSystem(AbstractFileSystem):
|
|
|
322
357
|
if headers:
|
|
323
358
|
request_headers.update(headers)
|
|
324
359
|
params = access.get("params")
|
|
360
|
+
body: Any = _prepare_stream(request_headers)
|
|
325
361
|
resp = self._session.request(
|
|
326
362
|
method=http_method.upper(),
|
|
327
363
|
url=url,
|
|
328
364
|
headers=request_headers,
|
|
329
365
|
params=params,
|
|
330
|
-
data=
|
|
366
|
+
data=body,
|
|
331
367
|
timeout=120,
|
|
332
368
|
)
|
|
333
|
-
if
|
|
334
|
-
callback.relative_update(
|
|
369
|
+
if operation == "put" and payload_size:
|
|
370
|
+
callback.relative_update(payload_size)
|
|
335
371
|
return resp
|
|
336
372
|
elif kind == "http-request":
|
|
337
373
|
# Generic HTTP request with custom headers
|
|
@@ -345,20 +381,21 @@ class CalkitFileSystem(AbstractFileSystem):
|
|
|
345
381
|
if headers:
|
|
346
382
|
request_headers.update(headers)
|
|
347
383
|
params = access.get("params")
|
|
384
|
+
body = _prepare_stream(request_headers)
|
|
348
385
|
resp = self._session.request(
|
|
349
386
|
method=http_method.upper(),
|
|
350
387
|
url=url,
|
|
351
388
|
headers=request_headers,
|
|
352
389
|
params=params,
|
|
353
|
-
data=
|
|
390
|
+
data=body,
|
|
354
391
|
timeout=120,
|
|
355
392
|
)
|
|
356
|
-
if
|
|
357
|
-
callback.relative_update(
|
|
393
|
+
if operation == "put" and payload_size:
|
|
394
|
+
callback.relative_update(payload_size)
|
|
358
395
|
return resp
|
|
359
396
|
elif kind == "presigned-multipart":
|
|
360
397
|
# S3 multipart upload using server-provided part URLs
|
|
361
|
-
if data is None:
|
|
398
|
+
if data is None and file_obj is None:
|
|
362
399
|
raise ValueError("Data required for multipart upload")
|
|
363
400
|
upload_id = access.get("upload_id")
|
|
364
401
|
part_urls = access.get("part_urls")
|
|
@@ -382,7 +419,8 @@ class CalkitFileSystem(AbstractFileSystem):
|
|
|
382
419
|
"presigned-multipart"
|
|
383
420
|
)
|
|
384
421
|
content_type = access.get("content_type")
|
|
385
|
-
|
|
422
|
+
total_bytes = len(data) if data is not None else int(file_size)
|
|
423
|
+
total_parts_needed = (total_bytes + part_size - 1) // part_size
|
|
386
424
|
if total_parts_needed > len(part_urls):
|
|
387
425
|
raise ValueError(
|
|
388
426
|
"Insufficient part URLs for multipart upload "
|
|
@@ -391,8 +429,12 @@ class CalkitFileSystem(AbstractFileSystem):
|
|
|
391
429
|
uploaded_parts: list[tuple[int, str]] = []
|
|
392
430
|
for part_num in range(1, total_parts_needed + 1):
|
|
393
431
|
start = (part_num - 1) * part_size
|
|
394
|
-
end = min(start + part_size,
|
|
395
|
-
|
|
432
|
+
end = min(start + part_size, total_bytes)
|
|
433
|
+
if data is not None:
|
|
434
|
+
part_data = data[start:end]
|
|
435
|
+
else:
|
|
436
|
+
file_obj.seek(start)
|
|
437
|
+
part_data = file_obj.read(end - start)
|
|
396
438
|
part_url = part_urls[part_num - 1]
|
|
397
439
|
part_headers = {}
|
|
398
440
|
if content_type:
|
|
@@ -429,7 +471,7 @@ class CalkitFileSystem(AbstractFileSystem):
|
|
|
429
471
|
return complete_resp
|
|
430
472
|
elif kind == "presigned-chunked":
|
|
431
473
|
# GCS resumable upload - requires multiple requests
|
|
432
|
-
if data is None:
|
|
474
|
+
if data is None and file_obj is None:
|
|
433
475
|
raise ValueError("Data required for chunked upload")
|
|
434
476
|
init_url = access.get("init_url")
|
|
435
477
|
if not init_url:
|
|
@@ -477,7 +519,7 @@ class CalkitFileSystem(AbstractFileSystem):
|
|
|
477
519
|
pass
|
|
478
520
|
|
|
479
521
|
# Step 2: Upload data in chunks
|
|
480
|
-
total_size = len(data)
|
|
522
|
+
total_size = len(data) if data is not None else int(file_size)
|
|
481
523
|
offset = 0
|
|
482
524
|
chunk_headers_base = dict(
|
|
483
525
|
access.get("chunk_headers") or access.get("headers") or {}
|
|
@@ -510,7 +552,11 @@ class CalkitFileSystem(AbstractFileSystem):
|
|
|
510
552
|
try:
|
|
511
553
|
while offset < total_size:
|
|
512
554
|
chunk_end = min(offset + chunk_size, total_size)
|
|
513
|
-
|
|
555
|
+
if data is not None:
|
|
556
|
+
chunk_data = data[offset:chunk_end]
|
|
557
|
+
else:
|
|
558
|
+
file_obj.seek(offset)
|
|
559
|
+
chunk_data = file_obj.read(chunk_end - offset)
|
|
514
560
|
# Set Content-Range header for the chunk
|
|
515
561
|
chunk_headers = {
|
|
516
562
|
**chunk_headers_base,
|
|
@@ -915,12 +961,9 @@ class CalkitFileSystem(AbstractFileSystem):
|
|
|
915
961
|
if os.path.isdir(lpath):
|
|
916
962
|
self.makedirs(rpath, exist_ok=True)
|
|
917
963
|
return None
|
|
918
|
-
with open(lpath, "rb") as f:
|
|
919
|
-
size = f.seek(0, 2)
|
|
920
|
-
callback.set_size(size)
|
|
921
|
-
f.seek(0)
|
|
922
|
-
data = f.read()
|
|
923
964
|
owner, project, file_path = _parse_path(rpath)
|
|
965
|
+
size = os.path.getsize(lpath)
|
|
966
|
+
callback.set_size(size)
|
|
924
967
|
operation_info = self._get_fs_op_info(
|
|
925
968
|
owner,
|
|
926
969
|
project,
|
|
@@ -928,12 +971,17 @@ class CalkitFileSystem(AbstractFileSystem):
|
|
|
928
971
|
"put",
|
|
929
972
|
content_length=size,
|
|
930
973
|
)
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
974
|
+
# Stream the file from disk rather than loading it into memory. This
|
|
975
|
+
# keeps RAM bounded when DVC pushes many (or very large) files in
|
|
976
|
+
# parallel via its worker pool.
|
|
977
|
+
with open(lpath, "rb") as f:
|
|
978
|
+
resp = self._execute_operation(
|
|
979
|
+
operation_info,
|
|
980
|
+
"put",
|
|
981
|
+
file_obj=f,
|
|
982
|
+
file_size=size,
|
|
983
|
+
callback=callback,
|
|
984
|
+
)
|
|
937
985
|
resp.raise_for_status()
|
|
938
986
|
|
|
939
987
|
|
|
@@ -122,3 +122,39 @@ def test_check_julia_env_caches_second_run(tmp_dir):
|
|
|
122
122
|
check=True,
|
|
123
123
|
)
|
|
124
124
|
assert "skipping Pkg.instantiate" not in result3.stdout
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def test_check_docker_env(tmp_dir):
|
|
128
|
+
# First create a Dockerfile with a known base image
|
|
129
|
+
with open("Dockerfile", "w") as f:
|
|
130
|
+
f.write("FROM python:3.9-slim\n")
|
|
131
|
+
# Now check the environment
|
|
132
|
+
subprocess.check_call(
|
|
133
|
+
[
|
|
134
|
+
"calkit",
|
|
135
|
+
"check",
|
|
136
|
+
"docker-env",
|
|
137
|
+
"python-3.9-slim",
|
|
138
|
+
"-i",
|
|
139
|
+
"Dockerfile",
|
|
140
|
+
"-o",
|
|
141
|
+
"Dockerfile-lock.json",
|
|
142
|
+
]
|
|
143
|
+
)
|
|
144
|
+
# Now modify the image to fail to build and ensure the lock file is deleted
|
|
145
|
+
with open("Dockerfile", "w") as f:
|
|
146
|
+
f.write("FROM non-existent-image:latest\n")
|
|
147
|
+
with pytest.raises(subprocess.CalledProcessError):
|
|
148
|
+
subprocess.check_call(
|
|
149
|
+
[
|
|
150
|
+
"calkit",
|
|
151
|
+
"check",
|
|
152
|
+
"docker-env",
|
|
153
|
+
"python-3.9-slim",
|
|
154
|
+
"-i",
|
|
155
|
+
"Dockerfile",
|
|
156
|
+
"-o",
|
|
157
|
+
"Dockerfile-lock.json",
|
|
158
|
+
]
|
|
159
|
+
)
|
|
160
|
+
assert not os.path.exists("Dockerfile-lock.json")
|
|
@@ -69,7 +69,7 @@ def delete_env(name: str):
|
|
|
69
69
|
|
|
70
70
|
@pytest.fixture
|
|
71
71
|
def conda_env_name():
|
|
72
|
-
name = calkit.to_kebab_case(os.path.basename(os.getcwd())) + "
|
|
72
|
+
name = calkit.to_kebab_case(os.path.basename(os.getcwd())) + "." + ENV_NAME
|
|
73
73
|
yield name
|
|
74
74
|
# Teardown code
|
|
75
75
|
delete_env(name)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|