calkit-python 0.40.1__tar.gz → 0.41.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 (337) hide show
  1. {calkit_python-0.40.1 → calkit_python-0.41.1}/AGENTS.md +4 -0
  2. {calkit_python-0.40.1 → calkit_python-0.41.1}/PKG-INFO +69 -1
  3. {calkit_python-0.40.1 → calkit_python-0.41.1}/README.md +68 -0
  4. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/__init__.py +4 -0
  5. calkit_python-0.41.1/calkit/cli/__init__.py +53 -0
  6. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/cli/check.py +82 -24
  7. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/cli/list.py +28 -0
  8. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/cli/main/core.py +151 -0
  9. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/cli/new.py +179 -17
  10. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/cli/scheduler.py +16 -5
  11. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/cli/update.py +99 -9
  12. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/core.py +154 -33
  13. calkit_python-0.41.1/calkit/dependencies.py +409 -0
  14. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/environments.py +136 -0
  15. calkit_python-0.41.1/calkit/install.py +229 -0
  16. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/models/core.py +40 -2
  17. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/models/pipeline.py +37 -0
  18. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/pipeline.py +2 -2
  19. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/tests/cli/main/test_core.py +125 -0
  20. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/tests/cli/test_new.py +17 -0
  21. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/tests/models/test_pipeline.py +46 -0
  22. calkit_python-0.41.1/calkit/tests/test_dependencies.py +277 -0
  23. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/tests/test_environments.py +85 -0
  24. calkit_python-0.41.1/calkit/tests/test_install.py +210 -0
  25. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/cli-reference.md +158 -105
  26. calkit_python-0.41.1/docs/dependencies.md +264 -0
  27. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/environments.md +77 -0
  28. calkit_python-0.41.1/docs/installation.md +130 -0
  29. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/pipeline/index.md +24 -0
  30. calkit_python-0.41.1/flake.lock +27 -0
  31. calkit_python-0.41.1/flake.nix +70 -0
  32. {calkit_python-0.40.1 → calkit_python-0.41.1}/scripts/generate-docs-references.py +13 -1
  33. calkit_python-0.40.1/calkit/cli/__init__.py +0 -7
  34. calkit_python-0.40.1/docs/dependencies.md +0 -70
  35. calkit_python-0.40.1/docs/installation.md +0 -62
  36. {calkit_python-0.40.1 → calkit_python-0.41.1}/.claude-plugin/marketplace.json +0 -0
  37. {calkit_python-0.40.1 → calkit_python-0.41.1}/.gitignore +0 -0
  38. {calkit_python-0.40.1 → calkit_python-0.41.1}/.pre-commit-config.yaml +0 -0
  39. {calkit_python-0.40.1 → calkit_python-0.41.1}/.prettierignore +0 -0
  40. {calkit_python-0.40.1 → calkit_python-0.41.1}/.python-version +0 -0
  41. {calkit_python-0.40.1 → calkit_python-0.41.1}/.vscode/launch.json +0 -0
  42. {calkit_python-0.40.1 → calkit_python-0.41.1}/.vscode/tasks.json +0 -0
  43. {calkit_python-0.40.1 → calkit_python-0.41.1}/.yarnrc.yml +0 -0
  44. {calkit_python-0.40.1 → calkit_python-0.41.1}/CITATION.cff +0 -0
  45. {calkit_python-0.40.1 → calkit_python-0.41.1}/CODE_OF_CONDUCT.md +0 -0
  46. {calkit_python-0.40.1 → calkit_python-0.41.1}/CONTRIBUTING.md +0 -0
  47. {calkit_python-0.40.1 → calkit_python-0.41.1}/LICENSE +0 -0
  48. {calkit_python-0.40.1 → calkit_python-0.41.1}/Makefile +0 -0
  49. {calkit_python-0.40.1 → calkit_python-0.41.1}/agent-plugin/.claude-plugin/plugin.json +0 -0
  50. {calkit_python-0.40.1 → calkit_python-0.41.1}/agent-plugin/skills/add-pipeline-stage/SKILL.md +0 -0
  51. {calkit_python-0.40.1 → calkit_python-0.41.1}/agent-plugin/skills/conventions/SKILL.md +0 -0
  52. {calkit_python-0.40.1 → calkit_python-0.41.1}/agent-plugin/skills/create-pipeline/SKILL.md +0 -0
  53. {calkit_python-0.40.1 → calkit_python-0.41.1}/babel.config.js +0 -0
  54. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/__main__.py +0 -0
  55. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/calc.py +0 -0
  56. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/check.py +0 -0
  57. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/cli/cloud.py +0 -0
  58. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/cli/config.py +0 -0
  59. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/cli/core.py +0 -0
  60. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/cli/describe.py +0 -0
  61. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/cli/dev.py +0 -0
  62. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/cli/import_.py +0 -0
  63. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/cli/latex.py +0 -0
  64. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/cli/main/__init__.py +0 -0
  65. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/cli/main/xr.py +0 -0
  66. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/cli/notebooks.py +0 -0
  67. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/cli/office.py +0 -0
  68. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/cli/overleaf.py +0 -0
  69. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/cloud.py +0 -0
  70. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/conda.py +0 -0
  71. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/config.py +0 -0
  72. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/datasets.py +0 -0
  73. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/detect.py +0 -0
  74. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/docker.py +0 -0
  75. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/dvc/__init__.py +0 -0
  76. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/dvc/core.py +0 -0
  77. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/dvc/zip.py +0 -0
  78. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/fs.py +0 -0
  79. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/git.py +0 -0
  80. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/github.py +0 -0
  81. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/gui.py +0 -0
  82. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/invenio.py +0 -0
  83. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/julia.py +0 -0
  84. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/jupyter.py +0 -0
  85. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/jupyterlab/__init__.py +0 -0
  86. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/jupyterlab/routes.py +0 -0
  87. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/labextension/package.json +0 -0
  88. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/labextension/schemas/calkit/package.json.orig +0 -0
  89. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/labextension/schemas/calkit/plugin.json +0 -0
  90. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/labextension/static/502.9a2c5772a15466e923ef.js +0 -0
  91. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/labextension/static/695.2c41003a452d43d2b358.js +0 -0
  92. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/labextension/static/867.a42a046aa5108f54f8fb.js +0 -0
  93. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/labextension/static/909.e3f9cc3408834a7fdcc3.js +0 -0
  94. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/labextension/static/946.050af2abf7845cfbdbd2.js +0 -0
  95. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/labextension/static/946.050af2abf7845cfbdbd2.js.LICENSE.txt +0 -0
  96. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/labextension/static/b2f1c3efe70cb539d121.png +0 -0
  97. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/labextension/static/remoteEntry.65469af996e7a96aa983.js +0 -0
  98. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/labextension/static/style.js +0 -0
  99. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/labextension/static/third-party-licenses.json +0 -0
  100. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/licenses.py +0 -0
  101. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/magics.py +0 -0
  102. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/matlab.py +0 -0
  103. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/models/__init__.py +0 -0
  104. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/models/io.py +0 -0
  105. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/models/iteration.py +0 -0
  106. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/notebooks.py +0 -0
  107. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/office.py +0 -0
  108. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/ops.py +0 -0
  109. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/overleaf.py +0 -0
  110. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/releases.py +0 -0
  111. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/server.py +0 -0
  112. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/templates/__init__.py +0 -0
  113. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/templates/core.py +0 -0
  114. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/templates/latex/__init__.py +0 -0
  115. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/templates/latex/article/paper.tex +0 -0
  116. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/templates/latex/core.py +0 -0
  117. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/templates/latex/jfm/jfm.bst +0 -0
  118. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/templates/latex/jfm/jfm.cls +0 -0
  119. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/templates/latex/jfm/lineno-FLM.sty +0 -0
  120. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/templates/latex/jfm/paper.tex +0 -0
  121. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/templates/latex/jfm/upmath.sty +0 -0
  122. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/tests/__init__.py +0 -0
  123. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/tests/cli/__init__.py +0 -0
  124. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/tests/cli/main/__init__.py +0 -0
  125. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/tests/cli/main/test_subprojects.py +0 -0
  126. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/tests/cli/main/test_xr.py +0 -0
  127. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/tests/cli/test_check.py +0 -0
  128. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/tests/cli/test_cloud.py +0 -0
  129. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/tests/cli/test_config.py +0 -0
  130. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/tests/cli/test_import.py +0 -0
  131. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/tests/cli/test_latex.py +0 -0
  132. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/tests/cli/test_list.py +0 -0
  133. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/tests/cli/test_notebooks.py +0 -0
  134. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/tests/cli/test_overleaf.py +0 -0
  135. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/tests/cli/test_update.py +0 -0
  136. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/tests/dvc/__init__.py +0 -0
  137. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/tests/dvc/test_core.py +0 -0
  138. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/tests/dvc/test_zip.py +0 -0
  139. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/tests/jupyterlab/__init__.py +0 -0
  140. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/tests/jupyterlab/test_routes.py +0 -0
  141. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/tests/models/__init__.py +0 -0
  142. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/tests/models/test_iteration.py +0 -0
  143. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/tests/test_calc.py +0 -0
  144. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/tests/test_check.py +0 -0
  145. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/tests/test_cloud.py +0 -0
  146. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/tests/test_conda.py +0 -0
  147. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/tests/test_core.py +0 -0
  148. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/tests/test_detect.py +0 -0
  149. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/tests/test_docker.py +0 -0
  150. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/tests/test_fs.py +0 -0
  151. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/tests/test_git.py +0 -0
  152. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/tests/test_invenio.py +0 -0
  153. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/tests/test_julia.py +0 -0
  154. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/tests/test_jupyter.py +0 -0
  155. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/tests/test_magics.py +0 -0
  156. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/tests/test_matlab.py +0 -0
  157. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/tests/test_notebooks.py +0 -0
  158. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/tests/test_pipeline.py +0 -0
  159. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/tests/test_releases.py +0 -0
  160. {calkit_python-0.40.1 → calkit_python-0.41.1}/calkit/tests/test_templates.py +0 -0
  161. {calkit_python-0.40.1 → calkit_python-0.41.1}/conftest.py +0 -0
  162. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/CNAME +0 -0
  163. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/ai-tools.md +0 -0
  164. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/apps.md +0 -0
  165. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/calculations.md +0 -0
  166. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/calkit-yaml.md +0 -0
  167. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/cloud-integration.md +0 -0
  168. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/datasets.md +0 -0
  169. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/examples.md +0 -0
  170. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/governance.md +0 -0
  171. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/help.md +0 -0
  172. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/hpc.md +0 -0
  173. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/img/c-to-the-k-white.svg +0 -0
  174. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/img/calkit-fragmentation-compendium.png +0 -0
  175. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/img/calkit-no-bg.png +0 -0
  176. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/img/connect-zenodo.png +0 -0
  177. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/img/jupyterlab/all-green.png +0 -0
  178. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/img/jupyterlab/collect-data-stale.png +0 -0
  179. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/img/jupyterlab/new-env.png +0 -0
  180. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/img/jupyterlab/new-notebook.png +0 -0
  181. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/img/jupyterlab/pipeline-badge.png +0 -0
  182. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/img/jupyterlab-params.png +0 -0
  183. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/img/plos-osi-code-2024-03.png +0 -0
  184. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/img/vscode-nb-params.png +0 -0
  185. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/index.md +0 -0
  186. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/jupyterlab.md +0 -0
  187. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/local-server.md +0 -0
  188. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/notebooks.md +0 -0
  189. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/overleaf.md +0 -0
  190. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/pipeline/manual-steps.md +0 -0
  191. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/pipeline/running-and-logging.md +0 -0
  192. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/quickstart.md +0 -0
  193. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/references.md +0 -0
  194. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/releases.md +0 -0
  195. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/reproducibility.md +0 -0
  196. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/subprojects.md +0 -0
  197. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/tutorials/adding-latex-pub-docker.md +0 -0
  198. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/tutorials/conda-envs.md +0 -0
  199. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/tutorials/existing-project.md +0 -0
  200. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/tutorials/first-project.md +0 -0
  201. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/tutorials/github-actions.md +0 -0
  202. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/tutorials/img/actions-repo-secrets.png +0 -0
  203. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/tutorials/img/latex-codespaces/building-codespace.png +0 -0
  204. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/tutorials/img/latex-codespaces/codespaces-secrets-2.png +0 -0
  205. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/tutorials/img/latex-codespaces/editor-split.png +0 -0
  206. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/tutorials/img/latex-codespaces/go-to-linked-code.png +0 -0
  207. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/tutorials/img/latex-codespaces/issue-from-selection.png +0 -0
  208. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/tutorials/img/latex-codespaces/new-project.png +0 -0
  209. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/tutorials/img/latex-codespaces/new-pub-2.png +0 -0
  210. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/tutorials/img/latex-codespaces/new-token.png +0 -0
  211. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/tutorials/img/latex-codespaces/paper.tex.png +0 -0
  212. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/tutorials/img/latex-codespaces/project-home-3.png +0 -0
  213. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/tutorials/img/latex-codespaces/push.png +0 -0
  214. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/tutorials/img/latex-codespaces/stage.png +0 -0
  215. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/tutorials/img/office/anakin-excel.jpg +0 -0
  216. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/tutorials/img/office/chart-more-rows.png +0 -0
  217. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/tutorials/img/office/create-project.png +0 -0
  218. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/tutorials/img/office/elsevier-research-data-guidelines.png +0 -0
  219. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/tutorials/img/office/excel-chart.png +0 -0
  220. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/tutorials/img/office/excel-data.png +0 -0
  221. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/tutorials/img/office/insert-link-to-file.png +0 -0
  222. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/tutorials/img/office/needs-clone.png +0 -0
  223. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/tutorials/img/office/new-stage.png +0 -0
  224. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/tutorials/img/office/phd-comics-version-control.webp +0 -0
  225. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/tutorials/img/office/pipeline-out-of-date.png +0 -0
  226. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/tutorials/img/office/status-more-rows.png +0 -0
  227. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/tutorials/img/office/uncommitted-changes.png +0 -0
  228. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/tutorials/img/office/untracked-data.png +0 -0
  229. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/tutorials/img/office/updated-publication.png +0 -0
  230. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/tutorials/img/office/word-to-pdf-stage-2.png +0 -0
  231. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/tutorials/img/office/workflow-page.png +0 -0
  232. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/tutorials/img/openfoam/clone.png +0 -0
  233. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/tutorials/img/openfoam/create-project.png +0 -0
  234. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/tutorials/img/openfoam/datasets-page.png +0 -0
  235. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/tutorials/img/openfoam/figure-on-website-updated.png +0 -0
  236. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/tutorials/img/openfoam/figure-on-website.png +0 -0
  237. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/tutorials/img/openfoam/new-token.png +0 -0
  238. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/tutorials/img/openfoam/reclone.png +0 -0
  239. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/tutorials/img/openfoam/status-after-import-dataset.png +0 -0
  240. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/tutorials/img/quick-actions.png +0 -0
  241. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/tutorials/img/run-proc.png +0 -0
  242. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/tutorials/img/vscode-slurm-notebook/create-calkit-env.png +0 -0
  243. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/tutorials/img/vscode-slurm-notebook/create-inner-env.png +0 -0
  244. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/tutorials/img/vscode-slurm-notebook/create-new-calkit-env.png +0 -0
  245. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/tutorials/img/vscode-slurm-notebook/select-calkit-env.png +0 -0
  246. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/tutorials/img/vscode-slurm-notebook/slurm-job-running.png +0 -0
  247. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/tutorials/img/vscode-slurm-notebook/slurm-launch-options.png +0 -0
  248. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/tutorials/img/vscode-slurm-notebook/starting-slurm-job.png +0 -0
  249. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/tutorials/index.md +0 -0
  250. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/tutorials/jupyterlab.md +0 -0
  251. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/tutorials/latex-codespaces.md +0 -0
  252. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/tutorials/matlab.md +0 -0
  253. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/tutorials/notebook-pipeline.md +0 -0
  254. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/tutorials/office.md +0 -0
  255. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/tutorials/openfoam.md +0 -0
  256. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/tutorials/procedures.md +0 -0
  257. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/tutorials/vscode-slurm-notebook.md +0 -0
  258. {calkit_python-0.40.1 → calkit_python-0.41.1}/docs/version-control.md +0 -0
  259. {calkit_python-0.40.1 → calkit_python-0.41.1}/install.json +0 -0
  260. {calkit_python-0.40.1 → calkit_python-0.41.1}/jest.config.js +0 -0
  261. {calkit_python-0.40.1 → calkit_python-0.41.1}/jupyter-config/server-config/calkit.json +0 -0
  262. {calkit_python-0.40.1 → calkit_python-0.41.1}/mkdocs.yml +0 -0
  263. {calkit_python-0.40.1 → calkit_python-0.41.1}/package.json +0 -0
  264. {calkit_python-0.40.1 → calkit_python-0.41.1}/pyproject.toml +0 -0
  265. {calkit_python-0.40.1 → calkit_python-0.41.1}/schema/plugin.json +0 -0
  266. {calkit_python-0.40.1 → calkit_python-0.41.1}/scripts/install.ps1 +0 -0
  267. {calkit_python-0.40.1 → calkit_python-0.41.1}/scripts/install.sh +0 -0
  268. {calkit_python-0.40.1 → calkit_python-0.41.1}/scripts/make-calk9.sh +0 -0
  269. {calkit_python-0.40.1 → calkit_python-0.41.1}/scripts/sync-docs.py +0 -0
  270. {calkit_python-0.40.1 → calkit_python-0.41.1}/src/__tests__/useQueries.spec.ts +0 -0
  271. {calkit_python-0.40.1 → calkit_python-0.41.1}/src/calkit-config.ts +0 -0
  272. {calkit_python-0.40.1 → calkit_python-0.41.1}/src/cell-output-marker.ts +0 -0
  273. {calkit_python-0.40.1 → calkit_python-0.41.1}/src/components/commit-dialog.tsx +0 -0
  274. {calkit_python-0.40.1 → calkit_python-0.41.1}/src/components/environment-editor.tsx +0 -0
  275. {calkit_python-0.40.1 → calkit_python-0.41.1}/src/components/notebook-registration.tsx +0 -0
  276. {calkit_python-0.40.1 → calkit_python-0.41.1}/src/components/notebook-toolbar.tsx +0 -0
  277. {calkit_python-0.40.1 → calkit_python-0.41.1}/src/components/pipeline-status-bar.tsx +0 -0
  278. {calkit_python-0.40.1 → calkit_python-0.41.1}/src/components/project-info-editor.tsx +0 -0
  279. {calkit_python-0.40.1 → calkit_python-0.41.1}/src/components/sidebar-settings.tsx +0 -0
  280. {calkit_python-0.40.1 → calkit_python-0.41.1}/src/components/sidebar.tsx +0 -0
  281. {calkit_python-0.40.1 → calkit_python-0.41.1}/src/components/stage-editor.tsx +0 -0
  282. {calkit_python-0.40.1 → calkit_python-0.41.1}/src/feature-flags.ts +0 -0
  283. {calkit_python-0.40.1 → calkit_python-0.41.1}/src/file-browser-menu.ts +0 -0
  284. {calkit_python-0.40.1 → calkit_python-0.41.1}/src/hooks/__tests__/useQueries.test.tsx +0 -0
  285. {calkit_python-0.40.1 → calkit_python-0.41.1}/src/hooks/useQueries.ts +0 -0
  286. {calkit_python-0.40.1 → calkit_python-0.41.1}/src/icons.ts +0 -0
  287. {calkit_python-0.40.1 → calkit_python-0.41.1}/src/index.ts +0 -0
  288. {calkit_python-0.40.1 → calkit_python-0.41.1}/src/io-tracker.ts +0 -0
  289. {calkit_python-0.40.1 → calkit_python-0.41.1}/src/pipeline-state.ts +0 -0
  290. {calkit_python-0.40.1 → calkit_python-0.41.1}/src/queryClient.ts +0 -0
  291. {calkit_python-0.40.1 → calkit_python-0.41.1}/src/request.ts +0 -0
  292. {calkit_python-0.40.1 → calkit_python-0.41.1}/src/shims-mainmenu.d.ts +0 -0
  293. {calkit_python-0.40.1 → calkit_python-0.41.1}/style/base.css +0 -0
  294. {calkit_python-0.40.1 → calkit_python-0.41.1}/style/cell-output-marker.css +0 -0
  295. {calkit_python-0.40.1 → calkit_python-0.41.1}/style/environment-editor.css +0 -0
  296. {calkit_python-0.40.1 → calkit_python-0.41.1}/style/environment-selector.css +0 -0
  297. {calkit_python-0.40.1 → calkit_python-0.41.1}/style/img/calkit-no-bg.png +0 -0
  298. {calkit_python-0.40.1 → calkit_python-0.41.1}/style/index.css +0 -0
  299. {calkit_python-0.40.1 → calkit_python-0.41.1}/style/index.js +0 -0
  300. {calkit_python-0.40.1 → calkit_python-0.41.1}/style/notebook-toolbar.css +0 -0
  301. {calkit_python-0.40.1 → calkit_python-0.41.1}/style/pipeline-status-bar.css +0 -0
  302. {calkit_python-0.40.1 → calkit_python-0.41.1}/style/sidebar.css +0 -0
  303. {calkit_python-0.40.1 → calkit_python-0.41.1}/test/dvc-md5-dir/osx-arm64.txt +0 -0
  304. {calkit_python-0.40.1 → calkit_python-0.41.1}/test/nb-julia.ipynb +0 -0
  305. {calkit_python-0.40.1 → calkit_python-0.41.1}/test/nb-params.ipynb +0 -0
  306. {calkit_python-0.40.1 → calkit_python-0.41.1}/test/nb-subdir.ipynb +0 -0
  307. {calkit_python-0.40.1 → calkit_python-0.41.1}/test/pipeline.ipynb +0 -0
  308. {calkit_python-0.40.1 → calkit_python-0.41.1}/test/script.py +0 -0
  309. {calkit_python-0.40.1 → calkit_python-0.41.1}/test/test-log.log +0 -0
  310. {calkit_python-0.40.1 → calkit_python-0.41.1}/tsconfig.json +0 -0
  311. {calkit_python-0.40.1 → calkit_python-0.41.1}/tsconfig.test.json +0 -0
  312. {calkit_python-0.40.1 → calkit_python-0.41.1}/ui-tests/.gitignore +0 -0
  313. {calkit_python-0.40.1 → calkit_python-0.41.1}/ui-tests/README.md +0 -0
  314. {calkit_python-0.40.1 → calkit_python-0.41.1}/ui-tests/jupyter_server_test_config.py +0 -0
  315. {calkit_python-0.40.1 → calkit_python-0.41.1}/ui-tests/package.json +0 -0
  316. {calkit_python-0.40.1 → calkit_python-0.41.1}/ui-tests/playwright.config.js +0 -0
  317. {calkit_python-0.40.1 → calkit_python-0.41.1}/ui-tests/tests/calkit.spec.ts +0 -0
  318. {calkit_python-0.40.1 → calkit_python-0.41.1}/ui-tests/yarn.lock +0 -0
  319. {calkit_python-0.40.1 → calkit_python-0.41.1}/uv.lock +0 -0
  320. {calkit_python-0.40.1 → calkit_python-0.41.1}/vscode-ext/.gitignore +0 -0
  321. {calkit_python-0.40.1 → calkit_python-0.41.1}/vscode-ext/.vscodeignore +0 -0
  322. {calkit_python-0.40.1 → calkit_python-0.41.1}/vscode-ext/CHANGELOG.md +0 -0
  323. {calkit_python-0.40.1 → calkit_python-0.41.1}/vscode-ext/LICENSE +0 -0
  324. {calkit_python-0.40.1 → calkit_python-0.41.1}/vscode-ext/README.md +0 -0
  325. {calkit_python-0.40.1 → calkit_python-0.41.1}/vscode-ext/images/calkit-no-bg.png +0 -0
  326. {calkit_python-0.40.1 → calkit_python-0.41.1}/vscode-ext/package-lock.json +0 -0
  327. {calkit_python-0.40.1 → calkit_python-0.41.1}/vscode-ext/package.json +0 -0
  328. {calkit_python-0.40.1 → calkit_python-0.41.1}/vscode-ext/scripts/set-proposed-api.js +0 -0
  329. {calkit_python-0.40.1 → calkit_python-0.41.1}/vscode-ext/src/environments.ts +0 -0
  330. {calkit_python-0.40.1 → calkit_python-0.41.1}/vscode-ext/src/extension.ts +0 -0
  331. {calkit_python-0.40.1 → calkit_python-0.41.1}/vscode-ext/src/notebooks.ts +0 -0
  332. {calkit_python-0.40.1 → calkit_python-0.41.1}/vscode-ext/src/test/environments.test.ts +0 -0
  333. {calkit_python-0.40.1 → calkit_python-0.41.1}/vscode-ext/src/test/kernel-selection.test.ts +0 -0
  334. {calkit_python-0.40.1 → calkit_python-0.41.1}/vscode-ext/src/test/notebooks.test.ts +0 -0
  335. {calkit_python-0.40.1 → calkit_python-0.41.1}/vscode-ext/src/types.ts +0 -0
  336. {calkit_python-0.40.1 → calkit_python-0.41.1}/vscode-ext/tsconfig.json +0 -0
  337. {calkit_python-0.40.1 → calkit_python-0.41.1}/yarn.lock +0 -0
@@ -25,3 +25,7 @@ a feature in one function over many different test functions.
25
25
  Do not write docstrings in test functions.
26
26
 
27
27
  For prose, only use one space after punctuation.
28
+
29
+ Don't overzealously split up functions just because they're long.
30
+ Functions should usually be used ~3 times before abstracting.
31
+ Otherwise, split up long ones into logical sections with comments.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: calkit-python
3
- Version: 0.40.1
3
+ Version: 0.41.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
@@ -193,6 +193,74 @@ you can use uv's `uvx` command to run it directly:
193
193
  uvx calk9 --help
194
194
  ```
195
195
 
196
+ ### Nix
197
+
198
+ Calkit ships a [flake](https://nixos.wiki/wiki/Flakes) at the root of
199
+ its repo, so [Nix](https://nixos.org/) users can pull the CLI into their
200
+ environments alongside their other tools.
201
+
202
+ Run it ad hoc without installing:
203
+
204
+ ```sh
205
+ nix run github:calkit/calkit -- --help
206
+ ```
207
+
208
+ Drop into a shell that has `calkit`, `git`, and `uv` on `PATH`:
209
+
210
+ ```sh
211
+ nix shell github:calkit/calkit
212
+ ```
213
+
214
+ Add it to your own `flake.nix` as an input:
215
+
216
+ ```nix
217
+ {
218
+ inputs.calkit.url = "github:calkit/calkit";
219
+ inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
220
+
221
+ outputs = { self, nixpkgs, calkit }: {
222
+ devShells.x86_64-linux.default =
223
+ nixpkgs.legacyPackages.x86_64-linux.mkShell {
224
+ packages = [ calkit.packages.x86_64-linux.default ];
225
+ };
226
+ };
227
+ }
228
+ ```
229
+
230
+ Then `nix develop` will give you a shell with the Calkit CLI ready to
231
+ use. To pin a specific Calkit release inside the shell, set the
232
+ `CALKIT_VERSION` environment variable (e.g. `CALKIT_VERSION=0.41.0`)
233
+ before invoking `calkit`.
234
+
235
+ The flake is currently a thin wrapper around `uvx --from calkit-python
236
+ calkit`. It depends on `uv` from `nixpkgs` and fetches the published
237
+ wheel from PyPI on first use. This trades a fully Nix-native build for
238
+ zero version-drift maintenance, and avoids the macOS `docx2pdf` /
239
+ `appscript` and JupyterLab labextension build issues that block a pure
240
+ nixpkgs derivation today. If you want a fully nixpkgs-native build,
241
+ see the community [`calkit-nix`](https://github.com/dwinkler1/calkit-nix)
242
+ flake.
243
+
244
+ Nix isn't supported natively on Windows; run Calkit inside
245
+ [WSL2](https://learn.microsoft.com/en-us/windows/wsl/install) and use
246
+ the flake there.
247
+
248
+ ### Running against a specific version
249
+
250
+ If a project requires a Calkit version other than the one you have
251
+ installed, use the top-level `--use-version` flag to re-invoke the CLI
252
+ under that release without changing your installation:
253
+
254
+ ```sh
255
+ calkit --use-version 0.38 run
256
+ ```
257
+
258
+ This re-execs the CLI via `uvx --from calkit-python@<version> calkit`,
259
+ so it requires [uv](https://docs.astral.sh/uv/) on `PATH`.
260
+ You can also declare a minimum version in `calkit.yaml`;
261
+ see
262
+ [Pinning the Calkit CLI version](https://docs.calkit.org/dependencies.md#pinning-the-calkit-cli-version).
263
+
196
264
  ### Calkit Assistant
197
265
 
198
266
  For Windows users, the
@@ -134,6 +134,74 @@ you can use uv's `uvx` command to run it directly:
134
134
  uvx calk9 --help
135
135
  ```
136
136
 
137
+ ### Nix
138
+
139
+ Calkit ships a [flake](https://nixos.wiki/wiki/Flakes) at the root of
140
+ its repo, so [Nix](https://nixos.org/) users can pull the CLI into their
141
+ environments alongside their other tools.
142
+
143
+ Run it ad hoc without installing:
144
+
145
+ ```sh
146
+ nix run github:calkit/calkit -- --help
147
+ ```
148
+
149
+ Drop into a shell that has `calkit`, `git`, and `uv` on `PATH`:
150
+
151
+ ```sh
152
+ nix shell github:calkit/calkit
153
+ ```
154
+
155
+ Add it to your own `flake.nix` as an input:
156
+
157
+ ```nix
158
+ {
159
+ inputs.calkit.url = "github:calkit/calkit";
160
+ inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
161
+
162
+ outputs = { self, nixpkgs, calkit }: {
163
+ devShells.x86_64-linux.default =
164
+ nixpkgs.legacyPackages.x86_64-linux.mkShell {
165
+ packages = [ calkit.packages.x86_64-linux.default ];
166
+ };
167
+ };
168
+ }
169
+ ```
170
+
171
+ Then `nix develop` will give you a shell with the Calkit CLI ready to
172
+ use. To pin a specific Calkit release inside the shell, set the
173
+ `CALKIT_VERSION` environment variable (e.g. `CALKIT_VERSION=0.41.0`)
174
+ before invoking `calkit`.
175
+
176
+ The flake is currently a thin wrapper around `uvx --from calkit-python
177
+ calkit`. It depends on `uv` from `nixpkgs` and fetches the published
178
+ wheel from PyPI on first use. This trades a fully Nix-native build for
179
+ zero version-drift maintenance, and avoids the macOS `docx2pdf` /
180
+ `appscript` and JupyterLab labextension build issues that block a pure
181
+ nixpkgs derivation today. If you want a fully nixpkgs-native build,
182
+ see the community [`calkit-nix`](https://github.com/dwinkler1/calkit-nix)
183
+ flake.
184
+
185
+ Nix isn't supported natively on Windows; run Calkit inside
186
+ [WSL2](https://learn.microsoft.com/en-us/windows/wsl/install) and use
187
+ the flake there.
188
+
189
+ ### Running against a specific version
190
+
191
+ If a project requires a Calkit version other than the one you have
192
+ installed, use the top-level `--use-version` flag to re-invoke the CLI
193
+ under that release without changing your installation:
194
+
195
+ ```sh
196
+ calkit --use-version 0.38 run
197
+ ```
198
+
199
+ This re-execs the CLI via `uvx --from calkit-python@<version> calkit`,
200
+ so it requires [uv](https://docs.astral.sh/uv/) on `PATH`.
201
+ You can also declare a minimum version in `calkit.yaml`;
202
+ see
203
+ [Pinning the Calkit CLI version](https://docs.calkit.org/dependencies.md#pinning-the-calkit-cli-version).
204
+
137
205
  ### Calkit Assistant
138
206
 
139
207
  For Windows users, the
@@ -15,6 +15,7 @@ if TYPE_CHECKING:
15
15
  conda,
16
16
  config,
17
17
  datasets,
18
+ dependencies,
18
19
  detect,
19
20
  docker,
20
21
  dvc,
@@ -23,6 +24,7 @@ if TYPE_CHECKING:
23
24
  git,
24
25
  github,
25
26
  gui,
27
+ install,
26
28
  invenio,
27
29
  julia,
28
30
  jupyter,
@@ -67,9 +69,11 @@ _SUBMODULES = {
67
69
  "pipeline",
68
70
  "matlab",
69
71
  "datasets",
72
+ "dependencies",
70
73
  "detect",
71
74
  "docker",
72
75
  "gui",
76
+ "install",
73
77
  "magics",
74
78
  "ops",
75
79
  "server",
@@ -0,0 +1,53 @@
1
+ from .core import * # noqa: F403
2
+
3
+
4
+ def run() -> None:
5
+ # Intercept ``--use-version`` before Typer/Click parses argv: Click
6
+ # processes eager options like ``--help`` and ``--version`` (and the
7
+ # group's ``no_args_is_help``) ahead of the callback body, so an
8
+ # invocation like ``calkit --use-version 0.1.1 -- --help`` would
9
+ # otherwise print the *current* CLI's help instead of re-execing
10
+ # under the requested version.
11
+ _maybe_exec_with_version()
12
+ from .main import app
13
+
14
+ app()
15
+
16
+
17
+ def _maybe_exec_with_version() -> None:
18
+ import sys
19
+
20
+ # Only scan the group's option region -- the tokens before the first
21
+ # subcommand (or the ``--`` end-of-options marker). A ``--use-version``
22
+ # buried in a forwarded arg (e.g. ``calkit xenv -- some-tool
23
+ # --use-version 1.0``) must not trigger a re-exec.
24
+ argv = sys.argv[1:]
25
+ version_spec: str | None = None
26
+ i = 0
27
+ while i < len(argv):
28
+ a = argv[i]
29
+ if a == "--":
30
+ break
31
+ if not a.startswith("-"):
32
+ # First non-option token is the subcommand name; stop here.
33
+ break
34
+ if a == "--use-version" and i + 1 < len(argv):
35
+ version_spec = argv[i + 1]
36
+ break
37
+ if a.startswith("--use-version="):
38
+ version_spec = a.split("=", 1)[1]
39
+ break
40
+ # Skip past an option's value when it takes one (heuristic: a
41
+ # following token that doesn't itself look like a flag). Worst
42
+ # case we treat a flag-with-no-value as one with one, which only
43
+ # affects where the loop terminates -- the outer ``break``s above
44
+ # still fire first if --use-version is present.
45
+ if i + 1 < len(argv) and not argv[i + 1].startswith("-"):
46
+ i += 2
47
+ else:
48
+ i += 1
49
+ if not version_spec:
50
+ return
51
+ from .main.core import _exec_with_version
52
+
53
+ _exec_with_version(version_spec)
@@ -14,10 +14,10 @@ import dotenv
14
14
  import typer
15
15
 
16
16
  import calkit
17
- from calkit.cli import raise_error, warn
17
+ from calkit.cli import AliasGroup, raise_error, warn
18
18
  from calkit.core import get_md5
19
19
 
20
- check_app = typer.Typer(no_args_is_help=True)
20
+ check_app = typer.Typer(cls=AliasGroup, no_args_is_help=True)
21
21
 
22
22
 
23
23
  def _juliaup_version_installed(julia_version: str) -> bool:
@@ -231,6 +231,61 @@ def _check_julia_env(
231
231
  return lock_fpath or os.path.join(env_dir, "Manifest.toml")
232
232
 
233
233
 
234
+ def _require_nix_available() -> None:
235
+ """Ensure the ``nix`` CLI is on PATH, with a friendly error otherwise.
236
+
237
+ On Windows we steer users to WSL2 rather than attempting native Nix,
238
+ which isn't officially supported.
239
+ """
240
+ if shutil.which("nix") is not None:
241
+ return
242
+ if _platform.system() == "Windows":
243
+ raise_error(
244
+ "Nix is not available natively on Windows. Run Calkit inside "
245
+ "WSL2 (https://learn.microsoft.com/en-us/windows/wsl/install) "
246
+ "and install Nix there."
247
+ )
248
+ raise_error(
249
+ "The 'nix' command was not found. Install it with "
250
+ "'calkit install nix' or from https://nixos.org/download."
251
+ )
252
+
253
+
254
+ def check_nix_env(env: dict, verbose: bool = False) -> str:
255
+ """Materialize / refresh ``flake.lock`` next to the flake.
256
+
257
+ Running ``nix flake lock`` writes ``flake.lock`` if missing and is a
258
+ no-op when the lock is already up-to-date. The lock file is what we
259
+ track as a DVC dep, so an out-of-date lock invalidates dependent
260
+ stages on the next ``calkit run``.
261
+ """
262
+ env_path = env.get("path")
263
+ if env_path is None:
264
+ raise_error("Nix environments require a path pointing to flake.nix")
265
+ assert isinstance(env_path, str)
266
+ if os.path.basename(env_path) != "flake.nix":
267
+ raise_error("Nix environments require a path pointing to flake.nix")
268
+ if not os.path.isfile(env_path):
269
+ raise_error(f"Nix flake not found: {env_path}")
270
+ _require_nix_available()
271
+ env_dir = os.path.dirname(os.path.abspath(env_path)) or "."
272
+ cmd = [
273
+ "nix",
274
+ "--extra-experimental-features",
275
+ "nix-command flakes",
276
+ "flake",
277
+ "lock",
278
+ ]
279
+ if verbose:
280
+ typer.echo(f"Running command: {cmd} (cwd={env_dir})")
281
+ try:
282
+ subprocess.check_call(cmd, cwd=env_dir)
283
+ except subprocess.CalledProcessError:
284
+ raise_error("Failed to lock Nix flake")
285
+ lock_fpath = os.path.join(os.path.dirname(env_path), "flake.lock")
286
+ return lock_fpath
287
+
288
+
234
289
  @check_app.command(name="repro")
235
290
  def check_repro(
236
291
  wdir: Annotated[
@@ -412,6 +467,8 @@ def check_environment(
412
467
  # env config so DVC stages that depend on the env get invalidated
413
468
  # when the config changes.
414
469
  write_scheduler_env_lock(env_name=env_name, env=env)
470
+ elif env["kind"] == "nix":
471
+ check_nix_env(env=env, verbose=verbose)
415
472
  else:
416
473
  raise_error(f"Environment kind '{env['kind']}' not supported")
417
474
  return get_env_lock_fpath(env=env, env_name=env_name, as_posix=False)
@@ -1243,20 +1300,31 @@ def check_matlab_env(
1243
1300
  )
1244
1301
 
1245
1302
 
1246
- @check_app.command(name="dependencies")
1247
- @check_app.command(name="deps")
1303
+ @check_app.command(name="deps|dependencies")
1248
1304
  def check_dependencies(
1249
1305
  verbose: Annotated[
1250
1306
  bool, typer.Option("--verbose", "-v", help="Print verbose output")
1251
1307
  ] = False,
1308
+ no_cache: Annotated[
1309
+ bool,
1310
+ typer.Option(
1311
+ "--no-cache",
1312
+ help=(
1313
+ "Re-probe every setup dependency, ignoring (and clearing) "
1314
+ "the cache at .calkit/local/dep-checks.sqlite."
1315
+ ),
1316
+ ),
1317
+ ] = False,
1252
1318
  ) -> None:
1253
1319
  """Check that a project's system-level dependencies are set up
1254
1320
  correctly.
1255
1321
  """
1256
1322
  typer.echo("Checking project dependencies")
1257
1323
  dotenv.load_dotenv(dotenv_path=".env", verbose=verbose)
1324
+ if no_cache:
1325
+ calkit.dependencies.cache_clear()
1258
1326
  try:
1259
- calkit.check_system_deps()
1327
+ calkit.check_system_deps(use_cache=not no_cache)
1260
1328
  except Exception as e:
1261
1329
  raise_error(str(e))
1262
1330
  message = "✅ All set!"
@@ -1278,32 +1346,22 @@ def check_env_vars(
1278
1346
  for name in env_var_dep_names:
1279
1347
  if verbose:
1280
1348
  typer.echo(f"Checking for environmental variable '{name}'")
1281
- attrs = {}
1349
+ # Pull the dep's attrs to honor any per-var default.
1350
+ attrs: dict = {}
1282
1351
  for dep in deps:
1283
- if isinstance(dep, dict) and "name" in dep:
1352
+ if isinstance(dep, dict) and dep.get("name") == name:
1284
1353
  attrs = dep
1285
1354
  break
1286
- elif isinstance(dep, dict) and list(dep.keys()) == [name]:
1287
- attrs = dep[name]
1355
+ if isinstance(dep, dict) and list(dep.keys()) == [name]:
1356
+ attrs = dep[name] or {}
1288
1357
  break
1289
1358
  if name not in os.environ:
1290
1359
  typer.echo(f"Missing env var '{name}'")
1291
- if "default" in attrs:
1292
- default = attrs["default"]
1293
- else:
1294
- default = None
1295
- value = typer.prompt(
1296
- f"Enter a value for {name}", default=default, type=str
1297
- )
1298
- dotenv.set_key(
1299
- dotenv_path=".env", key_to_set=name, value_to_set=value
1360
+ value = calkit.dependencies.prompt_and_store_env_var(
1361
+ name, default=attrs.get("default")
1300
1362
  )
1301
- # Ensure that .env is ignored by git
1302
- repo = calkit.git.get_repo()
1303
- if not repo.ignored(".env"):
1304
- typer.echo("Adding .env to .gitignore")
1305
- with open(".gitignore", "a") as f:
1306
- f.write("\n.env\n")
1363
+ if value is None:
1364
+ raise_error(f"No value provided for '{name}'")
1307
1365
  message = "✅ All set!"
1308
1366
  calkit.echo(message)
1309
1367
 
@@ -98,6 +98,34 @@ def list_templates():
98
98
  typer.echo(f"{kind}/{name}")
99
99
 
100
100
 
101
+ @list_app.command(name="installers")
102
+ def list_installers():
103
+ """List apps with a registered native installer.
104
+
105
+ These can be declared as ``kind: app`` dependencies in ``calkit.yaml``
106
+ and Calkit will offer to install them via ``calkit install <name>`` or
107
+ automatically during ``calkit run`` on an interactive TTY.
108
+ """
109
+ # Group entries that share the same underlying installer (e.g.,
110
+ # ``cargo``/``rustup``, ``julia``/``juliaup``) so the listing reflects
111
+ # the alias relationship rather than implying separate scripts.
112
+ groups: dict[int, list[str]] = {}
113
+ for name, entry in calkit.install.INSTALLERS.items():
114
+ groups.setdefault(id(entry), []).append(name)
115
+ for names in groups.values():
116
+ names.sort()
117
+ canonical = names[0]
118
+ entry = calkit.install.INSTALLERS[canonical]
119
+ aliases = ", ".join(names[1:])
120
+ header = canonical + (f" (aliases: {aliases})" if aliases else "")
121
+ typer.echo(header)
122
+ for platform in ("unix", "windows"):
123
+ ins = entry.get(platform) # type: ignore[arg-type]
124
+ if ins is None:
125
+ continue
126
+ typer.echo(f" {platform}: {ins['script']}")
127
+
128
+
101
129
  @list_app.command(name="procedures")
102
130
  def list_procedures():
103
131
  """List procedures in the current project."""
@@ -111,10 +111,63 @@ def main(
111
111
  bool,
112
112
  typer.Option("--version", help="Show version and exit."),
113
113
  ] = False,
114
+ use_version: Annotated[
115
+ Optional[str],
116
+ typer.Option(
117
+ "--use-version",
118
+ help=(
119
+ "Re-invoke the CLI under a specific calkit-python version "
120
+ "via 'uvx --from'."
121
+ ),
122
+ ),
123
+ ] = None,
114
124
  ):
115
125
  if version:
116
126
  typer.echo(f"Calkit {calkit.__version__}")
117
127
  raise typer.Exit()
128
+ if use_version:
129
+ _exec_with_version(use_version)
130
+
131
+
132
+ def _exec_with_version(version_spec: str) -> None:
133
+ """Replace this process with ``uvx --from calkit-python<spec> calkit ...``.
134
+
135
+ Strips ``--use-version`` from ``sys.argv`` before re-invoking so the
136
+ child process doesn't loop. Requires ``uv`` to be available on PATH.
137
+ """
138
+ from calkit.dependencies import _format_uvx_from
139
+
140
+ if shutil.which("uvx") is None:
141
+ raise_error(
142
+ "'--use-version' requires 'uvx' (install uv: "
143
+ "https://docs.astral.sh/uv/)."
144
+ )
145
+ cleaned: list[str] = []
146
+ argv = sys.argv[1:]
147
+ i = 0
148
+ while i < len(argv):
149
+ a = argv[i]
150
+ if a == "--use-version":
151
+ i += 2
152
+ continue
153
+ if a.startswith("--use-version="):
154
+ i += 1
155
+ continue
156
+ cleaned.append(a)
157
+ i += 1
158
+ # A leading ``--`` was only needed to escape *our* option parser
159
+ # (e.g. ``ck --use-version 0.3 -- --version``). Forwarding it would
160
+ # leave the child CLI to interpret it as a positional, so older
161
+ # versions error with "No such command '--version'".
162
+ if cleaned and cleaned[0] == "--":
163
+ cleaned = cleaned[1:]
164
+ cmd = [
165
+ "uvx",
166
+ "--from",
167
+ _format_uvx_from(version_spec),
168
+ "calkit",
169
+ ] + cleaned
170
+ os.execvp(cmd[0], cmd)
118
171
 
119
172
 
120
173
  @app.command(name="init")
@@ -346,6 +399,17 @@ def get_status(
346
399
  calkit.git.get_repo()
347
400
  except InvalidGitRepositoryError:
348
401
  git.Repo.init()
402
+ # Likewise, if this isn't a DVC repo, initialize one so the pipeline
403
+ # can be compiled and its status reported. DVC init requires a Git
404
+ # repo, which the block above ensures exists.
405
+ if not os.path.isfile(os.path.join(".dvc", "config")):
406
+ typer.echo("Initializing DVC repository")
407
+ try:
408
+ result = calkit.dvc.run_dvc_command(["init", "-q"])
409
+ if result != 0:
410
+ raise subprocess.CalledProcessError(result, "dvc init")
411
+ except subprocess.CalledProcessError as e:
412
+ raise_error(f"Failed to initialize DVC repository: {e}")
349
413
  valid_categories = ["project", "git", "dvc", "pipeline"]
350
414
  if categories is not None:
351
415
  for category in categories:
@@ -2332,6 +2396,44 @@ def run_in_env(
2332
2396
  subprocess.check_call(cmd, cwd=env_dir, env=env_vars)
2333
2397
  except subprocess.CalledProcessError:
2334
2398
  raise_error("Failed to run in renv")
2399
+ elif env["kind"] == "nix":
2400
+ from calkit.cli.check import check_nix_env
2401
+
2402
+ env_path = env.get("path")
2403
+ if env_path is None:
2404
+ raise_error(
2405
+ "Nix environments require a path pointing to flake.nix"
2406
+ )
2407
+ assert isinstance(env_path, str)
2408
+ if os.path.basename(env_path) != "flake.nix":
2409
+ raise_error(
2410
+ "Nix environments require a path pointing to flake.nix"
2411
+ )
2412
+ if not no_check:
2413
+ check_nix_env(env=env, verbose=verbose)
2414
+ env_dir = os.path.dirname(os.path.abspath(env_path)) or "."
2415
+ flake_ref = f"path:{env_dir}"
2416
+ shell_name = env.get("shell")
2417
+ if shell_name:
2418
+ flake_ref = f"{flake_ref}#{shell_name}"
2419
+ shell_cmd = _to_shell_cmd(cmd)
2420
+ nix_cmd = [
2421
+ "nix",
2422
+ "--extra-experimental-features",
2423
+ "nix-command flakes",
2424
+ "develop",
2425
+ flake_ref,
2426
+ "--command",
2427
+ "sh",
2428
+ "-c",
2429
+ shell_cmd,
2430
+ ]
2431
+ if verbose:
2432
+ typer.echo(f"Running command: {nix_cmd}")
2433
+ try:
2434
+ subprocess.check_call(nix_cmd, cwd=wdir)
2435
+ except subprocess.CalledProcessError:
2436
+ raise_error("Failed to run in Nix environment")
2335
2437
  elif env["kind"] == "matlab":
2336
2438
  if not no_check:
2337
2439
  check_matlab_env(
@@ -2379,6 +2481,55 @@ def run_in_env(
2379
2481
  raise_error("Environment kind not supported")
2380
2482
 
2381
2483
 
2484
+ @app.command(
2485
+ name="install",
2486
+ help=(
2487
+ "Install a registered native dependency (e.g., pixi, uv) via its "
2488
+ "upstream installer for the current platform."
2489
+ ),
2490
+ )
2491
+ def install_app(
2492
+ name: Annotated[
2493
+ str,
2494
+ typer.Argument(
2495
+ help="The app to install (e.g., 'pixi', 'uv').",
2496
+ ),
2497
+ ],
2498
+ yes: Annotated[
2499
+ bool,
2500
+ typer.Option(
2501
+ "--yes",
2502
+ "-y",
2503
+ help="Skip the confirmation prompt and install immediately.",
2504
+ ),
2505
+ ] = False,
2506
+ ) -> None:
2507
+ from calkit import install as _install
2508
+
2509
+ # Surface a platform-specific "use X instead" message before the
2510
+ # generic "no installer" error -- e.g., Nix on Windows needs WSL2.
2511
+ unsupported = _install.get_unsupported_message(name)
2512
+ if unsupported:
2513
+ raise_error(unsupported)
2514
+ entry = _install.get_installer(name)
2515
+ if entry is None:
2516
+ raise_error(
2517
+ f"No registered installer for '{name}'. Known apps: "
2518
+ + ", ".join(sorted(_install.INSTALLERS))
2519
+ )
2520
+ # ``--yes`` makes this scriptable (CI, provisioning) without losing
2521
+ # the safety prompt for plain interactive use.
2522
+ if yes:
2523
+ ok = _install.install(name)
2524
+ else:
2525
+ from calkit.dependencies import _is_interactive
2526
+
2527
+ ok = _install.prompt_and_install(name, interactive=_is_interactive())
2528
+ if not ok:
2529
+ raise_error(f"Failed to install '{name}'")
2530
+ typer.echo(f"✅ Installed '{name}'")
2531
+
2532
+
2382
2533
  @app.command(name="xproc|runproc", help="Execute a procedure.")
2383
2534
  def run_procedure(
2384
2535
  name: Annotated[str, typer.Argument(help="The name of the procedure.")],