calkit-python 0.35.5__tar.gz → 0.35.6__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.35.5 → calkit_python-0.35.6}/PKG-INFO +1 -1
- calkit_python-0.35.6/calkit/git.py +297 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/pipeline.py +5 -15
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/tests/test_git.py +59 -10
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/tests/test_pipeline.py +58 -5
- calkit_python-0.35.5/calkit/git.py +0 -197
- {calkit_python-0.35.5 → calkit_python-0.35.6}/.gitignore +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/.pre-commit-config.yaml +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/.prettierignore +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/.python-version +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/.yarnrc.yml +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/CITATION.cff +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/CODE_OF_CONDUCT.md +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/CONTRIBUTING.md +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/LICENSE +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/Makefile +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/README.md +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/babel.config.js +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/__init__.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/__main__.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/calc.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/check.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/cli/__init__.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/cli/check.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/cli/cloud.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/cli/config.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/cli/core.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/cli/describe.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/cli/import_.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/cli/latex.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/cli/list.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/cli/main/__init__.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/cli/main/core.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/cli/main/xr.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/cli/new.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/cli/notebooks.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/cli/office.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/cli/overleaf.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/cli/slurm.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/cli/update.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/cloud.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/conda.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/config.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/core.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/datasets.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/detect.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/docker.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/dvc.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/environments.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/fs.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/github.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/gui.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/invenio.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/julia.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/jupyter.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/jupyterlab/__init__.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/jupyterlab/routes.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/labextension/package.json +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/labextension/schemas/calkit/package.json.orig +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/labextension/schemas/calkit/plugin.json +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/labextension/static/502.9a2c5772a15466e923ef.js +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/labextension/static/695.2c41003a452d43d2b358.js +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/labextension/static/867.a42a046aa5108f54f8fb.js +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/labextension/static/909.651be47ca47390b78a92.js +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/labextension/static/946.050af2abf7845cfbdbd2.js +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/labextension/static/946.050af2abf7845cfbdbd2.js.LICENSE.txt +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/labextension/static/b2f1c3efe70cb539d121.png +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/labextension/static/remoteEntry.c091821b3d7f2d287a67.js +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/labextension/static/style.js +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/labextension/static/third-party-licenses.json +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/licenses.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/magics.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/matlab.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/models/__init__.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/models/core.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/models/io.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/models/iteration.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/models/pipeline.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/notebooks.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/office.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/ops.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/overleaf.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/releases.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/server.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/templates/__init__.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/templates/core.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/templates/latex/__init__.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/templates/latex/article/paper.tex +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/templates/latex/core.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/templates/latex/jfm/jfm.bst +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/templates/latex/jfm/jfm.cls +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/templates/latex/jfm/lineno-FLM.sty +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/templates/latex/jfm/paper.tex +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/templates/latex/jfm/upmath.sty +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/tests/__init__.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/tests/cli/__init__.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/tests/cli/main/__init__.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/tests/cli/main/test_core.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/tests/cli/main/test_xr.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/tests/cli/test_check.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/tests/cli/test_config.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/tests/cli/test_import.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/tests/cli/test_latex.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/tests/cli/test_list.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/tests/cli/test_new.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/tests/cli/test_notebooks.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/tests/cli/test_overleaf.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/tests/jupyterlab/__init__.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/tests/jupyterlab/test_routes.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/tests/models/__init__.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/tests/models/test_iteration.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/tests/models/test_pipeline.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/tests/test_calc.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/tests/test_check.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/tests/test_conda.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/tests/test_core.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/tests/test_detect.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/tests/test_docker.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/tests/test_dvc.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/tests/test_environments.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/tests/test_fs.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/tests/test_invenio.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/tests/test_julia.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/tests/test_jupyter.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/tests/test_magics.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/tests/test_matlab.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/tests/test_notebooks.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/tests/test_releases.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/calkit/tests/test_templates.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/conftest.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/CNAME +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/apps.md +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/calculations.md +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/calkit-yaml.md +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/cli-reference.md +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/cloud-integration.md +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/datasets.md +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/dependencies.md +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/environments.md +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/examples.md +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/governance.md +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/help.md +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/img/c-to-the-k-white.svg +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/img/calkit-fragmentation-compendium.png +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/img/calkit-no-bg.png +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/img/connect-zenodo.png +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/img/jupyterlab/all-green.png +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/img/jupyterlab/collect-data-stale.png +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/img/jupyterlab/new-env.png +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/img/jupyterlab/new-notebook.png +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/img/jupyterlab/pipeline-badge.png +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/img/jupyterlab-params.png +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/img/plos-osi-code-2024-03.png +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/img/vscode-nb-params.png +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/index.md +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/installation.md +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/jupyterlab.md +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/local-server.md +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/notebooks.md +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/overleaf.md +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/pipeline/index.md +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/pipeline/manual-steps.md +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/pipeline/running-and-logging.md +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/pipeline/slurm.md +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/quickstart.md +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/references.md +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/releases.md +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/reproducibility.md +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/tutorials/adding-latex-pub-docker.md +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/tutorials/conda-envs.md +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/tutorials/existing-project.md +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/tutorials/first-project.md +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/tutorials/github-actions.md +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/tutorials/img/actions-repo-secrets.png +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/tutorials/img/latex-codespaces/building-codespace.png +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/tutorials/img/latex-codespaces/codespaces-secrets-2.png +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/tutorials/img/latex-codespaces/editor-split.png +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/tutorials/img/latex-codespaces/go-to-linked-code.png +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/tutorials/img/latex-codespaces/issue-from-selection.png +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/tutorials/img/latex-codespaces/new-project.png +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/tutorials/img/latex-codespaces/new-pub-2.png +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/tutorials/img/latex-codespaces/new-token.png +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/tutorials/img/latex-codespaces/paper.tex.png +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/tutorials/img/latex-codespaces/project-home-3.png +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/tutorials/img/latex-codespaces/push.png +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/tutorials/img/latex-codespaces/stage.png +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/tutorials/img/office/anakin-excel.jpg +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/tutorials/img/office/chart-more-rows.png +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/tutorials/img/office/create-project.png +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/tutorials/img/office/elsevier-research-data-guidelines.png +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/tutorials/img/office/excel-chart.png +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/tutorials/img/office/excel-data.png +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/tutorials/img/office/insert-link-to-file.png +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/tutorials/img/office/needs-clone.png +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/tutorials/img/office/new-stage.png +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/tutorials/img/office/phd-comics-version-control.webp +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/tutorials/img/office/pipeline-out-of-date.png +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/tutorials/img/office/status-more-rows.png +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/tutorials/img/office/uncommitted-changes.png +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/tutorials/img/office/untracked-data.png +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/tutorials/img/office/updated-publication.png +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/tutorials/img/office/word-to-pdf-stage-2.png +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/tutorials/img/office/workflow-page.png +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/tutorials/img/openfoam/clone.png +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/tutorials/img/openfoam/create-project.png +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/tutorials/img/openfoam/datasets-page.png +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/tutorials/img/openfoam/figure-on-website-updated.png +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/tutorials/img/openfoam/figure-on-website.png +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/tutorials/img/openfoam/new-token.png +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/tutorials/img/openfoam/reclone.png +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/tutorials/img/openfoam/status-after-import-dataset.png +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/tutorials/img/quick-actions.png +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/tutorials/img/run-proc.png +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/tutorials/index.md +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/tutorials/jupyterlab.md +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/tutorials/latex-codespaces.md +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/tutorials/matlab.md +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/tutorials/notebook-pipeline.md +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/tutorials/office.md +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/tutorials/openfoam.md +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/tutorials/procedures.md +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/docs/version-control.md +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/install.json +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/jest.config.js +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/jupyter-config/server-config/calkit.json +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/mkdocs.yml +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/package.json +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/pyproject.toml +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/schema/plugin.json +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/scripts/generate-cli-reference.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/scripts/install.ps1 +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/scripts/install.sh +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/scripts/make-calk9.sh +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/scripts/sync-docs.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/src/__tests__/useQueries.spec.ts +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/src/calkit-config.ts +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/src/cell-output-marker.ts +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/src/components/commit-dialog.tsx +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/src/components/environment-editor.tsx +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/src/components/notebook-registration.tsx +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/src/components/notebook-toolbar.tsx +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/src/components/pipeline-status-bar.tsx +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/src/components/project-info-editor.tsx +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/src/components/sidebar-settings.tsx +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/src/components/sidebar.tsx +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/src/components/stage-editor.tsx +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/src/feature-flags.ts +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/src/file-browser-menu.ts +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/src/hooks/__tests__/useQueries.test.tsx +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/src/hooks/useQueries.ts +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/src/icons.ts +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/src/index.ts +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/src/io-tracker.ts +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/src/pipeline-state.ts +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/src/queryClient.ts +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/src/request.ts +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/src/shims-mainmenu.d.ts +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/style/base.css +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/style/cell-output-marker.css +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/style/environment-editor.css +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/style/environment-selector.css +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/style/img/calkit-no-bg.png +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/style/index.css +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/style/index.js +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/style/notebook-toolbar.css +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/style/pipeline-status-bar.css +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/style/sidebar.css +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/test/dvc-md5-dir/osx-arm64.txt +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/test/nb-julia.ipynb +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/test/nb-params.ipynb +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/test/nb-subdir.ipynb +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/test/pipeline.ipynb +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/test/script.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/test/test-log.log +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/tsconfig.json +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/tsconfig.test.json +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/ui-tests/.gitignore +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/ui-tests/README.md +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/ui-tests/jupyter_server_test_config.py +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/ui-tests/package.json +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/ui-tests/playwright.config.js +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/ui-tests/tests/calkit.spec.ts +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/ui-tests/yarn.lock +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/uv.lock +0 -0
- {calkit_python-0.35.5 → calkit_python-0.35.6}/yarn.lock +0 -0
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
"""Git-related functionality."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
from os import PathLike
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
import git
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def get_staged_files(
|
|
13
|
+
path: str | None = None, repo: git.Repo | None = None
|
|
14
|
+
) -> list[str]:
|
|
15
|
+
"""Get a list of staged files for the repo at ``path`` or the provided
|
|
16
|
+
repo.
|
|
17
|
+
"""
|
|
18
|
+
if repo is None:
|
|
19
|
+
repo = git.Repo(path)
|
|
20
|
+
cmd = ["--staged", "--name-only"]
|
|
21
|
+
if path is not None:
|
|
22
|
+
cmd.append(path)
|
|
23
|
+
diff = repo.git.diff(cmd)
|
|
24
|
+
paths = diff.split("\n")
|
|
25
|
+
return [p for p in paths if p]
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def get_changed_files(
|
|
29
|
+
path: str | None = None, repo: git.Repo | None = None
|
|
30
|
+
) -> list[str]:
|
|
31
|
+
"""Get a list of files that have been changed but not staged."""
|
|
32
|
+
if repo is None:
|
|
33
|
+
repo = git.Repo(path)
|
|
34
|
+
return [
|
|
35
|
+
item.a_path
|
|
36
|
+
for item in repo.index.diff(None)
|
|
37
|
+
if item.a_path is not None
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def get_untracked_files(
|
|
42
|
+
path: str | None = None, repo: git.Repo | None = None
|
|
43
|
+
) -> list[str]:
|
|
44
|
+
"""Get a list of untracked files."""
|
|
45
|
+
if repo is None:
|
|
46
|
+
repo = git.Repo(path)
|
|
47
|
+
return repo.untracked_files
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def get_staged_files_with_status(
|
|
51
|
+
path: str | None = None, repo: git.Repo | None = None
|
|
52
|
+
) -> list[dict]:
|
|
53
|
+
if repo is None:
|
|
54
|
+
repo = git.Repo(path)
|
|
55
|
+
cmd = ["--staged", "--name-status"]
|
|
56
|
+
if path is not None:
|
|
57
|
+
cmd.append(path)
|
|
58
|
+
diff = repo.git.diff(cmd)
|
|
59
|
+
paths = diff.split("\n")
|
|
60
|
+
res = []
|
|
61
|
+
for pathi in paths:
|
|
62
|
+
# Make sure line is not empty, e.g., a trailing newline
|
|
63
|
+
if pathi:
|
|
64
|
+
status, p = pathi.split("\t")
|
|
65
|
+
res.append({"status": status, "path": p})
|
|
66
|
+
return res
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def ls_files(repo: git.Repo, *args, **kwargs) -> list[str]:
|
|
70
|
+
"""Get a list of all files tracked by git."""
|
|
71
|
+
output = repo.git.ls_files(*args, **kwargs)
|
|
72
|
+
return [f for f in output.split("\n") if f]
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def _resolve_repo_and_ignore_path(
|
|
76
|
+
repo: git.Repo, path: str | PathLike
|
|
77
|
+
) -> tuple[git.Repo, str]:
|
|
78
|
+
"""Resolve which repo should own ignore rules for ``path``."""
|
|
79
|
+
# Normalize target path to absolute from the current repo root.
|
|
80
|
+
repo_root = Path(repo.working_dir).resolve()
|
|
81
|
+
path_obj = Path(path)
|
|
82
|
+
if path_obj.is_absolute():
|
|
83
|
+
abs_path = path_obj.resolve()
|
|
84
|
+
else:
|
|
85
|
+
abs_path = (repo_root / path_obj).resolve()
|
|
86
|
+
# If the path is inside a submodule, use that repo and relative path.
|
|
87
|
+
for submodule in repo.submodules:
|
|
88
|
+
submodule_root = (repo_root / submodule.path).resolve()
|
|
89
|
+
if abs_path == submodule_root:
|
|
90
|
+
continue
|
|
91
|
+
if abs_path.is_relative_to(submodule_root):
|
|
92
|
+
sub_repo = submodule.module()
|
|
93
|
+
rel_path = abs_path.relative_to(submodule_root).as_posix()
|
|
94
|
+
return sub_repo, rel_path
|
|
95
|
+
# Fall back to a repo-relative path when possible.
|
|
96
|
+
try:
|
|
97
|
+
rel_path = abs_path.relative_to(repo_root).as_posix()
|
|
98
|
+
except ValueError:
|
|
99
|
+
rel_path = path_obj.as_posix()
|
|
100
|
+
return repo, rel_path
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def _get_matching_gitignore_details(
|
|
104
|
+
repo: git.Repo, path: str
|
|
105
|
+
) -> tuple[Path | None, str | None]:
|
|
106
|
+
"""Return the repo-local gitignore file and pattern matching ``path``."""
|
|
107
|
+
try:
|
|
108
|
+
check_ignore = repo.git.check_ignore("-v", "--", path)
|
|
109
|
+
except git.GitCommandError:
|
|
110
|
+
return None, None
|
|
111
|
+
line = check_ignore.splitlines()[0]
|
|
112
|
+
try:
|
|
113
|
+
source_info, _ = line.split("\t", 1)
|
|
114
|
+
source_path, _, pattern = source_info.rsplit(":", 2)
|
|
115
|
+
except ValueError:
|
|
116
|
+
return None, None
|
|
117
|
+
if not source_path.endswith(".gitignore"):
|
|
118
|
+
return None, pattern
|
|
119
|
+
gitignore_path = (Path(repo.working_dir) / source_path).resolve()
|
|
120
|
+
try:
|
|
121
|
+
gitignore_path.relative_to(Path(repo.working_dir).resolve())
|
|
122
|
+
except ValueError:
|
|
123
|
+
return None, pattern
|
|
124
|
+
return gitignore_path, pattern
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def ensure_path_is_ignored(
|
|
128
|
+
repo: git.Repo, path: str | PathLike
|
|
129
|
+
) -> None | bool:
|
|
130
|
+
"""Ensure that the given path is ignored by Git.
|
|
131
|
+
|
|
132
|
+
Returns True if ``.gitignore`` was modified.
|
|
133
|
+
"""
|
|
134
|
+
# Resolve whether the ignore rule belongs to this repo or a submodule.
|
|
135
|
+
target_repo, target_path = _resolve_repo_and_ignore_path(repo, path)
|
|
136
|
+
# No-op if Git already ignores this path.
|
|
137
|
+
if target_repo.ignored(target_path):
|
|
138
|
+
return
|
|
139
|
+
# Read gitignore first to check if the path is already ignored
|
|
140
|
+
# If not, we don't want to add a line for it since it was added
|
|
141
|
+
# TODO: Add an option to remove cached (`git rm --cached`)
|
|
142
|
+
gitignore_path = os.path.join(target_repo.working_dir, ".gitignore")
|
|
143
|
+
if os.path.isfile(gitignore_path):
|
|
144
|
+
with open(gitignore_path) as f:
|
|
145
|
+
gitignore_txt = f.read()
|
|
146
|
+
lines = gitignore_txt.splitlines()
|
|
147
|
+
if target_path in lines:
|
|
148
|
+
return
|
|
149
|
+
with open(gitignore_path, "a") as f:
|
|
150
|
+
if (
|
|
151
|
+
os.path.isfile(gitignore_path)
|
|
152
|
+
and os.path.getsize(gitignore_path) > 0
|
|
153
|
+
):
|
|
154
|
+
f.write("\n")
|
|
155
|
+
f.write(f"{target_path}\n")
|
|
156
|
+
return True
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def ensure_path_is_not_ignored(
|
|
160
|
+
repo: git.Repo, path: str | PathLike
|
|
161
|
+
) -> None | bool:
|
|
162
|
+
"""Ensure a path is not ignored by Git."""
|
|
163
|
+
# Resolve whether the unignore rule belongs to this repo or a submodule.
|
|
164
|
+
target_repo, target_path = _resolve_repo_and_ignore_path(repo, path)
|
|
165
|
+
# No-op if Git does not ignore this path.
|
|
166
|
+
if not target_repo.ignored(target_path):
|
|
167
|
+
return
|
|
168
|
+
matching_gitignore_path, matched_pattern = _get_matching_gitignore_details(
|
|
169
|
+
target_repo, target_path
|
|
170
|
+
)
|
|
171
|
+
if matching_gitignore_path is not None:
|
|
172
|
+
gitignore_path = matching_gitignore_path.as_posix()
|
|
173
|
+
path_for_gitignore = (
|
|
174
|
+
(Path(target_repo.working_dir) / target_path)
|
|
175
|
+
.resolve()
|
|
176
|
+
.relative_to(matching_gitignore_path.parent.resolve())
|
|
177
|
+
.as_posix()
|
|
178
|
+
)
|
|
179
|
+
else:
|
|
180
|
+
gitignore_path = os.path.join(target_repo.working_dir, ".gitignore")
|
|
181
|
+
path_for_gitignore = target_path
|
|
182
|
+
if not os.path.isfile(gitignore_path):
|
|
183
|
+
with open(gitignore_path, "w") as f:
|
|
184
|
+
f.write(f"!{path_for_gitignore}\n")
|
|
185
|
+
return True
|
|
186
|
+
with open(gitignore_path) as f:
|
|
187
|
+
gitignore_txt = f.read()
|
|
188
|
+
lines = gitignore_txt.splitlines()
|
|
189
|
+
direct_rule_variants = [path_for_gitignore, f"/{path_for_gitignore}"]
|
|
190
|
+
if matched_pattern is not None and matched_pattern.startswith("/"):
|
|
191
|
+
no_ignore_line = f"!/{path_for_gitignore}"
|
|
192
|
+
else:
|
|
193
|
+
no_ignore_line = f"!{path_for_gitignore}"
|
|
194
|
+
path_parts = Path(path_for_gitignore).parts
|
|
195
|
+
|
|
196
|
+
def ancestor_requires_recursive_unignore() -> bool:
|
|
197
|
+
"""Return True if any ancestor-level ignore rule would block this path.
|
|
198
|
+
|
|
199
|
+
This includes explicit directory ignores (e.g. 'dir/' or '/dir/')
|
|
200
|
+
as well as ancestor-based glob patterns like 'dir/*' or '/dir/*',
|
|
201
|
+
i.e., any rule that would prevent reaching the nested path without
|
|
202
|
+
adding recursive unignore patterns.
|
|
203
|
+
"""
|
|
204
|
+
for i in range(1, len(path_parts)):
|
|
205
|
+
ancestor = "/".join(path_parts[:i])
|
|
206
|
+
if (
|
|
207
|
+
ancestor in lines
|
|
208
|
+
or f"/{ancestor}" in lines
|
|
209
|
+
or f"{ancestor}/" in lines
|
|
210
|
+
or f"/{ancestor}/" in lines
|
|
211
|
+
or f"{ancestor}/*" in lines
|
|
212
|
+
or f"/{ancestor}/*" in lines
|
|
213
|
+
):
|
|
214
|
+
return True
|
|
215
|
+
return False
|
|
216
|
+
|
|
217
|
+
if len(path_parts) == 1:
|
|
218
|
+
# Simple (non-nested) path: remove the direct ignore rule, or add a
|
|
219
|
+
# negation if the ignore comes from a glob or other pattern
|
|
220
|
+
direct_rule = next(
|
|
221
|
+
(rule for rule in direct_rule_variants if rule in lines), None
|
|
222
|
+
)
|
|
223
|
+
if direct_rule is not None:
|
|
224
|
+
lines.remove(direct_rule)
|
|
225
|
+
else:
|
|
226
|
+
# Remove any stale negation and re-append at the end so it takes
|
|
227
|
+
# precedence over any later re-ignore rule
|
|
228
|
+
if no_ignore_line in lines:
|
|
229
|
+
lines.remove(no_ignore_line)
|
|
230
|
+
lines.append(no_ignore_line)
|
|
231
|
+
else:
|
|
232
|
+
# Nested path: only apply recursive un-ignore rules when an ancestor
|
|
233
|
+
# directory is explicitly ignored
|
|
234
|
+
# Otherwise, remove a direct ignore
|
|
235
|
+
# rule for this path or add a simple negation if needed
|
|
236
|
+
removed_direct_rule = False
|
|
237
|
+
direct_rule = next(
|
|
238
|
+
(rule for rule in direct_rule_variants if rule in lines), None
|
|
239
|
+
)
|
|
240
|
+
if direct_rule is not None:
|
|
241
|
+
lines.remove(direct_rule)
|
|
242
|
+
removed_direct_rule = True
|
|
243
|
+
if ancestor_requires_recursive_unignore():
|
|
244
|
+
# Git will not traverse into a directory excluded by a "dir/"
|
|
245
|
+
# pattern, so a bare "!dir/sub/file" negation has no effect.
|
|
246
|
+
# We need to:
|
|
247
|
+
# 1. Convert any "ancestor/" (or "ancestor") exclude to
|
|
248
|
+
# "ancestor/*" so git traverses the directory while still
|
|
249
|
+
# ignoring direct children by default.
|
|
250
|
+
# 2. Add "!ancestor/" rules for intermediate directories.
|
|
251
|
+
# 3. Add "ancestor/*" re-ignore rules for each intermediate dir.
|
|
252
|
+
# 4. Add "!target_path" for the specific file.
|
|
253
|
+
for i in range(1, len(path_parts)):
|
|
254
|
+
ancestor = "/".join(path_parts[:i])
|
|
255
|
+
reignore_glob = f"{ancestor}/*"
|
|
256
|
+
if f"{ancestor}/" in lines:
|
|
257
|
+
idx = lines.index(f"{ancestor}/")
|
|
258
|
+
lines[idx] = reignore_glob
|
|
259
|
+
elif f"/{ancestor}/" in lines:
|
|
260
|
+
idx = lines.index(f"/{ancestor}/")
|
|
261
|
+
lines[idx] = f"/{ancestor}/*"
|
|
262
|
+
elif ancestor in lines:
|
|
263
|
+
idx = lines.index(ancestor)
|
|
264
|
+
lines[idx] = reignore_glob
|
|
265
|
+
elif f"/{ancestor}" in lines:
|
|
266
|
+
idx = lines.index(f"/{ancestor}")
|
|
267
|
+
lines[idx] = f"/{ancestor}/*"
|
|
268
|
+
no_ignore_dir = f"!{ancestor}/"
|
|
269
|
+
anchored_no_ignore_dir = f"!/{ancestor}/"
|
|
270
|
+
# The first ancestor does not need an explicit un-ignore once
|
|
271
|
+
# converted to "ancestor/*". Deeper ancestors do.
|
|
272
|
+
if i > 1:
|
|
273
|
+
# Remove stale entry and re-append so it takes precedence
|
|
274
|
+
if no_ignore_dir in lines:
|
|
275
|
+
lines.remove(no_ignore_dir)
|
|
276
|
+
elif anchored_no_ignore_dir in lines:
|
|
277
|
+
lines.remove(anchored_no_ignore_dir)
|
|
278
|
+
lines.append(no_ignore_dir)
|
|
279
|
+
if (
|
|
280
|
+
reignore_glob not in lines
|
|
281
|
+
and f"/{ancestor}/*" not in lines
|
|
282
|
+
):
|
|
283
|
+
lines.append(reignore_glob)
|
|
284
|
+
# Remove stale negation and re-append at the end so it takes
|
|
285
|
+
# precedence over any later re-ignore rule
|
|
286
|
+
if no_ignore_line in lines:
|
|
287
|
+
lines.remove(no_ignore_line)
|
|
288
|
+
lines.append(no_ignore_line)
|
|
289
|
+
elif not removed_direct_rule:
|
|
290
|
+
# The path may be ignored by a non-directory pattern (e.g., glob);
|
|
291
|
+
# remove stale negation and append at end so it takes precedence
|
|
292
|
+
if no_ignore_line in lines:
|
|
293
|
+
lines.remove(no_ignore_line)
|
|
294
|
+
lines.append(no_ignore_line)
|
|
295
|
+
with open(gitignore_path, "w") as f:
|
|
296
|
+
f.write(os.linesep.join(lines))
|
|
297
|
+
return True
|
|
@@ -241,25 +241,15 @@ def to_dvc(
|
|
|
241
241
|
outputs += stage.notebook_outputs
|
|
242
242
|
elif stage.kind == "sbatch":
|
|
243
243
|
outputs.append(stage.log_output)
|
|
244
|
-
# Build the set of current output paths so we can detect stale
|
|
245
|
-
# .gitignore entries from the previous version of the stage
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
if isinstance(out, PathOutput):
|
|
249
|
-
current_out_paths.add(out.path)
|
|
250
|
-
elif isinstance(out, str):
|
|
251
|
-
current_out_paths.add(out)
|
|
244
|
+
# Build the set of current DVC output paths so we can detect stale
|
|
245
|
+
# .gitignore entries from the previous version of the stage,
|
|
246
|
+
# including synthesized outputs like LaTeX PDFs
|
|
247
|
+
current_out_paths = set(calkit.dvc.out_paths_from_stage(dvc_stage))
|
|
252
248
|
# If this stage already existed, un-ignore any outputs that have
|
|
253
249
|
# been renamed or removed so .gitignore does not accumulate stale
|
|
254
250
|
# entries (e.g., after a capitalization change in the path)
|
|
255
251
|
old_stage = existing_dvc_stages.get(stage_name, {})
|
|
256
|
-
for
|
|
257
|
-
if isinstance(old_out, str):
|
|
258
|
-
old_path = old_out
|
|
259
|
-
elif isinstance(old_out, dict):
|
|
260
|
-
old_path = list(old_out.keys())[0]
|
|
261
|
-
else:
|
|
262
|
-
continue
|
|
252
|
+
for old_path in calkit.dvc.out_paths_from_stage(old_stage):
|
|
263
253
|
if old_path not in current_out_paths:
|
|
264
254
|
calkit.git.ensure_path_is_not_ignored(repo, path=old_path)
|
|
265
255
|
# Deal with any gitignore changes necessary
|
|
@@ -105,7 +105,7 @@ def test_ensure_path_is_not_ignored_nested(tmp_dir):
|
|
|
105
105
|
|
|
106
106
|
When a parent directory is excluded with a trailing slash (e.g.,
|
|
107
107
|
``results/``), git will not traverse into it, so a simple negation like
|
|
108
|
-
``!results/StageName/end.json`` has no effect.
|
|
108
|
+
``!results/StageName/end.json`` has no effect. The fix converts the
|
|
109
109
|
directory exclude to a glob pattern and adds intermediate un-ignore rules.
|
|
110
110
|
"""
|
|
111
111
|
repo = git.Repo.init()
|
|
@@ -124,15 +124,13 @@ def test_ensure_path_is_not_ignored_nested(tmp_dir):
|
|
|
124
124
|
assert result is True
|
|
125
125
|
with open(".gitignore") as f:
|
|
126
126
|
lines = f.read().splitlines()
|
|
127
|
-
#
|
|
128
|
-
assert
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
# The specific file must be explicitly un-ignored
|
|
135
|
-
assert "!results/StageName/end.json" in lines
|
|
127
|
+
# Keep the rules minimal while preserving the required behavior
|
|
128
|
+
assert lines == [
|
|
129
|
+
"results/*",
|
|
130
|
+
"!results/StageName/",
|
|
131
|
+
"results/StageName/*",
|
|
132
|
+
"!results/StageName/end.json",
|
|
133
|
+
]
|
|
136
134
|
# Verify git no longer considers the target file as ignored
|
|
137
135
|
assert not repo.ignored("results/StageName/end.json")
|
|
138
136
|
# Other files in results/ must still be ignored
|
|
@@ -148,3 +146,54 @@ def test_ensure_path_is_not_ignored_nested(tmp_dir):
|
|
|
148
146
|
repo, path="results/StageName/end.json"
|
|
149
147
|
)
|
|
150
148
|
assert result2 is None
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def test_ensure_path_is_not_ignored_nested_direct_path_rule(tmp_dir):
|
|
152
|
+
"""Unignoring a directly ignored nested path should only remove that
|
|
153
|
+
rule.
|
|
154
|
+
"""
|
|
155
|
+
repo = git.Repo.init()
|
|
156
|
+
target = "pubs/applied-ocean-research-model/references.bib"
|
|
157
|
+
sibling = "pubs/applied-ocean-research-model/paper.pdf"
|
|
158
|
+
with open(".gitignore", "w") as f:
|
|
159
|
+
f.write(f"{target}\n")
|
|
160
|
+
os.makedirs("pubs/applied-ocean-research-model", exist_ok=True)
|
|
161
|
+
with open(target, "w") as f:
|
|
162
|
+
f.write("@article{test}\n")
|
|
163
|
+
with open(sibling, "w") as f:
|
|
164
|
+
f.write("pdf\n")
|
|
165
|
+
# Only the direct target path should be ignored initially
|
|
166
|
+
assert repo.ignored(target)
|
|
167
|
+
assert not repo.ignored(sibling)
|
|
168
|
+
result = calkit.git.ensure_path_is_not_ignored(repo, path=target)
|
|
169
|
+
assert result is True
|
|
170
|
+
with open(".gitignore") as f:
|
|
171
|
+
lines = f.read().splitlines()
|
|
172
|
+
# Remove only the direct rule, with no recursive ancestor entries
|
|
173
|
+
assert target not in lines
|
|
174
|
+
assert f"!{target}" not in lines
|
|
175
|
+
assert "!pubs/" not in lines
|
|
176
|
+
assert "pubs/*" not in lines
|
|
177
|
+
assert "!pubs/applied-ocean-research-model/" not in lines
|
|
178
|
+
assert "pubs/applied-ocean-research-model/*" not in lines
|
|
179
|
+
assert not repo.ignored(target)
|
|
180
|
+
assert not repo.ignored(sibling)
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def test_ensure_path_is_not_ignored_nested_gitignore_direct_path_rule(tmp_dir):
|
|
184
|
+
repo = git.Repo.init()
|
|
185
|
+
os.makedirs("paper", exist_ok=True)
|
|
186
|
+
target = "paper/main.pdf"
|
|
187
|
+
with open("paper/.gitignore", "w") as f:
|
|
188
|
+
f.write("/main.pdf\n")
|
|
189
|
+
with open(target, "w") as f:
|
|
190
|
+
f.write("pdf\n")
|
|
191
|
+
assert repo.ignored(target)
|
|
192
|
+
result = calkit.git.ensure_path_is_not_ignored(repo, path=target)
|
|
193
|
+
assert result is True
|
|
194
|
+
with open("paper/.gitignore") as f:
|
|
195
|
+
lines = f.read().splitlines()
|
|
196
|
+
assert "/main.pdf" not in lines
|
|
197
|
+
assert "!/main.pdf" not in lines
|
|
198
|
+
assert not os.path.exists(".gitignore")
|
|
199
|
+
assert not repo.ignored(target)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"""Tests for ``calkit.pipeline``."""
|
|
2
2
|
|
|
3
|
+
import os
|
|
3
4
|
import subprocess
|
|
4
5
|
|
|
5
6
|
import git
|
|
@@ -653,9 +654,12 @@ def test_shell_script_stage_allows_non_composite_slurm_env():
|
|
|
653
654
|
|
|
654
655
|
|
|
655
656
|
def test_gitignore_updated_when_stage_output_renamed(tmp_dir):
|
|
656
|
-
"""When a stage output path is renamed
|
|
657
|
-
|
|
658
|
-
|
|
657
|
+
"""When a stage output path is renamed, stale .gitignore entries are
|
|
658
|
+
replaced.
|
|
659
|
+
|
|
660
|
+
Use the .gitignore contents for verification because case-only renames can
|
|
661
|
+
still appear ignored on case-insensitive filesystems like the default macOS
|
|
662
|
+
setup.
|
|
659
663
|
"""
|
|
660
664
|
subprocess.check_call(["calkit", "init"])
|
|
661
665
|
# Stage 1: initial calkit.yaml with output 'b_sparsity_plot.pdf' stored in DVC
|
|
@@ -682,6 +686,9 @@ def test_gitignore_updated_when_stage_output_renamed(tmp_dir):
|
|
|
682
686
|
# Verify DVC has added the old output path to .gitignore
|
|
683
687
|
repo = git.Repo(".")
|
|
684
688
|
assert repo.ignored("b_sparsity_plot.pdf")
|
|
689
|
+
with open(".gitignore") as f:
|
|
690
|
+
lines = f.read().splitlines()
|
|
691
|
+
assert "/b_sparsity_plot.pdf" in lines
|
|
685
692
|
# Stage 2: rename output (capitalization change) to 'B_sparsity_plot.pdf'
|
|
686
693
|
ck_info["pipeline"]["stages"]["plot"]["command"] = (
|
|
687
694
|
"touch B_sparsity_plot.pdf"
|
|
@@ -692,6 +699,52 @@ def test_gitignore_updated_when_stage_output_renamed(tmp_dir):
|
|
|
692
699
|
with open("calkit.yaml", "w") as f:
|
|
693
700
|
calkit.ryaml.dump(ck_info, f)
|
|
694
701
|
subprocess.check_call(["calkit", "run"])
|
|
695
|
-
|
|
696
|
-
|
|
702
|
+
with open(".gitignore") as f:
|
|
703
|
+
lines = f.read().splitlines()
|
|
704
|
+
assert "/b_sparsity_plot.pdf" not in lines
|
|
705
|
+
assert "/B_sparsity_plot.pdf" in lines
|
|
697
706
|
assert repo.ignored("B_sparsity_plot.pdf")
|
|
707
|
+
|
|
708
|
+
|
|
709
|
+
def test_gitignore_not_unignored_latex_pdf_output(tmp_dir):
|
|
710
|
+
repo = git.Repo.init()
|
|
711
|
+
subprocess.check_call(["calkit", "init"])
|
|
712
|
+
os.makedirs("paper", exist_ok=True)
|
|
713
|
+
with open("paper/.gitignore", "w") as f:
|
|
714
|
+
f.write("/main.pdf\n")
|
|
715
|
+
ck_info = {
|
|
716
|
+
"environments": {
|
|
717
|
+
"tex": {
|
|
718
|
+
"kind": "conda",
|
|
719
|
+
"path": "environment.yaml",
|
|
720
|
+
}
|
|
721
|
+
},
|
|
722
|
+
"pipeline": {
|
|
723
|
+
"stages": {
|
|
724
|
+
"build-paper": {
|
|
725
|
+
"kind": "latex",
|
|
726
|
+
"environment": "tex",
|
|
727
|
+
"target_path": "paper/main.tex",
|
|
728
|
+
"force": True,
|
|
729
|
+
"inputs": [
|
|
730
|
+
"paper/references.bib",
|
|
731
|
+
"paper/aasjournal.bst",
|
|
732
|
+
"paper/aastex631.cls",
|
|
733
|
+
"paper/results.tex",
|
|
734
|
+
"paper/diagrams",
|
|
735
|
+
"paper/figures",
|
|
736
|
+
],
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
},
|
|
740
|
+
}
|
|
741
|
+
with open("calkit.yaml", "w") as f:
|
|
742
|
+
calkit.ryaml.dump(ck_info, f)
|
|
743
|
+
calkit.pipeline.to_dvc(ck_info=ck_info, write=True)
|
|
744
|
+
assert not os.path.exists(".gitignore")
|
|
745
|
+
assert repo.ignored("paper/main.pdf")
|
|
746
|
+
calkit.pipeline.to_dvc(ck_info=ck_info, write=True)
|
|
747
|
+
assert not os.path.exists(".gitignore")
|
|
748
|
+
with open("paper/.gitignore") as f:
|
|
749
|
+
assert f.read().splitlines() == ["/main.pdf"]
|
|
750
|
+
assert repo.ignored("paper/main.pdf")
|