calkit-python 0.9.0__tar.gz → 0.9.2__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 (60) hide show
  1. {calkit_python-0.9.0 → calkit_python-0.9.2}/PKG-INFO +3 -3
  2. {calkit_python-0.9.0 → calkit_python-0.9.2}/README.md +2 -2
  3. {calkit_python-0.9.0 → calkit_python-0.9.2}/calkit/__init__.py +1 -1
  4. {calkit_python-0.9.0 → calkit_python-0.9.2}/calkit/cli/config.py +8 -0
  5. {calkit_python-0.9.0 → calkit_python-0.9.2}/calkit/cli/main.py +44 -11
  6. {calkit_python-0.9.0 → calkit_python-0.9.2}/calkit/cli/new.py +13 -6
  7. calkit_python-0.9.2/calkit/cli/update.py +39 -0
  8. {calkit_python-0.9.0 → calkit_python-0.9.2}/calkit/config.py +31 -10
  9. {calkit_python-0.9.0 → calkit_python-0.9.2}/calkit/docker.py +5 -4
  10. {calkit_python-0.9.0 → calkit_python-0.9.2}/calkit/templates/latex/core.py +1 -0
  11. {calkit_python-0.9.0 → calkit_python-0.9.2}/calkit/tests/cli/test_main.py +2 -2
  12. {calkit_python-0.9.0 → calkit_python-0.9.2}/calkit/tests/cli/test_new.py +1 -1
  13. {calkit_python-0.9.0 → calkit_python-0.9.2}/docs/tutorials/conda-envs.md +7 -6
  14. {calkit_python-0.9.0 → calkit_python-0.9.2}/.github/FUNDING.yml +0 -0
  15. {calkit_python-0.9.0 → calkit_python-0.9.2}/.github/workflows/publish-test.yml +0 -0
  16. {calkit_python-0.9.0 → calkit_python-0.9.2}/.github/workflows/publish.yml +0 -0
  17. {calkit_python-0.9.0 → calkit_python-0.9.2}/.gitignore +0 -0
  18. {calkit_python-0.9.0 → calkit_python-0.9.2}/LICENSE +0 -0
  19. {calkit_python-0.9.0 → calkit_python-0.9.2}/calkit/cli/__init__.py +0 -0
  20. {calkit_python-0.9.0 → calkit_python-0.9.2}/calkit/cli/core.py +0 -0
  21. {calkit_python-0.9.0 → calkit_python-0.9.2}/calkit/cli/import_.py +0 -0
  22. {calkit_python-0.9.0 → calkit_python-0.9.2}/calkit/cli/list.py +0 -0
  23. {calkit_python-0.9.0 → calkit_python-0.9.2}/calkit/cli/notebooks.py +0 -0
  24. {calkit_python-0.9.0 → calkit_python-0.9.2}/calkit/cli/office.py +0 -0
  25. {calkit_python-0.9.0 → calkit_python-0.9.2}/calkit/cloud.py +0 -0
  26. {calkit_python-0.9.0 → calkit_python-0.9.2}/calkit/conda.py +0 -0
  27. {calkit_python-0.9.0 → calkit_python-0.9.2}/calkit/core.py +0 -0
  28. {calkit_python-0.9.0 → calkit_python-0.9.2}/calkit/data.py +0 -0
  29. {calkit_python-0.9.0 → calkit_python-0.9.2}/calkit/dvc.py +0 -0
  30. {calkit_python-0.9.0 → calkit_python-0.9.2}/calkit/git.py +0 -0
  31. {calkit_python-0.9.0 → calkit_python-0.9.2}/calkit/gui.py +0 -0
  32. {calkit_python-0.9.0 → calkit_python-0.9.2}/calkit/jupyter.py +0 -0
  33. {calkit_python-0.9.0 → calkit_python-0.9.2}/calkit/magics.py +0 -0
  34. {calkit_python-0.9.0 → calkit_python-0.9.2}/calkit/models.py +0 -0
  35. {calkit_python-0.9.0 → calkit_python-0.9.2}/calkit/office.py +0 -0
  36. {calkit_python-0.9.0 → calkit_python-0.9.2}/calkit/server.py +0 -0
  37. {calkit_python-0.9.0 → calkit_python-0.9.2}/calkit/templates/__init__.py +0 -0
  38. {calkit_python-0.9.0 → calkit_python-0.9.2}/calkit/templates/core.py +0 -0
  39. {calkit_python-0.9.0 → calkit_python-0.9.2}/calkit/templates/latex/__init__.py +0 -0
  40. {calkit_python-0.9.0 → calkit_python-0.9.2}/calkit/templates/latex/article/paper.tex +0 -0
  41. {calkit_python-0.9.0 → calkit_python-0.9.2}/calkit/templates/latex/jfm/jfm.bst +0 -0
  42. {calkit_python-0.9.0 → calkit_python-0.9.2}/calkit/templates/latex/jfm/jfm.cls +0 -0
  43. {calkit_python-0.9.0 → calkit_python-0.9.2}/calkit/templates/latex/jfm/lineno-FLM.sty +0 -0
  44. {calkit_python-0.9.0 → calkit_python-0.9.2}/calkit/templates/latex/jfm/paper.tex +0 -0
  45. {calkit_python-0.9.0 → calkit_python-0.9.2}/calkit/templates/latex/jfm/upmath.sty +0 -0
  46. {calkit_python-0.9.0 → calkit_python-0.9.2}/calkit/tests/__init__.py +0 -0
  47. {calkit_python-0.9.0 → calkit_python-0.9.2}/calkit/tests/cli/__init__.py +0 -0
  48. {calkit_python-0.9.0 → calkit_python-0.9.2}/calkit/tests/cli/test_list.py +0 -0
  49. {calkit_python-0.9.0 → calkit_python-0.9.2}/calkit/tests/test_conda.py +0 -0
  50. {calkit_python-0.9.0 → calkit_python-0.9.2}/calkit/tests/test_core.py +0 -0
  51. {calkit_python-0.9.0 → calkit_python-0.9.2}/calkit/tests/test_dvc.py +0 -0
  52. {calkit_python-0.9.0 → calkit_python-0.9.2}/calkit/tests/test_jupyter.py +0 -0
  53. {calkit_python-0.9.0 → calkit_python-0.9.2}/calkit/tests/test_magics.py +0 -0
  54. {calkit_python-0.9.0 → calkit_python-0.9.2}/calkit/tests/test_templates.py +0 -0
  55. {calkit_python-0.9.0 → calkit_python-0.9.2}/docs/tutorials/adding-latex-pub-docker.md +0 -0
  56. {calkit_python-0.9.0 → calkit_python-0.9.2}/docs/tutorials/img/run-proc.png +0 -0
  57. {calkit_python-0.9.0 → calkit_python-0.9.2}/docs/tutorials/notebook-pipeline.md +0 -0
  58. {calkit_python-0.9.0 → calkit_python-0.9.2}/docs/tutorials/procedures.md +0 -0
  59. {calkit_python-0.9.0 → calkit_python-0.9.2}/pyproject.toml +0 -0
  60. {calkit_python-0.9.0 → calkit_python-0.9.2}/test/pipeline.ipynb +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: calkit-python
3
- Version: 0.9.0
3
+ Version: 0.9.2
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
@@ -106,8 +106,8 @@ If you want to use [Docker](https://docker.com) containers,
106
106
  which is typically a good idea,
107
107
  that should also be installed.
108
108
  For Python, we recommend
109
- [Mambaforge](https://conda-forge.org/miniforge/).
110
- If you're a Windows user and decide to install Mambaforge or any other
109
+ [Miniforge](https://conda-forge.org/miniforge/).
110
+ If you're a Windows user and decide to install Miniforge or any other
111
111
  Conda-based distribution,
112
112
  e.g., Anaconda, you'll probably want to ensure that environment is
113
113
  [activated by default in Git Bash](https://discuss.codecademy.com/t/setting-up-conda-in-git-bash/534473).
@@ -75,8 +75,8 @@ If you want to use [Docker](https://docker.com) containers,
75
75
  which is typically a good idea,
76
76
  that should also be installed.
77
77
  For Python, we recommend
78
- [Mambaforge](https://conda-forge.org/miniforge/).
79
- If you're a Windows user and decide to install Mambaforge or any other
78
+ [Miniforge](https://conda-forge.org/miniforge/).
79
+ If you're a Windows user and decide to install Miniforge or any other
80
80
  Conda-based distribution,
81
81
  e.g., Anaconda, you'll probably want to ensure that environment is
82
82
  [activated by default in Git Bash](https://discuss.codecademy.com/t/setting-up-conda-in-git-bash/534473).
@@ -1,4 +1,4 @@
1
- __version__ = "0.9.0"
1
+ __version__ = "0.9.2"
2
2
 
3
3
  from .core import *
4
4
  from . import git
@@ -57,3 +57,11 @@ def setup_remote_auth():
57
57
  if name == "calkit" or name.startswith("calkit:"):
58
58
  typer.echo(f"Setting up authentication for DVC remote: {name}")
59
59
  set_remote_auth(remote_name=name)
60
+
61
+
62
+ @config_app.command(name="list")
63
+ def list_config_keys():
64
+ """List keys in the config."""
65
+ cfg = config.read()
66
+ for key in cfg.model_dump():
67
+ typer.echo(key)
@@ -23,6 +23,7 @@ from calkit.cli.list import list_app
23
23
  from calkit.cli.new import new_app
24
24
  from calkit.cli.notebooks import notebooks_app
25
25
  from calkit.cli.office import office_app
26
+ from calkit.cli.update import update_app
26
27
  from calkit.models import Procedure
27
28
 
28
29
  app = typer.Typer(
@@ -42,6 +43,7 @@ app.add_typer(notebooks_app, name="nb", help="Work with Jupyter notebooks.")
42
43
  app.add_typer(list_app, name="list", help="List Calkit objects.")
43
44
  app.add_typer(import_app, name="import", help="Import objects.")
44
45
  app.add_typer(office_app, name="office", help="Work with Microsoft Office.")
46
+ app.add_typer(update_app, name="update", help="Update objects.")
45
47
 
46
48
 
47
49
  @app.callback()
@@ -291,26 +293,57 @@ def save(
291
293
  push()
292
294
 
293
295
 
294
- @app.command(name="pull", help="Pull with both Git and DVC.")
295
- def pull():
296
+ @app.command(name="pull")
297
+ def pull(
298
+ no_check_auth: Annotated[bool, typer.Option("--no-check-auth")] = False
299
+ ):
300
+ """Pull with both Git and DVC."""
296
301
  typer.echo("Git pulling")
297
- subprocess.call(["git", "pull"])
302
+ try:
303
+ subprocess.check_call(["git", "pull"])
304
+ except subprocess.CalledProcessError:
305
+ raise_error("Git pull failed")
298
306
  typer.echo("DVC pulling")
299
- subprocess.call(["dvc", "pull"])
307
+ if not no_check_auth:
308
+ # Check that our dvc remotes all have our DVC token set for them
309
+ remotes = calkit.dvc.get_remotes()
310
+ for name, url in remotes.items():
311
+ if name == "calkit" or name.startswith("calkit:"):
312
+ typer.echo(f"Checking authentication for DVC remote: {name}")
313
+ calkit.dvc.set_remote_auth(remote_name=name)
314
+ try:
315
+ subprocess.check_call(["dvc", "pull"])
316
+ except subprocess.CalledProcessError:
317
+ raise_error("DVC pull failed")
300
318
 
301
319
 
302
- @app.command(name="push", help="Push with both Git and DVC.")
303
- def push():
320
+ @app.command(name="push")
321
+ def push(
322
+ no_check_auth: Annotated[bool, typer.Option("--no-check-auth")] = False
323
+ ):
324
+ """Push with both Git and DVC."""
304
325
  typer.echo("Pushing to Git remote")
305
- subprocess.call(["git", "push"])
326
+ try:
327
+ subprocess.check_call(["git", "push"])
328
+ except subprocess.CalledProcessError:
329
+ raise_error("Git push failed")
306
330
  typer.echo("Pushing to DVC remote")
307
- subprocess.call(["dvc", "push"])
331
+ if not no_check_auth:
332
+ # Check that our dvc remotes all have our DVC token set for them
333
+ remotes = calkit.dvc.get_remotes()
334
+ for name, url in remotes.items():
335
+ if name == "calkit" or name.startswith("calkit:"):
336
+ typer.echo(f"Checking authentication for DVC remote: {name}")
337
+ calkit.dvc.set_remote_auth(remote_name=name)
338
+ try:
339
+ subprocess.check_call(["dvc", "push"])
340
+ except subprocess.CalledProcessError:
341
+ raise_error("DVC push failed")
308
342
 
309
343
 
310
- @app.command(
311
- name="local-server", help="Run the local server to interact over HTTP."
312
- )
344
+ @app.command(name="local-server")
313
345
  def run_local_server():
346
+ """Run the local server to interact over HTTP."""
314
347
  import uvicorn
315
348
 
316
349
  uvicorn.run(
@@ -216,7 +216,7 @@ def new_docker_env(
216
216
  layers: Annotated[
217
217
  list[str],
218
218
  typer.Option(
219
- "--add-layer", help="Add a layer (options: mambaforge, foampy)."
219
+ "--add-layer", help="Add a layer (options: miniforge, foampy)."
220
220
  ),
221
221
  ] = [],
222
222
  wdir: Annotated[
@@ -575,7 +575,12 @@ def new_publication(
575
575
  if env_name is not None and template_type != "latex":
576
576
  raise_error("Environments can only be created for latex templates")
577
577
  if env_name is not None and env_name in envs and not overwrite:
578
- raise_error(f"Environment '{env_name}' already exists")
578
+ typer.echo(
579
+ typer.style(
580
+ f"Environment '{env_name}' already exists; overwriting",
581
+ fg="yellow",
582
+ )
583
+ )
579
584
  if template_type is not None:
580
585
  try:
581
586
  template_obj = calkit.templates.get_template(template)
@@ -623,9 +628,8 @@ def new_publication(
623
628
  envs[env_name] = env
624
629
  env_remote = dict(
625
630
  kind="docker",
626
- image="kjarosh/latex:2024.4",
627
- description="TeXlive full from kjarosh.",
628
- platform="linux/amd64",
631
+ image="texlive/texlive:latest-full",
632
+ description="TeXlive full.",
629
633
  )
630
634
  with open(env_path, "w") as f:
631
635
  calkit.ryaml.dump(env_remote, f)
@@ -644,7 +648,10 @@ def new_publication(
644
648
  repo.git.add(path)
645
649
  # Create stage if applicable
646
650
  if stage_name is not None and template_type == "latex":
647
- cmd = f"cd {path} && latexmk -pdf {template_obj.target}"
651
+ cmd = (
652
+ f"cd {path} && latexmk -interaction=nonstopmode "
653
+ f"-pdf {template_obj.target}"
654
+ )
648
655
  if env_name is not None:
649
656
  cmd = f'calkit runenv -n {env_name} "{cmd}"'
650
657
  target_dep = os.path.join(path, template_obj.target)
@@ -0,0 +1,39 @@
1
+ """CLI for updating objects."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import os
6
+
7
+ import requests
8
+ import typer
9
+ from typing_extensions import Annotated
10
+
11
+ update_app = typer.Typer(no_args_is_help=True)
12
+
13
+
14
+ @update_app.command(name="devcontainer")
15
+ def update_devcontainer(
16
+ wdir: Annotated[
17
+ str,
18
+ typer.Option(
19
+ "--wdir",
20
+ help=(
21
+ "Working directory. "
22
+ "By default will run current working directory."
23
+ ),
24
+ ),
25
+ ] = None,
26
+ ):
27
+ """Update a project's devcontainer to match the latest Calkit spec."""
28
+ url = (
29
+ "https://raw.githubusercontent.com/calkit/devcontainer/"
30
+ "refs/heads/main/devcontainer.json"
31
+ )
32
+ typer.echo(f"Downloading {url}")
33
+ resp = requests.get(url)
34
+ out_dir = os.path.join(wdir or ".", ".devcontainer")
35
+ os.makedirs(out_dir, exist_ok=True)
36
+ out_fpath = os.path.join(out_dir, "devcontainer.json")
37
+ typer.echo(f"Writing to {out_fpath}")
38
+ with open(out_fpath, "w") as f:
39
+ f.write(resp.text)
@@ -7,8 +7,14 @@ from typing import Literal
7
7
 
8
8
  import keyring
9
9
  import yaml
10
+ from keyring.errors import NoKeyringError
10
11
  from pydantic import computed_field
11
- from pydantic_settings import BaseSettings, SettingsConfigDict
12
+ from pydantic_settings import (
13
+ BaseSettings,
14
+ PydanticBaseSettingsSource,
15
+ SettingsConfigDict,
16
+ YamlConfigSettingsSource,
17
+ )
12
18
 
13
19
 
14
20
  def get_env() -> Literal["local", "staging", "production"]:
@@ -21,9 +27,9 @@ def set_env(name: Literal["local", "staging", "production"]) -> None:
21
27
  os.environ[f"{__package__.upper()}_ENV"] = name
22
28
 
23
29
 
24
- def get_env_suffix() -> str:
30
+ def get_env_suffix(sep: str = "-") -> str:
25
31
  if get_env() != "production":
26
- return "-" + get_env()
32
+ return sep + get_env()
27
33
  return ""
28
34
 
29
35
 
@@ -39,16 +45,35 @@ class Settings(BaseSettings):
39
45
  f"config{get_env_suffix()}.yaml",
40
46
  ),
41
47
  extra="ignore",
48
+ env_prefix="CALKIT" + get_env_suffix(sep="_") + "_",
42
49
  )
43
50
  username: str | None = None
44
51
  token: str | None = None
45
52
  dvc_token: str | None = None
46
53
  dataframe_engine: Literal["pandas", "polars"] = "pandas"
47
54
 
55
+ @classmethod
56
+ def settings_customise_sources(
57
+ cls,
58
+ settings_cls: type[BaseSettings],
59
+ init_settings: PydanticBaseSettingsSource,
60
+ env_settings: PydanticBaseSettingsSource,
61
+ dotenv_settings: PydanticBaseSettingsSource,
62
+ file_secret_settings: PydanticBaseSettingsSource,
63
+ ) -> tuple[PydanticBaseSettingsSource]:
64
+ return (
65
+ init_settings,
66
+ env_settings,
67
+ YamlConfigSettingsSource(settings_cls),
68
+ )
69
+
48
70
  @computed_field
49
71
  @property
50
- def password(self) -> str:
51
- return keyring.get_password(get_app_name(), self.username)
72
+ def password(self) -> str | None:
73
+ try:
74
+ return keyring.get_password(get_app_name(), self.username)
75
+ except NoKeyringError:
76
+ return None
52
77
 
53
78
  @password.setter
54
79
  def password(self, value: str) -> None:
@@ -66,8 +91,4 @@ class Settings(BaseSettings):
66
91
 
67
92
  def read() -> Settings:
68
93
  """Read the config."""
69
- fpath = Settings.model_config["yaml_file"]
70
- if not os.path.isfile(fpath):
71
- return Settings()
72
- with open(fpath) as f:
73
- return Settings.model_validate(yaml.safe_load(f))
94
+ return Settings()
@@ -1,9 +1,9 @@
1
1
  """Functionality for working with Docker."""
2
2
 
3
- MAMBAFORGE_LAYER_TXT = r"""
3
+ MINIFORGE_LAYER_TXT = r"""
4
4
  # Install Miniforge
5
- ARG MINIFORGE_NAME=Mambaforge
6
- ARG MINIFORGE_VERSION=24.3.0-0
5
+ ARG MINIFORGE_NAME=Miniforge3
6
+ ARG MINIFORGE_VERSION=24.9.2-0
7
7
  ARG TARGETPLATFORM
8
8
 
9
9
  ENV CONDA_DIR=/opt/conda
@@ -47,6 +47,7 @@ RUN pip install --no-cache-dir numpy pandas matplotlib h5py \
47
47
  """.strip()
48
48
 
49
49
  LAYERS = {
50
- "mambaforge": MAMBAFORGE_LAYER_TXT,
50
+ "mambaforge": MINIFORGE_LAYER_TXT,
51
+ "miniforge": MINIFORGE_LAYER_TXT,
51
52
  "foampy": FOAMPY_LAYER_TEXT,
52
53
  }
@@ -7,5 +7,6 @@ GITIGNORE = """
7
7
  *.log
8
8
  *.pdf
9
9
  *.out
10
+ *.gz
10
11
  *.DS_Store
11
12
  """
@@ -17,7 +17,7 @@ def test_run_in_env(tmp_dir):
17
17
  "--name my-image "
18
18
  "--stage build-image "
19
19
  "--from ubuntu "
20
- "--add-layer mambaforge "
20
+ "--add-layer miniforge "
21
21
  "--description 'This is a test image'",
22
22
  shell=True,
23
23
  )
@@ -37,7 +37,7 @@ def test_run_in_env(tmp_dir):
37
37
  "--stage build-image-2 "
38
38
  "--path Dockerfile.2 "
39
39
  "--from ubuntu "
40
- "--add-layer mambaforge "
40
+ "--add-layer miniforge "
41
41
  "--add-layer foampy "
42
42
  "--description 'This is a test image 2'",
43
43
  shell=True,
@@ -167,5 +167,5 @@ def test_new_publication(tmp_dir):
167
167
  stage = dvc_pipeline["stages"]["build-latex-article"]
168
168
  assert stage["cmd"] == (
169
169
  "calkit runenv -n my-latex-env "
170
- '"cd my-paper && latexmk -pdf paper.tex"'
170
+ '"cd my-paper && latexmk -interaction=nonstopmode -pdf paper.tex"'
171
171
  )
@@ -69,16 +69,17 @@ If you run something like:
69
69
 
70
70
  ```sh
71
71
  calkit new conda-env \
72
- -n my-project-py11 \
72
+ -n my-project-py311 \
73
73
  python=3.11 \
74
74
  pip \
75
75
  matplotlib \
76
76
  pandas \
77
77
  jupyter \
78
- --pip tensorflow \
79
- --stage check-conda-env
78
+ --pip tensorflow
80
79
  ```
81
80
 
82
- Calkit will create an environment definition in `calkit.yaml` for use with
83
- `calkit runenv`, and since `--stage` was specified, Calkit will also add
84
- an environment check stage to the pipeline automatically.
81
+ Calkit will create an environment definition in `calkit.yaml`,
82
+ which enables running a command in this environment with
83
+ `calkit runenv -n my-project-py311 my-command-here`.
84
+ That call will automatically create or update the Conda environment on the fly
85
+ as needed and export a lock file describing the actual environment.
File without changes
File without changes