calkit-python 0.17.2__tar.gz → 0.17.3__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 (130) hide show
  1. {calkit_python-0.17.2 → calkit_python-0.17.3}/PKG-INFO +1 -1
  2. {calkit_python-0.17.2 → calkit_python-0.17.3}/calkit/__init__.py +1 -1
  3. {calkit_python-0.17.2 → calkit_python-0.17.3}/calkit/cli/main.py +54 -27
  4. {calkit_python-0.17.2 → calkit_python-0.17.3}/calkit/cli/new.py +22 -37
  5. {calkit_python-0.17.2 → calkit_python-0.17.3}/calkit/core.py +5 -0
  6. {calkit_python-0.17.2 → calkit_python-0.17.3}/calkit/tests/cli/test_main.py +20 -0
  7. {calkit_python-0.17.2 → calkit_python-0.17.3}/calkit/tests/cli/test_new.py +16 -0
  8. {calkit_python-0.17.2 → calkit_python-0.17.3}/calkit/tests/test_conda.py +14 -12
  9. {calkit_python-0.17.2 → calkit_python-0.17.3}/calkit/tests/test_core.py +5 -0
  10. {calkit_python-0.17.2 → calkit_python-0.17.3}/docs/calkit-yaml.md +17 -0
  11. calkit_python-0.17.3/docs/local-server.md +23 -0
  12. {calkit_python-0.17.2 → calkit_python-0.17.3}/docs/version-control.md +2 -0
  13. {calkit_python-0.17.2 → calkit_python-0.17.3}/mkdocs.yml +1 -0
  14. {calkit_python-0.17.2 → calkit_python-0.17.3}/.github/FUNDING.yml +0 -0
  15. {calkit_python-0.17.2 → calkit_python-0.17.3}/.github/workflows/docs.yml +0 -0
  16. {calkit_python-0.17.2 → calkit_python-0.17.3}/.github/workflows/publish-test.yml +0 -0
  17. {calkit_python-0.17.2 → calkit_python-0.17.3}/.github/workflows/publish.yml +0 -0
  18. {calkit_python-0.17.2 → calkit_python-0.17.3}/.gitignore +0 -0
  19. {calkit_python-0.17.2 → calkit_python-0.17.3}/LICENSE +0 -0
  20. {calkit_python-0.17.2 → calkit_python-0.17.3}/README.md +0 -0
  21. {calkit_python-0.17.2 → calkit_python-0.17.3}/calkit/__main__.py +0 -0
  22. {calkit_python-0.17.2 → calkit_python-0.17.3}/calkit/calc.py +0 -0
  23. {calkit_python-0.17.2 → calkit_python-0.17.3}/calkit/check.py +0 -0
  24. {calkit_python-0.17.2 → calkit_python-0.17.3}/calkit/cli/__init__.py +0 -0
  25. {calkit_python-0.17.2 → calkit_python-0.17.3}/calkit/cli/check.py +0 -0
  26. {calkit_python-0.17.2 → calkit_python-0.17.3}/calkit/cli/config.py +0 -0
  27. {calkit_python-0.17.2 → calkit_python-0.17.3}/calkit/cli/core.py +0 -0
  28. {calkit_python-0.17.2 → calkit_python-0.17.3}/calkit/cli/import_.py +0 -0
  29. {calkit_python-0.17.2 → calkit_python-0.17.3}/calkit/cli/list.py +0 -0
  30. {calkit_python-0.17.2 → calkit_python-0.17.3}/calkit/cli/notebooks.py +0 -0
  31. {calkit_python-0.17.2 → calkit_python-0.17.3}/calkit/cli/office.py +0 -0
  32. {calkit_python-0.17.2 → calkit_python-0.17.3}/calkit/cli/update.py +0 -0
  33. {calkit_python-0.17.2 → calkit_python-0.17.3}/calkit/cloud.py +0 -0
  34. {calkit_python-0.17.2 → calkit_python-0.17.3}/calkit/conda.py +0 -0
  35. {calkit_python-0.17.2 → calkit_python-0.17.3}/calkit/config.py +0 -0
  36. {calkit_python-0.17.2 → calkit_python-0.17.3}/calkit/datasets.py +0 -0
  37. {calkit_python-0.17.2 → calkit_python-0.17.3}/calkit/docker.py +0 -0
  38. {calkit_python-0.17.2 → calkit_python-0.17.3}/calkit/dvc.py +0 -0
  39. {calkit_python-0.17.2 → calkit_python-0.17.3}/calkit/git.py +0 -0
  40. {calkit_python-0.17.2 → calkit_python-0.17.3}/calkit/gui.py +0 -0
  41. {calkit_python-0.17.2 → calkit_python-0.17.3}/calkit/jupyter.py +0 -0
  42. {calkit_python-0.17.2 → calkit_python-0.17.3}/calkit/magics.py +0 -0
  43. {calkit_python-0.17.2 → calkit_python-0.17.3}/calkit/models.py +0 -0
  44. {calkit_python-0.17.2 → calkit_python-0.17.3}/calkit/office.py +0 -0
  45. {calkit_python-0.17.2 → calkit_python-0.17.3}/calkit/ops.py +0 -0
  46. {calkit_python-0.17.2 → calkit_python-0.17.3}/calkit/server.py +0 -0
  47. {calkit_python-0.17.2 → calkit_python-0.17.3}/calkit/templates/__init__.py +0 -0
  48. {calkit_python-0.17.2 → calkit_python-0.17.3}/calkit/templates/core.py +0 -0
  49. {calkit_python-0.17.2 → calkit_python-0.17.3}/calkit/templates/latex/__init__.py +0 -0
  50. {calkit_python-0.17.2 → calkit_python-0.17.3}/calkit/templates/latex/article/paper.tex +0 -0
  51. {calkit_python-0.17.2 → calkit_python-0.17.3}/calkit/templates/latex/core.py +0 -0
  52. {calkit_python-0.17.2 → calkit_python-0.17.3}/calkit/templates/latex/jfm/jfm.bst +0 -0
  53. {calkit_python-0.17.2 → calkit_python-0.17.3}/calkit/templates/latex/jfm/jfm.cls +0 -0
  54. {calkit_python-0.17.2 → calkit_python-0.17.3}/calkit/templates/latex/jfm/lineno-FLM.sty +0 -0
  55. {calkit_python-0.17.2 → calkit_python-0.17.3}/calkit/templates/latex/jfm/paper.tex +0 -0
  56. {calkit_python-0.17.2 → calkit_python-0.17.3}/calkit/templates/latex/jfm/upmath.sty +0 -0
  57. {calkit_python-0.17.2 → calkit_python-0.17.3}/calkit/tests/__init__.py +0 -0
  58. {calkit_python-0.17.2 → calkit_python-0.17.3}/calkit/tests/cli/__init__.py +0 -0
  59. {calkit_python-0.17.2 → calkit_python-0.17.3}/calkit/tests/cli/test_list.py +0 -0
  60. {calkit_python-0.17.2 → calkit_python-0.17.3}/calkit/tests/test_calc.py +0 -0
  61. {calkit_python-0.17.2 → calkit_python-0.17.3}/calkit/tests/test_check.py +0 -0
  62. {calkit_python-0.17.2 → calkit_python-0.17.3}/calkit/tests/test_dvc.py +0 -0
  63. {calkit_python-0.17.2 → calkit_python-0.17.3}/calkit/tests/test_jupyter.py +0 -0
  64. {calkit_python-0.17.2 → calkit_python-0.17.3}/calkit/tests/test_magics.py +0 -0
  65. {calkit_python-0.17.2 → calkit_python-0.17.3}/calkit/tests/test_templates.py +0 -0
  66. {calkit_python-0.17.2 → calkit_python-0.17.3}/docs/CNAME +0 -0
  67. {calkit_python-0.17.2 → calkit_python-0.17.3}/docs/apps.md +0 -0
  68. {calkit_python-0.17.2 → calkit_python-0.17.3}/docs/calculations.md +0 -0
  69. {calkit_python-0.17.2 → calkit_python-0.17.3}/docs/cli-reference.md +0 -0
  70. {calkit_python-0.17.2 → calkit_python-0.17.3}/docs/cloud-integration.md +0 -0
  71. {calkit_python-0.17.2 → calkit_python-0.17.3}/docs/environments.md +0 -0
  72. {calkit_python-0.17.2 → calkit_python-0.17.3}/docs/examples.md +0 -0
  73. {calkit_python-0.17.2 → calkit_python-0.17.3}/docs/help.md +0 -0
  74. {calkit_python-0.17.2 → calkit_python-0.17.3}/docs/img/c-to-the-k-white.svg +0 -0
  75. {calkit_python-0.17.2 → calkit_python-0.17.3}/docs/img/calkit-no-bg.png +0 -0
  76. {calkit_python-0.17.2 → calkit_python-0.17.3}/docs/index.md +0 -0
  77. {calkit_python-0.17.2 → calkit_python-0.17.3}/docs/installation.md +0 -0
  78. {calkit_python-0.17.2 → calkit_python-0.17.3}/docs/pipeline/index.md +0 -0
  79. {calkit_python-0.17.2 → calkit_python-0.17.3}/docs/pipeline/manual-steps.md +0 -0
  80. {calkit_python-0.17.2 → calkit_python-0.17.3}/docs/references.md +0 -0
  81. {calkit_python-0.17.2 → calkit_python-0.17.3}/docs/tutorials/adding-latex-pub-docker.md +0 -0
  82. {calkit_python-0.17.2 → calkit_python-0.17.3}/docs/tutorials/conda-envs.md +0 -0
  83. {calkit_python-0.17.2 → calkit_python-0.17.3}/docs/tutorials/first-project.md +0 -0
  84. {calkit_python-0.17.2 → calkit_python-0.17.3}/docs/tutorials/img/latex-codespaces/building-codespace.png +0 -0
  85. {calkit_python-0.17.2 → calkit_python-0.17.3}/docs/tutorials/img/latex-codespaces/codespaces-secrets-2.png +0 -0
  86. {calkit_python-0.17.2 → calkit_python-0.17.3}/docs/tutorials/img/latex-codespaces/editor-split.png +0 -0
  87. {calkit_python-0.17.2 → calkit_python-0.17.3}/docs/tutorials/img/latex-codespaces/go-to-linked-code.png +0 -0
  88. {calkit_python-0.17.2 → calkit_python-0.17.3}/docs/tutorials/img/latex-codespaces/issue-from-selection.png +0 -0
  89. {calkit_python-0.17.2 → calkit_python-0.17.3}/docs/tutorials/img/latex-codespaces/new-project.png +0 -0
  90. {calkit_python-0.17.2 → calkit_python-0.17.3}/docs/tutorials/img/latex-codespaces/new-pub-2.png +0 -0
  91. {calkit_python-0.17.2 → calkit_python-0.17.3}/docs/tutorials/img/latex-codespaces/new-token.png +0 -0
  92. {calkit_python-0.17.2 → calkit_python-0.17.3}/docs/tutorials/img/latex-codespaces/paper.tex.png +0 -0
  93. {calkit_python-0.17.2 → calkit_python-0.17.3}/docs/tutorials/img/latex-codespaces/project-home-3.png +0 -0
  94. {calkit_python-0.17.2 → calkit_python-0.17.3}/docs/tutorials/img/latex-codespaces/push.png +0 -0
  95. {calkit_python-0.17.2 → calkit_python-0.17.3}/docs/tutorials/img/latex-codespaces/stage.png +0 -0
  96. {calkit_python-0.17.2 → calkit_python-0.17.3}/docs/tutorials/img/office/anakin-excel.jpg +0 -0
  97. {calkit_python-0.17.2 → calkit_python-0.17.3}/docs/tutorials/img/office/chart-more-rows.png +0 -0
  98. {calkit_python-0.17.2 → calkit_python-0.17.3}/docs/tutorials/img/office/create-project.png +0 -0
  99. {calkit_python-0.17.2 → calkit_python-0.17.3}/docs/tutorials/img/office/elsevier-research-data-guidelines.png +0 -0
  100. {calkit_python-0.17.2 → calkit_python-0.17.3}/docs/tutorials/img/office/excel-chart.png +0 -0
  101. {calkit_python-0.17.2 → calkit_python-0.17.3}/docs/tutorials/img/office/excel-data.png +0 -0
  102. {calkit_python-0.17.2 → calkit_python-0.17.3}/docs/tutorials/img/office/insert-link-to-file.png +0 -0
  103. {calkit_python-0.17.2 → calkit_python-0.17.3}/docs/tutorials/img/office/needs-clone.png +0 -0
  104. {calkit_python-0.17.2 → calkit_python-0.17.3}/docs/tutorials/img/office/new-stage.png +0 -0
  105. {calkit_python-0.17.2 → calkit_python-0.17.3}/docs/tutorials/img/office/phd-comics-version-control.webp +0 -0
  106. {calkit_python-0.17.2 → calkit_python-0.17.3}/docs/tutorials/img/office/pipeline-out-of-date.png +0 -0
  107. {calkit_python-0.17.2 → calkit_python-0.17.3}/docs/tutorials/img/office/status-more-rows.png +0 -0
  108. {calkit_python-0.17.2 → calkit_python-0.17.3}/docs/tutorials/img/office/uncommitted-changes.png +0 -0
  109. {calkit_python-0.17.2 → calkit_python-0.17.3}/docs/tutorials/img/office/untracked-data.png +0 -0
  110. {calkit_python-0.17.2 → calkit_python-0.17.3}/docs/tutorials/img/office/updated-publication.png +0 -0
  111. {calkit_python-0.17.2 → calkit_python-0.17.3}/docs/tutorials/img/office/word-to-pdf-stage-2.png +0 -0
  112. {calkit_python-0.17.2 → calkit_python-0.17.3}/docs/tutorials/img/office/workflow-page.png +0 -0
  113. {calkit_python-0.17.2 → calkit_python-0.17.3}/docs/tutorials/img/openfoam/clone.png +0 -0
  114. {calkit_python-0.17.2 → calkit_python-0.17.3}/docs/tutorials/img/openfoam/create-project.png +0 -0
  115. {calkit_python-0.17.2 → calkit_python-0.17.3}/docs/tutorials/img/openfoam/datasets-page.png +0 -0
  116. {calkit_python-0.17.2 → calkit_python-0.17.3}/docs/tutorials/img/openfoam/figure-on-website-updated.png +0 -0
  117. {calkit_python-0.17.2 → calkit_python-0.17.3}/docs/tutorials/img/openfoam/figure-on-website.png +0 -0
  118. {calkit_python-0.17.2 → calkit_python-0.17.3}/docs/tutorials/img/openfoam/new-token.png +0 -0
  119. {calkit_python-0.17.2 → calkit_python-0.17.3}/docs/tutorials/img/openfoam/reclone.png +0 -0
  120. {calkit_python-0.17.2 → calkit_python-0.17.3}/docs/tutorials/img/openfoam/status-after-import-dataset.png +0 -0
  121. {calkit_python-0.17.2 → calkit_python-0.17.3}/docs/tutorials/img/run-proc.png +0 -0
  122. {calkit_python-0.17.2 → calkit_python-0.17.3}/docs/tutorials/latex-codespaces.md +0 -0
  123. {calkit_python-0.17.2 → calkit_python-0.17.3}/docs/tutorials/matlab.md +0 -0
  124. {calkit_python-0.17.2 → calkit_python-0.17.3}/docs/tutorials/notebook-pipeline.md +0 -0
  125. {calkit_python-0.17.2 → calkit_python-0.17.3}/docs/tutorials/office.md +0 -0
  126. {calkit_python-0.17.2 → calkit_python-0.17.3}/docs/tutorials/openfoam.md +0 -0
  127. {calkit_python-0.17.2 → calkit_python-0.17.3}/docs/tutorials/procedures.md +0 -0
  128. {calkit_python-0.17.2 → calkit_python-0.17.3}/pyproject.toml +0 -0
  129. {calkit_python-0.17.2 → calkit_python-0.17.3}/test/pipeline.ipynb +0 -0
  130. {calkit_python-0.17.2 → calkit_python-0.17.3}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: calkit-python
3
- Version: 0.17.2
3
+ Version: 0.17.3
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.17.2"
1
+ __version__ = "0.17.3"
2
2
 
3
3
  from .core import *
4
4
  from . import git
@@ -51,9 +51,31 @@ app.add_typer(update_app, name="update", help="Update objects.")
51
51
  app.add_typer(check_app, name="check", help="Check things.")
52
52
 
53
53
  # Constants for version control auto-ignore
54
- AUTO_IGNORE_SUFFIXES = [".DS_Store", ".env"]
54
+ AUTO_IGNORE_SUFFIXES = [".DS_Store", ".env", ".pyc"]
55
55
  AUTO_IGNORE_PATHS = [os.path.join(".dvc", "config.local")]
56
- AUTO_IGNORE_PREFIXES = [".venv"]
56
+ AUTO_IGNORE_PREFIXES = [".venv", "__pycache__"]
57
+ # Constants for version control auto-add to DVC
58
+ DVC_EXTENSIONS = [
59
+ ".png",
60
+ ".jpeg",
61
+ ".jpg",
62
+ ".gif",
63
+ ".h5",
64
+ ".parquet",
65
+ ".pickle",
66
+ ".mp4",
67
+ ".avi",
68
+ ".webm",
69
+ ".pdf",
70
+ ".xlsx",
71
+ ".docx",
72
+ ".xls",
73
+ ".doc",
74
+ ".nc",
75
+ ".nc4",
76
+ ".zarr",
77
+ ]
78
+ DVC_SIZE_THRESH_BYTES = 1_000_000
57
79
 
58
80
 
59
81
  def _to_shell_cmd(cmd: list[str]) -> str:
@@ -195,6 +217,14 @@ def add(
195
217
  help="Automatically commit and use this as a message.",
196
218
  ),
197
219
  ] = None,
220
+ auto_commit_message: Annotated[
221
+ bool,
222
+ typer.Option(
223
+ "--auto-message",
224
+ "-M",
225
+ help="Commit with an automatically-generated message.",
226
+ ),
227
+ ] = False,
198
228
  disable_auto_ignore: Annotated[
199
229
  bool, typer.Option("--no-auto-ignore", help="Disable auto-ignore.")
200
230
  ] = False,
@@ -215,6 +245,18 @@ def add(
215
245
  Note: This will enable the 'autostage' feature of DVC, automatically
216
246
  adding any .dvc files to Git when adding to DVC.
217
247
  """
248
+ if auto_commit_message:
249
+ if commit_message is not None:
250
+ raise_error(
251
+ "Commit message should not be provided if using "
252
+ "automatic message"
253
+ )
254
+ if "." in paths:
255
+ raise_error("Cannot auto-generate commit message for '.'")
256
+ if len(paths) > 1:
257
+ raise_error(
258
+ "Cannot auto-generate commit message for more than one path"
259
+ )
218
260
  if to is not None and to not in ["git", "dvc"]:
219
261
  raise_error(f"Invalid option for 'to': {to}")
220
262
  try:
@@ -239,40 +281,25 @@ def add(
239
281
  # Ensure autostage is enabled for DVC
240
282
  subprocess.call(["dvc", "config", "core.autostage", "true"])
241
283
  subprocess.call(["git", "add", ".dvc/config"])
284
+ dvc_paths = [obj.get("path") for obj in dvc_repo.ls(".", dvc_only=True)]
285
+ untracked_git_files = repo.untracked_files
286
+ if auto_commit_message:
287
+ # See if this path is in the repo already
288
+ if paths[0] in dvc_paths or repo.git.ls_files(paths[0]):
289
+ commit_message = f"Update {paths[0]}"
290
+ else:
291
+ commit_message = f"Add {paths[0]}"
242
292
  if to is not None:
243
293
  subprocess.call([to, "add"] + paths)
244
294
  else:
245
- dvc_extensions = [
246
- ".png",
247
- ".jpeg",
248
- ".jpg",
249
- ".gif",
250
- ".h5",
251
- ".parquet",
252
- ".pickle",
253
- ".mp4",
254
- ".avi",
255
- ".webm",
256
- ".pdf",
257
- ".xlsx",
258
- ".docx",
259
- ".xls",
260
- ".doc",
261
- ]
262
- dvc_size_thresh_bytes = 1_000_000
263
- dvc_paths = [
264
- obj.get("path") for obj in dvc_repo.ls(".", dvc_only=True)
265
- ]
266
295
  if "." in paths:
267
296
  paths.remove(".")
268
- # TODO: There is some copy/paste from the `save` function here
269
297
  dvc_status = dvc_repo.data_status()
270
298
  for dvc_uncommitted in dvc_status["uncommitted"].get(
271
299
  "modified", []
272
300
  ):
273
301
  typer.echo(f"Adding {dvc_uncommitted} to DVC")
274
302
  dvc_repo.commit(dvc_uncommitted, force=True)
275
- untracked_git_files = repo.untracked_files
276
303
  if not disable_auto_ignore:
277
304
  for untracked_file in untracked_git_files:
278
305
  if (
@@ -315,10 +342,10 @@ def add(
315
342
  f"Adding {path} to DVC since it's already tracked with DVC"
316
343
  )
317
344
  subprocess.call(["dvc", "add", path])
318
- elif os.path.splitext(path)[-1] in dvc_extensions:
345
+ elif os.path.splitext(path)[-1] in DVC_EXTENSIONS:
319
346
  typer.echo(f"Adding {path} to DVC per its extension")
320
347
  subprocess.call(["dvc", "add", path])
321
- elif calkit.get_size(path) > dvc_size_thresh_bytes:
348
+ elif calkit.get_size(path) > DVC_SIZE_THRESH_BYTES:
322
349
  typer.echo(
323
350
  f"Adding {path} to DVC since it's greater than 1 MB"
324
351
  )
@@ -3,7 +3,6 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import os
6
- import re
7
6
  import shutil
8
7
  import subprocess
9
8
 
@@ -109,7 +108,7 @@ def new_project(
109
108
  if os.path.isdir(abs_path) and os.listdir(abs_path):
110
109
  warn(f"{abs_path} is not empty")
111
110
  if name is None:
112
- name = re.sub(r"[-_,\.\ ]", "-", os.path.basename(abs_path).lower())
111
+ name = calkit.to_kebab_case(os.path.basename(abs_path))
113
112
  if " " in name:
114
113
  warn("Invalid name; replacing spaces with hyphens")
115
114
  name = name.replace(" ", "-")
@@ -242,8 +241,10 @@ def new_project(
242
241
  ck_info = dict(name=name, title=title, description=description) | ck_info
243
242
  with open(os.path.join(abs_path, "calkit.yaml"), "w") as f:
244
243
  ryaml.dump(ck_info, f)
244
+ repo.git.add("calkit.yaml")
245
245
  # Create dev container spec
246
246
  update_devcontainer(wdir=abs_path)
247
+ repo.git.add(".devcontainer")
247
248
  # Create README
248
249
  readme_fpath = os.path.join(abs_path, "README.md")
249
250
  if os.path.isfile(readme_fpath) and not overwrite:
@@ -257,6 +258,7 @@ def new_project(
257
258
  )
258
259
  with open(readme_fpath, "w") as f:
259
260
  f.write(readme_txt)
261
+ repo.git.add("README.md")
260
262
  if git_repo_url and not repo.remotes:
261
263
  typer.echo(f"Adding Git remote {git_repo_url}")
262
264
  repo.git.remote(["add", "origin", git_repo_url])
@@ -267,7 +269,6 @@ def new_project(
267
269
  typer.echo("Setting up Calkit Cloud DVC remote")
268
270
  calkit.dvc.configure_remote(wdir=abs_path)
269
271
  calkit.dvc.set_remote_auth(wdir=abs_path)
270
- repo.git.add(".")
271
272
  if repo.git.diff("--staged") and not no_commit:
272
273
  repo.git.commit(["-m", "Initialize Calkit project"])
273
274
  typer.echo(success_message)
@@ -916,16 +917,24 @@ def new_conda_env(
916
917
  name: Annotated[
917
918
  str, typer.Option("--name", "-n", help="Environment name.")
918
919
  ],
920
+ conda_name: Annotated[
921
+ str,
922
+ typer.Option(
923
+ "--conda-name",
924
+ help=(
925
+ "Name to use in the Conda environment file, if desired. "
926
+ "Will be automatically generated if not provided. "
927
+ "Note that these should be unique since Conda environments are "
928
+ "a system-wide collection."
929
+ ),
930
+ ),
931
+ ] = None,
919
932
  path: Annotated[
920
933
  str, typer.Option("--path", help="Environment YAML file path.")
921
934
  ] = "environment.yml",
922
935
  pip_packages: Annotated[
923
936
  list[str], typer.Option("--pip", help="Packages to install with pip.")
924
937
  ] = [],
925
- stage: Annotated[
926
- str,
927
- typer.Option("--stage", help="DVC pipeline stage name for checking."),
928
- ] = None,
929
938
  description: Annotated[
930
939
  str, typer.Option("--description", help="Description.")
931
940
  ] = None,
@@ -957,9 +966,14 @@ def new_conda_env(
957
966
  f"Environment with name {name} already exists "
958
967
  "(use -f to overwrite)"
959
968
  )
969
+ if conda_name is None:
970
+ project_name = ck_info.get("name")
971
+ if project_name is None:
972
+ project_name = os.path.basename(os.getcwd())
973
+ conda_name = calkit.to_kebab_case(project_name) + "-" + name
960
974
  # Write environment to path
961
975
  conda_env = dict(
962
- name=name, channels=["conda-forge"], dependencies=packages
976
+ name=conda_name, channels=["conda-forge"], dependencies=packages
963
977
  )
964
978
  if pip_packages:
965
979
  conda_env["dependencies"].append(dict(pip=pip_packages))
@@ -968,42 +982,13 @@ def new_conda_env(
968
982
  repo.git.add(path)
969
983
  typer.echo("Adding environment to calkit.yaml")
970
984
  env = dict(path=path, kind="conda")
971
- if stage is not None:
972
- env["stage"] = stage
973
985
  if description is not None:
974
986
  env["description"] = description
975
987
  envs[name] = env
976
988
  ck_info["environments"] = envs
977
989
  with open("calkit.yaml", "w") as f:
978
990
  ryaml.dump(ck_info, f)
979
- # If we're creating a stage, do so with DVC
980
- if stage:
981
- typer.echo(f"Creating DVC stage {stage}")
982
- if not os.path.isfile(".dvc/config"):
983
- typer.echo("Running dvc init")
984
- subprocess.check_call(["dvc", "init"])
985
- ck_cmd = f"calkit check-conda-env -f {path}"
986
- fname, ext = os.path.splitext(path)
987
- lock_path = f"{fname}-lock{ext}"
988
- subprocess.check_call(
989
- [
990
- "dvc",
991
- "stage",
992
- "add",
993
- "-f",
994
- "-n",
995
- stage,
996
- "--always-changed",
997
- "-d",
998
- path,
999
- "--outs-persist-no-cache",
1000
- lock_path,
1001
- ck_cmd,
1002
- ]
1003
- )
1004
991
  repo.git.add("calkit.yaml")
1005
- if stage:
1006
- repo.git.add("dvc.yaml")
1007
992
  if not no_commit and repo.git.diff("--staged"):
1008
993
  repo.git.commit(["-m", f"Add Conda environment {name}"])
1009
994
 
@@ -380,3 +380,8 @@ def get_size(path: str):
380
380
  if not os.path.islink(fp):
381
381
  total_size += os.path.getsize(fp)
382
382
  return total_size
383
+
384
+
385
+ def to_kebab_case(str) -> str:
386
+ """Convert a string to kebab-case."""
387
+ return re.sub(r"[-_,\.\ ]", "-", str.lower())
@@ -276,3 +276,23 @@ def test_add(tmp_dir):
276
276
  assert "data" in calkit.dvc.list_paths()
277
277
  # Check that we can run `calkit add .`
278
278
  subprocess.check_call(["calkit", "add", "."])
279
+ # Test the auto commit message feature
280
+ subprocess.check_call(["git", "reset"])
281
+ subprocess.check_call(["calkit", "add", "large.bin", "-M"])
282
+ repo = git.Repo()
283
+ assert repo.head.commit.message.strip() == "Update large.bin"
284
+ subprocess.check_call(["calkit", "add", "src", "-M"])
285
+ assert repo.head.commit.message.strip() == "Add src"
286
+ with open("src/code.py", "w") as f:
287
+ f.write("# This is the new code")
288
+ subprocess.check_call(["calkit", "add", "src/code.py", "-M"])
289
+ assert repo.head.commit.message.strip() == "Update src/code.py"
290
+ with open("data/raw/file2.bin", "wb") as f:
291
+ f.write(os.urandom(2_000_000))
292
+ subprocess.check_call(["calkit", "add", "data", "-M"])
293
+ assert repo.head.commit.message.strip() == "Update data"
294
+ os.makedirs("data2")
295
+ with open("data2/large2.bin", "wb") as f:
296
+ f.write(os.urandom(2_000_000))
297
+ subprocess.check_call(["calkit", "add", "data2", "-M"])
298
+ assert repo.head.commit.message.strip() == "Add data2"
@@ -3,6 +3,7 @@
3
3
  import os
4
4
  import subprocess
5
5
 
6
+ import git
6
7
  import pytest
7
8
 
8
9
  import calkit
@@ -212,3 +213,18 @@ def test_new_uv_venv(tmp_dir):
212
213
  assert env.path == "requirements-2.txt"
213
214
  assert env.prefix == ".venv2"
214
215
  assert env.kind == "uv-venv"
216
+
217
+
218
+ def test_new_project(tmp_dir):
219
+ subprocess.check_call(["touch", "some-existing-file.txt"])
220
+ subprocess.check_call(
221
+ ["calkit", "new", "project", ".", "--title", "My new project"]
222
+ )
223
+ repo = git.Repo()
224
+ assert "some-existing-file.txt" in repo.untracked_files
225
+ assert repo.git.ls_files("calkit.yaml")
226
+ assert repo.git.ls_files("README.md")
227
+ assert not repo.git.ls_files("some-other-file.txt")
228
+ assert repo.git.ls_files(".devcontainer")
229
+ ck_info = calkit.load_calkit_info()
230
+ assert ck_info["title"] == "My new project"
@@ -1,12 +1,15 @@
1
1
  """Tests for the ``conda`` module."""
2
2
 
3
+ import os
3
4
  import subprocess
4
- import uuid
5
5
 
6
6
  import pytest
7
7
 
8
+ import calkit
8
9
  from calkit.conda import _check_list, _check_single, check_env
9
10
 
11
+ ENV_NAME = "main"
12
+
10
13
 
11
14
  def test_check_single():
12
15
  assert _check_single("python=3.12", "python=3.12.18", conda=True)
@@ -31,15 +34,14 @@ def delete_env(name: str):
31
34
 
32
35
 
33
36
  @pytest.fixture
34
- def env_name():
35
- # Setup code
36
- name = "tmp_" + str(uuid.uuid4())[:12]
37
+ def conda_env_name():
38
+ name = calkit.to_kebab_case(os.path.basename(os.getcwd())) + "-" + ENV_NAME
37
39
  yield name
38
40
  # Teardown code
39
41
  delete_env(name)
40
42
 
41
43
 
42
- def test_check_env(tmp_dir, env_name):
44
+ def test_check_env(tmp_dir, conda_env_name):
43
45
  subprocess.check_call(["git", "init"])
44
46
  subprocess.check_call(["dvc", "init"])
45
47
  subprocess.check_call(
@@ -48,7 +50,7 @@ def test_check_env(tmp_dir, env_name):
48
50
  "new",
49
51
  "conda-env",
50
52
  "-n",
51
- env_name,
53
+ ENV_NAME,
52
54
  "python",
53
55
  "pip",
54
56
  "--pip",
@@ -69,7 +71,7 @@ def test_check_env(tmp_dir, env_name):
69
71
  "conda-env",
70
72
  "--overwrite",
71
73
  "-n",
72
- env_name,
74
+ ENV_NAME,
73
75
  "python=3.11.0",
74
76
  "pip",
75
77
  "--pip",
@@ -91,7 +93,7 @@ def test_check_env(tmp_dir, env_name):
91
93
  "conda-env",
92
94
  "--overwrite",
93
95
  "-n",
94
- env_name,
96
+ ENV_NAME,
95
97
  "python=3.11.0",
96
98
  "pip",
97
99
  "sqlalchemy",
@@ -102,7 +104,7 @@ def test_check_env(tmp_dir, env_name):
102
104
  "conda",
103
105
  "run",
104
106
  "-n",
105
- env_name,
107
+ ENV_NAME,
106
108
  "pip",
107
109
  "install",
108
110
  "--upgrade",
@@ -118,7 +120,7 @@ def test_check_env(tmp_dir, env_name):
118
120
  "conda-env",
119
121
  "--overwrite",
120
122
  "-n",
121
- env_name,
123
+ ENV_NAME,
122
124
  "python=3.11.0",
123
125
  "pip",
124
126
  "sqlalchemy",
@@ -133,7 +135,7 @@ def test_check_env(tmp_dir, env_name):
133
135
  "conda-env",
134
136
  "--overwrite",
135
137
  "-n",
136
- env_name,
138
+ ENV_NAME,
137
139
  "python=3.11.0",
138
140
  "pip",
139
141
  "--pip",
@@ -150,7 +152,7 @@ def test_check_env(tmp_dir, env_name):
150
152
  "conda-env",
151
153
  "--overwrite",
152
154
  "-n",
153
- env_name,
155
+ ENV_NAME,
154
156
  "python=3.12",
155
157
  "--pip",
156
158
  "numpy>=1",
@@ -6,3 +6,8 @@ import calkit
6
6
  def test_find_project_dirs():
7
7
  calkit.find_project_dirs()
8
8
  assert calkit.find_project_dirs(relative=False)
9
+
10
+
11
+ def test_to_kebab_case():
12
+ assert calkit.to_kebab_case("THIS IS") == "this-is"
13
+ assert calkit.to_kebab_case("this_is_my-Project") == "this-is-my-project"
@@ -19,3 +19,20 @@ for the project's important metadata, which includes its:
19
19
  Objects can be imported from other projects,
20
20
  which produces a chain of reference to allow tracking reuse
21
21
  and reduce redundant storage.
22
+
23
+ ## Showcase
24
+
25
+ The project showcase is a list of elements that best represent the project,
26
+ shown on the project homepage on the Calkit Cloud web app.
27
+ For example:
28
+
29
+ ```yaml
30
+ showcase:
31
+ - text: Here is some text.
32
+ - figure: figures/my-figure.png
33
+ - text: There is a figure above.
34
+ ```
35
+
36
+ [This project](https://calkit.io/petebachant/strava-analysis)
37
+ has a showcase that includes Plotly figures saved as JSON,
38
+ which render interactively.
@@ -0,0 +1,23 @@
1
+ # Local server for GUI interaction
2
+
3
+ Calkit includes a local server for interacting with projects locally via the
4
+ Calkit Cloud UI ([calkit.io](https://calkit.io)).
5
+ It can be launched with:
6
+
7
+ ```sh
8
+ calkit local-server
9
+ ```
10
+
11
+ If you then navigate to the project homepage on
12
+ [calkit.io](https://calkit.io) and visit the "local machine"
13
+ tab,
14
+ you'll be able to visually perform tasks like committing and ignoring files,
15
+ running the pipeline, adding stages to the pipeline,
16
+ and pushing to the cloud.
17
+
18
+ This feature is used in the [Microsoft Office tutorial](tutorials/office.md).
19
+
20
+ ![Local server page](tutorials/img/office/pipeline-out-of-date.png){ width="450px" }
21
+ /// caption
22
+ The local server status widget on the Calkit Cloud UI.
23
+ ///
@@ -170,4 +170,6 @@ Options:
170
170
  - `--to`, `-t`: Manually specify `git` or `dvc` as the tracking mechanism.
171
171
  - `--commit-message`, `-m`: Create a commit after adding
172
172
  and use the provided message.
173
+ - `--auto-commit-message`, `-M`: Commit with an automatically-generated message.
174
+ Only compatible when adding one path.
173
175
  - `--push`: Push to the Git or DVC remote after committing.
@@ -47,6 +47,7 @@ nav:
47
47
  - References: references.md
48
48
  - Calculations: calculations.md
49
49
  - Apps: apps.md
50
+ - Local server (GUI interaction): local-server.md
50
51
  - Examples: examples.md
51
52
  - Tutorials:
52
53
  - tutorials/first-project.md
File without changes
File without changes
File without changes