calkit-python 0.0.4__py3-none-any.whl → 0.0.6__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.
calkit/__init__.py CHANGED
@@ -1,4 +1,4 @@
1
- __version__ = "0.0.4"
1
+ __version__ = "0.0.6"
2
2
 
3
3
  from .core import *
4
4
  from . import git
calkit/cli.py CHANGED
@@ -11,16 +11,37 @@ import git
11
11
  import typer
12
12
  from typing_extensions import Annotated, Optional
13
13
 
14
+ import calkit
14
15
  from calkit.core import ryaml
15
16
 
16
17
  from . import config
17
18
  from .dvc import configure_remote, set_remote_auth
18
19
 
19
- app = typer.Typer()
20
- config_app = typer.Typer()
21
- new_app = typer.Typer()
20
+ app = typer.Typer(
21
+ invoke_without_command=True,
22
+ no_args_is_help=True,
23
+ context_settings=dict(help_option_names=["-h", "--help"]),
24
+ )
25
+ config_app = typer.Typer(no_args_is_help=True)
26
+ new_app = typer.Typer(no_args_is_help=True)
27
+ notebooks_app = typer.Typer(no_args_is_help=True)
22
28
  app.add_typer(config_app, name="config", help="Configure Calkit.")
23
- app.add_typer(new_app, name="new", help="Add new Calkit object.")
29
+ app.add_typer(
30
+ new_app, name="new", help="Add new Calkit object (to calkit.yaml)."
31
+ )
32
+ app.add_typer(notebooks_app, name="nb", help="Work with Jupyter notebooks.")
33
+
34
+
35
+ @app.callback()
36
+ def main(
37
+ version: Annotated[
38
+ bool,
39
+ typer.Option("--version", help="Show version and exit."),
40
+ ] = False,
41
+ ):
42
+ if version:
43
+ typer.echo(calkit.__version__)
44
+ raise typer.Exit()
24
45
 
25
46
 
26
47
  @config_app.command(name="set")
@@ -135,7 +156,7 @@ def new_figure(
135
156
  description: Annotated[str, typer.Option("--desc")] = None,
136
157
  commit: Annotated[bool, typer.Option("--commit")] = False,
137
158
  ):
138
- """Add a new figure to ``calkit.yaml``."""
159
+ """Add a new figure."""
139
160
  if os.path.isfile("calkit.yaml"):
140
161
  with open("calkit.yaml") as f:
141
162
  ck_info = ryaml.load(f)
@@ -163,6 +184,7 @@ def new_question(
163
184
  question: str,
164
185
  commit: Annotated[bool, typer.Option("--commit")] = False,
165
186
  ):
187
+ """Add a new question."""
166
188
  if os.path.isfile("calkit.yaml"):
167
189
  with open("calkit.yaml") as f:
168
190
  ck_info = ryaml.load(f)
@@ -183,6 +205,109 @@ def new_question(
183
205
  repo.git.commit(["-m", "Add question"])
184
206
 
185
207
 
208
+ @new_app.command("notebook")
209
+ def new_notebook(
210
+ path: Annotated[str, typer.Argument(help="Notebook path (relative)")],
211
+ title: Annotated[str, typer.Option("--title")],
212
+ description: Annotated[str, typer.Option("--desc")] = None,
213
+ commit: Annotated[bool, typer.Option("--commit")] = False,
214
+ ):
215
+ """Add a new notebook."""
216
+ if os.path.isabs(path):
217
+ raise ValueError("Path must be relative")
218
+ if not os.path.isfile(path):
219
+ raise ValueError("Path is not a file")
220
+ if not path.endswith(".ipynb"):
221
+ raise ValueError("Path does not have .ipynb extension")
222
+ # TODO: Add option to create stages that run `calkit nb clean` and
223
+ # `calkit nb execute`
224
+ if os.path.isfile("calkit.yaml"):
225
+ with open("calkit.yaml") as f:
226
+ ck_info = ryaml.load(f)
227
+ else:
228
+ ck_info = {}
229
+ notebooks = ck_info.get("notebooks", [])
230
+ paths = [f.get("path") for f in notebooks]
231
+ if path in paths:
232
+ raise ValueError(f"Notebook at path {path} already exists")
233
+ obj = dict(path=path, title=title)
234
+ if description is not None:
235
+ obj["description"] = description
236
+ notebooks.append(obj)
237
+ ck_info["notebooks"] = notebooks
238
+ with open("calkit.yaml", "w") as f:
239
+ ryaml.dump(ck_info, f)
240
+ if commit:
241
+ repo = git.Repo()
242
+ repo.git.add("calkit.yaml")
243
+ repo.git.commit(["-m", f"Add notebook {path}"])
244
+
245
+
246
+ @notebooks_app.command("clean")
247
+ def clean_notebook_outputs(path: str):
248
+ """Clean notebook and place a copy in the cleaned notebooks directory.
249
+
250
+ This can be useful to use as a preprocessing DVC stage to use a clean
251
+ notebook as a dependency for a stage that caches and executed notebook.
252
+ """
253
+ if os.path.isabs(path):
254
+ raise ValueError("Path must be relative")
255
+ fpath_out = os.path.join(".calkit", "notebooks", "cleaned", path)
256
+ folder = os.path.dirname(fpath_out)
257
+ os.makedirs(folder, exist_ok=True)
258
+ subprocess.call(
259
+ [
260
+ "jupyter",
261
+ "nbconvert",
262
+ path,
263
+ "--clear-output",
264
+ "--to",
265
+ "notebook",
266
+ "--output",
267
+ fpath_out,
268
+ ]
269
+ )
270
+
271
+
272
+ @notebooks_app.command("execute")
273
+ def execute_notebook(
274
+ path: str,
275
+ to: Annotated[
276
+ str, typer.Option("--to", help="Output format ('html' or 'notebook').")
277
+ ] = "notebook",
278
+ ):
279
+ """Execute notebook and place a copy in the relevant directory.
280
+
281
+ This can be useful to use as a preprocessing DVC stage to use a clean
282
+ notebook as a dependency for a stage that caches and executed notebook.
283
+ """
284
+ if os.path.isabs(path):
285
+ raise ValueError("Path must be relative")
286
+ if to == "html":
287
+ subdir = "html"
288
+ fname_out = path.removesuffix(".ipynb") + ".html"
289
+ elif to == "notebook":
290
+ subdir = "executed"
291
+ fname_out = path
292
+ else:
293
+ raise ValueError(f"Invalid output format: '{to}'")
294
+ fpath_out = os.path.join(".calkit", "notebooks", subdir, fname_out)
295
+ folder = os.path.dirname(fpath_out)
296
+ os.makedirs(folder, exist_ok=True)
297
+ subprocess.call(
298
+ [
299
+ "jupyter",
300
+ "nbconvert",
301
+ path,
302
+ "--execute",
303
+ "--to",
304
+ to,
305
+ "--output",
306
+ fpath_out,
307
+ ]
308
+ )
309
+
310
+
186
311
  @app.command(name="server", help="Run the local server.")
187
312
  def run_server():
188
313
  import uvicorn
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: calkit-python
3
- Version: 0.0.4
3
+ Version: 0.0.6
4
4
  Summary: Reproducibility simplified.
5
5
  Project-URL: Homepage, https://github.com/calkit/calkit
6
6
  Project-URL: Issues, https://github.com/calkit/calkit/issues
@@ -1,5 +1,5 @@
1
- calkit/__init__.py,sha256=ZhTSlSvcKFHVv921t4q9zBBPNWHaT4h43s3G26KldNo,142
2
- calkit/cli.py,sha256=FkZGfQNSjWKRjWDX10GMDTh3NM9E7cW9DJch2h_F75Q,7930
1
+ calkit/__init__.py,sha256=MLdE9hjYmVEWkHdbusBCZDUzUC3oiY_AL-IfCGKX8eI,142
2
+ calkit/cli.py,sha256=Ko3ntXUTqYeiLv00PQz68SWRp_vY1hruQgjmgwXnuzc,11788
3
3
  calkit/cloud.py,sha256=CnQKms4mBQo4X8jVLIa-70-3jPDl38zRNFyK5TjiaHM,2209
4
4
  calkit/config.py,sha256=NPFRk5inn66Wy44pyx8WppyqvIzkW1sO6VjXwIcCacE,2044
5
5
  calkit/core.py,sha256=qLNjBwlECzMitL85pMGIHzne4j7FpQAR9-ukYtdIMig,1225
@@ -13,8 +13,8 @@ calkit/server.py,sha256=gq3643ABKTQu1eVR_OqJ-SdQh2dPLHSFsipmmAK5ttA,5959
13
13
  calkit/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
14
  calkit/tests/test_core.py,sha256=CdRqvYnq3MidyTknvfIbkmmhMfydpyKtTW9hakAvzsc,167
15
15
  calkit/tests/test_jupyter.py,sha256=YTL6zI740UM2KUjskSipzvSKxsyQ8rVPFQIX5cb2tMQ,114
16
- calkit_python-0.0.4.dist-info/METADATA,sha256=yAlvKleBuX6xFXFH3u7UHZVJILjlC-RIOSeQEXcNx8A,4004
17
- calkit_python-0.0.4.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
18
- calkit_python-0.0.4.dist-info/entry_points.txt,sha256=tiPfbDDZNB-YStw5YVO_4Gww0W3Dcdy8Mh6muX_GWnY,42
19
- calkit_python-0.0.4.dist-info/licenses/LICENSE,sha256=9ZamCaSUTZk9rcrnf-sWFKLOHr3ws-S_dgKMegW4nw8,1056
20
- calkit_python-0.0.4.dist-info/RECORD,,
16
+ calkit_python-0.0.6.dist-info/METADATA,sha256=kL3dH09fqVyHjPjkKnclC21IAHwmwP8NNdvWgOEEthg,4004
17
+ calkit_python-0.0.6.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
18
+ calkit_python-0.0.6.dist-info/entry_points.txt,sha256=tiPfbDDZNB-YStw5YVO_4Gww0W3Dcdy8Mh6muX_GWnY,42
19
+ calkit_python-0.0.6.dist-info/licenses/LICENSE,sha256=9ZamCaSUTZk9rcrnf-sWFKLOHr3ws-S_dgKMegW4nw8,1056
20
+ calkit_python-0.0.6.dist-info/RECORD,,