calkit-python 0.41.19__tar.gz → 0.41.21__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.41.21/.gitmodules +3 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/CONTRIBUTING.md +1 -1
- {calkit_python-0.41.19 → calkit_python-0.41.21}/PKG-INFO +9 -8
- {calkit_python-0.41.19 → calkit_python-0.41.21}/README.md +7 -6
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/cli/list.py +35 -1
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/cli/main/core.py +33 -3
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/cli/new.py +4 -8
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/cli/overleaf.py +12 -2
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/detect.py +102 -25
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/dvc/zip.py +17 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/git.py +29 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/models/core.py +11 -1
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/tests/cli/main/test_core.py +90 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/tests/cli/test_list.py +41 -1
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/tests/cli/test_new.py +14 -19
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/tests/cli/test_overleaf.py +47 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/tests/dvc/test_zip.py +25 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/tests/models/test_core.py +22 -1
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/tests/test_detect.py +59 -2
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/calkit-yaml.md +1 -1
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/cli-reference.md +3 -3
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/help.md +1 -1
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/index.md +7 -6
- calkit_python-0.41.21/docs/questions.md +31 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/tutorials/latex-codespaces.md +27 -4
- {calkit_python-0.41.19 → calkit_python-0.41.21}/mkdocs.yml +1 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/pyproject.toml +1 -2
- {calkit_python-0.41.19 → calkit_python-0.41.21}/uv.lock +1064 -136
- {calkit_python-0.41.19 → calkit_python-0.41.21}/.claude-plugin/marketplace.json +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/.gitattributes +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/.gitignore +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/.pre-commit-config.yaml +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/.prettierignore +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/.prettierrc.json +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/.python-version +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/.vscode/launch.json +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/.vscode/tasks.json +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/AGENTS.md +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/CITATION.cff +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/CODE_OF_CONDUCT.md +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/LICENSE +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/Makefile +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/agent-plugin/.claude-plugin/plugin.json +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/agent-plugin/skills/add-pipeline-stage/SKILL.md +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/agent-plugin/skills/conventions/SKILL.md +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/agent-plugin/skills/create-pipeline/SKILL.md +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/__init__.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/__main__.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/calc.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/check.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/cli/__init__.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/cli/check.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/cli/cloud.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/cli/config.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/cli/core.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/cli/delete.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/cli/describe.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/cli/dev.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/cli/import_.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/cli/latex.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/cli/main/__init__.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/cli/main/xr.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/cli/notebooks.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/cli/office.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/cli/scheduler.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/cli/update.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/cloud.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/conda.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/config.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/core.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/datasets.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/dependencies.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/docker.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/dvc/__init__.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/dvc/core.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/environments.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/fs.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/github.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/gui.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/install.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/invenio.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/julia.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/jupyter.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/jupyterlab/__init__.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/jupyterlab/routes.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/labextension/package.json +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/labextension/schemas/calkit/package.json.orig +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/labextension/schemas/calkit/plugin.json +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/labextension/static/502.9a2c5772a15466e923ef.js +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/labextension/static/695.2c41003a452d43d2b358.js +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/labextension/static/867.a42a046aa5108f54f8fb.js +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/labextension/static/909.e3f9cc3408834a7fdcc3.js +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/labextension/static/946.050af2abf7845cfbdbd2.js +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/labextension/static/946.050af2abf7845cfbdbd2.js.LICENSE.txt +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/labextension/static/b2f1c3efe70cb539d121.png +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/labextension/static/remoteEntry.ac9035764d5b2adbb542.js +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/labextension/static/style.js +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/labextension/static/third-party-licenses.json +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/licenses.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/magics.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/matlab.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/models/__init__.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/models/io.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/models/iteration.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/models/pipeline.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/notebooks.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/office.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/ops.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/overleaf.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/pipeline.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/releases.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/server.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/templates/__init__.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/templates/core.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/templates/latex/__init__.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/templates/latex/article/paper.tex +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/templates/latex/core.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/templates/latex/jfm/jfm.bst +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/templates/latex/jfm/jfm.cls +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/templates/latex/jfm/lineno-FLM.sty +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/templates/latex/jfm/paper.tex +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/templates/latex/jfm/upmath.sty +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/tests/__init__.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/tests/cli/__init__.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/tests/cli/main/__init__.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/tests/cli/main/test_lock.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/tests/cli/main/test_subprojects.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/tests/cli/main/test_xr.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/tests/cli/test_check.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/tests/cli/test_cloud.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/tests/cli/test_config.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/tests/cli/test_delete.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/tests/cli/test_import.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/tests/cli/test_latex.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/tests/cli/test_notebooks.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/tests/cli/test_scheduler.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/tests/cli/test_update.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/tests/dvc/__init__.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/tests/dvc/test_core.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/tests/jupyterlab/__init__.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/tests/jupyterlab/conftest.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/tests/jupyterlab/test_routes.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/tests/models/__init__.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/tests/models/test_iteration.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/tests/models/test_pipeline.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/tests/test_calc.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/tests/test_check.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/tests/test_cloud.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/tests/test_conda.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/tests/test_core.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/tests/test_dependencies.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/tests/test_docker.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/tests/test_environments.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/tests/test_fs.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/tests/test_git.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/tests/test_install.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/tests/test_invenio.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/tests/test_julia.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/tests/test_jupyter.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/tests/test_licenses.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/tests/test_magics.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/tests/test_matlab.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/tests/test_notebooks.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/tests/test_pipeline.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/tests/test_releases.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/calkit/tests/test_templates.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/CNAME +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/acknowledgements.md +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/ai-tools.md +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/apps.md +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/calculations.md +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/cloud-integration.md +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/datasets.md +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/dependencies.md +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/environments.md +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/examples.md +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/governance.md +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/hpc.md +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/img/c-to-the-k-white.svg +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/img/calkit-fragmentation-compendium.png +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/img/calkit-no-bg.png +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/img/caltech.png +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/img/connect-zenodo.png +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/img/jupyterlab/all-green.png +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/img/jupyterlab/collect-data-stale.png +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/img/jupyterlab/new-env.png +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/img/jupyterlab/new-notebook.png +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/img/jupyterlab/pipeline-badge.png +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/img/jupyterlab-params.png +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/img/pipeline.png +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/img/plos-osi-code-2024-03.png +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/img/schmidt-sciences.png +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/img/vscode-nb-params.png +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/installation.md +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/jupyterlab.md +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/local-server.md +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/notebooks.md +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/overleaf.md +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/pipeline/index.md +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/pipeline/manual-steps.md +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/pipeline/running-and-logging.md +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/quickstart.md +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/references.md +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/releases.md +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/reproducibility.md +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/subprojects.md +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/tutorials/adding-latex-pub-docker.md +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/tutorials/ai-agents.md +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/tutorials/conda-envs.md +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/tutorials/existing-project.md +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/tutorials/first-project.md +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/tutorials/github-actions.md +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/tutorials/img/actions-repo-secrets.png +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/tutorials/img/latex-codespaces/building-codespace.png +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/tutorials/img/latex-codespaces/codespaces-secrets-2.png +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/tutorials/img/latex-codespaces/editor-split.png +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/tutorials/img/latex-codespaces/go-to-linked-code.png +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/tutorials/img/latex-codespaces/issue-from-selection.png +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/tutorials/img/latex-codespaces/new-project.png +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/tutorials/img/latex-codespaces/new-pub-2.png +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/tutorials/img/latex-codespaces/new-token.png +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/tutorials/img/latex-codespaces/paper.tex.png +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/tutorials/img/latex-codespaces/project-home-3.png +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/tutorials/img/latex-codespaces/push.png +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/tutorials/img/latex-codespaces/stage.png +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/tutorials/img/office/anakin-excel.jpg +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/tutorials/img/office/chart-more-rows.png +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/tutorials/img/office/create-project.png +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/tutorials/img/office/elsevier-research-data-guidelines.png +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/tutorials/img/office/excel-chart.png +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/tutorials/img/office/excel-data.png +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/tutorials/img/office/insert-link-to-file.png +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/tutorials/img/office/needs-clone.png +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/tutorials/img/office/new-stage.png +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/tutorials/img/office/phd-comics-version-control.webp +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/tutorials/img/office/pipeline-out-of-date.png +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/tutorials/img/office/status-more-rows.png +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/tutorials/img/office/uncommitted-changes.png +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/tutorials/img/office/untracked-data.png +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/tutorials/img/office/updated-publication.png +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/tutorials/img/office/word-to-pdf-stage-2.png +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/tutorials/img/office/workflow-page.png +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/tutorials/img/openfoam/clone.png +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/tutorials/img/openfoam/create-project.png +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/tutorials/img/openfoam/datasets-page.png +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/tutorials/img/openfoam/figure-on-website-updated.png +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/tutorials/img/openfoam/figure-on-website.png +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/tutorials/img/openfoam/new-token.png +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/tutorials/img/openfoam/reclone.png +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/tutorials/img/openfoam/status-after-import-dataset.png +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/tutorials/img/quick-actions.png +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/tutorials/img/run-proc.png +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/tutorials/img/vscode-slurm-notebook/create-calkit-env.png +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/tutorials/img/vscode-slurm-notebook/create-inner-env.png +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/tutorials/img/vscode-slurm-notebook/create-new-calkit-env.png +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/tutorials/img/vscode-slurm-notebook/select-calkit-env.png +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/tutorials/img/vscode-slurm-notebook/slurm-job-running.png +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/tutorials/img/vscode-slurm-notebook/slurm-launch-options.png +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/tutorials/img/vscode-slurm-notebook/starting-slurm-job.png +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/tutorials/index.md +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/tutorials/jupyterlab.md +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/tutorials/matlab.md +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/tutorials/notebook-pipeline.md +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/tutorials/office.md +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/tutorials/openfoam.md +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/tutorials/procedures.md +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/tutorials/vscode-slurm-notebook.md +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/docs/version-control.md +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/flake.lock +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/flake.nix +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/jupyterlab-ext/.yarnrc.yml +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/jupyterlab-ext/babel.config.js +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/jupyterlab-ext/install.json +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/jupyterlab-ext/jest.config.js +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/jupyterlab-ext/jupyter-config/server-config/calkit.json +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/jupyterlab-ext/package.json +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/jupyterlab-ext/schema/plugin.json +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/jupyterlab-ext/src/__tests__/useQueries.spec.ts +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/jupyterlab-ext/src/calkit-config.ts +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/jupyterlab-ext/src/cell-output-marker.ts +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/jupyterlab-ext/src/components/commit-dialog.tsx +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/jupyterlab-ext/src/components/environment-editor.tsx +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/jupyterlab-ext/src/components/notebook-registration.tsx +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/jupyterlab-ext/src/components/notebook-toolbar.tsx +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/jupyterlab-ext/src/components/pipeline-status-bar.tsx +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/jupyterlab-ext/src/components/project-info-editor.tsx +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/jupyterlab-ext/src/components/sidebar-settings.tsx +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/jupyterlab-ext/src/components/sidebar.tsx +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/jupyterlab-ext/src/components/stage-editor.tsx +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/jupyterlab-ext/src/feature-flags.ts +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/jupyterlab-ext/src/file-browser-menu.ts +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/jupyterlab-ext/src/hooks/__tests__/useQueries.test.tsx +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/jupyterlab-ext/src/hooks/useQueries.ts +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/jupyterlab-ext/src/icons.ts +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/jupyterlab-ext/src/index.ts +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/jupyterlab-ext/src/io-tracker.ts +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/jupyterlab-ext/src/pipeline-state.ts +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/jupyterlab-ext/src/queryClient.ts +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/jupyterlab-ext/src/request.ts +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/jupyterlab-ext/src/shims-mainmenu.d.ts +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/jupyterlab-ext/style/base.css +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/jupyterlab-ext/style/cell-output-marker.css +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/jupyterlab-ext/style/environment-editor.css +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/jupyterlab-ext/style/environment-selector.css +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/jupyterlab-ext/style/img/calkit-no-bg.png +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/jupyterlab-ext/style/index.css +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/jupyterlab-ext/style/index.js +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/jupyterlab-ext/style/notebook-toolbar.css +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/jupyterlab-ext/style/pipeline-status-bar.css +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/jupyterlab-ext/style/sidebar.css +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/jupyterlab-ext/tsconfig.json +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/jupyterlab-ext/tsconfig.test.json +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/jupyterlab-ext/ui-tests/.gitignore +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/jupyterlab-ext/ui-tests/README.md +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/jupyterlab-ext/ui-tests/jupyter_server_test_config.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/jupyterlab-ext/ui-tests/package.json +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/jupyterlab-ext/ui-tests/playwright.config.js +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/jupyterlab-ext/ui-tests/tests/calkit.spec.ts +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/jupyterlab-ext/ui-tests/yarn.lock +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/jupyterlab-ext/yarn.lock +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/scripts/generate-docs-references.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/scripts/install.ps1 +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/scripts/install.sh +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/scripts/make-calk9.sh +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/scripts/sync-docs.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/test/dvc-md5-dir/osx-arm64.txt +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/test/nb-julia.ipynb +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/test/nb-params.ipynb +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/test/nb-subdir.ipynb +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/test/pipeline.ipynb +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/test/script.py +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/test/test-log.log +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/vscode-ext/.gitignore +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/vscode-ext/.vscodeignore +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/vscode-ext/CHANGELOG.md +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/vscode-ext/LICENSE +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/vscode-ext/README.md +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/vscode-ext/images/calkit-icon.svg +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/vscode-ext/images/calkit-no-bg.png +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/vscode-ext/package-lock.json +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/vscode-ext/package.json +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/vscode-ext/scripts/set-proposed-api.js +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/vscode-ext/src/environments.ts +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/vscode-ext/src/extension.ts +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/vscode-ext/src/figures/core.ts +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/vscode-ext/src/figures/view.ts +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/vscode-ext/src/notebooks.ts +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/vscode-ext/src/pipeline/core.ts +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/vscode-ext/src/sidebar.ts +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/vscode-ext/src/test/environments.test.ts +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/vscode-ext/src/test/figures.test.ts +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/vscode-ext/src/test/kernel-selection.test.ts +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/vscode-ext/src/test/notebooks.test.ts +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/vscode-ext/src/test/pipeline.test.ts +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/vscode-ext/src/types.ts +0 -0
- {calkit_python-0.41.19 → calkit_python-0.41.21}/vscode-ext/tsconfig.json +0 -0
|
@@ -98,7 +98,7 @@ This guide will help you get started.
|
|
|
98
98
|
## 🎉 Join the community
|
|
99
99
|
|
|
100
100
|
- Participate in **[GitHub Discussions](https://github.com/calkit/discussions)**.
|
|
101
|
-
- Join our [**Discord**](https://discord.gg/
|
|
101
|
+
- Join our [**Discord**](https://discord.gg/m2MBC79HzD) for real-time collaboration.
|
|
102
102
|
- Follow our updates on [**LinkedIn**](https://linkedin.com/company/calkit).
|
|
103
103
|
|
|
104
104
|
We appreciate your help in making Calkit better! 🚀
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: calkit-python
|
|
3
|
-
Version: 0.41.
|
|
3
|
+
Version: 0.41.21
|
|
4
4
|
Summary: Reproducibility simplified.
|
|
5
5
|
Project-URL: Homepage, https://calkit.org
|
|
6
6
|
Project-URL: Issues, https://github.com/calkit/calkit/issues
|
|
@@ -26,7 +26,7 @@ Requires-Dist: arithmeval
|
|
|
26
26
|
Requires-Dist: bibtexparser
|
|
27
27
|
Requires-Dist: checksumdir
|
|
28
28
|
Requires-Dist: docx2pdf
|
|
29
|
-
Requires-Dist: dvc==3.67.1
|
|
29
|
+
Requires-Dist: dvc[all]==3.67.1
|
|
30
30
|
Requires-Dist: fastapi
|
|
31
31
|
Requires-Dist: fsspec>=2026.4.0
|
|
32
32
|
Requires-Dist: gitpython
|
|
@@ -78,15 +78,16 @@ Description-Content-Type: text/markdown
|
|
|
78
78
|
|
|
79
79
|
<!-- INCLUDE: docs/index.md -->
|
|
80
80
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
81
|
+
Typical research workflows are horizontally-siloed, i.e.,
|
|
82
|
+
various stages--data collection, analysis, writing--are performed in
|
|
83
|
+
disconnected systems,
|
|
84
|
+
turning research into a slow, error-prone, and tedious
|
|
85
|
+
[waterfall](https://en.wikipedia.org/wiki/Waterfall_model) process.
|
|
85
86
|
|
|
86
87
|
Calkit helps you integrate code, data, figures, results, publications,
|
|
87
88
|
and more into a cohesive, traceable, and portable _knowledge creation system_,
|
|
88
|
-
so every output can be traced back to its source
|
|
89
|
-
single command.
|
|
89
|
+
so every output can be traced back to its source (provenance)
|
|
90
|
+
and reproduced with a single command.
|
|
90
91
|
|
|
91
92
|
With industry standard tools combined into a unified and simplified experience
|
|
92
93
|
tailored for research,
|
|
@@ -19,15 +19,16 @@
|
|
|
19
19
|
|
|
20
20
|
<!-- INCLUDE: docs/index.md -->
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
Typical research workflows are horizontally-siloed, i.e.,
|
|
23
|
+
various stages--data collection, analysis, writing--are performed in
|
|
24
|
+
disconnected systems,
|
|
25
|
+
turning research into a slow, error-prone, and tedious
|
|
26
|
+
[waterfall](https://en.wikipedia.org/wiki/Waterfall_model) process.
|
|
26
27
|
|
|
27
28
|
Calkit helps you integrate code, data, figures, results, publications,
|
|
28
29
|
and more into a cohesive, traceable, and portable _knowledge creation system_,
|
|
29
|
-
so every output can be traced back to its source
|
|
30
|
-
single command.
|
|
30
|
+
so every output can be traced back to its source (provenance)
|
|
31
|
+
and reproduced with a single command.
|
|
31
32
|
|
|
32
33
|
With industry standard tools combined into a unified and simplified experience
|
|
33
34
|
tailored for research,
|
|
@@ -174,6 +174,40 @@ def list_presentations(
|
|
|
174
174
|
_list_artifacts("presentations", json_output, declared_only)
|
|
175
175
|
|
|
176
176
|
|
|
177
|
+
def _echo_question(n: int, question: str | dict) -> None:
|
|
178
|
+
"""Print a single question in the human-readable YAML-ish listing format.
|
|
179
|
+
|
|
180
|
+
String questions are shown as a numbered line. Rich (dict) questions are
|
|
181
|
+
shown with their text on the first line followed by hypothesis, answer,
|
|
182
|
+
evidence, and any other fields in YAML-like indented form.
|
|
183
|
+
"""
|
|
184
|
+
if isinstance(question, str):
|
|
185
|
+
typer.echo(f"{n}. {question}")
|
|
186
|
+
return
|
|
187
|
+
# Copy so popping 'question' doesn't mutate the caller's dict.
|
|
188
|
+
question = dict(question)
|
|
189
|
+
text = question.pop("question", "")
|
|
190
|
+
typer.echo(f"{n}. question: {text}")
|
|
191
|
+
for k, v in question.items():
|
|
192
|
+
if isinstance(v, dict):
|
|
193
|
+
typer.echo(f" {k}:")
|
|
194
|
+
for k1, v1 in v.items():
|
|
195
|
+
typer.echo(f" {k1}: {v1}")
|
|
196
|
+
elif isinstance(v, list):
|
|
197
|
+
typer.echo(f" {k}:")
|
|
198
|
+
for item in v:
|
|
199
|
+
if isinstance(item, dict):
|
|
200
|
+
for n1, (k1, v1) in enumerate(item.items()):
|
|
201
|
+
if n1 == 0:
|
|
202
|
+
typer.echo(f" - {k1}: {v1}")
|
|
203
|
+
else:
|
|
204
|
+
typer.echo(f" {k1}: {v1}")
|
|
205
|
+
else:
|
|
206
|
+
typer.echo(f" - {item}")
|
|
207
|
+
else:
|
|
208
|
+
typer.echo(f" {k}: {v}")
|
|
209
|
+
|
|
210
|
+
|
|
177
211
|
@list_app.command(name="questions")
|
|
178
212
|
def list_questions(
|
|
179
213
|
json_output: Annotated[
|
|
@@ -186,7 +220,7 @@ def list_questions(
|
|
|
186
220
|
typer.echo(json.dumps(questions))
|
|
187
221
|
return
|
|
188
222
|
for n, question in enumerate(questions, start=1):
|
|
189
|
-
|
|
223
|
+
_echo_question(n, question)
|
|
190
224
|
|
|
191
225
|
|
|
192
226
|
@list_app.command(name="publications|pubs")
|
|
@@ -179,11 +179,26 @@ def init(
|
|
|
179
179
|
typer.Option(
|
|
180
180
|
"--force",
|
|
181
181
|
"-f",
|
|
182
|
-
help="
|
|
182
|
+
help="Re-initialize even if the project is already initialized.",
|
|
183
183
|
),
|
|
184
184
|
] = False,
|
|
185
185
|
):
|
|
186
186
|
"""Initialize the current working directory."""
|
|
187
|
+
import git
|
|
188
|
+
from git.exc import InvalidGitRepositoryError
|
|
189
|
+
|
|
190
|
+
def _project_is_initialized() -> bool:
|
|
191
|
+
try:
|
|
192
|
+
git.Repo(".", search_parent_directories=False)
|
|
193
|
+
except InvalidGitRepositoryError:
|
|
194
|
+
return False
|
|
195
|
+
return os.path.isfile(".dvc/config") and os.path.isfile("calkit.yaml")
|
|
196
|
+
|
|
197
|
+
if _project_is_initialized() and not force:
|
|
198
|
+
raise_error(
|
|
199
|
+
"This project is already initialized. "
|
|
200
|
+
"Use --force to re-initialize."
|
|
201
|
+
)
|
|
187
202
|
subprocess.run(["git", "init"])
|
|
188
203
|
result = calkit.dvc.run_dvc_command(
|
|
189
204
|
["init"] + (["--force"] if force else [])
|
|
@@ -197,13 +212,15 @@ def init(
|
|
|
197
212
|
# Commit the newly created .dvc directory
|
|
198
213
|
repo = calkit.git.get_repo()
|
|
199
214
|
repo.git.add(".dvc")
|
|
200
|
-
|
|
215
|
+
if calkit.git.get_staged_files(repo=repo):
|
|
216
|
+
repo.git.commit("-m", "Initialize DVC")
|
|
201
217
|
# Create an empty calkit.yaml if one doesn't already exist
|
|
202
218
|
if not os.path.isfile("calkit.yaml"):
|
|
203
219
|
with open("calkit.yaml", "w"):
|
|
204
220
|
pass
|
|
205
221
|
repo.git.add("calkit.yaml")
|
|
206
|
-
|
|
222
|
+
if calkit.git.get_staged_files(repo=repo):
|
|
223
|
+
repo.git.commit("-m", "Initialize Calkit")
|
|
207
224
|
# TODO: Initialize `dvc.yaml`
|
|
208
225
|
# TODO: Add a sane .gitignore file
|
|
209
226
|
# TODO: Add a sane LICENSE file?
|
|
@@ -769,6 +786,8 @@ def add(
|
|
|
769
786
|
elif to == "git":
|
|
770
787
|
subprocess.call(["git", "add"] + paths)
|
|
771
788
|
elif to == "dvc":
|
|
789
|
+
for path in paths:
|
|
790
|
+
calkit.git.ensure_dvc_pointer_is_not_ignored(repo, path)
|
|
772
791
|
calkit.dvc.run_dvc_command(["add"] + paths)
|
|
773
792
|
elif to == "dvc-zip":
|
|
774
793
|
for path in paths:
|
|
@@ -882,6 +901,7 @@ def add(
|
|
|
882
901
|
f"Adding {path} to DVC since it's already tracked "
|
|
883
902
|
"with DVC"
|
|
884
903
|
)
|
|
904
|
+
calkit.git.ensure_dvc_pointer_is_not_ignored(repo, path)
|
|
885
905
|
calkit.dvc.run_dvc_command(["add", path])
|
|
886
906
|
elif posix_path in pipeline_output_storage:
|
|
887
907
|
# Respect storage explicitly set in the pipeline definition
|
|
@@ -926,6 +946,7 @@ def add(
|
|
|
926
946
|
typer.echo(f"Would add {path} to DVC (per extension)")
|
|
927
947
|
else:
|
|
928
948
|
typer.echo(f"Adding {path} to DVC per its extension")
|
|
949
|
+
calkit.git.ensure_dvc_pointer_is_not_ignored(repo, path)
|
|
929
950
|
calkit.dvc.run_dvc_command(["add", path])
|
|
930
951
|
elif calkit.dvc.zip.is_zip_candidate(path):
|
|
931
952
|
if dry_run:
|
|
@@ -946,6 +967,7 @@ def add(
|
|
|
946
967
|
typer.echo(
|
|
947
968
|
f"Adding {path} to DVC since it's greater than 1 MB"
|
|
948
969
|
)
|
|
970
|
+
calkit.git.ensure_dvc_pointer_is_not_ignored(repo, path)
|
|
949
971
|
calkit.dvc.run_dvc_command(["add", path])
|
|
950
972
|
else:
|
|
951
973
|
if dry_run:
|
|
@@ -3201,6 +3223,14 @@ def call_dvc(
|
|
|
3201
3223
|
and DVC is not installed.
|
|
3202
3224
|
"""
|
|
3203
3225
|
result = calkit.dvc.run_dvc_command(sys.argv[2:])
|
|
3226
|
+
if result != 0 and len(sys.argv) > 2 and sys.argv[2] == "add":
|
|
3227
|
+
typer.secho(
|
|
3228
|
+
"Hint: If DVC failed because a .dvc pointer file is git-ignored, "
|
|
3229
|
+
"use `calkit add --to=dvc <path>` instead so Calkit can "
|
|
3230
|
+
"automatically manage the gitignore exception.",
|
|
3231
|
+
fg=typer.colors.YELLOW,
|
|
3232
|
+
err=True,
|
|
3233
|
+
)
|
|
3204
3234
|
sys.exit(result)
|
|
3205
3235
|
|
|
3206
3236
|
|
|
@@ -3174,7 +3174,7 @@ def new_release(
|
|
|
3174
3174
|
detected_kind, artifact = calkit.releases.find_artifact(path, ck_info)
|
|
3175
3175
|
if detected_kind is None:
|
|
3176
3176
|
detected_kind = calkit.detect.detect_artifact_kind(
|
|
3177
|
-
pathlib.Path(path).as_posix()
|
|
3177
|
+
pathlib.Path(path).as_posix(),
|
|
3178
3178
|
)
|
|
3179
3179
|
if release_kind is None:
|
|
3180
3180
|
if detected_kind is None:
|
|
@@ -3258,16 +3258,12 @@ def new_release(
|
|
|
3258
3258
|
# stored as-is (renamed); folders and whole-project releases are
|
|
3259
3259
|
# zipped.
|
|
3260
3260
|
project_name = calkit.detect_project_name(prepend_owner=False)
|
|
3261
|
-
if path == ".":
|
|
3261
|
+
if path == "." or os.path.isdir(path):
|
|
3262
3262
|
stored_filename = f"{project_name}-{name}.zip"
|
|
3263
3263
|
is_zip = True
|
|
3264
|
-
elif os.path.isdir(path):
|
|
3265
|
-
folder_name = os.path.basename(os.path.normpath(path))
|
|
3266
|
-
stored_filename = f"{project_name}-{folder_name}-{name}.zip"
|
|
3267
|
-
is_zip = True
|
|
3268
3264
|
elif os.path.isfile(path):
|
|
3269
|
-
|
|
3270
|
-
stored_filename = f"{project_name}-{
|
|
3265
|
+
_, ext = os.path.splitext(os.path.basename(path))
|
|
3266
|
+
stored_filename = f"{project_name}-{name}{ext}"
|
|
3271
3267
|
is_zip = False
|
|
3272
3268
|
else:
|
|
3273
3269
|
raise_error(f"Release path '{path}' does not exist")
|
|
@@ -437,7 +437,12 @@ def sync(
|
|
|
437
437
|
raise_error("No Overleaf sync info found")
|
|
438
438
|
overleaf_sync_dirs = list(overleaf_info.keys())
|
|
439
439
|
if paths is not None:
|
|
440
|
-
paths = [
|
|
440
|
+
paths = [
|
|
441
|
+
(os.path.dirname(p) if os.path.isfile(p) else p)
|
|
442
|
+
.strip()
|
|
443
|
+
.rstrip("/\\")
|
|
444
|
+
for p in paths
|
|
445
|
+
]
|
|
441
446
|
for path in paths:
|
|
442
447
|
if path not in overleaf_sync_dirs:
|
|
443
448
|
raise_error(f"Path '{path}' is not synced with Overleaf")
|
|
@@ -611,7 +616,12 @@ def get_status(
|
|
|
611
616
|
raise_error("No Overleaf sync info found")
|
|
612
617
|
overleaf_sync_dirs = list(overleaf_info.keys())
|
|
613
618
|
if paths is not None:
|
|
614
|
-
paths = [
|
|
619
|
+
paths = [
|
|
620
|
+
(os.path.dirname(p) if os.path.isfile(p) else p)
|
|
621
|
+
.strip()
|
|
622
|
+
.rstrip("/\\")
|
|
623
|
+
for p in paths
|
|
624
|
+
]
|
|
615
625
|
for path in paths:
|
|
616
626
|
if path not in overleaf_sync_dirs:
|
|
617
627
|
raise_error(f"Path '{path}' is not synced with Overleaf")
|
|
@@ -13,6 +13,8 @@ import sys
|
|
|
13
13
|
from pathlib import Path
|
|
14
14
|
from typing import Literal
|
|
15
15
|
|
|
16
|
+
import pathspec
|
|
17
|
+
|
|
16
18
|
NotebookLanguage = Literal["python", "julia", "r"]
|
|
17
19
|
|
|
18
20
|
|
|
@@ -1549,6 +1551,20 @@ def _is_stdlib_module(module_name: str) -> bool:
|
|
|
1549
1551
|
return base_module in common_stdlib
|
|
1550
1552
|
|
|
1551
1553
|
|
|
1554
|
+
_PYTHON_IMPORT_TO_DISTRIBUTION = {
|
|
1555
|
+
"sklearn": "scikit-learn",
|
|
1556
|
+
"skimage": "scikit-image",
|
|
1557
|
+
"cv2": "opencv-python",
|
|
1558
|
+
"PIL": "Pillow",
|
|
1559
|
+
"bs4": "beautifulsoup4",
|
|
1560
|
+
"yaml": "PyYAML",
|
|
1561
|
+
"dateutil": "python-dateutil",
|
|
1562
|
+
"dotenv": "python-dotenv",
|
|
1563
|
+
"serial": "pyserial",
|
|
1564
|
+
"git": "GitPython",
|
|
1565
|
+
}
|
|
1566
|
+
|
|
1567
|
+
|
|
1552
1568
|
def detect_python_dependencies(
|
|
1553
1569
|
script_path: str | None = None,
|
|
1554
1570
|
code: str | None = None,
|
|
@@ -1614,13 +1630,21 @@ def detect_python_dependencies(
|
|
|
1614
1630
|
if not _is_stdlib_module(module_name):
|
|
1615
1631
|
# Get the top-level package name
|
|
1616
1632
|
top_level = module_name.split(".")[0]
|
|
1617
|
-
dependencies.add(
|
|
1633
|
+
dependencies.add(
|
|
1634
|
+
_PYTHON_IMPORT_TO_DISTRIBUTION.get(
|
|
1635
|
+
top_level, top_level
|
|
1636
|
+
)
|
|
1637
|
+
)
|
|
1618
1638
|
elif isinstance(node, ast.ImportFrom):
|
|
1619
1639
|
if node.module and node.level == 0:
|
|
1620
1640
|
module_name = node.module
|
|
1621
1641
|
if not _is_stdlib_module(module_name):
|
|
1622
1642
|
top_level = module_name.split(".")[0]
|
|
1623
|
-
dependencies.add(
|
|
1643
|
+
dependencies.add(
|
|
1644
|
+
_PYTHON_IMPORT_TO_DISTRIBUTION.get(
|
|
1645
|
+
top_level, top_level
|
|
1646
|
+
)
|
|
1647
|
+
)
|
|
1624
1648
|
return sorted(list(dependencies))
|
|
1625
1649
|
|
|
1626
1650
|
|
|
@@ -1927,6 +1951,21 @@ PRESENTATION_NAMES = {
|
|
|
1927
1951
|
"talk.pdf",
|
|
1928
1952
|
}
|
|
1929
1953
|
|
|
1954
|
+
DETECTION_IGNORE_FPATH = os.path.join(".calkit", "ignore")
|
|
1955
|
+
|
|
1956
|
+
|
|
1957
|
+
def load_detection_ignore(wdir: str | None = None) -> pathspec.PathSpec | None:
|
|
1958
|
+
"""Load ``.calkit/ignore`` artifact detection exclusions."""
|
|
1959
|
+
import pathspec
|
|
1960
|
+
|
|
1961
|
+
fpath = DETECTION_IGNORE_FPATH
|
|
1962
|
+
if wdir is not None:
|
|
1963
|
+
fpath = os.path.join(wdir, fpath)
|
|
1964
|
+
if not os.path.isfile(fpath):
|
|
1965
|
+
return None
|
|
1966
|
+
with open(fpath, encoding="utf-8") as f:
|
|
1967
|
+
return pathspec.PathSpec.from_lines("gitwildmatch", f)
|
|
1968
|
+
|
|
1930
1969
|
|
|
1931
1970
|
def _ancestor_dir_names(rel_path: str) -> set[str]:
|
|
1932
1971
|
"""Lower-cased names of the ancestor directories of a "/"-separated path."""
|
|
@@ -1938,8 +1977,12 @@ def _path_ext(rel_path: str) -> str:
|
|
|
1938
1977
|
return ("." + name.rsplit(".", 1)[-1].lower()) if "." in name else ""
|
|
1939
1978
|
|
|
1940
1979
|
|
|
1941
|
-
def is_figure_path(
|
|
1980
|
+
def is_figure_path(
|
|
1981
|
+
rel_path: str, *, ignore: pathspec.PathSpec | None = None
|
|
1982
|
+
) -> bool:
|
|
1942
1983
|
"""Whether a repo-relative path looks like an auto-detectable figure."""
|
|
1984
|
+
if ignore is not None and ignore.match_file(rel_path):
|
|
1985
|
+
return False
|
|
1943
1986
|
ancestors = _ancestor_dir_names(rel_path)
|
|
1944
1987
|
ext = _path_ext(rel_path)
|
|
1945
1988
|
if ext in FIGURE_EXTENSIONS and ancestors & FIGURE_DIRS:
|
|
@@ -1951,37 +1994,49 @@ def is_figure_path(rel_path: str) -> bool:
|
|
|
1951
1994
|
return False
|
|
1952
1995
|
|
|
1953
1996
|
|
|
1954
|
-
def is_dataset_path(
|
|
1997
|
+
def is_dataset_path(
|
|
1998
|
+
rel_path: str, *, ignore: pathspec.PathSpec | None = None
|
|
1999
|
+
) -> bool:
|
|
1955
2000
|
"""Whether a repo-relative path looks like an auto-detectable dataset."""
|
|
2001
|
+
if ignore is not None and ignore.match_file(rel_path):
|
|
2002
|
+
return False
|
|
1956
2003
|
return (
|
|
1957
2004
|
_path_ext(rel_path) in DATASET_EXTENSIONS
|
|
1958
2005
|
and bool(_ancestor_dir_names(rel_path) & DATA_DIRS)
|
|
1959
|
-
and not is_figure_path(rel_path)
|
|
2006
|
+
and not is_figure_path(rel_path, ignore=ignore)
|
|
1960
2007
|
)
|
|
1961
2008
|
|
|
1962
2009
|
|
|
1963
|
-
def is_result_path(
|
|
2010
|
+
def is_result_path(
|
|
2011
|
+
rel_path: str, *, ignore: pathspec.PathSpec | None = None
|
|
2012
|
+
) -> bool:
|
|
1964
2013
|
"""Whether a repo-relative path looks like an auto-detectable result.
|
|
1965
2014
|
|
|
1966
2015
|
A result is a data-like file (JSON, CSV, etc.) under a ``results``-style
|
|
1967
2016
|
directory. Anything already detected as a figure or dataset is excluded.
|
|
1968
2017
|
"""
|
|
2018
|
+
if ignore is not None and ignore.match_file(rel_path):
|
|
2019
|
+
return False
|
|
1969
2020
|
return (
|
|
1970
2021
|
_path_ext(rel_path) in RESULT_EXTENSIONS
|
|
1971
2022
|
and bool(_ancestor_dir_names(rel_path) & RESULT_DIRS)
|
|
1972
|
-
and not is_figure_path(rel_path)
|
|
1973
|
-
and not is_dataset_path(rel_path)
|
|
2023
|
+
and not is_figure_path(rel_path, ignore=ignore)
|
|
2024
|
+
and not is_dataset_path(rel_path, ignore=ignore)
|
|
1974
2025
|
)
|
|
1975
2026
|
|
|
1976
2027
|
|
|
1977
|
-
def is_presentation_path(
|
|
2028
|
+
def is_presentation_path(
|
|
2029
|
+
rel_path: str, *, ignore: pathspec.PathSpec | None = None
|
|
2030
|
+
) -> bool:
|
|
1978
2031
|
"""Whether a repo-relative path looks like an auto-detectable presentation.
|
|
1979
2032
|
|
|
1980
2033
|
Either a slide-deck file (PDF/PPTX/KEY) under a ``slides``/``presentations``
|
|
1981
2034
|
directory, or a file with a presentation-like name (e.g. ``slides.pdf``,
|
|
1982
2035
|
``presentation.pdf``) anywhere. Figures are excluded.
|
|
1983
2036
|
"""
|
|
1984
|
-
if
|
|
2037
|
+
if ignore is not None and ignore.match_file(rel_path):
|
|
2038
|
+
return False
|
|
2039
|
+
if is_figure_path(rel_path, ignore=ignore):
|
|
1985
2040
|
return False
|
|
1986
2041
|
name = rel_path.rsplit("/", 1)[-1].lower()
|
|
1987
2042
|
if name in PRESENTATION_NAMES:
|
|
@@ -2018,7 +2073,9 @@ PUBLICATION_NAMES = {
|
|
|
2018
2073
|
}
|
|
2019
2074
|
|
|
2020
2075
|
|
|
2021
|
-
def is_publication_path(
|
|
2076
|
+
def is_publication_path(
|
|
2077
|
+
rel_path: str, *, ignore: pathspec.PathSpec | None = None
|
|
2078
|
+
) -> bool:
|
|
2022
2079
|
"""Whether a repo-relative path looks like an auto-detectable publication.
|
|
2023
2080
|
|
|
2024
2081
|
Either a document (PDF/TeX/DOCX) under a ``paper``/``publication``/
|
|
@@ -2026,7 +2083,11 @@ def is_publication_path(rel_path: str) -> bool:
|
|
|
2026
2083
|
``manuscript.pdf``, ``main.tex``) anywhere. Figures and presentations are
|
|
2027
2084
|
excluded.
|
|
2028
2085
|
"""
|
|
2029
|
-
if
|
|
2086
|
+
if ignore is not None and ignore.match_file(rel_path):
|
|
2087
|
+
return False
|
|
2088
|
+
if is_figure_path(rel_path, ignore=ignore) or is_presentation_path(
|
|
2089
|
+
rel_path, ignore=ignore
|
|
2090
|
+
):
|
|
2030
2091
|
return False
|
|
2031
2092
|
name = rel_path.rsplit("/", 1)[-1].lower()
|
|
2032
2093
|
if name in PUBLICATION_NAMES:
|
|
@@ -2036,19 +2097,21 @@ def is_publication_path(rel_path: str) -> bool:
|
|
|
2036
2097
|
)
|
|
2037
2098
|
|
|
2038
2099
|
|
|
2039
|
-
def detect_artifact_kind(
|
|
2100
|
+
def detect_artifact_kind(
|
|
2101
|
+
rel_path: str, *, ignore: pathspec.PathSpec | None = None
|
|
2102
|
+
) -> str | None:
|
|
2040
2103
|
"""Infer an artifact's release kind from its repo-relative path.
|
|
2041
2104
|
|
|
2042
2105
|
Returns one of ``"figure"``, ``"presentation"``, ``"publication"``, or
|
|
2043
2106
|
``"dataset"``, or ``None`` if the path doesn't look like any of these.
|
|
2044
2107
|
"""
|
|
2045
|
-
if is_figure_path(rel_path):
|
|
2108
|
+
if is_figure_path(rel_path, ignore=ignore):
|
|
2046
2109
|
return "figure"
|
|
2047
|
-
if is_presentation_path(rel_path):
|
|
2110
|
+
if is_presentation_path(rel_path, ignore=ignore):
|
|
2048
2111
|
return "presentation"
|
|
2049
|
-
if is_publication_path(rel_path):
|
|
2112
|
+
if is_publication_path(rel_path, ignore=ignore):
|
|
2050
2113
|
return "publication"
|
|
2051
|
-
if is_dataset_path(rel_path):
|
|
2114
|
+
if is_dataset_path(rel_path, ignore=ignore):
|
|
2052
2115
|
return "dataset"
|
|
2053
2116
|
return None
|
|
2054
2117
|
|
|
@@ -2090,6 +2153,7 @@ def _collapse_dataset_folders(paths: list[str]) -> list[str]:
|
|
|
2090
2153
|
def detect_figures(
|
|
2091
2154
|
candidate_paths: list[str],
|
|
2092
2155
|
reserved_paths: list[str] | tuple[str, ...] = (),
|
|
2156
|
+
ignore: pathspec.PathSpec | None = None,
|
|
2093
2157
|
) -> list[str]:
|
|
2094
2158
|
"""Auto-detected figure paths among ``candidate_paths``.
|
|
2095
2159
|
|
|
@@ -2103,7 +2167,7 @@ def detect_figures(
|
|
|
2103
2167
|
for p in candidate_paths
|
|
2104
2168
|
if not _is_hidden_path(p)
|
|
2105
2169
|
and not _is_under_any_dir(p, reserved)
|
|
2106
|
-
and is_figure_path(p)
|
|
2170
|
+
and is_figure_path(p, ignore=ignore)
|
|
2107
2171
|
}
|
|
2108
2172
|
)
|
|
2109
2173
|
|
|
@@ -2112,6 +2176,7 @@ def detect_datasets(
|
|
|
2112
2176
|
candidate_paths: list[str],
|
|
2113
2177
|
reserved_paths: list[str] | tuple[str, ...] = (),
|
|
2114
2178
|
figure_paths: list[str] | tuple[str, ...] = (),
|
|
2179
|
+
ignore: pathspec.PathSpec | None = None,
|
|
2115
2180
|
) -> list[str]:
|
|
2116
2181
|
"""Auto-detected dataset paths among ``candidate_paths``.
|
|
2117
2182
|
|
|
@@ -2126,7 +2191,7 @@ def detect_datasets(
|
|
|
2126
2191
|
if not _is_hidden_path(p)
|
|
2127
2192
|
and not _is_under_any_dir(p, reserved)
|
|
2128
2193
|
and p not in figset
|
|
2129
|
-
and is_dataset_path(p)
|
|
2194
|
+
and is_dataset_path(p, ignore=ignore)
|
|
2130
2195
|
}
|
|
2131
2196
|
return _collapse_dataset_folders(sorted(files))
|
|
2132
2197
|
|
|
@@ -2134,6 +2199,7 @@ def detect_datasets(
|
|
|
2134
2199
|
def detect_results(
|
|
2135
2200
|
candidate_paths: list[str],
|
|
2136
2201
|
reserved_paths: list[str] | tuple[str, ...] = (),
|
|
2202
|
+
ignore: pathspec.PathSpec | None = None,
|
|
2137
2203
|
) -> list[str]:
|
|
2138
2204
|
"""Auto-detected result paths among ``candidate_paths``.
|
|
2139
2205
|
|
|
@@ -2147,7 +2213,7 @@ def detect_results(
|
|
|
2147
2213
|
for p in candidate_paths
|
|
2148
2214
|
if not _is_hidden_path(p)
|
|
2149
2215
|
and not _is_under_any_dir(p, reserved)
|
|
2150
|
-
and is_result_path(p)
|
|
2216
|
+
and is_result_path(p, ignore=ignore)
|
|
2151
2217
|
}
|
|
2152
2218
|
)
|
|
2153
2219
|
|
|
@@ -2155,6 +2221,7 @@ def detect_results(
|
|
|
2155
2221
|
def detect_presentations(
|
|
2156
2222
|
candidate_paths: list[str],
|
|
2157
2223
|
reserved_paths: list[str] | tuple[str, ...] = (),
|
|
2224
|
+
ignore: pathspec.PathSpec | None = None,
|
|
2158
2225
|
) -> list[str]:
|
|
2159
2226
|
"""Auto-detected presentation paths among ``candidate_paths``."""
|
|
2160
2227
|
reserved = list(reserved_paths)
|
|
@@ -2164,7 +2231,7 @@ def detect_presentations(
|
|
|
2164
2231
|
for p in candidate_paths
|
|
2165
2232
|
if not _is_hidden_path(p)
|
|
2166
2233
|
and not _is_under_any_dir(p, reserved)
|
|
2167
|
-
and is_presentation_path(p)
|
|
2234
|
+
and is_presentation_path(p, ignore=ignore)
|
|
2168
2235
|
}
|
|
2169
2236
|
)
|
|
2170
2237
|
|
|
@@ -2254,18 +2321,28 @@ def detect_project_artifacts(
|
|
|
2254
2321
|
|
|
2255
2322
|
if ck_info is None:
|
|
2256
2323
|
ck_info = calkit.load_calkit_info(wdir=wdir)
|
|
2324
|
+
ignore = load_detection_ignore(wdir=wdir)
|
|
2257
2325
|
reserved = _reserved_artifact_paths(wdir=wdir, ck_info=ck_info)
|
|
2258
2326
|
candidates = list(
|
|
2259
2327
|
dict.fromkeys(
|
|
2260
2328
|
[*list_repo_files(wdir=wdir), *list_dvc_tracked_files(wdir=wdir)]
|
|
2261
2329
|
)
|
|
2262
2330
|
)
|
|
2263
|
-
figures = detect_figures(
|
|
2331
|
+
figures = detect_figures(
|
|
2332
|
+
candidates, reserved_paths=reserved, ignore=ignore
|
|
2333
|
+
)
|
|
2264
2334
|
datasets = detect_datasets(
|
|
2265
|
-
candidates,
|
|
2335
|
+
candidates,
|
|
2336
|
+
reserved_paths=reserved,
|
|
2337
|
+
figure_paths=figures,
|
|
2338
|
+
ignore=ignore,
|
|
2339
|
+
)
|
|
2340
|
+
results = detect_results(
|
|
2341
|
+
candidates, reserved_paths=reserved, ignore=ignore
|
|
2342
|
+
)
|
|
2343
|
+
presentations = detect_presentations(
|
|
2344
|
+
candidates, reserved_paths=reserved, ignore=ignore
|
|
2266
2345
|
)
|
|
2267
|
-
results = detect_results(candidates, reserved_paths=reserved)
|
|
2268
|
-
presentations = detect_presentations(candidates, reserved_paths=reserved)
|
|
2269
2346
|
return {
|
|
2270
2347
|
"figures": figures,
|
|
2271
2348
|
"datasets": datasets,
|
|
@@ -499,6 +499,23 @@ def _sync_one(
|
|
|
499
499
|
# pipeline output that hasn't been produced yet on a fresh run)
|
|
500
500
|
if workspace_hash is None and zip_hash is None:
|
|
501
501
|
return None
|
|
502
|
+
# Workspace doesn't exist with no prior sync record while syncing to-zip —
|
|
503
|
+
# there's nothing to push into the zip (e.g., the zip was pulled but
|
|
504
|
+
# never unzipped into the workspace)
|
|
505
|
+
if (
|
|
506
|
+
workspace_hash is None
|
|
507
|
+
and last_sync_record is None
|
|
508
|
+
and direction == "to-zip"
|
|
509
|
+
):
|
|
510
|
+
return None
|
|
511
|
+
# Zip doesn't exist with no prior sync record while syncing to-workspace —
|
|
512
|
+
# there's nothing to pull into the workspace
|
|
513
|
+
if (
|
|
514
|
+
zip_hash is None
|
|
515
|
+
and last_sync_record is None
|
|
516
|
+
and direction == "to-workspace"
|
|
517
|
+
):
|
|
518
|
+
return None
|
|
502
519
|
# Deletion + change on the other side is a conflict
|
|
503
520
|
if workspace_deleted and zip_changed and direction == "both":
|
|
504
521
|
raise RuntimeError(
|
|
@@ -337,3 +337,32 @@ def ensure_path_is_not_ignored(
|
|
|
337
337
|
if target_repo.ignored(target_path) and _depth < 10:
|
|
338
338
|
ensure_path_is_not_ignored(target_repo, target_path, _depth + 1)
|
|
339
339
|
return True
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
def ensure_dvc_pointer_is_not_ignored(repo, path: str) -> None:
|
|
343
|
+
"""Ensure the .dvc pointer for ``path`` will not be Git-ignored.
|
|
344
|
+
|
|
345
|
+
A broad pattern in a ``.gitignore`` (e.g. ``*.pdf*``) can also match the
|
|
346
|
+
``<path>.dvc`` pointer DVC commits to Git, causing ``dvc add`` to fail with
|
|
347
|
+
"bad DVC file name ... is git-ignored". This appends a ``!*.dvc`` negation
|
|
348
|
+
to the ``.gitignore`` in the pointer's own directory (which wins under Git
|
|
349
|
+
precedence) so pointers stay tracked. Idempotent.
|
|
350
|
+
"""
|
|
351
|
+
path = path.replace("\\", "/").rstrip("/")
|
|
352
|
+
pointer = path + ".dvc"
|
|
353
|
+
if pointer not in repo.ignored(pointer):
|
|
354
|
+
return
|
|
355
|
+
pointer_dir = os.path.dirname(pointer)
|
|
356
|
+
gitignore_path = os.path.join(repo.working_dir, pointer_dir, ".gitignore")
|
|
357
|
+
exception = "!*.dvc"
|
|
358
|
+
existing_lines = []
|
|
359
|
+
if os.path.isfile(gitignore_path):
|
|
360
|
+
with open(gitignore_path, "r", encoding="utf-8") as f:
|
|
361
|
+
existing_lines = f.read().splitlines()
|
|
362
|
+
if exception in existing_lines:
|
|
363
|
+
return # Already present
|
|
364
|
+
os.makedirs(os.path.dirname(gitignore_path), exist_ok=True)
|
|
365
|
+
with open(gitignore_path, "a", encoding="utf-8") as f:
|
|
366
|
+
if existing_lines and existing_lines[-1] != "":
|
|
367
|
+
f.write("\n")
|
|
368
|
+
f.write(exception + "\n")
|
|
@@ -351,13 +351,23 @@ class ResultsEvidence(BaseModel):
|
|
|
351
351
|
explanation: str | None = None
|
|
352
352
|
|
|
353
353
|
|
|
354
|
+
class PublicationEvidence(BaseModel):
|
|
355
|
+
"""Evidence in the form of a publication."""
|
|
356
|
+
|
|
357
|
+
kind: Literal["publication"] = "publication"
|
|
358
|
+
path: str
|
|
359
|
+
explanation: str | None = None
|
|
360
|
+
|
|
361
|
+
|
|
354
362
|
class Question(BaseModel):
|
|
355
363
|
"""A question the project hopes to answer."""
|
|
356
364
|
|
|
357
365
|
question: str
|
|
358
366
|
hypothesis: str | None = None
|
|
359
367
|
answer: str | None = None
|
|
360
|
-
evidence:
|
|
368
|
+
evidence: (
|
|
369
|
+
list[FigureEvidence | ResultsEvidence | PublicationEvidence] | None
|
|
370
|
+
) = None
|
|
361
371
|
|
|
362
372
|
|
|
363
373
|
class Dependency(BaseModel):
|