calkit-python 0.21.5__tar.gz → 0.21.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 (144) hide show
  1. {calkit_python-0.21.5 → calkit_python-0.21.6}/PKG-INFO +9 -3
  2. {calkit_python-0.21.5 → calkit_python-0.21.6}/README.md +8 -2
  3. {calkit_python-0.21.5 → calkit_python-0.21.6}/calkit/__init__.py +1 -1
  4. {calkit_python-0.21.5 → calkit_python-0.21.6}/calkit/cli/core.py +2 -0
  5. {calkit_python-0.21.5 → calkit_python-0.21.6}/calkit/cli/import_.py +2 -1
  6. {calkit_python-0.21.5 → calkit_python-0.21.6}/calkit/cli/main.py +38 -13
  7. {calkit_python-0.21.5 → calkit_python-0.21.6}/calkit/cli/new.py +18 -6
  8. {calkit_python-0.21.5 → calkit_python-0.21.6}/calkit/dvc.py +49 -5
  9. {calkit_python-0.21.5 → calkit_python-0.21.6}/calkit/magics.py +2 -0
  10. {calkit_python-0.21.5 → calkit_python-0.21.6}/calkit/ops.py +3 -0
  11. {calkit_python-0.21.5 → calkit_python-0.21.6}/calkit/server.py +10 -4
  12. {calkit_python-0.21.5 → calkit_python-0.21.6}/calkit/templates/core.py +2 -0
  13. {calkit_python-0.21.5 → calkit_python-0.21.6}/calkit/tests/cli/test_main.py +7 -4
  14. {calkit_python-0.21.5 → calkit_python-0.21.6}/calkit/tests/cli/test_new.py +4 -8
  15. {calkit_python-0.21.5 → calkit_python-0.21.6}/calkit/tests/test_check.py +2 -1
  16. {calkit_python-0.21.5 → calkit_python-0.21.6}/calkit/tests/test_conda.py +1 -2
  17. {calkit_python-0.21.5 → calkit_python-0.21.6}/calkit/tests/test_dvc.py +9 -1
  18. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/installation.md +8 -2
  19. {calkit_python-0.21.5 → calkit_python-0.21.6}/pyproject.toml +1 -0
  20. {calkit_python-0.21.5 → calkit_python-0.21.6}/.github/FUNDING.yml +0 -0
  21. {calkit_python-0.21.5 → calkit_python-0.21.6}/.github/workflows/docs.yml +0 -0
  22. {calkit_python-0.21.5 → calkit_python-0.21.6}/.github/workflows/format.yml +0 -0
  23. {calkit_python-0.21.5 → calkit_python-0.21.6}/.github/workflows/publish-test.yml +0 -0
  24. {calkit_python-0.21.5 → calkit_python-0.21.6}/.github/workflows/publish.yml +0 -0
  25. {calkit_python-0.21.5 → calkit_python-0.21.6}/.github/workflows/test.yml +0 -0
  26. {calkit_python-0.21.5 → calkit_python-0.21.6}/.gitignore +0 -0
  27. {calkit_python-0.21.5 → calkit_python-0.21.6}/.pre-commit-config.yaml +0 -0
  28. {calkit_python-0.21.5 → calkit_python-0.21.6}/CONTRIBUTING.md +0 -0
  29. {calkit_python-0.21.5 → calkit_python-0.21.6}/LICENSE +0 -0
  30. {calkit_python-0.21.5 → calkit_python-0.21.6}/Makefile +0 -0
  31. {calkit_python-0.21.5 → calkit_python-0.21.6}/calkit/__main__.py +0 -0
  32. {calkit_python-0.21.5 → calkit_python-0.21.6}/calkit/calc.py +0 -0
  33. {calkit_python-0.21.5 → calkit_python-0.21.6}/calkit/check.py +0 -0
  34. {calkit_python-0.21.5 → calkit_python-0.21.6}/calkit/cli/__init__.py +0 -0
  35. {calkit_python-0.21.5 → calkit_python-0.21.6}/calkit/cli/check.py +0 -0
  36. {calkit_python-0.21.5 → calkit_python-0.21.6}/calkit/cli/cloud.py +0 -0
  37. {calkit_python-0.21.5 → calkit_python-0.21.6}/calkit/cli/config.py +0 -0
  38. {calkit_python-0.21.5 → calkit_python-0.21.6}/calkit/cli/list.py +0 -0
  39. {calkit_python-0.21.5 → calkit_python-0.21.6}/calkit/cli/notebooks.py +0 -0
  40. {calkit_python-0.21.5 → calkit_python-0.21.6}/calkit/cli/office.py +0 -0
  41. {calkit_python-0.21.5 → calkit_python-0.21.6}/calkit/cli/update.py +0 -0
  42. {calkit_python-0.21.5 → calkit_python-0.21.6}/calkit/cloud.py +0 -0
  43. {calkit_python-0.21.5 → calkit_python-0.21.6}/calkit/conda.py +0 -0
  44. {calkit_python-0.21.5 → calkit_python-0.21.6}/calkit/config.py +0 -0
  45. {calkit_python-0.21.5 → calkit_python-0.21.6}/calkit/core.py +0 -0
  46. {calkit_python-0.21.5 → calkit_python-0.21.6}/calkit/datasets.py +0 -0
  47. {calkit_python-0.21.5 → calkit_python-0.21.6}/calkit/docker.py +0 -0
  48. {calkit_python-0.21.5 → calkit_python-0.21.6}/calkit/git.py +0 -0
  49. {calkit_python-0.21.5 → calkit_python-0.21.6}/calkit/github.py +0 -0
  50. {calkit_python-0.21.5 → calkit_python-0.21.6}/calkit/gui.py +0 -0
  51. {calkit_python-0.21.5 → calkit_python-0.21.6}/calkit/jupyter.py +0 -0
  52. {calkit_python-0.21.5 → calkit_python-0.21.6}/calkit/models.py +0 -0
  53. {calkit_python-0.21.5 → calkit_python-0.21.6}/calkit/office.py +0 -0
  54. {calkit_python-0.21.5 → calkit_python-0.21.6}/calkit/releases.py +0 -0
  55. {calkit_python-0.21.5 → calkit_python-0.21.6}/calkit/templates/__init__.py +0 -0
  56. {calkit_python-0.21.5 → calkit_python-0.21.6}/calkit/templates/latex/__init__.py +0 -0
  57. {calkit_python-0.21.5 → calkit_python-0.21.6}/calkit/templates/latex/article/paper.tex +0 -0
  58. {calkit_python-0.21.5 → calkit_python-0.21.6}/calkit/templates/latex/core.py +0 -0
  59. {calkit_python-0.21.5 → calkit_python-0.21.6}/calkit/templates/latex/jfm/jfm.bst +0 -0
  60. {calkit_python-0.21.5 → calkit_python-0.21.6}/calkit/templates/latex/jfm/jfm.cls +0 -0
  61. {calkit_python-0.21.5 → calkit_python-0.21.6}/calkit/templates/latex/jfm/lineno-FLM.sty +0 -0
  62. {calkit_python-0.21.5 → calkit_python-0.21.6}/calkit/templates/latex/jfm/paper.tex +0 -0
  63. {calkit_python-0.21.5 → calkit_python-0.21.6}/calkit/templates/latex/jfm/upmath.sty +0 -0
  64. {calkit_python-0.21.5 → calkit_python-0.21.6}/calkit/tests/__init__.py +0 -0
  65. {calkit_python-0.21.5 → calkit_python-0.21.6}/calkit/tests/cli/__init__.py +0 -0
  66. {calkit_python-0.21.5 → calkit_python-0.21.6}/calkit/tests/cli/test_list.py +0 -0
  67. {calkit_python-0.21.5 → calkit_python-0.21.6}/calkit/tests/test_calc.py +0 -0
  68. {calkit_python-0.21.5 → calkit_python-0.21.6}/calkit/tests/test_core.py +0 -0
  69. {calkit_python-0.21.5 → calkit_python-0.21.6}/calkit/tests/test_jupyter.py +0 -0
  70. {calkit_python-0.21.5 → calkit_python-0.21.6}/calkit/tests/test_magics.py +0 -0
  71. {calkit_python-0.21.5 → calkit_python-0.21.6}/calkit/tests/test_templates.py +0 -0
  72. {calkit_python-0.21.5 → calkit_python-0.21.6}/calkit/zenodo.py +0 -0
  73. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/CNAME +0 -0
  74. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/apps.md +0 -0
  75. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/calculations.md +0 -0
  76. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/calkit-yaml.md +0 -0
  77. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/cli-reference.md +0 -0
  78. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/cloud-integration.md +0 -0
  79. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/datasets.md +0 -0
  80. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/environments.md +0 -0
  81. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/examples.md +0 -0
  82. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/help.md +0 -0
  83. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/img/c-to-the-k-white.svg +0 -0
  84. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/img/calkit-no-bg.png +0 -0
  85. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/img/connect-zenodo.png +0 -0
  86. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/index.md +0 -0
  87. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/local-server.md +0 -0
  88. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/pipeline/index.md +0 -0
  89. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/pipeline/manual-steps.md +0 -0
  90. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/references.md +0 -0
  91. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/releases.md +0 -0
  92. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/tutorials/adding-latex-pub-docker.md +0 -0
  93. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/tutorials/conda-envs.md +0 -0
  94. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/tutorials/existing-project.md +0 -0
  95. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/tutorials/first-project.md +0 -0
  96. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/tutorials/img/latex-codespaces/building-codespace.png +0 -0
  97. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/tutorials/img/latex-codespaces/codespaces-secrets-2.png +0 -0
  98. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/tutorials/img/latex-codespaces/editor-split.png +0 -0
  99. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/tutorials/img/latex-codespaces/go-to-linked-code.png +0 -0
  100. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/tutorials/img/latex-codespaces/issue-from-selection.png +0 -0
  101. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/tutorials/img/latex-codespaces/new-project.png +0 -0
  102. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/tutorials/img/latex-codespaces/new-pub-2.png +0 -0
  103. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/tutorials/img/latex-codespaces/new-token.png +0 -0
  104. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/tutorials/img/latex-codespaces/paper.tex.png +0 -0
  105. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/tutorials/img/latex-codespaces/project-home-3.png +0 -0
  106. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/tutorials/img/latex-codespaces/push.png +0 -0
  107. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/tutorials/img/latex-codespaces/stage.png +0 -0
  108. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/tutorials/img/office/anakin-excel.jpg +0 -0
  109. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/tutorials/img/office/chart-more-rows.png +0 -0
  110. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/tutorials/img/office/create-project.png +0 -0
  111. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/tutorials/img/office/elsevier-research-data-guidelines.png +0 -0
  112. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/tutorials/img/office/excel-chart.png +0 -0
  113. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/tutorials/img/office/excel-data.png +0 -0
  114. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/tutorials/img/office/insert-link-to-file.png +0 -0
  115. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/tutorials/img/office/needs-clone.png +0 -0
  116. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/tutorials/img/office/new-stage.png +0 -0
  117. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/tutorials/img/office/phd-comics-version-control.webp +0 -0
  118. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/tutorials/img/office/pipeline-out-of-date.png +0 -0
  119. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/tutorials/img/office/status-more-rows.png +0 -0
  120. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/tutorials/img/office/uncommitted-changes.png +0 -0
  121. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/tutorials/img/office/untracked-data.png +0 -0
  122. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/tutorials/img/office/updated-publication.png +0 -0
  123. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/tutorials/img/office/word-to-pdf-stage-2.png +0 -0
  124. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/tutorials/img/office/workflow-page.png +0 -0
  125. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/tutorials/img/openfoam/clone.png +0 -0
  126. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/tutorials/img/openfoam/create-project.png +0 -0
  127. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/tutorials/img/openfoam/datasets-page.png +0 -0
  128. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/tutorials/img/openfoam/figure-on-website-updated.png +0 -0
  129. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/tutorials/img/openfoam/figure-on-website.png +0 -0
  130. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/tutorials/img/openfoam/new-token.png +0 -0
  131. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/tutorials/img/openfoam/reclone.png +0 -0
  132. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/tutorials/img/openfoam/status-after-import-dataset.png +0 -0
  133. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/tutorials/img/run-proc.png +0 -0
  134. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/tutorials/index.md +0 -0
  135. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/tutorials/latex-codespaces.md +0 -0
  136. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/tutorials/matlab.md +0 -0
  137. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/tutorials/notebook-pipeline.md +0 -0
  138. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/tutorials/office.md +0 -0
  139. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/tutorials/openfoam.md +0 -0
  140. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/tutorials/procedures.md +0 -0
  141. {calkit_python-0.21.5 → calkit_python-0.21.6}/docs/version-control.md +0 -0
  142. {calkit_python-0.21.5 → calkit_python-0.21.6}/mkdocs.yml +0 -0
  143. {calkit_python-0.21.5 → calkit_python-0.21.6}/test/pipeline.ipynb +0 -0
  144. {calkit_python-0.21.5 → calkit_python-0.21.6}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: calkit-python
3
- Version: 0.21.5
3
+ Version: 0.21.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
@@ -73,9 +73,15 @@ If you want to use [Docker](https://docker.com) containers,
73
73
  which is typically a good idea,
74
74
  that should also be installed.
75
75
  For Python, we recommend
76
- [Miniforge](https://conda-forge.org/miniforge/).
76
+ [uv](https://docs.astral.sh/uv/).
77
77
 
78
- After Python is installed, run:
78
+ With uv installed, install Calkit with:
79
+
80
+ ```sh
81
+ uv tool install calkit-python
82
+ ```
83
+
84
+ Alternatively, but less ideally, you can install with your system Python:
79
85
 
80
86
  ```sh
81
87
  pip install calkit-python
@@ -35,9 +35,15 @@ If you want to use [Docker](https://docker.com) containers,
35
35
  which is typically a good idea,
36
36
  that should also be installed.
37
37
  For Python, we recommend
38
- [Miniforge](https://conda-forge.org/miniforge/).
38
+ [uv](https://docs.astral.sh/uv/).
39
39
 
40
- After Python is installed, run:
40
+ With uv installed, install Calkit with:
41
+
42
+ ```sh
43
+ uv tool install calkit-python
44
+ ```
45
+
46
+ Alternatively, but less ideally, you can install with your system Python:
41
47
 
42
48
  ```sh
43
49
  pip install calkit-python
@@ -1,4 +1,4 @@
1
- __version__ = "0.21.5"
1
+ __version__ = "0.21.6"
2
2
 
3
3
  from .core import *
4
4
  from . import git
@@ -1,5 +1,7 @@
1
1
  """Core CLI functionality."""
2
2
 
3
+ from __future__ import annotations
4
+
3
5
  import os
4
6
  import subprocess
5
7
 
@@ -5,6 +5,7 @@ from __future__ import annotations
5
5
  import base64
6
6
  import os
7
7
  import subprocess
8
+ import sys
8
9
  from copy import deepcopy
9
10
  from typing import Annotated
10
11
 
@@ -204,7 +205,7 @@ def import_dataset(
204
205
  if not no_dvc_pull and dvc_import is not None:
205
206
  # Run dvc pull
206
207
  typer.echo("Running dvc pull")
207
- subprocess.call(["dvc", "pull", dvc_fpath])
208
+ subprocess.call([sys.executable, "-m", "dvc", "pull", dvc_fpath])
208
209
 
209
210
 
210
211
  @import_app.command(name="environment")
@@ -122,12 +122,14 @@ def init(
122
122
  ):
123
123
  """Initialize the current working directory."""
124
124
  subprocess.run(["git", "init"])
125
- dvc_cmd = ["dvc", "init"]
125
+ dvc_cmd = [sys.executable, "-m", "dvc", "init"]
126
126
  if force:
127
127
  dvc_cmd.append("-f")
128
128
  subprocess.run(dvc_cmd)
129
129
  # Ensure autostage is enabled for DVC
130
- subprocess.call(["dvc", "config", "core.autostage", "true"])
130
+ subprocess.call(
131
+ [sys.executable, "-m", "dvc", "config", "core.autostage", "true"]
132
+ )
131
133
  # Commit the newly created .dvc directory
132
134
  repo = git.Repo()
133
135
  repo.git.add(".dvc")
@@ -214,7 +216,7 @@ def clone(
214
216
  # DVC pull
215
217
  if not no_dvc_pull:
216
218
  try:
217
- subprocess.check_call(["dvc", "pull"])
219
+ subprocess.check_call([sys.executable, "-m", "dvc", "pull"])
218
220
  except subprocess.CalledProcessError:
219
221
  raise_error("Failed to pull from DVC remote(s)")
220
222
 
@@ -243,10 +245,10 @@ def get_status():
243
245
  run_cmd(["git", "status"])
244
246
  typer.echo()
245
247
  print_sep("Data (DVC)")
246
- run_cmd(["dvc", "data", "status"])
248
+ run_cmd([sys.executable, "-m", "dvc", "data", "status"])
247
249
  typer.echo()
248
250
  print_sep("Pipeline (DVC)")
249
- run_cmd(["dvc", "status"])
251
+ run_cmd([sys.executable, "-m", "dvc", "status"])
250
252
 
251
253
 
252
254
  @app.command(name="diff")
@@ -255,7 +257,7 @@ def diff():
255
257
  print_sep("Code (Git)")
256
258
  run_cmd(["git", "diff"])
257
259
  print_sep("Pipeline (DVC)")
258
- run_cmd(["dvc", "diff"])
260
+ run_cmd([sys.executable, "-m", "dvc", "diff"])
259
261
 
260
262
 
261
263
  @app.command(name="add")
@@ -331,7 +333,9 @@ def add(
331
333
  warn("DVC not initialized yet; initializing")
332
334
  dvc_repo = dvc.repo.Repo.init()
333
335
  # Ensure autostage is enabled for DVC
334
- subprocess.call(["dvc", "config", "core.autostage", "true"])
336
+ subprocess.call(
337
+ [sys.executable, "-m", "dvc", "config", "core.autostage", "true"]
338
+ )
335
339
  subprocess.call(["git", "add", ".dvc/config"])
336
340
  dvc_paths = calkit.dvc.list_paths()
337
341
  untracked_git_files = repo.untracked_files
@@ -393,15 +397,15 @@ def add(
393
397
  typer.echo(
394
398
  f"Adding {path} to DVC since it's already tracked with DVC"
395
399
  )
396
- subprocess.call(["dvc", "add", path])
400
+ subprocess.call([sys.executable, "-m", "dvc", "add", path])
397
401
  elif os.path.splitext(path)[-1] in DVC_EXTENSIONS:
398
402
  typer.echo(f"Adding {path} to DVC per its extension")
399
- subprocess.call(["dvc", "add", path])
403
+ subprocess.call([sys.executable, "-m", "dvc", "add", path])
400
404
  elif calkit.get_size(path) > DVC_SIZE_THRESH_BYTES:
401
405
  typer.echo(
402
406
  f"Adding {path} to DVC since it's greater than 1 MB"
403
407
  )
404
- subprocess.call(["dvc", "add", path])
408
+ subprocess.call([sys.executable, "-m", "dvc", "add", path])
405
409
  else:
406
410
  typer.echo(f"Adding {path} to Git")
407
411
  subprocess.call(["git", "add", path])
@@ -561,7 +565,7 @@ def pull(
561
565
  typer.echo(f"Checking authentication for DVC remote: {name}")
562
566
  calkit.dvc.set_remote_auth(remote_name=name)
563
567
  try:
564
- subprocess.check_call(["dvc", "pull"])
568
+ subprocess.check_call([sys.executable, "-m", "dvc", "pull"])
565
569
  except subprocess.CalledProcessError:
566
570
  raise_error("DVC pull failed")
567
571
 
@@ -589,7 +593,7 @@ def push(
589
593
  )
590
594
  calkit.dvc.set_remote_auth(remote_name=name)
591
595
  try:
592
- subprocess.check_call(["dvc", "push"])
596
+ subprocess.check_call([sys.executable, "-m", "dvc", "push"])
593
597
  except subprocess.CalledProcessError:
594
598
  raise_error("DVC push failed")
595
599
 
@@ -716,7 +720,7 @@ def run(
716
720
  if downstream is not None:
717
721
  args += downstream
718
722
  try:
719
- subprocess.check_call(["dvc", "repro"] + args)
723
+ subprocess.check_call([sys.executable, "-m", "dvc", "repro"] + args)
720
724
  except subprocess.CalledProcessError:
721
725
  raise_error("DVC pipeline failed")
722
726
  # Now parse stage metadata for calkit objects
@@ -1391,3 +1395,24 @@ def switch_branch(name: Annotated[str, typer.Argument(help="Branch name.")]):
1391
1395
  else:
1392
1396
  cmd = [name]
1393
1397
  repo.git.checkout(cmd)
1398
+
1399
+
1400
+ @app.command(
1401
+ name="dvc",
1402
+ add_help_option=False,
1403
+ context_settings={
1404
+ "ignore_unknown_options": True,
1405
+ "allow_extra_args": True,
1406
+ },
1407
+ )
1408
+ def call_dvc(
1409
+ ctx: typer.Context,
1410
+ help: Annotated[bool, typer.Option("-h", "--help")] = False,
1411
+ ):
1412
+ """Run a command with the DVC CLI.
1413
+
1414
+ Useful if Calkit is installed as a tool, e.g., with `uv tool` or `pipx`,
1415
+ and DVC is not installed.
1416
+ """
1417
+ process = subprocess.run([sys.executable, "-m", "dvc"] + sys.argv[2:])
1418
+ sys.exit(process.returncode)
@@ -7,6 +7,7 @@ import os
7
7
  import pathlib
8
8
  import shutil
9
9
  import subprocess
10
+ import sys
10
11
  import zipfile
11
12
  from enum import Enum
12
13
 
@@ -127,7 +128,7 @@ def new_project(
127
128
  typer.echo("Initializing DVC repository")
128
129
  try:
129
130
  subprocess.run(
130
- ["dvc", "init", "-q"],
131
+ [sys.executable, "-m", "dvc", "init", "-q"],
131
132
  cwd=abs_path,
132
133
  capture_output=True,
133
134
  check=True,
@@ -287,7 +288,16 @@ def new_project(
287
288
  "and `calkit config remote`"
288
289
  )
289
290
  subprocess.call(
290
- ["dvc", "remote", "remove", "calkit", "-q"], cwd=abs_path
291
+ [
292
+ sys.executable,
293
+ "-m",
294
+ "dvc",
295
+ "remote",
296
+ "remove",
297
+ "calkit",
298
+ "-q",
299
+ ],
300
+ cwd=abs_path,
291
301
  )
292
302
  try:
293
303
  calkit.dvc.set_remote_auth(wdir=abs_path)
@@ -308,7 +318,9 @@ def new_project(
308
318
  repo = git.Repo(abs_path)
309
319
  if not os.path.isfile(os.path.join(abs_path, ".dvc", "config")):
310
320
  typer.echo("Initializing DVC repository")
311
- subprocess.run(["dvc", "init", "-q"], cwd=abs_path)
321
+ subprocess.run(
322
+ [sys.executable, "-m", "dvc", "init", "-q"], cwd=abs_path
323
+ )
312
324
  # Create calkit.yaml file
313
325
  ck_info = calkit.load_calkit_info(wdir=abs_path)
314
326
  ck_info = dict(name=name, title=title, description=description) | ck_info
@@ -439,7 +451,7 @@ def new_figure(
439
451
  for out in outs:
440
452
  outs_cmd += ["-o", out]
441
453
  subprocess.check_call(
442
- ["dvc", "stage", "add", "-n", stage_name]
454
+ [sys.executable, "-m", "dvc", "stage", "add", "-n", stage_name]
443
455
  + (["-f"] if overwrite else [])
444
456
  + deps_cmd
445
457
  + outs_cmd
@@ -779,7 +791,7 @@ def new_dataset(
779
791
  for out in outs:
780
792
  outs_cmd += ["-o", out]
781
793
  subprocess.check_call(
782
- ["dvc", "stage", "add", "-n", stage_name]
794
+ [sys.executable, "-m", "dvc", "stage", "add", "-n", stage_name]
783
795
  + (["-f"] if overwrite else [])
784
796
  + deps_cmd
785
797
  + outs_cmd
@@ -1486,7 +1498,7 @@ def new_stage(
1486
1498
  cmd += f"zsh {target}"
1487
1499
  elif kind.value == "r-script":
1488
1500
  cmd += f"Rscript {target}"
1489
- add_cmd = ["dvc", "stage", "add", "-n", name]
1501
+ add_cmd = [sys.executable, "-m", "dvc", "stage", "add", "-n", name]
1490
1502
  for dep in [target] + deps:
1491
1503
  add_cmd += ["-d", dep]
1492
1504
  for out in outs:
@@ -5,6 +5,7 @@ from __future__ import annotations
5
5
  import logging
6
6
  import os
7
7
  import subprocess
8
+ import sys
8
9
 
9
10
  import dvc.repo
10
11
  import git
@@ -40,11 +41,30 @@ def configure_remote(wdir: str = None):
40
41
  base_url = calkit.cloud.get_base_url()
41
42
  remote_url = f"{base_url}/projects/{project_name}/dvc"
42
43
  subprocess.check_call(
43
- ["dvc", "remote", "add", "-d", "-f", get_app_name(), remote_url],
44
+ [
45
+ sys.executable,
46
+ "-m",
47
+ "dvc",
48
+ "remote",
49
+ "add",
50
+ "-d",
51
+ "-f",
52
+ get_app_name(),
53
+ remote_url,
54
+ ],
44
55
  cwd=wdir,
45
56
  )
46
57
  subprocess.check_call(
47
- ["dvc", "remote", "modify", get_app_name(), "auth", "custom"],
58
+ [
59
+ sys.executable,
60
+ "-m",
61
+ "dvc",
62
+ "remote",
63
+ "modify",
64
+ get_app_name(),
65
+ "auth",
66
+ "custom",
67
+ ],
48
68
  cwd=wdir,
49
69
  )
50
70
 
@@ -95,8 +115,30 @@ def add_external_remote(owner_name: str, project_name: str) -> dict:
95
115
  base_url = calkit.cloud.get_base_url()
96
116
  remote_url = f"{base_url}/projects/{owner_name}/{project_name}/dvc"
97
117
  remote_name = f"{get_app_name()}:{owner_name}/{project_name}"
98
- subprocess.call(["dvc", "remote", "add", "-f", remote_name, remote_url])
99
- subprocess.call(["dvc", "remote", "modify", remote_name, "auth", "custom"])
118
+ subprocess.call(
119
+ [
120
+ sys.executable,
121
+ "-m",
122
+ "dvc",
123
+ "remote",
124
+ "add",
125
+ "-f",
126
+ remote_name,
127
+ remote_url,
128
+ ]
129
+ )
130
+ subprocess.call(
131
+ [
132
+ sys.executable,
133
+ "-m",
134
+ "dvc",
135
+ "remote",
136
+ "modify",
137
+ remote_name,
138
+ "auth",
139
+ "custom",
140
+ ]
141
+ )
100
142
  set_remote_auth(remote_name)
101
143
  return {"name": remote_name, "url": remote_url}
102
144
 
@@ -114,7 +156,9 @@ def get_remotes(wdir: str = None) -> dict[str, str]:
114
156
  value.
115
157
  """
116
158
  out = (
117
- subprocess.check_output(["dvc", "remote", "list"], cwd=wdir)
159
+ subprocess.check_output(
160
+ [sys.executable, "-m", "dvc", "remote", "list"], cwd=wdir
161
+ )
118
162
  .decode()
119
163
  .strip()
120
164
  )
@@ -1,5 +1,7 @@
1
1
  """IPython magics."""
2
2
 
3
+ from __future__ import annotations
4
+
3
5
  import ast
4
6
  import os
5
7
  import pathlib
@@ -4,7 +4,10 @@ An op is a process that runs outside the pipeline, e.g., for continuous data
4
4
  collection, a task run on a schedule, or a fixed number of iterations.
5
5
  """
6
6
 
7
+ from __future__ import annotations
8
+
7
9
  from typing import Literal
10
+
8
11
  from pydantic import BaseModel
9
12
 
10
13
 
@@ -7,6 +7,7 @@ import os
7
7
  import platform
8
8
  import re
9
9
  import subprocess
10
+ import sys
10
11
  from typing import Literal
11
12
 
12
13
  import dvc
@@ -218,7 +219,9 @@ def dvc_pull(owner_name: str, project_name: str) -> Message:
218
219
  logger.info(f"Looking for project {owner_name}/{project_name}")
219
220
  project = get_local_project(owner_name, project_name)
220
221
  logger.info(f"Found project at {project.wdir}")
221
- subprocess.check_call(["dvc", "pull"], cwd=project.wdir)
222
+ subprocess.check_call(
223
+ [sys.executable, "-m", "dvc", "pull"], cwd=project.wdir
224
+ )
222
225
  return Message(message="Success!")
223
226
 
224
227
 
@@ -227,7 +230,9 @@ def dvc_push(owner_name: str, project_name: str) -> Message:
227
230
  logger.info(f"Looking for project {owner_name}/{project_name}")
228
231
  project = get_local_project(owner_name, project_name)
229
232
  logger.info(f"Found project at {project.wdir}")
230
- subprocess.check_call(["dvc", "push"], cwd=project.wdir)
233
+ subprocess.check_call(
234
+ [sys.executable, "-m", "dvc", "push"], cwd=project.wdir
235
+ )
231
236
  return Message(message="Success!")
232
237
 
233
238
 
@@ -453,7 +458,8 @@ def discard_changes(owner_name: str, project_name: str) -> Message:
453
458
  for path in changed:
454
459
  logger.info(f"Checking out {path} with DVC")
455
460
  subprocess.check_call(
456
- ["dvc", "checkout", path, "--force"], cwd=project.wdir
461
+ [sys.executable, "-m", "dvc", "checkout", path, "--force"],
462
+ cwd=project.wdir,
457
463
  )
458
464
  except dvc.config.ConfigError:
459
465
  pass
@@ -496,7 +502,7 @@ def get_pipeline(owner_name: str, project_name: str) -> Pipeline:
496
502
  raw_yaml = f.read()
497
503
  pipeline = calkit.ryaml.load(raw_yaml)
498
504
  mermaid = subprocess.check_output(
499
- ["dvc", "dag", "--mermaid"], cwd=project.wdir
505
+ [sys.executable, "-m", "dvc", "dag", "--mermaid"], cwd=project.wdir
500
506
  ).decode()
501
507
  return Pipeline(
502
508
  raw_yaml=raw_yaml,
@@ -1,5 +1,7 @@
1
1
  """Core functionality for working with templates."""
2
2
 
3
+ from __future__ import annotations
4
+
3
5
  import os
4
6
  import shutil
5
7
  from typing import Literal
@@ -14,8 +14,7 @@ from calkit.cli.main import _to_shell_cmd
14
14
 
15
15
 
16
16
  def test_run_in_env(tmp_dir):
17
- subprocess.check_call("git init", shell=True)
18
- subprocess.check_call("dvc init", shell=True)
17
+ subprocess.check_call("calkit init", shell=True)
19
18
  # First create a new Docker environment for this bare project
20
19
  subprocess.check_call(
21
20
  "calkit new docker-env "
@@ -110,8 +109,7 @@ def test_run_in_env(tmp_dir):
110
109
 
111
110
 
112
111
  def test_run_in_venv(tmp_dir):
113
- subprocess.check_call("git init", shell=True)
114
- subprocess.check_call("dvc init", shell=True)
112
+ subprocess.check_call("calkit init", shell=True)
115
113
  # Test uv venv
116
114
  subprocess.check_call(
117
115
  [
@@ -353,3 +351,8 @@ def test_save(tmp_dir):
353
351
  )
354
352
  last_commit_message = repo.head.commit.message.strip()
355
353
  assert last_commit_message == "A unique message"
354
+
355
+
356
+ def test_call_dvc():
357
+ subprocess.check_call(["calkit", "dvc", "--help"])
358
+ subprocess.check_call(["calkit", "dvc", "stage", "--help"])
@@ -10,8 +10,7 @@ import calkit
10
10
 
11
11
 
12
12
  def test_new_foreach_stage(tmp_dir):
13
- subprocess.check_call(["git", "init"])
14
- subprocess.check_call(["dvc", "init"])
13
+ subprocess.check_call(["calkit", "init"])
15
14
  subprocess.check_call(
16
15
  [
17
16
  "calkit",
@@ -54,8 +53,7 @@ def test_new_foreach_stage(tmp_dir):
54
53
 
55
54
 
56
55
  def test_new_figure(tmp_dir):
57
- subprocess.check_call(["git", "init"])
58
- subprocess.check_call(["dvc", "init"])
56
+ subprocess.check_call(["calkit", "init"])
59
57
  subprocess.check_call(
60
58
  [
61
59
  "calkit",
@@ -134,8 +132,7 @@ def test_new_figure(tmp_dir):
134
132
 
135
133
 
136
134
  def test_new_publication(tmp_dir):
137
- subprocess.check_call(["git", "init"])
138
- subprocess.check_call(["dvc", "init"])
135
+ subprocess.check_call(["calkit", "init"])
139
136
  subprocess.check_call(
140
137
  [
141
138
  "calkit",
@@ -173,8 +170,7 @@ def test_new_publication(tmp_dir):
173
170
 
174
171
 
175
172
  def test_new_uv_venv(tmp_dir):
176
- subprocess.check_call(["git", "init"])
177
- subprocess.check_call(["dvc", "init"])
173
+ subprocess.check_call(["calkit", "init"])
178
174
  subprocess.check_call(
179
175
  [
180
176
  "calkit",
@@ -2,6 +2,7 @@
2
2
 
3
3
  import os
4
4
  import subprocess
5
+ import sys
5
6
 
6
7
  from calkit.check import check_reproducibility
7
8
 
@@ -16,7 +17,7 @@ def test_check_reproducibility(tmp_path):
16
17
  assert not res.is_dvc_repo
17
18
  assert not res.has_readme
18
19
  assert "no README.md" in res.recommendation
19
- subprocess.run(["dvc", "init"])
20
+ subprocess.run([sys.executable, "-m", "dvc", "init"])
20
21
  res = check_reproducibility()
21
22
  assert res.is_dvc_repo
22
23
  assert res.n_dvc_remotes == 0
@@ -42,8 +42,7 @@ def conda_env_name():
42
42
 
43
43
 
44
44
  def test_check_env(tmp_dir, conda_env_name):
45
- subprocess.check_call(["git", "init"])
46
- subprocess.check_call(["dvc", "init"])
45
+ subprocess.check_call(["calkit", "init"])
47
46
  subprocess.check_call(
48
47
  [
49
48
  "calkit",
@@ -10,6 +10,14 @@ def test_get_remotes(tmp_dir):
10
10
  assert not calkit.dvc.get_remotes()
11
11
  subprocess.call(["dvc", "init"])
12
12
  assert not calkit.dvc.get_remotes()
13
- subprocess.call(["dvc", "remote", "add", "something", "https://sup.com"])
13
+ subprocess.call(
14
+ [
15
+ "dvc",
16
+ "remote",
17
+ "add",
18
+ "something",
19
+ "https://sup.com",
20
+ ]
21
+ )
14
22
  resp = calkit.dvc.get_remotes()
15
23
  assert resp == {"something": "https://sup.com"}
@@ -5,9 +5,15 @@ If you want to use [Docker](https://docker.com) containers,
5
5
  which is typically a good idea,
6
6
  that should also be installed.
7
7
  For Python, we recommend
8
- [Miniforge](https://conda-forge.org/miniforge/).
8
+ [uv](https://docs.astral.sh/uv/).
9
9
 
10
- After Python is installed, execute:
10
+ With uv installed, install Calkit with:
11
+
12
+ ```sh
13
+ uv tool install calkit-python
14
+ ```
15
+
16
+ Alternatively, but less ideally, you can install with your system Python:
11
17
 
12
18
  ```sh
13
19
  pip install calkit-python
@@ -93,3 +93,4 @@ show_error_codes = true
93
93
  target-version = "py39"
94
94
  line-length = 79
95
95
  fix = true
96
+ extend-select = ["I"]
File without changes
File without changes
File without changes