lamin_cli 0.17.4__py2.py3-none-any.whl → 0.17.6__py2.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.
- lamin_cli/__init__.py +1 -1
- lamin_cli/__main__.py +300 -303
- lamin_cli/_get.py +82 -82
- lamin_cli/_migration.py +48 -48
- lamin_cli/_save.py +119 -111
- {lamin_cli-0.17.4.dist-info → lamin_cli-0.17.6.dist-info}/LICENSE +201 -201
- {lamin_cli-0.17.4.dist-info → lamin_cli-0.17.6.dist-info}/METADATA +1 -1
- lamin_cli-0.17.6.dist-info/RECORD +11 -0
- {lamin_cli-0.17.4.dist-info → lamin_cli-0.17.6.dist-info}/WHEEL +1 -1
- lamin_cli-0.17.4.dist-info/RECORD +0 -11
- {lamin_cli-0.17.4.dist-info → lamin_cli-0.17.6.dist-info}/entry_points.txt +0 -0
lamin_cli/_get.py
CHANGED
|
@@ -1,82 +1,82 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
from typing import Tuple
|
|
3
|
-
from lamin_utils import logger
|
|
4
|
-
import lamindb_setup as ln_setup
|
|
5
|
-
from pathlib import Path
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
def decompose_url(url: str) -> Tuple[str, str, str]:
|
|
9
|
-
assert "transform" in url or "artifact" in url
|
|
10
|
-
for entity in ["transform", "artifact"]:
|
|
11
|
-
if entity in url:
|
|
12
|
-
break
|
|
13
|
-
uid = url.split(f"{entity}/")[1]
|
|
14
|
-
instance_slug = "/".join(url.replace("https://lamin.ai/", "").split("/")[:2])
|
|
15
|
-
return instance_slug, entity, uid
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
def get(entity: str, uid: str = None, key: str = None, with_env: bool = False):
|
|
19
|
-
if entity.startswith("https://lamin.ai"):
|
|
20
|
-
url = entity
|
|
21
|
-
instance_slug, entity, uid = decompose_url(url)
|
|
22
|
-
elif entity not in {"artifact", "transform"}:
|
|
23
|
-
raise ValueError(
|
|
24
|
-
"entity has to be a URL starting with https://lamin.ai or 'artifact' or"
|
|
25
|
-
" 'transform'"
|
|
26
|
-
)
|
|
27
|
-
else:
|
|
28
|
-
instance_slug = None
|
|
29
|
-
|
|
30
|
-
if instance_slug is not None:
|
|
31
|
-
auto_connect = ln_setup.settings.auto_connect
|
|
32
|
-
# we don't want to auto-connect when importing lamindb
|
|
33
|
-
ln_setup.settings.auto_connect = False
|
|
34
|
-
|
|
35
|
-
import lamindb as ln
|
|
36
|
-
from lamindb._finish import script_to_notebook
|
|
37
|
-
|
|
38
|
-
ln_setup.settings.auto_connect = auto_connect
|
|
39
|
-
ln.connect(instance_slug)
|
|
40
|
-
else:
|
|
41
|
-
import lamindb as ln
|
|
42
|
-
from lamindb._finish import script_to_notebook
|
|
43
|
-
|
|
44
|
-
# below is to silence warnings about missing run inputs
|
|
45
|
-
ln.settings.track_run_inputs = False
|
|
46
|
-
|
|
47
|
-
if entity == "transform":
|
|
48
|
-
transform = (
|
|
49
|
-
ln.Transform.get(uid) if uid is not None else ln.Transform.get(key=key)
|
|
50
|
-
)
|
|
51
|
-
target_filename = transform.key
|
|
52
|
-
if transform._source_code_artifact_id is not None:
|
|
53
|
-
# backward compat
|
|
54
|
-
filepath_cache = transform._source_code_artifact.cache()
|
|
55
|
-
if not target_filename.endswith(transform._source_code_artifact.suffix):
|
|
56
|
-
target_filename += transform._source_code_artifact.suffix
|
|
57
|
-
filepath_cache.rename(target_filename)
|
|
58
|
-
elif transform.source_code is not None:
|
|
59
|
-
if transform.key.endswith(".ipynb"):
|
|
60
|
-
script_to_notebook(transform, target_filename)
|
|
61
|
-
else:
|
|
62
|
-
Path(target_filename).write_text(transform.source_code)
|
|
63
|
-
else:
|
|
64
|
-
raise ValueError("No source code available for this transform.")
|
|
65
|
-
logger.important(target_filename)
|
|
66
|
-
if with_env:
|
|
67
|
-
if (
|
|
68
|
-
transform.latest_run is not None
|
|
69
|
-
and transform.latest_run.environment is not None
|
|
70
|
-
):
|
|
71
|
-
filepath_env_cache = transform.latest_run.environment.cache()
|
|
72
|
-
target_env_filename = (
|
|
73
|
-
".".join(target_filename.split(".")[:-1]) + "__requirements.txt"
|
|
74
|
-
)
|
|
75
|
-
filepath_env_cache.rename(target_env_filename)
|
|
76
|
-
logger.important(target_env_filename)
|
|
77
|
-
else:
|
|
78
|
-
logger.warning("latest transform run with environment doesn't exist")
|
|
79
|
-
elif entity == "artifact":
|
|
80
|
-
artifact = ln.Artifact.get(uid) if uid is not None else ln.Artifact.get(key=key)
|
|
81
|
-
cache_path = artifact.cache()
|
|
82
|
-
logger.important(cache_path)
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from typing import Tuple
|
|
3
|
+
from lamin_utils import logger
|
|
4
|
+
import lamindb_setup as ln_setup
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def decompose_url(url: str) -> Tuple[str, str, str]:
|
|
9
|
+
assert "transform" in url or "artifact" in url
|
|
10
|
+
for entity in ["transform", "artifact"]:
|
|
11
|
+
if entity in url:
|
|
12
|
+
break
|
|
13
|
+
uid = url.split(f"{entity}/")[1]
|
|
14
|
+
instance_slug = "/".join(url.replace("https://lamin.ai/", "").split("/")[:2])
|
|
15
|
+
return instance_slug, entity, uid
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def get(entity: str, uid: str = None, key: str = None, with_env: bool = False):
|
|
19
|
+
if entity.startswith("https://lamin.ai"):
|
|
20
|
+
url = entity
|
|
21
|
+
instance_slug, entity, uid = decompose_url(url)
|
|
22
|
+
elif entity not in {"artifact", "transform"}:
|
|
23
|
+
raise ValueError(
|
|
24
|
+
"entity has to be a URL starting with https://lamin.ai or 'artifact' or"
|
|
25
|
+
" 'transform'"
|
|
26
|
+
)
|
|
27
|
+
else:
|
|
28
|
+
instance_slug = None
|
|
29
|
+
|
|
30
|
+
if instance_slug is not None:
|
|
31
|
+
auto_connect = ln_setup.settings.auto_connect
|
|
32
|
+
# we don't want to auto-connect when importing lamindb
|
|
33
|
+
ln_setup.settings.auto_connect = False
|
|
34
|
+
|
|
35
|
+
import lamindb as ln
|
|
36
|
+
from lamindb._finish import script_to_notebook
|
|
37
|
+
|
|
38
|
+
ln_setup.settings.auto_connect = auto_connect
|
|
39
|
+
ln.connect(instance_slug)
|
|
40
|
+
else:
|
|
41
|
+
import lamindb as ln
|
|
42
|
+
from lamindb._finish import script_to_notebook
|
|
43
|
+
|
|
44
|
+
# below is to silence warnings about missing run inputs
|
|
45
|
+
ln.settings.track_run_inputs = False
|
|
46
|
+
|
|
47
|
+
if entity == "transform":
|
|
48
|
+
transform = (
|
|
49
|
+
ln.Transform.get(uid) if uid is not None else ln.Transform.get(key=key)
|
|
50
|
+
)
|
|
51
|
+
target_filename = transform.key
|
|
52
|
+
if transform._source_code_artifact_id is not None:
|
|
53
|
+
# backward compat
|
|
54
|
+
filepath_cache = transform._source_code_artifact.cache()
|
|
55
|
+
if not target_filename.endswith(transform._source_code_artifact.suffix):
|
|
56
|
+
target_filename += transform._source_code_artifact.suffix
|
|
57
|
+
filepath_cache.rename(target_filename)
|
|
58
|
+
elif transform.source_code is not None:
|
|
59
|
+
if transform.key.endswith(".ipynb"):
|
|
60
|
+
script_to_notebook(transform, target_filename)
|
|
61
|
+
else:
|
|
62
|
+
Path(target_filename).write_text(transform.source_code)
|
|
63
|
+
else:
|
|
64
|
+
raise ValueError("No source code available for this transform.")
|
|
65
|
+
logger.important(target_filename)
|
|
66
|
+
if with_env:
|
|
67
|
+
if (
|
|
68
|
+
transform.latest_run is not None
|
|
69
|
+
and transform.latest_run.environment is not None
|
|
70
|
+
):
|
|
71
|
+
filepath_env_cache = transform.latest_run.environment.cache()
|
|
72
|
+
target_env_filename = (
|
|
73
|
+
".".join(target_filename.split(".")[:-1]) + "__requirements.txt"
|
|
74
|
+
)
|
|
75
|
+
filepath_env_cache.rename(target_env_filename)
|
|
76
|
+
logger.important(target_env_filename)
|
|
77
|
+
else:
|
|
78
|
+
logger.warning("latest transform run with environment doesn't exist")
|
|
79
|
+
elif entity == "artifact":
|
|
80
|
+
artifact = ln.Artifact.get(uid) if uid is not None else ln.Artifact.get(key=key)
|
|
81
|
+
cache_path = artifact.cache()
|
|
82
|
+
logger.important(cache_path)
|
lamin_cli/_migration.py
CHANGED
|
@@ -1,48 +1,48 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
import os
|
|
3
|
-
from typing import Optional
|
|
4
|
-
|
|
5
|
-
if os.environ.get("NO_RICH"):
|
|
6
|
-
import click as click
|
|
7
|
-
else:
|
|
8
|
-
import rich_click as click
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
@click.group()
|
|
12
|
-
def migrate():
|
|
13
|
-
"""Manage migrations."""
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
@migrate.command("create")
|
|
17
|
-
def create():
|
|
18
|
-
"""Create a new migration."""
|
|
19
|
-
from lamindb_setup._migrate import migrate
|
|
20
|
-
|
|
21
|
-
return migrate.create()
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
@migrate.command("deploy")
|
|
25
|
-
def deploy():
|
|
26
|
-
"""Deploy migrations."""
|
|
27
|
-
from lamindb_setup._migrate import migrate
|
|
28
|
-
|
|
29
|
-
return migrate.deploy()
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
@migrate.command("squash")
|
|
33
|
-
@click.option("--package-name", type=str, default=None)
|
|
34
|
-
@click.option("--end-number", type=str, default=None)
|
|
35
|
-
@click.option("--start-number", type=str, default=None)
|
|
36
|
-
def squash(
|
|
37
|
-
package_name: Optional[str],
|
|
38
|
-
end_number: Optional[str],
|
|
39
|
-
start_number: Optional[str],
|
|
40
|
-
):
|
|
41
|
-
"""Squash migrations."""
|
|
42
|
-
from lamindb_setup._migrate import migrate
|
|
43
|
-
|
|
44
|
-
return migrate.squash(
|
|
45
|
-
package_name=package_name,
|
|
46
|
-
migration_nr=end_number,
|
|
47
|
-
start_migration_nr=start_number,
|
|
48
|
-
)
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
import os
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
if os.environ.get("NO_RICH"):
|
|
6
|
+
import click as click
|
|
7
|
+
else:
|
|
8
|
+
import rich_click as click
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@click.group()
|
|
12
|
+
def migrate():
|
|
13
|
+
"""Manage migrations."""
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@migrate.command("create")
|
|
17
|
+
def create():
|
|
18
|
+
"""Create a new migration."""
|
|
19
|
+
from lamindb_setup._migrate import migrate
|
|
20
|
+
|
|
21
|
+
return migrate.create()
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@migrate.command("deploy")
|
|
25
|
+
def deploy():
|
|
26
|
+
"""Deploy migrations."""
|
|
27
|
+
from lamindb_setup._migrate import migrate
|
|
28
|
+
|
|
29
|
+
return migrate.deploy()
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@migrate.command("squash")
|
|
33
|
+
@click.option("--package-name", type=str, default=None)
|
|
34
|
+
@click.option("--end-number", type=str, default=None)
|
|
35
|
+
@click.option("--start-number", type=str, default=None)
|
|
36
|
+
def squash(
|
|
37
|
+
package_name: Optional[str],
|
|
38
|
+
end_number: Optional[str],
|
|
39
|
+
start_number: Optional[str],
|
|
40
|
+
):
|
|
41
|
+
"""Squash migrations."""
|
|
42
|
+
from lamindb_setup._migrate import migrate
|
|
43
|
+
|
|
44
|
+
return migrate.squash(
|
|
45
|
+
package_name=package_name,
|
|
46
|
+
migration_nr=end_number,
|
|
47
|
+
start_migration_nr=start_number,
|
|
48
|
+
)
|
lamin_cli/_save.py
CHANGED
|
@@ -1,111 +1,119 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
from pathlib import Path
|
|
3
|
-
from typing import
|
|
4
|
-
import lamindb_setup as ln_setup
|
|
5
|
-
from lamin_utils import logger
|
|
6
|
-
import re
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
def get_stem_uid_and_version_from_file(
|
|
10
|
-
file_path: Path,
|
|
11
|
-
) -> tuple[str | None, str | None, str | None]:
|
|
12
|
-
# line-by-line matching might be faster, but let's go with this for now
|
|
13
|
-
with open(file_path) as file:
|
|
14
|
-
content = file.read()
|
|
15
|
-
|
|
16
|
-
if file_path.suffix == ".py":
|
|
17
|
-
uid_pattern = re.compile(r'\.context\.uid\s*=\s*["\']([^"\']+)["\']')
|
|
18
|
-
stem_uid_pattern = re.compile(
|
|
19
|
-
r'\.transform\.stem_uid\s*=\s*["\']([^"\']+)["\']'
|
|
20
|
-
)
|
|
21
|
-
version_pattern = re.compile(r'\.transform\.version\s*=\s*["\']([^"\']+)["\']')
|
|
22
|
-
elif file_path.suffix == ".ipynb":
|
|
23
|
-
uid_pattern = re.compile(r'\.context\.uid\s*=\s*\\["\']([^"\']+)\\["\']')
|
|
24
|
-
stem_uid_pattern = re.compile(
|
|
25
|
-
r'\.transform\.stem_uid\s*=\s*\\["\']([^"\']+)\\["\']'
|
|
26
|
-
)
|
|
27
|
-
version_pattern = re.compile(
|
|
28
|
-
r'\.transform\.version\s*=\s*\\["\']([^"\']+)\\["\']'
|
|
29
|
-
)
|
|
30
|
-
else:
|
|
31
|
-
raise ValueError("Only .py and .ipynb files are supported.")
|
|
32
|
-
|
|
33
|
-
# Search for matches in the entire file content
|
|
34
|
-
uid_match = uid_pattern.search(content)
|
|
35
|
-
stem_uid_match = stem_uid_pattern.search(content)
|
|
36
|
-
version_match = version_pattern.search(content)
|
|
37
|
-
|
|
38
|
-
# Extract values if matches are found
|
|
39
|
-
uid = uid_match.group(1) if uid_match else None
|
|
40
|
-
stem_uid = stem_uid_match.group(1) if stem_uid_match else None
|
|
41
|
-
version = version_match.group(1) if version_match else None
|
|
42
|
-
|
|
43
|
-
if uid is None and (stem_uid is None or version is None):
|
|
44
|
-
raise SystemExit(
|
|
45
|
-
"ln.context.uid isn't"
|
|
46
|
-
f" set in {file_path}\nCall ln.context.track() and copy/paste the output"
|
|
47
|
-
" into the notebook"
|
|
48
|
-
)
|
|
49
|
-
return uid, stem_uid, version
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
def save_from_filepath_cli(
|
|
53
|
-
filepath: Union[str, Path],
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import Union
|
|
4
|
+
import lamindb_setup as ln_setup
|
|
5
|
+
from lamin_utils import logger
|
|
6
|
+
import re
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def get_stem_uid_and_version_from_file(
|
|
10
|
+
file_path: Path,
|
|
11
|
+
) -> tuple[str | None, str | None, str | None]:
|
|
12
|
+
# line-by-line matching might be faster, but let's go with this for now
|
|
13
|
+
with open(file_path) as file:
|
|
14
|
+
content = file.read()
|
|
15
|
+
|
|
16
|
+
if file_path.suffix == ".py":
|
|
17
|
+
uid_pattern = re.compile(r'\.context\.uid\s*=\s*["\']([^"\']+)["\']')
|
|
18
|
+
stem_uid_pattern = re.compile(
|
|
19
|
+
r'\.transform\.stem_uid\s*=\s*["\']([^"\']+)["\']'
|
|
20
|
+
)
|
|
21
|
+
version_pattern = re.compile(r'\.transform\.version\s*=\s*["\']([^"\']+)["\']')
|
|
22
|
+
elif file_path.suffix == ".ipynb":
|
|
23
|
+
uid_pattern = re.compile(r'\.context\.uid\s*=\s*\\["\']([^"\']+)\\["\']')
|
|
24
|
+
stem_uid_pattern = re.compile(
|
|
25
|
+
r'\.transform\.stem_uid\s*=\s*\\["\']([^"\']+)\\["\']'
|
|
26
|
+
)
|
|
27
|
+
version_pattern = re.compile(
|
|
28
|
+
r'\.transform\.version\s*=\s*\\["\']([^"\']+)\\["\']'
|
|
29
|
+
)
|
|
30
|
+
else:
|
|
31
|
+
raise ValueError("Only .py and .ipynb files are supported.")
|
|
32
|
+
|
|
33
|
+
# Search for matches in the entire file content
|
|
34
|
+
uid_match = uid_pattern.search(content)
|
|
35
|
+
stem_uid_match = stem_uid_pattern.search(content)
|
|
36
|
+
version_match = version_pattern.search(content)
|
|
37
|
+
|
|
38
|
+
# Extract values if matches are found
|
|
39
|
+
uid = uid_match.group(1) if uid_match else None
|
|
40
|
+
stem_uid = stem_uid_match.group(1) if stem_uid_match else None
|
|
41
|
+
version = version_match.group(1) if version_match else None
|
|
42
|
+
|
|
43
|
+
if uid is None and (stem_uid is None or version is None):
|
|
44
|
+
raise SystemExit(
|
|
45
|
+
"ln.context.uid isn't"
|
|
46
|
+
f" set in {file_path}\nCall ln.context.track() and copy/paste the output"
|
|
47
|
+
" into the notebook"
|
|
48
|
+
)
|
|
49
|
+
return uid, stem_uid, version
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def save_from_filepath_cli(
|
|
53
|
+
filepath: Union[str, Path],
|
|
54
|
+
key: str | None,
|
|
55
|
+
description: str | None,
|
|
56
|
+
registry: str | None,
|
|
57
|
+
) -> str | None:
|
|
58
|
+
if not isinstance(filepath, Path):
|
|
59
|
+
filepath = Path(filepath)
|
|
60
|
+
|
|
61
|
+
# this will be gone once we get rid of lamin load or enable loading multiple
|
|
62
|
+
# instances sequentially
|
|
63
|
+
auto_connect_state = ln_setup.settings.auto_connect
|
|
64
|
+
ln_setup.settings.auto_connect = True
|
|
65
|
+
|
|
66
|
+
import lamindb as ln
|
|
67
|
+
from lamindb._finish import save_context_core
|
|
68
|
+
|
|
69
|
+
ln_setup.settings.auto_connect = auto_connect_state
|
|
70
|
+
|
|
71
|
+
if registry is None:
|
|
72
|
+
registry = "transform" if filepath.suffix in {".py", ".ipynb"} else "artifact"
|
|
73
|
+
|
|
74
|
+
if registry == "artifact":
|
|
75
|
+
ln.settings.creation.artifact_silence_missing_run_warning = True
|
|
76
|
+
if key is None and description is None:
|
|
77
|
+
logger.error("Please pass a key or description via --key or --description")
|
|
78
|
+
return "missing-key-or-description"
|
|
79
|
+
artifact = ln.Artifact(filepath, key=key, description=description).save()
|
|
80
|
+
logger.important(f"saved: {artifact}")
|
|
81
|
+
logger.important(f"storage path: {artifact.path}")
|
|
82
|
+
if ln_setup.settings.storage.type == "s3":
|
|
83
|
+
logger.important(f"storage url: {artifact.path.to_url()}")
|
|
84
|
+
if ln_setup.settings.instance.is_remote:
|
|
85
|
+
slug = ln_setup.settings.instance.slug
|
|
86
|
+
logger.important(f"go to: https://lamin.ai/{slug}/artifact/{artifact.uid}")
|
|
87
|
+
return None
|
|
88
|
+
elif registry == "transform":
|
|
89
|
+
# consider notebooks & scripts a transform
|
|
90
|
+
uid, stem_uid, transform_version = get_stem_uid_and_version_from_file(filepath)
|
|
91
|
+
if uid is not None:
|
|
92
|
+
transform = ln.Transform.filter(uid=uid).one_or_none()
|
|
93
|
+
if transform is None:
|
|
94
|
+
logger.error(
|
|
95
|
+
f"Did not find uid '{uid}'"
|
|
96
|
+
" in Transform registry. Did you run ln.context.track()?"
|
|
97
|
+
)
|
|
98
|
+
return "not-tracked-in-transform-registry"
|
|
99
|
+
else:
|
|
100
|
+
transform = ln.Transform.get(
|
|
101
|
+
uid__startswith=stem_uid, version=transform_version
|
|
102
|
+
)
|
|
103
|
+
# latest run of this transform by user
|
|
104
|
+
run = ln.Run.filter(transform=transform).order_by("-started_at").first()
|
|
105
|
+
if run.created_by.id != ln_setup.settings.user.id:
|
|
106
|
+
response = input(
|
|
107
|
+
"You are trying to save a transform created by another user: Source and"
|
|
108
|
+
" report files will be tagged with *your* user id. Proceed? (y/n)"
|
|
109
|
+
)
|
|
110
|
+
if response != "y":
|
|
111
|
+
return "aborted-save-notebook-created-by-different-user"
|
|
112
|
+
return save_context_core(
|
|
113
|
+
run=run,
|
|
114
|
+
transform=transform,
|
|
115
|
+
filepath=filepath,
|
|
116
|
+
from_cli=True,
|
|
117
|
+
)
|
|
118
|
+
else:
|
|
119
|
+
raise SystemExit("Allowed values for '--registry' are: 'artifact', 'transform'")
|