calkit-python 0.41.2__tar.gz → 0.41.4__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 (336) hide show
  1. calkit_python-0.41.4/.gitattributes +1 -0
  2. {calkit_python-0.41.2 → calkit_python-0.41.4}/PKG-INFO +1 -1
  3. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/cli/check.py +1 -1
  4. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/cli/main/core.py +20 -5
  5. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/cli/new.py +3 -3
  6. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/cli/scheduler.py +16 -7
  7. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/detect.py +18 -11
  8. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/dvc/core.py +70 -0
  9. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/dvc/zip.py +7 -2
  10. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/environments.py +23 -9
  11. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/git.py +4 -4
  12. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/jupyterlab/routes.py +6 -3
  13. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/overleaf.py +4 -1
  14. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/pipeline.py +78 -44
  15. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/releases.py +2 -2
  16. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/server.py +3 -5
  17. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/tests/cli/main/test_core.py +25 -0
  18. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/tests/cli/main/test_xr.py +5 -0
  19. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/tests/cli/test_check.py +9 -0
  20. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/tests/cli/test_latex.py +15 -0
  21. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/tests/cli/test_new.py +5 -0
  22. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/tests/cli/test_notebooks.py +9 -0
  23. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/tests/cli/test_overleaf.py +5 -1
  24. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/tests/cli/test_scheduler.py +7 -0
  25. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/tests/cli/test_update.py +5 -0
  26. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/tests/dvc/test_core.py +88 -0
  27. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/tests/test_conda.py +17 -2
  28. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/tests/test_environments.py +34 -0
  29. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/tests/test_git.py +14 -0
  30. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/tests/test_install.py +13 -0
  31. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/tests/test_pipeline.py +92 -0
  32. {calkit_python-0.41.2 → calkit_python-0.41.4}/.claude-plugin/marketplace.json +0 -0
  33. {calkit_python-0.41.2 → calkit_python-0.41.4}/.gitignore +0 -0
  34. {calkit_python-0.41.2 → calkit_python-0.41.4}/.pre-commit-config.yaml +0 -0
  35. {calkit_python-0.41.2 → calkit_python-0.41.4}/.prettierignore +0 -0
  36. {calkit_python-0.41.2 → calkit_python-0.41.4}/.python-version +0 -0
  37. {calkit_python-0.41.2 → calkit_python-0.41.4}/.vscode/launch.json +0 -0
  38. {calkit_python-0.41.2 → calkit_python-0.41.4}/.vscode/tasks.json +0 -0
  39. {calkit_python-0.41.2 → calkit_python-0.41.4}/.yarnrc.yml +0 -0
  40. {calkit_python-0.41.2 → calkit_python-0.41.4}/AGENTS.md +0 -0
  41. {calkit_python-0.41.2 → calkit_python-0.41.4}/CITATION.cff +0 -0
  42. {calkit_python-0.41.2 → calkit_python-0.41.4}/CODE_OF_CONDUCT.md +0 -0
  43. {calkit_python-0.41.2 → calkit_python-0.41.4}/CONTRIBUTING.md +0 -0
  44. {calkit_python-0.41.2 → calkit_python-0.41.4}/LICENSE +0 -0
  45. {calkit_python-0.41.2 → calkit_python-0.41.4}/Makefile +0 -0
  46. {calkit_python-0.41.2 → calkit_python-0.41.4}/README.md +0 -0
  47. {calkit_python-0.41.2 → calkit_python-0.41.4}/agent-plugin/.claude-plugin/plugin.json +0 -0
  48. {calkit_python-0.41.2 → calkit_python-0.41.4}/agent-plugin/skills/add-pipeline-stage/SKILL.md +0 -0
  49. {calkit_python-0.41.2 → calkit_python-0.41.4}/agent-plugin/skills/conventions/SKILL.md +0 -0
  50. {calkit_python-0.41.2 → calkit_python-0.41.4}/agent-plugin/skills/create-pipeline/SKILL.md +0 -0
  51. {calkit_python-0.41.2 → calkit_python-0.41.4}/babel.config.js +0 -0
  52. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/__init__.py +0 -0
  53. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/__main__.py +0 -0
  54. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/calc.py +0 -0
  55. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/check.py +0 -0
  56. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/cli/__init__.py +0 -0
  57. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/cli/cloud.py +0 -0
  58. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/cli/config.py +0 -0
  59. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/cli/core.py +0 -0
  60. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/cli/describe.py +0 -0
  61. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/cli/dev.py +0 -0
  62. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/cli/import_.py +0 -0
  63. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/cli/latex.py +0 -0
  64. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/cli/list.py +0 -0
  65. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/cli/main/__init__.py +0 -0
  66. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/cli/main/xr.py +0 -0
  67. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/cli/notebooks.py +0 -0
  68. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/cli/office.py +0 -0
  69. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/cli/overleaf.py +0 -0
  70. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/cli/update.py +0 -0
  71. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/cloud.py +0 -0
  72. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/conda.py +0 -0
  73. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/config.py +0 -0
  74. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/core.py +0 -0
  75. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/datasets.py +0 -0
  76. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/dependencies.py +0 -0
  77. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/docker.py +0 -0
  78. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/dvc/__init__.py +0 -0
  79. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/fs.py +0 -0
  80. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/github.py +0 -0
  81. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/gui.py +0 -0
  82. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/install.py +0 -0
  83. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/invenio.py +0 -0
  84. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/julia.py +0 -0
  85. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/jupyter.py +0 -0
  86. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/jupyterlab/__init__.py +0 -0
  87. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/labextension/package.json +0 -0
  88. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/labextension/schemas/calkit/package.json.orig +0 -0
  89. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/labextension/schemas/calkit/plugin.json +0 -0
  90. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/labextension/static/502.9a2c5772a15466e923ef.js +0 -0
  91. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/labextension/static/695.2c41003a452d43d2b358.js +0 -0
  92. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/labextension/static/867.a42a046aa5108f54f8fb.js +0 -0
  93. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/labextension/static/909.e3f9cc3408834a7fdcc3.js +0 -0
  94. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/labextension/static/946.050af2abf7845cfbdbd2.js +0 -0
  95. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/labextension/static/946.050af2abf7845cfbdbd2.js.LICENSE.txt +0 -0
  96. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/labextension/static/b2f1c3efe70cb539d121.png +0 -0
  97. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/labextension/static/remoteEntry.65469af996e7a96aa983.js +0 -0
  98. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/labextension/static/style.js +0 -0
  99. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/labextension/static/third-party-licenses.json +0 -0
  100. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/licenses.py +0 -0
  101. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/magics.py +0 -0
  102. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/matlab.py +0 -0
  103. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/models/__init__.py +0 -0
  104. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/models/core.py +0 -0
  105. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/models/io.py +0 -0
  106. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/models/iteration.py +0 -0
  107. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/models/pipeline.py +0 -0
  108. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/notebooks.py +0 -0
  109. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/office.py +0 -0
  110. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/ops.py +0 -0
  111. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/templates/__init__.py +0 -0
  112. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/templates/core.py +0 -0
  113. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/templates/latex/__init__.py +0 -0
  114. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/templates/latex/article/paper.tex +0 -0
  115. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/templates/latex/core.py +0 -0
  116. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/templates/latex/jfm/jfm.bst +0 -0
  117. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/templates/latex/jfm/jfm.cls +0 -0
  118. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/templates/latex/jfm/lineno-FLM.sty +0 -0
  119. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/templates/latex/jfm/paper.tex +0 -0
  120. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/templates/latex/jfm/upmath.sty +0 -0
  121. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/tests/__init__.py +0 -0
  122. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/tests/cli/__init__.py +0 -0
  123. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/tests/cli/main/__init__.py +0 -0
  124. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/tests/cli/main/test_subprojects.py +0 -0
  125. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/tests/cli/test_cloud.py +0 -0
  126. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/tests/cli/test_config.py +0 -0
  127. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/tests/cli/test_import.py +0 -0
  128. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/tests/cli/test_list.py +0 -0
  129. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/tests/dvc/__init__.py +0 -0
  130. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/tests/dvc/test_zip.py +0 -0
  131. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/tests/jupyterlab/__init__.py +0 -0
  132. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/tests/jupyterlab/test_routes.py +0 -0
  133. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/tests/models/__init__.py +0 -0
  134. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/tests/models/test_iteration.py +0 -0
  135. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/tests/models/test_pipeline.py +0 -0
  136. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/tests/test_calc.py +0 -0
  137. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/tests/test_check.py +0 -0
  138. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/tests/test_cloud.py +0 -0
  139. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/tests/test_core.py +0 -0
  140. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/tests/test_dependencies.py +0 -0
  141. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/tests/test_detect.py +0 -0
  142. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/tests/test_docker.py +0 -0
  143. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/tests/test_fs.py +0 -0
  144. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/tests/test_invenio.py +0 -0
  145. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/tests/test_julia.py +0 -0
  146. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/tests/test_jupyter.py +0 -0
  147. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/tests/test_magics.py +0 -0
  148. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/tests/test_matlab.py +0 -0
  149. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/tests/test_notebooks.py +0 -0
  150. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/tests/test_releases.py +0 -0
  151. {calkit_python-0.41.2 → calkit_python-0.41.4}/calkit/tests/test_templates.py +0 -0
  152. {calkit_python-0.41.2 → calkit_python-0.41.4}/conftest.py +0 -0
  153. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/CNAME +0 -0
  154. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/ai-tools.md +0 -0
  155. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/apps.md +0 -0
  156. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/calculations.md +0 -0
  157. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/calkit-yaml.md +0 -0
  158. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/cli-reference.md +0 -0
  159. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/cloud-integration.md +0 -0
  160. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/datasets.md +0 -0
  161. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/dependencies.md +0 -0
  162. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/environments.md +0 -0
  163. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/examples.md +0 -0
  164. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/governance.md +0 -0
  165. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/help.md +0 -0
  166. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/hpc.md +0 -0
  167. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/img/c-to-the-k-white.svg +0 -0
  168. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/img/calkit-fragmentation-compendium.png +0 -0
  169. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/img/calkit-no-bg.png +0 -0
  170. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/img/connect-zenodo.png +0 -0
  171. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/img/jupyterlab/all-green.png +0 -0
  172. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/img/jupyterlab/collect-data-stale.png +0 -0
  173. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/img/jupyterlab/new-env.png +0 -0
  174. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/img/jupyterlab/new-notebook.png +0 -0
  175. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/img/jupyterlab/pipeline-badge.png +0 -0
  176. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/img/jupyterlab-params.png +0 -0
  177. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/img/plos-osi-code-2024-03.png +0 -0
  178. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/img/vscode-nb-params.png +0 -0
  179. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/index.md +0 -0
  180. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/installation.md +0 -0
  181. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/jupyterlab.md +0 -0
  182. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/local-server.md +0 -0
  183. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/notebooks.md +0 -0
  184. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/overleaf.md +0 -0
  185. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/pipeline/index.md +0 -0
  186. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/pipeline/manual-steps.md +0 -0
  187. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/pipeline/running-and-logging.md +0 -0
  188. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/quickstart.md +0 -0
  189. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/references.md +0 -0
  190. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/releases.md +0 -0
  191. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/reproducibility.md +0 -0
  192. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/subprojects.md +0 -0
  193. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/tutorials/adding-latex-pub-docker.md +0 -0
  194. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/tutorials/conda-envs.md +0 -0
  195. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/tutorials/existing-project.md +0 -0
  196. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/tutorials/first-project.md +0 -0
  197. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/tutorials/github-actions.md +0 -0
  198. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/tutorials/img/actions-repo-secrets.png +0 -0
  199. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/tutorials/img/latex-codespaces/building-codespace.png +0 -0
  200. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/tutorials/img/latex-codespaces/codespaces-secrets-2.png +0 -0
  201. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/tutorials/img/latex-codespaces/editor-split.png +0 -0
  202. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/tutorials/img/latex-codespaces/go-to-linked-code.png +0 -0
  203. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/tutorials/img/latex-codespaces/issue-from-selection.png +0 -0
  204. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/tutorials/img/latex-codespaces/new-project.png +0 -0
  205. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/tutorials/img/latex-codespaces/new-pub-2.png +0 -0
  206. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/tutorials/img/latex-codespaces/new-token.png +0 -0
  207. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/tutorials/img/latex-codespaces/paper.tex.png +0 -0
  208. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/tutorials/img/latex-codespaces/project-home-3.png +0 -0
  209. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/tutorials/img/latex-codespaces/push.png +0 -0
  210. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/tutorials/img/latex-codespaces/stage.png +0 -0
  211. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/tutorials/img/office/anakin-excel.jpg +0 -0
  212. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/tutorials/img/office/chart-more-rows.png +0 -0
  213. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/tutorials/img/office/create-project.png +0 -0
  214. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/tutorials/img/office/elsevier-research-data-guidelines.png +0 -0
  215. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/tutorials/img/office/excel-chart.png +0 -0
  216. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/tutorials/img/office/excel-data.png +0 -0
  217. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/tutorials/img/office/insert-link-to-file.png +0 -0
  218. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/tutorials/img/office/needs-clone.png +0 -0
  219. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/tutorials/img/office/new-stage.png +0 -0
  220. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/tutorials/img/office/phd-comics-version-control.webp +0 -0
  221. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/tutorials/img/office/pipeline-out-of-date.png +0 -0
  222. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/tutorials/img/office/status-more-rows.png +0 -0
  223. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/tutorials/img/office/uncommitted-changes.png +0 -0
  224. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/tutorials/img/office/untracked-data.png +0 -0
  225. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/tutorials/img/office/updated-publication.png +0 -0
  226. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/tutorials/img/office/word-to-pdf-stage-2.png +0 -0
  227. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/tutorials/img/office/workflow-page.png +0 -0
  228. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/tutorials/img/openfoam/clone.png +0 -0
  229. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/tutorials/img/openfoam/create-project.png +0 -0
  230. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/tutorials/img/openfoam/datasets-page.png +0 -0
  231. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/tutorials/img/openfoam/figure-on-website-updated.png +0 -0
  232. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/tutorials/img/openfoam/figure-on-website.png +0 -0
  233. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/tutorials/img/openfoam/new-token.png +0 -0
  234. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/tutorials/img/openfoam/reclone.png +0 -0
  235. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/tutorials/img/openfoam/status-after-import-dataset.png +0 -0
  236. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/tutorials/img/quick-actions.png +0 -0
  237. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/tutorials/img/run-proc.png +0 -0
  238. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/tutorials/img/vscode-slurm-notebook/create-calkit-env.png +0 -0
  239. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/tutorials/img/vscode-slurm-notebook/create-inner-env.png +0 -0
  240. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/tutorials/img/vscode-slurm-notebook/create-new-calkit-env.png +0 -0
  241. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/tutorials/img/vscode-slurm-notebook/select-calkit-env.png +0 -0
  242. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/tutorials/img/vscode-slurm-notebook/slurm-job-running.png +0 -0
  243. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/tutorials/img/vscode-slurm-notebook/slurm-launch-options.png +0 -0
  244. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/tutorials/img/vscode-slurm-notebook/starting-slurm-job.png +0 -0
  245. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/tutorials/index.md +0 -0
  246. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/tutorials/jupyterlab.md +0 -0
  247. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/tutorials/latex-codespaces.md +0 -0
  248. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/tutorials/matlab.md +0 -0
  249. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/tutorials/notebook-pipeline.md +0 -0
  250. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/tutorials/office.md +0 -0
  251. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/tutorials/openfoam.md +0 -0
  252. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/tutorials/procedures.md +0 -0
  253. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/tutorials/vscode-slurm-notebook.md +0 -0
  254. {calkit_python-0.41.2 → calkit_python-0.41.4}/docs/version-control.md +0 -0
  255. {calkit_python-0.41.2 → calkit_python-0.41.4}/flake.lock +0 -0
  256. {calkit_python-0.41.2 → calkit_python-0.41.4}/flake.nix +0 -0
  257. {calkit_python-0.41.2 → calkit_python-0.41.4}/install.json +0 -0
  258. {calkit_python-0.41.2 → calkit_python-0.41.4}/jest.config.js +0 -0
  259. {calkit_python-0.41.2 → calkit_python-0.41.4}/jupyter-config/server-config/calkit.json +0 -0
  260. {calkit_python-0.41.2 → calkit_python-0.41.4}/mkdocs.yml +0 -0
  261. {calkit_python-0.41.2 → calkit_python-0.41.4}/package.json +0 -0
  262. {calkit_python-0.41.2 → calkit_python-0.41.4}/pyproject.toml +0 -0
  263. {calkit_python-0.41.2 → calkit_python-0.41.4}/schema/plugin.json +0 -0
  264. {calkit_python-0.41.2 → calkit_python-0.41.4}/scripts/generate-docs-references.py +0 -0
  265. {calkit_python-0.41.2 → calkit_python-0.41.4}/scripts/install.ps1 +0 -0
  266. {calkit_python-0.41.2 → calkit_python-0.41.4}/scripts/install.sh +0 -0
  267. {calkit_python-0.41.2 → calkit_python-0.41.4}/scripts/make-calk9.sh +0 -0
  268. {calkit_python-0.41.2 → calkit_python-0.41.4}/scripts/sync-docs.py +0 -0
  269. {calkit_python-0.41.2 → calkit_python-0.41.4}/src/__tests__/useQueries.spec.ts +0 -0
  270. {calkit_python-0.41.2 → calkit_python-0.41.4}/src/calkit-config.ts +0 -0
  271. {calkit_python-0.41.2 → calkit_python-0.41.4}/src/cell-output-marker.ts +0 -0
  272. {calkit_python-0.41.2 → calkit_python-0.41.4}/src/components/commit-dialog.tsx +0 -0
  273. {calkit_python-0.41.2 → calkit_python-0.41.4}/src/components/environment-editor.tsx +0 -0
  274. {calkit_python-0.41.2 → calkit_python-0.41.4}/src/components/notebook-registration.tsx +0 -0
  275. {calkit_python-0.41.2 → calkit_python-0.41.4}/src/components/notebook-toolbar.tsx +0 -0
  276. {calkit_python-0.41.2 → calkit_python-0.41.4}/src/components/pipeline-status-bar.tsx +0 -0
  277. {calkit_python-0.41.2 → calkit_python-0.41.4}/src/components/project-info-editor.tsx +0 -0
  278. {calkit_python-0.41.2 → calkit_python-0.41.4}/src/components/sidebar-settings.tsx +0 -0
  279. {calkit_python-0.41.2 → calkit_python-0.41.4}/src/components/sidebar.tsx +0 -0
  280. {calkit_python-0.41.2 → calkit_python-0.41.4}/src/components/stage-editor.tsx +0 -0
  281. {calkit_python-0.41.2 → calkit_python-0.41.4}/src/feature-flags.ts +0 -0
  282. {calkit_python-0.41.2 → calkit_python-0.41.4}/src/file-browser-menu.ts +0 -0
  283. {calkit_python-0.41.2 → calkit_python-0.41.4}/src/hooks/__tests__/useQueries.test.tsx +0 -0
  284. {calkit_python-0.41.2 → calkit_python-0.41.4}/src/hooks/useQueries.ts +0 -0
  285. {calkit_python-0.41.2 → calkit_python-0.41.4}/src/icons.ts +0 -0
  286. {calkit_python-0.41.2 → calkit_python-0.41.4}/src/index.ts +0 -0
  287. {calkit_python-0.41.2 → calkit_python-0.41.4}/src/io-tracker.ts +0 -0
  288. {calkit_python-0.41.2 → calkit_python-0.41.4}/src/pipeline-state.ts +0 -0
  289. {calkit_python-0.41.2 → calkit_python-0.41.4}/src/queryClient.ts +0 -0
  290. {calkit_python-0.41.2 → calkit_python-0.41.4}/src/request.ts +0 -0
  291. {calkit_python-0.41.2 → calkit_python-0.41.4}/src/shims-mainmenu.d.ts +0 -0
  292. {calkit_python-0.41.2 → calkit_python-0.41.4}/style/base.css +0 -0
  293. {calkit_python-0.41.2 → calkit_python-0.41.4}/style/cell-output-marker.css +0 -0
  294. {calkit_python-0.41.2 → calkit_python-0.41.4}/style/environment-editor.css +0 -0
  295. {calkit_python-0.41.2 → calkit_python-0.41.4}/style/environment-selector.css +0 -0
  296. {calkit_python-0.41.2 → calkit_python-0.41.4}/style/img/calkit-no-bg.png +0 -0
  297. {calkit_python-0.41.2 → calkit_python-0.41.4}/style/index.css +0 -0
  298. {calkit_python-0.41.2 → calkit_python-0.41.4}/style/index.js +0 -0
  299. {calkit_python-0.41.2 → calkit_python-0.41.4}/style/notebook-toolbar.css +0 -0
  300. {calkit_python-0.41.2 → calkit_python-0.41.4}/style/pipeline-status-bar.css +0 -0
  301. {calkit_python-0.41.2 → calkit_python-0.41.4}/style/sidebar.css +0 -0
  302. {calkit_python-0.41.2 → calkit_python-0.41.4}/test/dvc-md5-dir/osx-arm64.txt +0 -0
  303. {calkit_python-0.41.2 → calkit_python-0.41.4}/test/nb-julia.ipynb +0 -0
  304. {calkit_python-0.41.2 → calkit_python-0.41.4}/test/nb-params.ipynb +0 -0
  305. {calkit_python-0.41.2 → calkit_python-0.41.4}/test/nb-subdir.ipynb +0 -0
  306. {calkit_python-0.41.2 → calkit_python-0.41.4}/test/pipeline.ipynb +0 -0
  307. {calkit_python-0.41.2 → calkit_python-0.41.4}/test/script.py +0 -0
  308. {calkit_python-0.41.2 → calkit_python-0.41.4}/test/test-log.log +0 -0
  309. {calkit_python-0.41.2 → calkit_python-0.41.4}/tsconfig.json +0 -0
  310. {calkit_python-0.41.2 → calkit_python-0.41.4}/tsconfig.test.json +0 -0
  311. {calkit_python-0.41.2 → calkit_python-0.41.4}/ui-tests/.gitignore +0 -0
  312. {calkit_python-0.41.2 → calkit_python-0.41.4}/ui-tests/README.md +0 -0
  313. {calkit_python-0.41.2 → calkit_python-0.41.4}/ui-tests/jupyter_server_test_config.py +0 -0
  314. {calkit_python-0.41.2 → calkit_python-0.41.4}/ui-tests/package.json +0 -0
  315. {calkit_python-0.41.2 → calkit_python-0.41.4}/ui-tests/playwright.config.js +0 -0
  316. {calkit_python-0.41.2 → calkit_python-0.41.4}/ui-tests/tests/calkit.spec.ts +0 -0
  317. {calkit_python-0.41.2 → calkit_python-0.41.4}/ui-tests/yarn.lock +0 -0
  318. {calkit_python-0.41.2 → calkit_python-0.41.4}/uv.lock +0 -0
  319. {calkit_python-0.41.2 → calkit_python-0.41.4}/vscode-ext/.gitignore +0 -0
  320. {calkit_python-0.41.2 → calkit_python-0.41.4}/vscode-ext/.vscodeignore +0 -0
  321. {calkit_python-0.41.2 → calkit_python-0.41.4}/vscode-ext/CHANGELOG.md +0 -0
  322. {calkit_python-0.41.2 → calkit_python-0.41.4}/vscode-ext/LICENSE +0 -0
  323. {calkit_python-0.41.2 → calkit_python-0.41.4}/vscode-ext/README.md +0 -0
  324. {calkit_python-0.41.2 → calkit_python-0.41.4}/vscode-ext/images/calkit-no-bg.png +0 -0
  325. {calkit_python-0.41.2 → calkit_python-0.41.4}/vscode-ext/package-lock.json +0 -0
  326. {calkit_python-0.41.2 → calkit_python-0.41.4}/vscode-ext/package.json +0 -0
  327. {calkit_python-0.41.2 → calkit_python-0.41.4}/vscode-ext/scripts/set-proposed-api.js +0 -0
  328. {calkit_python-0.41.2 → calkit_python-0.41.4}/vscode-ext/src/environments.ts +0 -0
  329. {calkit_python-0.41.2 → calkit_python-0.41.4}/vscode-ext/src/extension.ts +0 -0
  330. {calkit_python-0.41.2 → calkit_python-0.41.4}/vscode-ext/src/notebooks.ts +0 -0
  331. {calkit_python-0.41.2 → calkit_python-0.41.4}/vscode-ext/src/test/environments.test.ts +0 -0
  332. {calkit_python-0.41.2 → calkit_python-0.41.4}/vscode-ext/src/test/kernel-selection.test.ts +0 -0
  333. {calkit_python-0.41.2 → calkit_python-0.41.4}/vscode-ext/src/test/notebooks.test.ts +0 -0
  334. {calkit_python-0.41.2 → calkit_python-0.41.4}/vscode-ext/src/types.ts +0 -0
  335. {calkit_python-0.41.2 → calkit_python-0.41.4}/vscode-ext/tsconfig.json +0 -0
  336. {calkit_python-0.41.2 → calkit_python-0.41.4}/yarn.lock +0 -0
@@ -0,0 +1 @@
1
+ test/dvc-md5-dir/** text eol=lf
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: calkit-python
3
- Version: 0.41.2
3
+ Version: 0.41.4
4
4
  Summary: Reproducibility simplified.
5
5
  Project-URL: Homepage, https://calkit.org
6
6
  Project-URL: Issues, https://github.com/calkit/calkit/issues
@@ -381,7 +381,7 @@ def check_environment(
381
381
  quiet=not verbose,
382
382
  )
383
383
  elif env["kind"] == "pixi":
384
- cmd = ["pixi", "lock"]
384
+ cmd = ["pixi", "install"]
385
385
  env_dir = os.path.dirname(env["path"])
386
386
  if env_dir:
387
387
  cmd += ["--manifest-path", env["path"]]
@@ -502,10 +502,11 @@ def get_status(
502
502
  if "dvc" in categories:
503
503
  try:
504
504
  dvc_repo = calkit.dvc.get_dvc_repo()
505
- data_status = dvc_repo.data_status()
506
- if isinstance(data_status, dict):
507
- data_status.pop("git", None)
508
- status_dict["dvc"] = data_status
505
+ data_status = dict(dvc_repo.data_status())
506
+ data_status.pop("git", None)
507
+ status_dict["dvc"] = calkit.dvc.data_status_as_posix(
508
+ data_status
509
+ )
509
510
  except Exception as e:
510
511
  status_dict["dvc"] = {"error": f"{e.__class__.__name__}: {e}"}
511
512
  if "pipeline" in categories or "dvc" in categories:
@@ -557,6 +558,7 @@ def get_status(
557
558
  dvc_repo = calkit.dvc.get_dvc_repo()
558
559
  raw = dict(dvc_repo.data_status())
559
560
  raw.pop("git", None)
561
+ raw = calkit.dvc.data_status_as_posix(raw)
560
562
  typer.echo(_format_dvc_data_status(raw, zip_path_map))
561
563
  if "pipeline" in categories or "dvc" in categories:
562
564
  print_sep("Pipeline")
@@ -579,6 +581,8 @@ def get_status(
579
581
  if stale_stage is None:
580
582
  continue
581
583
  typer.echo(f" {typer.style(stage_name, fg='yellow')}:")
584
+ if stale_stage.always_run:
585
+ typer.echo(" always runs")
582
586
  if stale_stage.modified_command:
583
587
  typer.echo(" modified command")
584
588
  # Show stale outputs for this stage
@@ -596,8 +600,16 @@ def get_status(
596
600
  typer.echo(" modified inputs:")
597
601
  for input_path in stale_stage.modified_inputs:
598
602
  typer.echo(f" {input_path}")
603
+ if pipeline_status.always_run_stage_names:
604
+ typer.echo("Always-run stages:")
605
+ for stage_name in pipeline_status.always_run_stage_names:
606
+ typer.echo(f" {typer.style(stage_name, fg='cyan')}")
599
607
  elif pipeline_status:
600
608
  typer.echo("Pipeline is up to date.")
609
+ if pipeline_status.always_run_stage_names:
610
+ typer.echo("Always-run stages:")
611
+ for stage_name in pipeline_status.always_run_stage_names:
612
+ typer.echo(f" {typer.style(stage_name, fg='cyan')}")
601
613
 
602
614
 
603
615
  @app.command(name="diff")
@@ -2421,7 +2433,10 @@ def run_in_env(
2421
2433
  elif env["kind"] == "pixi":
2422
2434
  env_cmd = []
2423
2435
  if "name" in env:
2424
- env_cmd = ["--environment", env["name"]]
2436
+ env_cmd += ["--environment", env["name"]]
2437
+ env_path = env.get("path")
2438
+ if env_path and os.path.dirname(env_path):
2439
+ env_cmd += ["--manifest-path", os.path.abspath(env_path)]
2425
2440
  cmd = ["pixi", "run"] + env_cmd + cmd
2426
2441
  if verbose:
2427
2442
  typer.echo(f"Running command: {cmd}")
@@ -1152,10 +1152,10 @@ def new_publication(
1152
1152
  deps += stage.get("outs", [])
1153
1153
  # Create publication object
1154
1154
  if template_type == "latex":
1155
- pub_fpath = os.path.join(
1155
+ pub_fpath = pathlib.Path(
1156
1156
  path,
1157
1157
  template_obj.target.removesuffix(".tex") + ".pdf", # type: ignore
1158
- )
1158
+ ).as_posix()
1159
1159
  else:
1160
1160
  pub_fpath = path
1161
1161
  if not overwrite and pub_fpath in pub_paths:
@@ -1190,7 +1190,7 @@ def new_publication(
1190
1190
  stage = LatexStage(
1191
1191
  kind="latex",
1192
1192
  environment=env_name,
1193
- target_path=os.path.join(path, template_obj.target), # type: ignore
1193
+ target_path=pathlib.Path(path, template_obj.target).as_posix(), # type: ignore
1194
1194
  outputs=[pub_fpath],
1195
1195
  ).model_dump()
1196
1196
  if "pipeline" not in ck_info:
@@ -92,9 +92,9 @@ def _mock_enabled() -> bool:
92
92
 
93
93
 
94
94
  def _require_posix_mock() -> None:
95
- # The mock backend uses bash, new sessions, and process-group signals.
96
- if os.name != "posix":
97
- raise_error("CALKIT_MOCK_SCHEDULER is only supported on POSIX systems")
95
+ # The mock backend uses bash; if that is missing, the mock cannot run.
96
+ if shutil.which("bash") is None:
97
+ raise_error("CALKIT_MOCK_SCHEDULER requires bash on PATH")
98
98
 
99
99
 
100
100
  def _ensure_mock_dir() -> None:
@@ -177,13 +177,19 @@ def _mock_submit(job_id: str, job_command: str, log_path: str) -> int:
177
177
  env = dict(os.environ)
178
178
  env.setdefault("PBS_O_WORKDIR", os.getcwd())
179
179
  with open(log_path, "w") as log_file:
180
- proc = subprocess.Popen(
181
- ["bash", "-c", wrapped],
180
+ popen_kwargs = dict(
182
181
  stdout=log_file,
183
182
  stderr=subprocess.STDOUT,
184
- start_new_session=True,
185
183
  env=env,
186
184
  )
185
+ if os.name == "posix":
186
+ popen_kwargs["start_new_session"] = True
187
+ elif hasattr(subprocess, "CREATE_NEW_PROCESS_GROUP"):
188
+ popen_kwargs["creationflags"] = subprocess.CREATE_NEW_PROCESS_GROUP
189
+ proc = subprocess.Popen(
190
+ ["bash", "-c", wrapped],
191
+ **popen_kwargs,
192
+ )
187
193
  return proc.pid
188
194
 
189
195
 
@@ -192,7 +198,10 @@ def _mock_cancel(job_id: str) -> tuple[bool, str]:
192
198
  pid = _mock_pid(job_id)
193
199
  if pid is not None:
194
200
  try:
195
- os.killpg(os.getpgid(pid), signal.SIGTERM)
201
+ if os.name == "posix":
202
+ os.killpg(os.getpgid(pid), signal.SIGTERM)
203
+ else:
204
+ os.kill(pid, signal.SIGTERM)
196
205
  except (ProcessLookupError, PermissionError):
197
206
  pass
198
207
  # Drop a sentinel so later liveness checks report the job as finished.
@@ -10,6 +10,7 @@ import os
10
10
  import re
11
11
  import shlex
12
12
  import sys
13
+ from pathlib import Path
13
14
  from typing import Literal
14
15
 
15
16
  NotebookLanguage = Literal["python", "julia", "r"]
@@ -114,7 +115,7 @@ def detect_julia_script_io(
114
115
  if not os.path.isabs(match):
115
116
  full_path = os.path.join(script_dir, match)
116
117
  if os.path.exists(full_path):
117
- inputs.append(os.path.relpath(full_path))
118
+ inputs.append(Path(os.path.relpath(full_path)).as_posix())
118
119
  elif _is_valid_project_path(match):
119
120
  inputs.append(match)
120
121
  read_patterns = [
@@ -421,26 +422,29 @@ def detect_latex_io(tex_path: str) -> dict[str, list[str]]:
421
422
  for pattern, pattern_type in patterns:
422
423
  matches = re.findall(pattern, content)
423
424
  for match in matches:
425
+
426
+ def _resolve(name: str) -> str:
427
+ return Path(
428
+ os.path.normpath(os.path.join(tex_dir, name))
429
+ ).as_posix()
430
+
424
431
  if pattern_type == "bib":
425
432
  files = [f.strip() for f in match.split(",")]
426
433
  for f in files:
427
434
  if not f.endswith(".bib"):
428
435
  f += ".bib"
429
436
  # Resolve relative to the document directory
430
- resolved = os.path.normpath(os.path.join(tex_dir, f))
431
- inputs.append(resolved)
437
+ inputs.append(_resolve(f))
432
438
  elif pattern_type == "tex":
433
439
  filename = match
434
440
  if not filename.endswith(".tex"):
435
441
  filename += ".tex"
436
442
  # Resolve relative to the document directory
437
- resolved = os.path.normpath(os.path.join(tex_dir, filename))
438
- inputs.append(resolved)
443
+ inputs.append(_resolve(filename))
439
444
  else:
440
445
  # Include graphics or other files
441
446
  # Resolve relative to the document directory
442
- resolved = os.path.normpath(os.path.join(tex_dir, match))
443
- inputs.append(resolved)
447
+ inputs.append(_resolve(match))
444
448
  # Filter and deduplicate inputs
445
449
  inputs = [p for p in inputs if _is_valid_project_path(p)]
446
450
  inputs = list(dict.fromkeys(inputs))
@@ -774,6 +778,9 @@ def _detect_python_code_io(
774
778
  except ValueError:
775
779
  # If paths are on different drives (Windows), use normalized path
776
780
  rel_path = full_path
781
+ # Always emit posix separators so downstream comparisons are stable
782
+ # across platforms.
783
+ rel_path = Path(rel_path).as_posix()
777
784
  # Strip leading ../ for paths outside project root
778
785
  while rel_path.startswith("../"):
779
786
  rel_path = rel_path[3:]
@@ -938,7 +945,7 @@ def _detect_julia_code_io(
938
945
  if not os.path.isabs(match):
939
946
  full_path = os.path.join(script_dir, match)
940
947
  if os.path.exists(full_path):
941
- inputs.append(os.path.relpath(full_path))
948
+ inputs.append(Path(os.path.relpath(full_path)).as_posix())
942
949
  elif _is_valid_project_path(match):
943
950
  inputs.append(match)
944
951
  read_patterns = [
@@ -978,12 +985,12 @@ def _resolve_python_import(
978
985
  if os.path.exists(file_path) and _is_valid_project_path(
979
986
  os.path.relpath(file_path)
980
987
  ):
981
- return os.path.relpath(file_path)
988
+ return Path(os.path.relpath(file_path)).as_posix()
982
989
  init_path = os.path.join(search_dir, module_path, "__init__.py")
983
990
  if os.path.exists(init_path) and _is_valid_project_path(
984
991
  os.path.relpath(init_path)
985
992
  ):
986
- return os.path.relpath(init_path)
993
+ return Path(os.path.relpath(init_path)).as_posix()
987
994
  return None
988
995
 
989
996
 
@@ -1018,7 +1025,7 @@ def _detect_r_code_io(
1018
1025
  if not os.path.isabs(match):
1019
1026
  full_path = os.path.join(script_dir, match)
1020
1027
  if os.path.exists(full_path):
1021
- inputs.append(os.path.relpath(full_path))
1028
+ inputs.append(Path(os.path.relpath(full_path)).as_posix())
1022
1029
  elif _is_valid_project_path(match):
1023
1030
  inputs.append(match)
1024
1031
  # Read patterns that capture variables, file.path() expressions, or literals
@@ -26,6 +26,24 @@ logger.setLevel(logging.INFO)
26
26
  USE_CK_REMOTE_BY_DEFAULT = True
27
27
 
28
28
 
29
+ class _FrozenStageWarningFilter(logging.Filter):
30
+ """Drop DVC's "stage is frozen" warnings.
31
+
32
+ DVC emits these for every frozen stage on every ``status``/``repro`` call
33
+ ("... not going to be shown in the status output." and "... not going to
34
+ be reproduced."). Frozen stages are pinned by design, so the warnings are
35
+ noise — the substring shared by both variants is matched here.
36
+ """
37
+
38
+ def filter(self, record: logging.LogRecord) -> bool:
39
+ return "is frozen. Its dependencies are" not in record.getMessage()
40
+
41
+
42
+ _frozen_stage_warning_filter = _FrozenStageWarningFilter()
43
+ for _name in ("dvc.repo.reproduce", "dvc.repo.status"):
44
+ logging.getLogger(_name).addFilter(_frozen_stage_warning_filter)
45
+
46
+
29
47
  class CalkitDVCFileSystem(ObjectFileSystem):
30
48
  """DVC-facing filesystem wrapper for the ``ck://`` scheme."""
31
49
 
@@ -614,3 +632,55 @@ def hash_path(path: str) -> dict:
614
632
  return hash_file(path)
615
633
  else:
616
634
  raise ValueError(f"Path does not exist: {path}")
635
+
636
+
637
+ def _path_item_as_posix(item):
638
+ # Renamed entries are dicts like {"old": ..., "new": ...}.
639
+ if isinstance(item, dict):
640
+ return {k: Path(v).as_posix() for k, v in item.items()}
641
+ return Path(item).as_posix()
642
+
643
+
644
+ def data_status_as_posix(data_status: dict) -> dict:
645
+ """Convert all paths in DVC data status to posix format.
646
+
647
+ We skip the ``git`` entry since Git already formats as posix.
648
+ """
649
+ data_status_fmt = {}
650
+ for cat, obj in data_status.items():
651
+ if cat == "git":
652
+ data_status_fmt[cat] = obj
653
+ elif isinstance(obj, list):
654
+ data_status_fmt[cat] = [_path_item_as_posix(p) for p in obj]
655
+ elif isinstance(obj, dict):
656
+ obj_fmt = {}
657
+ for cat2, obj_i in obj.items():
658
+ obj_fmt[cat2] = [_path_item_as_posix(p) for p in obj_i]
659
+ data_status_fmt[cat] = obj_fmt
660
+ else:
661
+ data_status_fmt[cat] = obj
662
+ return data_status_fmt
663
+
664
+
665
+ def status_as_posix(status: dict) -> dict:
666
+ """Convert all paths in repo status to posix format."""
667
+ status_fmt = {}
668
+ for stage_name, st_list in status.items():
669
+ st_list_fmt = []
670
+ for st_dict in st_list:
671
+ if isinstance(st_dict, str):
672
+ st_list_fmt.append(st_dict)
673
+ continue
674
+ st_dict_fmt = {}
675
+ for st_cat, path_st_dict in st_dict.items():
676
+ if not isinstance(path_st_dict, dict):
677
+ # e.g. {"changed command": "python src/new-script.py"}
678
+ st_dict_fmt[st_cat] = path_st_dict
679
+ continue
680
+ path_st_dict_fmt = {}
681
+ for p, st in path_st_dict.items():
682
+ path_st_dict_fmt[Path(p).as_posix()] = st
683
+ st_dict_fmt[st_cat] = path_st_dict_fmt
684
+ st_list_fmt.append(st_dict_fmt)
685
+ status_fmt[stage_name] = st_list_fmt
686
+ return status_fmt
@@ -113,7 +113,7 @@ class SyncRecord(BaseModel):
113
113
 
114
114
  def make_zip_path(workspace_path: str) -> str:
115
115
  """Make a zip path for a given workspace path."""
116
- return os.path.join(ZIPS_DIR, "files", workspace_path + ".zip")
116
+ return Path(ZIPS_DIR, "files", f"{workspace_path}.zip").as_posix()
117
117
 
118
118
 
119
119
  def _path_map_path(wdir: str | None = None) -> str:
@@ -272,6 +272,7 @@ def get_sync_record(
272
272
  ) -> SyncRecord | None:
273
273
  """Get a sync record for a given workspace path."""
274
274
  _check_local_dir(wdir)
275
+ workspace_path = Path(workspace_path).as_posix()
275
276
  with SqliteDict(_sync_records_path(wdir)) as db:
276
277
  raw = db.get(workspace_path)
277
278
  if raw is not None:
@@ -283,13 +284,14 @@ def write_sync_record(record: SyncRecord, wdir: str | None = None):
283
284
  """Write a sync record."""
284
285
  _check_local_dir(wdir)
285
286
  with SqliteDict(_sync_records_path(wdir)) as db:
286
- db[record.workspace_path] = record.model_dump()
287
+ db[Path(record.workspace_path).as_posix()] = record.model_dump()
287
288
  db.commit()
288
289
 
289
290
 
290
291
  def delete_sync_record(workspace_path: str, wdir: str | None = None):
291
292
  """Delete a sync record."""
292
293
  _check_local_dir(wdir)
294
+ workspace_path = Path(workspace_path).as_posix()
293
295
  with SqliteDict(_sync_records_path(wdir)) as db:
294
296
  if workspace_path in db:
295
297
  del db[workspace_path]
@@ -466,6 +468,9 @@ def sync_one(
466
468
  workspace_path = os.path.join(wdir, workspace_path)
467
469
  if zip_path is not None:
468
470
  zip_path = os.path.join(wdir, zip_path)
471
+ workspace_path = Path(workspace_path).as_posix()
472
+ if zip_path is not None:
473
+ zip_path = Path(zip_path).as_posix()
469
474
  return _sync_one(workspace_path, zip_path, direction, wdir=wdir)
470
475
 
471
476
 
@@ -38,6 +38,12 @@ CONDA_VENV_ARCHS = [
38
38
  ]
39
39
  ENV_CHECK_CACHE_TTL_SECONDS = 3600
40
40
  KINDS_NO_CHECK = ["_system", "ssh"]
41
+
42
+
43
+ def _as_posix_path(path: str) -> str:
44
+ return Path(path).as_posix()
45
+
46
+
41
47
  COMPOSITE_ENV_SEP = ":"
42
48
  VALID_OUTER_ENV_KINDS = ["slurm", "pbs"]
43
49
 
@@ -314,6 +320,12 @@ def get_env_lock_fpath(
314
320
  lock_fpath = os.path.join(env_dir, "uv.lock")
315
321
  else:
316
322
  lock_fpath = "uv.lock"
323
+ elif env_kind == "pixi":
324
+ env_dir = os.path.dirname(env.get("path") or "")
325
+ if env_dir:
326
+ lock_fpath = os.path.join(env_dir, "pixi.lock")
327
+ else:
328
+ lock_fpath = "pixi.lock"
317
329
  elif env_kind in ["venv", "uv-venv"]:
318
330
  if legacy:
319
331
  lock_fpath += ".txt"
@@ -711,7 +723,7 @@ def make_env_name(path: str, all_env_names: list[str], kind: str) -> str:
711
723
  str
712
724
  A unique environment name.
713
725
  """
714
- dirname = os.path.basename(os.path.dirname(path))
726
+ dirname = Path(path).parent.name
715
727
  # If this is the first env in the project, call it main
716
728
  if not all_env_names:
717
729
  return dirname or "main"
@@ -835,7 +847,7 @@ def env_from_name_or_path(
835
847
  exists=True,
836
848
  )
837
849
  # Check if name_or_path is a file and detect environment type
838
- env_path = name_or_path
850
+ env_path = _as_posix_path(name_or_path)
839
851
  if os.path.isfile(env_path):
840
852
  if env_path.endswith("requirements.txt"):
841
853
  # TODO: Detect if uv is installed, and use a plain venv if not
@@ -845,9 +857,9 @@ def env_from_name_or_path(
845
857
  "kind": "uv-venv",
846
858
  "path": env_path,
847
859
  "python": DEFAULT_PYTHON_VERSION,
848
- "prefix": os.path.join(
849
- os.path.split(env_path)[0], ".venv"
850
- ),
860
+ "prefix": Path(env_path)
861
+ .parent.joinpath(".venv")
862
+ .as_posix(),
851
863
  },
852
864
  exists=False,
853
865
  )
@@ -936,9 +948,10 @@ def env_from_name_and_or_path(
936
948
  if ck_info is None:
937
949
  ck_info = calkit.load_calkit_info()
938
950
  envs = ck_info.get("environments", {})
951
+ path = _as_posix_path(path) if path else None
939
952
  if name and name in envs:
940
953
  env = envs[name]
941
- if path and env.get("path") != path:
954
+ if path and _as_posix_path(env.get("path", "")) != path:
942
955
  raise ValueError(
943
956
  f"Environment '{name}' exists but has a different path "
944
957
  f"('{env.get('path')}') than provided ('{path}')"
@@ -952,7 +965,7 @@ def env_from_name_and_or_path(
952
965
  # Look for a sub-environment with the given name and path
953
966
  for sub_name, sub_env in envs.items():
954
967
  if (sub_name == sub_env_name) or (
955
- path and sub_env.get("path") == path
968
+ path and _as_posix_path(sub_env.get("path", "")) == path
956
969
  ):
957
970
  return EnvDetectResult(
958
971
  name=sub_name,
@@ -989,12 +1002,13 @@ def env_from_notebook_path(
989
1002
  """
990
1003
  if ck_info is None:
991
1004
  ck_info = calkit.load_calkit_info()
1005
+ notebook_path = _as_posix_path(notebook_path)
992
1006
  stages = ck_info.get("pipeline", {}).get("stages", {})
993
1007
  envs = ck_info.get("environments", {})
994
1008
  for stage in stages.values():
995
1009
  if (
996
1010
  stage.get("kind") == "jupyter-notebook"
997
- and stage.get("notebook_path") == notebook_path
1011
+ and _as_posix_path(stage.get("notebook_path", "")) == notebook_path
998
1012
  ):
999
1013
  env_name = stage.get("environment")
1000
1014
  if env_name:
@@ -1002,7 +1016,7 @@ def env_from_notebook_path(
1002
1016
  if env:
1003
1017
  return EnvDetectResult(name=env_name, env=env, exists=True)
1004
1018
  for nb in ck_info.get("notebooks", []):
1005
- if nb.get("path") == notebook_path:
1019
+ if _as_posix_path(nb.get("path", "")) == notebook_path:
1006
1020
  env_name = nb.get("environment")
1007
1021
  if env_name:
1008
1022
  env = envs.get(env_name)
@@ -157,7 +157,7 @@ def ensure_path_is_ignored(
157
157
  if os.path.isfile(gitignore_path):
158
158
  with open(gitignore_path) as f:
159
159
  gitignore_txt = f.read()
160
- lines = gitignore_txt.splitlines()
160
+ lines = [line for line in gitignore_txt.splitlines() if line]
161
161
  if target_path in lines:
162
162
  # The direct rule exists; also remove any stale negation that
163
163
  # follows it, otherwise the negation wins and the path stays
@@ -169,7 +169,7 @@ def ensure_path_is_ignored(
169
169
  for n in stale:
170
170
  lines.remove(n)
171
171
  with open(gitignore_path, "w") as f:
172
- f.write(os.linesep.join(lines))
172
+ f.write("\n".join(lines))
173
173
  return True
174
174
  # Remove any stale negations for this path so the ignore rule takes
175
175
  # effect cleanly without accumulating contradictory entries.
@@ -180,7 +180,7 @@ def ensure_path_is_ignored(
180
180
  lines.remove(n)
181
181
  lines.append(target_path)
182
182
  with open(gitignore_path, "w") as f:
183
- f.write(os.linesep.join(lines))
183
+ f.write("\n".join(lines))
184
184
  return True
185
185
  with open(gitignore_path, "a") as f:
186
186
  if (
@@ -329,7 +329,7 @@ def ensure_path_is_not_ignored(
329
329
  lines.remove(no_ignore_line)
330
330
  lines.append(no_ignore_line)
331
331
  with open(gitignore_path, "w") as f:
332
- f.write(os.linesep.join(lines))
332
+ f.write("\n".join(lines))
333
333
  # If the path is still ignored after updating this gitignore file (e.g.,
334
334
  # because a subdirectory .gitignore also contains a matching rule), fix
335
335
  # that file as well. Depth-limit guards against pathological gitignore
@@ -903,11 +903,14 @@ class PipelineStatusRouteHandler(APIHandler):
903
903
  pipeline_status = {
904
904
  k.split("dvc.yaml:")[-1]: v
905
905
  for k, v in raw_status.items()
906
- if v != ["always changed"]
907
- and not k.endswith(".dvc")
906
+ if not k.endswith(".dvc")
908
907
  and k.split("dvc.yaml:")[-1].split("@")[0] not in frozen_stages
909
908
  }
910
- is_outdated = len(pipeline_status) > 0
909
+ # Always-run-only stages are surfaced in pipeline_status but do
910
+ # not count toward is_outdated, matching the CLI's is_stale logic.
911
+ is_outdated = any(
912
+ v != ["always changed"] for v in pipeline_status.values()
913
+ )
911
914
  self.finish(
912
915
  json.dumps(
913
916
  {
@@ -4,6 +4,7 @@ import json
4
4
  import os
5
5
  import shutil
6
6
  import subprocess
7
+ import tempfile
7
8
  import warnings
8
9
  from copy import deepcopy
9
10
  from functools import cached_property
@@ -23,7 +24,9 @@ def get_git_remote_url(project_id: str, token: str) -> str:
23
24
  If running against a test environment, this will use a local directory.
24
25
  """
25
26
  if calkit.config.get_env() == "test":
26
- return os.path.join("/tmp", "overleaf", project_id)
27
+ return (
28
+ Path(tempfile.gettempdir()) / "overleaf" / project_id
29
+ ).as_posix()
27
30
  return f"https://git:{token}@git.overleaf.com/{project_id}"
28
31
 
29
32