calkit-python 0.38.4__tar.gz → 0.39.1__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 (328) hide show
  1. {calkit_python-0.38.4 → calkit_python-0.39.1}/AGENTS.md +4 -0
  2. {calkit_python-0.38.4 → calkit_python-0.39.1}/PKG-INFO +1 -1
  3. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/__init__.py +38 -0
  4. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/check.py +1 -2
  5. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/cli/check.py +1 -3
  6. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/cli/config.py +1 -2
  7. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/cli/core.py +16 -1
  8. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/cli/import_.py +4 -8
  9. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/cli/list.py +1 -3
  10. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/cli/main/core.py +140 -35
  11. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/cli/main/xr.py +2 -2
  12. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/cli/new.py +22 -54
  13. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/cli/overleaf.py +5 -5
  14. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/cli/update.py +5 -12
  15. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/core.py +6 -16
  16. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/dvc/core.py +1 -2
  17. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/dvc/zip.py +84 -48
  18. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/git.py +18 -4
  19. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/jupyterlab/routes.py +5 -6
  20. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/notebooks.py +1 -3
  21. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/pipeline.py +422 -47
  22. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/releases.py +1 -3
  23. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/server.py +17 -15
  24. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/tests/cli/main/test_core.py +74 -0
  25. calkit_python-0.39.1/calkit/tests/cli/main/test_subprojects.py +298 -0
  26. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/tests/dvc/test_core.py +1 -1
  27. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/tests/test_pipeline.py +365 -1
  28. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/cli-reference.md +6 -4
  29. calkit_python-0.39.1/docs/subprojects.md +18 -0
  30. {calkit_python-0.38.4 → calkit_python-0.39.1}/mkdocs.yml +1 -0
  31. {calkit_python-0.38.4 → calkit_python-0.39.1}/.claude-plugin/marketplace.json +0 -0
  32. {calkit_python-0.38.4 → calkit_python-0.39.1}/.gitignore +0 -0
  33. {calkit_python-0.38.4 → calkit_python-0.39.1}/.pre-commit-config.yaml +0 -0
  34. {calkit_python-0.38.4 → calkit_python-0.39.1}/.prettierignore +0 -0
  35. {calkit_python-0.38.4 → calkit_python-0.39.1}/.python-version +0 -0
  36. {calkit_python-0.38.4 → calkit_python-0.39.1}/.vscode/launch.json +0 -0
  37. {calkit_python-0.38.4 → calkit_python-0.39.1}/.vscode/tasks.json +0 -0
  38. {calkit_python-0.38.4 → calkit_python-0.39.1}/.yarnrc.yml +0 -0
  39. {calkit_python-0.38.4 → calkit_python-0.39.1}/CITATION.cff +0 -0
  40. {calkit_python-0.38.4 → calkit_python-0.39.1}/CODE_OF_CONDUCT.md +0 -0
  41. {calkit_python-0.38.4 → calkit_python-0.39.1}/CONTRIBUTING.md +0 -0
  42. {calkit_python-0.38.4 → calkit_python-0.39.1}/LICENSE +0 -0
  43. {calkit_python-0.38.4 → calkit_python-0.39.1}/Makefile +0 -0
  44. {calkit_python-0.38.4 → calkit_python-0.39.1}/README.md +0 -0
  45. {calkit_python-0.38.4 → calkit_python-0.39.1}/agent-plugin/.claude-plugin/plugin.json +0 -0
  46. {calkit_python-0.38.4 → calkit_python-0.39.1}/agent-plugin/skills/add-pipeline-stage/SKILL.md +0 -0
  47. {calkit_python-0.38.4 → calkit_python-0.39.1}/agent-plugin/skills/conventions/SKILL.md +0 -0
  48. {calkit_python-0.38.4 → calkit_python-0.39.1}/agent-plugin/skills/create-pipeline/SKILL.md +0 -0
  49. {calkit_python-0.38.4 → calkit_python-0.39.1}/babel.config.js +0 -0
  50. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/__main__.py +0 -0
  51. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/calc.py +0 -0
  52. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/cli/__init__.py +0 -0
  53. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/cli/cloud.py +0 -0
  54. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/cli/describe.py +0 -0
  55. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/cli/dev.py +0 -0
  56. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/cli/latex.py +0 -0
  57. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/cli/main/__init__.py +0 -0
  58. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/cli/notebooks.py +0 -0
  59. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/cli/office.py +0 -0
  60. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/cli/slurm.py +0 -0
  61. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/cloud.py +0 -0
  62. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/conda.py +0 -0
  63. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/config.py +0 -0
  64. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/datasets.py +0 -0
  65. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/detect.py +0 -0
  66. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/docker.py +0 -0
  67. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/dvc/__init__.py +0 -0
  68. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/environments.py +0 -0
  69. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/fs.py +0 -0
  70. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/github.py +0 -0
  71. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/gui.py +0 -0
  72. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/invenio.py +0 -0
  73. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/julia.py +0 -0
  74. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/jupyter.py +0 -0
  75. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/jupyterlab/__init__.py +0 -0
  76. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/labextension/package.json +0 -0
  77. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/labextension/schemas/calkit/package.json.orig +0 -0
  78. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/labextension/schemas/calkit/plugin.json +0 -0
  79. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/labextension/static/502.9a2c5772a15466e923ef.js +0 -0
  80. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/labextension/static/695.2c41003a452d43d2b358.js +0 -0
  81. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/labextension/static/867.a42a046aa5108f54f8fb.js +0 -0
  82. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/labextension/static/909.e3f9cc3408834a7fdcc3.js +0 -0
  83. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/labextension/static/946.050af2abf7845cfbdbd2.js +0 -0
  84. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/labextension/static/946.050af2abf7845cfbdbd2.js.LICENSE.txt +0 -0
  85. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/labextension/static/b2f1c3efe70cb539d121.png +0 -0
  86. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/labextension/static/remoteEntry.65469af996e7a96aa983.js +0 -0
  87. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/labextension/static/style.js +0 -0
  88. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/labextension/static/third-party-licenses.json +0 -0
  89. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/licenses.py +0 -0
  90. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/magics.py +0 -0
  91. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/matlab.py +0 -0
  92. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/models/__init__.py +0 -0
  93. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/models/core.py +0 -0
  94. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/models/io.py +0 -0
  95. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/models/iteration.py +0 -0
  96. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/models/pipeline.py +0 -0
  97. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/office.py +0 -0
  98. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/ops.py +0 -0
  99. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/overleaf.py +0 -0
  100. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/templates/__init__.py +0 -0
  101. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/templates/core.py +0 -0
  102. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/templates/latex/__init__.py +0 -0
  103. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/templates/latex/article/paper.tex +0 -0
  104. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/templates/latex/core.py +0 -0
  105. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/templates/latex/jfm/jfm.bst +0 -0
  106. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/templates/latex/jfm/jfm.cls +0 -0
  107. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/templates/latex/jfm/lineno-FLM.sty +0 -0
  108. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/templates/latex/jfm/paper.tex +0 -0
  109. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/templates/latex/jfm/upmath.sty +0 -0
  110. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/tests/__init__.py +0 -0
  111. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/tests/cli/__init__.py +0 -0
  112. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/tests/cli/main/__init__.py +0 -0
  113. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/tests/cli/main/test_xr.py +0 -0
  114. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/tests/cli/test_check.py +0 -0
  115. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/tests/cli/test_cloud.py +0 -0
  116. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/tests/cli/test_config.py +0 -0
  117. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/tests/cli/test_import.py +0 -0
  118. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/tests/cli/test_latex.py +0 -0
  119. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/tests/cli/test_list.py +0 -0
  120. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/tests/cli/test_new.py +0 -0
  121. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/tests/cli/test_notebooks.py +0 -0
  122. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/tests/cli/test_overleaf.py +0 -0
  123. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/tests/cli/test_update.py +0 -0
  124. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/tests/dvc/__init__.py +0 -0
  125. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/tests/dvc/test_zip.py +0 -0
  126. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/tests/jupyterlab/__init__.py +0 -0
  127. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/tests/jupyterlab/test_routes.py +0 -0
  128. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/tests/models/__init__.py +0 -0
  129. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/tests/models/test_iteration.py +0 -0
  130. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/tests/models/test_pipeline.py +0 -0
  131. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/tests/test_calc.py +0 -0
  132. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/tests/test_check.py +0 -0
  133. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/tests/test_cloud.py +0 -0
  134. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/tests/test_conda.py +0 -0
  135. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/tests/test_core.py +0 -0
  136. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/tests/test_detect.py +0 -0
  137. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/tests/test_docker.py +0 -0
  138. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/tests/test_environments.py +0 -0
  139. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/tests/test_fs.py +0 -0
  140. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/tests/test_git.py +0 -0
  141. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/tests/test_invenio.py +0 -0
  142. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/tests/test_julia.py +0 -0
  143. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/tests/test_jupyter.py +0 -0
  144. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/tests/test_magics.py +0 -0
  145. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/tests/test_matlab.py +0 -0
  146. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/tests/test_notebooks.py +0 -0
  147. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/tests/test_releases.py +0 -0
  148. {calkit_python-0.38.4 → calkit_python-0.39.1}/calkit/tests/test_templates.py +0 -0
  149. {calkit_python-0.38.4 → calkit_python-0.39.1}/conftest.py +0 -0
  150. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/CNAME +0 -0
  151. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/ai-tools.md +0 -0
  152. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/apps.md +0 -0
  153. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/calculations.md +0 -0
  154. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/calkit-yaml.md +0 -0
  155. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/cloud-integration.md +0 -0
  156. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/datasets.md +0 -0
  157. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/dependencies.md +0 -0
  158. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/environments.md +0 -0
  159. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/examples.md +0 -0
  160. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/governance.md +0 -0
  161. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/help.md +0 -0
  162. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/img/c-to-the-k-white.svg +0 -0
  163. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/img/calkit-fragmentation-compendium.png +0 -0
  164. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/img/calkit-no-bg.png +0 -0
  165. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/img/connect-zenodo.png +0 -0
  166. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/img/jupyterlab/all-green.png +0 -0
  167. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/img/jupyterlab/collect-data-stale.png +0 -0
  168. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/img/jupyterlab/new-env.png +0 -0
  169. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/img/jupyterlab/new-notebook.png +0 -0
  170. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/img/jupyterlab/pipeline-badge.png +0 -0
  171. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/img/jupyterlab-params.png +0 -0
  172. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/img/plos-osi-code-2024-03.png +0 -0
  173. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/img/vscode-nb-params.png +0 -0
  174. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/index.md +0 -0
  175. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/installation.md +0 -0
  176. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/jupyterlab.md +0 -0
  177. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/local-server.md +0 -0
  178. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/notebooks.md +0 -0
  179. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/overleaf.md +0 -0
  180. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/pipeline/index.md +0 -0
  181. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/pipeline/manual-steps.md +0 -0
  182. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/pipeline/running-and-logging.md +0 -0
  183. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/pipeline/slurm.md +0 -0
  184. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/quickstart.md +0 -0
  185. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/references.md +0 -0
  186. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/releases.md +0 -0
  187. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/reproducibility.md +0 -0
  188. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/tutorials/adding-latex-pub-docker.md +0 -0
  189. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/tutorials/conda-envs.md +0 -0
  190. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/tutorials/existing-project.md +0 -0
  191. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/tutorials/first-project.md +0 -0
  192. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/tutorials/github-actions.md +0 -0
  193. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/tutorials/img/actions-repo-secrets.png +0 -0
  194. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/tutorials/img/latex-codespaces/building-codespace.png +0 -0
  195. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/tutorials/img/latex-codespaces/codespaces-secrets-2.png +0 -0
  196. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/tutorials/img/latex-codespaces/editor-split.png +0 -0
  197. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/tutorials/img/latex-codespaces/go-to-linked-code.png +0 -0
  198. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/tutorials/img/latex-codespaces/issue-from-selection.png +0 -0
  199. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/tutorials/img/latex-codespaces/new-project.png +0 -0
  200. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/tutorials/img/latex-codespaces/new-pub-2.png +0 -0
  201. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/tutorials/img/latex-codespaces/new-token.png +0 -0
  202. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/tutorials/img/latex-codespaces/paper.tex.png +0 -0
  203. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/tutorials/img/latex-codespaces/project-home-3.png +0 -0
  204. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/tutorials/img/latex-codespaces/push.png +0 -0
  205. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/tutorials/img/latex-codespaces/stage.png +0 -0
  206. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/tutorials/img/office/anakin-excel.jpg +0 -0
  207. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/tutorials/img/office/chart-more-rows.png +0 -0
  208. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/tutorials/img/office/create-project.png +0 -0
  209. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/tutorials/img/office/elsevier-research-data-guidelines.png +0 -0
  210. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/tutorials/img/office/excel-chart.png +0 -0
  211. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/tutorials/img/office/excel-data.png +0 -0
  212. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/tutorials/img/office/insert-link-to-file.png +0 -0
  213. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/tutorials/img/office/needs-clone.png +0 -0
  214. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/tutorials/img/office/new-stage.png +0 -0
  215. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/tutorials/img/office/phd-comics-version-control.webp +0 -0
  216. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/tutorials/img/office/pipeline-out-of-date.png +0 -0
  217. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/tutorials/img/office/status-more-rows.png +0 -0
  218. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/tutorials/img/office/uncommitted-changes.png +0 -0
  219. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/tutorials/img/office/untracked-data.png +0 -0
  220. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/tutorials/img/office/updated-publication.png +0 -0
  221. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/tutorials/img/office/word-to-pdf-stage-2.png +0 -0
  222. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/tutorials/img/office/workflow-page.png +0 -0
  223. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/tutorials/img/openfoam/clone.png +0 -0
  224. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/tutorials/img/openfoam/create-project.png +0 -0
  225. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/tutorials/img/openfoam/datasets-page.png +0 -0
  226. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/tutorials/img/openfoam/figure-on-website-updated.png +0 -0
  227. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/tutorials/img/openfoam/figure-on-website.png +0 -0
  228. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/tutorials/img/openfoam/new-token.png +0 -0
  229. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/tutorials/img/openfoam/reclone.png +0 -0
  230. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/tutorials/img/openfoam/status-after-import-dataset.png +0 -0
  231. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/tutorials/img/quick-actions.png +0 -0
  232. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/tutorials/img/run-proc.png +0 -0
  233. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/tutorials/img/vscode-slurm-notebook/create-calkit-env.png +0 -0
  234. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/tutorials/img/vscode-slurm-notebook/create-inner-env.png +0 -0
  235. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/tutorials/img/vscode-slurm-notebook/create-new-calkit-env.png +0 -0
  236. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/tutorials/img/vscode-slurm-notebook/select-calkit-env.png +0 -0
  237. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/tutorials/img/vscode-slurm-notebook/slurm-job-running.png +0 -0
  238. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/tutorials/img/vscode-slurm-notebook/slurm-launch-options.png +0 -0
  239. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/tutorials/img/vscode-slurm-notebook/starting-slurm-job.png +0 -0
  240. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/tutorials/index.md +0 -0
  241. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/tutorials/jupyterlab.md +0 -0
  242. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/tutorials/latex-codespaces.md +0 -0
  243. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/tutorials/matlab.md +0 -0
  244. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/tutorials/notebook-pipeline.md +0 -0
  245. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/tutorials/office.md +0 -0
  246. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/tutorials/openfoam.md +0 -0
  247. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/tutorials/procedures.md +0 -0
  248. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/tutorials/vscode-slurm-notebook.md +0 -0
  249. {calkit_python-0.38.4 → calkit_python-0.39.1}/docs/version-control.md +0 -0
  250. {calkit_python-0.38.4 → calkit_python-0.39.1}/install.json +0 -0
  251. {calkit_python-0.38.4 → calkit_python-0.39.1}/jest.config.js +0 -0
  252. {calkit_python-0.38.4 → calkit_python-0.39.1}/jupyter-config/server-config/calkit.json +0 -0
  253. {calkit_python-0.38.4 → calkit_python-0.39.1}/package.json +0 -0
  254. {calkit_python-0.38.4 → calkit_python-0.39.1}/pyproject.toml +0 -0
  255. {calkit_python-0.38.4 → calkit_python-0.39.1}/schema/plugin.json +0 -0
  256. {calkit_python-0.38.4 → calkit_python-0.39.1}/scripts/generate-docs-references.py +0 -0
  257. {calkit_python-0.38.4 → calkit_python-0.39.1}/scripts/install.ps1 +0 -0
  258. {calkit_python-0.38.4 → calkit_python-0.39.1}/scripts/install.sh +0 -0
  259. {calkit_python-0.38.4 → calkit_python-0.39.1}/scripts/make-calk9.sh +0 -0
  260. {calkit_python-0.38.4 → calkit_python-0.39.1}/scripts/sync-docs.py +0 -0
  261. {calkit_python-0.38.4 → calkit_python-0.39.1}/src/__tests__/useQueries.spec.ts +0 -0
  262. {calkit_python-0.38.4 → calkit_python-0.39.1}/src/calkit-config.ts +0 -0
  263. {calkit_python-0.38.4 → calkit_python-0.39.1}/src/cell-output-marker.ts +0 -0
  264. {calkit_python-0.38.4 → calkit_python-0.39.1}/src/components/commit-dialog.tsx +0 -0
  265. {calkit_python-0.38.4 → calkit_python-0.39.1}/src/components/environment-editor.tsx +0 -0
  266. {calkit_python-0.38.4 → calkit_python-0.39.1}/src/components/notebook-registration.tsx +0 -0
  267. {calkit_python-0.38.4 → calkit_python-0.39.1}/src/components/notebook-toolbar.tsx +0 -0
  268. {calkit_python-0.38.4 → calkit_python-0.39.1}/src/components/pipeline-status-bar.tsx +0 -0
  269. {calkit_python-0.38.4 → calkit_python-0.39.1}/src/components/project-info-editor.tsx +0 -0
  270. {calkit_python-0.38.4 → calkit_python-0.39.1}/src/components/sidebar-settings.tsx +0 -0
  271. {calkit_python-0.38.4 → calkit_python-0.39.1}/src/components/sidebar.tsx +0 -0
  272. {calkit_python-0.38.4 → calkit_python-0.39.1}/src/components/stage-editor.tsx +0 -0
  273. {calkit_python-0.38.4 → calkit_python-0.39.1}/src/feature-flags.ts +0 -0
  274. {calkit_python-0.38.4 → calkit_python-0.39.1}/src/file-browser-menu.ts +0 -0
  275. {calkit_python-0.38.4 → calkit_python-0.39.1}/src/hooks/__tests__/useQueries.test.tsx +0 -0
  276. {calkit_python-0.38.4 → calkit_python-0.39.1}/src/hooks/useQueries.ts +0 -0
  277. {calkit_python-0.38.4 → calkit_python-0.39.1}/src/icons.ts +0 -0
  278. {calkit_python-0.38.4 → calkit_python-0.39.1}/src/index.ts +0 -0
  279. {calkit_python-0.38.4 → calkit_python-0.39.1}/src/io-tracker.ts +0 -0
  280. {calkit_python-0.38.4 → calkit_python-0.39.1}/src/pipeline-state.ts +0 -0
  281. {calkit_python-0.38.4 → calkit_python-0.39.1}/src/queryClient.ts +0 -0
  282. {calkit_python-0.38.4 → calkit_python-0.39.1}/src/request.ts +0 -0
  283. {calkit_python-0.38.4 → calkit_python-0.39.1}/src/shims-mainmenu.d.ts +0 -0
  284. {calkit_python-0.38.4 → calkit_python-0.39.1}/style/base.css +0 -0
  285. {calkit_python-0.38.4 → calkit_python-0.39.1}/style/cell-output-marker.css +0 -0
  286. {calkit_python-0.38.4 → calkit_python-0.39.1}/style/environment-editor.css +0 -0
  287. {calkit_python-0.38.4 → calkit_python-0.39.1}/style/environment-selector.css +0 -0
  288. {calkit_python-0.38.4 → calkit_python-0.39.1}/style/img/calkit-no-bg.png +0 -0
  289. {calkit_python-0.38.4 → calkit_python-0.39.1}/style/index.css +0 -0
  290. {calkit_python-0.38.4 → calkit_python-0.39.1}/style/index.js +0 -0
  291. {calkit_python-0.38.4 → calkit_python-0.39.1}/style/notebook-toolbar.css +0 -0
  292. {calkit_python-0.38.4 → calkit_python-0.39.1}/style/pipeline-status-bar.css +0 -0
  293. {calkit_python-0.38.4 → calkit_python-0.39.1}/style/sidebar.css +0 -0
  294. {calkit_python-0.38.4 → calkit_python-0.39.1}/test/dvc-md5-dir/osx-arm64.txt +0 -0
  295. {calkit_python-0.38.4 → calkit_python-0.39.1}/test/nb-julia.ipynb +0 -0
  296. {calkit_python-0.38.4 → calkit_python-0.39.1}/test/nb-params.ipynb +0 -0
  297. {calkit_python-0.38.4 → calkit_python-0.39.1}/test/nb-subdir.ipynb +0 -0
  298. {calkit_python-0.38.4 → calkit_python-0.39.1}/test/pipeline.ipynb +0 -0
  299. {calkit_python-0.38.4 → calkit_python-0.39.1}/test/script.py +0 -0
  300. {calkit_python-0.38.4 → calkit_python-0.39.1}/test/test-log.log +0 -0
  301. {calkit_python-0.38.4 → calkit_python-0.39.1}/tsconfig.json +0 -0
  302. {calkit_python-0.38.4 → calkit_python-0.39.1}/tsconfig.test.json +0 -0
  303. {calkit_python-0.38.4 → calkit_python-0.39.1}/ui-tests/.gitignore +0 -0
  304. {calkit_python-0.38.4 → calkit_python-0.39.1}/ui-tests/README.md +0 -0
  305. {calkit_python-0.38.4 → calkit_python-0.39.1}/ui-tests/jupyter_server_test_config.py +0 -0
  306. {calkit_python-0.38.4 → calkit_python-0.39.1}/ui-tests/package.json +0 -0
  307. {calkit_python-0.38.4 → calkit_python-0.39.1}/ui-tests/playwright.config.js +0 -0
  308. {calkit_python-0.38.4 → calkit_python-0.39.1}/ui-tests/tests/calkit.spec.ts +0 -0
  309. {calkit_python-0.38.4 → calkit_python-0.39.1}/ui-tests/yarn.lock +0 -0
  310. {calkit_python-0.38.4 → calkit_python-0.39.1}/uv.lock +0 -0
  311. {calkit_python-0.38.4 → calkit_python-0.39.1}/vscode-ext/.gitignore +0 -0
  312. {calkit_python-0.38.4 → calkit_python-0.39.1}/vscode-ext/.vscodeignore +0 -0
  313. {calkit_python-0.38.4 → calkit_python-0.39.1}/vscode-ext/CHANGELOG.md +0 -0
  314. {calkit_python-0.38.4 → calkit_python-0.39.1}/vscode-ext/LICENSE +0 -0
  315. {calkit_python-0.38.4 → calkit_python-0.39.1}/vscode-ext/README.md +0 -0
  316. {calkit_python-0.38.4 → calkit_python-0.39.1}/vscode-ext/images/calkit-no-bg.png +0 -0
  317. {calkit_python-0.38.4 → calkit_python-0.39.1}/vscode-ext/package-lock.json +0 -0
  318. {calkit_python-0.38.4 → calkit_python-0.39.1}/vscode-ext/package.json +0 -0
  319. {calkit_python-0.38.4 → calkit_python-0.39.1}/vscode-ext/scripts/set-proposed-api.js +0 -0
  320. {calkit_python-0.38.4 → calkit_python-0.39.1}/vscode-ext/src/environments.ts +0 -0
  321. {calkit_python-0.38.4 → calkit_python-0.39.1}/vscode-ext/src/extension.ts +0 -0
  322. {calkit_python-0.38.4 → calkit_python-0.39.1}/vscode-ext/src/notebooks.ts +0 -0
  323. {calkit_python-0.38.4 → calkit_python-0.39.1}/vscode-ext/src/test/environments.test.ts +0 -0
  324. {calkit_python-0.38.4 → calkit_python-0.39.1}/vscode-ext/src/test/kernel-selection.test.ts +0 -0
  325. {calkit_python-0.38.4 → calkit_python-0.39.1}/vscode-ext/src/test/notebooks.test.ts +0 -0
  326. {calkit_python-0.38.4 → calkit_python-0.39.1}/vscode-ext/src/types.ts +0 -0
  327. {calkit_python-0.38.4 → calkit_python-0.39.1}/vscode-ext/tsconfig.json +0 -0
  328. {calkit_python-0.38.4 → calkit_python-0.39.1}/yarn.lock +0 -0
@@ -21,3 +21,7 @@ Agents should never make commits to Git.
21
21
 
22
22
  Prefer tests that include multiple scenarios to comprehensively test
23
23
  a feature in one function over many different test functions.
24
+
25
+ Do not write docstrings in test functions.
26
+
27
+ For prose, only use one space after punctuation.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: calkit-python
3
- Version: 0.38.4
3
+ Version: 0.39.1
4
4
  Summary: Reproducibility simplified.
5
5
  Project-URL: Homepage, https://calkit.org
6
6
  Project-URL: Issues, https://github.com/calkit/calkit/issues
@@ -1,9 +1,47 @@
1
+ from __future__ import annotations
2
+
1
3
  from importlib.metadata import version as _version
4
+ from typing import TYPE_CHECKING
2
5
 
3
6
  __version__ = _version("calkit-python")
4
7
 
5
8
  from .core import * # noqa: F403, I001
6
9
 
10
+ if TYPE_CHECKING:
11
+ from calkit import ( # noqa: F401
12
+ calc,
13
+ check,
14
+ cloud,
15
+ conda,
16
+ config,
17
+ datasets,
18
+ detect,
19
+ docker,
20
+ dvc,
21
+ environments,
22
+ fs,
23
+ git,
24
+ github,
25
+ gui,
26
+ invenio,
27
+ julia,
28
+ jupyter,
29
+ licenses,
30
+ magics,
31
+ matlab,
32
+ models,
33
+ notebooks,
34
+ office,
35
+ ops,
36
+ overleaf,
37
+ pipeline,
38
+ releases,
39
+ server,
40
+ templates,
41
+ )
42
+
43
+ from .notebooks import declare_notebook # noqa: F401
44
+
7
45
  # Lazy-load submodules to speed up imports
8
46
  _SUBMODULES = {
9
47
  "git",
@@ -174,14 +174,13 @@ def check_reproducibility(
174
174
  wdir: str = ".", log_func: Callable | None = None
175
175
  ) -> ReproCheck:
176
176
  """Check the reproducibility of a project."""
177
- import git
178
177
  from git.exc import InvalidGitRepositoryError
179
178
 
180
179
  res = dict()
181
180
  if log_func is None:
182
181
  log_func = print
183
182
  try:
184
- git.Repo(wdir)
183
+ calkit.git.get_repo(wdir)
185
184
  res["is_git_repo"] = True
186
185
  except InvalidGitRepositoryError:
187
186
  res["is_git_repo"] = False
@@ -1292,9 +1292,7 @@ def check_env_vars(
1292
1292
  dotenv_path=".env", key_to_set=name, value_to_set=value
1293
1293
  )
1294
1294
  # Ensure that .env is ignored by git
1295
- import git
1296
-
1297
- repo = git.Repo()
1295
+ repo = calkit.git.get_repo()
1298
1296
  if not repo.ignored(".env"):
1299
1297
  typer.echo("Adding .env to .gitignore")
1300
1298
  with open(".gitignore", "a") as f:
@@ -92,7 +92,6 @@ def setup_remote(
92
92
  """Setup the Calkit cloud as the default DVC remote and store a token in
93
93
  the local config.
94
94
  """
95
- import git
96
95
  from git.exc import InvalidGitRepositoryError
97
96
 
98
97
  from calkit.dvc import configure_remote, set_remote_auth
@@ -113,7 +112,7 @@ def setup_remote(
113
112
  except (ValueError, RuntimeError) as e:
114
113
  raise_error(f"Failed to set up DVC remote: {e}")
115
114
  if not no_commit:
116
- repo = git.Repo()
115
+ repo = calkit.git.get_repo()
117
116
  repo.git.add(".dvc/config")
118
117
  if ".dvc/config" in calkit.git.get_staged_files():
119
118
  typer.echo("Committing changes to DVC config")
@@ -46,10 +46,25 @@ def complete_stage_names(
46
46
  ryaml = ruamel.yaml.YAML()
47
47
  with open("calkit.yaml") as f:
48
48
  info = ryaml.load(f) or {}
49
+ candidates: list[str] = []
49
50
  stages = info.get("pipeline", {}).get("stages", {})
51
+ candidates.extend(stages.keys())
52
+ for sp_cfg in info.get("subprojects", []):
53
+ if not isinstance(sp_cfg, dict) or not sp_cfg.get("path"):
54
+ continue
55
+ sp_path = sp_cfg["path"]
56
+ sp_calkit = os.path.join(sp_path, "calkit.yaml")
57
+ sp_name = os.path.basename(sp_path.rstrip("/"))
58
+ candidates.append(sp_name)
59
+ if os.path.isfile(sp_calkit):
60
+ with open(sp_calkit) as f:
61
+ sp_info = ryaml.load(f) or {}
62
+ sp_stages = sp_info.get("pipeline", {}).get("stages", {})
63
+ for stage in sp_stages:
64
+ candidates.append(f"{sp_name}:{stage}")
50
65
  return [
51
66
  CompletionItem(name)
52
- for name in stages
67
+ for name in candidates
53
68
  if name.startswith(incomplete)
54
69
  ]
55
70
  except Exception:
@@ -72,7 +72,6 @@ def import_dataset(
72
72
 
73
73
  Currently only supports datasets kept in DVC, not Git.
74
74
  """
75
- import git
76
75
  import requests
77
76
  from tqdm import tqdm
78
77
 
@@ -95,7 +94,7 @@ def import_dataset(
95
94
  raise_error("A dataset already exists in this project at this path")
96
95
  elif overwrite and ds_dest_path in ds_paths:
97
96
  datasets = [ds for ds in datasets if ds["path"] != ds_dest_path]
98
- repo = git.Repo()
97
+ repo = calkit.git.get_repo()
99
98
  # Obtain, save, and commit the .dvc file for the dataset, or if this is
100
99
  # kept in Git, just download the files and commit them here
101
100
  typer.echo("Fetching import info")
@@ -261,8 +260,6 @@ def import_environment(
261
260
  ] = False,
262
261
  ) -> None:
263
262
  """Import an environment from another project."""
264
- import git
265
-
266
263
  raise_error(
267
264
  "This command is not yet implemented; "
268
265
  "please thumbs-up this issue if you'd like to see "
@@ -317,7 +314,7 @@ def import_environment(
317
314
  ck_info["environments"] = environments
318
315
  with open("calkit.yaml", "w") as f:
319
316
  calkit.ryaml.dump(ck_info, f)
320
- repo = git.Repo()
317
+ repo = calkit.git.get_repo()
321
318
  repo.git.add("calkit.yaml")
322
319
  if not no_commit and calkit.git.get_staged_files():
323
320
  repo.git.commit(["-m", f"Import environment {src}"])
@@ -371,7 +368,6 @@ def import_from_zenodo(
371
368
  ] = False,
372
369
  ):
373
370
  """Import files from a Zenodo record."""
374
- import git
375
371
  import requests
376
372
 
377
373
  from calkit.dvc import run_dvc_command
@@ -440,7 +436,7 @@ def import_from_zenodo(
440
436
  for chunk in resp.iter_content(chunk_size=8192):
441
437
  f.write(chunk)
442
438
  # Decide if this should be stored in Git or DVC
443
- repo = git.Repo()
439
+ repo = calkit.git.get_repo()
444
440
  commit_paths = []
445
441
  if storage is None:
446
442
  if calkit.get_size(dest_dir) > calkit.DVC_SIZE_THRESH_BYTES:
@@ -508,7 +504,7 @@ def import_from_zenodo(
508
504
  json.dump(imports, f, indent=2)
509
505
  # Commit if desired
510
506
  if not no_commit:
511
- repo = git.Repo()
507
+ repo = calkit.git.get_repo()
512
508
  repo.git.add(commit_paths)
513
509
  if repo.git.diff(commit_paths + ["--staged"]):
514
510
  repo.git.commit(
@@ -151,10 +151,8 @@ def list_stages(
151
151
  @list_app.command(name="remotes")
152
152
  def list_remotes():
153
153
  """List Git and DVC remotes."""
154
- import git
155
-
156
154
  try:
157
- repo = git.Repo()
155
+ repo = calkit.git.get_repo()
158
156
  for remote in repo.remotes:
159
157
  typer.echo(f"(Git) {remote.name}: {remote.url}")
160
158
  except Exception as e:
@@ -125,8 +125,6 @@ def init(
125
125
  ] = False,
126
126
  ):
127
127
  """Initialize the current working directory."""
128
- import git
129
-
130
128
  subprocess.run(["git", "init"])
131
129
  result = calkit.dvc.run_dvc_command(
132
130
  ["init"] + (["--force"] if force else [])
@@ -138,7 +136,7 @@ def init(
138
136
  if result != 0:
139
137
  raise_error("Failed to configure DVC autostage")
140
138
  # Commit the newly created .dvc directory
141
- repo = git.Repo()
139
+ repo = calkit.git.get_repo()
142
140
  repo.git.add(".dvc")
143
141
  repo.git.commit("-m", "Initialize DVC")
144
142
  # TODO: Initialize `calkit.yaml`
@@ -316,6 +314,17 @@ def get_status(
316
314
  ),
317
315
  ),
318
316
  ] = None,
317
+ no_check_envs: Annotated[
318
+ bool,
319
+ typer.Option(
320
+ "--no-env-check",
321
+ help=(
322
+ "Skip environment checks. "
323
+ "Note that this may produce an inaccurate pipeline status "
324
+ "if materialized environments have changed."
325
+ ),
326
+ ),
327
+ ] = False,
319
328
  as_json: Annotated[
320
329
  bool, typer.Option("--json", help="Output status as JSON.")
321
330
  ] = False,
@@ -325,10 +334,12 @@ def get_status(
325
334
  from git.exc import InvalidGitRepositoryError
326
335
 
327
336
  ck_info = calkit.load_calkit_info()
328
- # If there's anything in ck_info and this isn't a Git repo, initialize one
337
+ # If there's anything in ck_info and this isn't a Git repo, initialize one.
338
+ # Use search_parent_directories so a subproject folder inside a parent repo
339
+ # is discovered correctly rather than getting a new git init.
329
340
  if ck_info:
330
341
  try:
331
- git.Repo()
342
+ calkit.git.get_repo()
332
343
  except InvalidGitRepositoryError:
333
344
  git.Repo.init()
334
345
  valid_categories = ["project", "git", "dvc", "pipeline"]
@@ -349,7 +360,7 @@ def get_status(
349
360
  pipeline_status = calkit.pipeline.get_status(
350
361
  ck_info=ck_info,
351
362
  targets=targets,
352
- check_environments=True,
363
+ check_environments=not no_check_envs,
353
364
  clean_notebooks=True,
354
365
  compile_to_dvc=True,
355
366
  )
@@ -373,7 +384,7 @@ def get_status(
373
384
  )
374
385
  if "git" in categories:
375
386
  try:
376
- repo = git.Repo()
387
+ repo = calkit.git.get_repo()
377
388
  changed_files = calkit.git.get_changed_files(repo=repo)
378
389
  staged_files = calkit.git.get_staged_files(repo=repo)
379
390
  untracked_files = calkit.git.get_untracked_files(repo=repo)
@@ -577,7 +588,6 @@ def add(
577
588
  adding any .dvc files to Git when adding to DVC.
578
589
  """
579
590
  import dvc.repo
580
- import git
581
591
  from dvc.exceptions import NotDvcRepoError
582
592
  from git.exc import InvalidGitRepositoryError
583
593
 
@@ -598,7 +608,7 @@ def add(
598
608
  if to is not None and to not in ["git", "dvc", "dvc-zip"]:
599
609
  raise_error(f"Invalid option for 'to': {to}")
600
610
  try:
601
- repo = git.Repo()
611
+ repo = calkit.git.get_repo()
602
612
  except InvalidGitRepositoryError:
603
613
  # Prompt user if they want to run git init here
604
614
  warn("Current directory is not a Git repo")
@@ -610,7 +620,7 @@ def add(
610
620
  subprocess.check_call(["git", "init"])
611
621
  else:
612
622
  raise_error("Not currently in a Git repo; run `calkit init` first")
613
- repo = git.Repo()
623
+ repo = calkit.git.get_repo()
614
624
  try:
615
625
  dvc_repo = calkit.dvc.get_dvc_repo()
616
626
  except NotDvcRepoError:
@@ -1043,10 +1053,32 @@ def pull(
1043
1053
  if calkit.dvc.detect_calkit_remote_type(name, url) == "http":
1044
1054
  typer.echo(f"Checking authentication for DVC remote: {name}")
1045
1055
  calkit.dvc.set_remote_auth(remote_name=name)
1056
+ if (
1057
+ not no_recursive
1058
+ and "--recursive" not in dvc_args
1059
+ and "-R" not in dvc_args
1060
+ ):
1061
+ dvc_args.append("--recursive")
1046
1062
  result = calkit.dvc.run_dvc_command(["pull"] + dvc_args)
1047
1063
  if result != 0:
1048
1064
  raise_error("DVC pull failed")
1049
1065
  calkit.dvc.zip.sync_all(direction="to-workspace")
1066
+ if not no_recursive:
1067
+ # Pull DVC in isolated subprojects (those with their own .dvc folder)
1068
+ ck_info = calkit.load_calkit_info()
1069
+ for sp in ck_info.get("subprojects", []):
1070
+ if not isinstance(sp, dict) or not sp.get("path"):
1071
+ continue
1072
+ sp_path = sp["path"]
1073
+ if not os.path.isdir(os.path.join(sp_path, ".dvc")):
1074
+ continue
1075
+ typer.echo(f"DVC pulling subproject: {sp_path}")
1076
+ sp_result = calkit.dvc.run_dvc_command(
1077
+ ["pull"] + dvc_args, cwd=sp_path
1078
+ )
1079
+ if sp_result != 0:
1080
+ raise_error(f"DVC pull failed for subproject: {sp_path}")
1081
+ calkit.dvc.zip.sync_all(direction="to-workspace", wdir=sp_path)
1050
1082
 
1051
1083
 
1052
1084
  @app.command(name="push")
@@ -1116,9 +1148,7 @@ def ignore(
1116
1148
  ] = False,
1117
1149
  ):
1118
1150
  """Ignore a file, i.e., keep it out of version control."""
1119
- import git
1120
-
1121
- repo = git.Repo()
1151
+ repo = calkit.git.get_repo()
1122
1152
  # Ensure path makes it into .gitignore as a POSIX path
1123
1153
  path = Path(path).as_posix()
1124
1154
  if repo.ignored(path):
@@ -1129,7 +1159,7 @@ def ignore(
1129
1159
  with open(".gitignore", "a") as f:
1130
1160
  f.write(txt)
1131
1161
  if not no_commit:
1132
- repo = git.Repo()
1162
+ repo = calkit.git.get_repo()
1133
1163
  repo.git.reset()
1134
1164
  repo.git.add(".gitignore")
1135
1165
  if calkit.git.get_staged_files():
@@ -1384,13 +1414,18 @@ def run(
1384
1414
  help="Sync with Overleaf before and after running.",
1385
1415
  ),
1386
1416
  ] = False,
1417
+ no_push: Annotated[
1418
+ bool,
1419
+ typer.Option(
1420
+ "--no-push", help="Do not push to Git and DVC after saving."
1421
+ ),
1422
+ ] = False,
1387
1423
  ) -> dict:
1388
1424
  """Check dependencies and run the pipeline."""
1389
1425
  import dvc.log
1390
1426
  import dvc.repo
1391
1427
  import dvc.repo.reproduce
1392
1428
  import dvc.ui
1393
- import git
1394
1429
  from dvc.cli import main as dvc_cli_main
1395
1430
  from git.exc import InvalidGitRepositoryError
1396
1431
 
@@ -1404,9 +1439,11 @@ def run(
1404
1439
  os.environ["CALKIT_PIPELINE_RUNNING"] = "1"
1405
1440
  dotenv.load_dotenv(dotenv_path=".env", verbose=verbose)
1406
1441
  ck_info = calkit.load_calkit_info()
1407
- # Ensure Git is initialized so DVC can be used
1442
+ # Ensure Git is initialized so DVC can be used.
1443
+ # Use search_parent_directories so running from a subproject folder
1444
+ # discovers the parent repo instead of triggering a new git init.
1408
1445
  try:
1409
- git.Repo()
1446
+ calkit.git.get_repo()
1410
1447
  except InvalidGitRepositoryError:
1411
1448
  if not quiet:
1412
1449
  typer.echo("Initializing Git repo")
@@ -1456,12 +1493,45 @@ def run(
1456
1493
  failed = not result.get("success", False)
1457
1494
  if failed:
1458
1495
  warn(f"Failed to check environment '{env_name}'")
1496
+ # Check environments for each subproject so DVC can detect changes
1497
+ subprojects = ck_info.get("subprojects", [])
1498
+ if subprojects:
1499
+ prev_cwd = os.getcwd()
1500
+ for subproject in subprojects:
1501
+ if not isinstance(subproject, dict) or not subproject.get("path"):
1502
+ continue
1503
+ sp = Path(subproject["path"]).as_posix()
1504
+ if not os.path.isdir(sp):
1505
+ continue
1506
+ if not quiet:
1507
+ typer.echo(f"Checking environments for subproject: {sp}")
1508
+ os.chdir(sp)
1509
+ try:
1510
+ sp_ck_info = calkit.load_calkit_info()
1511
+ sp_env_results = calkit.environments.check_all_in_pipeline(
1512
+ ck_info=sp_ck_info, force=force
1513
+ )
1514
+ for env_name, sp_result in sp_env_results.items():
1515
+ if verbose:
1516
+ typer.echo(f"{sp}/{env_name}: {sp_result}")
1517
+ if not sp_result.get("success", False):
1518
+ warn(
1519
+ f"Failed to check environment '{env_name}' "
1520
+ f"in subproject '{sp}'"
1521
+ )
1522
+ except Exception as e:
1523
+ warn(
1524
+ f"Failed to check environments for subproject '{sp}': "
1525
+ f"{e.__class__.__name__}: {e}"
1526
+ )
1527
+ finally:
1528
+ os.chdir(prev_cwd)
1459
1529
  # If specified, perform initial Overleaf sync
1460
1530
  if sync_overleaf:
1461
1531
  overleaf_sync(no_commit=False, no_push=True, verbose=verbose)
1462
- # Compile the DVC pipeline
1532
+ # Compile the DVC pipeline (and subproject pipelines)
1463
1533
  dvc_stages = None
1464
- if ck_info.get("pipeline", {}):
1534
+ if ck_info.get("pipeline", {}) or ck_info.get("subprojects"):
1465
1535
  if not quiet:
1466
1536
  typer.echo("Compiling DVC pipeline")
1467
1537
  try:
@@ -1521,7 +1591,7 @@ def run(
1521
1591
  raise_error("No stages found to run")
1522
1592
  if save_logs:
1523
1593
  # Get status of Git repo before running
1524
- repo = git.Repo()
1594
+ repo = calkit.git.get_repo()
1525
1595
  git_rev = repo.head.commit.hexsha
1526
1596
  try:
1527
1597
  git_branch = repo.active_branch.name
@@ -1538,7 +1608,9 @@ def run(
1538
1608
  dvc_data_status_before.pop("git", None) # Remove git status
1539
1609
  if targets is None:
1540
1610
  targets = []
1541
- args = deepcopy(targets)
1611
+ args, isolated_sp_targets = calkit.pipeline.translate_run_targets(
1612
+ deepcopy(targets), ck_info=ck_info
1613
+ )
1542
1614
  # Extract any boolean args
1543
1615
  for name in [
1544
1616
  "quiet",
@@ -1560,6 +1632,47 @@ def run(
1560
1632
  ]:
1561
1633
  if locals()[name.replace("-", "_")]:
1562
1634
  args.append("--" + name)
1635
+ # Inline subprojects (no .dvc/ dir) share the parent DVC project.
1636
+ # Tell DVC to discover all pipelines so their dvc.yaml files are included,
1637
+ # unless the user already specified targets that include dvc.yaml paths
1638
+ # (translated from subproject shorthand) or --all-pipelines was passed.
1639
+ inline_subprojects = [
1640
+ sp
1641
+ for sp in subprojects
1642
+ if isinstance(sp, dict)
1643
+ and sp.get("path")
1644
+ and not os.path.isdir(os.path.join(sp["path"], ".dvc"))
1645
+ ]
1646
+ translated_targets_have_dvc_yaml = any(
1647
+ "dvc.yaml" in t for t in args if not t.startswith("--")
1648
+ )
1649
+ if (
1650
+ inline_subprojects
1651
+ and not targets
1652
+ and not all_pipelines
1653
+ and not translated_targets_have_dvc_yaml
1654
+ ):
1655
+ args.append("--all-pipelines")
1656
+ failed = False
1657
+ # Run isolated subproject stage targets directly inside their directories.
1658
+ if isolated_sp_targets:
1659
+ for sp_path, stage_name in isolated_sp_targets:
1660
+ sp_args = [stage_name] if stage_name else []
1661
+ if dry:
1662
+ sp_args.append("--dry")
1663
+ if force:
1664
+ sp_args.append("--force")
1665
+ original_dir = os.getcwd()
1666
+ try:
1667
+ os.chdir(sp_path)
1668
+ sp_res = dvc_cli_main(["repro"] + sp_args)
1669
+ finally:
1670
+ os.chdir(original_dir)
1671
+ if sp_res != 0:
1672
+ failed = True
1673
+ if not args or all(a.startswith("--") for a in args):
1674
+ # Only isolated subproject stage targets were given; skip parent run
1675
+ return {}
1563
1676
  if pipeline is not None:
1564
1677
  args += ["--pipeline", pipeline]
1565
1678
  if downstream is not None:
@@ -1593,7 +1706,7 @@ def run(
1593
1706
  # Disable other misc DVC output
1594
1707
  dvc.ui.ui.write = lambda *args, **kwargs: None
1595
1708
  res = dvc_cli_main(["repro"] + args)
1596
- failed = res != 0
1709
+ failed = failed or res != 0
1597
1710
  # Parse log to get timing and which stages ran
1598
1711
  with open(log_fpath, "r") as f:
1599
1712
  log_content = f.read()
@@ -1687,7 +1800,7 @@ def run(
1687
1800
  save_message = "Run pipeline"
1688
1801
  if not quiet:
1689
1802
  typer.echo("Saving the project after successful run")
1690
- save(save_all=True, message=save_message)
1803
+ save(save_all=True, message=save_message, no_push=no_push)
1691
1804
  # If specified, perform final Overleaf sync
1692
1805
  if sync_overleaf:
1693
1806
  overleaf_sync(
@@ -2272,8 +2385,6 @@ def run_procedure(
2272
2385
  return bool(value)
2273
2386
  return value
2274
2387
 
2275
- import git
2276
-
2277
2388
  from calkit.models import Procedure
2278
2389
 
2279
2390
  ck_info = calkit.load_calkit_info(process_includes="procedures")
@@ -2285,7 +2396,7 @@ def run_procedure(
2285
2396
  proc = Procedure.model_validate(procs[name])
2286
2397
  except Exception as e:
2287
2398
  raise_error(f"Procedure '{name}' is invalid: {e}")
2288
- git_repo = git.Repo()
2399
+ git_repo = calkit.git.get_repo()
2289
2400
  # Check to make sure the working tree is clean, so we know we ran the
2290
2401
  # committed version of the procedure
2291
2402
  git_status = git_repo.git.status()
@@ -2431,10 +2542,8 @@ def set_env_var(
2431
2542
  value: Annotated[str, typer.Argument(help="Value of the variable.")],
2432
2543
  ):
2433
2544
  """Set an environmental variable for the project in its '.env' file."""
2434
- import git
2435
-
2436
2545
  # Ensure that .env is ignored by git
2437
- repo = git.Repo()
2546
+ repo = calkit.git.get_repo()
2438
2547
  if not repo.ignored(".env"):
2439
2548
  typer.echo("Adding .env to .gitignore")
2440
2549
  with open(".gitignore", "a") as f:
@@ -2493,9 +2602,7 @@ def upgrade(
2493
2602
  @app.command(name="switch-branch")
2494
2603
  def switch_branch(name: Annotated[str, typer.Argument(help="Branch name.")]):
2495
2604
  """Switch to a different branch."""
2496
- import git
2497
-
2498
- repo = git.Repo()
2605
+ repo = calkit.git.get_repo()
2499
2606
  if name not in repo.heads:
2500
2607
  typer.echo(f"Branch '{name}' does not exist; creating")
2501
2608
  cmd = ["-b", name]
@@ -2624,9 +2731,7 @@ def map_paths(
2624
2731
  Currently this is done with copying. Outputs are ensured to be ignored by
2625
2732
  Git.
2626
2733
  """
2627
- import git
2628
-
2629
- repo = git.Repo()
2734
+ repo = calkit.git.get_repo()
2630
2735
 
2631
2736
  def validate_and_split(mapping: str) -> tuple[str, str]:
2632
2737
  if "->" not in mapping:
@@ -297,7 +297,7 @@ def execute_and_record(
297
297
  language = "latex"
298
298
  pdf_path = first_arg.removesuffix(".tex") + ".pdf"
299
299
  try:
300
- repo = git.Repo(".")
300
+ repo = calkit.git.get_repo()
301
301
  if repo.git.ls_files(pdf_path):
302
302
  stage["pdf_storage"] = "git"
303
303
  else:
@@ -484,7 +484,7 @@ def execute_and_record(
484
484
  )
485
485
  # Initialize git repo and get DVC paths for storage determination
486
486
  try:
487
- repo = git.Repo(".")
487
+ repo = calkit.git.get_repo()
488
488
  except InvalidGitRepositoryError:
489
489
  repo = None
490
490
  dvc_paths = []