lamin_cli 0.21.0__tar.gz → 0.21.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.
- {lamin_cli-0.21.0 → lamin_cli-0.21.2}/PKG-INFO +2 -2
- lamin_cli-0.21.2/lamin_cli/__init__.py +3 -0
- {lamin_cli-0.21.0 → lamin_cli-0.21.2}/lamin_cli/_save.py +13 -7
- {lamin_cli-0.21.0 → lamin_cli-0.21.2}/pyproject.toml +1 -1
- lamin_cli-0.21.2/tests/test_parse_uid_from_code.py +122 -0
- {lamin_cli-0.21.0 → lamin_cli-0.21.2}/tests/test_save_notebooks.py +1 -1
- lamin_cli-0.21.0/lamin_cli/__init__.py +0 -3
- {lamin_cli-0.21.0 → lamin_cli-0.21.2}/.github/workflows/doc-changes.yml +0 -0
- {lamin_cli-0.21.0 → lamin_cli-0.21.2}/.gitignore +0 -0
- {lamin_cli-0.21.0 → lamin_cli-0.21.2}/.pre-commit-config.yaml +0 -0
- {lamin_cli-0.21.0 → lamin_cli-0.21.2}/LICENSE +0 -0
- {lamin_cli-0.21.0 → lamin_cli-0.21.2}/README.md +0 -0
- {lamin_cli-0.21.0 → lamin_cli-0.21.2}/lamin_cli/__main__.py +0 -0
- {lamin_cli-0.21.0 → lamin_cli-0.21.2}/lamin_cli/_cache.py +0 -0
- {lamin_cli-0.21.0 → lamin_cli-0.21.2}/lamin_cli/_load.py +0 -0
- {lamin_cli-0.21.0 → lamin_cli-0.21.2}/lamin_cli/_migration.py +0 -0
- {lamin_cli-0.21.0 → lamin_cli-0.21.2}/lamin_cli/_settings.py +0 -0
- {lamin_cli-0.21.0 → lamin_cli-0.21.2}/tests/conftest.py +0 -0
- {lamin_cli-0.21.0 → lamin_cli-0.21.2}/tests/notebooks/not-initialized.ipynb +0 -0
- {lamin_cli-0.21.0 → lamin_cli-0.21.2}/tests/notebooks/with-title-and-initialized-consecutive.ipynb +0 -0
- {lamin_cli-0.21.0 → lamin_cli-0.21.2}/tests/notebooks/with-title-and-initialized-non-consecutive.ipynb +0 -0
- {lamin_cli-0.21.0 → lamin_cli-0.21.2}/tests/scripts/merely-import-lamindb.py +0 -0
- {lamin_cli-0.21.0 → lamin_cli-0.21.2}/tests/scripts/run-track-and-finish-sync-git.py +0 -0
- {lamin_cli-0.21.0 → lamin_cli-0.21.2}/tests/scripts/run-track-and-finish.py +0 -0
- {lamin_cli-0.21.0 → lamin_cli-0.21.2}/tests/scripts/run-track-with-params.py +0 -0
- {lamin_cli-0.21.0 → lamin_cli-0.21.2}/tests/scripts/run-track.R +0 -0
- {lamin_cli-0.21.0 → lamin_cli-0.21.2}/tests/scripts/run-track.qmd +0 -0
- {lamin_cli-0.21.0 → lamin_cli-0.21.2}/tests/test_cli.py +0 -0
- {lamin_cli-0.21.0 → lamin_cli-0.21.2}/tests/test_load.py +0 -0
- {lamin_cli-0.21.0 → lamin_cli-0.21.2}/tests/test_migrate.py +0 -0
- {lamin_cli-0.21.0 → lamin_cli-0.21.2}/tests/test_multi_process.py +0 -0
- {lamin_cli-0.21.0 → lamin_cli-0.21.2}/tests/test_save_files.py +0 -0
- {lamin_cli-0.21.0 → lamin_cli-0.21.2}/tests/test_save_r_code.py +0 -0
- {lamin_cli-0.21.0 → lamin_cli-0.21.2}/tests/test_save_scripts.py +0 -0
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: lamin_cli
|
|
3
|
-
Version: 0.21.
|
|
3
|
+
Version: 0.21.2
|
|
4
4
|
Summary: Lamin CLI.
|
|
5
5
|
Author-email: Lamin Labs <open-source@lamin.ai>
|
|
6
6
|
Description-Content-Type: text/markdown
|
|
7
|
-
Requires-Dist: lamindb_setup==0.
|
|
7
|
+
Requires-Dist: lamindb_setup==0.81.0
|
|
8
8
|
Requires-Dist: rich-click>=1.7
|
|
9
9
|
Project-URL: Home, https://github.com/laminlabs/lamin-cli
|
|
10
10
|
|
|
@@ -10,7 +10,10 @@ def parse_uid_from_code(
|
|
|
10
10
|
content: str, suffix: str
|
|
11
11
|
) -> tuple[str | None, str | None, str | None]:
|
|
12
12
|
if suffix == ".py":
|
|
13
|
-
track_pattern = re.compile(
|
|
13
|
+
track_pattern = re.compile(
|
|
14
|
+
r'ln\.track\(\s*(?:transform\s*=\s*)?(["\'])([a-zA-Z0-9]{16})\1'
|
|
15
|
+
)
|
|
16
|
+
# backward compat
|
|
14
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*["\']([^"\']+)["\']'
|
|
@@ -18,8 +21,9 @@ def parse_uid_from_code(
|
|
|
18
21
|
version_pattern = re.compile(r'\.transform\.version\s*=\s*["\']([^"\']+)["\']')
|
|
19
22
|
elif suffix == ".ipynb":
|
|
20
23
|
track_pattern = re.compile(
|
|
21
|
-
r'ln\.track\(\s*(?:
|
|
24
|
+
r'ln\.track\(\s*(?:transform\s*=\s*)?(?:\\"|\')([a-zA-Z0-9]{16})(?:\\"|\')'
|
|
22
25
|
)
|
|
26
|
+
# backward compat
|
|
23
27
|
uid_pattern = re.compile(r'\.context\.uid\s*=\s*\\["\']([^"\']+)\\["\']')
|
|
24
28
|
stem_uid_pattern = re.compile(
|
|
25
29
|
r'\.transform\.stem_uid\s*=\s*\\["\']([^"\']+)\\["\']'
|
|
@@ -28,7 +32,9 @@ def parse_uid_from_code(
|
|
|
28
32
|
r'\.transform\.version\s*=\s*\\["\']([^"\']+)\\["\']'
|
|
29
33
|
)
|
|
30
34
|
elif suffix in {".R", ".qmd", ".Rmd"}:
|
|
31
|
-
track_pattern = re.compile(
|
|
35
|
+
track_pattern = re.compile(
|
|
36
|
+
r'track\(\s*(?:transform\s*=\s*)?([\'"])([a-zA-Z0-9]{16})\1'
|
|
37
|
+
)
|
|
32
38
|
uid_pattern = None
|
|
33
39
|
stem_uid_pattern = None
|
|
34
40
|
version_pattern = None
|
|
@@ -40,7 +46,8 @@ def parse_uid_from_code(
|
|
|
40
46
|
|
|
41
47
|
# Search for matches in the entire file content
|
|
42
48
|
uid_match = track_pattern.search(content)
|
|
43
|
-
|
|
49
|
+
group_index = 1 if suffix == ".ipynb" else 2
|
|
50
|
+
uid = uid_match.group(group_index) if uid_match else None
|
|
44
51
|
stem_uid = None
|
|
45
52
|
version = None
|
|
46
53
|
|
|
@@ -55,10 +62,9 @@ def parse_uid_from_code(
|
|
|
55
62
|
version = version_match.group(1) if version_match else None
|
|
56
63
|
|
|
57
64
|
if uid is None and (stem_uid is None or version is None):
|
|
58
|
-
target = "script" if suffix
|
|
65
|
+
target = "script" if suffix in {".py", ".R"} else "notebook"
|
|
59
66
|
raise SystemExit(
|
|
60
|
-
"Cannot infer transform uid."
|
|
61
|
-
f"\nCall `ln.track()` and copy/paste the output into the {target}."
|
|
67
|
+
f"Cannot infer transform uid. Did you run `ln.track()` in your {target}?"
|
|
62
68
|
)
|
|
63
69
|
|
|
64
70
|
return uid, stem_uid, version
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
from lamin_cli._save import parse_uid_from_code
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def test_python_track_pattern():
|
|
6
|
+
valid_cases = [
|
|
7
|
+
# Basic cases with 16 character requirement
|
|
8
|
+
('ln.track("abcd123456789xyz")', "abcd123456789xyz"),
|
|
9
|
+
("ln.track('abcd123456789xyz')", "abcd123456789xyz"),
|
|
10
|
+
# With transform parameter
|
|
11
|
+
('ln.track(transform="abcd123456789xyz")', "abcd123456789xyz"),
|
|
12
|
+
("ln.track(transform='abcd123456789xyz')", "abcd123456789xyz"),
|
|
13
|
+
# With whitespace variations
|
|
14
|
+
('ln.track( "abcd123456789xyz" )', "abcd123456789xyz"),
|
|
15
|
+
('ln.track( transform ="abcd123456789xyz")', "abcd123456789xyz"),
|
|
16
|
+
('ln.track(\n "abcd123456789xyz"\n)', "abcd123456789xyz"),
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
invalid_cases = [
|
|
20
|
+
# Mismatched quotes
|
|
21
|
+
"ln.track(\"abcd123456789xyz')",
|
|
22
|
+
"ln.track('abcd123456789xyz\")",
|
|
23
|
+
# Wrong length
|
|
24
|
+
'ln.track("abc123")', # Too short
|
|
25
|
+
'ln.track("abcd123456789xyz0")', # Too long
|
|
26
|
+
# Invalid characters
|
|
27
|
+
'ln.track("abcd-123456789xyz")', # Contains hyphen
|
|
28
|
+
'ln.track("abcd_123456789xyz")', # Contains underscore
|
|
29
|
+
'ln.track("abcd!123456789xyz")', # Contains special character
|
|
30
|
+
# Old uid parameter
|
|
31
|
+
'ln.track(uid="abcd123456789xyz")',
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
# Test valid cases
|
|
35
|
+
for content, expected_uid in valid_cases:
|
|
36
|
+
uid, _, _ = parse_uid_from_code(content, ".py")
|
|
37
|
+
assert uid == expected_uid, f"Failed for valid content: {content}"
|
|
38
|
+
|
|
39
|
+
# Test invalid cases
|
|
40
|
+
for content in invalid_cases:
|
|
41
|
+
with pytest.raises(SystemExit):
|
|
42
|
+
uid, _, _ = parse_uid_from_code(content, ".py")
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def test_jupyter_track_pattern():
|
|
46
|
+
valid_cases = [
|
|
47
|
+
# Basic cases
|
|
48
|
+
(r"ln.track(\"abcd123456789xyz\")", "abcd123456789xyz"),
|
|
49
|
+
("ln.track('abcd123456789xyz')", "abcd123456789xyz"),
|
|
50
|
+
# With transform parameter
|
|
51
|
+
(r"ln.track(transform=\"abcd123456789xyz\")", "abcd123456789xyz"),
|
|
52
|
+
("ln.track(transform='abcd123456789xyz')", "abcd123456789xyz"),
|
|
53
|
+
# With whitespace variations
|
|
54
|
+
(r"ln.track( \"abcd123456789xyz\" )", "abcd123456789xyz"),
|
|
55
|
+
(r"ln.track( transform =\"abcd123456789xyz\")", "abcd123456789xyz"),
|
|
56
|
+
]
|
|
57
|
+
|
|
58
|
+
invalid_cases = [
|
|
59
|
+
# Mismatched quotes
|
|
60
|
+
r"ln.track(\"abcd123456789xyz')",
|
|
61
|
+
# Wrong length
|
|
62
|
+
r"ln.track(\"abc123\")", # Too short
|
|
63
|
+
r"ln.track(\"abcd123456789xyz0\")", # Too long
|
|
64
|
+
# Invalid characters
|
|
65
|
+
r"ln.track(\"abcd-123456789xyz\")", # Contains hyphen
|
|
66
|
+
r"ln.track(\"abcd_123456789xyz\")", # Contains underscore
|
|
67
|
+
# Old uid parameter
|
|
68
|
+
r"ln.track(uid=\"abcd123456789xyz\")",
|
|
69
|
+
]
|
|
70
|
+
|
|
71
|
+
# Test valid cases
|
|
72
|
+
for content, expected_uid in valid_cases:
|
|
73
|
+
uid, _, _ = parse_uid_from_code(content, ".ipynb")
|
|
74
|
+
assert uid == expected_uid, f"Failed for valid content: {content}"
|
|
75
|
+
|
|
76
|
+
# Test invalid cases
|
|
77
|
+
for content in invalid_cases:
|
|
78
|
+
print(content)
|
|
79
|
+
with pytest.raises(SystemExit):
|
|
80
|
+
uid, _, _ = parse_uid_from_code(content, ".py")
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def test_edge_cases():
|
|
84
|
+
test_cases = [
|
|
85
|
+
# Multiple track calls (should match first valid one)
|
|
86
|
+
(
|
|
87
|
+
'ln.track("abcd123456789xyz")\nln.track("efgh123456789xyz")',
|
|
88
|
+
"abcd123456789xyz",
|
|
89
|
+
".py",
|
|
90
|
+
),
|
|
91
|
+
# Comments in code -- this will fail
|
|
92
|
+
# ('# ln.track("abcd123456789xyz")\nln.track("real123456789xyz")', "real123456789xyz", ".py"),
|
|
93
|
+
# Mixed valid and invalid cases
|
|
94
|
+
(
|
|
95
|
+
'ln.track("invalid")\nln.track("abcd123456789xyz")',
|
|
96
|
+
"abcd123456789xyz",
|
|
97
|
+
".py",
|
|
98
|
+
),
|
|
99
|
+
]
|
|
100
|
+
|
|
101
|
+
for content, expected_uid, suffix in test_cases:
|
|
102
|
+
print(content)
|
|
103
|
+
uid, _, _ = parse_uid_from_code(content, suffix)
|
|
104
|
+
assert uid == expected_uid, f"Failed for content: {content}"
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def test_r_track_pattern():
|
|
108
|
+
suffixes = [".R", ".qmd", ".Rmd"]
|
|
109
|
+
|
|
110
|
+
valid_cases = [
|
|
111
|
+
# Basic cases with 16 character requirement
|
|
112
|
+
('track("abcd123456789xyz")', "abcd123456789xyz"),
|
|
113
|
+
("track('abcd123456789xyz')", "abcd123456789xyz"),
|
|
114
|
+
]
|
|
115
|
+
|
|
116
|
+
# Test valid cases across all R-related suffixes
|
|
117
|
+
for suffix in suffixes:
|
|
118
|
+
for content, expected_uid in valid_cases:
|
|
119
|
+
uid, _, _ = parse_uid_from_code(content, suffix)
|
|
120
|
+
assert (
|
|
121
|
+
uid == expected_uid
|
|
122
|
+
), f"Failed for valid content with {suffix}: {content}"
|
|
@@ -22,7 +22,7 @@ def test_save_not_initialized():
|
|
|
22
22
|
)
|
|
23
23
|
assert result.returncode == 1
|
|
24
24
|
assert (
|
|
25
|
-
"
|
|
25
|
+
"Cannot infer transform uid. Did you run `ln.track()` in your notebook?"
|
|
26
26
|
in result.stderr.decode()
|
|
27
27
|
)
|
|
28
28
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{lamin_cli-0.21.0 → lamin_cli-0.21.2}/tests/notebooks/with-title-and-initialized-consecutive.ipynb
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|