calkit-python 0.36.0__tar.gz → 0.37.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (308) hide show
  1. {calkit_python-0.36.0 → calkit_python-0.37.0}/PKG-INFO +1 -1
  2. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/cli/main/core.py +172 -15
  3. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/core.py +6 -4
  4. calkit_python-0.37.0/calkit/dvc/zip.py +472 -0
  5. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/git.py +30 -2
  6. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/models/io.py +1 -1
  7. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/models/pipeline.py +5 -6
  8. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/pipeline.py +23 -6
  9. calkit_python-0.37.0/calkit/templates/latex/__init__.py +1 -0
  10. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/tests/cli/main/test_core.py +74 -0
  11. calkit_python-0.36.0/calkit/tests/test_dvc.py → calkit_python-0.37.0/calkit/tests/dvc/test_core.py +1 -1
  12. calkit_python-0.37.0/calkit/tests/dvc/test_zip.py +298 -0
  13. calkit_python-0.37.0/calkit/tests/models/__init__.py +0 -0
  14. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/tests/test_core.py +19 -0
  15. calkit_python-0.37.0/calkit/tests/test_git.py +387 -0
  16. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/tests/test_pipeline.py +11 -0
  17. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/cli-reference.md +43 -42
  18. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/tutorials/existing-project.md +6 -7
  19. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/version-control.md +51 -5
  20. calkit_python-0.36.0/calkit/tests/test_git.py +0 -199
  21. {calkit_python-0.36.0 → calkit_python-0.37.0}/.gitignore +0 -0
  22. {calkit_python-0.36.0 → calkit_python-0.37.0}/.pre-commit-config.yaml +0 -0
  23. {calkit_python-0.36.0 → calkit_python-0.37.0}/.prettierignore +0 -0
  24. {calkit_python-0.36.0 → calkit_python-0.37.0}/.python-version +0 -0
  25. {calkit_python-0.36.0 → calkit_python-0.37.0}/.vscode/launch.json +0 -0
  26. {calkit_python-0.36.0 → calkit_python-0.37.0}/.vscode/tasks.json +0 -0
  27. {calkit_python-0.36.0 → calkit_python-0.37.0}/.yarnrc.yml +0 -0
  28. {calkit_python-0.36.0 → calkit_python-0.37.0}/CITATION.cff +0 -0
  29. {calkit_python-0.36.0 → calkit_python-0.37.0}/CODE_OF_CONDUCT.md +0 -0
  30. {calkit_python-0.36.0 → calkit_python-0.37.0}/CONTRIBUTING.md +0 -0
  31. {calkit_python-0.36.0 → calkit_python-0.37.0}/LICENSE +0 -0
  32. {calkit_python-0.36.0 → calkit_python-0.37.0}/Makefile +0 -0
  33. {calkit_python-0.36.0 → calkit_python-0.37.0}/README.md +0 -0
  34. {calkit_python-0.36.0 → calkit_python-0.37.0}/babel.config.js +0 -0
  35. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/__init__.py +0 -0
  36. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/__main__.py +0 -0
  37. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/calc.py +0 -0
  38. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/check.py +0 -0
  39. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/cli/__init__.py +0 -0
  40. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/cli/check.py +0 -0
  41. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/cli/cloud.py +0 -0
  42. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/cli/config.py +0 -0
  43. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/cli/core.py +0 -0
  44. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/cli/describe.py +0 -0
  45. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/cli/import_.py +0 -0
  46. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/cli/latex.py +0 -0
  47. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/cli/list.py +0 -0
  48. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/cli/main/__init__.py +0 -0
  49. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/cli/main/xr.py +0 -0
  50. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/cli/new.py +0 -0
  51. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/cli/notebooks.py +0 -0
  52. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/cli/office.py +0 -0
  53. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/cli/overleaf.py +0 -0
  54. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/cli/slurm.py +0 -0
  55. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/cli/update.py +0 -0
  56. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/cloud.py +0 -0
  57. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/conda.py +0 -0
  58. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/config.py +0 -0
  59. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/datasets.py +0 -0
  60. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/detect.py +0 -0
  61. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/docker.py +0 -0
  62. {calkit_python-0.36.0/calkit/templates → calkit_python-0.37.0/calkit/dvc}/__init__.py +0 -0
  63. /calkit_python-0.36.0/calkit/dvc.py → /calkit_python-0.37.0/calkit/dvc/core.py +0 -0
  64. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/environments.py +0 -0
  65. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/fs.py +0 -0
  66. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/github.py +0 -0
  67. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/gui.py +0 -0
  68. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/invenio.py +0 -0
  69. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/julia.py +0 -0
  70. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/jupyter.py +0 -0
  71. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/jupyterlab/__init__.py +0 -0
  72. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/jupyterlab/routes.py +0 -0
  73. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/labextension/package.json +0 -0
  74. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/labextension/schemas/calkit/package.json.orig +0 -0
  75. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/labextension/schemas/calkit/plugin.json +0 -0
  76. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/labextension/static/502.9a2c5772a15466e923ef.js +0 -0
  77. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/labextension/static/695.2c41003a452d43d2b358.js +0 -0
  78. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/labextension/static/867.a42a046aa5108f54f8fb.js +0 -0
  79. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/labextension/static/909.651be47ca47390b78a92.js +0 -0
  80. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/labextension/static/946.050af2abf7845cfbdbd2.js +0 -0
  81. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/labextension/static/946.050af2abf7845cfbdbd2.js.LICENSE.txt +0 -0
  82. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/labextension/static/b2f1c3efe70cb539d121.png +0 -0
  83. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/labextension/static/remoteEntry.c091821b3d7f2d287a67.js +0 -0
  84. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/labextension/static/style.js +0 -0
  85. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/labextension/static/third-party-licenses.json +0 -0
  86. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/licenses.py +0 -0
  87. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/magics.py +0 -0
  88. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/matlab.py +0 -0
  89. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/models/__init__.py +0 -0
  90. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/models/core.py +0 -0
  91. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/models/iteration.py +0 -0
  92. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/notebooks.py +0 -0
  93. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/office.py +0 -0
  94. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/ops.py +0 -0
  95. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/overleaf.py +0 -0
  96. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/releases.py +0 -0
  97. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/server.py +0 -0
  98. {calkit_python-0.36.0/calkit/templates/latex → calkit_python-0.37.0/calkit/templates}/__init__.py +0 -0
  99. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/templates/core.py +0 -0
  100. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/templates/latex/article/paper.tex +0 -0
  101. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/templates/latex/core.py +0 -0
  102. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/templates/latex/jfm/jfm.bst +0 -0
  103. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/templates/latex/jfm/jfm.cls +0 -0
  104. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/templates/latex/jfm/lineno-FLM.sty +0 -0
  105. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/templates/latex/jfm/paper.tex +0 -0
  106. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/templates/latex/jfm/upmath.sty +0 -0
  107. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/tests/__init__.py +0 -0
  108. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/tests/cli/__init__.py +0 -0
  109. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/tests/cli/main/__init__.py +0 -0
  110. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/tests/cli/main/test_xr.py +0 -0
  111. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/tests/cli/test_check.py +0 -0
  112. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/tests/cli/test_config.py +0 -0
  113. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/tests/cli/test_import.py +0 -0
  114. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/tests/cli/test_latex.py +0 -0
  115. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/tests/cli/test_list.py +0 -0
  116. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/tests/cli/test_new.py +0 -0
  117. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/tests/cli/test_notebooks.py +0 -0
  118. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/tests/cli/test_overleaf.py +0 -0
  119. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/tests/cli/test_update.py +0 -0
  120. {calkit_python-0.36.0/calkit/tests/jupyterlab → calkit_python-0.37.0/calkit/tests/dvc}/__init__.py +0 -0
  121. {calkit_python-0.36.0/calkit/tests/models → calkit_python-0.37.0/calkit/tests/jupyterlab}/__init__.py +0 -0
  122. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/tests/jupyterlab/test_routes.py +0 -0
  123. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/tests/models/test_iteration.py +0 -0
  124. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/tests/models/test_pipeline.py +0 -0
  125. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/tests/test_calc.py +0 -0
  126. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/tests/test_check.py +0 -0
  127. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/tests/test_conda.py +0 -0
  128. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/tests/test_detect.py +0 -0
  129. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/tests/test_docker.py +0 -0
  130. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/tests/test_environments.py +0 -0
  131. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/tests/test_fs.py +0 -0
  132. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/tests/test_invenio.py +0 -0
  133. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/tests/test_julia.py +0 -0
  134. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/tests/test_jupyter.py +0 -0
  135. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/tests/test_magics.py +0 -0
  136. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/tests/test_matlab.py +0 -0
  137. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/tests/test_notebooks.py +0 -0
  138. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/tests/test_releases.py +0 -0
  139. {calkit_python-0.36.0 → calkit_python-0.37.0}/calkit/tests/test_templates.py +0 -0
  140. {calkit_python-0.36.0 → calkit_python-0.37.0}/conftest.py +0 -0
  141. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/CNAME +0 -0
  142. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/apps.md +0 -0
  143. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/calculations.md +0 -0
  144. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/calkit-yaml.md +0 -0
  145. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/cloud-integration.md +0 -0
  146. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/datasets.md +0 -0
  147. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/dependencies.md +0 -0
  148. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/environments.md +0 -0
  149. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/examples.md +0 -0
  150. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/governance.md +0 -0
  151. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/help.md +0 -0
  152. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/img/c-to-the-k-white.svg +0 -0
  153. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/img/calkit-fragmentation-compendium.png +0 -0
  154. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/img/calkit-no-bg.png +0 -0
  155. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/img/connect-zenodo.png +0 -0
  156. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/img/jupyterlab/all-green.png +0 -0
  157. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/img/jupyterlab/collect-data-stale.png +0 -0
  158. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/img/jupyterlab/new-env.png +0 -0
  159. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/img/jupyterlab/new-notebook.png +0 -0
  160. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/img/jupyterlab/pipeline-badge.png +0 -0
  161. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/img/jupyterlab-params.png +0 -0
  162. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/img/plos-osi-code-2024-03.png +0 -0
  163. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/img/vscode-nb-params.png +0 -0
  164. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/index.md +0 -0
  165. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/installation.md +0 -0
  166. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/jupyterlab.md +0 -0
  167. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/local-server.md +0 -0
  168. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/notebooks.md +0 -0
  169. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/overleaf.md +0 -0
  170. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/pipeline/index.md +0 -0
  171. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/pipeline/manual-steps.md +0 -0
  172. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/pipeline/running-and-logging.md +0 -0
  173. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/pipeline/slurm.md +0 -0
  174. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/quickstart.md +0 -0
  175. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/references.md +0 -0
  176. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/releases.md +0 -0
  177. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/reproducibility.md +0 -0
  178. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/tutorials/adding-latex-pub-docker.md +0 -0
  179. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/tutorials/conda-envs.md +0 -0
  180. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/tutorials/first-project.md +0 -0
  181. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/tutorials/github-actions.md +0 -0
  182. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/tutorials/img/actions-repo-secrets.png +0 -0
  183. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/tutorials/img/latex-codespaces/building-codespace.png +0 -0
  184. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/tutorials/img/latex-codespaces/codespaces-secrets-2.png +0 -0
  185. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/tutorials/img/latex-codespaces/editor-split.png +0 -0
  186. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/tutorials/img/latex-codespaces/go-to-linked-code.png +0 -0
  187. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/tutorials/img/latex-codespaces/issue-from-selection.png +0 -0
  188. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/tutorials/img/latex-codespaces/new-project.png +0 -0
  189. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/tutorials/img/latex-codespaces/new-pub-2.png +0 -0
  190. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/tutorials/img/latex-codespaces/new-token.png +0 -0
  191. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/tutorials/img/latex-codespaces/paper.tex.png +0 -0
  192. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/tutorials/img/latex-codespaces/project-home-3.png +0 -0
  193. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/tutorials/img/latex-codespaces/push.png +0 -0
  194. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/tutorials/img/latex-codespaces/stage.png +0 -0
  195. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/tutorials/img/office/anakin-excel.jpg +0 -0
  196. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/tutorials/img/office/chart-more-rows.png +0 -0
  197. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/tutorials/img/office/create-project.png +0 -0
  198. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/tutorials/img/office/elsevier-research-data-guidelines.png +0 -0
  199. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/tutorials/img/office/excel-chart.png +0 -0
  200. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/tutorials/img/office/excel-data.png +0 -0
  201. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/tutorials/img/office/insert-link-to-file.png +0 -0
  202. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/tutorials/img/office/needs-clone.png +0 -0
  203. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/tutorials/img/office/new-stage.png +0 -0
  204. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/tutorials/img/office/phd-comics-version-control.webp +0 -0
  205. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/tutorials/img/office/pipeline-out-of-date.png +0 -0
  206. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/tutorials/img/office/status-more-rows.png +0 -0
  207. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/tutorials/img/office/uncommitted-changes.png +0 -0
  208. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/tutorials/img/office/untracked-data.png +0 -0
  209. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/tutorials/img/office/updated-publication.png +0 -0
  210. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/tutorials/img/office/word-to-pdf-stage-2.png +0 -0
  211. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/tutorials/img/office/workflow-page.png +0 -0
  212. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/tutorials/img/openfoam/clone.png +0 -0
  213. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/tutorials/img/openfoam/create-project.png +0 -0
  214. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/tutorials/img/openfoam/datasets-page.png +0 -0
  215. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/tutorials/img/openfoam/figure-on-website-updated.png +0 -0
  216. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/tutorials/img/openfoam/figure-on-website.png +0 -0
  217. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/tutorials/img/openfoam/new-token.png +0 -0
  218. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/tutorials/img/openfoam/reclone.png +0 -0
  219. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/tutorials/img/openfoam/status-after-import-dataset.png +0 -0
  220. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/tutorials/img/quick-actions.png +0 -0
  221. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/tutorials/img/run-proc.png +0 -0
  222. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/tutorials/index.md +0 -0
  223. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/tutorials/jupyterlab.md +0 -0
  224. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/tutorials/latex-codespaces.md +0 -0
  225. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/tutorials/matlab.md +0 -0
  226. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/tutorials/notebook-pipeline.md +0 -0
  227. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/tutorials/office.md +0 -0
  228. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/tutorials/openfoam.md +0 -0
  229. {calkit_python-0.36.0 → calkit_python-0.37.0}/docs/tutorials/procedures.md +0 -0
  230. {calkit_python-0.36.0 → calkit_python-0.37.0}/install.json +0 -0
  231. {calkit_python-0.36.0 → calkit_python-0.37.0}/jest.config.js +0 -0
  232. {calkit_python-0.36.0 → calkit_python-0.37.0}/jupyter-config/server-config/calkit.json +0 -0
  233. {calkit_python-0.36.0 → calkit_python-0.37.0}/mkdocs.yml +0 -0
  234. {calkit_python-0.36.0 → calkit_python-0.37.0}/package.json +0 -0
  235. {calkit_python-0.36.0 → calkit_python-0.37.0}/pyproject.toml +0 -0
  236. {calkit_python-0.36.0 → calkit_python-0.37.0}/schema/plugin.json +0 -0
  237. {calkit_python-0.36.0 → calkit_python-0.37.0}/scripts/generate-cli-reference.py +0 -0
  238. {calkit_python-0.36.0 → calkit_python-0.37.0}/scripts/install.ps1 +0 -0
  239. {calkit_python-0.36.0 → calkit_python-0.37.0}/scripts/install.sh +0 -0
  240. {calkit_python-0.36.0 → calkit_python-0.37.0}/scripts/make-calk9.sh +0 -0
  241. {calkit_python-0.36.0 → calkit_python-0.37.0}/scripts/sync-docs.py +0 -0
  242. {calkit_python-0.36.0 → calkit_python-0.37.0}/src/__tests__/useQueries.spec.ts +0 -0
  243. {calkit_python-0.36.0 → calkit_python-0.37.0}/src/calkit-config.ts +0 -0
  244. {calkit_python-0.36.0 → calkit_python-0.37.0}/src/cell-output-marker.ts +0 -0
  245. {calkit_python-0.36.0 → calkit_python-0.37.0}/src/components/commit-dialog.tsx +0 -0
  246. {calkit_python-0.36.0 → calkit_python-0.37.0}/src/components/environment-editor.tsx +0 -0
  247. {calkit_python-0.36.0 → calkit_python-0.37.0}/src/components/notebook-registration.tsx +0 -0
  248. {calkit_python-0.36.0 → calkit_python-0.37.0}/src/components/notebook-toolbar.tsx +0 -0
  249. {calkit_python-0.36.0 → calkit_python-0.37.0}/src/components/pipeline-status-bar.tsx +0 -0
  250. {calkit_python-0.36.0 → calkit_python-0.37.0}/src/components/project-info-editor.tsx +0 -0
  251. {calkit_python-0.36.0 → calkit_python-0.37.0}/src/components/sidebar-settings.tsx +0 -0
  252. {calkit_python-0.36.0 → calkit_python-0.37.0}/src/components/sidebar.tsx +0 -0
  253. {calkit_python-0.36.0 → calkit_python-0.37.0}/src/components/stage-editor.tsx +0 -0
  254. {calkit_python-0.36.0 → calkit_python-0.37.0}/src/feature-flags.ts +0 -0
  255. {calkit_python-0.36.0 → calkit_python-0.37.0}/src/file-browser-menu.ts +0 -0
  256. {calkit_python-0.36.0 → calkit_python-0.37.0}/src/hooks/__tests__/useQueries.test.tsx +0 -0
  257. {calkit_python-0.36.0 → calkit_python-0.37.0}/src/hooks/useQueries.ts +0 -0
  258. {calkit_python-0.36.0 → calkit_python-0.37.0}/src/icons.ts +0 -0
  259. {calkit_python-0.36.0 → calkit_python-0.37.0}/src/index.ts +0 -0
  260. {calkit_python-0.36.0 → calkit_python-0.37.0}/src/io-tracker.ts +0 -0
  261. {calkit_python-0.36.0 → calkit_python-0.37.0}/src/pipeline-state.ts +0 -0
  262. {calkit_python-0.36.0 → calkit_python-0.37.0}/src/queryClient.ts +0 -0
  263. {calkit_python-0.36.0 → calkit_python-0.37.0}/src/request.ts +0 -0
  264. {calkit_python-0.36.0 → calkit_python-0.37.0}/src/shims-mainmenu.d.ts +0 -0
  265. {calkit_python-0.36.0 → calkit_python-0.37.0}/style/base.css +0 -0
  266. {calkit_python-0.36.0 → calkit_python-0.37.0}/style/cell-output-marker.css +0 -0
  267. {calkit_python-0.36.0 → calkit_python-0.37.0}/style/environment-editor.css +0 -0
  268. {calkit_python-0.36.0 → calkit_python-0.37.0}/style/environment-selector.css +0 -0
  269. {calkit_python-0.36.0 → calkit_python-0.37.0}/style/img/calkit-no-bg.png +0 -0
  270. {calkit_python-0.36.0 → calkit_python-0.37.0}/style/index.css +0 -0
  271. {calkit_python-0.36.0 → calkit_python-0.37.0}/style/index.js +0 -0
  272. {calkit_python-0.36.0 → calkit_python-0.37.0}/style/notebook-toolbar.css +0 -0
  273. {calkit_python-0.36.0 → calkit_python-0.37.0}/style/pipeline-status-bar.css +0 -0
  274. {calkit_python-0.36.0 → calkit_python-0.37.0}/style/sidebar.css +0 -0
  275. {calkit_python-0.36.0 → calkit_python-0.37.0}/test/dvc-md5-dir/osx-arm64.txt +0 -0
  276. {calkit_python-0.36.0 → calkit_python-0.37.0}/test/nb-julia.ipynb +0 -0
  277. {calkit_python-0.36.0 → calkit_python-0.37.0}/test/nb-params.ipynb +0 -0
  278. {calkit_python-0.36.0 → calkit_python-0.37.0}/test/nb-subdir.ipynb +0 -0
  279. {calkit_python-0.36.0 → calkit_python-0.37.0}/test/pipeline.ipynb +0 -0
  280. {calkit_python-0.36.0 → calkit_python-0.37.0}/test/script.py +0 -0
  281. {calkit_python-0.36.0 → calkit_python-0.37.0}/test/test-log.log +0 -0
  282. {calkit_python-0.36.0 → calkit_python-0.37.0}/tsconfig.json +0 -0
  283. {calkit_python-0.36.0 → calkit_python-0.37.0}/tsconfig.test.json +0 -0
  284. {calkit_python-0.36.0 → calkit_python-0.37.0}/ui-tests/.gitignore +0 -0
  285. {calkit_python-0.36.0 → calkit_python-0.37.0}/ui-tests/README.md +0 -0
  286. {calkit_python-0.36.0 → calkit_python-0.37.0}/ui-tests/jupyter_server_test_config.py +0 -0
  287. {calkit_python-0.36.0 → calkit_python-0.37.0}/ui-tests/package.json +0 -0
  288. {calkit_python-0.36.0 → calkit_python-0.37.0}/ui-tests/playwright.config.js +0 -0
  289. {calkit_python-0.36.0 → calkit_python-0.37.0}/ui-tests/tests/calkit.spec.ts +0 -0
  290. {calkit_python-0.36.0 → calkit_python-0.37.0}/ui-tests/yarn.lock +0 -0
  291. {calkit_python-0.36.0 → calkit_python-0.37.0}/uv.lock +0 -0
  292. {calkit_python-0.36.0 → calkit_python-0.37.0}/vscode-ext/.gitignore +0 -0
  293. {calkit_python-0.36.0 → calkit_python-0.37.0}/vscode-ext/.vscodeignore +0 -0
  294. {calkit_python-0.36.0 → calkit_python-0.37.0}/vscode-ext/CHANGELOG.md +0 -0
  295. {calkit_python-0.36.0 → calkit_python-0.37.0}/vscode-ext/LICENSE +0 -0
  296. {calkit_python-0.36.0 → calkit_python-0.37.0}/vscode-ext/README.md +0 -0
  297. {calkit_python-0.36.0 → calkit_python-0.37.0}/vscode-ext/images/calkit-no-bg.png +0 -0
  298. {calkit_python-0.36.0 → calkit_python-0.37.0}/vscode-ext/package-lock.json +0 -0
  299. {calkit_python-0.36.0 → calkit_python-0.37.0}/vscode-ext/package.json +0 -0
  300. {calkit_python-0.36.0 → calkit_python-0.37.0}/vscode-ext/scripts/set-proposed-api.js +0 -0
  301. {calkit_python-0.36.0 → calkit_python-0.37.0}/vscode-ext/src/environments.ts +0 -0
  302. {calkit_python-0.36.0 → calkit_python-0.37.0}/vscode-ext/src/extension.ts +0 -0
  303. {calkit_python-0.36.0 → calkit_python-0.37.0}/vscode-ext/src/notebooks.ts +0 -0
  304. {calkit_python-0.36.0 → calkit_python-0.37.0}/vscode-ext/src/test/environments.test.ts +0 -0
  305. {calkit_python-0.36.0 → calkit_python-0.37.0}/vscode-ext/src/test/notebooks.test.ts +0 -0
  306. {calkit_python-0.36.0 → calkit_python-0.37.0}/vscode-ext/src/types.ts +0 -0
  307. {calkit_python-0.36.0 → calkit_python-0.37.0}/vscode-ext/tsconfig.json +0 -0
  308. {calkit_python-0.36.0 → calkit_python-0.37.0}/yarn.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: calkit-python
3
- Version: 0.36.0
3
+ Version: 0.37.0
4
4
  Summary: Reproducibility simplified.
5
5
  Project-URL: Homepage, https://calkit.org
6
6
  Project-URL: Issues, https://github.com/calkit/calkit/issues
@@ -25,6 +25,7 @@ from git.exc import InvalidGitRepositoryError
25
25
  from typing_extensions import Annotated, Optional
26
26
 
27
27
  import calkit
28
+ import calkit.dvc.zip
28
29
  import calkit.matlab
29
30
  import calkit.pipeline
30
31
  from calkit import (
@@ -225,6 +226,69 @@ def clone(
225
226
  raise_error("Failed to pull from DVC remote(s)")
226
227
  except Exception as e:
227
228
  raise_error(f"Failed to pull from DVC remote(s): {e}")
229
+ calkit.dvc.zip.sync_all(direction="to-workspace")
230
+
231
+
232
+ def _format_dvc_data_status(status: dict, zip_path_map: dict) -> str:
233
+ """Format DVC data status, substituting zip paths with workspace paths."""
234
+ reverse_zip = {zip_p: ws for ws, zip_p in zip_path_map.items()}
235
+ color_map = {
236
+ "added": typer.colors.GREEN,
237
+ "modified": typer.colors.YELLOW,
238
+ "deleted": typer.colors.RED,
239
+ "renamed": typer.colors.CYAN,
240
+ }
241
+
242
+ def transform(path: str) -> str | None:
243
+ if path in reverse_zip:
244
+ return reverse_zip[path] + " (zipped)"
245
+ return path
246
+
247
+ def format_section(changes: dict, title: str) -> list[str]:
248
+ entries = []
249
+ for change_type, color in color_map.items():
250
+ for item in changes.get(change_type, []):
251
+ if isinstance(item, dict):
252
+ old = transform(item.get("old", ""))
253
+ new = transform(item.get("new", ""))
254
+ if old is not None and new is not None:
255
+ line = typer.style(
256
+ f" {change_type}: {old} -> {new}", fg=color
257
+ )
258
+ entries.append(line)
259
+ else:
260
+ display = transform(item)
261
+ if display is not None:
262
+ line = typer.style(
263
+ f" {change_type}: {display}", fg=color
264
+ )
265
+ entries.append(line)
266
+ if not entries:
267
+ return []
268
+ return [title] + entries
269
+
270
+ lines = []
271
+ lines += format_section(
272
+ status.get("committed", {}), "DVC committed changes:"
273
+ )
274
+ lines += format_section(
275
+ status.get("uncommitted", {}), "DVC uncommitted changes:"
276
+ )
277
+ not_in_cache = [transform(p) for p in status.get("not_in_cache", [])]
278
+ not_in_cache = [p for p in not_in_cache if p is not None]
279
+ if not_in_cache:
280
+ lines.append(typer.style("Files not in cache:", bold=True))
281
+ for p in not_in_cache:
282
+ lines.append(f" {p}")
283
+ not_in_remote = [transform(p) for p in status.get("not_in_remote", [])]
284
+ not_in_remote = [p for p in not_in_remote if p is not None]
285
+ if not_in_remote:
286
+ lines.append(typer.style("Files not in remote:", bold=True))
287
+ for p in not_in_remote:
288
+ lines.append(f" {p}")
289
+ if not lines:
290
+ return "No changes.\n"
291
+ return "\n".join(lines) + "\n"
228
292
 
229
293
 
230
294
  @app.command(name="status")
@@ -273,6 +337,9 @@ def get_status(
273
337
  categories = valid_categories
274
338
  pipeline_status = None
275
339
  if "pipeline" in categories or "dvc" in categories:
340
+ # Sync zips so the zip files reflect current workspace state before
341
+ # reporting status
342
+ calkit.dvc.zip.sync_all(direction="to-zip")
276
343
  pipeline_status = calkit.pipeline.get_status(
277
344
  ck_info=ck_info,
278
345
  targets=targets,
@@ -388,11 +455,16 @@ def get_status(
388
455
  typer.echo()
389
456
  if "dvc" in categories:
390
457
  print_sep("DVC")
391
- dvc_data_cmd = ["data", "status"]
392
- if targets:
393
- dvc_data_cmd += targets
394
- run_dvc_command(dvc_data_cmd)
395
- typer.echo()
458
+ try:
459
+ get_dvc_repo()
460
+ except Exception:
461
+ typer.echo("This is not a DVC repository.\n")
462
+ else:
463
+ zip_path_map = calkit.dvc.zip.get_zip_path_map()
464
+ dvc_repo = get_dvc_repo()
465
+ raw = dict(dvc_repo.data_status())
466
+ raw.pop("git", None)
467
+ typer.echo(_format_dvc_data_status(raw, zip_path_map))
396
468
  if "pipeline" in categories or "dvc" in categories:
397
469
  print_sep("Pipeline")
398
470
  # Nicely format the results from pipeline status
@@ -403,26 +475,29 @@ def get_status(
403
475
  typer.echo("This project has no pipeline.")
404
476
  return
405
477
  elif pipeline_status and pipeline_status.is_stale:
478
+ typer.echo("Stale stages:")
406
479
  for stage_name in pipeline_status.stale_stage_names:
407
480
  stale_stage = pipeline_status.stale_stages.get(stage_name)
408
481
  if stale_stage is None:
409
482
  continue
410
- typer.echo(f"{typer.style(stage_name, fg='yellow')}:")
483
+ typer.echo(f" {typer.style(stage_name, fg='yellow')}:")
484
+ if stale_stage.modified_command:
485
+ typer.echo(" modified command")
411
486
  # Show stale outputs for this stage
412
487
  if stale_stage.stale_outputs:
413
- typer.echo(" stale outputs:")
488
+ typer.echo(" stale outputs:")
414
489
  for output_path in stale_stage.stale_outputs:
415
- typer.echo(f" {output_path}")
490
+ typer.echo(f" {output_path}")
416
491
  # Show modified outputs from this stage
417
492
  if stale_stage.modified_outputs:
418
- typer.echo(" modified outputs:")
493
+ typer.echo(" modified outputs:")
419
494
  for output_path in stale_stage.modified_outputs:
420
- typer.echo(f" {output_path}")
495
+ typer.echo(f" {output_path}")
421
496
  # Show modified inputs making the stage stale
422
497
  if stale_stage.modified_inputs:
423
- typer.echo(" modified inputs:")
498
+ typer.echo(" modified inputs:")
424
499
  for input_path in stale_stage.modified_inputs:
425
- typer.echo(f" {input_path}")
500
+ typer.echo(f" {input_path}")
426
501
  elif pipeline_status:
427
502
  typer.echo("Pipeline is up to date.")
428
503
 
@@ -474,7 +549,9 @@ def add(
474
549
  to: Annotated[
475
550
  str | None,
476
551
  typer.Option(
477
- "--to", "-t", help="System with which to add (git or dvc)."
552
+ "--to",
553
+ "-t",
554
+ help="System with which to add (git, dvc, or dvc-zip).",
478
555
  ),
479
556
  ] = None,
480
557
  ):
@@ -500,7 +577,7 @@ def add(
500
577
  raise_error(
501
578
  "Cannot auto-generate commit message for more than one path"
502
579
  )
503
- if to is not None and to not in ["git", "dvc"]:
580
+ if to is not None and to not in ["git", "dvc", "dvc-zip"]:
504
581
  raise_error(f"Invalid option for 'to': {to}")
505
582
  try:
506
583
  repo = git.Repo()
@@ -543,6 +620,10 @@ def add(
543
620
  subprocess.call(["git", "add"] + paths)
544
621
  elif to == "dvc":
545
622
  run_dvc_command(["add"] + paths)
623
+ elif to == "dvc-zip":
624
+ for path in paths:
625
+ typer.echo(f"Adding {path} as a DVC zip")
626
+ calkit.dvc.zip.add(path)
546
627
  else:
547
628
  raise_error(f"Invalid option for 'to': {to}")
548
629
  else:
@@ -591,7 +672,14 @@ def add(
591
672
  d.a_path for d in repo.index.diff(None) if d.a_path is not None
592
673
  ]:
593
674
  paths.append(changed_file)
675
+ zip_path_map = calkit.dvc.zip.get_zip_path_map()
594
676
  for path in paths:
677
+ # Check if this path is already registered as a zip
678
+ posix_path = Path(path).as_posix()
679
+ if posix_path in zip_path_map:
680
+ typer.echo(f"Adding {path} via DVC zip")
681
+ calkit.dvc.zip.add(path)
682
+ continue
595
683
  # Detect if this file should be tracked with Git or DVC
596
684
  # First see if it's in Git
597
685
  if repo.git.ls_files(path):
@@ -607,6 +695,12 @@ def add(
607
695
  elif os.path.splitext(path)[-1] in DVC_EXTENSIONS:
608
696
  typer.echo(f"Adding {path} to DVC per its extension")
609
697
  run_dvc_command(["add", path])
698
+ elif calkit.dvc.zip.is_zip_candidate(path):
699
+ typer.echo(
700
+ f"Adding {path} as a DVC zip "
701
+ "(large directory of small files)"
702
+ )
703
+ calkit.dvc.zip.add(path)
610
704
  elif calkit.get_size(path) > DVC_SIZE_THRESH_BYTES:
611
705
  typer.echo(
612
706
  f"Adding {path} to DVC since it's greater than 1 MB"
@@ -842,6 +936,7 @@ def pull(
842
936
  result = run_dvc_command(["pull"] + dvc_args)
843
937
  if result != 0:
844
938
  raise_error("DVC pull failed")
939
+ calkit.dvc.zip.sync_all(direction="to-workspace")
845
940
 
846
941
 
847
942
  @app.command(name="push")
@@ -1177,6 +1272,7 @@ def run(
1177
1272
  import dvc.ui
1178
1273
  from dvc.cli import main as dvc_cli_main
1179
1274
 
1275
+ import calkit.dvc.zip
1180
1276
  import calkit.environments
1181
1277
  import calkit.pipeline
1182
1278
  from calkit.cli.overleaf import sync as overleaf_sync
@@ -1376,10 +1472,38 @@ def run(
1376
1472
  dvc.ui.ui.write = lambda *args, **kwargs: None
1377
1473
  res = dvc_cli_main(["repro"] + args)
1378
1474
  failed = res != 0
1379
- # Parse log to get timing
1475
+ # Parse log to get timing and which stages ran
1380
1476
  with open(log_fpath, "r") as f:
1381
1477
  log_content = f.read()
1382
1478
  stage_run_info = _stage_run_info_from_log_content(log_content)
1479
+ # Zip dvc-zip outputs for stages that actually ran
1480
+ if stage_run_info:
1481
+ from calkit.models.io import PathOutput
1482
+ from calkit.models.pipeline import Pipeline
1483
+
1484
+ ck_info = calkit.load_calkit_info()
1485
+ pipeline_cfg = ck_info.get("pipeline", {})
1486
+ if pipeline_cfg:
1487
+ try:
1488
+ ck_pipeline = Pipeline.model_validate(pipeline_cfg)
1489
+ zip_input_paths = []
1490
+ for stage_name in stage_run_info:
1491
+ stage = ck_pipeline.stages.get(stage_name)
1492
+ if stage is None:
1493
+ continue
1494
+ for out in stage.outputs:
1495
+ if (
1496
+ isinstance(out, PathOutput)
1497
+ and out.storage == "dvc-zip"
1498
+ ):
1499
+ zip_input_paths.append(out.path)
1500
+ if zip_input_paths:
1501
+ calkit.dvc.zip.sync_some(
1502
+ zip_input_paths, direction="to-zip"
1503
+ )
1504
+ except Exception:
1505
+ # Fall back to syncing all zips if pipeline parsing fails
1506
+ calkit.dvc.zip.sync_all(direction="to-zip")
1383
1507
  # Close logger file handler to prevent permissions issues if deleting
1384
1508
  dvc.log.logger.removeHandler(file_handler)
1385
1509
  file_handler.close()
@@ -2245,6 +2369,39 @@ def switch_branch(name: Annotated[str, typer.Argument(help="Branch name.")]):
2245
2369
  else:
2246
2370
  cmd = [name]
2247
2371
  repo.git.checkout(cmd)
2372
+ # After switching branches, DVC-tracked zips may have changed; check out
2373
+ # the new branch's DVC data and unzip to the workspace
2374
+ run_dvc_command(["checkout"])
2375
+ calkit.dvc.zip.sync_all(direction="to-workspace")
2376
+
2377
+
2378
+ @app.command(name="stash")
2379
+ def stash(
2380
+ pop: Annotated[
2381
+ bool, typer.Option("--pop", help="Pop the most recent stash.")
2382
+ ] = False,
2383
+ ):
2384
+ """Stash or restore workspace changes including dvc-zip tracked dirs.
2385
+
2386
+ Without --pop: zips any modified workspace dirs into the DVC cache, then
2387
+ git-stashes (saving the updated .dvc files), checks out the committed DVC
2388
+ state, and unzips it to the workspace.
2389
+
2390
+ With --pop: pops the git stash (restoring the saved .dvc files), checks
2391
+ out the stashed DVC state, and unzips it to the workspace.
2392
+ """
2393
+ if pop:
2394
+ subprocess.check_call(["git", "stash", "pop"])
2395
+ run_dvc_command(["checkout"])
2396
+ calkit.dvc.zip.sync_all(direction="to-workspace")
2397
+ else:
2398
+ # Zip any modified workspace dirs so their current state is in the DVC
2399
+ # cache (the updated .dvc file will be captured by git stash)
2400
+ calkit.dvc.zip.sync_all(direction="to-zip")
2401
+ subprocess.check_call(["git", "stash"])
2402
+ # Restore the committed zip versions and unzip them
2403
+ run_dvc_command(["checkout"])
2404
+ calkit.dvc.zip.sync_all(direction="to-workspace")
2248
2405
 
2249
2406
 
2250
2407
  @app.command(
@@ -647,10 +647,12 @@ def get_system_info() -> dict:
647
647
  def get_md5(path: str, exclude_files: list[str] | None = None) -> str:
648
648
  if os.path.isdir(path):
649
649
  return checksumdir.dirhash(path, excluded_files=exclude_files)
650
- else:
651
- with open(path) as f:
652
- content = f.read()
653
- return hashlib.md5(content.encode()).hexdigest()
650
+ hasher = hashlib.md5()
651
+ with open(path, "rb") as f:
652
+ # Read the file in chunks to avoid memory issues with large files
653
+ for chunk in iter(lambda: f.read(4096), b""):
654
+ hasher.update(chunk)
655
+ return hasher.hexdigest()
654
656
 
655
657
 
656
658
  def set_env_vars(ck_info: dict, cli: bool = True) -> None: