lamin_cli 1.12.0__py2.py3-none-any.whl → 1.12.1__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/_annotate.py CHANGED
@@ -1,47 +1,47 @@
1
- def _parse_features_list(features_list: tuple) -> dict:
2
- """Parse feature list into a dictionary.
3
-
4
- Supports multiple formats:
5
- - Quoted values: 'perturbation="DMSO","IFNG"' → {"perturbation": ["DMSO", "IFNG"]}
6
- - Unquoted values: 'perturbation=IFNG,DMSO' → {"perturbation": ["IFNG", "DMSO"]}
7
- - Single values: 'cell_line=HEK297' → {"cell_line": "HEK297"}
8
- - Mixed: ('perturbation="DMSO","IFNG"', 'cell_line=HEK297', 'genes=TP53,BRCA1')
9
- """
10
- import re
11
-
12
- import lamindb as ln
13
-
14
- feature_dict = {}
15
-
16
- for feature_assignment in features_list:
17
- if "=" not in feature_assignment:
18
- raise ln.errors.InvalidArgument(
19
- f"Invalid feature assignment: '{feature_assignment}'. Expected format: 'feature=value' or 'feature=\"value1\",\"value2\"'"
20
- )
21
-
22
- feature_name, values_str = feature_assignment.split("=", 1)
23
- feature_name = feature_name.strip()
24
-
25
- # Parse quoted values using regex
26
- # This will match quoted strings like "DMSO","IFNG" or single values like HEK297
27
- quoted_values = re.findall(r'"([^"]*)"', values_str)
28
-
29
- if quoted_values:
30
- # If we found quoted values, use them
31
- if len(quoted_values) == 1:
32
- feature_dict[feature_name] = quoted_values[0]
33
- else:
34
- feature_dict[feature_name] = quoted_values
35
- else:
36
- # If no quoted values, treat as single unquoted value
37
- # Remove any surrounding whitespace
38
- value = values_str.strip()
39
-
40
- # Handle comma-separated unquoted values
41
- if "," in value:
42
- values = [v.strip() for v in value.split(",")]
43
- feature_dict[feature_name] = values
44
- else:
45
- feature_dict[feature_name] = value
46
-
47
- return feature_dict
1
+ def _parse_features_list(features_list: tuple) -> dict:
2
+ """Parse feature list into a dictionary.
3
+
4
+ Supports multiple formats:
5
+ - Quoted values: 'perturbation="DMSO","IFNG"' → {"perturbation": ["DMSO", "IFNG"]}
6
+ - Unquoted values: 'perturbation=IFNG,DMSO' → {"perturbation": ["IFNG", "DMSO"]}
7
+ - Single values: 'cell_line=HEK297' → {"cell_line": "HEK297"}
8
+ - Mixed: ('perturbation="DMSO","IFNG"', 'cell_line=HEK297', 'genes=TP53,BRCA1')
9
+ """
10
+ import re
11
+
12
+ import lamindb as ln
13
+
14
+ feature_dict = {}
15
+
16
+ for feature_assignment in features_list:
17
+ if "=" not in feature_assignment:
18
+ raise ln.errors.InvalidArgument(
19
+ f"Invalid feature assignment: '{feature_assignment}'. Expected format: 'feature=value' or 'feature=\"value1\",\"value2\"'"
20
+ )
21
+
22
+ feature_name, values_str = feature_assignment.split("=", 1)
23
+ feature_name = feature_name.strip()
24
+
25
+ # Parse quoted values using regex
26
+ # This will match quoted strings like "DMSO","IFNG" or single values like HEK297
27
+ quoted_values = re.findall(r'"([^"]*)"', values_str)
28
+
29
+ if quoted_values:
30
+ # If we found quoted values, use them
31
+ if len(quoted_values) == 1:
32
+ feature_dict[feature_name] = quoted_values[0]
33
+ else:
34
+ feature_dict[feature_name] = quoted_values
35
+ else:
36
+ # If no quoted values, treat as single unquoted value
37
+ # Remove any surrounding whitespace
38
+ value = values_str.strip()
39
+
40
+ # Handle comma-separated unquoted values
41
+ if "," in value:
42
+ values = [v.strip() for v in value.split(",")]
43
+ feature_dict[feature_name] = values
44
+ else:
45
+ feature_dict[feature_name] = value
46
+
47
+ return feature_dict
lamin_cli/_cache.py CHANGED
@@ -1,41 +1,49 @@
1
- from __future__ import annotations
2
-
3
- import os
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 cache():
13
- """Get, set, or clear the cache directory."""
14
-
15
-
16
- @cache.command("set")
17
- @click.argument(
18
- "cache_dir",
19
- type=click.Path(dir_okay=True, file_okay=False),
20
- )
21
- def set_cache(cache_dir: str):
22
- """Set the cache directory."""
23
- from lamindb_setup._cache import set_cache_dir
24
-
25
- set_cache_dir(cache_dir)
26
-
27
-
28
- @cache.command("clear")
29
- def clear_cache():
30
- """Clear the cache directory."""
31
- from lamindb_setup._cache import clear_cache_dir
32
-
33
- clear_cache_dir()
34
-
35
-
36
- @cache.command("get")
37
- def get_cache():
38
- """Get the cache directory."""
39
- from lamindb_setup._cache import get_cache_dir
40
-
41
- click.echo(f"The cache directory is {get_cache_dir()}")
1
+ from __future__ import annotations
2
+
3
+ import os
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 cache():
13
+ """Get, set, reset, or clear the cache directory."""
14
+
15
+
16
+ @cache.command("set")
17
+ @click.argument(
18
+ "cache_dir",
19
+ type=click.Path(dir_okay=True, file_okay=False),
20
+ )
21
+ def set_cache(cache_dir: str):
22
+ """Set the path to the cache directory."""
23
+ from lamindb_setup._cache import set_cache_dir
24
+
25
+ set_cache_dir(cache_dir)
26
+
27
+
28
+ @cache.command("reset")
29
+ def reset_cache():
30
+ """Reset the cache directory to the default path."""
31
+ from lamindb_setup._cache import set_cache_dir
32
+
33
+ set_cache_dir(None)
34
+
35
+
36
+ @cache.command("clear")
37
+ def clear_cache():
38
+ """Clear contents of the cache directory."""
39
+ from lamindb_setup._cache import clear_cache_dir
40
+
41
+ clear_cache_dir()
42
+
43
+
44
+ @cache.command("get")
45
+ def get_cache():
46
+ """Get the path to the cache directory."""
47
+ from lamindb_setup._cache import get_cache_dir
48
+
49
+ click.echo(f"The cache directory is {get_cache_dir()}")
lamin_cli/_context.py CHANGED
@@ -1,76 +1,76 @@
1
- import os
2
- import sys
3
- from pathlib import Path
4
-
5
- import click
6
- from lamin_utils import logger
7
- from lamindb_setup.core._settings_store import settings_dir
8
-
9
-
10
- def get_current_run_file() -> Path:
11
- """Get the path to the file storing the current run UID."""
12
- return settings_dir / "current_shell_run.txt"
13
-
14
-
15
- def is_interactive_shell() -> bool:
16
- """Check if running in an interactive terminal."""
17
- return sys.stdin.isatty() and sys.stdout.isatty() and os.isatty(0)
18
-
19
-
20
- def get_script_filename() -> Path:
21
- """Try to get the filename of the calling shell script."""
22
- import psutil
23
-
24
- parent = psutil.Process(os.getppid())
25
- cmdline = parent.cmdline()
26
-
27
- # For shells like bash, sh, zsh
28
- if parent.name() in ["bash", "sh", "zsh", "dash"]:
29
- # cmdline is typically: ['/bin/bash', 'script.sh', ...]
30
- if len(cmdline) > 1 and not cmdline[1].startswith("-"):
31
- return Path(cmdline[1])
32
- raise click.ClickException(
33
- "Cannot determine script filename. Please run in an interactive shell."
34
- )
35
-
36
-
37
- def track():
38
- import lamindb as ln
39
-
40
- if not ln.setup.settings._instance_exists:
41
- raise click.ClickException(
42
- "Not connected to an instance. Please run: lamin connect account/name"
43
- )
44
- path = get_script_filename()
45
- source_code = path.read_text()
46
- transform = ln.Transform(
47
- key=path.name, source_code=source_code, type="script"
48
- ).save()
49
- run = ln.Run(transform=transform).save()
50
- current_run_file = get_current_run_file()
51
- current_run_file.parent.mkdir(parents=True, exist_ok=True)
52
- current_run_file.write_text(run.uid)
53
- logger.important(f"started tracking shell run: {run.uid}")
54
-
55
-
56
- def finish():
57
- from datetime import datetime, timezone
58
-
59
- import lamindb as ln
60
-
61
- if not ln.setup.settings._instance_exists:
62
- raise click.ClickException(
63
- "Not connected to an instance. Please run: lamin connect account/name"
64
- )
65
-
66
- current_run_file = get_current_run_file()
67
- if not current_run_file.exists():
68
- raise click.ClickException(
69
- "No active run to finish. Please run `lamin track` first."
70
- )
71
- run = ln.Run.get(uid=current_run_file.read_text().strip())
72
- run._status_code = 0
73
- run.finished_at = datetime.now(timezone.utc)
74
- run.save()
75
- current_run_file.unlink()
76
- logger.important(f"finished tracking shell run: {run.uid}")
1
+ import os
2
+ import sys
3
+ from pathlib import Path
4
+
5
+ import click
6
+ from lamin_utils import logger
7
+ from lamindb_setup.core._settings_store import settings_dir
8
+
9
+
10
+ def get_current_run_file() -> Path:
11
+ """Get the path to the file storing the current run UID."""
12
+ return settings_dir / "current_shell_run.txt"
13
+
14
+
15
+ def is_interactive_shell() -> bool:
16
+ """Check if running in an interactive terminal."""
17
+ return sys.stdin.isatty() and sys.stdout.isatty() and os.isatty(0)
18
+
19
+
20
+ def get_script_filename() -> Path:
21
+ """Try to get the filename of the calling shell script."""
22
+ import psutil
23
+
24
+ parent = psutil.Process(os.getppid())
25
+ cmdline = parent.cmdline()
26
+
27
+ # For shells like bash, sh, zsh
28
+ if parent.name() in ["bash", "sh", "zsh", "dash"]:
29
+ # cmdline is typically: ['/bin/bash', 'script.sh', ...]
30
+ if len(cmdline) > 1 and not cmdline[1].startswith("-"):
31
+ return Path(cmdline[1])
32
+ raise click.ClickException(
33
+ "Cannot determine script filename. Please run in an interactive shell."
34
+ )
35
+
36
+
37
+ def track():
38
+ import lamindb as ln
39
+
40
+ if not ln.setup.settings._instance_exists:
41
+ raise click.ClickException(
42
+ "Not connected to an instance. Please run: lamin connect account/name"
43
+ )
44
+ path = get_script_filename()
45
+ source_code = path.read_text()
46
+ transform = ln.Transform(
47
+ key=path.name, source_code=source_code, type="script"
48
+ ).save()
49
+ run = ln.Run(transform=transform).save()
50
+ current_run_file = get_current_run_file()
51
+ current_run_file.parent.mkdir(parents=True, exist_ok=True)
52
+ current_run_file.write_text(run.uid)
53
+ logger.important(f"started tracking shell run: {run.uid}")
54
+
55
+
56
+ def finish():
57
+ from datetime import datetime, timezone
58
+
59
+ import lamindb as ln
60
+
61
+ if not ln.setup.settings._instance_exists:
62
+ raise click.ClickException(
63
+ "Not connected to an instance. Please run: lamin connect account/name"
64
+ )
65
+
66
+ current_run_file = get_current_run_file()
67
+ if not current_run_file.exists():
68
+ raise click.ClickException(
69
+ "No active run to finish. Please run `lamin track` first."
70
+ )
71
+ run = ln.Run.get(uid=current_run_file.read_text().strip())
72
+ run._status_code = 0
73
+ run.finished_at = datetime.now(timezone.utc)
74
+ run.save()
75
+ current_run_file.unlink()
76
+ logger.important(f"finished tracking shell run: {run.uid}")
lamin_cli/_delete.py CHANGED
@@ -1,85 +1,85 @@
1
- import click
2
- from lamindb_setup import connect
3
- from lamindb_setup import delete as delete_instance
4
- from lamindb_setup.errors import StorageNotEmpty
5
-
6
- from .urls import decompose_url
7
-
8
-
9
- def delete(
10
- entity: str,
11
- name: str | None = None,
12
- uid: str | None = None,
13
- key: str | None = None,
14
- permanent: bool | None = None,
15
- force: bool = False,
16
- ):
17
- # TODO: refactor to abstract getting and deleting across entities
18
- if entity.startswith("https://") and "lamin" in entity:
19
- url = entity
20
- instance, entity, uid = decompose_url(url)
21
- connect(instance)
22
-
23
- if entity == "branch":
24
- assert name is not None, "You have to pass a name for deleting a branch."
25
- from lamindb import Branch
26
-
27
- Branch.get(name=name).delete(permanent=permanent)
28
- elif entity == "artifact":
29
- assert uid is not None or key is not None, (
30
- "You have to pass a uid or key for deleting an artifact."
31
- )
32
- from lamindb import Artifact
33
-
34
- if key is not None:
35
- record = Artifact.objects.filter(key=key).order_by("-created_at").first()
36
- if record is None:
37
- raise SystemExit(f"Artifact with key={key} does not exist.")
38
- else:
39
- record = Artifact.get(uid)
40
- record.delete(permanent=permanent)
41
- elif entity == "transform":
42
- assert uid is not None or key is not None, (
43
- "You have to pass a uid or key for deleting a transform."
44
- )
45
- from lamindb import Transform
46
-
47
- if key is not None:
48
- record = Transform.objects.filter(key=key).order_by("-created_at").first()
49
- if record is None:
50
- raise SystemExit(f"Transform with key={key} does not exist.")
51
- else:
52
- record = Transform.get(uid)
53
- record.delete(permanent=permanent)
54
- elif entity == "collection":
55
- assert uid is not None or key is not None, (
56
- "You have to pass a uid or key for deleting a collection."
57
- )
58
- from lamindb import Collection
59
-
60
- if key is not None:
61
- record = Collection.objects.filter(key=key).order_by("-created_at").first()
62
- if record is None:
63
- raise SystemExit(f"Collection with key={key} does not exist.")
64
- else:
65
- record = Collection.get(uid)
66
- record.delete(permanent=permanent)
67
- elif entity == "record":
68
- assert uid is not None or name is not None, (
69
- "You have to pass a uid or name for deleting a record."
70
- )
71
- from lamindb import Record
72
-
73
- if name is not None:
74
- record = Record.objects.get(name=name)
75
- if record is None:
76
- raise SystemExit(f"Record with name={name} does not exist.")
77
- else:
78
- record = Record.get(uid)
79
- record.delete(permanent=permanent)
80
- else:
81
- # could introduce "db" as an entity
82
- try:
83
- return delete_instance(entity, force=force)
84
- except StorageNotEmpty as e:
85
- raise click.ClickException(str(e)) from e
1
+ import click
2
+ from lamindb_setup import connect
3
+ from lamindb_setup import delete as delete_instance
4
+ from lamindb_setup.errors import StorageNotEmpty
5
+
6
+ from .urls import decompose_url
7
+
8
+
9
+ def delete(
10
+ entity: str,
11
+ name: str | None = None,
12
+ uid: str | None = None,
13
+ key: str | None = None,
14
+ permanent: bool | None = None,
15
+ force: bool = False,
16
+ ):
17
+ # TODO: refactor to abstract getting and deleting across entities
18
+ if entity.startswith("https://") and "lamin" in entity:
19
+ url = entity
20
+ instance, entity, uid = decompose_url(url)
21
+ connect(instance)
22
+
23
+ if entity == "branch":
24
+ assert name is not None, "You have to pass a name for deleting a branch."
25
+ from lamindb import Branch
26
+
27
+ Branch.get(name=name).delete(permanent=permanent)
28
+ elif entity == "artifact":
29
+ assert uid is not None or key is not None, (
30
+ "You have to pass a uid or key for deleting an artifact."
31
+ )
32
+ from lamindb import Artifact
33
+
34
+ if key is not None:
35
+ record = Artifact.objects.filter(key=key).order_by("-created_at").first()
36
+ if record is None:
37
+ raise SystemExit(f"Artifact with key={key} does not exist.")
38
+ else:
39
+ record = Artifact.get(uid)
40
+ record.delete(permanent=permanent)
41
+ elif entity == "transform":
42
+ assert uid is not None or key is not None, (
43
+ "You have to pass a uid or key for deleting a transform."
44
+ )
45
+ from lamindb import Transform
46
+
47
+ if key is not None:
48
+ record = Transform.objects.filter(key=key).order_by("-created_at").first()
49
+ if record is None:
50
+ raise SystemExit(f"Transform with key={key} does not exist.")
51
+ else:
52
+ record = Transform.get(uid)
53
+ record.delete(permanent=permanent)
54
+ elif entity == "collection":
55
+ assert uid is not None or key is not None, (
56
+ "You have to pass a uid or key for deleting a collection."
57
+ )
58
+ from lamindb import Collection
59
+
60
+ if key is not None:
61
+ record = Collection.objects.filter(key=key).order_by("-created_at").first()
62
+ if record is None:
63
+ raise SystemExit(f"Collection with key={key} does not exist.")
64
+ else:
65
+ record = Collection.get(uid)
66
+ record.delete(permanent=permanent)
67
+ elif entity == "record":
68
+ assert uid is not None or name is not None, (
69
+ "You have to pass a uid or name for deleting a record."
70
+ )
71
+ from lamindb import Record
72
+
73
+ if name is not None:
74
+ record = Record.objects.get(name=name)
75
+ if record is None:
76
+ raise SystemExit(f"Record with name={name} does not exist.")
77
+ else:
78
+ record = Record.get(uid)
79
+ record.delete(permanent=permanent)
80
+ else:
81
+ # could introduce "db" as an entity
82
+ try:
83
+ return delete_instance(entity, force=force)
84
+ except StorageNotEmpty as e:
85
+ raise click.ClickException(str(e)) from e