lamindb 1.4.0__py3-none-any.whl → 1.5.1__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.
Files changed (57) hide show
  1. lamindb/__init__.py +52 -36
  2. lamindb/_finish.py +17 -10
  3. lamindb/_tracked.py +1 -1
  4. lamindb/base/__init__.py +3 -1
  5. lamindb/base/fields.py +40 -22
  6. lamindb/base/ids.py +1 -94
  7. lamindb/base/types.py +2 -0
  8. lamindb/base/uids.py +117 -0
  9. lamindb/core/_context.py +203 -102
  10. lamindb/core/_settings.py +38 -25
  11. lamindb/core/datasets/__init__.py +11 -4
  12. lamindb/core/datasets/_core.py +5 -5
  13. lamindb/core/datasets/_small.py +0 -93
  14. lamindb/core/datasets/mini_immuno.py +172 -0
  15. lamindb/core/loaders.py +1 -1
  16. lamindb/core/storage/_backed_access.py +100 -6
  17. lamindb/core/storage/_polars_lazy_df.py +51 -0
  18. lamindb/core/storage/_pyarrow_dataset.py +15 -30
  19. lamindb/core/storage/_tiledbsoma.py +29 -13
  20. lamindb/core/storage/objects.py +6 -0
  21. lamindb/core/subsettings/__init__.py +2 -0
  22. lamindb/core/subsettings/_annotation_settings.py +11 -0
  23. lamindb/curators/__init__.py +7 -3349
  24. lamindb/curators/_legacy.py +2056 -0
  25. lamindb/curators/core.py +1534 -0
  26. lamindb/errors.py +11 -0
  27. lamindb/examples/__init__.py +27 -0
  28. lamindb/examples/schemas/__init__.py +12 -0
  29. lamindb/examples/schemas/_anndata.py +25 -0
  30. lamindb/examples/schemas/_simple.py +19 -0
  31. lamindb/integrations/_vitessce.py +8 -5
  32. lamindb/migrations/0091_alter_featurevalue_options_alter_space_options_and_more.py +24 -0
  33. lamindb/migrations/0092_alter_artifactfeaturevalue_artifact_and_more.py +75 -0
  34. lamindb/migrations/0093_alter_schemacomponent_unique_together.py +16 -0
  35. lamindb/models/__init__.py +4 -1
  36. lamindb/models/_describe.py +21 -4
  37. lamindb/models/_feature_manager.py +382 -287
  38. lamindb/models/_label_manager.py +8 -2
  39. lamindb/models/artifact.py +177 -106
  40. lamindb/models/artifact_set.py +122 -0
  41. lamindb/models/collection.py +73 -52
  42. lamindb/models/core.py +1 -1
  43. lamindb/models/feature.py +51 -17
  44. lamindb/models/has_parents.py +69 -14
  45. lamindb/models/project.py +1 -1
  46. lamindb/models/query_manager.py +221 -22
  47. lamindb/models/query_set.py +247 -172
  48. lamindb/models/record.py +65 -247
  49. lamindb/models/run.py +4 -4
  50. lamindb/models/save.py +8 -2
  51. lamindb/models/schema.py +456 -184
  52. lamindb/models/transform.py +2 -2
  53. lamindb/models/ulabel.py +8 -5
  54. {lamindb-1.4.0.dist-info → lamindb-1.5.1.dist-info}/METADATA +6 -6
  55. {lamindb-1.4.0.dist-info → lamindb-1.5.1.dist-info}/RECORD +57 -43
  56. {lamindb-1.4.0.dist-info → lamindb-1.5.1.dist-info}/LICENSE +0 -0
  57. {lamindb-1.4.0.dist-info → lamindb-1.5.1.dist-info}/WHEEL +0 -0
lamindb/errors.py CHANGED
@@ -94,3 +94,14 @@ class UpdateContext(SystemExit):
94
94
  """Transform settings require update."""
95
95
 
96
96
  pass
97
+
98
+
99
+ # -------------------------------------------------------------------------------------
100
+ # record
101
+ # -------------------------------------------------------------------------------------
102
+
103
+
104
+ class NoWriteAccess(Exception):
105
+ """No write access to a space."""
106
+
107
+ pass
@@ -0,0 +1,27 @@
1
+ """Examples.
2
+
3
+ .. autosummary::
4
+ :toctree: .
5
+
6
+ ingest_mini_immuno_datasets
7
+ schemas
8
+
9
+ """
10
+
11
+ from . import schemas
12
+
13
+
14
+ def ingest_mini_immuno_datasets():
15
+ """Ingest mini immuno datasets.
16
+
17
+ .. literalinclude:: scripts/ingest_mini_immuno_datasets.py
18
+ :language: python
19
+ """
20
+ import sys
21
+ from pathlib import Path
22
+
23
+ docs_path = Path(__file__).parent.parent.parent / "docs" / "scripts"
24
+ if str(docs_path) not in sys.path:
25
+ sys.path.append(str(docs_path))
26
+
27
+ import ingest_mini_immuno_datasets # noqa
@@ -0,0 +1,12 @@
1
+ """Example schemas.
2
+
3
+ .. autosummary::
4
+ :toctree: .
5
+
6
+ valid_features
7
+ anndata_ensembl_gene_ids_and_valid_features_in_obs
8
+
9
+ """
10
+
11
+ from ._anndata import anndata_ensembl_gene_ids_and_valid_features_in_obs
12
+ from ._simple import valid_features
@@ -0,0 +1,25 @@
1
+ from ... import Schema
2
+
3
+
4
+ def anndata_ensembl_gene_ids_and_valid_features_in_obs() -> Schema:
5
+ """Return a schema for an AnnData with Ensembl gene IDs and valid features in obs.
6
+
7
+ .. literalinclude:: scripts/define_schema_anndata_ensembl_gene_ids_and_valid_features_in_obs.py
8
+ :language: python
9
+ """
10
+ import subprocess
11
+ from pathlib import Path
12
+
13
+ docs_path = Path(__file__).parent.parent.parent.parent / "docs" / "scripts"
14
+ subprocess.run(
15
+ [
16
+ "python",
17
+ str(
18
+ docs_path
19
+ / "define_schema_anndata_ensembl_gene_ids_and_valid_features_in_obs.py"
20
+ ),
21
+ ],
22
+ check=True,
23
+ )
24
+
25
+ return Schema.get(name="anndata_ensembl_gene_ids_and_valid_features_in_obs")
@@ -0,0 +1,19 @@
1
+ from ... import Schema
2
+
3
+
4
+ def valid_features() -> Schema:
5
+ """Return a schema for an AnnData with Ensembl gene IDs and valid features in obs.
6
+
7
+ .. literalinclude:: scripts/define_schema_anndata_ensembl_gene_ids_and_valid_features_in_obs.py
8
+ :language: python
9
+ """
10
+ import subprocess
11
+ from pathlib import Path
12
+
13
+ docs_path = Path(__file__).parent.parent.parent.parent / "docs" / "scripts"
14
+ subprocess.run(
15
+ ["python", str(docs_path / "define_valid_features.py")],
16
+ check=True,
17
+ )
18
+
19
+ return Schema.get(name="valid_features")
@@ -19,7 +19,9 @@ if TYPE_CHECKING:
19
19
  # "unit test": https://github.com/laminlabs/lamindb/blob/main/docs/storage/vitessce.ipynb
20
20
  # integration test & context: https://github.com/laminlabs/lamin-spatial/blob/main/docs/vitessce.ipynb
21
21
  def save_vitessce_config(
22
- vitessce_config: VitessceConfig, description: str | None = None
22
+ vitessce_config: VitessceConfig,
23
+ key: str | None = None,
24
+ description: str | None = None,
23
25
  ) -> Artifact:
24
26
  """Validates and saves a `VitessceConfig` object.
25
27
 
@@ -30,9 +32,10 @@ def save_vitessce_config(
30
32
 
31
33
  Args:
32
34
  vitessce_config: A `VitessceConfig` object.
33
- description: A description for the `VitessceConfig` object. Is used as
34
- `key` for a `Collection` in case the `VitessceConfig` object
35
- references multiple artifacts.
35
+ key: A key for the `VitessceConfig` object. Is used as `key` for a
36
+ `Collection` in case the `VitessceConfig` object references
37
+ multiple artifacts.
38
+ description: A description for the `VitessceConfig` object.
36
39
 
37
40
  .. versionchanged:: 0.76.12
38
41
  Now assumes `vitessce-python >= 3.4.0`, which allows passing artifacts within `VitessceConfig`.
@@ -77,7 +80,7 @@ def save_vitessce_config(
77
80
  with open(config_file_local_path, "w") as file:
78
81
  json.dump(vc_dict, file)
79
82
  vitessce_config_artifact = Artifact(
80
- config_file_local_path, description=description, run=run
83
+ config_file_local_path, key=key, description=description, run=run
81
84
  ).save()
82
85
  slug = ln_setup.settings.instance.slug
83
86
  logger.important(
@@ -0,0 +1,24 @@
1
+ # Generated by Django 5.1.4 on 2025-04-30 09:11
2
+
3
+ from django.db import migrations
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+ dependencies = [
8
+ ("lamindb", "0090_squashed"),
9
+ ]
10
+
11
+ operations = [
12
+ migrations.AlterModelOptions(
13
+ name="featurevalue",
14
+ options={"base_manager_name": "objects"},
15
+ ),
16
+ migrations.AlterModelOptions(
17
+ name="space",
18
+ options={"base_manager_name": "objects"},
19
+ ),
20
+ migrations.AlterModelOptions(
21
+ name="user",
22
+ options={"base_manager_name": "objects"},
23
+ ),
24
+ ]
@@ -0,0 +1,75 @@
1
+ # Generated by Django 5.2 on 2025-05-06 20:34
2
+
3
+ import django.db.models.deletion
4
+ from django.db import migrations
5
+
6
+ import lamindb.base.fields
7
+
8
+
9
+ class Migration(migrations.Migration):
10
+ dependencies = [
11
+ ("lamindb", "0091_alter_featurevalue_options_alter_space_options_and_more"),
12
+ ]
13
+
14
+ operations = [
15
+ migrations.AlterField(
16
+ model_name="artifactfeaturevalue",
17
+ name="artifact",
18
+ field=lamindb.base.fields.ForeignKey(
19
+ blank=True,
20
+ on_delete=django.db.models.deletion.CASCADE,
21
+ related_name="links_featurevalue",
22
+ to="lamindb.artifact",
23
+ ),
24
+ ),
25
+ migrations.AlterField(
26
+ model_name="artifactfeaturevalue",
27
+ name="featurevalue",
28
+ field=lamindb.base.fields.ForeignKey(
29
+ blank=True,
30
+ on_delete=django.db.models.deletion.PROTECT,
31
+ related_name="links_artifact",
32
+ to="lamindb.featurevalue",
33
+ ),
34
+ ),
35
+ migrations.AlterField(
36
+ model_name="artifactparamvalue",
37
+ name="artifact",
38
+ field=lamindb.base.fields.ForeignKey(
39
+ blank=True,
40
+ on_delete=django.db.models.deletion.CASCADE,
41
+ related_name="links_paramvalue",
42
+ to="lamindb.artifact",
43
+ ),
44
+ ),
45
+ migrations.AlterField(
46
+ model_name="artifactparamvalue",
47
+ name="paramvalue",
48
+ field=lamindb.base.fields.ForeignKey(
49
+ blank=True,
50
+ on_delete=django.db.models.deletion.PROTECT,
51
+ related_name="links_artifact",
52
+ to="lamindb.paramvalue",
53
+ ),
54
+ ),
55
+ migrations.AlterField(
56
+ model_name="runparamvalue",
57
+ name="paramvalue",
58
+ field=lamindb.base.fields.ForeignKey(
59
+ blank=True,
60
+ on_delete=django.db.models.deletion.PROTECT,
61
+ related_name="links_run",
62
+ to="lamindb.paramvalue",
63
+ ),
64
+ ),
65
+ migrations.AlterField(
66
+ model_name="runparamvalue",
67
+ name="run",
68
+ field=lamindb.base.fields.ForeignKey(
69
+ blank=True,
70
+ on_delete=django.db.models.deletion.CASCADE,
71
+ related_name="links_paramvalue",
72
+ to="lamindb.run",
73
+ ),
74
+ ),
75
+ ]
@@ -0,0 +1,16 @@
1
+ # Generated by Django 5.2 on 2025-05-07 12:16
2
+
3
+ from django.db import migrations
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+ dependencies = [
8
+ ("lamindb", "0092_alter_artifactfeaturevalue_artifact_and_more"),
9
+ ]
10
+
11
+ operations = [
12
+ migrations.AlterUniqueTogether(
13
+ name="schemacomponent",
14
+ unique_together={("composite", "slot"), ("composite", "slot", "component")},
15
+ ),
16
+ ]
@@ -6,7 +6,9 @@
6
6
  BasicRecord
7
7
  Record
8
8
  Registry
9
+ BasicQuerySet
9
10
  QuerySet
11
+ ArtifactSet
10
12
  QueryManager
11
13
  RecordList
12
14
  FeatureManager
@@ -55,7 +57,8 @@ from .collection import Collection, CollectionArtifact
55
57
  from .project import Person, Project, Reference
56
58
  from .flextable import FlexTable, RunData
57
59
  from .query_manager import QueryManager
58
- from .query_set import QuerySet, RecordList
60
+ from .query_set import BasicQuerySet, QuerySet, RecordList
61
+ from .artifact_set import ArtifactSet
59
62
  from .has_parents import HasParents
60
63
  from datetime import datetime as _datetime
61
64
 
@@ -1,6 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import datetime
4
+ import re
4
5
  from typing import TYPE_CHECKING
5
6
 
6
7
  from lamin_utils import logger
@@ -35,7 +36,9 @@ TYPE_WIDTH = 25
35
36
  VALUES_WIDTH = 40
36
37
 
37
38
 
38
- def print_rich_tree(tree: Tree, fallback=str):
39
+ def format_rich_tree(
40
+ tree: Tree, fallback: str = "", return_str: bool = False, strip_ansi: bool = True
41
+ ) -> str | None:
39
42
  from rich.console import Console
40
43
 
41
44
  # If tree has no children, return fallback
@@ -45,6 +48,20 @@ def print_rich_tree(tree: Tree, fallback=str):
45
48
  console = Console(force_terminal=True)
46
49
  printed = False
47
50
 
51
+ if return_str:
52
+ from io import StringIO
53
+
54
+ string_io = StringIO()
55
+ str_console = Console(file=string_io, force_terminal=True)
56
+ str_console.print(tree)
57
+ result = string_io.getvalue()
58
+ if strip_ansi:
59
+ ansi_escape = re.compile(r"\x1b(?:\[[0-9;]*[a-zA-Z]|\(B)")
60
+ result = ansi_escape.sub("", result)
61
+ # rstrip trailing whitespace on every line
62
+ result = "\n".join(line.rstrip() for line in result.splitlines())
63
+ return result
64
+
48
65
  try:
49
66
  if not is_run_from_ipython:
50
67
  from IPython import get_ipython
@@ -55,16 +72,16 @@ def print_rich_tree(tree: Tree, fallback=str):
55
72
  if isinstance(shell, InteractiveShell):
56
73
  display(tree)
57
74
  printed = True
58
- return ""
75
+ return None
59
76
  except (NameError, ImportError):
60
77
  pass
61
78
 
62
- # If not printed through IPython
63
79
  if not printed:
64
80
  # be careful to test this on a terminal
65
81
  console = Console(force_terminal=True)
66
82
  console.print(tree)
67
- return ""
83
+
84
+ return None
68
85
 
69
86
 
70
87
  def describe_header(self: Artifact | Collection | Run) -> Tree: