calkit-python 0.0.9__tar.gz → 0.1.0__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.
- {calkit_python-0.0.9 → calkit_python-0.1.0}/PKG-INFO +32 -1
- {calkit_python-0.0.9 → calkit_python-0.1.0}/README.md +31 -0
- {calkit_python-0.0.9 → calkit_python-0.1.0}/calkit/__init__.py +2 -1
- {calkit_python-0.0.9 → calkit_python-0.1.0}/calkit/cli/core.py +2 -1
- calkit_python-0.1.0/calkit/cli/import_.py +122 -0
- {calkit_python-0.0.9 → calkit_python-0.1.0}/calkit/cli/list.py +9 -0
- {calkit_python-0.0.9 → calkit_python-0.1.0}/calkit/cli/main.py +132 -1
- calkit_python-0.1.0/calkit/cli/new.py +354 -0
- calkit_python-0.1.0/calkit/docker.py +50 -0
- {calkit_python-0.0.9 → calkit_python-0.1.0}/calkit/dvc.py +25 -4
- {calkit_python-0.0.9 → calkit_python-0.1.0}/calkit/models.py +26 -6
- calkit_python-0.1.0/calkit/tests/cli/__init__.py +0 -0
- calkit_python-0.1.0/calkit/tests/cli/test_list.py +8 -0
- calkit_python-0.1.0/calkit/tests/cli/test_main.py +91 -0
- calkit_python-0.1.0/calkit/tests/cli/test_new.py +128 -0
- calkit_python-0.0.9/calkit/cli/new.py +0 -96
- {calkit_python-0.0.9 → calkit_python-0.1.0}/.github/FUNDING.yml +0 -0
- {calkit_python-0.0.9 → calkit_python-0.1.0}/.github/workflows/publish-test.yml +0 -0
- {calkit_python-0.0.9 → calkit_python-0.1.0}/.github/workflows/publish.yml +0 -0
- {calkit_python-0.0.9 → calkit_python-0.1.0}/.gitignore +0 -0
- {calkit_python-0.0.9 → calkit_python-0.1.0}/LICENSE +0 -0
- {calkit_python-0.0.9 → calkit_python-0.1.0}/calkit/cli/__init__.py +0 -0
- {calkit_python-0.0.9 → calkit_python-0.1.0}/calkit/cli/config.py +0 -0
- {calkit_python-0.0.9 → calkit_python-0.1.0}/calkit/cli/notebooks.py +0 -0
- {calkit_python-0.0.9 → calkit_python-0.1.0}/calkit/cloud.py +0 -0
- {calkit_python-0.0.9 → calkit_python-0.1.0}/calkit/config.py +0 -0
- {calkit_python-0.0.9 → calkit_python-0.1.0}/calkit/core.py +0 -0
- {calkit_python-0.0.9 → calkit_python-0.1.0}/calkit/data.py +0 -0
- {calkit_python-0.0.9 → calkit_python-0.1.0}/calkit/git.py +0 -0
- {calkit_python-0.0.9 → calkit_python-0.1.0}/calkit/gui.py +0 -0
- {calkit_python-0.0.9 → calkit_python-0.1.0}/calkit/jupyter.py +0 -0
- {calkit_python-0.0.9 → calkit_python-0.1.0}/calkit/server.py +0 -0
- {calkit_python-0.0.9 → calkit_python-0.1.0}/calkit/tests/__init__.py +0 -0
- {calkit_python-0.0.9 → calkit_python-0.1.0}/calkit/tests/test_core.py +0 -0
- {calkit_python-0.0.9 → calkit_python-0.1.0}/calkit/tests/test_jupyter.py +0 -0
- {calkit_python-0.0.9 → calkit_python-0.1.0}/examples/cfd-study/README.md +0 -0
- {calkit_python-0.0.9 → calkit_python-0.1.0}/examples/cfd-study/calkit.yaml +0 -0
- {calkit_python-0.0.9 → calkit_python-0.1.0}/examples/cfd-study/config/simulations/runs.csv +0 -0
- {calkit_python-0.0.9 → calkit_python-0.1.0}/examples/cfd-study/notebook.ipynb +0 -0
- {calkit_python-0.0.9 → calkit_python-0.1.0}/examples/ms-office/.gitignore +0 -0
- {calkit_python-0.0.9 → calkit_python-0.1.0}/examples/ms-office/README.md +0 -0
- {calkit_python-0.0.9 → calkit_python-0.1.0}/examples/ms-office/calkit.yaml +0 -0
- {calkit_python-0.0.9 → calkit_python-0.1.0}/pyproject.toml +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: calkit-python
|
|
3
|
-
Version: 0.0
|
|
3
|
+
Version: 0.1.0
|
|
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
|
|
@@ -107,3 +107,34 @@ what files should be considered datasets, figures, publications, etc.
|
|
|
107
107
|
The Calkit cloud reads this database and registers the various entities
|
|
108
108
|
as part of the entire ecosystem such that if a project is made public,
|
|
109
109
|
other researchers can find and reuse your work to accelerate their own.
|
|
110
|
+
|
|
111
|
+
## Design/UX principles
|
|
112
|
+
|
|
113
|
+
1. Be opinionated. Users should not be forced to make unimportant decisions.
|
|
114
|
+
However, if they disagree, they should have the ability to change the
|
|
115
|
+
default behavior. The most common use case should be default.
|
|
116
|
+
Commands that are commonly executed as groups should be combined, but
|
|
117
|
+
still available to be run individually if desired.
|
|
118
|
+
1. Commits should ideally be made automatically as part of actions that make
|
|
119
|
+
changes to the project repo. For
|
|
120
|
+
example, if a new object is added via the CLI, a commit should be made
|
|
121
|
+
right then unless otherwise specified. This saves the trouble of running
|
|
122
|
+
multiple commands and encourages atomic commits.
|
|
123
|
+
1. Pushes should require explicit input from the user.
|
|
124
|
+
It is still TBD whether or not a pull should automatically be
|
|
125
|
+
made, though in general we want to encourage trunk-based development, i.e.,
|
|
126
|
+
only working on a single branch. One exception might be for local
|
|
127
|
+
experimentation that has a high likelihood of failure, in which case a
|
|
128
|
+
branch can be a nice way to throw those changes away.
|
|
129
|
+
Multiple branches should probably not live in the cloud, however, except
|
|
130
|
+
for small, quickly merged pull requests.
|
|
131
|
+
1. Idempotency is always a good thing. Unnecessary state is bad. For example,
|
|
132
|
+
we should not encourage caching pipeline outputs for operations that are
|
|
133
|
+
cheap. Caching should happen either for state that is valuable on its
|
|
134
|
+
own, like a figure, or for an intermediate result that is expensive to
|
|
135
|
+
generate.
|
|
136
|
+
1. There should be the smallest number of
|
|
137
|
+
frequently used commands as possible, and they should require at little
|
|
138
|
+
memorization as possible to know how to execute, e.g., a user should be
|
|
139
|
+
able to keep running `calkit run` and that's all they really need to do
|
|
140
|
+
to make sure the project is up-to-date.
|
|
@@ -79,3 +79,34 @@ what files should be considered datasets, figures, publications, etc.
|
|
|
79
79
|
The Calkit cloud reads this database and registers the various entities
|
|
80
80
|
as part of the entire ecosystem such that if a project is made public,
|
|
81
81
|
other researchers can find and reuse your work to accelerate their own.
|
|
82
|
+
|
|
83
|
+
## Design/UX principles
|
|
84
|
+
|
|
85
|
+
1. Be opinionated. Users should not be forced to make unimportant decisions.
|
|
86
|
+
However, if they disagree, they should have the ability to change the
|
|
87
|
+
default behavior. The most common use case should be default.
|
|
88
|
+
Commands that are commonly executed as groups should be combined, but
|
|
89
|
+
still available to be run individually if desired.
|
|
90
|
+
1. Commits should ideally be made automatically as part of actions that make
|
|
91
|
+
changes to the project repo. For
|
|
92
|
+
example, if a new object is added via the CLI, a commit should be made
|
|
93
|
+
right then unless otherwise specified. This saves the trouble of running
|
|
94
|
+
multiple commands and encourages atomic commits.
|
|
95
|
+
1. Pushes should require explicit input from the user.
|
|
96
|
+
It is still TBD whether or not a pull should automatically be
|
|
97
|
+
made, though in general we want to encourage trunk-based development, i.e.,
|
|
98
|
+
only working on a single branch. One exception might be for local
|
|
99
|
+
experimentation that has a high likelihood of failure, in which case a
|
|
100
|
+
branch can be a nice way to throw those changes away.
|
|
101
|
+
Multiple branches should probably not live in the cloud, however, except
|
|
102
|
+
for small, quickly merged pull requests.
|
|
103
|
+
1. Idempotency is always a good thing. Unnecessary state is bad. For example,
|
|
104
|
+
we should not encourage caching pipeline outputs for operations that are
|
|
105
|
+
cheap. Caching should happen either for state that is valuable on its
|
|
106
|
+
own, like a figure, or for an intermediate result that is expensive to
|
|
107
|
+
generate.
|
|
108
|
+
1. There should be the smallest number of
|
|
109
|
+
frequently used commands as possible, and they should require at little
|
|
110
|
+
memorization as possible to know how to execute, e.g., a user should be
|
|
111
|
+
able to keep running `calkit run` and that's all they really need to do
|
|
112
|
+
to make sure the project is up-to-date.
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"""Core CLI functionality."""
|
|
2
2
|
|
|
3
3
|
import os
|
|
4
|
-
import pty
|
|
5
4
|
import subprocess
|
|
6
5
|
|
|
7
6
|
import typer
|
|
@@ -19,4 +18,6 @@ def run_cmd(cmd: list[str]):
|
|
|
19
18
|
if os.name == "nt":
|
|
20
19
|
subprocess.call(cmd)
|
|
21
20
|
else:
|
|
21
|
+
import pty
|
|
22
|
+
|
|
22
23
|
pty.spawn(cmd, lambda fd: os.read(fd, 1024))
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"""CLI for importing objects."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
import subprocess
|
|
7
|
+
from typing import Annotated
|
|
8
|
+
|
|
9
|
+
import git
|
|
10
|
+
import typer
|
|
11
|
+
|
|
12
|
+
import calkit
|
|
13
|
+
|
|
14
|
+
import_app = typer.Typer(no_args_is_help=True)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@import_app.command(name="dataset")
|
|
18
|
+
def import_dataset(
|
|
19
|
+
src_path: Annotated[
|
|
20
|
+
str,
|
|
21
|
+
typer.Argument(
|
|
22
|
+
help=(
|
|
23
|
+
"Location of dataset, including project owner and name, e.g., "
|
|
24
|
+
"someone/some-project/data/some-data.csv"
|
|
25
|
+
)
|
|
26
|
+
),
|
|
27
|
+
],
|
|
28
|
+
dest_path: Annotated[
|
|
29
|
+
str,
|
|
30
|
+
typer.Argument(help="Output path at which to save."),
|
|
31
|
+
] = None,
|
|
32
|
+
overwrite: Annotated[
|
|
33
|
+
bool,
|
|
34
|
+
typer.Option(
|
|
35
|
+
"--overwrite",
|
|
36
|
+
"-f",
|
|
37
|
+
help="Force adding the dataset even if it already exists.",
|
|
38
|
+
),
|
|
39
|
+
] = False,
|
|
40
|
+
):
|
|
41
|
+
"""Import a dataset.
|
|
42
|
+
|
|
43
|
+
Currently only supports datasets kept in DVC, not Git.
|
|
44
|
+
"""
|
|
45
|
+
# Ensure we don't already have a dataset at this path
|
|
46
|
+
path_split = src_path.split("/")
|
|
47
|
+
owner_name = path_split[0]
|
|
48
|
+
project_name = path_split[1]
|
|
49
|
+
path = "/".join(path_split[2:])
|
|
50
|
+
if dest_path is None:
|
|
51
|
+
dest_path = path
|
|
52
|
+
ck_info = calkit.load_calkit_info()
|
|
53
|
+
datasets = ck_info.get("datasets", [])
|
|
54
|
+
ds_paths = [ds["path"] for ds in datasets]
|
|
55
|
+
if not overwrite and dest_path in ds_paths:
|
|
56
|
+
raise ValueError(
|
|
57
|
+
"A dataset already exists in this project at this path"
|
|
58
|
+
)
|
|
59
|
+
elif overwrite and dest_path in ds_paths:
|
|
60
|
+
datasets = [ds for ds in datasets if ds["path"] != dest_path]
|
|
61
|
+
repo = git.Repo()
|
|
62
|
+
# Obtain, save, and commit the .dvc file for the dataset
|
|
63
|
+
typer.echo("Fetching import info")
|
|
64
|
+
resp = calkit.cloud.get(
|
|
65
|
+
f"/projects/{owner_name}/{project_name}/datasets/{path}"
|
|
66
|
+
)
|
|
67
|
+
if not "dvc_import" in resp:
|
|
68
|
+
raise ValueError("This file is not available to import with DVC")
|
|
69
|
+
dvc_fpath = dest_path + ".dvc"
|
|
70
|
+
dvc_dir = os.path.dirname(dvc_fpath)
|
|
71
|
+
os.makedirs(dvc_dir, exist_ok=True)
|
|
72
|
+
# Update path in .dvc file if necessary
|
|
73
|
+
dvc_import = resp["dvc_import"]
|
|
74
|
+
dvc_import["outs"][0]["path"] = os.path.basename(dest_path)
|
|
75
|
+
typer.echo("Saving .dvc file")
|
|
76
|
+
with open(dvc_fpath, "w") as f:
|
|
77
|
+
calkit.ryaml.dump(dvc_import, f)
|
|
78
|
+
repo.git.add(dvc_fpath)
|
|
79
|
+
# Ensure we have a DVC remote corresponding to this project, and that we
|
|
80
|
+
# have a token set for that remote
|
|
81
|
+
typer.echo("Adding new DVC remote")
|
|
82
|
+
calkit.dvc.add_external_remote(
|
|
83
|
+
owner_name=owner_name, project_name=project_name
|
|
84
|
+
)
|
|
85
|
+
repo.git.add(".dvc/config")
|
|
86
|
+
# Add to .gitignore
|
|
87
|
+
typer.echo("Checking .gitignore")
|
|
88
|
+
if os.path.isfile(".gitignore"):
|
|
89
|
+
with open(".gitignore") as f:
|
|
90
|
+
gitignore = f.read()
|
|
91
|
+
else:
|
|
92
|
+
gitignore = ""
|
|
93
|
+
if dest_path not in gitignore.split("\n"):
|
|
94
|
+
typer.echo(f"Adding {dest_path} to .gitignore")
|
|
95
|
+
gitignore = gitignore.rstrip() + "\n" + dest_path + "\n"
|
|
96
|
+
with open(".gitignore", "w") as f:
|
|
97
|
+
f.write(gitignore)
|
|
98
|
+
repo.git.add(".gitignore")
|
|
99
|
+
# Add to datasets in calkit.yaml
|
|
100
|
+
typer.echo("Adding dataset to calkit.yaml")
|
|
101
|
+
new_ds = calkit.models.ImportedDataset(
|
|
102
|
+
path=dest_path,
|
|
103
|
+
title=resp.get("title"),
|
|
104
|
+
description=resp.get("description"),
|
|
105
|
+
stage=None,
|
|
106
|
+
imported_from=calkit.models._ImportedFromProject(
|
|
107
|
+
project=f"{owner_name}/{project_name}",
|
|
108
|
+
path=path,
|
|
109
|
+
git_rev=None, # TODO?
|
|
110
|
+
),
|
|
111
|
+
)
|
|
112
|
+
datasets.append(new_ds.model_dump())
|
|
113
|
+
ck_info["datasets"] = datasets
|
|
114
|
+
with open("calkit.yaml", "w") as f:
|
|
115
|
+
calkit.ryaml.dump(ck_info, f)
|
|
116
|
+
repo.git.add("calkit.yaml")
|
|
117
|
+
# Commit any necessary changes
|
|
118
|
+
typer.echo("Committing changes")
|
|
119
|
+
repo.git.commit(["-m", f"Import dataset {src_path}"])
|
|
120
|
+
# Run dvc pull
|
|
121
|
+
typer.echo("Running dvc pull")
|
|
122
|
+
subprocess.call(["dvc", "pull", dest_path])
|
|
@@ -68,3 +68,12 @@ def list_publications():
|
|
|
68
68
|
@list_app.command(name="references")
|
|
69
69
|
def list_references():
|
|
70
70
|
_list_objects("references")
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
@list_app.command(name="environments")
|
|
74
|
+
def list_environments():
|
|
75
|
+
envs = calkit.load_calkit_info().get("environments", {})
|
|
76
|
+
for name, env in envs.items():
|
|
77
|
+
typer.echo(name + ":")
|
|
78
|
+
for k, v in env.items():
|
|
79
|
+
typer.echo(f" {k}: {v}")
|
|
@@ -4,13 +4,16 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
import os
|
|
6
6
|
import subprocess
|
|
7
|
+
import sys
|
|
7
8
|
|
|
9
|
+
import git
|
|
8
10
|
import typer
|
|
9
11
|
from typing_extensions import Annotated, Optional
|
|
10
12
|
|
|
11
13
|
import calkit
|
|
12
14
|
from calkit.cli import print_sep, run_cmd
|
|
13
15
|
from calkit.cli.config import config_app
|
|
16
|
+
from calkit.cli.import_ import import_app
|
|
14
17
|
from calkit.cli.list import list_app
|
|
15
18
|
from calkit.cli.new import new_app
|
|
16
19
|
from calkit.cli.notebooks import notebooks_app
|
|
@@ -27,6 +30,7 @@ app.add_typer(
|
|
|
27
30
|
)
|
|
28
31
|
app.add_typer(notebooks_app, name="nb", help="Work with Jupyter notebooks.")
|
|
29
32
|
app.add_typer(list_app, name="list", help="List Calkit objects.")
|
|
33
|
+
app.add_typer(import_app, name="import", help="Import objects.")
|
|
30
34
|
|
|
31
35
|
|
|
32
36
|
@app.callback()
|
|
@@ -37,7 +41,7 @@ def main(
|
|
|
37
41
|
] = False,
|
|
38
42
|
):
|
|
39
43
|
if version:
|
|
40
|
-
typer.echo(calkit.__version__)
|
|
44
|
+
typer.echo(f"Calkit {calkit.__version__}")
|
|
41
45
|
raise typer.Exit()
|
|
42
46
|
|
|
43
47
|
|
|
@@ -119,8 +123,16 @@ def add(
|
|
|
119
123
|
if os.path.isdir(path):
|
|
120
124
|
typer.echo("Cannot auto-add directories; use git or dvc")
|
|
121
125
|
raise typer.Exit(1)
|
|
126
|
+
repo = git.Repo()
|
|
122
127
|
for path in paths:
|
|
123
128
|
# Detect if this file should be tracked with Git or DVC
|
|
129
|
+
# First see if it's in Git
|
|
130
|
+
if repo.git.ls_files(path):
|
|
131
|
+
typer.echo(
|
|
132
|
+
f"Adding {path} to Git since it's already in the repo"
|
|
133
|
+
)
|
|
134
|
+
subprocess.call(["git", "add", path])
|
|
135
|
+
continue
|
|
124
136
|
if os.path.splitext(path)[-1] in dvc_extensions:
|
|
125
137
|
typer.echo(f"Adding {path} to DVC per its extension")
|
|
126
138
|
subprocess.call(["dvc", "add", path])
|
|
@@ -168,6 +180,50 @@ def commit(
|
|
|
168
180
|
push()
|
|
169
181
|
|
|
170
182
|
|
|
183
|
+
@app.command(name="save")
|
|
184
|
+
def save(
|
|
185
|
+
paths: Annotated[
|
|
186
|
+
Optional[list[str]],
|
|
187
|
+
typer.Argument(
|
|
188
|
+
help=(
|
|
189
|
+
"Paths to add and commit. If not provided, will default to "
|
|
190
|
+
"any changed files that have been added previously."
|
|
191
|
+
),
|
|
192
|
+
),
|
|
193
|
+
] = None,
|
|
194
|
+
all: Annotated[
|
|
195
|
+
Optional[bool],
|
|
196
|
+
typer.Option(
|
|
197
|
+
"--all", "-a", help="Automatically stage all changed files."
|
|
198
|
+
),
|
|
199
|
+
] = False,
|
|
200
|
+
message: Annotated[
|
|
201
|
+
Optional[str], typer.Option("--message", "-m", help="Commit message.")
|
|
202
|
+
] = None,
|
|
203
|
+
to: Annotated[
|
|
204
|
+
str,
|
|
205
|
+
typer.Option(
|
|
206
|
+
"--to", "-t", help="System with which to add (git or dvc)."
|
|
207
|
+
),
|
|
208
|
+
] = None,
|
|
209
|
+
no_push: Annotated[
|
|
210
|
+
bool,
|
|
211
|
+
typer.Option(
|
|
212
|
+
"--no-push", help="Do not push to Git and DVC after committing."
|
|
213
|
+
),
|
|
214
|
+
] = False,
|
|
215
|
+
):
|
|
216
|
+
"""Save paths by committing and pushing.
|
|
217
|
+
|
|
218
|
+
This is essentially git/dvc add, commit, and push in one step.
|
|
219
|
+
"""
|
|
220
|
+
if paths is not None:
|
|
221
|
+
add(paths, to=to)
|
|
222
|
+
commit(all=True if paths is None else False, message=message)
|
|
223
|
+
if not no_push:
|
|
224
|
+
push()
|
|
225
|
+
|
|
226
|
+
|
|
171
227
|
@app.command(name="pull", help="Pull with both Git and DVC.")
|
|
172
228
|
def pull():
|
|
173
229
|
typer.echo("Git pulling")
|
|
@@ -354,3 +410,78 @@ def manual_step(
|
|
|
354
410
|
)
|
|
355
411
|
input(message + " (press enter to confirm): ")
|
|
356
412
|
typer.echo("Done")
|
|
413
|
+
|
|
414
|
+
|
|
415
|
+
@app.command(
|
|
416
|
+
name="run-env",
|
|
417
|
+
help="Run a command in an environment.",
|
|
418
|
+
context_settings={"ignore_unknown_options": True},
|
|
419
|
+
)
|
|
420
|
+
def run_in_env(
|
|
421
|
+
cmd: Annotated[
|
|
422
|
+
list[str], typer.Argument(help="Command to run in the environment.")
|
|
423
|
+
],
|
|
424
|
+
env_name: Annotated[
|
|
425
|
+
str,
|
|
426
|
+
typer.Option(
|
|
427
|
+
"--name",
|
|
428
|
+
"-n",
|
|
429
|
+
help=(
|
|
430
|
+
"Environment name in which to run. "
|
|
431
|
+
"Only necessary if there are multiple in this project."
|
|
432
|
+
),
|
|
433
|
+
),
|
|
434
|
+
] = None,
|
|
435
|
+
verbose: Annotated[
|
|
436
|
+
bool, typer.Option("--verbose", "-v", help="Print verbose output.")
|
|
437
|
+
] = False,
|
|
438
|
+
):
|
|
439
|
+
ck_info = calkit.load_calkit_info()
|
|
440
|
+
envs = ck_info.get("environments", {})
|
|
441
|
+
if not envs:
|
|
442
|
+
typer.echo("No environments defined in calkit.yaml", err=True)
|
|
443
|
+
raise typer.Exit(1)
|
|
444
|
+
if isinstance(envs, list):
|
|
445
|
+
typer.echo(
|
|
446
|
+
"Error: Environments should be a dict, not a list", err=True
|
|
447
|
+
)
|
|
448
|
+
raise typer.Exit(1)
|
|
449
|
+
if len(envs) > 1 and env_name is None:
|
|
450
|
+
typer.echo(
|
|
451
|
+
"Environment must be specified if there are multiple",
|
|
452
|
+
err=True,
|
|
453
|
+
)
|
|
454
|
+
raise typer.Exit(1)
|
|
455
|
+
if env_name is None:
|
|
456
|
+
env_name = list(envs.keys())[0]
|
|
457
|
+
env = envs[env_name]
|
|
458
|
+
cwd = os.getcwd()
|
|
459
|
+
image_name = env.get("image", env_name)
|
|
460
|
+
wdir = env.get("wdir", "/work")
|
|
461
|
+
if env["kind"] == "docker":
|
|
462
|
+
cmd = " ".join(cmd)
|
|
463
|
+
cmd = [
|
|
464
|
+
"docker",
|
|
465
|
+
"run",
|
|
466
|
+
"-it" if sys.stdin.isatty() else "-i",
|
|
467
|
+
"--rm",
|
|
468
|
+
"-w",
|
|
469
|
+
wdir,
|
|
470
|
+
"-v",
|
|
471
|
+
f"{cwd}:{wdir}",
|
|
472
|
+
image_name,
|
|
473
|
+
"bash",
|
|
474
|
+
"-c",
|
|
475
|
+
f"{cmd}",
|
|
476
|
+
]
|
|
477
|
+
if verbose:
|
|
478
|
+
typer.echo(f"Running command: {cmd}")
|
|
479
|
+
subprocess.call(cmd)
|
|
480
|
+
elif env["kind"] == "conda":
|
|
481
|
+
cmd = ["conda", "run", "-n", env_name] + cmd
|
|
482
|
+
if verbose:
|
|
483
|
+
typer.echo(f"Running command: {cmd}")
|
|
484
|
+
subprocess.call(cmd)
|
|
485
|
+
else:
|
|
486
|
+
typer.echo("Environment kind not supported", err=True)
|
|
487
|
+
raise typer.Exit(1)
|