calkit-python 0.41.18__py3-none-any.whl → 0.41.20__py3-none-any.whl

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 (41) hide show
  1. calkit/cli/core.py +2 -2
  2. calkit/cli/latex.py +45 -1
  3. calkit/cli/list.py +12 -10
  4. calkit/cli/main/core.py +20 -3
  5. calkit/cli/new.py +645 -473
  6. calkit/cli/scheduler.py +60 -18
  7. calkit/cli/update.py +2 -3
  8. calkit/detect.py +62 -0
  9. calkit/dvc/zip.py +17 -0
  10. calkit/models/core.py +27 -26
  11. calkit/models/pipeline.py +71 -6
  12. calkit/pipeline.py +181 -2
  13. calkit/releases.py +53 -0
  14. calkit/tests/cli/main/test_core.py +82 -1
  15. calkit/tests/cli/test_latex.py +32 -0
  16. calkit/tests/cli/test_new.py +209 -0
  17. calkit/tests/cli/test_scheduler.py +18 -0
  18. calkit/tests/dvc/test_zip.py +25 -0
  19. calkit/tests/models/test_pipeline.py +94 -2
  20. calkit/tests/test_detect.py +31 -0
  21. calkit/tests/test_pipeline.py +115 -1
  22. {calkit_python-0.41.18.dist-info → calkit_python-0.41.20.dist-info}/METADATA +2 -2
  23. {calkit_python-0.41.18.dist-info → calkit_python-0.41.20.dist-info}/RECORD +41 -41
  24. {calkit_python-0.41.18.data → calkit_python-0.41.20.data}/data/etc/jupyter/jupyter_server_config.d/calkit.json +0 -0
  25. {calkit_python-0.41.18.data → calkit_python-0.41.20.data}/data/share/jupyter/labextensions/calkit/install.json +0 -0
  26. {calkit_python-0.41.18.data → calkit_python-0.41.20.data}/data/share/jupyter/labextensions/calkit/package.json +0 -0
  27. {calkit_python-0.41.18.data → calkit_python-0.41.20.data}/data/share/jupyter/labextensions/calkit/schemas/calkit/package.json.orig +0 -0
  28. {calkit_python-0.41.18.data → calkit_python-0.41.20.data}/data/share/jupyter/labextensions/calkit/schemas/calkit/plugin.json +0 -0
  29. {calkit_python-0.41.18.data → calkit_python-0.41.20.data}/data/share/jupyter/labextensions/calkit/static/502.9a2c5772a15466e923ef.js +0 -0
  30. {calkit_python-0.41.18.data → calkit_python-0.41.20.data}/data/share/jupyter/labextensions/calkit/static/695.2c41003a452d43d2b358.js +0 -0
  31. {calkit_python-0.41.18.data → calkit_python-0.41.20.data}/data/share/jupyter/labextensions/calkit/static/867.a42a046aa5108f54f8fb.js +0 -0
  32. {calkit_python-0.41.18.data → calkit_python-0.41.20.data}/data/share/jupyter/labextensions/calkit/static/909.e3f9cc3408834a7fdcc3.js +0 -0
  33. {calkit_python-0.41.18.data → calkit_python-0.41.20.data}/data/share/jupyter/labextensions/calkit/static/946.050af2abf7845cfbdbd2.js +0 -0
  34. {calkit_python-0.41.18.data → calkit_python-0.41.20.data}/data/share/jupyter/labextensions/calkit/static/946.050af2abf7845cfbdbd2.js.LICENSE.txt +0 -0
  35. {calkit_python-0.41.18.data → calkit_python-0.41.20.data}/data/share/jupyter/labextensions/calkit/static/b2f1c3efe70cb539d121.png +0 -0
  36. {calkit_python-0.41.18.data → calkit_python-0.41.20.data}/data/share/jupyter/labextensions/calkit/static/remoteEntry.ac9035764d5b2adbb542.js +0 -0
  37. {calkit_python-0.41.18.data → calkit_python-0.41.20.data}/data/share/jupyter/labextensions/calkit/static/style.js +0 -0
  38. {calkit_python-0.41.18.data → calkit_python-0.41.20.data}/data/share/jupyter/labextensions/calkit/static/third-party-licenses.json +0 -0
  39. {calkit_python-0.41.18.dist-info → calkit_python-0.41.20.dist-info}/WHEEL +0 -0
  40. {calkit_python-0.41.18.dist-info → calkit_python-0.41.20.dist-info}/entry_points.txt +0 -0
  41. {calkit_python-0.41.18.dist-info → calkit_python-0.41.20.dist-info}/licenses/LICENSE +0 -0
calkit/cli/core.py CHANGED
@@ -5,7 +5,7 @@ from __future__ import annotations
5
5
  import os
6
6
  import re
7
7
  import subprocess
8
- from typing import TYPE_CHECKING
8
+ from typing import TYPE_CHECKING, NoReturn
9
9
 
10
10
  import typer
11
11
  from typer.core import TyperGroup
@@ -96,7 +96,7 @@ def run_cmd(cmd: list[str]):
96
96
  pty.spawn(cmd, lambda fd: os.read(fd, 1024))
97
97
 
98
98
 
99
- def raise_error(txt: str):
99
+ def raise_error(txt: str) -> NoReturn:
100
100
  typer.echo(typer.style("Error: " + str(txt), fg="red"), err=True)
101
101
  raise typer.Exit(1)
102
102
 
calkit/cli/latex.py CHANGED
@@ -7,6 +7,7 @@ import os
7
7
  import string
8
8
  import subprocess
9
9
  from copy import deepcopy
10
+ from pathlib import Path
10
11
 
11
12
  import typer
12
13
  from typing_extensions import Annotated
@@ -135,6 +136,36 @@ def build(
135
136
  help="Path to a latexmkrc file to use for compilation.",
136
137
  ),
137
138
  ] = None,
139
+ output_dir: Annotated[
140
+ str | None,
141
+ typer.Option(
142
+ "--output-dir",
143
+ help=(
144
+ "Directory for the compiled PDF, relative to the current "
145
+ "directory. Passed to latexmk as -outdir."
146
+ ),
147
+ ),
148
+ ] = None,
149
+ aux_dir: Annotated[
150
+ str | None,
151
+ typer.Option(
152
+ "--aux-dir",
153
+ help=(
154
+ "Directory for auxiliary files, relative to the current "
155
+ "directory. Passed to latexmk as -auxdir."
156
+ ),
157
+ ),
158
+ ] = None,
159
+ latexmk_args: Annotated[
160
+ list[str],
161
+ typer.Option(
162
+ "--latexmk-arg",
163
+ help=(
164
+ "Extra argument to pass through to latexmk. Repeat the option "
165
+ "to pass more than one."
166
+ ),
167
+ ),
168
+ ] = [],
138
169
  no_synctex: Annotated[
139
170
  bool,
140
171
  typer.Option(
@@ -173,7 +204,20 @@ def build(
173
204
  latexmk_cmd.append("-silent")
174
205
  if force:
175
206
  latexmk_cmd.append("-f")
176
- latexmk_cmd += ["-interaction=nonstopmode", tex_file]
207
+ # latexmk runs with -cd, so its -outdir/-auxdir are relative to the .tex
208
+ # file's directory; convert the (current-directory-relative) Calkit paths
209
+ # into that frame.
210
+ tex_dir = os.path.dirname(tex_file) or "."
211
+ if output_dir is not None:
212
+ rel = Path(os.path.relpath(output_dir, tex_dir)).as_posix()
213
+ latexmk_cmd.append(f"-outdir={rel}")
214
+ if aux_dir is not None:
215
+ rel = Path(os.path.relpath(aux_dir, tex_dir)).as_posix()
216
+ latexmk_cmd.append(f"-auxdir={rel}")
217
+ latexmk_cmd.append("-interaction=nonstopmode")
218
+ # User pass-through args come last so they can override Calkit's defaults.
219
+ latexmk_cmd += latexmk_args
220
+ latexmk_cmd.append(tex_file)
177
221
  if environment is not None:
178
222
  if no_check:
179
223
  check_cmd = ["--no-check"]
calkit/cli/list.py CHANGED
@@ -261,21 +261,23 @@ def list_releases():
261
261
  objs = calkit.load_calkit_info().get("releases", {})
262
262
  for name, obj in objs.items():
263
263
  typer.echo(name + ":")
264
- # First figure out if the release is published
264
+ # Figure out if the release is published. Internal releases are never
265
+ # uploaded to an archival service, so skip the lookup for them.
265
266
  published = None
266
- try:
267
- published = calkit.invenio.get(
268
- f"/records/{obj.get('record_id')}",
269
- service=obj.get("publisher"),
270
- )["is_published"]
271
- except Exception:
267
+ if not obj.get("internal"):
272
268
  try:
273
269
  published = calkit.invenio.get(
274
- f"/records/{obj.get('record_id')}/draft",
270
+ f"/records/{obj.get('record_id')}",
275
271
  service=obj.get("publisher"),
276
272
  )["is_published"]
277
- except Exception as e:
278
- warn(f"Cannot tell if release {name} is published: {e}")
273
+ except Exception:
274
+ try:
275
+ published = calkit.invenio.get(
276
+ f"/records/{obj.get('record_id')}/draft",
277
+ service=obj.get("publisher"),
278
+ )["is_published"]
279
+ except Exception as e:
280
+ warn(f"Cannot tell if release {name} is published: {e}")
279
281
  if published is not None:
280
282
  typer.echo(f" published: {published}")
281
283
  for k, v in obj.items():
calkit/cli/main/core.py CHANGED
@@ -179,11 +179,26 @@ def init(
179
179
  typer.Option(
180
180
  "--force",
181
181
  "-f",
182
- help="Force reinitializing DVC if already initialized.",
182
+ help="Re-initialize even if the project is already initialized.",
183
183
  ),
184
184
  ] = False,
185
185
  ):
186
186
  """Initialize the current working directory."""
187
+ import git
188
+ from git.exc import InvalidGitRepositoryError
189
+
190
+ def _project_is_initialized() -> bool:
191
+ try:
192
+ git.Repo(".", search_parent_directories=False)
193
+ except InvalidGitRepositoryError:
194
+ return False
195
+ return os.path.isfile(".dvc/config") and os.path.isfile("calkit.yaml")
196
+
197
+ if _project_is_initialized() and not force:
198
+ raise_error(
199
+ "This project is already initialized. "
200
+ "Use --force to re-initialize."
201
+ )
187
202
  subprocess.run(["git", "init"])
188
203
  result = calkit.dvc.run_dvc_command(
189
204
  ["init"] + (["--force"] if force else [])
@@ -197,13 +212,15 @@ def init(
197
212
  # Commit the newly created .dvc directory
198
213
  repo = calkit.git.get_repo()
199
214
  repo.git.add(".dvc")
200
- repo.git.commit("-m", "Initialize DVC")
215
+ if calkit.git.get_staged_files(repo=repo):
216
+ repo.git.commit("-m", "Initialize DVC")
201
217
  # Create an empty calkit.yaml if one doesn't already exist
202
218
  if not os.path.isfile("calkit.yaml"):
203
219
  with open("calkit.yaml", "w"):
204
220
  pass
205
221
  repo.git.add("calkit.yaml")
206
- repo.git.commit("-m", "Initialize Calkit")
222
+ if calkit.git.get_staged_files(repo=repo):
223
+ repo.git.commit("-m", "Initialize Calkit")
207
224
  # TODO: Initialize `dvc.yaml`
208
225
  # TODO: Add a sane .gitignore file
209
226
  # TODO: Add a sane LICENSE file?