calkit-python 0.41.13__tar.gz → 0.41.15__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 (350) hide show
  1. {calkit_python-0.41.13 → calkit_python-0.41.15}/AGENTS.md +3 -0
  2. {calkit_python-0.41.13 → calkit_python-0.41.15}/PKG-INFO +1 -1
  3. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/cli/check.py +5 -2
  4. calkit_python-0.41.15/calkit/cli/delete.py +33 -0
  5. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/cli/list.py +56 -1
  6. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/cli/main/core.py +38 -6
  7. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/cli/new.py +98 -1
  8. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/cli/notebooks.py +17 -10
  9. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/cli/scheduler.py +20 -0
  10. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/cli/update.py +1 -1
  11. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/core.py +7 -3
  12. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/detect.py +103 -2
  13. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/dvc/core.py +133 -57
  14. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/julia.py +29 -2
  15. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/models/core.py +58 -5
  16. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/notebooks.py +1 -3
  17. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/pipeline.py +57 -8
  18. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/tests/cli/main/test_core.py +103 -45
  19. calkit_python-0.41.15/calkit/tests/cli/main/test_lock.py +274 -0
  20. calkit_python-0.41.15/calkit/tests/cli/test_delete.py +23 -0
  21. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/tests/cli/test_list.py +46 -0
  22. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/tests/cli/test_new.py +48 -0
  23. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/tests/cli/test_scheduler.py +4 -0
  24. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/tests/dvc/test_core.py +17 -36
  25. calkit_python-0.41.15/calkit/tests/models/test_core.py +25 -0
  26. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/tests/test_core.py +15 -0
  27. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/tests/test_detect.py +67 -0
  28. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/tests/test_julia.py +46 -0
  29. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/tests/test_pipeline.py +49 -0
  30. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/cli-reference.md +160 -14
  31. calkit_python-0.41.15/vscode-ext/README.md +148 -0
  32. {calkit_python-0.41.13 → calkit_python-0.41.15}/vscode-ext/package.json +200 -2
  33. {calkit_python-0.41.13 → calkit_python-0.41.15}/vscode-ext/src/extension.ts +962 -528
  34. calkit_python-0.41.15/vscode-ext/src/figures/core.ts +93 -0
  35. calkit_python-0.41.15/vscode-ext/src/figures/view.ts +474 -0
  36. calkit_python-0.41.15/vscode-ext/src/pipeline/core.ts +81 -0
  37. {calkit_python-0.41.13 → calkit_python-0.41.15}/vscode-ext/src/sidebar.ts +478 -146
  38. calkit_python-0.41.15/vscode-ext/src/test/figures.test.ts +96 -0
  39. calkit_python-0.41.15/vscode-ext/src/test/pipeline.test.ts +61 -0
  40. {calkit_python-0.41.13 → calkit_python-0.41.15}/vscode-ext/src/types.ts +43 -0
  41. calkit_python-0.41.13/vscode-ext/README.md +0 -66
  42. {calkit_python-0.41.13 → calkit_python-0.41.15}/.claude-plugin/marketplace.json +0 -0
  43. {calkit_python-0.41.13 → calkit_python-0.41.15}/.gitattributes +0 -0
  44. {calkit_python-0.41.13 → calkit_python-0.41.15}/.gitignore +0 -0
  45. {calkit_python-0.41.13 → calkit_python-0.41.15}/.pre-commit-config.yaml +0 -0
  46. {calkit_python-0.41.13 → calkit_python-0.41.15}/.prettierignore +0 -0
  47. {calkit_python-0.41.13 → calkit_python-0.41.15}/.python-version +0 -0
  48. {calkit_python-0.41.13 → calkit_python-0.41.15}/.vscode/launch.json +0 -0
  49. {calkit_python-0.41.13 → calkit_python-0.41.15}/.vscode/tasks.json +0 -0
  50. {calkit_python-0.41.13 → calkit_python-0.41.15}/.yarnrc.yml +0 -0
  51. {calkit_python-0.41.13 → calkit_python-0.41.15}/CITATION.cff +0 -0
  52. {calkit_python-0.41.13 → calkit_python-0.41.15}/CODE_OF_CONDUCT.md +0 -0
  53. {calkit_python-0.41.13 → calkit_python-0.41.15}/CONTRIBUTING.md +0 -0
  54. {calkit_python-0.41.13 → calkit_python-0.41.15}/LICENSE +0 -0
  55. {calkit_python-0.41.13 → calkit_python-0.41.15}/Makefile +0 -0
  56. {calkit_python-0.41.13 → calkit_python-0.41.15}/README.md +0 -0
  57. {calkit_python-0.41.13 → calkit_python-0.41.15}/agent-plugin/.claude-plugin/plugin.json +0 -0
  58. {calkit_python-0.41.13 → calkit_python-0.41.15}/agent-plugin/skills/add-pipeline-stage/SKILL.md +0 -0
  59. {calkit_python-0.41.13 → calkit_python-0.41.15}/agent-plugin/skills/conventions/SKILL.md +0 -0
  60. {calkit_python-0.41.13 → calkit_python-0.41.15}/agent-plugin/skills/create-pipeline/SKILL.md +0 -0
  61. {calkit_python-0.41.13 → calkit_python-0.41.15}/babel.config.js +0 -0
  62. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/__init__.py +0 -0
  63. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/__main__.py +0 -0
  64. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/calc.py +0 -0
  65. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/check.py +0 -0
  66. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/cli/__init__.py +0 -0
  67. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/cli/cloud.py +0 -0
  68. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/cli/config.py +0 -0
  69. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/cli/core.py +0 -0
  70. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/cli/describe.py +0 -0
  71. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/cli/dev.py +0 -0
  72. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/cli/import_.py +0 -0
  73. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/cli/latex.py +0 -0
  74. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/cli/main/__init__.py +0 -0
  75. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/cli/main/xr.py +0 -0
  76. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/cli/office.py +0 -0
  77. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/cli/overleaf.py +0 -0
  78. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/cloud.py +0 -0
  79. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/conda.py +0 -0
  80. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/config.py +0 -0
  81. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/datasets.py +0 -0
  82. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/dependencies.py +0 -0
  83. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/docker.py +0 -0
  84. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/dvc/__init__.py +0 -0
  85. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/dvc/zip.py +0 -0
  86. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/environments.py +0 -0
  87. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/fs.py +0 -0
  88. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/git.py +0 -0
  89. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/github.py +0 -0
  90. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/gui.py +0 -0
  91. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/install.py +0 -0
  92. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/invenio.py +0 -0
  93. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/jupyter.py +0 -0
  94. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/jupyterlab/__init__.py +0 -0
  95. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/jupyterlab/routes.py +0 -0
  96. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/labextension/package.json +0 -0
  97. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/labextension/schemas/calkit/package.json.orig +0 -0
  98. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/labextension/schemas/calkit/plugin.json +0 -0
  99. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/labextension/static/502.9a2c5772a15466e923ef.js +0 -0
  100. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/labextension/static/695.2c41003a452d43d2b358.js +0 -0
  101. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/labextension/static/867.a42a046aa5108f54f8fb.js +0 -0
  102. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/labextension/static/909.e3f9cc3408834a7fdcc3.js +0 -0
  103. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/labextension/static/946.050af2abf7845cfbdbd2.js +0 -0
  104. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/labextension/static/946.050af2abf7845cfbdbd2.js.LICENSE.txt +0 -0
  105. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/labextension/static/b2f1c3efe70cb539d121.png +0 -0
  106. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/labextension/static/remoteEntry.65469af996e7a96aa983.js +0 -0
  107. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/labextension/static/style.js +0 -0
  108. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/labextension/static/third-party-licenses.json +0 -0
  109. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/licenses.py +0 -0
  110. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/magics.py +0 -0
  111. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/matlab.py +0 -0
  112. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/models/__init__.py +0 -0
  113. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/models/io.py +0 -0
  114. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/models/iteration.py +0 -0
  115. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/models/pipeline.py +0 -0
  116. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/office.py +0 -0
  117. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/ops.py +0 -0
  118. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/overleaf.py +0 -0
  119. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/releases.py +0 -0
  120. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/server.py +0 -0
  121. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/templates/__init__.py +0 -0
  122. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/templates/core.py +0 -0
  123. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/templates/latex/__init__.py +0 -0
  124. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/templates/latex/article/paper.tex +0 -0
  125. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/templates/latex/core.py +0 -0
  126. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/templates/latex/jfm/jfm.bst +0 -0
  127. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/templates/latex/jfm/jfm.cls +0 -0
  128. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/templates/latex/jfm/lineno-FLM.sty +0 -0
  129. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/templates/latex/jfm/paper.tex +0 -0
  130. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/templates/latex/jfm/upmath.sty +0 -0
  131. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/tests/__init__.py +0 -0
  132. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/tests/cli/__init__.py +0 -0
  133. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/tests/cli/main/__init__.py +0 -0
  134. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/tests/cli/main/test_subprojects.py +0 -0
  135. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/tests/cli/main/test_xr.py +0 -0
  136. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/tests/cli/test_check.py +0 -0
  137. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/tests/cli/test_cloud.py +0 -0
  138. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/tests/cli/test_config.py +0 -0
  139. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/tests/cli/test_import.py +0 -0
  140. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/tests/cli/test_latex.py +0 -0
  141. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/tests/cli/test_notebooks.py +0 -0
  142. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/tests/cli/test_overleaf.py +0 -0
  143. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/tests/cli/test_update.py +0 -0
  144. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/tests/dvc/__init__.py +0 -0
  145. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/tests/dvc/test_zip.py +0 -0
  146. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/tests/jupyterlab/__init__.py +0 -0
  147. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/tests/jupyterlab/test_routes.py +0 -0
  148. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/tests/models/__init__.py +0 -0
  149. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/tests/models/test_iteration.py +0 -0
  150. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/tests/models/test_pipeline.py +0 -0
  151. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/tests/test_calc.py +0 -0
  152. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/tests/test_check.py +0 -0
  153. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/tests/test_cloud.py +0 -0
  154. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/tests/test_conda.py +0 -0
  155. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/tests/test_dependencies.py +0 -0
  156. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/tests/test_docker.py +0 -0
  157. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/tests/test_environments.py +0 -0
  158. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/tests/test_fs.py +0 -0
  159. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/tests/test_git.py +0 -0
  160. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/tests/test_install.py +0 -0
  161. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/tests/test_invenio.py +0 -0
  162. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/tests/test_jupyter.py +0 -0
  163. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/tests/test_licenses.py +0 -0
  164. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/tests/test_magics.py +0 -0
  165. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/tests/test_matlab.py +0 -0
  166. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/tests/test_notebooks.py +0 -0
  167. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/tests/test_releases.py +0 -0
  168. {calkit_python-0.41.13 → calkit_python-0.41.15}/calkit/tests/test_templates.py +0 -0
  169. {calkit_python-0.41.13 → calkit_python-0.41.15}/conftest.py +0 -0
  170. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/CNAME +0 -0
  171. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/ai-tools.md +0 -0
  172. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/apps.md +0 -0
  173. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/calculations.md +0 -0
  174. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/calkit-yaml.md +0 -0
  175. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/cloud-integration.md +0 -0
  176. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/datasets.md +0 -0
  177. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/dependencies.md +0 -0
  178. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/environments.md +0 -0
  179. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/examples.md +0 -0
  180. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/governance.md +0 -0
  181. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/help.md +0 -0
  182. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/hpc.md +0 -0
  183. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/img/c-to-the-k-white.svg +0 -0
  184. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/img/calkit-fragmentation-compendium.png +0 -0
  185. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/img/calkit-no-bg.png +0 -0
  186. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/img/connect-zenodo.png +0 -0
  187. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/img/jupyterlab/all-green.png +0 -0
  188. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/img/jupyterlab/collect-data-stale.png +0 -0
  189. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/img/jupyterlab/new-env.png +0 -0
  190. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/img/jupyterlab/new-notebook.png +0 -0
  191. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/img/jupyterlab/pipeline-badge.png +0 -0
  192. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/img/jupyterlab-params.png +0 -0
  193. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/img/plos-osi-code-2024-03.png +0 -0
  194. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/img/vscode-nb-params.png +0 -0
  195. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/index.md +0 -0
  196. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/installation.md +0 -0
  197. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/jupyterlab.md +0 -0
  198. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/local-server.md +0 -0
  199. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/notebooks.md +0 -0
  200. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/overleaf.md +0 -0
  201. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/pipeline/index.md +0 -0
  202. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/pipeline/manual-steps.md +0 -0
  203. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/pipeline/running-and-logging.md +0 -0
  204. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/quickstart.md +0 -0
  205. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/references.md +0 -0
  206. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/releases.md +0 -0
  207. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/reproducibility.md +0 -0
  208. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/subprojects.md +0 -0
  209. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/tutorials/adding-latex-pub-docker.md +0 -0
  210. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/tutorials/ai-agents.md +0 -0
  211. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/tutorials/conda-envs.md +0 -0
  212. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/tutorials/existing-project.md +0 -0
  213. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/tutorials/first-project.md +0 -0
  214. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/tutorials/github-actions.md +0 -0
  215. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/tutorials/img/actions-repo-secrets.png +0 -0
  216. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/tutorials/img/latex-codespaces/building-codespace.png +0 -0
  217. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/tutorials/img/latex-codespaces/codespaces-secrets-2.png +0 -0
  218. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/tutorials/img/latex-codespaces/editor-split.png +0 -0
  219. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/tutorials/img/latex-codespaces/go-to-linked-code.png +0 -0
  220. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/tutorials/img/latex-codespaces/issue-from-selection.png +0 -0
  221. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/tutorials/img/latex-codespaces/new-project.png +0 -0
  222. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/tutorials/img/latex-codespaces/new-pub-2.png +0 -0
  223. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/tutorials/img/latex-codespaces/new-token.png +0 -0
  224. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/tutorials/img/latex-codespaces/paper.tex.png +0 -0
  225. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/tutorials/img/latex-codespaces/project-home-3.png +0 -0
  226. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/tutorials/img/latex-codespaces/push.png +0 -0
  227. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/tutorials/img/latex-codespaces/stage.png +0 -0
  228. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/tutorials/img/office/anakin-excel.jpg +0 -0
  229. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/tutorials/img/office/chart-more-rows.png +0 -0
  230. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/tutorials/img/office/create-project.png +0 -0
  231. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/tutorials/img/office/elsevier-research-data-guidelines.png +0 -0
  232. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/tutorials/img/office/excel-chart.png +0 -0
  233. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/tutorials/img/office/excel-data.png +0 -0
  234. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/tutorials/img/office/insert-link-to-file.png +0 -0
  235. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/tutorials/img/office/needs-clone.png +0 -0
  236. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/tutorials/img/office/new-stage.png +0 -0
  237. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/tutorials/img/office/phd-comics-version-control.webp +0 -0
  238. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/tutorials/img/office/pipeline-out-of-date.png +0 -0
  239. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/tutorials/img/office/status-more-rows.png +0 -0
  240. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/tutorials/img/office/uncommitted-changes.png +0 -0
  241. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/tutorials/img/office/untracked-data.png +0 -0
  242. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/tutorials/img/office/updated-publication.png +0 -0
  243. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/tutorials/img/office/word-to-pdf-stage-2.png +0 -0
  244. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/tutorials/img/office/workflow-page.png +0 -0
  245. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/tutorials/img/openfoam/clone.png +0 -0
  246. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/tutorials/img/openfoam/create-project.png +0 -0
  247. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/tutorials/img/openfoam/datasets-page.png +0 -0
  248. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/tutorials/img/openfoam/figure-on-website-updated.png +0 -0
  249. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/tutorials/img/openfoam/figure-on-website.png +0 -0
  250. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/tutorials/img/openfoam/new-token.png +0 -0
  251. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/tutorials/img/openfoam/reclone.png +0 -0
  252. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/tutorials/img/openfoam/status-after-import-dataset.png +0 -0
  253. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/tutorials/img/quick-actions.png +0 -0
  254. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/tutorials/img/run-proc.png +0 -0
  255. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/tutorials/img/vscode-slurm-notebook/create-calkit-env.png +0 -0
  256. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/tutorials/img/vscode-slurm-notebook/create-inner-env.png +0 -0
  257. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/tutorials/img/vscode-slurm-notebook/create-new-calkit-env.png +0 -0
  258. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/tutorials/img/vscode-slurm-notebook/select-calkit-env.png +0 -0
  259. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/tutorials/img/vscode-slurm-notebook/slurm-job-running.png +0 -0
  260. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/tutorials/img/vscode-slurm-notebook/slurm-launch-options.png +0 -0
  261. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/tutorials/img/vscode-slurm-notebook/starting-slurm-job.png +0 -0
  262. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/tutorials/index.md +0 -0
  263. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/tutorials/jupyterlab.md +0 -0
  264. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/tutorials/latex-codespaces.md +0 -0
  265. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/tutorials/matlab.md +0 -0
  266. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/tutorials/notebook-pipeline.md +0 -0
  267. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/tutorials/office.md +0 -0
  268. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/tutorials/openfoam.md +0 -0
  269. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/tutorials/procedures.md +0 -0
  270. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/tutorials/vscode-slurm-notebook.md +0 -0
  271. {calkit_python-0.41.13 → calkit_python-0.41.15}/docs/version-control.md +0 -0
  272. {calkit_python-0.41.13 → calkit_python-0.41.15}/flake.lock +0 -0
  273. {calkit_python-0.41.13 → calkit_python-0.41.15}/flake.nix +0 -0
  274. {calkit_python-0.41.13 → calkit_python-0.41.15}/install.json +0 -0
  275. {calkit_python-0.41.13 → calkit_python-0.41.15}/jest.config.js +0 -0
  276. {calkit_python-0.41.13 → calkit_python-0.41.15}/jupyter-config/server-config/calkit.json +0 -0
  277. {calkit_python-0.41.13 → calkit_python-0.41.15}/mkdocs.yml +0 -0
  278. {calkit_python-0.41.13 → calkit_python-0.41.15}/package.json +0 -0
  279. {calkit_python-0.41.13 → calkit_python-0.41.15}/pyproject.toml +0 -0
  280. {calkit_python-0.41.13 → calkit_python-0.41.15}/schema/plugin.json +0 -0
  281. {calkit_python-0.41.13 → calkit_python-0.41.15}/scripts/generate-docs-references.py +0 -0
  282. {calkit_python-0.41.13 → calkit_python-0.41.15}/scripts/install.ps1 +0 -0
  283. {calkit_python-0.41.13 → calkit_python-0.41.15}/scripts/install.sh +0 -0
  284. {calkit_python-0.41.13 → calkit_python-0.41.15}/scripts/make-calk9.sh +0 -0
  285. {calkit_python-0.41.13 → calkit_python-0.41.15}/scripts/sync-docs.py +0 -0
  286. {calkit_python-0.41.13 → calkit_python-0.41.15}/src/__tests__/useQueries.spec.ts +0 -0
  287. {calkit_python-0.41.13 → calkit_python-0.41.15}/src/calkit-config.ts +0 -0
  288. {calkit_python-0.41.13 → calkit_python-0.41.15}/src/cell-output-marker.ts +0 -0
  289. {calkit_python-0.41.13 → calkit_python-0.41.15}/src/components/commit-dialog.tsx +0 -0
  290. {calkit_python-0.41.13 → calkit_python-0.41.15}/src/components/environment-editor.tsx +0 -0
  291. {calkit_python-0.41.13 → calkit_python-0.41.15}/src/components/notebook-registration.tsx +0 -0
  292. {calkit_python-0.41.13 → calkit_python-0.41.15}/src/components/notebook-toolbar.tsx +0 -0
  293. {calkit_python-0.41.13 → calkit_python-0.41.15}/src/components/pipeline-status-bar.tsx +0 -0
  294. {calkit_python-0.41.13 → calkit_python-0.41.15}/src/components/project-info-editor.tsx +0 -0
  295. {calkit_python-0.41.13 → calkit_python-0.41.15}/src/components/sidebar-settings.tsx +0 -0
  296. {calkit_python-0.41.13 → calkit_python-0.41.15}/src/components/sidebar.tsx +0 -0
  297. {calkit_python-0.41.13 → calkit_python-0.41.15}/src/components/stage-editor.tsx +0 -0
  298. {calkit_python-0.41.13 → calkit_python-0.41.15}/src/feature-flags.ts +0 -0
  299. {calkit_python-0.41.13 → calkit_python-0.41.15}/src/file-browser-menu.ts +0 -0
  300. {calkit_python-0.41.13 → calkit_python-0.41.15}/src/hooks/__tests__/useQueries.test.tsx +0 -0
  301. {calkit_python-0.41.13 → calkit_python-0.41.15}/src/hooks/useQueries.ts +0 -0
  302. {calkit_python-0.41.13 → calkit_python-0.41.15}/src/icons.ts +0 -0
  303. {calkit_python-0.41.13 → calkit_python-0.41.15}/src/index.ts +0 -0
  304. {calkit_python-0.41.13 → calkit_python-0.41.15}/src/io-tracker.ts +0 -0
  305. {calkit_python-0.41.13 → calkit_python-0.41.15}/src/pipeline-state.ts +0 -0
  306. {calkit_python-0.41.13 → calkit_python-0.41.15}/src/queryClient.ts +0 -0
  307. {calkit_python-0.41.13 → calkit_python-0.41.15}/src/request.ts +0 -0
  308. {calkit_python-0.41.13 → calkit_python-0.41.15}/src/shims-mainmenu.d.ts +0 -0
  309. {calkit_python-0.41.13 → calkit_python-0.41.15}/style/base.css +0 -0
  310. {calkit_python-0.41.13 → calkit_python-0.41.15}/style/cell-output-marker.css +0 -0
  311. {calkit_python-0.41.13 → calkit_python-0.41.15}/style/environment-editor.css +0 -0
  312. {calkit_python-0.41.13 → calkit_python-0.41.15}/style/environment-selector.css +0 -0
  313. {calkit_python-0.41.13 → calkit_python-0.41.15}/style/img/calkit-no-bg.png +0 -0
  314. {calkit_python-0.41.13 → calkit_python-0.41.15}/style/index.css +0 -0
  315. {calkit_python-0.41.13 → calkit_python-0.41.15}/style/index.js +0 -0
  316. {calkit_python-0.41.13 → calkit_python-0.41.15}/style/notebook-toolbar.css +0 -0
  317. {calkit_python-0.41.13 → calkit_python-0.41.15}/style/pipeline-status-bar.css +0 -0
  318. {calkit_python-0.41.13 → calkit_python-0.41.15}/style/sidebar.css +0 -0
  319. {calkit_python-0.41.13 → calkit_python-0.41.15}/test/dvc-md5-dir/osx-arm64.txt +0 -0
  320. {calkit_python-0.41.13 → calkit_python-0.41.15}/test/nb-julia.ipynb +0 -0
  321. {calkit_python-0.41.13 → calkit_python-0.41.15}/test/nb-params.ipynb +0 -0
  322. {calkit_python-0.41.13 → calkit_python-0.41.15}/test/nb-subdir.ipynb +0 -0
  323. {calkit_python-0.41.13 → calkit_python-0.41.15}/test/pipeline.ipynb +0 -0
  324. {calkit_python-0.41.13 → calkit_python-0.41.15}/test/script.py +0 -0
  325. {calkit_python-0.41.13 → calkit_python-0.41.15}/test/test-log.log +0 -0
  326. {calkit_python-0.41.13 → calkit_python-0.41.15}/tsconfig.json +0 -0
  327. {calkit_python-0.41.13 → calkit_python-0.41.15}/tsconfig.test.json +0 -0
  328. {calkit_python-0.41.13 → calkit_python-0.41.15}/ui-tests/.gitignore +0 -0
  329. {calkit_python-0.41.13 → calkit_python-0.41.15}/ui-tests/README.md +0 -0
  330. {calkit_python-0.41.13 → calkit_python-0.41.15}/ui-tests/jupyter_server_test_config.py +0 -0
  331. {calkit_python-0.41.13 → calkit_python-0.41.15}/ui-tests/package.json +0 -0
  332. {calkit_python-0.41.13 → calkit_python-0.41.15}/ui-tests/playwright.config.js +0 -0
  333. {calkit_python-0.41.13 → calkit_python-0.41.15}/ui-tests/tests/calkit.spec.ts +0 -0
  334. {calkit_python-0.41.13 → calkit_python-0.41.15}/ui-tests/yarn.lock +0 -0
  335. {calkit_python-0.41.13 → calkit_python-0.41.15}/uv.lock +0 -0
  336. {calkit_python-0.41.13 → calkit_python-0.41.15}/vscode-ext/.gitignore +0 -0
  337. {calkit_python-0.41.13 → calkit_python-0.41.15}/vscode-ext/.vscodeignore +0 -0
  338. {calkit_python-0.41.13 → calkit_python-0.41.15}/vscode-ext/CHANGELOG.md +0 -0
  339. {calkit_python-0.41.13 → calkit_python-0.41.15}/vscode-ext/LICENSE +0 -0
  340. {calkit_python-0.41.13 → calkit_python-0.41.15}/vscode-ext/images/calkit-icon.svg +0 -0
  341. {calkit_python-0.41.13 → calkit_python-0.41.15}/vscode-ext/images/calkit-no-bg.png +0 -0
  342. {calkit_python-0.41.13 → calkit_python-0.41.15}/vscode-ext/package-lock.json +0 -0
  343. {calkit_python-0.41.13 → calkit_python-0.41.15}/vscode-ext/scripts/set-proposed-api.js +0 -0
  344. {calkit_python-0.41.13 → calkit_python-0.41.15}/vscode-ext/src/environments.ts +0 -0
  345. {calkit_python-0.41.13 → calkit_python-0.41.15}/vscode-ext/src/notebooks.ts +0 -0
  346. {calkit_python-0.41.13 → calkit_python-0.41.15}/vscode-ext/src/test/environments.test.ts +0 -0
  347. {calkit_python-0.41.13 → calkit_python-0.41.15}/vscode-ext/src/test/kernel-selection.test.ts +0 -0
  348. {calkit_python-0.41.13 → calkit_python-0.41.15}/vscode-ext/src/test/notebooks.test.ts +0 -0
  349. {calkit_python-0.41.13 → calkit_python-0.41.15}/vscode-ext/tsconfig.json +0 -0
  350. {calkit_python-0.41.13 → calkit_python-0.41.15}/yarn.lock +0 -0
@@ -43,3 +43,6 @@ The only exception here is if splitting up a function makes it easier to
43
43
  write meaningful unit tests.
44
44
  If a function is only used inside one other function, nest it inside the
45
45
  caller at the top.
46
+
47
+ No spaces on either side of en or em dashes used for ranges or pauses in prose,
48
+ respectively.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: calkit-python
3
- Version: 0.41.13
3
+ Version: 0.41.15
4
4
  Summary: Reproducibility simplified.
5
5
  Project-URL: Homepage, https://calkit.org
6
6
  Project-URL: Issues, https://github.com/calkit/calkit/issues
@@ -180,7 +180,8 @@ def _check_julia_env(
180
180
  try:
181
181
  subprocess.check_call(
182
182
  cmd,
183
- env=os.environ.copy() | {"JULIA_LOAD_PATH": "@:@stdlib"},
183
+ env=os.environ.copy()
184
+ | {"JULIA_LOAD_PATH": calkit.julia.load_path()},
184
185
  )
185
186
  except subprocess.CalledProcessError:
186
187
  calkit.environments.save_cache(
@@ -206,7 +207,9 @@ def _check_julia_env(
206
207
  cmd = calkit.julia.ensure_startup_file_disabled_in_command(cmd)
207
208
  try:
208
209
  subprocess.check_call(
209
- cmd, env=os.environ.copy() | {"JULIA_LOAD_PATH": "@:@stdlib"}
210
+ cmd,
211
+ env=os.environ.copy()
212
+ | {"JULIA_LOAD_PATH": calkit.julia.load_path()},
210
213
  )
211
214
  except subprocess.CalledProcessError:
212
215
  calkit.environments.save_cache(
@@ -0,0 +1,33 @@
1
+ """CLI for deleting objects."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import typer
6
+
7
+ import calkit
8
+ from calkit.cli import AliasGroup, raise_error
9
+ from calkit.core import ryaml
10
+
11
+ delete_app = typer.Typer(cls=AliasGroup, no_args_is_help=True)
12
+
13
+
14
+ @delete_app.command(name="question")
15
+ def delete_question(
16
+ index: int = typer.Argument(
17
+ ...,
18
+ help="1-based index of the question to remove (see `calkit list questions`).",
19
+ ),
20
+ ):
21
+ """Remove a question by its 1-based index."""
22
+ ck_info = calkit.load_calkit_info()
23
+ questions = ck_info.get("questions", []) or []
24
+ if index < 1 or index > len(questions):
25
+ raise_error(
26
+ f"Invalid question index {index}; "
27
+ f"there are {len(questions)} question(s)."
28
+ )
29
+ removed = questions.pop(index - 1)
30
+ ck_info["questions"] = questions
31
+ with open("calkit.yaml", "w") as f:
32
+ ryaml.dump(ck_info, f)
33
+ typer.echo(f"Removed question: {removed}")
@@ -55,7 +55,7 @@ def _list_objects(
55
55
 
56
56
 
57
57
  def _list_artifacts(
58
- kind: Literal["figures", "datasets"],
58
+ kind: Literal["figures", "datasets", "results", "presentations"],
59
59
  json_output: bool,
60
60
  declared_only: bool,
61
61
  ):
@@ -134,6 +134,61 @@ def list_datasets(
134
134
  _list_artifacts("datasets", json_output, declared_only)
135
135
 
136
136
 
137
+ @list_app.command(name="results")
138
+ def list_results(
139
+ json_output: Annotated[
140
+ bool, typer.Option("--json", help="Output result as JSON.")
141
+ ] = False,
142
+ declared_only: Annotated[
143
+ bool,
144
+ typer.Option(
145
+ "--declared-only",
146
+ help=(
147
+ "Only list results declared in calkit.yaml; "
148
+ "skip auto-detection."
149
+ ),
150
+ ),
151
+ ] = False,
152
+ ):
153
+ """List results in the project."""
154
+ _list_artifacts("results", json_output, declared_only)
155
+
156
+
157
+ @list_app.command(name="presentations|pres")
158
+ def list_presentations(
159
+ json_output: Annotated[
160
+ bool, typer.Option("--json", help="Output result as JSON.")
161
+ ] = False,
162
+ declared_only: Annotated[
163
+ bool,
164
+ typer.Option(
165
+ "--declared-only",
166
+ help=(
167
+ "Only list presentations declared in calkit.yaml; "
168
+ "skip auto-detection."
169
+ ),
170
+ ),
171
+ ] = False,
172
+ ):
173
+ """List presentations in the project."""
174
+ _list_artifacts("presentations", json_output, declared_only)
175
+
176
+
177
+ @list_app.command(name="questions")
178
+ def list_questions(
179
+ json_output: Annotated[
180
+ bool, typer.Option("--json", help="Output result as JSON.")
181
+ ] = False,
182
+ ):
183
+ """List the project's questions (1-indexed)."""
184
+ questions = calkit.load_calkit_info().get("questions", []) or []
185
+ if json_output:
186
+ typer.echo(json.dumps(questions))
187
+ return
188
+ for n, question in enumerate(questions, start=1):
189
+ typer.echo(f"{n}. {question}")
190
+
191
+
137
192
  @list_app.command(name="publications|pubs")
138
193
  def list_publications():
139
194
  """List publications in the project."""
@@ -48,6 +48,7 @@ from calkit.cli.check import (
48
48
  )
49
49
  from calkit.cli.cloud import cloud_app
50
50
  from calkit.cli.config import config_app
51
+ from calkit.cli.delete import delete_app
51
52
  from calkit.cli.describe import describe_app
52
53
  from calkit.cli.dev import dev_app
53
54
  from calkit.cli.import_ import import_app
@@ -69,6 +70,7 @@ app = typer.Typer(
69
70
  )
70
71
  app.add_typer(config_app, name="config", help="Configure Calkit.")
71
72
  app.add_typer(new_app, name="new|create", help="Create a new Calkit object.")
73
+ app.add_typer(delete_app, name="delete|rm", help="Delete a Calkit object.")
72
74
  app.add_typer(
73
75
  notebooks_app, name="notebooks|nb", help="Work with Jupyter notebooks."
74
76
  )
@@ -579,6 +581,18 @@ def get_status(
579
581
  if pipeline_status and not pipeline_status.has_pipeline:
580
582
  typer.echo("This project has no pipeline.")
581
583
  return
584
+ # A failed environment check makes get_status bail out before computing
585
+ # staleness, leaving stale_stages empty. Don't let that masquerade as an
586
+ # up-to-date pipeline---say plainly that the status is unknown.
587
+ elif pipeline_status and pipeline_status.failed_environment_checks:
588
+ # The failing environments were already named in the warning emitted
589
+ # right after computing pipeline_status, so keep this explanatory
590
+ # only rather than repeating the list.
591
+ typer.echo(
592
+ "Pipeline status unavailable until the failed environment "
593
+ "checks above are resolved."
594
+ )
595
+ return
582
596
  elif pipeline_status and pipeline_status.is_stale:
583
597
  typer.echo("Stale stages:")
584
598
  for stage_name in pipeline_status.stale_stage_names:
@@ -1172,7 +1186,10 @@ def pull(
1172
1186
  and "-R" not in dvc_args
1173
1187
  ):
1174
1188
  dvc_args.append("--recursive")
1175
- result = calkit.dvc.run_dvc_command(["pull"] + dvc_args, lock_retries=5)
1189
+ result = calkit.dvc.run_dvc_command(
1190
+ ["pull"] + dvc_args,
1191
+ lock_timeout=calkit.dvc.DEFAULT_RUN_LOCK_TIMEOUT,
1192
+ )
1176
1193
  if result != 0:
1177
1194
  raise_error("DVC pull failed")
1178
1195
  calkit.dvc.zip.sync_all(direction="to-workspace")
@@ -1187,7 +1204,9 @@ def pull(
1187
1204
  continue
1188
1205
  typer.echo(f"DVC pulling subproject: {sp_path}")
1189
1206
  sp_result = calkit.dvc.run_dvc_command(
1190
- ["pull"] + dvc_args, cwd=sp_path, lock_retries=5
1207
+ ["pull"] + dvc_args,
1208
+ cwd=sp_path,
1209
+ lock_timeout=calkit.dvc.DEFAULT_RUN_LOCK_TIMEOUT,
1191
1210
  )
1192
1211
  if sp_result != 0:
1193
1212
  raise_error(f"DVC pull failed for subproject: {sp_path}")
@@ -1225,7 +1244,8 @@ def push(
1225
1244
  if remotes:
1226
1245
  typer.echo("Pushing to DVC remote")
1227
1246
  result = calkit.dvc.run_dvc_command(
1228
- ["push"] + dvc_args, lock_retries=5
1247
+ ["push"] + dvc_args,
1248
+ lock_timeout=calkit.dvc.DEFAULT_RUN_LOCK_TIMEOUT,
1229
1249
  )
1230
1250
  if result != 0:
1231
1251
  raise_error("DVC push failed")
@@ -2035,7 +2055,10 @@ def run(
2035
2055
  original_dir = os.getcwd()
2036
2056
  try:
2037
2057
  os.chdir(sp_path)
2038
- sp_res = dvc_cli_main(["repro"] + sp_args)
2058
+ with calkit.dvc.dvc_lock_timeout(
2059
+ calkit.dvc.DEFAULT_RUN_LOCK_TIMEOUT
2060
+ ):
2061
+ sp_res = dvc_cli_main(["repro"] + sp_args)
2039
2062
  finally:
2040
2063
  os.chdir(original_dir)
2041
2064
  if sp_res != 0:
@@ -2104,7 +2127,15 @@ def run(
2104
2127
  if force:
2105
2128
  os.environ["CALKIT_FORCE"] = "1"
2106
2129
  try:
2107
- res = dvc_cli_main(["repro"] + args)
2130
+ # Wait generously for the repo lock instead of failing after DVC's 3s
2131
+ # default. Brief contention is common and benign: a background
2132
+ # `calkit status` poller (e.g. the VS Code extension), a stage whose
2133
+ # command is itself `calkit run`, or DVC's own per-stage re-lock (DVC
2134
+ # releases the repo lock while a stage command runs and re-acquires it
2135
+ # the instant it finishes) can all hold it momentarily. Without this,
2136
+ # such a collision aborts the whole run with "Unable to acquire lock".
2137
+ with calkit.dvc.dvc_lock_timeout(calkit.dvc.DEFAULT_RUN_LOCK_TIMEOUT):
2138
+ res = dvc_cli_main(["repro"] + args)
2108
2139
  finally:
2109
2140
  os.environ.pop("CALKIT_FORCE", None)
2110
2141
  failed = failed or res != 0
@@ -2567,7 +2598,8 @@ def run_in_env(
2567
2598
  subprocess.check_call(
2568
2599
  julia_cmd,
2569
2600
  cwd=wdir,
2570
- env=os.environ.copy() | {"JULIA_LOAD_PATH": "@:@stdlib"},
2601
+ env=os.environ.copy()
2602
+ | {"JULIA_LOAD_PATH": calkit.julia.load_path()},
2571
2603
  )
2572
2604
  except subprocess.CalledProcessError:
2573
2605
  raise_error("Failed to run in julia environment")
@@ -9,6 +9,7 @@ import shutil
9
9
  import subprocess
10
10
  import time
11
11
  from enum import Enum
12
+ from typing import Literal
12
13
 
13
14
  import typer
14
15
  from typing_extensions import Annotated
@@ -591,6 +592,102 @@ def new_figure(
591
592
  repo.git.commit(["-m", f"Add figure {path}"])
592
593
 
593
594
 
595
+ def _new_simple_artifact(
596
+ kind: Literal["results", "presentations"],
597
+ path: str,
598
+ title: str,
599
+ description: str | None,
600
+ stage_name: str | None,
601
+ no_commit: bool,
602
+ overwrite: bool,
603
+ ) -> None:
604
+ """Declare a simple artifact (path/title/description/stage) in calkit.yaml."""
605
+ singular = kind.rstrip("s")
606
+ ck_info = calkit.load_calkit_info()
607
+ objects = ck_info.get(kind, [])
608
+ paths = [o.get("path") for o in objects]
609
+ if not overwrite and path in paths:
610
+ raise_error(f"{singular.capitalize()} at path {path} already exists")
611
+ if overwrite and path in paths:
612
+ objects = [o for o in objects if o.get("path") != path]
613
+ obj = dict(path=path, title=title)
614
+ if description is not None:
615
+ obj["description"] = description
616
+ if stage_name is not None:
617
+ obj["stage"] = stage_name
618
+ objects.append(obj)
619
+ ck_info[kind] = objects
620
+ with open("calkit.yaml", "w") as f:
621
+ ryaml.dump(ck_info, f)
622
+ if not no_commit:
623
+ repo = calkit.git.get_repo()
624
+ repo.git.add("calkit.yaml")
625
+ if repo.git.diff("--staged"):
626
+ repo.git.commit(["-m", f"Add {singular} {path}"])
627
+
628
+
629
+ @new_app.command(name="result")
630
+ def new_result(
631
+ path: str,
632
+ title: Annotated[str, typer.Option("--title")],
633
+ description: Annotated[str | None, typer.Option("--description")] = None,
634
+ stage_name: Annotated[
635
+ str | None,
636
+ typer.Option(
637
+ "--stage",
638
+ help="Name of the pipeline stage that generates this result.",
639
+ ),
640
+ ] = None,
641
+ no_commit: Annotated[bool, typer.Option("--no-commit")] = False,
642
+ overwrite: Annotated[
643
+ bool,
644
+ typer.Option(
645
+ "--overwrite",
646
+ "-f",
647
+ help="Overwrite existing result if one exists.",
648
+ ),
649
+ ] = False,
650
+ ):
651
+ """Declare a new result."""
652
+ _new_simple_artifact(
653
+ "results", path, title, description, stage_name, no_commit, overwrite
654
+ )
655
+
656
+
657
+ @new_app.command(name="presentation|pres")
658
+ def new_presentation(
659
+ path: str,
660
+ title: Annotated[str, typer.Option("--title")],
661
+ description: Annotated[str | None, typer.Option("--description")] = None,
662
+ stage_name: Annotated[
663
+ str | None,
664
+ typer.Option(
665
+ "--stage",
666
+ help="Name of the pipeline stage that generates this presentation.",
667
+ ),
668
+ ] = None,
669
+ no_commit: Annotated[bool, typer.Option("--no-commit")] = False,
670
+ overwrite: Annotated[
671
+ bool,
672
+ typer.Option(
673
+ "--overwrite",
674
+ "-f",
675
+ help="Overwrite existing presentation if one exists.",
676
+ ),
677
+ ] = False,
678
+ ):
679
+ """Declare a new presentation."""
680
+ _new_simple_artifact(
681
+ "presentations",
682
+ path,
683
+ title,
684
+ description,
685
+ stage_name,
686
+ no_commit,
687
+ overwrite,
688
+ )
689
+
690
+
594
691
  @new_app.command("question")
595
692
  def new_question(
596
693
  question: str,
@@ -2011,7 +2108,7 @@ def new_julia_env(
2011
2108
  except subprocess.CalledProcessError:
2012
2109
  raise_error(f"Failed to install Julia version {julia_version}")
2013
2110
  cmd = ["julia", f"+{julia_version}", f"--project={env_dir}", "-e"]
2014
- install_cmd = f'using Pkg; Pkg.activate("{env_dir}");'
2111
+ install_cmd = f'using Pkg; Pkg.activate("{calkit.julia.escape_string(env_dir)}");'
2015
2112
  for package in packages or []:
2016
2113
  install_cmd += f' Pkg.add("{package}");'
2017
2114
  cmd.append(install_cmd)
@@ -310,14 +310,18 @@ def check_env_kernel(
310
310
  "still failed."
311
311
  )
312
312
  # Don't include version in display_name; IJulia appends it automatically
313
+ # Escape interpolated values for the Julia string literals---notably the
314
+ # Windows project path, whose backslashes are otherwise read as invalid
315
+ # unicode escapes.
316
+ esc = calkit.julia.escape_string
313
317
  julia_cmd = (
314
318
  "import IJulia;"
315
319
  "kp=IJulia.installkernel("
316
- f'"{kernel_name}",'
317
- f'"--project={env_dir_abs}",'
320
+ f'"{esc(kernel_name)}",'
321
+ f'"--project={esc(env_dir_abs)}",'
318
322
  '"--startup-file=no",'
319
- f'displayname="{display_name}",'
320
- 'env=Dict("JULIA_LOAD_PATH" => "@:@stdlib")'
323
+ f'displayname="{esc(display_name)}",'
324
+ f'env=Dict("JULIA_LOAD_PATH" => "{esc(calkit.julia.load_path())}")'
321
325
  ");"
322
326
  "println(kp);"
323
327
  )
@@ -474,8 +478,7 @@ def execute_notebook(
474
478
  # Create this environment and write it to file
475
479
  envs[res.name] = res.env
476
480
  ck_info["environments"] = envs
477
- with open("calkit.yaml", "w") as f:
478
- calkit.ryaml.dump(ck_info, f)
481
+ calkit.save_calkit_info(ck_info)
479
482
  # Detect language from environment
480
483
  if language is None:
481
484
  detected_language = language_from_notebook(path)
@@ -501,16 +504,20 @@ def execute_notebook(
501
504
  raise ValueError(
502
505
  "Language must be one of 'python', 'matlab', 'julia', or 'r'"
503
506
  )
504
- # Try to set kernelspec metadata so execution uses the expected kernel
507
+ # Try to set kernelspec metadata so execution uses the expected kernel.
508
+ # Always read/write as UTF-8: notebooks routinely contain non-ASCII (e.g.,
509
+ # Greek letters such as "ν" in code), and on Windows the default open()
510
+ # encoding is cp1252, which mangles UTF-8 content into mojibake ("ν" ->
511
+ # "ν") and breaks execution.
505
512
  try:
506
- with open(path, "r") as f:
513
+ with open(path, "r", encoding="utf-8") as f:
507
514
  nb_json = json.load(f)
508
515
  metadata = nb_json.setdefault("metadata", {})
509
516
  kernelspec = metadata.setdefault("kernelspec", {})
510
517
  kernelspec["name"] = kernel_name
511
518
  kernelspec["display_name"] = display_name
512
- kernelspec.setdefault("language", language.lower())
513
- with open(path, "w") as f:
519
+ kernelspec["language"] = language.lower()
520
+ with open(path, "w", encoding="utf-8") as f:
514
521
  json.dump(nb_json, f, indent=1)
515
522
  except Exception as e:
516
523
  if verbose:
@@ -77,6 +77,23 @@ def _record_job(name: str, info: dict) -> None:
77
77
  jobs[name] = info
78
78
 
79
79
 
80
+ def _delete_job(name: str) -> None:
81
+ """Remove a job record from the database.
82
+
83
+ Used when a job is canceled (e.g. the user hits Ctrl+C while waiting for
84
+ it). Without this the record would linger, and the next ``calkit run``
85
+ would find the job gone from the queue with no exit status and wrongly
86
+ treat it as successful instead of resubmitting it.
87
+ """
88
+ if not os.path.isfile(JOBS_DB_PATH):
89
+ return
90
+ with SqliteDict(
91
+ JOBS_DB_PATH, autocommit=True, timeout=JOBS_DB_TIMEOUT
92
+ ) as jobs:
93
+ if name in jobs:
94
+ del jobs[name]
95
+
96
+
80
97
  def _mock_enabled() -> bool:
81
98
  """Whether scheduler commands should run jobs locally.
82
99
 
@@ -390,6 +407,9 @@ def _wait_until_done(kind: str, job_id: str, name: str) -> int | None:
390
407
  ok, stderr = _cancel(kind, job_id)
391
408
  if not ok:
392
409
  typer.echo(f"Failed to cancel job '{name}' ({job_id}): {stderr}")
410
+ # Drop the record so the next run resubmits this job instead of
411
+ # mistaking the canceled job (which has no exit status) for a success.
412
+ _delete_job(name)
393
413
  raise typer.Exit(130)
394
414
 
395
415
 
@@ -746,7 +746,7 @@ def update_julia_env(
746
746
  env_dir = os.path.dirname(spec_path) or "."
747
747
  julia_version = env.get("julia")
748
748
  julia_bin = ["julia", f"+{julia_version}"] if julia_version else ["julia"]
749
- cmds = [f'Pkg.activate("{env_dir}")']
749
+ cmds = [f'Pkg.activate("{calkit.julia.escape_string(env_dir)}")']
750
750
  if add:
751
751
  pkg_list = "[" + ", ".join(f'"{p}"' for p in add) + "]"
752
752
  cmds.append(f"Pkg.add({pkg_list})")
@@ -144,7 +144,9 @@ def load_calkit_info(
144
144
  if wdir is not None:
145
145
  fpath = os.path.join(wdir, fpath)
146
146
  if os.path.isfile(fpath):
147
- with open(fpath) as f:
147
+ # Always read as UTF-8; on Windows the default open() encoding is
148
+ # cp1252, which mangles non-ASCII content (e.g., Greek letters).
149
+ with open(fpath, encoding="utf-8") as f:
148
150
  info = ryaml.load(f)
149
151
  if info is None:
150
152
  info = {}
@@ -166,7 +168,7 @@ def load_calkit_info(
166
168
  if wdir is not None:
167
169
  include_fpath = os.path.join(wdir, include_fpath)
168
170
  if os.path.isfile(include_fpath):
169
- with open(include_fpath) as f:
171
+ with open(include_fpath, encoding="utf-8") as f:
170
172
  include_data = ryaml.load(f)
171
173
  info[kind][obj_name] |= include_data
172
174
  return info
@@ -180,7 +182,9 @@ def save_calkit_info(
180
182
  fpath = "calkit.yaml"
181
183
  if wdir is not None:
182
184
  fpath = os.path.join(wdir, fpath)
183
- with open(fpath, "w") as f:
185
+ # Always write as UTF-8; on Windows the default open() encoding is cp1252,
186
+ # which mangles non-ASCII content (e.g., Greek letters) into mojibake.
187
+ with open(fpath, "w", encoding="utf-8") as f:
184
188
  ryaml.dump(info, f)
185
189
 
186
190
 
@@ -1837,6 +1837,31 @@ DATASET_EXTENSIONS = {
1837
1837
  ".ndjson",
1838
1838
  }
1839
1839
  DATA_DIRS = {"data", "datasets", "dataset"}
1840
+ RESULT_DIRS = {"results", "result"}
1841
+ RESULT_EXTENSIONS = {
1842
+ ".json",
1843
+ ".csv",
1844
+ ".tsv",
1845
+ ".yaml",
1846
+ ".yml",
1847
+ ".parquet",
1848
+ ".h5",
1849
+ ".hdf5",
1850
+ ".txt",
1851
+ ".html",
1852
+ }
1853
+ PRESENTATION_DIRS = {"presentations", "presentation", "slides", "talks"}
1854
+ PRESENTATION_EXTENSIONS = {".pdf", ".pptx", ".key"}
1855
+ # Files that look like a presentation regardless of which directory they live in.
1856
+ PRESENTATION_NAMES = {
1857
+ "slides.pdf",
1858
+ "slides.pptx",
1859
+ "slides.key",
1860
+ "presentation.pdf",
1861
+ "presentation.pptx",
1862
+ "presentation.key",
1863
+ "talk.pdf",
1864
+ }
1840
1865
 
1841
1866
 
1842
1867
  def _ancestor_dir_names(rel_path: str) -> set[str]:
@@ -1871,6 +1896,37 @@ def is_dataset_path(rel_path: str) -> bool:
1871
1896
  )
1872
1897
 
1873
1898
 
1899
+ def is_result_path(rel_path: str) -> bool:
1900
+ """Whether a repo-relative path looks like an auto-detectable result.
1901
+
1902
+ A result is a data-like file (JSON, CSV, etc.) under a ``results``-style
1903
+ directory. Anything already detected as a figure or dataset is excluded.
1904
+ """
1905
+ return (
1906
+ _path_ext(rel_path) in RESULT_EXTENSIONS
1907
+ and bool(_ancestor_dir_names(rel_path) & RESULT_DIRS)
1908
+ and not is_figure_path(rel_path)
1909
+ and not is_dataset_path(rel_path)
1910
+ )
1911
+
1912
+
1913
+ def is_presentation_path(rel_path: str) -> bool:
1914
+ """Whether a repo-relative path looks like an auto-detectable presentation.
1915
+
1916
+ Either a slide-deck file (PDF/PPTX/KEY) under a ``slides``/``presentations``
1917
+ directory, or a file with a presentation-like name (e.g. ``slides.pdf``,
1918
+ ``presentation.pdf``) anywhere. Figures are excluded.
1919
+ """
1920
+ if is_figure_path(rel_path):
1921
+ return False
1922
+ name = rel_path.rsplit("/", 1)[-1].lower()
1923
+ if name in PRESENTATION_NAMES:
1924
+ return True
1925
+ return _path_ext(rel_path) in PRESENTATION_EXTENSIONS and bool(
1926
+ _ancestor_dir_names(rel_path) & PRESENTATION_DIRS
1927
+ )
1928
+
1929
+
1874
1930
  def _is_hidden_path(rel_path: str) -> bool:
1875
1931
  return any(part.startswith(".") for part in rel_path.split("/"))
1876
1932
 
@@ -1949,6 +2005,44 @@ def detect_datasets(
1949
2005
  return _collapse_dataset_folders(sorted(files))
1950
2006
 
1951
2007
 
2008
+ def detect_results(
2009
+ candidate_paths: list[str],
2010
+ reserved_paths: list[str] | tuple[str, ...] = (),
2011
+ ) -> list[str]:
2012
+ """Auto-detected result paths among ``candidate_paths``.
2013
+
2014
+ Paths under a dot-directory or under one of ``reserved_paths`` (declared
2015
+ artifacts) are skipped.
2016
+ """
2017
+ reserved = list(reserved_paths)
2018
+ return sorted(
2019
+ {
2020
+ p
2021
+ for p in candidate_paths
2022
+ if not _is_hidden_path(p)
2023
+ and not _is_under_any_dir(p, reserved)
2024
+ and is_result_path(p)
2025
+ }
2026
+ )
2027
+
2028
+
2029
+ def detect_presentations(
2030
+ candidate_paths: list[str],
2031
+ reserved_paths: list[str] | tuple[str, ...] = (),
2032
+ ) -> list[str]:
2033
+ """Auto-detected presentation paths among ``candidate_paths``."""
2034
+ reserved = list(reserved_paths)
2035
+ return sorted(
2036
+ {
2037
+ p
2038
+ for p in candidate_paths
2039
+ if not _is_hidden_path(p)
2040
+ and not _is_under_any_dir(p, reserved)
2041
+ and is_presentation_path(p)
2042
+ }
2043
+ )
2044
+
2045
+
1952
2046
  def list_repo_files(wdir: str | None = None) -> list[str]:
1953
2047
  """Repo-relative paths of files Git does not ignore.
1954
2048
 
@@ -2014,7 +2108,7 @@ def _reserved_artifact_paths(
2014
2108
  if ck_info is None:
2015
2109
  ck_info = calkit.load_calkit_info(wdir=wdir)
2016
2110
  paths: list[str] = []
2017
- for kind in ("figures", "datasets"):
2111
+ for kind in ("figures", "datasets", "results", "presentations"):
2018
2112
  for obj in ck_info.get(kind, []) or []:
2019
2113
  if isinstance(obj, dict) and isinstance(obj.get("path"), str):
2020
2114
  paths.append(obj["path"])
@@ -2044,4 +2138,11 @@ def detect_project_artifacts(
2044
2138
  datasets = detect_datasets(
2045
2139
  candidates, reserved_paths=reserved, figure_paths=figures
2046
2140
  )
2047
- return {"figures": figures, "datasets": datasets}
2141
+ results = detect_results(candidates, reserved_paths=reserved)
2142
+ presentations = detect_presentations(candidates, reserved_paths=reserved)
2143
+ return {
2144
+ "figures": figures,
2145
+ "datasets": datasets,
2146
+ "results": results,
2147
+ "presentations": presentations,
2148
+ }