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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (303) hide show
  1. {calkit_python-0.35.7 → calkit_python-0.36.0}/.gitignore +1 -1
  2. calkit_python-0.36.0/.vscode/launch.json +17 -0
  3. calkit_python-0.36.0/.vscode/tasks.json +15 -0
  4. {calkit_python-0.35.7 → calkit_python-0.36.0}/PKG-INFO +1 -1
  5. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/cli/main/core.py +83 -4
  6. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/cli/new.py +153 -30
  7. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/cli/notebooks.py +119 -13
  8. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/cli/update.py +127 -0
  9. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/labextension/package.json +14 -0
  10. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/labextension/schemas/calkit/package.json.orig +14 -0
  11. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/tests/cli/test_new.py +16 -0
  12. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/tests/cli/test_notebooks.py +36 -0
  13. calkit_python-0.36.0/calkit/tests/cli/test_update.py +22 -0
  14. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/cli-reference.md +149 -41
  15. {calkit_python-0.35.7 → calkit_python-0.36.0}/package.json +14 -0
  16. {calkit_python-0.35.7 → calkit_python-0.36.0}/pyproject.toml +1 -0
  17. calkit_python-0.36.0/vscode-ext/.gitignore +3 -0
  18. calkit_python-0.36.0/vscode-ext/.vscodeignore +5 -0
  19. calkit_python-0.36.0/vscode-ext/CHANGELOG.md +6 -0
  20. calkit_python-0.36.0/vscode-ext/LICENSE +19 -0
  21. calkit_python-0.36.0/vscode-ext/README.md +66 -0
  22. calkit_python-0.36.0/vscode-ext/images/calkit-no-bg.png +0 -0
  23. calkit_python-0.36.0/vscode-ext/package-lock.json +77 -0
  24. calkit_python-0.36.0/vscode-ext/package.json +138 -0
  25. calkit_python-0.36.0/vscode-ext/scripts/set-proposed-api.js +25 -0
  26. calkit_python-0.36.0/vscode-ext/src/environments.ts +224 -0
  27. calkit_python-0.36.0/vscode-ext/src/extension.ts +3510 -0
  28. calkit_python-0.36.0/vscode-ext/src/notebooks.ts +79 -0
  29. calkit_python-0.36.0/vscode-ext/src/test/environments.test.ts +130 -0
  30. calkit_python-0.36.0/vscode-ext/src/test/notebooks.test.ts +70 -0
  31. calkit_python-0.36.0/vscode-ext/src/types.ts +25 -0
  32. calkit_python-0.36.0/vscode-ext/tsconfig.json +14 -0
  33. {calkit_python-0.35.7 → calkit_python-0.36.0}/.pre-commit-config.yaml +0 -0
  34. {calkit_python-0.35.7 → calkit_python-0.36.0}/.prettierignore +0 -0
  35. {calkit_python-0.35.7 → calkit_python-0.36.0}/.python-version +0 -0
  36. {calkit_python-0.35.7 → calkit_python-0.36.0}/.yarnrc.yml +0 -0
  37. {calkit_python-0.35.7 → calkit_python-0.36.0}/CITATION.cff +0 -0
  38. {calkit_python-0.35.7 → calkit_python-0.36.0}/CODE_OF_CONDUCT.md +0 -0
  39. {calkit_python-0.35.7 → calkit_python-0.36.0}/CONTRIBUTING.md +0 -0
  40. {calkit_python-0.35.7 → calkit_python-0.36.0}/LICENSE +0 -0
  41. {calkit_python-0.35.7 → calkit_python-0.36.0}/Makefile +0 -0
  42. {calkit_python-0.35.7 → calkit_python-0.36.0}/README.md +0 -0
  43. {calkit_python-0.35.7 → calkit_python-0.36.0}/babel.config.js +0 -0
  44. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/__init__.py +0 -0
  45. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/__main__.py +0 -0
  46. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/calc.py +0 -0
  47. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/check.py +0 -0
  48. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/cli/__init__.py +0 -0
  49. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/cli/check.py +0 -0
  50. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/cli/cloud.py +0 -0
  51. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/cli/config.py +0 -0
  52. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/cli/core.py +0 -0
  53. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/cli/describe.py +0 -0
  54. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/cli/import_.py +0 -0
  55. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/cli/latex.py +0 -0
  56. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/cli/list.py +0 -0
  57. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/cli/main/__init__.py +0 -0
  58. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/cli/main/xr.py +0 -0
  59. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/cli/office.py +0 -0
  60. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/cli/overleaf.py +0 -0
  61. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/cli/slurm.py +0 -0
  62. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/cloud.py +0 -0
  63. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/conda.py +0 -0
  64. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/config.py +0 -0
  65. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/core.py +0 -0
  66. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/datasets.py +0 -0
  67. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/detect.py +0 -0
  68. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/docker.py +0 -0
  69. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/dvc.py +0 -0
  70. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/environments.py +0 -0
  71. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/fs.py +0 -0
  72. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/git.py +0 -0
  73. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/github.py +0 -0
  74. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/gui.py +0 -0
  75. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/invenio.py +0 -0
  76. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/julia.py +0 -0
  77. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/jupyter.py +0 -0
  78. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/jupyterlab/__init__.py +0 -0
  79. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/jupyterlab/routes.py +0 -0
  80. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/labextension/schemas/calkit/plugin.json +0 -0
  81. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/labextension/static/502.9a2c5772a15466e923ef.js +0 -0
  82. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/labextension/static/695.2c41003a452d43d2b358.js +0 -0
  83. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/labextension/static/867.a42a046aa5108f54f8fb.js +0 -0
  84. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/labextension/static/909.651be47ca47390b78a92.js +0 -0
  85. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/labextension/static/946.050af2abf7845cfbdbd2.js +0 -0
  86. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/labextension/static/946.050af2abf7845cfbdbd2.js.LICENSE.txt +0 -0
  87. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/labextension/static/b2f1c3efe70cb539d121.png +0 -0
  88. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/labextension/static/remoteEntry.c091821b3d7f2d287a67.js +0 -0
  89. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/labextension/static/style.js +0 -0
  90. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/labextension/static/third-party-licenses.json +0 -0
  91. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/licenses.py +0 -0
  92. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/magics.py +0 -0
  93. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/matlab.py +0 -0
  94. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/models/__init__.py +0 -0
  95. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/models/core.py +0 -0
  96. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/models/io.py +0 -0
  97. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/models/iteration.py +0 -0
  98. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/models/pipeline.py +0 -0
  99. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/notebooks.py +0 -0
  100. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/office.py +0 -0
  101. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/ops.py +0 -0
  102. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/overleaf.py +0 -0
  103. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/pipeline.py +0 -0
  104. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/releases.py +0 -0
  105. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/server.py +0 -0
  106. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/templates/__init__.py +0 -0
  107. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/templates/core.py +0 -0
  108. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/templates/latex/__init__.py +0 -0
  109. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/templates/latex/article/paper.tex +0 -0
  110. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/templates/latex/core.py +0 -0
  111. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/templates/latex/jfm/jfm.bst +0 -0
  112. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/templates/latex/jfm/jfm.cls +0 -0
  113. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/templates/latex/jfm/lineno-FLM.sty +0 -0
  114. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/templates/latex/jfm/paper.tex +0 -0
  115. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/templates/latex/jfm/upmath.sty +0 -0
  116. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/tests/__init__.py +0 -0
  117. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/tests/cli/__init__.py +0 -0
  118. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/tests/cli/main/__init__.py +0 -0
  119. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/tests/cli/main/test_core.py +0 -0
  120. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/tests/cli/main/test_xr.py +0 -0
  121. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/tests/cli/test_check.py +0 -0
  122. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/tests/cli/test_config.py +0 -0
  123. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/tests/cli/test_import.py +0 -0
  124. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/tests/cli/test_latex.py +0 -0
  125. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/tests/cli/test_list.py +0 -0
  126. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/tests/cli/test_overleaf.py +0 -0
  127. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/tests/jupyterlab/__init__.py +0 -0
  128. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/tests/jupyterlab/test_routes.py +0 -0
  129. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/tests/models/__init__.py +0 -0
  130. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/tests/models/test_iteration.py +0 -0
  131. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/tests/models/test_pipeline.py +0 -0
  132. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/tests/test_calc.py +0 -0
  133. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/tests/test_check.py +0 -0
  134. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/tests/test_conda.py +0 -0
  135. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/tests/test_core.py +0 -0
  136. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/tests/test_detect.py +0 -0
  137. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/tests/test_docker.py +0 -0
  138. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/tests/test_dvc.py +0 -0
  139. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/tests/test_environments.py +0 -0
  140. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/tests/test_fs.py +0 -0
  141. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/tests/test_git.py +0 -0
  142. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/tests/test_invenio.py +0 -0
  143. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/tests/test_julia.py +0 -0
  144. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/tests/test_jupyter.py +0 -0
  145. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/tests/test_magics.py +0 -0
  146. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/tests/test_matlab.py +0 -0
  147. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/tests/test_notebooks.py +0 -0
  148. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/tests/test_pipeline.py +0 -0
  149. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/tests/test_releases.py +0 -0
  150. {calkit_python-0.35.7 → calkit_python-0.36.0}/calkit/tests/test_templates.py +0 -0
  151. {calkit_python-0.35.7 → calkit_python-0.36.0}/conftest.py +0 -0
  152. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/CNAME +0 -0
  153. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/apps.md +0 -0
  154. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/calculations.md +0 -0
  155. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/calkit-yaml.md +0 -0
  156. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/cloud-integration.md +0 -0
  157. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/datasets.md +0 -0
  158. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/dependencies.md +0 -0
  159. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/environments.md +0 -0
  160. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/examples.md +0 -0
  161. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/governance.md +0 -0
  162. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/help.md +0 -0
  163. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/img/c-to-the-k-white.svg +0 -0
  164. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/img/calkit-fragmentation-compendium.png +0 -0
  165. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/img/calkit-no-bg.png +0 -0
  166. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/img/connect-zenodo.png +0 -0
  167. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/img/jupyterlab/all-green.png +0 -0
  168. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/img/jupyterlab/collect-data-stale.png +0 -0
  169. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/img/jupyterlab/new-env.png +0 -0
  170. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/img/jupyterlab/new-notebook.png +0 -0
  171. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/img/jupyterlab/pipeline-badge.png +0 -0
  172. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/img/jupyterlab-params.png +0 -0
  173. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/img/plos-osi-code-2024-03.png +0 -0
  174. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/img/vscode-nb-params.png +0 -0
  175. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/index.md +0 -0
  176. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/installation.md +0 -0
  177. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/jupyterlab.md +0 -0
  178. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/local-server.md +0 -0
  179. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/notebooks.md +0 -0
  180. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/overleaf.md +0 -0
  181. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/pipeline/index.md +0 -0
  182. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/pipeline/manual-steps.md +0 -0
  183. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/pipeline/running-and-logging.md +0 -0
  184. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/pipeline/slurm.md +0 -0
  185. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/quickstart.md +0 -0
  186. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/references.md +0 -0
  187. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/releases.md +0 -0
  188. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/reproducibility.md +0 -0
  189. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/tutorials/adding-latex-pub-docker.md +0 -0
  190. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/tutorials/conda-envs.md +0 -0
  191. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/tutorials/existing-project.md +0 -0
  192. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/tutorials/first-project.md +0 -0
  193. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/tutorials/github-actions.md +0 -0
  194. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/tutorials/img/actions-repo-secrets.png +0 -0
  195. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/tutorials/img/latex-codespaces/building-codespace.png +0 -0
  196. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/tutorials/img/latex-codespaces/codespaces-secrets-2.png +0 -0
  197. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/tutorials/img/latex-codespaces/editor-split.png +0 -0
  198. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/tutorials/img/latex-codespaces/go-to-linked-code.png +0 -0
  199. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/tutorials/img/latex-codespaces/issue-from-selection.png +0 -0
  200. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/tutorials/img/latex-codespaces/new-project.png +0 -0
  201. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/tutorials/img/latex-codespaces/new-pub-2.png +0 -0
  202. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/tutorials/img/latex-codespaces/new-token.png +0 -0
  203. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/tutorials/img/latex-codespaces/paper.tex.png +0 -0
  204. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/tutorials/img/latex-codespaces/project-home-3.png +0 -0
  205. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/tutorials/img/latex-codespaces/push.png +0 -0
  206. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/tutorials/img/latex-codespaces/stage.png +0 -0
  207. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/tutorials/img/office/anakin-excel.jpg +0 -0
  208. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/tutorials/img/office/chart-more-rows.png +0 -0
  209. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/tutorials/img/office/create-project.png +0 -0
  210. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/tutorials/img/office/elsevier-research-data-guidelines.png +0 -0
  211. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/tutorials/img/office/excel-chart.png +0 -0
  212. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/tutorials/img/office/excel-data.png +0 -0
  213. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/tutorials/img/office/insert-link-to-file.png +0 -0
  214. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/tutorials/img/office/needs-clone.png +0 -0
  215. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/tutorials/img/office/new-stage.png +0 -0
  216. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/tutorials/img/office/phd-comics-version-control.webp +0 -0
  217. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/tutorials/img/office/pipeline-out-of-date.png +0 -0
  218. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/tutorials/img/office/status-more-rows.png +0 -0
  219. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/tutorials/img/office/uncommitted-changes.png +0 -0
  220. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/tutorials/img/office/untracked-data.png +0 -0
  221. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/tutorials/img/office/updated-publication.png +0 -0
  222. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/tutorials/img/office/word-to-pdf-stage-2.png +0 -0
  223. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/tutorials/img/office/workflow-page.png +0 -0
  224. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/tutorials/img/openfoam/clone.png +0 -0
  225. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/tutorials/img/openfoam/create-project.png +0 -0
  226. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/tutorials/img/openfoam/datasets-page.png +0 -0
  227. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/tutorials/img/openfoam/figure-on-website-updated.png +0 -0
  228. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/tutorials/img/openfoam/figure-on-website.png +0 -0
  229. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/tutorials/img/openfoam/new-token.png +0 -0
  230. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/tutorials/img/openfoam/reclone.png +0 -0
  231. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/tutorials/img/openfoam/status-after-import-dataset.png +0 -0
  232. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/tutorials/img/quick-actions.png +0 -0
  233. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/tutorials/img/run-proc.png +0 -0
  234. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/tutorials/index.md +0 -0
  235. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/tutorials/jupyterlab.md +0 -0
  236. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/tutorials/latex-codespaces.md +0 -0
  237. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/tutorials/matlab.md +0 -0
  238. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/tutorials/notebook-pipeline.md +0 -0
  239. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/tutorials/office.md +0 -0
  240. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/tutorials/openfoam.md +0 -0
  241. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/tutorials/procedures.md +0 -0
  242. {calkit_python-0.35.7 → calkit_python-0.36.0}/docs/version-control.md +0 -0
  243. {calkit_python-0.35.7 → calkit_python-0.36.0}/install.json +0 -0
  244. {calkit_python-0.35.7 → calkit_python-0.36.0}/jest.config.js +0 -0
  245. {calkit_python-0.35.7 → calkit_python-0.36.0}/jupyter-config/server-config/calkit.json +0 -0
  246. {calkit_python-0.35.7 → calkit_python-0.36.0}/mkdocs.yml +0 -0
  247. {calkit_python-0.35.7 → calkit_python-0.36.0}/schema/plugin.json +0 -0
  248. {calkit_python-0.35.7 → calkit_python-0.36.0}/scripts/generate-cli-reference.py +0 -0
  249. {calkit_python-0.35.7 → calkit_python-0.36.0}/scripts/install.ps1 +0 -0
  250. {calkit_python-0.35.7 → calkit_python-0.36.0}/scripts/install.sh +0 -0
  251. {calkit_python-0.35.7 → calkit_python-0.36.0}/scripts/make-calk9.sh +0 -0
  252. {calkit_python-0.35.7 → calkit_python-0.36.0}/scripts/sync-docs.py +0 -0
  253. {calkit_python-0.35.7 → calkit_python-0.36.0}/src/__tests__/useQueries.spec.ts +0 -0
  254. {calkit_python-0.35.7 → calkit_python-0.36.0}/src/calkit-config.ts +0 -0
  255. {calkit_python-0.35.7 → calkit_python-0.36.0}/src/cell-output-marker.ts +0 -0
  256. {calkit_python-0.35.7 → calkit_python-0.36.0}/src/components/commit-dialog.tsx +0 -0
  257. {calkit_python-0.35.7 → calkit_python-0.36.0}/src/components/environment-editor.tsx +0 -0
  258. {calkit_python-0.35.7 → calkit_python-0.36.0}/src/components/notebook-registration.tsx +0 -0
  259. {calkit_python-0.35.7 → calkit_python-0.36.0}/src/components/notebook-toolbar.tsx +0 -0
  260. {calkit_python-0.35.7 → calkit_python-0.36.0}/src/components/pipeline-status-bar.tsx +0 -0
  261. {calkit_python-0.35.7 → calkit_python-0.36.0}/src/components/project-info-editor.tsx +0 -0
  262. {calkit_python-0.35.7 → calkit_python-0.36.0}/src/components/sidebar-settings.tsx +0 -0
  263. {calkit_python-0.35.7 → calkit_python-0.36.0}/src/components/sidebar.tsx +0 -0
  264. {calkit_python-0.35.7 → calkit_python-0.36.0}/src/components/stage-editor.tsx +0 -0
  265. {calkit_python-0.35.7 → calkit_python-0.36.0}/src/feature-flags.ts +0 -0
  266. {calkit_python-0.35.7 → calkit_python-0.36.0}/src/file-browser-menu.ts +0 -0
  267. {calkit_python-0.35.7 → calkit_python-0.36.0}/src/hooks/__tests__/useQueries.test.tsx +0 -0
  268. {calkit_python-0.35.7 → calkit_python-0.36.0}/src/hooks/useQueries.ts +0 -0
  269. {calkit_python-0.35.7 → calkit_python-0.36.0}/src/icons.ts +0 -0
  270. {calkit_python-0.35.7 → calkit_python-0.36.0}/src/index.ts +0 -0
  271. {calkit_python-0.35.7 → calkit_python-0.36.0}/src/io-tracker.ts +0 -0
  272. {calkit_python-0.35.7 → calkit_python-0.36.0}/src/pipeline-state.ts +0 -0
  273. {calkit_python-0.35.7 → calkit_python-0.36.0}/src/queryClient.ts +0 -0
  274. {calkit_python-0.35.7 → calkit_python-0.36.0}/src/request.ts +0 -0
  275. {calkit_python-0.35.7 → calkit_python-0.36.0}/src/shims-mainmenu.d.ts +0 -0
  276. {calkit_python-0.35.7 → calkit_python-0.36.0}/style/base.css +0 -0
  277. {calkit_python-0.35.7 → calkit_python-0.36.0}/style/cell-output-marker.css +0 -0
  278. {calkit_python-0.35.7 → calkit_python-0.36.0}/style/environment-editor.css +0 -0
  279. {calkit_python-0.35.7 → calkit_python-0.36.0}/style/environment-selector.css +0 -0
  280. {calkit_python-0.35.7 → calkit_python-0.36.0}/style/img/calkit-no-bg.png +0 -0
  281. {calkit_python-0.35.7 → calkit_python-0.36.0}/style/index.css +0 -0
  282. {calkit_python-0.35.7 → calkit_python-0.36.0}/style/index.js +0 -0
  283. {calkit_python-0.35.7 → calkit_python-0.36.0}/style/notebook-toolbar.css +0 -0
  284. {calkit_python-0.35.7 → calkit_python-0.36.0}/style/pipeline-status-bar.css +0 -0
  285. {calkit_python-0.35.7 → calkit_python-0.36.0}/style/sidebar.css +0 -0
  286. {calkit_python-0.35.7 → calkit_python-0.36.0}/test/dvc-md5-dir/osx-arm64.txt +0 -0
  287. {calkit_python-0.35.7 → calkit_python-0.36.0}/test/nb-julia.ipynb +0 -0
  288. {calkit_python-0.35.7 → calkit_python-0.36.0}/test/nb-params.ipynb +0 -0
  289. {calkit_python-0.35.7 → calkit_python-0.36.0}/test/nb-subdir.ipynb +0 -0
  290. {calkit_python-0.35.7 → calkit_python-0.36.0}/test/pipeline.ipynb +0 -0
  291. {calkit_python-0.35.7 → calkit_python-0.36.0}/test/script.py +0 -0
  292. {calkit_python-0.35.7 → calkit_python-0.36.0}/test/test-log.log +0 -0
  293. {calkit_python-0.35.7 → calkit_python-0.36.0}/tsconfig.json +0 -0
  294. {calkit_python-0.35.7 → calkit_python-0.36.0}/tsconfig.test.json +0 -0
  295. {calkit_python-0.35.7 → calkit_python-0.36.0}/ui-tests/.gitignore +0 -0
  296. {calkit_python-0.35.7 → calkit_python-0.36.0}/ui-tests/README.md +0 -0
  297. {calkit_python-0.35.7 → calkit_python-0.36.0}/ui-tests/jupyter_server_test_config.py +0 -0
  298. {calkit_python-0.35.7 → calkit_python-0.36.0}/ui-tests/package.json +0 -0
  299. {calkit_python-0.35.7 → calkit_python-0.36.0}/ui-tests/playwright.config.js +0 -0
  300. {calkit_python-0.35.7 → calkit_python-0.36.0}/ui-tests/tests/calkit.spec.ts +0 -0
  301. {calkit_python-0.35.7 → calkit_python-0.36.0}/ui-tests/yarn.lock +0 -0
  302. {calkit_python-0.35.7 → calkit_python-0.36.0}/uv.lock +0 -0
  303. {calkit_python-0.35.7 → calkit_python-0.36.0}/yarn.lock +0 -0
@@ -1,7 +1,7 @@
1
1
  dev.ipynb
2
2
  *.pyc
3
3
  .DS_Store
4
- .vscode
4
+ .vscode/settings.json
5
5
  site
6
6
  .env
7
7
  .venv
@@ -0,0 +1,17 @@
1
+ {
2
+ "version": "0.2.0",
3
+ "configurations": [
4
+ {
5
+ "name": "Run Calkit VS Code Extension",
6
+ "type": "extensionHost",
7
+ "request": "launch",
8
+ "runtimeExecutable": "${execPath}",
9
+ "args": [
10
+ "--extensionDevelopmentPath=${workspaceFolder}/vscode-ext",
11
+ "--enable-proposed-api=calkit.calkit-vscode"
12
+ ],
13
+ "outFiles": ["${workspaceFolder}/vscode-ext/out/**/*.js"],
14
+ "preLaunchTask": "npm: compile (vscode-ext)"
15
+ }
16
+ ]
17
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "version": "2.0.0",
3
+ "tasks": [
4
+ {
5
+ "type": "shell",
6
+ "command": "npm",
7
+ "args": ["run", "dev:compile"],
8
+ "options": {
9
+ "cwd": "${workspaceFolder}/vscode-ext"
10
+ },
11
+ "label": "npm: compile (vscode-ext)",
12
+ "problemMatcher": ["$tsc"]
13
+ }
14
+ ]
15
+ }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: calkit-python
3
- Version: 0.35.7
3
+ Version: 0.36.0
4
4
  Summary: Reproducibility simplified.
5
5
  Project-URL: Homepage, https://calkit.org
6
6
  Project-URL: Issues, https://github.com/calkit/calkit/issues
@@ -249,6 +249,9 @@ def get_status(
249
249
  ),
250
250
  ),
251
251
  ] = None,
252
+ as_json: Annotated[
253
+ bool, typer.Option("--json", help="Output status as JSON.")
254
+ ] = False,
252
255
  ):
253
256
  """View status (project, version control, and/or pipeline)."""
254
257
  ck_info = calkit.load_calkit_info()
@@ -284,6 +287,78 @@ def get_status(
284
287
  "Failed pipeline environment checks for: "
285
288
  + ", ".join(pipeline_status.failed_environment_checks)
286
289
  )
290
+ if as_json:
291
+ status_dict = {}
292
+ if "project" in categories:
293
+ status = calkit.get_latest_project_status()
294
+ status_dict["project"] = (
295
+ None
296
+ if status is None
297
+ else {
298
+ "status": status.status,
299
+ "message": status.message,
300
+ "timestamp": status.timestamp.isoformat(),
301
+ }
302
+ )
303
+ if "git" in categories:
304
+ try:
305
+ repo = git.Repo()
306
+ changed_files = calkit.git.get_changed_files(repo=repo)
307
+ staged_files = calkit.git.get_staged_files(repo=repo)
308
+ untracked_files = calkit.git.get_untracked_files(repo=repo)
309
+ if targets:
310
+ target_prefixes = [
311
+ Path(target).as_posix().rstrip("/")
312
+ for target in targets
313
+ ]
314
+
315
+ def _matches_target(path: str) -> bool:
316
+ path = Path(path).as_posix()
317
+ return any(
318
+ path == prefix or path.startswith(prefix + "/")
319
+ for prefix in target_prefixes
320
+ )
321
+
322
+ changed_files = [
323
+ path for path in changed_files if _matches_target(path)
324
+ ]
325
+ staged_files = [
326
+ path for path in staged_files if _matches_target(path)
327
+ ]
328
+ untracked_files = [
329
+ path
330
+ for path in untracked_files
331
+ if _matches_target(path)
332
+ ]
333
+ status_dict["git"] = {
334
+ "branch": None
335
+ if repo.head.is_detached
336
+ else repo.active_branch.name,
337
+ "is_dirty": repo.is_dirty(untracked_files=True),
338
+ "changed_files": changed_files,
339
+ "staged_files": staged_files,
340
+ "untracked_files": untracked_files,
341
+ }
342
+ except InvalidGitRepositoryError:
343
+ status_dict["git"] = {"error": "Not a Git repository"}
344
+ if "dvc" in categories:
345
+ try:
346
+ dvc_repo = calkit.dvc.get_dvc_repo()
347
+ data_status = dvc_repo.data_status()
348
+ if isinstance(data_status, dict):
349
+ data_status.pop("git", None)
350
+ status_dict["dvc"] = data_status
351
+ except Exception as e:
352
+ status_dict["dvc"] = {"error": f"{e.__class__.__name__}: {e}"}
353
+ if "pipeline" in categories or "dvc" in categories:
354
+ if pipeline_status is None:
355
+ status_dict["pipeline"] = None
356
+ else:
357
+ status_dict["pipeline"] = pipeline_status.model_dump(
358
+ mode="json"
359
+ )
360
+ print(json.dumps(status_dict, indent=2, default=str))
361
+ return
287
362
  if "project" in categories:
288
363
  print_sep("Project")
289
364
  # Print latest status
@@ -322,7 +397,11 @@ def get_status(
322
397
  print_sep("Pipeline")
323
398
  # Nicely format the results from pipeline status
324
399
  if pipeline_status and pipeline_status.errors:
325
- typer.echo("Pipeline status unavailable due to errors.")
400
+ warn("Pipeline status unavailable due to errors.")
401
+ return
402
+ if pipeline_status and not pipeline_status.has_pipeline:
403
+ typer.echo("This project has no pipeline.")
404
+ return
326
405
  elif pipeline_status and pipeline_status.is_stale:
327
406
  for stage_name in pipeline_status.stale_stage_names:
328
407
  stale_stage = pipeline_status.stale_stages.get(stage_name)
@@ -333,17 +412,17 @@ def get_status(
333
412
  if stale_stage.stale_outputs:
334
413
  typer.echo(" stale outputs:")
335
414
  for output_path in stale_stage.stale_outputs:
336
- typer.echo(f" - {output_path}")
415
+ typer.echo(f" {output_path}")
337
416
  # Show modified outputs from this stage
338
417
  if stale_stage.modified_outputs:
339
418
  typer.echo(" modified outputs:")
340
419
  for output_path in stale_stage.modified_outputs:
341
- typer.echo(f" - {output_path}")
420
+ typer.echo(f" {output_path}")
342
421
  # Show modified inputs making the stage stale
343
422
  if stale_stage.modified_inputs:
344
423
  typer.echo(" modified inputs:")
345
424
  for input_path in stale_stage.modified_inputs:
346
- typer.echo(f" - {input_path}")
425
+ typer.echo(f" {input_path}")
347
426
  elif pipeline_status:
348
427
  typer.echo("Pipeline is up to date.")
349
428
 
@@ -1333,6 +1333,75 @@ def new_uv_env(
1333
1333
  repo.git.commit(["-m", f"Add uv environment {name}"])
1334
1334
 
1335
1335
 
1336
+ @new_app.command("slurm-env")
1337
+ def new_slurm_env(
1338
+ name: Annotated[
1339
+ str, typer.Option("--name", "-n", help="Environment name.")
1340
+ ],
1341
+ host: Annotated[
1342
+ str,
1343
+ typer.Option("--host", help="Host where SLURM commands should run."),
1344
+ ] = "localhost",
1345
+ default_options: Annotated[
1346
+ list[str],
1347
+ typer.Option(
1348
+ "--default-option",
1349
+ help=(
1350
+ "Default sbatch/srun option string (for example --gpus=1). "
1351
+ "Repeat for multiple options."
1352
+ ),
1353
+ ),
1354
+ ] = [],
1355
+ description: Annotated[
1356
+ str | None, typer.Option("--description", help="Description.")
1357
+ ] = None,
1358
+ overwrite: Annotated[
1359
+ bool,
1360
+ typer.Option(
1361
+ "--overwrite",
1362
+ "-f",
1363
+ help="Overwrite any existing environment with this name.",
1364
+ ),
1365
+ ] = False,
1366
+ no_commit: Annotated[
1367
+ bool, typer.Option("--no-commit", help="Do not commit changes.")
1368
+ ] = False,
1369
+ ):
1370
+ """Create a new SLURM environment."""
1371
+ host = host.strip()
1372
+ if not host:
1373
+ raise_error("Host is required")
1374
+ ck_info = calkit.load_calkit_info()
1375
+ envs = ck_info.get("environments", {})
1376
+ if isinstance(envs, list):
1377
+ typer.echo("Converting environments from list to dict")
1378
+ envs = {env.pop("name"): env for env in envs}
1379
+ if name in envs and not overwrite:
1380
+ raise_error(
1381
+ f"Environment with name {name} already exists "
1382
+ "(use -f to overwrite)"
1383
+ )
1384
+ normalized_default_options = [
1385
+ opt.strip() for opt in default_options if opt.strip()
1386
+ ]
1387
+ env = {"kind": "slurm", "host": host}
1388
+ if normalized_default_options:
1389
+ env["default_options"] = normalized_default_options # type: ignore
1390
+ if description is not None:
1391
+ env["description"] = description
1392
+ envs[name] = env
1393
+ ck_info["environments"] = envs
1394
+ with open("calkit.yaml", "w") as f:
1395
+ ryaml.dump(ck_info, f)
1396
+ if not no_commit:
1397
+ repo = git.Repo()
1398
+ repo.git.add("calkit.yaml")
1399
+ if repo.git.diff(["--staged", "calkit.yaml"]):
1400
+ repo.git.commit(
1401
+ ["calkit.yaml", "-m", f"Add SLURM environment {name}"]
1402
+ )
1403
+
1404
+
1336
1405
  @new_app.command("uv-venv")
1337
1406
  def new_uv_venv(
1338
1407
  name: Annotated[
@@ -1615,21 +1684,29 @@ def new_pixi_env(
1615
1684
  @new_app.command("julia-env")
1616
1685
  def new_julia_env(
1617
1686
  packages: Annotated[
1618
- list[str],
1619
- typer.Argument(help="Packages to include in the environment."),
1620
- ],
1687
+ list[str] | None,
1688
+ typer.Argument(
1689
+ help="Optional packages to include in the environment."
1690
+ ),
1691
+ ] = None,
1621
1692
  name: Annotated[
1622
1693
  str, typer.Option("--name", "-n", help="Environment name.")
1623
- ],
1694
+ ] = "main",
1624
1695
  path: Annotated[
1625
- str, typer.Option("--path", help="Path for Project.toml file.")
1626
- ] = "Project.toml",
1696
+ str | None,
1697
+ typer.Option("--path", help="Path for Project.toml file."),
1698
+ ] = None,
1627
1699
  description: Annotated[
1628
1700
  str | None, typer.Option("--description", help="Description.")
1629
1701
  ] = None,
1630
1702
  julia_version: Annotated[
1631
- str, typer.Option("--julia", "-j", help="Julia version.")
1632
- ] = "1.11",
1703
+ str | None,
1704
+ typer.Option(
1705
+ "--julia",
1706
+ "-j",
1707
+ help="Julia version. Auto-detected if not supplied.",
1708
+ ),
1709
+ ] = None,
1633
1710
  overwrite: Annotated[
1634
1711
  bool,
1635
1712
  typer.Option(
@@ -1641,8 +1718,17 @@ def new_julia_env(
1641
1718
  no_commit: Annotated[
1642
1719
  bool, typer.Option("--no-commit", help="Do not commit changes.")
1643
1720
  ] = False,
1721
+ no_check: Annotated[
1722
+ bool,
1723
+ typer.Option(
1724
+ "--no-check",
1725
+ help="Do not check environment is up-to-date after creation.",
1726
+ ),
1727
+ ] = False,
1644
1728
  ):
1645
- """Create a new Julia environment."""
1729
+ """Create a new Julia environment or add an existing one to calkit.yaml."""
1730
+ if path is None:
1731
+ path = "Project.toml"
1646
1732
  if not os.path.basename(path) == "Project.toml":
1647
1733
  raise_error(
1648
1734
  "Julia environment paths must point to a Project.toml file"
@@ -1665,27 +1751,57 @@ def new_julia_env(
1665
1751
  f"Environment with name {name} already exists "
1666
1752
  "(use -f to overwrite)"
1667
1753
  )
1668
- # Create the environment now
1754
+ # Detect Julia version if not supplied
1755
+ if julia_version is None:
1756
+ try:
1757
+ julia_version = calkit.julia.get_version()
1758
+ except ValueError as e:
1759
+ raise_error(
1760
+ f"Failed to detect Julia version: {e}. "
1761
+ "Use --julia to specify a version."
1762
+ )
1763
+ # Check for duplicate Julia environments with same path and version
1764
+ for env_name, env_config in envs.items():
1765
+ if (
1766
+ env_config.get("kind") == "julia"
1767
+ and env_config.get("path") == path
1768
+ and env_config.get("julia") == julia_version
1769
+ ):
1770
+ raise_error(
1771
+ f"Julia environment '{env_name}' already exists with path "
1772
+ f"'{path}' and version '{julia_version}'; "
1773
+ f"Use a different path, version, or --overwrite to replace it"
1774
+ )
1669
1775
  env_dir = os.path.dirname(path)
1670
1776
  if env_dir:
1671
1777
  os.makedirs(env_dir, exist_ok=True)
1672
1778
  else:
1673
1779
  env_dir = "."
1674
- # First make sure the Julia version is installed
1675
- cmd = ["juliaup", "add", julia_version]
1676
- try:
1677
- subprocess.run(cmd, check=True)
1678
- except subprocess.CalledProcessError:
1679
- raise_error(f"Failed to install Julia version {julia_version}")
1680
- cmd = ["julia", f"+{julia_version}", f"--project={env_dir}", "-e"]
1681
- install_cmd = "using Pkg;"
1682
- for package in packages:
1683
- install_cmd += f' Pkg.add("{package}");'
1684
- cmd.append(install_cmd)
1685
- try:
1686
- subprocess.run(cmd, check=True)
1687
- except subprocess.CalledProcessError:
1688
- raise_error("Failed to create new Julia environment")
1780
+ project_exists = os.path.isfile(path)
1781
+ created_project_file = False
1782
+ # If packages are provided, initialize via Julia/Pkg.
1783
+ if packages:
1784
+ # First make sure the Julia version is installed
1785
+ cmd = ["juliaup", "add", julia_version]
1786
+ try:
1787
+ subprocess.run(cmd, check=True)
1788
+ except subprocess.CalledProcessError:
1789
+ raise_error(f"Failed to install Julia version {julia_version}")
1790
+ cmd = ["julia", f"+{julia_version}", f"--project={env_dir}", "-e"]
1791
+ install_cmd = f'using Pkg; Pkg.activate("{env_dir}");'
1792
+ for package in packages or []:
1793
+ install_cmd += f' Pkg.add("{package}");'
1794
+ cmd.append(install_cmd)
1795
+ try:
1796
+ subprocess.run(cmd, check=True)
1797
+ except subprocess.CalledProcessError:
1798
+ raise_error("Failed to create new Julia environment")
1799
+ elif not project_exists:
1800
+ # Allow creating a Julia environment scaffold without requiring Julia
1801
+ # tooling at creation time. IJulia or other packages can be added later.
1802
+ with open(path, "w") as f:
1803
+ f.write("[deps]\n")
1804
+ created_project_file = True
1689
1805
  typer.echo("Adding environment to calkit.yaml")
1690
1806
  env = dict(kind="julia", path=path, julia=julia_version)
1691
1807
  if description is not None:
@@ -1694,11 +1810,18 @@ def new_julia_env(
1694
1810
  ck_info["environments"] = envs
1695
1811
  with open("calkit.yaml", "w") as f:
1696
1812
  ryaml.dump(ck_info, f)
1697
- repo.git.add(path)
1698
- repo.git.add(os.path.join(env_dir, "Manifest.toml"))
1699
- repo.git.add("calkit.yaml")
1700
- if not no_commit and repo.git.diff("--staged"):
1701
- repo.git.commit(["-m", f"Add Julia env {name}"])
1813
+ if not no_commit:
1814
+ repo.git.add("calkit.yaml")
1815
+ if packages or created_project_file:
1816
+ repo.git.add(path)
1817
+ if packages:
1818
+ repo.git.add(os.path.join(env_dir, "Manifest.toml"))
1819
+ if not no_check and packages:
1820
+ env_lock_fpath = check_environment(env_name=name)
1821
+ if env_lock_fpath is not None:
1822
+ repo.git.add(env_lock_fpath)
1823
+ if repo.git.diff("--staged"):
1824
+ repo.git.commit(["-m", f"Add Julia env {name}"])
1702
1825
 
1703
1826
 
1704
1827
  @new_app.command("renv")
@@ -84,6 +84,39 @@ def _parse_params(params: list[str]) -> dict[str, Any]:
84
84
  return parameters
85
85
 
86
86
 
87
+ def _check_ijulia_available(
88
+ julia_version: str,
89
+ env_dir: str,
90
+ ) -> bool:
91
+ ijulia_check_cmd = [
92
+ "julia",
93
+ f"+{julia_version}",
94
+ "--project=" + env_dir,
95
+ "-e",
96
+ (
97
+ "import Pkg; "
98
+ "deps = Pkg.project().dependencies; "
99
+ 'if !haskey(deps, "IJulia"); '
100
+ 'println("IJulia is not in this Julia project environment."); '
101
+ "exit(3); "
102
+ "end"
103
+ ),
104
+ ]
105
+ try:
106
+ ijulia_check_cmd_checked = calkit.julia.check_version_in_command(
107
+ ijulia_check_cmd
108
+ )
109
+ except Exception as e:
110
+ raise_error(f"Failed to check Julia version: {e}")
111
+ return False
112
+ res = subprocess.run(
113
+ ijulia_check_cmd_checked,
114
+ capture_output=True,
115
+ text=True,
116
+ )
117
+ return res.returncode == 0
118
+
119
+
87
120
  @notebooks_app.command("check-kernel")
88
121
  def check_env_kernel(
89
122
  env_name: Annotated[
@@ -115,10 +148,25 @@ def check_env_kernel(
115
148
  verbose: Annotated[
116
149
  bool, typer.Option("--verbose", "-v", help="Print verbose output.")
117
150
  ] = False,
151
+ json_output: Annotated[
152
+ bool,
153
+ typer.Option("--json", help="Output result as JSON."),
154
+ ] = False,
155
+ auto_add_deps: Annotated[
156
+ bool,
157
+ typer.Option(
158
+ "--auto-add-deps",
159
+ help=(
160
+ "Automatically install missing kernel dependencies "
161
+ "(e.g., IJulia for Julia environments)."
162
+ ),
163
+ ),
164
+ ] = False,
118
165
  ) -> tuple[str, str]:
119
166
  """Check that an environment has a registered Jupyter kernel."""
120
167
  from calkit.cli.check import check_environment
121
168
  from calkit.cli.main import run_in_env
169
+ from calkit.cli.update import update_environment
122
170
  from calkit.environments import language_from_env
123
171
 
124
172
  def get_env():
@@ -152,14 +200,24 @@ def check_env_kernel(
152
200
  "--display-name",
153
201
  display_name,
154
202
  ]
155
- res = run_in_env(
156
- cmd=cmd,
157
- env_name=env_name,
158
- no_check=no_check,
159
- verbose=verbose,
160
- relaxed_check=True,
161
- )
162
- return kernel_name, display_name
203
+ if json_output:
204
+ # For JSON output, run silently and don't show intermediate
205
+ # messages
206
+ res = run_in_env(
207
+ cmd=cmd,
208
+ env_name=env_name,
209
+ no_check=no_check,
210
+ verbose=False,
211
+ relaxed_check=True,
212
+ )
213
+ else:
214
+ res = run_in_env(
215
+ cmd=cmd,
216
+ env_name=env_name,
217
+ no_check=no_check,
218
+ verbose=verbose,
219
+ relaxed_check=True,
220
+ )
163
221
  elif language == "r":
164
222
  cmd = [
165
223
  "Rscript",
@@ -176,7 +234,6 @@ def check_env_kernel(
176
234
  verbose=verbose,
177
235
  relaxed_check=True,
178
236
  )
179
- return kernel_name, display_name
180
237
  elif language == "julia":
181
238
  if not no_check:
182
239
  check_environment(env_name=env_name, verbose=verbose)
@@ -193,6 +250,43 @@ def check_env_kernel(
193
250
  if not env_dir:
194
251
  env_dir = "."
195
252
  env_dir_abs = os.path.abspath(env_dir)
253
+ # In reproducible Julia environments we disable global package loading,
254
+ # so IJulia must exist in the project environment itself.
255
+ ijulia_ok = _check_ijulia_available(
256
+ julia_version=julia_version,
257
+ env_dir=env_dir,
258
+ )
259
+ if not ijulia_ok:
260
+ should_install = auto_add_deps
261
+ if not should_install and sys.stdin.isatty() and not json_output:
262
+ should_install = typer.confirm(
263
+ (
264
+ "IJulia is not installed in this Julia environment. "
265
+ "Install now with "
266
+ f"'calkit update env --name {env_name} --add IJulia'?"
267
+ ),
268
+ default=True,
269
+ )
270
+ if not should_install:
271
+ raise_error(
272
+ "IJulia is not installed in this Julia environment. "
273
+ "Install it and retry, or pass --auto-add-deps to "
274
+ "install automatically."
275
+ )
276
+ try:
277
+ update_environment(env_name=env_name, add_packages=["IJulia"])
278
+ except Exception as e:
279
+ raise_error(f"Failed to install IJulia: {e}")
280
+ ijulia_ok = _check_ijulia_available(
281
+ julia_version=julia_version,
282
+ env_dir=env_dir,
283
+ )
284
+ if not ijulia_ok:
285
+ raise_error(
286
+ "IJulia installation completed but the dependency check "
287
+ "still failed."
288
+ )
289
+ # Don't include version in display_name; IJulia appends it automatically
196
290
  julia_cmd = (
197
291
  "import IJulia;"
198
292
  "kp=IJulia.installkernel("
@@ -218,13 +312,25 @@ def check_env_kernel(
218
312
  raise_error(f"Failed to create kernel:\n{res.stdout}")
219
313
  kernel_path = res.stdout.strip()
220
314
  kernel_name = os.path.basename(kernel_path)
221
- typer.echo(
222
- f"Registered IJulia kernel '{kernel_name}' at: {kernel_path}"
223
- )
224
- return kernel_name, display_name
315
+ # Update display_name to include version for matching in VS Code
316
+ # The kernel name format is like: project_-env-X.Y or project_-env-X.Y.Z
317
+ # Extract version from kernel_name or use julia_version
318
+ display_name = f"{display_name} {julia_version}"
319
+ if not json_output:
320
+ typer.echo(
321
+ f"Registered IJulia kernel '{kernel_name}' at: {kernel_path}"
322
+ )
225
323
  else:
226
324
  raise_error(f"{language} not supported")
227
325
  return "", "" # For typing analysis since raise_error exits
326
+ # Output result
327
+ if json_output:
328
+ result = {
329
+ "kernel_name": kernel_name,
330
+ "display_name": display_name,
331
+ }
332
+ typer.echo(json.dumps(result))
333
+ return kernel_name, display_name
228
334
 
229
335
 
230
336
  @notebooks_app.command("exec", help="Alias for 'execute'.")