calkit-python 0.30.4__tar.gz → 0.30.6__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 (182) hide show
  1. {calkit_python-0.30.4 → calkit_python-0.30.6}/PKG-INFO +1 -1
  2. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/__init__.py +1 -1
  3. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/cli/main.py +29 -7
  4. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/cli/notebooks.py +108 -20
  5. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/config.py +4 -0
  6. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/tests/cli/test_notebooks.py +35 -0
  7. calkit_python-0.30.6/test/nb-julia.ipynb +25 -0
  8. {calkit_python-0.30.4 → calkit_python-0.30.6}/.github/FUNDING.yml +0 -0
  9. {calkit_python-0.30.4 → calkit_python-0.30.6}/.github/workflows/docs.yml +0 -0
  10. {calkit_python-0.30.4 → calkit_python-0.30.6}/.github/workflows/format.yml +0 -0
  11. {calkit_python-0.30.4 → calkit_python-0.30.6}/.github/workflows/publish-test.yml +0 -0
  12. {calkit_python-0.30.4 → calkit_python-0.30.6}/.github/workflows/publish.yml +0 -0
  13. {calkit_python-0.30.4 → calkit_python-0.30.6}/.github/workflows/test.yml +0 -0
  14. {calkit_python-0.30.4 → calkit_python-0.30.6}/.gitignore +0 -0
  15. {calkit_python-0.30.4 → calkit_python-0.30.6}/.pre-commit-config.yaml +0 -0
  16. {calkit_python-0.30.4 → calkit_python-0.30.6}/.python-version +0 -0
  17. {calkit_python-0.30.4 → calkit_python-0.30.6}/CITATION.cff +0 -0
  18. {calkit_python-0.30.4 → calkit_python-0.30.6}/CONTRIBUTING.md +0 -0
  19. {calkit_python-0.30.4 → calkit_python-0.30.6}/LICENSE +0 -0
  20. {calkit_python-0.30.4 → calkit_python-0.30.6}/Makefile +0 -0
  21. {calkit_python-0.30.4 → calkit_python-0.30.6}/README.md +0 -0
  22. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/__main__.py +0 -0
  23. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/calc.py +0 -0
  24. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/check.py +0 -0
  25. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/cli/__init__.py +0 -0
  26. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/cli/check.py +0 -0
  27. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/cli/cloud.py +0 -0
  28. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/cli/config.py +0 -0
  29. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/cli/core.py +0 -0
  30. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/cli/describe.py +0 -0
  31. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/cli/import_.py +0 -0
  32. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/cli/list.py +0 -0
  33. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/cli/new.py +0 -0
  34. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/cli/office.py +0 -0
  35. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/cli/overleaf.py +0 -0
  36. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/cli/slurm.py +0 -0
  37. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/cli/update.py +0 -0
  38. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/cloud.py +0 -0
  39. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/conda.py +0 -0
  40. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/core.py +0 -0
  41. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/datasets.py +0 -0
  42. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/docker.py +0 -0
  43. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/dvc.py +0 -0
  44. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/environments.py +0 -0
  45. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/git.py +0 -0
  46. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/github.py +0 -0
  47. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/gui.py +0 -0
  48. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/jupyter.py +0 -0
  49. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/magics.py +0 -0
  50. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/matlab.py +0 -0
  51. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/models/__init__.py +0 -0
  52. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/models/core.py +0 -0
  53. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/models/io.py +0 -0
  54. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/models/iteration.py +0 -0
  55. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/models/pipeline.py +0 -0
  56. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/notebooks.py +0 -0
  57. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/office.py +0 -0
  58. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/ops.py +0 -0
  59. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/pipeline.py +0 -0
  60. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/releases.py +0 -0
  61. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/server.py +0 -0
  62. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/templates/__init__.py +0 -0
  63. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/templates/core.py +0 -0
  64. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/templates/latex/__init__.py +0 -0
  65. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/templates/latex/article/paper.tex +0 -0
  66. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/templates/latex/core.py +0 -0
  67. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/templates/latex/jfm/jfm.bst +0 -0
  68. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/templates/latex/jfm/jfm.cls +0 -0
  69. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/templates/latex/jfm/lineno-FLM.sty +0 -0
  70. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/templates/latex/jfm/paper.tex +0 -0
  71. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/templates/latex/jfm/upmath.sty +0 -0
  72. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/tests/__init__.py +0 -0
  73. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/tests/cli/__init__.py +0 -0
  74. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/tests/cli/test_check.py +0 -0
  75. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/tests/cli/test_config.py +0 -0
  76. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/tests/cli/test_list.py +0 -0
  77. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/tests/cli/test_main.py +0 -0
  78. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/tests/cli/test_new.py +0 -0
  79. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/tests/models/__init__.py +0 -0
  80. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/tests/models/test_iteration.py +0 -0
  81. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/tests/models/test_pipeline.py +0 -0
  82. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/tests/test_calc.py +0 -0
  83. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/tests/test_check.py +0 -0
  84. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/tests/test_conda.py +0 -0
  85. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/tests/test_core.py +0 -0
  86. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/tests/test_dvc.py +0 -0
  87. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/tests/test_jupyter.py +0 -0
  88. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/tests/test_magics.py +0 -0
  89. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/tests/test_notebooks.py +0 -0
  90. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/tests/test_pipeline.py +0 -0
  91. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/tests/test_templates.py +0 -0
  92. {calkit_python-0.30.4 → calkit_python-0.30.6}/calkit/zenodo.py +0 -0
  93. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/CNAME +0 -0
  94. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/apps.md +0 -0
  95. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/calculations.md +0 -0
  96. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/calkit-yaml.md +0 -0
  97. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/cli-reference.md +0 -0
  98. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/cloud-integration.md +0 -0
  99. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/datasets.md +0 -0
  100. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/dependencies.md +0 -0
  101. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/environments.md +0 -0
  102. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/examples.md +0 -0
  103. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/help.md +0 -0
  104. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/img/c-to-the-k-white.svg +0 -0
  105. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/img/calkit-no-bg.png +0 -0
  106. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/img/connect-zenodo.png +0 -0
  107. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/img/jupyterlab-params.png +0 -0
  108. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/img/vscode-nb-params.png +0 -0
  109. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/index.md +0 -0
  110. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/installation.md +0 -0
  111. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/local-server.md +0 -0
  112. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/notebooks.md +0 -0
  113. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/overleaf.md +0 -0
  114. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/pipeline/index.md +0 -0
  115. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/pipeline/manual-steps.md +0 -0
  116. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/pipeline/running-and-logging.md +0 -0
  117. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/pipeline/slurm.md +0 -0
  118. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/quickstart.md +0 -0
  119. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/references.md +0 -0
  120. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/releases.md +0 -0
  121. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/tutorials/adding-latex-pub-docker.md +0 -0
  122. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/tutorials/conda-envs.md +0 -0
  123. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/tutorials/existing-project.md +0 -0
  124. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/tutorials/first-project.md +0 -0
  125. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/tutorials/github-actions.md +0 -0
  126. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/tutorials/img/actions-repo-secrets.png +0 -0
  127. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/tutorials/img/latex-codespaces/building-codespace.png +0 -0
  128. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/tutorials/img/latex-codespaces/codespaces-secrets-2.png +0 -0
  129. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/tutorials/img/latex-codespaces/editor-split.png +0 -0
  130. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/tutorials/img/latex-codespaces/go-to-linked-code.png +0 -0
  131. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/tutorials/img/latex-codespaces/issue-from-selection.png +0 -0
  132. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/tutorials/img/latex-codespaces/new-project.png +0 -0
  133. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/tutorials/img/latex-codespaces/new-pub-2.png +0 -0
  134. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/tutorials/img/latex-codespaces/new-token.png +0 -0
  135. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/tutorials/img/latex-codespaces/paper.tex.png +0 -0
  136. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/tutorials/img/latex-codespaces/project-home-3.png +0 -0
  137. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/tutorials/img/latex-codespaces/push.png +0 -0
  138. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/tutorials/img/latex-codespaces/stage.png +0 -0
  139. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/tutorials/img/office/anakin-excel.jpg +0 -0
  140. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/tutorials/img/office/chart-more-rows.png +0 -0
  141. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/tutorials/img/office/create-project.png +0 -0
  142. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/tutorials/img/office/elsevier-research-data-guidelines.png +0 -0
  143. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/tutorials/img/office/excel-chart.png +0 -0
  144. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/tutorials/img/office/excel-data.png +0 -0
  145. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/tutorials/img/office/insert-link-to-file.png +0 -0
  146. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/tutorials/img/office/needs-clone.png +0 -0
  147. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/tutorials/img/office/new-stage.png +0 -0
  148. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/tutorials/img/office/phd-comics-version-control.webp +0 -0
  149. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/tutorials/img/office/pipeline-out-of-date.png +0 -0
  150. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/tutorials/img/office/status-more-rows.png +0 -0
  151. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/tutorials/img/office/uncommitted-changes.png +0 -0
  152. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/tutorials/img/office/untracked-data.png +0 -0
  153. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/tutorials/img/office/updated-publication.png +0 -0
  154. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/tutorials/img/office/word-to-pdf-stage-2.png +0 -0
  155. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/tutorials/img/office/workflow-page.png +0 -0
  156. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/tutorials/img/openfoam/clone.png +0 -0
  157. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/tutorials/img/openfoam/create-project.png +0 -0
  158. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/tutorials/img/openfoam/datasets-page.png +0 -0
  159. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/tutorials/img/openfoam/figure-on-website-updated.png +0 -0
  160. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/tutorials/img/openfoam/figure-on-website.png +0 -0
  161. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/tutorials/img/openfoam/new-token.png +0 -0
  162. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/tutorials/img/openfoam/reclone.png +0 -0
  163. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/tutorials/img/openfoam/status-after-import-dataset.png +0 -0
  164. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/tutorials/img/quick-actions.png +0 -0
  165. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/tutorials/img/run-proc.png +0 -0
  166. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/tutorials/index.md +0 -0
  167. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/tutorials/latex-codespaces.md +0 -0
  168. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/tutorials/matlab.md +0 -0
  169. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/tutorials/notebook-pipeline.md +0 -0
  170. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/tutorials/office.md +0 -0
  171. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/tutorials/openfoam.md +0 -0
  172. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/tutorials/procedures.md +0 -0
  173. {calkit_python-0.30.4 → calkit_python-0.30.6}/docs/version-control.md +0 -0
  174. {calkit_python-0.30.4 → calkit_python-0.30.6}/mkdocs.yml +0 -0
  175. {calkit_python-0.30.4 → calkit_python-0.30.6}/pyproject.toml +0 -0
  176. {calkit_python-0.30.4 → calkit_python-0.30.6}/scripts/install.ps1 +0 -0
  177. {calkit_python-0.30.4 → calkit_python-0.30.6}/scripts/install.sh +0 -0
  178. {calkit_python-0.30.4 → calkit_python-0.30.6}/test/nb-params.ipynb +0 -0
  179. {calkit_python-0.30.4 → calkit_python-0.30.6}/test/nb-subdir.ipynb +0 -0
  180. {calkit_python-0.30.4 → calkit_python-0.30.6}/test/pipeline.ipynb +0 -0
  181. {calkit_python-0.30.4 → calkit_python-0.30.6}/test/test-log.log +0 -0
  182. {calkit_python-0.30.4 → calkit_python-0.30.6}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: calkit-python
3
- Version: 0.30.4
3
+ Version: 0.30.6
4
4
  Summary: Reproducibility simplified.
5
5
  Project-URL: Homepage, https://calkit.org
6
6
  Project-URL: Issues, https://github.com/calkit/calkit/issues
@@ -1,4 +1,4 @@
1
- __version__ = "0.30.4"
1
+ __version__ = "0.30.6"
2
2
 
3
3
  from .core import * # noqa: F403, I001
4
4
  from . import git # noqa: F401
@@ -9,6 +9,7 @@ import logging
9
9
  import os
10
10
  import platform as _platform
11
11
  import posixpath
12
+ import shutil
12
13
  import subprocess
13
14
  import sys
14
15
  import time
@@ -1828,20 +1829,41 @@ def set_env_var(
1828
1829
  @app.command(name="upgrade")
1829
1830
  def upgrade():
1830
1831
  """Upgrade Calkit."""
1831
- if calkit.check_dep_exists("pipx"):
1832
- cmd = ["pipx", "upgrade", "calkit-python"]
1833
- elif calkit.check_dep_exists("uv"):
1832
+ # First detect how Calkit is installed
1833
+ # If installed with uv tool, calkit will be located at something like
1834
+ # ~/.local/bin/calkit
1835
+ which_calkit = shutil.which("calkit")
1836
+ if which_calkit is None:
1837
+ raise_error("Calkit is not installed")
1838
+ split_path = os.path.normpath(str(which_calkit)).split(os.sep)
1839
+ if (
1840
+ ".local" in split_path
1841
+ and "bin" in split_path
1842
+ and calkit.check_dep_exists("uv")
1843
+ ):
1844
+ # This is a uv tool install
1834
1845
  cmd = [
1835
1846
  "uv",
1836
- "pip",
1847
+ "tool",
1837
1848
  "install",
1838
- "--system",
1839
1849
  "--upgrade",
1840
1850
  "calkit-python",
1841
1851
  ]
1852
+ elif "pipx" in split_path and calkit.check_dep_exists("pipx"):
1853
+ cmd = ["pipx", "upgrade", "calkit-python"]
1842
1854
  else:
1843
- cmd = ["pip", "install", "--upgrade", "calkit-python"]
1844
- subprocess.run(cmd)
1855
+ cmd = [
1856
+ sys.executable,
1857
+ "-m",
1858
+ "pip",
1859
+ "install",
1860
+ "--upgrade",
1861
+ "calkit-python",
1862
+ ]
1863
+ res = subprocess.run(cmd)
1864
+ if res.returncode != 0:
1865
+ raise_error("Upgrade failed")
1866
+ typer.echo("Success!")
1845
1867
 
1846
1868
 
1847
1869
  @app.command(name="switch-branch")
@@ -89,28 +89,104 @@ def check_env_kernel(
89
89
  "--no-check", help="Do not check environment before executing."
90
90
  ),
91
91
  ] = False,
92
+ language: Annotated[
93
+ str | None,
94
+ typer.Option(
95
+ "--language",
96
+ "-l",
97
+ help=(
98
+ "Notebook language; if 'matlab', MATLAB kernel must be "
99
+ "available in environment."
100
+ ),
101
+ ),
102
+ ] = None,
92
103
  verbose: Annotated[
93
104
  bool, typer.Option("--verbose", "-v", help="Print verbose output.")
94
105
  ] = False,
95
106
  ):
96
107
  """Check that an environment has a registered kernel."""
108
+ from calkit.cli.check import check_environment
97
109
  from calkit.cli.main import run_in_env
98
110
 
111
+ def get_env():
112
+ ck_info = calkit.load_calkit_info()
113
+ envs = ck_info.get("environments", {})
114
+ if env_name not in envs:
115
+ raise_error(
116
+ f"No environment '{env_name}' defined for this project"
117
+ )
118
+ return envs[env_name]
119
+
120
+ env = None
121
+ # Detect language from environment
122
+ if language is None:
123
+ env = get_env()
124
+ if env.get("kind") == "julia":
125
+ language = "julia"
126
+ else:
127
+ language = "python"
99
128
  project_name = calkit.detect_project_name(prepend_owner=False)
100
129
  kernel_name = calkit.to_kebab_case(f"{project_name}-{env_name}")
101
- cmd = [
102
- "python",
103
- "-m",
104
- "ipykernel",
105
- "install",
106
- "--user",
107
- "--name",
108
- kernel_name,
109
- "--display-name",
110
- f"{project_name}: {env_name}",
111
- ]
112
- run_in_env(cmd=cmd, env_name=env_name, no_check=no_check, verbose=verbose)
113
- return kernel_name
130
+ display_name = f"{project_name}: {env_name}"
131
+ if language == "python":
132
+ cmd = [
133
+ "python",
134
+ "-m",
135
+ "ipykernel",
136
+ "install",
137
+ "--user",
138
+ "--name",
139
+ kernel_name,
140
+ "--display-name",
141
+ display_name,
142
+ ]
143
+ res = run_in_env(
144
+ cmd=cmd,
145
+ env_name=env_name,
146
+ no_check=no_check,
147
+ verbose=verbose,
148
+ )
149
+ return kernel_name
150
+ elif language == "julia":
151
+ if not no_check:
152
+ check_environment(env_name=env_name, verbose=verbose)
153
+ if env is None:
154
+ env = get_env()
155
+ env_path = env.get("path")
156
+ julia_version = env.get("julia")
157
+ env_fname = os.path.basename(env_path)
158
+ if not env_fname == "Project.toml":
159
+ raise_error(
160
+ "Julia environments require a path pointing to Project.toml"
161
+ )
162
+ env_dir = os.path.dirname(env_path)
163
+ if not env_dir:
164
+ env_dir = "."
165
+ julia_cmd = (
166
+ "import IJulia;"
167
+ "kp=IJulia.installkernel("
168
+ f'"{display_name}",'
169
+ '"--project=@.",'
170
+ 'env=Dict("JULIA_LOAD_PATH" => "@:@stdlib")'
171
+ ");"
172
+ "println(kp);"
173
+ )
174
+ cmd = [
175
+ "julia",
176
+ f"+{julia_version}",
177
+ "--project=" + env_dir,
178
+ "-e",
179
+ julia_cmd,
180
+ ]
181
+ res = subprocess.run(cmd, capture_output=True, text=True)
182
+ if res.returncode != 0:
183
+ raise_error(f"Failed to create kernel:\n{res.stdout}")
184
+ kernel_path = res.stdout.strip()
185
+ typer.echo(f"Registered IJulia kernel at: {kernel_path}")
186
+ kernel_name = os.path.basename(kernel_path)
187
+ return kernel_name
188
+ else:
189
+ raise_error(f"{language} not supported")
114
190
 
115
191
 
116
192
  @notebooks_app.command("execute")
@@ -164,7 +240,7 @@ def execute_notebook(
164
240
  ),
165
241
  ] = None,
166
242
  language: Annotated[
167
- str,
243
+ str | None,
168
244
  typer.Option(
169
245
  "--language",
170
246
  "-l",
@@ -173,7 +249,7 @@ def execute_notebook(
173
249
  "available in environment."
174
250
  ),
175
251
  ),
176
- ] = "python",
252
+ ] = None,
177
253
  verbose: Annotated[
178
254
  bool, typer.Option("--verbose", "-v", help="Print verbose output.")
179
255
  ] = False,
@@ -187,22 +263,34 @@ def execute_notebook(
187
263
 
188
264
  if os.path.isabs(path):
189
265
  raise ValueError("Path must be relative")
266
+ # Detect language from environment
267
+ if language is None:
268
+ ck_info = calkit.load_calkit_info()
269
+ envs = ck_info.get("environments", {})
270
+ if env_name not in envs:
271
+ raise_error(
272
+ f"No environment '{env_name}' defined for this project"
273
+ )
274
+ env = envs[env_name]
275
+ if env.get("kind") == "julia":
276
+ language = "julia"
277
+ else:
278
+ language = "python"
279
+ typer.echo(f"Using {language} as notebook language")
190
280
  if language.lower() not in ["python", "matlab", "julia"]:
191
281
  raise ValueError(
192
282
  "Language must be one of 'python', 'matlab', or 'julia'"
193
283
  )
194
284
  # First, ensure the specified environment has a kernel we can use
195
285
  # We need to check the environment type and create the kernel if needed
196
- if language.lower() == "python":
286
+ if language.lower() in ["python", "julia"]:
197
287
  kernel_name = check_env_kernel(
198
288
  env_name=env_name, no_check=no_check, verbose=verbose
199
289
  )
200
290
  elif language.lower() == "matlab":
201
291
  kernel_name = "jupyter_matlab_kernel"
202
- else:
203
- raise_error(f"Language '{language}' not yet supported")
204
- # We can't handle parameters unless language is Python
205
- if language.lower() != "python":
292
+ # We can't handle parameters unless language is Python or Julia
293
+ if language.lower() not in ["python", "julia"]:
206
294
  if params or params_json is not None or params_base64 is not None:
207
295
  raise_error("Parameters can only be passed to Python notebooks")
208
296
  # Parse parameters
@@ -4,6 +4,7 @@ from __future__ import annotations
4
4
 
5
5
  import os
6
6
  import platform
7
+ import warnings
7
8
  from typing import Any, Literal
8
9
  from typing import get_args as get_type_args
9
10
 
@@ -38,6 +39,9 @@ def supports_keyring() -> bool:
38
39
  except keyring.errors.InitError:
39
40
  # Backend failed to initialize (e.g., user dismissed prompt)
40
41
  return False
42
+ except keyring.errors.KeyringLocked:
43
+ warnings.warn("Keyring is locked; will use YAML config file")
44
+ return False
41
45
  except keyring.errors.KeyringError as e:
42
46
  # Check if the underlying exception indicates no backend
43
47
  if "No backend found" in str(e):
@@ -135,3 +135,38 @@ def test_execute_notebook(tmp_dir):
135
135
  assert params_out["my_value"] == project_params["my_project_value"]
136
136
  assert params_out["my_list"] == list(range(1, 6))
137
137
  assert params_out["my_dict"] == params["my_dict"]
138
+
139
+
140
+ def test_execute_notebook_julia(tmp_dir):
141
+ subprocess.check_call(
142
+ [
143
+ "calkit",
144
+ "new",
145
+ "project",
146
+ ".",
147
+ "-n",
148
+ "cool-project",
149
+ "--title",
150
+ "Cool project",
151
+ ]
152
+ )
153
+ subprocess.check_call(
154
+ [
155
+ "calkit",
156
+ "new",
157
+ "julia-env",
158
+ "--name",
159
+ "main",
160
+ "--julia",
161
+ "1.11",
162
+ "IJulia",
163
+ ]
164
+ )
165
+ nb_fpath = os.path.join(
166
+ os.path.dirname(__file__), "..", "..", "..", "test", "nb-julia.ipynb"
167
+ )
168
+ os.makedirs("notebooks")
169
+ shutil.copy(nb_fpath, "notebooks/main.ipynb")
170
+ subprocess.check_call(
171
+ ["calkit", "nb", "execute", "-e", "main", "notebooks/main.ipynb"]
172
+ )
@@ -0,0 +1,25 @@
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "code",
5
+ "execution_count": null,
6
+ "id": "0",
7
+ "metadata": {
8
+ "vscode": {
9
+ "languageId": "julia"
10
+ }
11
+ },
12
+ "outputs": [],
13
+ "source": [
14
+ "println(\"Hello from Julia!\")"
15
+ ]
16
+ }
17
+ ],
18
+ "metadata": {
19
+ "language_info": {
20
+ "name": "python"
21
+ }
22
+ },
23
+ "nbformat": 4,
24
+ "nbformat_minor": 5
25
+ }
File without changes
File without changes
File without changes
File without changes