lamin_cli 0.16.0__tar.gz → 0.16.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 (27) hide show
  1. {lamin_cli-0.16.0 → lamin_cli-0.16.2}/PKG-INFO +1 -1
  2. lamin_cli-0.16.2/lamin_cli/__init__.py +3 -0
  3. {lamin_cli-0.16.0 → lamin_cli-0.16.2}/lamin_cli/__main__.py +12 -5
  4. {lamin_cli-0.16.0 → lamin_cli-0.16.2}/lamin_cli/_save.py +30 -19
  5. {lamin_cli-0.16.0 → lamin_cli-0.16.2}/tests/notebooks/with-title-and-initialized-consecutive.ipynb +2 -3
  6. {lamin_cli-0.16.0 → lamin_cli-0.16.2}/tests/notebooks/with-title-and-initialized-non-consecutive.ipynb +1 -1
  7. {lamin_cli-0.16.0 → lamin_cli-0.16.2}/tests/scripts/run-track-and-finish-sync-git.py +3 -4
  8. {lamin_cli-0.16.0 → lamin_cli-0.16.2}/tests/scripts/run-track-and-finish.py +3 -4
  9. {lamin_cli-0.16.0 → lamin_cli-0.16.2}/tests/test_save_notebooks.py +17 -16
  10. {lamin_cli-0.16.0 → lamin_cli-0.16.2}/tests/test_save_scripts.py +22 -22
  11. lamin_cli-0.16.0/lamin_cli/__init__.py +0 -3
  12. {lamin_cli-0.16.0 → lamin_cli-0.16.2}/.github/workflows/doc-changes.yml +0 -0
  13. {lamin_cli-0.16.0 → lamin_cli-0.16.2}/.gitignore +0 -0
  14. {lamin_cli-0.16.0 → lamin_cli-0.16.2}/.pre-commit-config.yaml +0 -0
  15. {lamin_cli-0.16.0 → lamin_cli-0.16.2}/README.md +0 -0
  16. {lamin_cli-0.16.0 → lamin_cli-0.16.2}/lamin_cli/_cache.py +0 -0
  17. {lamin_cli-0.16.0 → lamin_cli-0.16.2}/lamin_cli/_get.py +0 -0
  18. {lamin_cli-0.16.0 → lamin_cli-0.16.2}/lamin_cli/_migration.py +0 -0
  19. {lamin_cli-0.16.0 → lamin_cli-0.16.2}/pyproject.toml +0 -0
  20. {lamin_cli-0.16.0 → lamin_cli-0.16.2}/tests/conftest.py +0 -0
  21. {lamin_cli-0.16.0 → lamin_cli-0.16.2}/tests/notebooks/not-initialized.ipynb +0 -0
  22. {lamin_cli-0.16.0 → lamin_cli-0.16.2}/tests/scripts/merely-import-lamindb.py +0 -0
  23. {lamin_cli-0.16.0 → lamin_cli-0.16.2}/tests/test_cli.py +0 -0
  24. {lamin_cli-0.16.0 → lamin_cli-0.16.2}/tests/test_get.py +0 -0
  25. {lamin_cli-0.16.0 → lamin_cli-0.16.2}/tests/test_migrate.py +0 -0
  26. {lamin_cli-0.16.0 → lamin_cli-0.16.2}/tests/test_multi_process.py +0 -0
  27. {lamin_cli-0.16.0 → lamin_cli-0.16.2}/tests/test_save_files.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: lamin_cli
3
- Version: 0.16.0
3
+ Version: 0.16.2
4
4
  Summary: Lamin CLI.
5
5
  Author-email: Lamin Labs <open-source@lamin.ai>
6
6
  Description-Content-Type: text/markdown
@@ -0,0 +1,3 @@
1
+ """Lamin CLI."""
2
+
3
+ __version__ = "0.16.2"
@@ -5,6 +5,7 @@ from collections import OrderedDict
5
5
  import inspect
6
6
  from importlib.metadata import PackageNotFoundError, version
7
7
  from typing import Optional, Mapping
8
+ from functools import wraps
8
9
 
9
10
  # https://github.com/ewels/rich-click/issues/19
10
11
  # Otherwise rich-click takes over the formatting.
@@ -60,12 +61,18 @@ else:
60
61
  ]
61
62
  }
62
63
 
63
- lamin_group_decorator = click.rich_config(
64
- help_config=click.RichHelpConfiguration(
65
- command_groups=COMMAND_GROUPS,
66
- style_commands_table_column_width_ratio=(1, 13),
64
+ def lamin_group_decorator(f):
65
+ @click.rich_config(
66
+ help_config=click.RichHelpConfiguration(
67
+ command_groups=COMMAND_GROUPS,
68
+ style_commands_table_column_width_ratio=(1, 13),
69
+ )
67
70
  )
68
- )(click.group())
71
+ @click.group()
72
+ @wraps(f)
73
+ def wrapper(*args, **kwargs):
74
+ return f(*args, **kwargs)
75
+ return wrapper
69
76
 
70
77
 
71
78
  from click import Command, Context
@@ -6,17 +6,21 @@ from lamin_utils import logger
6
6
  import re
7
7
 
8
8
 
9
- def get_stem_uid_and_version_from_file(file_path: Path) -> tuple[str, str]:
9
+ def get_stem_uid_and_version_from_file(
10
+ file_path: Path,
11
+ ) -> tuple[str | None, str | None, str | None]:
10
12
  # line-by-line matching might be faster, but let's go with this for now
11
13
  with open(file_path) as file:
12
14
  content = file.read()
13
15
 
14
16
  if file_path.suffix == ".py":
17
+ uid_pattern = re.compile(r'\.context\.uid\s*=\s*["\']([^"\']+)["\']')
15
18
  stem_uid_pattern = re.compile(
16
19
  r'\.transform\.stem_uid\s*=\s*["\']([^"\']+)["\']'
17
20
  )
18
21
  version_pattern = re.compile(r'\.transform\.version\s*=\s*["\']([^"\']+)["\']')
19
22
  elif file_path.suffix == ".ipynb":
23
+ uid_pattern = re.compile(r'\.context\.uid\s*=\s*\\["\']([^"\']+)\\["\']')
20
24
  stem_uid_pattern = re.compile(
21
25
  r'\.transform\.stem_uid\s*=\s*\\["\']([^"\']+)\\["\']'
22
26
  )
@@ -27,20 +31,22 @@ def get_stem_uid_and_version_from_file(file_path: Path) -> tuple[str, str]:
27
31
  raise ValueError("Only .py and .ipynb files are supported.")
28
32
 
29
33
  # Search for matches in the entire file content
34
+ uid_match = uid_pattern.search(content)
30
35
  stem_uid_match = stem_uid_pattern.search(content)
31
36
  version_match = version_pattern.search(content)
32
37
 
33
38
  # Extract values if matches are found
39
+ uid = uid_match.group(1) if uid_match else None
34
40
  stem_uid = stem_uid_match.group(1) if stem_uid_match else None
35
41
  version = version_match.group(1) if version_match else None
36
42
 
37
- if stem_uid is None or version is None:
43
+ if uid is None and (stem_uid is None or version is None):
38
44
  raise SystemExit(
39
- "ln.settings.transform.stem_uid and ln.settings.transform.version aren't"
40
- f" set in {file_path}\nCall ln.track() and copy/paste the output into the"
41
- " notebook"
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"
42
48
  )
43
- return stem_uid, version
49
+ return uid, stem_uid, version
44
50
 
45
51
 
46
52
  def save_from_filepath_cli(
@@ -55,7 +61,7 @@ def save_from_filepath_cli(
55
61
  ln_setup.settings.auto_connect = True
56
62
 
57
63
  import lamindb as ln
58
- from lamindb._finish import save_run_context_core
64
+ from lamindb._finish import save_context_core
59
65
 
60
66
  ln_setup.settings.auto_connect = auto_connect_state
61
67
 
@@ -75,17 +81,22 @@ def save_from_filepath_cli(
75
81
  return None
76
82
  else:
77
83
  # consider notebooks & scripts a transform
78
- stem_uid, transform_version = get_stem_uid_and_version_from_file(filepath)
79
- # the corresponding transform family in the transform table
80
- transform_family = ln.Transform.filter(uid__startswith=stem_uid).all()
81
- if len(transform_family) == 0:
82
- logger.error(
83
- f"Did not find stem uid '{stem_uid}'"
84
- " in Transform registry. Did you run ln.track()?"
85
- )
86
- return "not-tracked-in-transform-registry"
87
- # the specific version
88
- transform = transform_family.filter(version=transform_version).one()
84
+ uid, stem_uid, transform_version = get_stem_uid_and_version_from_file(filepath)
85
+ if uid is not None:
86
+ transform = ln.Transform.filter(uid=uid).one_or_none()
87
+ if transform is None:
88
+ logger.error(
89
+ f"Did not find uid '{uid}'"
90
+ " in Transform registry. Did you run ln.context.track()?"
91
+ )
92
+ return "not-tracked-in-transform-registry"
93
+ # refactor this, save_context_core should not depend on transform_family
94
+ transform_family = transform.versions
95
+ else:
96
+ # the corresponding transform family in the transform table
97
+ transform_family = ln.Transform.filter(uid__startswith=stem_uid).all()
98
+ # the specific version
99
+ transform = transform_family.filter(version=transform_version).one()
89
100
  # latest run of this transform by user
90
101
  run = ln.Run.filter(transform=transform).order_by("-started_at").first()
91
102
  if run.created_by.id != ln_setup.settings.user.id:
@@ -95,7 +106,7 @@ def save_from_filepath_cli(
95
106
  )
96
107
  if response != "y":
97
108
  return "aborted-save-notebook-created-by-different-user"
98
- return save_run_context_core(
109
+ return save_context_core(
99
110
  run=run,
100
111
  transform=transform,
101
112
  filepath=filepath,
@@ -66,9 +66,8 @@
66
66
  }
67
67
  ],
68
68
  "source": [
69
- "ln.settings.transform.stem_uid = \"hlsFXswrJjtt\"\n",
70
- "ln.settings.transform.version = \"1\"\n",
71
- "ln.track()"
69
+ "ln.context.uid = \"hlsFXswrJjtt0000\"\n",
70
+ "ln.context.track()"
72
71
  ]
73
72
  },
74
73
  {
@@ -67,7 +67,7 @@
67
67
  "source": [
68
68
  "ln.settings.transform.stem_uid = \"HDMGkxN9rgFA\"\n",
69
69
  "ln.settings.transform.version = \"1\"\n",
70
- "ln.track()"
70
+ "ln.context.track()"
71
71
  ]
72
72
  }
73
73
  ],
@@ -1,16 +1,15 @@
1
1
  import lamindb as ln
2
2
 
3
3
  ln.settings.sync_git_repo = "https://github.com/laminlabs/lamin-cli"
4
- ln.settings.transform.stem_uid = "m5uCHTTpJnjQ"
5
- ln.settings.transform.version = "1"
6
- ln.settings.transform.name = "My good script"
4
+ ln.context.uid = "m5uCHTTpJnjQ0000"
5
+ ln.context.name = "My good script"
7
6
 
8
7
 
9
8
  if __name__ == "__main__":
10
9
  # we're using new_run here to mock the notebook situation
11
10
  # and cover the look up of an existing run in the tests
12
11
  # new_run = True is trivial
13
- ln.track(new_run=False)
12
+ ln.context.track(new_run=False)
14
13
 
15
14
  print("hello!")
16
15
 
@@ -1,14 +1,13 @@
1
1
  import lamindb as ln
2
2
 
3
- ln.settings.transform.stem_uid = "VFYCIuaw2GsX"
4
- ln.settings.transform.version = "1"
5
- ln.settings.transform.name = "My good script 2"
3
+ ln.context.uid = "VFYCIuaw2GsX0000"
4
+ ln.context.name = "My good script 2"
6
5
 
7
6
  if __name__ == "__main__":
8
7
  # we're using new_run here to mock the notebook situation
9
8
  # and cover the look up of an existing run in the tests
10
9
  # new_run = True is trivial
11
- ln.track(new_run=False)
10
+ ln.context.track(new_run=False)
12
11
 
13
12
  print("hello!")
14
13
 
@@ -21,7 +21,7 @@ def test_save_not_initialized():
21
21
  )
22
22
  assert result.returncode == 1
23
23
  assert (
24
- "Call ln.track() and copy/paste the output into the notebook"
24
+ "Call ln.context.track() and copy/paste the output into the notebook"
25
25
  in result.stderr.decode()
26
26
  )
27
27
 
@@ -62,10 +62,10 @@ def test_save_consecutive():
62
62
  env = os.environ
63
63
  env["LAMIN_TESTING"] = "true"
64
64
 
65
- transform = ln.Transform.filter(uid="hlsFXswrJjtt5zKv").one_or_none()
65
+ transform = ln.Transform.filter(uid="hlsFXswrJjtt0000").one_or_none()
66
66
  assert transform is None
67
67
 
68
- # let's try to save a notebook for which `ln.track()` was never run
68
+ # let's try to save a notebook for which `ln.context.track()` was never run
69
69
  result = subprocess.run(
70
70
  f"lamin save {notebook_path}",
71
71
  shell=True,
@@ -73,13 +73,13 @@ def test_save_consecutive():
73
73
  env=env,
74
74
  )
75
75
  assert result.returncode == 1
76
- assert "Did not find stem uid 'hlsFXswrJjtt'" in result.stdout.decode()
76
+ assert "Did not find uid 'hlsFXswrJjtt0000'" in result.stdout.decode()
77
77
 
78
- # now, let's re-run this notebook so that ln.track() is actually run
78
+ # now, let's re-run this notebook so that ln.context.track() is actually run
79
79
  nbproject_test.execute_notebooks(notebook_path, print_outputs=True)
80
80
 
81
81
  # now, there is a transform record, but we're missing all artifacts
82
- transform = ln.Transform.filter(uid="hlsFXswrJjtt5zKv").one_or_none()
82
+ transform = ln.Transform.filter(uid="hlsFXswrJjtt0000").one_or_none()
83
83
  assert transform is not None
84
84
  assert transform.latest_run.report is None
85
85
  assert transform._source_code_artifact is None
@@ -95,11 +95,11 @@ def test_save_consecutive():
95
95
  assert result.returncode == 0
96
96
 
97
97
  # now, we have the associated artifacts
98
- transform = ln.Transform.filter(uid="hlsFXswrJjtt5zKv").one_or_none()
98
+ transform = ln.Transform.filter(uid="hlsFXswrJjtt0000").one_or_none()
99
99
  assert transform is not None
100
100
  assert transform.latest_run.report.path.exists()
101
101
  assert transform.latest_run.report.path == transform.latest_run.report.path
102
- assert transform._source_code_artifact.hash == "5nc_HMjPvT9n26OWrjq6uQ"
102
+ assert transform._source_code_artifact.hash == "EQrdZpS-fPaz5MKk_g02AA"
103
103
  assert transform.latest_run.environment.path.exists()
104
104
  assert transform._source_code_artifact.path.exists()
105
105
 
@@ -114,8 +114,8 @@ def test_save_consecutive():
114
114
  # try re-running - it fails
115
115
  with pytest.raises(CellExecutionError) as error:
116
116
  nbproject_test.execute_notebooks(notebook_path, print_outputs=True)
117
- print(error.exconly())
118
- assert "UpdateTransformSettings" in error.exconly()
117
+ # print(error.exconly())
118
+ assert "UpdateContext" in error.exconly()
119
119
 
120
120
  # try re-saving - it works but will issue an interactive warning dialogue
121
121
  # that clarifies that the user is about to re-save the notebook
@@ -127,29 +127,30 @@ def test_save_consecutive():
127
127
  )
128
128
  assert result.returncode == 0
129
129
  # the source code is overwritten with the edits, reflected in a new hash
130
- transform = ln.Transform.get("hlsFXswrJjtt5zKv")
130
+ transform = ln.Transform.get("hlsFXswrJjtt0000")
131
131
  assert transform.latest_run.report.path.exists()
132
132
  assert transform.latest_run.report.path == transform.latest_run.report.path
133
- assert transform._source_code_artifact.hash == "ocLybD0Hv_L3NhhXgTyQcw"
133
+ assert transform._source_code_artifact.hash == "DMVEHVQqmY3ektOg2KtKKA"
134
134
  assert transform.latest_run.environment.path.exists()
135
135
  assert transform._source_code_artifact.path.exists()
136
136
 
137
137
  # get the the source code via command line
138
138
  result = subprocess.run(
139
139
  "lamin get"
140
- f" https://lamin.ai/{ln.setup.settings.user.handle}/laminci-unit-tests/transform/hlsFXswrJjtt5zKv", # noqa
140
+ f" https://lamin.ai/{ln.setup.settings.user.handle}/laminci-unit-tests/transform/hlsFXswrJjtt0000", # noqa
141
141
  shell=True,
142
142
  capture_output=True,
143
143
  )
144
- print(result.stderr.decode())
144
+ # print(result.stderr.decode())
145
145
  assert result.returncode == 0
146
146
 
147
147
  # now, assume the user renames the notebook
148
148
  new_path = notebook_path.with_name("new_name.ipynb")
149
149
  os.system(f"cp {notebook_path} {new_path}")
150
150
 
151
- # upon re-running it, the user is asked whether it's still the same notebook
151
+ # upon re-running it, the user is asked to create a new stem uid
152
152
  with pytest.raises(CellExecutionError) as error:
153
153
  nbproject_test.execute_notebooks(new_path, print_outputs=True)
154
154
 
155
- assert "Please update your transform settings as follows" in error.exconly()
155
+ print(error.exconly())
156
+ assert "Notebook filename changed." in error.exconly()
@@ -19,9 +19,9 @@ def test_run_save_cache():
19
19
  shell=True,
20
20
  capture_output=True,
21
21
  )
22
- print(result.stderr.decode())
22
+ # print(result.stdout.decode())
23
23
  assert result.returncode == 1
24
- assert "Did you run ln.track()" in result.stdout.decode()
24
+ assert "Did you run ln.context.track()?" in result.stdout.decode()
25
25
 
26
26
  # run the script
27
27
  result = subprocess.run(
@@ -29,15 +29,15 @@ def test_run_save_cache():
29
29
  shell=True,
30
30
  capture_output=True,
31
31
  )
32
- print(result.stdout.decode())
33
- print(result.stderr.decode())
32
+ # print(result.stdout.decode())
33
+ # print(result.stderr.decode())
34
34
  assert result.returncode == 0
35
- assert "saved: Transform" in result.stdout.decode()
36
- assert "m5uCHTTpJnjQ5zKv" in result.stdout.decode()
37
- assert "saved: Run" in result.stdout.decode()
35
+ assert "created Transform" in result.stdout.decode()
36
+ assert "m5uCHTTpJnjQ0000" in result.stdout.decode()
37
+ assert "created Run" in result.stdout.decode()
38
38
 
39
39
  transform = ln.Transform.get("m5uCHTTpJnjQ")
40
- assert transform._source_code_artifact.hash == "T1zmmTJyeEpBxjaHcHcZdg"
40
+ assert transform._source_code_artifact.hash == "Cwk0OPOyUH5nzTiU2ISlDQ"
41
41
  assert transform.latest_run.environment.path.exists()
42
42
  assert transform._source_code_artifact.path.exists()
43
43
 
@@ -48,12 +48,12 @@ def test_run_save_cache():
48
48
  capture_output=True,
49
49
  env=env,
50
50
  )
51
- print(result.stdout.decode())
52
- print(result.stderr.decode())
51
+ # print(result.stdout.decode())
52
+ # print(result.stderr.decode())
53
53
  assert result.returncode == 0
54
- assert "loaded: Transform" in result.stdout.decode()
55
- assert "m5uCHTTpJnjQ5zKv" in result.stdout.decode()
56
- assert "loaded: Run" in result.stdout.decode()
54
+ assert "loaded Transform" in result.stdout.decode()
55
+ assert "m5uCHTTpJnjQ0000" in result.stdout.decode()
56
+ assert "loaded Run" in result.stdout.decode()
57
57
  assert "source code is already saved" in result.stdout.decode()
58
58
 
59
59
  # you can re-save the script
@@ -63,8 +63,8 @@ def test_run_save_cache():
63
63
  capture_output=True,
64
64
  env=env,
65
65
  )
66
- print(result.stdout.decode())
67
- print(result.stderr.decode())
66
+ # print(result.stdout.decode())
67
+ # print(result.stderr.decode())
68
68
  assert result.returncode == 0
69
69
  assert "source code is already saved" in result.stdout.decode()
70
70
  assert "run.environment is already saved" in result.stdout.decode()
@@ -73,15 +73,15 @@ def test_run_save_cache():
73
73
  content = filepath.read_text() + "\n # edited"
74
74
  filepath.write_text(content)
75
75
 
76
- # re-run the script
76
+ # re-run the script without commiting
77
77
  result = subprocess.run(
78
78
  f"python {filepath}",
79
79
  shell=True,
80
80
  capture_output=True,
81
81
  env=env,
82
82
  )
83
- print(result.stdout.decode())
84
- print(result.stderr.decode())
83
+ # print(result.stdout.decode())
84
+ # print(result.stderr.decode())
85
85
  assert result.returncode == 1
86
86
  assert "Did not find blob hash" in result.stderr.decode()
87
87
 
@@ -101,15 +101,15 @@ def test_run_save_cache():
101
101
  capture_output=True,
102
102
  env=env,
103
103
  )
104
- print(result.stdout.decode())
105
- print(result.stderr.decode())
104
+ # print(result.stdout.decode())
105
+ # print(result.stderr.decode())
106
106
  assert result.returncode == 1
107
- assert "Please update your transform settings as follows" in result.stderr.decode()
107
+ assert "Source code changed, bump version by setting" in result.stderr.decode()
108
108
 
109
109
  # try to get the the source code via command line
110
110
  result = subprocess.run(
111
111
  "lamin get"
112
- f" https://lamin.ai/{settings.user.handle}/laminci-unit-tests/transform/m5uCHTTpJnjQ5zKv", # noqa
112
+ f" https://lamin.ai/{settings.user.handle}/laminci-unit-tests/transform/m5uCHTTpJnjQ0000", # noqa
113
113
  shell=True,
114
114
  capture_output=True,
115
115
  )
@@ -1,3 +0,0 @@
1
- """Lamin CLI."""
2
-
3
- __version__ = "0.16.0"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes