lamindb 0.75.0__py3-none-any.whl → 0.75.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.
- lamindb/__init__.py +1 -1
- lamindb/_can_validate.py +52 -22
- lamindb/_curate.py +384 -144
- lamindb/_from_values.py +8 -8
- lamindb/_record.py +26 -26
- lamindb/_save.py +5 -5
- lamindb/_view.py +13 -11
- lamindb/core/__init__.py +2 -0
- lamindb/core/_data.py +4 -4
- lamindb/core/_feature_manager.py +16 -6
- lamindb/core/schema.py +5 -5
- lamindb/core/storage/__init__.py +11 -2
- lamindb/core/storage/_valid_suffixes.py +16 -2
- lamindb/integrations/_vitessce.py +68 -31
- {lamindb-0.75.0.dist-info → lamindb-0.75.1.dist-info}/METADATA +4 -4
- {lamindb-0.75.0.dist-info → lamindb-0.75.1.dist-info}/RECORD +18 -18
- {lamindb-0.75.0.dist-info → lamindb-0.75.1.dist-info}/LICENSE +0 -0
- {lamindb-0.75.0.dist-info → lamindb-0.75.1.dist-info}/WHEEL +0 -0
lamindb/_from_values.py
CHANGED
@@ -335,9 +335,9 @@ def _bulk_create_dicts_from_df(
|
|
335
335
|
return df.reset_index().to_dict(orient="records"), multi_msg
|
336
336
|
|
337
337
|
|
338
|
-
def _has_organism_field(
|
338
|
+
def _has_organism_field(registry: type[Record]) -> bool:
|
339
339
|
try:
|
340
|
-
|
340
|
+
registry._meta.get_field("organism")
|
341
341
|
return True
|
342
342
|
except FieldDoesNotExist:
|
343
343
|
return False
|
@@ -346,17 +346,17 @@ def _has_organism_field(orm: type[Record]) -> bool:
|
|
346
346
|
def _get_organism_record(
|
347
347
|
field: StrField, organism: str | Record, force: bool = False
|
348
348
|
) -> Record:
|
349
|
-
|
349
|
+
registry = field.field.model
|
350
350
|
check = True
|
351
|
-
if not force and hasattr(
|
352
|
-
check = field.field.name !=
|
351
|
+
if not force and hasattr(registry, "_ontology_id_field"):
|
352
|
+
check = field.field.name != registry._ontology_id_field
|
353
353
|
# e.g. bionty.CellMarker has "name" as _ontology_id_field
|
354
|
-
if not
|
354
|
+
if not registry._ontology_id_field.endswith("id"):
|
355
355
|
check = True
|
356
356
|
|
357
|
-
if _has_organism_field(
|
357
|
+
if _has_organism_field(registry) and check:
|
358
358
|
from bionty._bionty import create_or_get_organism_record
|
359
359
|
|
360
|
-
organism_record = create_or_get_organism_record(organism=organism, orm=
|
360
|
+
organism_record = create_or_get_organism_record(organism=organism, orm=registry)
|
361
361
|
if organism_record is not None:
|
362
362
|
return organism_record
|
lamindb/_record.py
CHANGED
@@ -36,9 +36,9 @@ def init_self_from_db(self: Record, existing_record: Record):
|
|
36
36
|
self._state.db = "default"
|
37
37
|
|
38
38
|
|
39
|
-
def validate_required_fields(
|
39
|
+
def validate_required_fields(record: Record, kwargs):
|
40
40
|
required_fields = {
|
41
|
-
k.name for k in
|
41
|
+
k.name for k in record._meta.fields if not k.null and k.default is None
|
42
42
|
}
|
43
43
|
required_fields_not_passed = {k: None for k in required_fields if k not in kwargs}
|
44
44
|
kwargs.update(required_fields_not_passed)
|
@@ -77,9 +77,9 @@ def suggest_records_with_similar_names(record: Record, kwargs) -> bool:
|
|
77
77
|
return False
|
78
78
|
|
79
79
|
|
80
|
-
def __init__(
|
80
|
+
def __init__(record: Record, *args, **kwargs):
|
81
81
|
if not args:
|
82
|
-
validate_required_fields(
|
82
|
+
validate_required_fields(record, kwargs)
|
83
83
|
|
84
84
|
# do not search for names if an id is passed; this is important
|
85
85
|
# e.g. when synching ids from the notebook store to lamindb
|
@@ -87,29 +87,29 @@ def __init__(orm: Record, *args, **kwargs):
|
|
87
87
|
if "_has_consciously_provided_uid" in kwargs:
|
88
88
|
has_consciously_provided_uid = kwargs.pop("_has_consciously_provided_uid")
|
89
89
|
if settings.creation.search_names and not has_consciously_provided_uid:
|
90
|
-
match = suggest_records_with_similar_names(
|
90
|
+
match = suggest_records_with_similar_names(record, kwargs)
|
91
91
|
if match:
|
92
92
|
if "version" in kwargs:
|
93
93
|
version_comment = " and version"
|
94
|
-
existing_record =
|
94
|
+
existing_record = record.__class__.filter(
|
95
95
|
name=kwargs["name"], version=kwargs["version"]
|
96
96
|
).one_or_none()
|
97
97
|
else:
|
98
98
|
version_comment = ""
|
99
|
-
existing_record =
|
99
|
+
existing_record = record.__class__.filter(name=kwargs["name"]).one()
|
100
100
|
if existing_record is not None:
|
101
101
|
logger.important(
|
102
|
-
f"returning existing {
|
102
|
+
f"returning existing {record.__class__.__name__} record with same"
|
103
103
|
f" name{version_comment}: '{kwargs['name']}'"
|
104
104
|
)
|
105
|
-
init_self_from_db(
|
105
|
+
init_self_from_db(record, existing_record)
|
106
106
|
return None
|
107
|
-
super(Record,
|
108
|
-
elif len(args) != len(
|
107
|
+
super(Record, record).__init__(**kwargs)
|
108
|
+
elif len(args) != len(record._meta.concrete_fields):
|
109
109
|
raise ValueError("please provide keyword arguments, not plain arguments")
|
110
110
|
else:
|
111
111
|
# object is loaded from DB (**kwargs could be omitted below, I believe)
|
112
|
-
super(Record,
|
112
|
+
super(Record, record).__init__(*args, **kwargs)
|
113
113
|
|
114
114
|
|
115
115
|
@classmethod # type:ignore
|
@@ -191,11 +191,11 @@ def _search(
|
|
191
191
|
truncate_words: bool = False,
|
192
192
|
) -> QuerySet:
|
193
193
|
input_queryset = _queryset(cls, using_key=using_key)
|
194
|
-
|
194
|
+
registry = input_queryset.model
|
195
195
|
if field is None:
|
196
196
|
fields = [
|
197
197
|
field.name
|
198
|
-
for field in
|
198
|
+
for field in registry._meta.fields
|
199
199
|
if field.get_internal_type() in {"CharField", "TextField"}
|
200
200
|
]
|
201
201
|
else:
|
@@ -287,7 +287,7 @@ def _lookup(
|
|
287
287
|
) -> NamedTuple:
|
288
288
|
"""{}""" # noqa: D415
|
289
289
|
queryset = _queryset(cls, using_key=using_key)
|
290
|
-
field = get_name_field(
|
290
|
+
field = get_name_field(registry=queryset.model, field=field)
|
291
291
|
|
292
292
|
return Lookup(
|
293
293
|
records=queryset,
|
@@ -296,7 +296,7 @@ def _lookup(
|
|
296
296
|
prefix="ln",
|
297
297
|
).lookup(
|
298
298
|
return_field=(
|
299
|
-
get_name_field(
|
299
|
+
get_name_field(registry=queryset.model, field=return_field)
|
300
300
|
if return_field is not None
|
301
301
|
else None
|
302
302
|
)
|
@@ -315,24 +315,24 @@ def lookup(
|
|
315
315
|
|
316
316
|
|
317
317
|
def get_name_field(
|
318
|
-
|
318
|
+
registry: type[Record] | QuerySet | Manager,
|
319
319
|
*,
|
320
320
|
field: str | StrField | None = None,
|
321
321
|
) -> str:
|
322
|
-
"""Get the 1st char or text field from the
|
323
|
-
if isinstance(
|
324
|
-
|
325
|
-
model_field_names = [i.name for i in
|
322
|
+
"""Get the 1st char or text field from the registry."""
|
323
|
+
if isinstance(registry, (QuerySet, Manager)):
|
324
|
+
registry = registry.model
|
325
|
+
model_field_names = [i.name for i in registry._meta.fields]
|
326
326
|
|
327
327
|
# set to default name field
|
328
328
|
if field is None:
|
329
|
-
if hasattr(
|
330
|
-
field =
|
329
|
+
if hasattr(registry, "_name_field"):
|
330
|
+
field = registry._meta.get_field(registry._name_field)
|
331
331
|
elif "name" in model_field_names:
|
332
|
-
field =
|
332
|
+
field = registry._meta.get_field("name")
|
333
333
|
else:
|
334
334
|
# first char or text field that doesn't contain "id"
|
335
|
-
for i in
|
335
|
+
for i in registry._meta.fields:
|
336
336
|
if "id" in i.name:
|
337
337
|
continue
|
338
338
|
if i.get_internal_type() in {"CharField", "TextField"}:
|
@@ -360,7 +360,7 @@ def get_name_field(
|
|
360
360
|
def _queryset(cls: Record | QuerySet | Manager, using_key: str) -> QuerySet:
|
361
361
|
if isinstance(cls, (QuerySet, Manager)):
|
362
362
|
return cls.all()
|
363
|
-
elif using_key is None:
|
363
|
+
elif using_key is None or using_key == "default":
|
364
364
|
return cls.objects.all()
|
365
365
|
else:
|
366
366
|
# using must be called on cls, otherwise the connection isn't found
|
lamindb/_save.py
CHANGED
@@ -108,21 +108,21 @@ def bulk_create(records: Iterable[Record], ignore_conflicts: bool | None = False
|
|
108
108
|
records_by_orm = defaultdict(list)
|
109
109
|
for record in records:
|
110
110
|
records_by_orm[record.__class__].append(record)
|
111
|
-
for
|
112
|
-
|
111
|
+
for registry, records in records_by_orm.items():
|
112
|
+
registry.objects.bulk_create(records, ignore_conflicts=ignore_conflicts)
|
113
113
|
|
114
114
|
|
115
115
|
def bulk_update(records: Iterable[Record], ignore_conflicts: bool | None = False):
|
116
116
|
records_by_orm = defaultdict(list)
|
117
117
|
for record in records:
|
118
118
|
records_by_orm[record.__class__].append(record)
|
119
|
-
for
|
119
|
+
for registry, records in records_by_orm.items():
|
120
120
|
field_names = [
|
121
121
|
field.name
|
122
|
-
for field in
|
122
|
+
for field in registry._meta.fields
|
123
123
|
if (field.name != "created_at" and field.name != "id")
|
124
124
|
]
|
125
|
-
|
125
|
+
registry.objects.bulk_update(records, field_names)
|
126
126
|
|
127
127
|
|
128
128
|
# This is also used within Artifact.save()
|
lamindb/_view.py
CHANGED
@@ -41,15 +41,17 @@ def view(
|
|
41
41
|
schema_module = importlib.import_module(get_schema_module_name(schema_name))
|
42
42
|
|
43
43
|
all_registries = {
|
44
|
-
|
45
|
-
for
|
46
|
-
if inspect.isclass(
|
47
|
-
and issubclass(
|
48
|
-
and
|
44
|
+
registry
|
45
|
+
for registry in schema_module.__dict__.values()
|
46
|
+
if inspect.isclass(registry)
|
47
|
+
and issubclass(registry, Record)
|
48
|
+
and registry is not Record
|
49
49
|
}
|
50
50
|
if registries is not None:
|
51
51
|
filtered_registries = {
|
52
|
-
|
52
|
+
registry
|
53
|
+
for registry in all_registries
|
54
|
+
if registry.__name__ in registries
|
53
55
|
}
|
54
56
|
else:
|
55
57
|
filtered_registries = all_registries
|
@@ -59,12 +61,12 @@ def view(
|
|
59
61
|
logger.print("*" * len(section_no_color))
|
60
62
|
logger.print(section)
|
61
63
|
logger.print("*" * len(section_no_color))
|
62
|
-
for
|
63
|
-
if hasattr(
|
64
|
-
df =
|
64
|
+
for registry in sorted(filtered_registries, key=lambda x: x.__name__):
|
65
|
+
if hasattr(registry, "updated_at"):
|
66
|
+
df = registry.filter().order_by("-updated_at")[:n].df()
|
65
67
|
else:
|
66
68
|
# need to adjust in the future
|
67
|
-
df =
|
69
|
+
df = registry.df().iloc[-n:]
|
68
70
|
if df.shape[0] > 0:
|
69
|
-
logger.print(colors.blue(colors.bold(
|
71
|
+
logger.print(colors.blue(colors.bold(registry.__name__)))
|
70
72
|
show(df)
|
lamindb/core/__init__.py
CHANGED
lamindb/core/_data.py
CHANGED
@@ -14,8 +14,8 @@ from lnschema_core.models import (
|
|
14
14
|
Record,
|
15
15
|
Run,
|
16
16
|
ULabel,
|
17
|
-
__repr__,
|
18
17
|
format_field_value,
|
18
|
+
record_repr,
|
19
19
|
)
|
20
20
|
|
21
21
|
from lamindb._parents import view_lineage
|
@@ -108,7 +108,7 @@ def describe(self: HasFeatures, print_types: bool = False):
|
|
108
108
|
# )
|
109
109
|
|
110
110
|
model_name = self.__class__.__name__
|
111
|
-
msg = f"{colors.green(model_name)}{
|
111
|
+
msg = f"{colors.green(model_name)}{record_repr(self, include_foreign_keys=False).lstrip(model_name)}\n"
|
112
112
|
prov_msg = ""
|
113
113
|
|
114
114
|
fields = self._meta.fields
|
@@ -251,8 +251,8 @@ def add_labels(
|
|
251
251
|
if feature.dtype.startswith("cat["):
|
252
252
|
orm_dict = dict_schema_name_to_model_name(Artifact)
|
253
253
|
for reg in feature.dtype.replace("cat[", "").rstrip("]").split("|"):
|
254
|
-
|
255
|
-
records_validated +=
|
254
|
+
registry = orm_dict.get(reg)
|
255
|
+
records_validated += registry.from_values(records, field=field)
|
256
256
|
|
257
257
|
# feature doesn't have registries and therefore can't create records from values
|
258
258
|
# ask users to pass records
|
lamindb/core/_feature_manager.py
CHANGED
@@ -118,9 +118,7 @@ def get_feature_set_links(host: Artifact | Collection) -> QuerySet:
|
|
118
118
|
|
119
119
|
def get_link_attr(link: LinkORM | type[LinkORM], data: HasFeatures) -> str:
|
120
120
|
link_model_name = link.__class__.__name__
|
121
|
-
if
|
122
|
-
link_model_name == "ModelBase" or link_model_name == "RecordMeta"
|
123
|
-
): # we passed the type of the link
|
121
|
+
if link_model_name in {"Registry", "ModelBase"}: # we passed the type of the link
|
124
122
|
link_model_name = link.__name__
|
125
123
|
return link_model_name.replace(data.__class__.__name__, "").lower()
|
126
124
|
|
@@ -746,9 +744,9 @@ def _add_set_from_mudata(
|
|
746
744
|
# parse and register features
|
747
745
|
mdata = self._host.load()
|
748
746
|
feature_sets = {}
|
749
|
-
obs_features =
|
747
|
+
obs_features = Feature.from_values(mdata.obs.columns)
|
750
748
|
if len(obs_features) > 0:
|
751
|
-
feature_sets["obs"] = FeatureSet(features=
|
749
|
+
feature_sets["obs"] = FeatureSet(features=obs_features)
|
752
750
|
for modality, field in var_fields.items():
|
753
751
|
modality_fs = parse_feature_sets_from_anndata(
|
754
752
|
mdata[modality],
|
@@ -760,8 +758,20 @@ def _add_set_from_mudata(
|
|
760
758
|
for k, v in modality_fs.items():
|
761
759
|
feature_sets[f"['{modality}'].{k}"] = v
|
762
760
|
|
761
|
+
def unify_feature_sets_by_hash(feature_sets):
|
762
|
+
unique_values = {}
|
763
|
+
|
764
|
+
for key, value in feature_sets.items():
|
765
|
+
value_hash = value.hash # Assuming each value has a .hash attribute
|
766
|
+
if value_hash in unique_values:
|
767
|
+
feature_sets[key] = unique_values[value_hash]
|
768
|
+
else:
|
769
|
+
unique_values[value_hash] = value
|
770
|
+
|
771
|
+
return feature_sets
|
772
|
+
|
763
773
|
# link feature sets
|
764
|
-
self._host._feature_sets = feature_sets
|
774
|
+
self._host._feature_sets = unify_feature_sets_by_hash(feature_sets)
|
765
775
|
self._host.save()
|
766
776
|
|
767
777
|
|
lamindb/core/schema.py
CHANGED
@@ -4,16 +4,16 @@ from django.db.models import ManyToManyField
|
|
4
4
|
from lnschema_core.models import Feature, FeatureSet, LinkORM, Record
|
5
5
|
|
6
6
|
|
7
|
-
def dict_schema_name_to_model_name(
|
7
|
+
def dict_schema_name_to_model_name(registry: type[Record]) -> dict[str, Record]:
|
8
8
|
d: dict = {
|
9
9
|
i.related_model.__get_name_with_schema__(): i.related_model
|
10
|
-
for i in
|
10
|
+
for i in registry._meta.related_objects
|
11
11
|
if i.related_name is not None
|
12
12
|
}
|
13
13
|
d.update(
|
14
14
|
{
|
15
15
|
i.related_model.__get_name_with_schema__(): i.related_model
|
16
|
-
for i in
|
16
|
+
for i in registry._meta.many_to_many
|
17
17
|
if i.name is not None
|
18
18
|
}
|
19
19
|
)
|
@@ -21,12 +21,12 @@ def dict_schema_name_to_model_name(orm: type[Record]) -> dict[str, Record]:
|
|
21
21
|
|
22
22
|
|
23
23
|
def dict_related_model_to_related_name(
|
24
|
-
|
24
|
+
registry: type[Record], links: bool = False
|
25
25
|
) -> dict[str, str]:
|
26
26
|
def include(model: Record):
|
27
27
|
return not links != issubclass(model, LinkORM)
|
28
28
|
|
29
|
-
related_objects =
|
29
|
+
related_objects = registry._meta.related_objects + registry._meta.many_to_many
|
30
30
|
d: dict = {
|
31
31
|
record.related_model.__get_name_with_schema__(): (
|
32
32
|
record.related_name
|
lamindb/core/storage/__init__.py
CHANGED
@@ -1,4 +1,13 @@
|
|
1
|
-
"""Storage
|
1
|
+
"""Storage API.
|
2
|
+
|
3
|
+
Valid suffixes.
|
4
|
+
|
5
|
+
.. autosummary::
|
6
|
+
:toctree: .
|
7
|
+
|
8
|
+
VALID_SUFFIXES
|
9
|
+
|
10
|
+
Array accessors.
|
2
11
|
|
3
12
|
.. autosummary::
|
4
13
|
:toctree: .
|
@@ -11,6 +20,6 @@ from lamindb_setup.core.upath import LocalPathClasses, UPath, infer_filesystem
|
|
11
20
|
|
12
21
|
from ._anndata_sizes import size_adata
|
13
22
|
from ._backed_access import AnnDataAccessor, BackedAccessor
|
14
|
-
from ._valid_suffixes import
|
23
|
+
from ._valid_suffixes import VALID_SUFFIXES
|
15
24
|
from .objects import infer_suffix, write_to_disk
|
16
25
|
from .paths import delete_storage, load_to_memory
|
@@ -1,5 +1,19 @@
|
|
1
|
-
from lamindb_setup.core.upath import VALID_COMPOSITE_SUFFIXES,
|
1
|
+
from lamindb_setup.core.upath import VALID_COMPOSITE_SUFFIXES, VALID_SIMPLE_SUFFIXES
|
2
2
|
|
3
3
|
# add new composite suffixes like so
|
4
|
-
VALID_COMPOSITE_SUFFIXES.update(
|
4
|
+
VALID_COMPOSITE_SUFFIXES.update(
|
5
|
+
{
|
6
|
+
".vitessce.json",
|
7
|
+
".ome.zarr",
|
8
|
+
}
|
9
|
+
)
|
5
10
|
# can do the same for simple valid suffixes
|
11
|
+
|
12
|
+
|
13
|
+
class VALID_SUFFIXES:
|
14
|
+
"""Valid suffixes."""
|
15
|
+
|
16
|
+
SIMPLE: set[str] = VALID_SIMPLE_SUFFIXES
|
17
|
+
"""Simple suffixes."""
|
18
|
+
COMPOSITE: set[str] = VALID_COMPOSITE_SUFFIXES
|
19
|
+
"""Composite suffixes."""
|
@@ -15,61 +15,98 @@ if TYPE_CHECKING:
|
|
15
15
|
from vitessce import VitessceConfig
|
16
16
|
|
17
17
|
|
18
|
-
#
|
19
|
-
|
18
|
+
# "unit test": https://github.com/laminlabs/lamindb/blob/main/docs/storage/vitessce.ipynb
|
19
|
+
# integration test & context: https://github.com/laminlabs/lamin-spatial/blob/main/docs/vitessce.ipynb
|
20
|
+
def save_vitessce_config(
|
21
|
+
vitessce_config: VitessceConfig, description: str | None = None
|
22
|
+
) -> Artifact:
|
20
23
|
"""Validates and saves a ``VitessceConfig`` object.
|
21
24
|
|
22
|
-
|
25
|
+
Guide: :doc:`docs:vitessce`.
|
23
26
|
|
24
27
|
Args:
|
25
|
-
vitessce_config (``VitessceConfig``): A VitessceConfig object.
|
26
|
-
description: A description for the artifact.
|
28
|
+
vitessce_config (``VitessceConfig``): A `VitessceConfig` object.
|
29
|
+
description: A description for the `VitessceConfig` artifact.
|
27
30
|
|
31
|
+
.. versionchanged:: 0.75.1
|
32
|
+
Now displays the "Vitessce button" on the hub next to the dataset. It additionally keeps displaying it next to the configuration file.
|
28
33
|
.. versionchanged:: 0.70.2
|
29
|
-
|
34
|
+
No longer saves the dataset. It only saves the `VitessceConfig` object.
|
30
35
|
"""
|
36
|
+
# can only import here because vitessce is not a dependency
|
37
|
+
from vitessce import VitessceConfig
|
38
|
+
|
39
|
+
from lamindb.core.storage import VALID_SUFFIXES
|
40
|
+
|
41
|
+
assert isinstance(vitessce_config, VitessceConfig) # noqa: S101
|
31
42
|
vc_dict = vitessce_config.to_dict()
|
43
|
+
valid_composite_zarr_suffixes = [
|
44
|
+
suffix for suffix in VALID_SUFFIXES.COMPOSITE if suffix.endswith(".zarr")
|
45
|
+
]
|
32
46
|
# validate
|
33
|
-
|
34
|
-
|
35
|
-
for
|
36
|
-
|
37
|
-
|
38
|
-
|
47
|
+
dataset_artifacts = []
|
48
|
+
assert vc_dict["datasets"] # noqa: S101
|
49
|
+
for vitessce_dataset in vc_dict["datasets"]:
|
50
|
+
# didn't find good ways to violate the below, hence using plain asserts
|
51
|
+
# without user feedback
|
52
|
+
assert "files" in vitessce_dataset # noqa: S101
|
53
|
+
assert vitessce_dataset["files"] # noqa: S101
|
54
|
+
for file in vitessce_dataset["files"]:
|
39
55
|
if "url" not in file:
|
40
56
|
raise ValueError("Each file must have a 'url' key.")
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
57
|
+
s3_path = file["url"]
|
58
|
+
s3_path_last_element = s3_path.split("/")[-1]
|
59
|
+
# note 1: the following parses the stem uid of the artifact from the S3 path
|
60
|
+
# there might be a better way of doing this in case the vitessce config
|
61
|
+
# gets updated in the future; but given these paths are set in stone
|
62
|
+
# this should be more robust than it looks
|
63
|
+
#
|
64
|
+
# note 2: what's not great is the fact that people might use composite suffixes we don't recognize
|
65
|
+
# I don't know what to do about it other than documenting it clearly
|
66
|
+
# https://github.com/laminlabs/lamindb/blob/main/lamindb/core/storage/_valid_suffixes.py
|
67
|
+
# https://docs.lamin.ai/lamindb.core.storage.valid_suffixes
|
68
|
+
#
|
69
|
+
# now start with attempting to strip the composite suffix candidates
|
70
|
+
for suffix in valid_composite_zarr_suffixes:
|
71
|
+
s3_path_last_element = s3_path_last_element.replace(suffix, "")
|
72
|
+
# in case there was no hit, strip plain ".zarr"
|
73
|
+
artifact_stem_uid = s3_path_last_element.replace(".zarr", "")
|
74
|
+
# if there is still a "." in string, we
|
75
|
+
if "." in artifact_stem_uid:
|
76
|
+
raise ValueError(
|
77
|
+
f"Suffix should be '.zarr' or one of {valid_composite_zarr_suffixes}. Inspect your path {s3_path}"
|
45
78
|
)
|
46
|
-
|
47
|
-
filename.replace(".anndata.zarr", "")
|
48
|
-
.replace(".spatialdata.zarr", "")
|
49
|
-
.replace(".ome.zarr", "")
|
50
|
-
)
|
51
|
-
artifact = Artifact.filter(uid__startswith=filestem).one_or_none()
|
79
|
+
artifact = Artifact.filter(uid__startswith=artifact_stem_uid).one_or_none()
|
52
80
|
if artifact is None:
|
53
|
-
|
54
|
-
f"
|
81
|
+
raise ValueError(
|
82
|
+
f"Could not find dataset with stem uid '{artifact_stem_uid}' in lamindb: {vitessce_dataset}. Did you follow https://docs.lamin.ai/vitessce? It appears the AWS S3 path doesn't encode a lamindb uid."
|
55
83
|
)
|
56
84
|
else:
|
57
|
-
|
85
|
+
dataset_artifacts.append(artifact)
|
58
86
|
# link inputs
|
59
87
|
with logger.mute():
|
60
|
-
transform = Transform(name="save_vitessce_config", type="function", version="
|
88
|
+
transform = Transform(name="save_vitessce_config", type="function", version="2")
|
61
89
|
transform.save()
|
62
90
|
run = Run(transform=transform)
|
63
91
|
run.save()
|
64
|
-
|
92
|
+
if len(dataset_artifacts) > 1:
|
93
|
+
# if we have more datasets, we should create a collection
|
94
|
+
# and attach an action to the collection
|
95
|
+
raise NotImplementedError
|
96
|
+
run.input_artifacts.set(dataset_artifacts)
|
65
97
|
# create a JSON export
|
66
98
|
config_file_local_path = (
|
67
99
|
ln_setup.settings.storage.cache_dir / "config.vitessce.json"
|
68
100
|
)
|
69
101
|
with open(config_file_local_path, "w") as file:
|
70
102
|
json.dump(vc_dict, file)
|
71
|
-
|
72
|
-
|
103
|
+
vitessce_config_artifact = Artifact(
|
104
|
+
config_file_local_path, description=description, run=run
|
105
|
+
).save()
|
106
|
+
# we have one and only one dataset artifact, hence the following line is OK
|
107
|
+
dataset_artifacts[0]._actions.add(vitessce_config_artifact)
|
73
108
|
slug = ln_setup.settings.instance.slug
|
74
|
-
logger.important(
|
75
|
-
|
109
|
+
logger.important(
|
110
|
+
f"go to: https://lamin.ai/{slug}/artifact/{vitessce_config_artifact.uid}"
|
111
|
+
)
|
112
|
+
return vitessce_config_artifact
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: lamindb
|
3
|
-
Version: 0.75.
|
3
|
+
Version: 0.75.1
|
4
4
|
Summary: A data framework for biology.
|
5
5
|
Author-email: Lamin Labs <open-source@lamin.ai>
|
6
6
|
Requires-Python: >=3.8
|
@@ -9,8 +9,8 @@ Classifier: Programming Language :: Python :: 3.8
|
|
9
9
|
Classifier: Programming Language :: Python :: 3.9
|
10
10
|
Classifier: Programming Language :: Python :: 3.10
|
11
11
|
Classifier: Programming Language :: Python :: 3.11
|
12
|
-
Requires-Dist: lnschema_core==0.72.
|
13
|
-
Requires-Dist: lamindb_setup==0.76.
|
12
|
+
Requires-Dist: lnschema_core==0.72.2
|
13
|
+
Requires-Dist: lamindb_setup==0.76.3
|
14
14
|
Requires-Dist: lamin_utils==0.13.2
|
15
15
|
Requires-Dist: lamin_cli==0.16.0
|
16
16
|
Requires-Dist: rapidfuzz
|
@@ -24,7 +24,7 @@ Requires-Dist: pandas
|
|
24
24
|
Requires-Dist: graphviz
|
25
25
|
Requires-Dist: psycopg2-binary
|
26
26
|
Requires-Dist: lamindb_setup[aws] ; extra == "aws"
|
27
|
-
Requires-Dist: bionty==0.
|
27
|
+
Requires-Dist: bionty==0.48.0 ; extra == "bionty"
|
28
28
|
Requires-Dist: pre-commit ; extra == "dev"
|
29
29
|
Requires-Dist: nox ; extra == "dev"
|
30
30
|
Requires-Dist: laminci>=0.3 ; extra == "dev"
|
@@ -1,28 +1,28 @@
|
|
1
|
-
lamindb/__init__.py,sha256=
|
1
|
+
lamindb/__init__.py,sha256=i66mHHYh9TUGKmCb5WgvaZx0flzOQyKKLcCpz01_8X0,2249
|
2
2
|
lamindb/_artifact.py,sha256=pu0d2CuRkT4xP5hLpkrKlSPU3Maihmdk1B7VKu-cjj4,42575
|
3
|
-
lamindb/_can_validate.py,sha256=
|
3
|
+
lamindb/_can_validate.py,sha256=jPZHhtPaZJos5bL8Mk8ZNh34mItwYRwOynhofKUxwfY,17472
|
4
4
|
lamindb/_collection.py,sha256=vrvuww4MLPx6qHqRWy6tLvRHOmXdvEjYN7dnG9DIIPU,14894
|
5
|
-
lamindb/_curate.py,sha256=
|
5
|
+
lamindb/_curate.py,sha256=M42XxtcSKSo2Vh3xCio1UogVS0kCG1Dtx5cwEwnWOEM,55508
|
6
6
|
lamindb/_feature.py,sha256=hLj5KDhIVkZrIa7IbiHGyUBGZS7PeDNxKsNK1EadBAc,7377
|
7
7
|
lamindb/_feature_set.py,sha256=DmAy96V_RyV0yiyvWOCHgustXPsCaMwn4TrWwh2qDd8,8104
|
8
8
|
lamindb/_filter.py,sha256=I1tSIF-izmD48YpB8NtKmau59Vpt6C54RPHWc3oinGM,1412
|
9
9
|
lamindb/_finish.py,sha256=3rGY4RxhcKR1BIdgf6GPB03AArhlV5vYtD6wxtTHYxE,10817
|
10
|
-
lamindb/_from_values.py,sha256=
|
10
|
+
lamindb/_from_values.py,sha256=tE6LKWbixZWbt-ILsy2EeRh7i9eKvvAeJv081VQRGAk,12859
|
11
11
|
lamindb/_is_versioned.py,sha256=Z_zVsHTnNaWvD15dEz18VocsSgka53jUzs_wDr78ltI,1344
|
12
12
|
lamindb/_parents.py,sha256=eMavdd6IO6STOVJSlR2TzdRtx6sKYDKsMOtlR3DZlgQ,15599
|
13
13
|
lamindb/_query_manager.py,sha256=6_ZqQr0SKTYsbMtJd5BmaMoyASIVel5v2F1KMgacWlU,4252
|
14
14
|
lamindb/_query_set.py,sha256=LM5NsAWy5FCZZSxX1VbE20RdA5nsyk4_5p4abuMjdcI,11662
|
15
|
-
lamindb/_record.py,sha256=
|
15
|
+
lamindb/_record.py,sha256=XtNKZol9X5u3h1fecDhOn5Z1OpTXunQ9UrZwcHSiajM,19219
|
16
16
|
lamindb/_run.py,sha256=xj3ER4F_yWvuNw1mr0XU-QuIPi5hBO7Ue0ygBgJQ6mc,1887
|
17
|
-
lamindb/_save.py,sha256=
|
17
|
+
lamindb/_save.py,sha256=9lpFpQLgmPOp6JcoM9XetNkbYu2JgY70sGQZVz3Gzmw,11027
|
18
18
|
lamindb/_storage.py,sha256=GBVChv-DHVMNEBJL5l_JT6B4RDhZ6NnwgzmUICphYKk,413
|
19
19
|
lamindb/_transform.py,sha256=OtZmCSS-mxWPJU0S6p79sYauY-cKIxqBYfeMX0-SQ_A,3435
|
20
20
|
lamindb/_ulabel.py,sha256=XDSdZBXX_ki5s1vOths3MjF2x5DPggBR_PV_KF4SGyg,1611
|
21
21
|
lamindb/_utils.py,sha256=LGdiW4k3GClLz65vKAVRkL6Tw-Gkx9DWAdez1jyA5bE,428
|
22
|
-
lamindb/_view.py,sha256=
|
23
|
-
lamindb/core/__init__.py,sha256=
|
24
|
-
lamindb/core/_data.py,sha256=
|
25
|
-
lamindb/core/_feature_manager.py,sha256=
|
22
|
+
lamindb/_view.py,sha256=4Ln2ItTb3857PAI-70O8eJYqoTJ_NNFc7E_wds6OGns,2412
|
23
|
+
lamindb/core/__init__.py,sha256=uCtTkcUwJ7w40cWdaVBymiyxMuKlkdX-QZMtOr3k0us,1441
|
24
|
+
lamindb/core/_data.py,sha256=AbBVvutI7iFZW5PVEYzx0HIlaLhR9KpnoPyba9OI86k,16253
|
25
|
+
lamindb/core/_feature_manager.py,sha256=gJowe9-tifi0Z5IcChV-jtGYVdl6XgR2m_oswwhU17Y,31980
|
26
26
|
lamindb/core/_label_manager.py,sha256=5jbBF9aYPeeqpDZDimAXskGw76YUaQTQak6XAt6madU,9183
|
27
27
|
lamindb/core/_mapped_collection.py,sha256=wN2qEXnKrx0kqblVml_Kx9hYomUAZLYKckGXX4-9dr0,19621
|
28
28
|
lamindb/core/_run_context.py,sha256=bk4hwbGbx1no-JKVpLioIOU5dyO8YCdg-srbQV7UuGE,18371
|
@@ -31,17 +31,17 @@ lamindb/core/_sync_git.py,sha256=qc0yfPyKeG4uuNT_3qsv-mkIMqhLFqfXNeNVO49vV00,454
|
|
31
31
|
lamindb/core/_track_environment.py,sha256=STzEVUzOeUEWdX7WDJUkKH4u08k7eupRX6AXQwoVt14,828
|
32
32
|
lamindb/core/exceptions.py,sha256=rNLDlqDJt6stM_HGeE9qR0oWRNn4Kq0WDdIi85P53VA,1057
|
33
33
|
lamindb/core/fields.py,sha256=47Jmh3efUr5ZscgimR_yckY-I3cNf8ScLutbwKCK3j4,162
|
34
|
-
lamindb/core/schema.py,sha256=
|
34
|
+
lamindb/core/schema.py,sha256=KiYQn_8fokSMztTNDe6qUocZzKXWxU32H-YChNJv51A,1877
|
35
35
|
lamindb/core/types.py,sha256=uVBqSVLoQaTkqP9nqsJhwU6yYnx8H5e6-ZxrB6vpOOw,265
|
36
36
|
lamindb/core/versioning.py,sha256=8fapNQmpxlUaiJG9oo9Y4I7xtFXzD077dMwzkeWTMMY,4965
|
37
37
|
lamindb/core/datasets/__init__.py,sha256=zRP98oqUAaXhqWyKMiH0s_ImVIuNeziQQ2kQ_t0f-DI,1353
|
38
38
|
lamindb/core/datasets/_core.py,sha256=04mqj3IVIpY97HlD7VVL6-E6tf7za9suzE3lH07Z698,19564
|
39
39
|
lamindb/core/datasets/_fake.py,sha256=BZF9R_1iF0HDnvtZNqL2FtsjSMuqDIfuFxnw_LJYIh4,953
|
40
|
-
lamindb/core/storage/__init__.py,sha256=
|
40
|
+
lamindb/core/storage/__init__.py,sha256=MjKg2-p8EbOYTVsgufnK93ut7HG7_MzLDAqtzXt0U2Q,501
|
41
41
|
lamindb/core/storage/_anndata_accessor.py,sha256=jmEZeeZlt8-qBXRkU0tTA-t6dVEb_dH86wc1ok0jSRY,24030
|
42
42
|
lamindb/core/storage/_anndata_sizes.py,sha256=aXO3OB--tF5MChenSsigW6Q-RuE8YJJOUTVukkLrv9A,1029
|
43
43
|
lamindb/core/storage/_backed_access.py,sha256=MsSgiIccHVhqOcur2lZ4mj5LSIL5OL8nX4eqK6mloU0,4732
|
44
|
-
lamindb/core/storage/_valid_suffixes.py,sha256=
|
44
|
+
lamindb/core/storage/_valid_suffixes.py,sha256=9erE4FX1ArRoTkvn5pzUmlKQSYnKeQBymOnOPCv2TD4,465
|
45
45
|
lamindb/core/storage/_zarr.py,sha256=5ceEz6YIvgvUnVVNWhK5Z4W0WfrvyvY82Yna5jSX1_E,3661
|
46
46
|
lamindb/core/storage/objects.py,sha256=OzvBCS-Urz5mr-O95qYt6RGBDDX5HmjfRRKWPPDn1ZE,1797
|
47
47
|
lamindb/core/storage/paths.py,sha256=I0UjQfXfh3MptfLgpA0iSyR-X9pLOvgtXNr4B_Lwk4g,7810
|
@@ -49,10 +49,10 @@ lamindb/core/subsettings/__init__.py,sha256=KFHPzIE7f7Bj4RgMjGQF4CjTdHVG_VNFBrCn
|
|
49
49
|
lamindb/core/subsettings/_creation_settings.py,sha256=54mfMH_osC753hpxcl7Dq1rwBD2LHnWveXtQpkLBITE,1194
|
50
50
|
lamindb/core/subsettings/_transform_settings.py,sha256=4YbCuZtJo6zdytl6UQR4GvdDkTtT6SRBqVzofGzNOt8,583
|
51
51
|
lamindb/integrations/__init__.py,sha256=MoLRD_qqX5WHFUAqHL6zoY_cDkWH0zimaGT_1CyXKnk,124
|
52
|
-
lamindb/integrations/_vitessce.py,sha256=
|
52
|
+
lamindb/integrations/_vitessce.py,sha256=jcpLUNFq1BsDpZDkG5L3nzWNXDLuy3Eep_GfY0XqhhA,5077
|
53
53
|
lamindb/setup/__init__.py,sha256=OwZpZzPDv5lPPGXZP7-zK6UdO4FHvvuBh439yZvIp3A,410
|
54
54
|
lamindb/setup/core/__init__.py,sha256=SevlVrc2AZWL3uALbE5sopxBnIZPWZ1IB0NBDudiAL8,167
|
55
|
-
lamindb-0.75.
|
56
|
-
lamindb-0.75.
|
57
|
-
lamindb-0.75.
|
58
|
-
lamindb-0.75.
|
55
|
+
lamindb-0.75.1.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
56
|
+
lamindb-0.75.1.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81
|
57
|
+
lamindb-0.75.1.dist-info/METADATA,sha256=dhUZDNTu6BtE-J67uGuRwJMQEJk8V_NpEurzVc90GoM,2669
|
58
|
+
lamindb-0.75.1.dist-info/RECORD,,
|