lamindb 0.48a2__py3-none-any.whl → 0.48.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 +15 -24
- lamindb/_context.py +5 -2
- lamindb/_dataset.py +6 -3
- lamindb/_delete.py +6 -6
- lamindb/_feature.py +61 -26
- lamindb/_feature_manager.py +176 -0
- lamindb/_feature_set.py +63 -27
- lamindb/_file.py +120 -76
- lamindb/_from_values.py +88 -28
- lamindb/_label.py +85 -0
- lamindb/_logger.py +1 -1
- lamindb/_manager.py +24 -17
- lamindb/_orm.py +157 -33
- lamindb/_queryset.py +37 -35
- lamindb/_save.py +19 -9
- lamindb/_transform.py +12 -3
- lamindb/_view.py +1 -1
- lamindb/dev/__init__.py +4 -0
- lamindb/dev/_settings.py +1 -1
- lamindb/dev/_view_parents.py +70 -34
- lamindb/dev/datasets/__init__.py +12 -0
- lamindb/dev/datasets/_core.py +116 -65
- lamindb/dev/storage/__init__.py +1 -5
- lamindb/dev/storage/_backed_access.py +505 -379
- lamindb/dev/storage/file.py +3 -1
- {lamindb-0.48a2.dist-info → lamindb-0.48.1.dist-info}/METADATA +10 -8
- lamindb-0.48.1.dist-info/RECORD +42 -0
- lamindb/_category.py +0 -42
- lamindb-0.48a2.dist-info/RECORD +0 -41
- {lamindb-0.48a2.dist-info → lamindb-0.48.1.dist-info}/LICENSE +0 -0
- {lamindb-0.48a2.dist-info → lamindb-0.48.1.dist-info}/WHEEL +0 -0
- {lamindb-0.48a2.dist-info → lamindb-0.48.1.dist-info}/entry_points.txt +0 -0
lamindb/_manager.py
CHANGED
@@ -8,38 +8,45 @@ class Manager(models.Manager):
|
|
8
8
|
|
9
9
|
See Also:
|
10
10
|
|
11
|
+
:class:`lamindb.dev.QuerySet`
|
11
12
|
`django Manager <https://docs.djangoproject.com/en/4.2/topics/db/managers/>`__
|
12
13
|
|
13
14
|
Examples:
|
14
15
|
|
15
|
-
>>> ln.save(ln.
|
16
|
-
>>>
|
17
|
-
>>> ln.
|
18
|
-
>>>
|
19
|
-
>>>
|
20
|
-
>>> manager =
|
16
|
+
>>> ln.save(ln.Label.from_values(["Label1", "Label2", "Label3"], field="name"))
|
17
|
+
>>> labels = ln.Label.select(name__icontains = "label").all()
|
18
|
+
>>> ln.Label(name="Label1").save()
|
19
|
+
>>> label = ln.Label.select(name="Label1").one()
|
20
|
+
>>> label.parents.set(labels)
|
21
|
+
>>> manager = label.parents
|
22
|
+
>>> manager.df()
|
21
23
|
"""
|
22
24
|
|
23
25
|
def list(self, field: Optional[str] = None):
|
24
26
|
"""Populate a list with the results.
|
25
27
|
|
26
28
|
Examples:
|
27
|
-
>>> ln.save(ln.
|
28
|
-
>>>
|
29
|
-
>>> ln.
|
30
|
-
>>>
|
31
|
-
>>>
|
32
|
-
>>>
|
33
|
-
[
|
34
|
-
|
35
|
-
|
36
|
-
>>>
|
37
|
-
['
|
29
|
+
>>> ln.save(ln.Label.from_values(["Label1", "Label2", "Label3"], field="name"))
|
30
|
+
>>> labels = ln.Label.select(name__icontains = "label").all()
|
31
|
+
>>> ln.Label(name="Label1").save()
|
32
|
+
>>> label = ln.Label.select(name="Label1").one()
|
33
|
+
>>> label.parents.set(labels)
|
34
|
+
>>> label.parents.list()
|
35
|
+
[Label(id=sFMcPepC, name=Label1, updated_at=2023-07-19 19:45:17, created_by_id=DzTjkKse), # noqa
|
36
|
+
Label(id=2SscQvsM, name=Label2, updated_at=2023-07-19 19:45:17, created_by_id=DzTjkKse), # noqa
|
37
|
+
Label(id=lecV87vi, name=Label3, updated_at=2023-07-19 19:45:17, created_by_id=DzTjkKse)] # noqa
|
38
|
+
>>> label.parents.list("name")
|
39
|
+
['Label1', 'Label2', 'Label3']
|
38
40
|
"""
|
39
41
|
if field is None:
|
40
42
|
return [item for item in self.all()]
|
41
43
|
else:
|
42
44
|
return [item for item in self.values_list(field, flat=True)]
|
43
45
|
|
46
|
+
def df(self, **kwargs):
|
47
|
+
"""Convert to DataFrame."""
|
48
|
+
return self.all().df(**kwargs)
|
49
|
+
|
44
50
|
|
45
51
|
setattr(models.Manager, "list", Manager.list)
|
52
|
+
setattr(models.Manager, "df", Manager.df)
|
lamindb/_orm.py
CHANGED
@@ -5,9 +5,9 @@ import pandas as pd
|
|
5
5
|
from django.core.exceptions import FieldDoesNotExist
|
6
6
|
from django.db.models import Manager, QuerySet
|
7
7
|
from django.db.models.query_utils import DeferredAttribute as Field
|
8
|
-
from
|
9
|
-
from
|
10
|
-
from
|
8
|
+
from lamin_utils import colors, logger
|
9
|
+
from lamin_utils._lookup import Lookup
|
10
|
+
from lamin_utils._search import search as base_search
|
11
11
|
from lamindb_setup.dev._docs import doc_args
|
12
12
|
from lnschema_core import ORM
|
13
13
|
from lnschema_core.models import format_datetime
|
@@ -16,7 +16,9 @@ from lnschema_core.types import ListLike, StrField
|
|
16
16
|
from lamindb.dev.utils import attach_func_to_class_method
|
17
17
|
|
18
18
|
from . import _TESTING
|
19
|
+
from ._feature_manager import create_features_df
|
19
20
|
from ._from_values import _has_species_field, get_or_create_records
|
21
|
+
from .dev._settings import settings
|
20
22
|
|
21
23
|
IPYTHON = getattr(builtins, "__IPYTHON__", False)
|
22
24
|
|
@@ -105,7 +107,12 @@ def __init__(orm: ORM, *args, **kwargs):
|
|
105
107
|
super(ORM, orm).__init__(*args, **kwargs)
|
106
108
|
|
107
109
|
|
108
|
-
def view_parents(
|
110
|
+
def view_parents(
|
111
|
+
self,
|
112
|
+
field: Optional[StrField] = None,
|
113
|
+
with_children: bool = False,
|
114
|
+
distance: int = 100,
|
115
|
+
):
|
109
116
|
from lamindb.dev._view_parents import view_parents as _view_parents
|
110
117
|
|
111
118
|
if field is None:
|
@@ -113,7 +120,9 @@ def view_parents(self, field: Optional[StrField] = None, distance: int = 100):
|
|
113
120
|
if not isinstance(field, str):
|
114
121
|
field = field.field.name
|
115
122
|
|
116
|
-
return _view_parents(
|
123
|
+
return _view_parents(
|
124
|
+
record=self, field=field, with_children=with_children, distance=distance
|
125
|
+
)
|
117
126
|
|
118
127
|
|
119
128
|
@classmethod # type:ignore
|
@@ -281,7 +290,7 @@ def _inspect(
|
|
281
290
|
**kwargs,
|
282
291
|
) -> Union["pd.DataFrame", Dict[str, List[str]]]:
|
283
292
|
"""{}"""
|
284
|
-
from
|
293
|
+
from lamin_utils._inspect import inspect
|
285
294
|
|
286
295
|
if not isinstance(field, str):
|
287
296
|
field = field.field.name
|
@@ -337,7 +346,7 @@ def _map_synonyms(
|
|
337
346
|
**kwargs,
|
338
347
|
) -> Union[List[str], Dict[str, str]]:
|
339
348
|
"""{}"""
|
340
|
-
from
|
349
|
+
from lamin_utils._map_synonyms import map_synonyms
|
341
350
|
|
342
351
|
if field is None:
|
343
352
|
field = get_default_str_field(cls)
|
@@ -388,9 +397,40 @@ def map_synonyms(
|
|
388
397
|
)
|
389
398
|
|
390
399
|
|
400
|
+
def _labels_with_feature_names(labels: Union[QuerySet, Manager]) -> Dict:
|
401
|
+
from django.db.models import F
|
402
|
+
|
403
|
+
df = labels.annotate(feature_name=F("feature__name")).df()
|
404
|
+
return df.groupby("feature_name")["name"].apply(list).to_dict()
|
405
|
+
|
406
|
+
|
391
407
|
def describe(self):
|
392
|
-
model_name = self.__class__.__name__
|
408
|
+
model_name = colors.green(self.__class__.__name__)
|
393
409
|
msg = ""
|
410
|
+
|
411
|
+
def dict_related_model_to_related_name(orm):
|
412
|
+
d: Dict = {
|
413
|
+
f"{i.related_model.__get_schema_name__()}.{i.related_model.__name__}": (
|
414
|
+
i.related_name
|
415
|
+
)
|
416
|
+
for i in orm._meta.related_objects
|
417
|
+
if i.related_name is not None
|
418
|
+
}
|
419
|
+
d.update(
|
420
|
+
{
|
421
|
+
f"{i.related_model.__get_schema_name__()}.{i.related_model.__name__}": (
|
422
|
+
i.name
|
423
|
+
)
|
424
|
+
for i in orm._meta.many_to_many
|
425
|
+
if i.name is not None
|
426
|
+
}
|
427
|
+
)
|
428
|
+
|
429
|
+
return d
|
430
|
+
|
431
|
+
file_related_models = dict_related_model_to_related_name(self)
|
432
|
+
|
433
|
+
# Display the file record
|
394
434
|
fields = self._meta.fields
|
395
435
|
direct_fields = []
|
396
436
|
foreign_key_fields = []
|
@@ -399,42 +439,126 @@ def describe(self):
|
|
399
439
|
foreign_key_fields.append(f.name)
|
400
440
|
else:
|
401
441
|
direct_fields.append(f.name)
|
442
|
+
|
443
|
+
# Display Provenance
|
402
444
|
# display line by line the foreign key fields
|
445
|
+
emojis = {"storage": "💾", "created_by": "👤", "transform": "💫", "run": "🚗"}
|
403
446
|
if len(foreign_key_fields) > 0:
|
404
447
|
record_msg = f"{model_name}({''.join([f'{i}={self.__getattribute__(i)}, ' for i in direct_fields])})" # noqa
|
405
448
|
msg += f"{record_msg.rstrip(', )')})\n\n"
|
406
449
|
|
407
|
-
msg += "
|
450
|
+
msg += f"{colors.green('Provenance')}:\n "
|
408
451
|
related_msg = "".join(
|
409
|
-
[
|
452
|
+
[
|
453
|
+
f"{emojis.get(i, '📎')} {i}: {self.__getattribute__(i)}\n "
|
454
|
+
for i in foreign_key_fields
|
455
|
+
]
|
410
456
|
)
|
411
457
|
msg += related_msg
|
458
|
+
# input of
|
459
|
+
if self.input_of.exists():
|
460
|
+
values = [format_datetime(i.run_at) for i in self.input_of.all()]
|
461
|
+
msg += f"⬇️ input_of ({colors.italic('core.Run')}): {values}\n "
|
412
462
|
msg = msg.rstrip(" ")
|
413
463
|
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
464
|
+
if not self.feature_sets.exists():
|
465
|
+
print(msg)
|
466
|
+
return
|
467
|
+
else:
|
468
|
+
feature_sets_related_models = dict_related_model_to_related_name(
|
469
|
+
self.feature_sets.first()
|
470
|
+
)
|
471
|
+
# Display Features by slot
|
472
|
+
msg += f"{colors.green('Features')}:\n"
|
473
|
+
# var
|
474
|
+
feature_sets = self.feature_sets.exclude(ref_orm="Feature")
|
475
|
+
if feature_sets.exists():
|
476
|
+
for feature_set in feature_sets.all():
|
477
|
+
key = f"{feature_set.ref_schema}.{feature_set.ref_orm}"
|
478
|
+
related_name = feature_sets_related_models.get(key)
|
479
|
+
values = (
|
480
|
+
feature_set.__getattribute__(related_name)
|
481
|
+
.all()[:5]
|
482
|
+
.list(feature_set.ref_field)
|
483
|
+
)
|
484
|
+
slots = self.feature_sets.through.objects.filter(
|
485
|
+
file=self, feature_set=feature_set
|
486
|
+
).list("slot")
|
487
|
+
for slot in slots:
|
488
|
+
if slot == "var":
|
489
|
+
slot += " (X)"
|
490
|
+
msg += f" 🗺️ {colors.bold(slot)}:\n"
|
491
|
+
ref = colors.italic(f"{key}.{feature_set.ref_field}")
|
492
|
+
msg += f" 🔗 index ({feature_set.n}, {ref}): {values}\n".replace(
|
493
|
+
"]", "...]"
|
494
|
+
)
|
495
|
+
|
496
|
+
# obs
|
497
|
+
# ref_orm=Feature, combine all features into one dataframe
|
498
|
+
feature_sets = self.feature_sets.filter(ref_orm="Feature").all()
|
499
|
+
if feature_sets.exists():
|
500
|
+
features_df = create_features_df(
|
501
|
+
file=self, feature_sets=feature_sets.all(), exclude=True
|
502
|
+
)
|
503
|
+
for slot in features_df["slot"].unique():
|
504
|
+
df_slot = features_df[features_df.slot == slot]
|
505
|
+
if slot == "obs":
|
506
|
+
slot += " (metadata)"
|
507
|
+
msg += f" 🗺️ {colors.bold(slot)}:\n"
|
508
|
+
df_label_index = df_slot[
|
509
|
+
(df_slot["labels_orm"] == "Label")
|
510
|
+
& (df_slot["labels_schema"] == "core")
|
511
|
+
].index
|
512
|
+
|
513
|
+
# for labels
|
514
|
+
if len(df_label_index) > 0:
|
515
|
+
labels_schema = "core"
|
516
|
+
labels_orm = "Label"
|
517
|
+
key = f"{labels_schema}.{labels_orm}"
|
518
|
+
related_name = file_related_models.get(key)
|
519
|
+
related_objects = self.__getattribute__(related_name)
|
520
|
+
labels = _labels_with_feature_names(related_objects)
|
521
|
+
msg_objects = ""
|
522
|
+
for k, v in labels.items():
|
523
|
+
msg_objects_k = (
|
524
|
+
f" 🔗 {k} ({len(v)}, {colors.italic(key)}): {v[:5]}\n"
|
525
|
+
)
|
526
|
+
if len(v) > 5:
|
527
|
+
msg_objects_k = msg_objects_k.replace("]", " ... ]")
|
528
|
+
msg_objects += msg_objects_k
|
529
|
+
msg += msg_objects
|
530
|
+
|
531
|
+
# for non-labels
|
532
|
+
nonlabel_index = df_slot.index.difference(df_label_index)
|
533
|
+
if len(nonlabel_index) == 0:
|
534
|
+
continue
|
535
|
+
df_nonlabels = df_slot.loc[nonlabel_index]
|
536
|
+
df_nonlabels = (
|
537
|
+
df_nonlabels.groupby(["labels_schema", "labels_orm"], group_keys=False)[
|
538
|
+
"name"
|
539
|
+
]
|
540
|
+
.apply(lambda x: "|".join(x))
|
541
|
+
.reset_index()
|
542
|
+
)
|
543
|
+
for _, row in df_nonlabels.iterrows():
|
544
|
+
key = f"{row.labels_schema}.{row.labels_orm}"
|
545
|
+
related_name = file_related_models.get(key)
|
546
|
+
related_objects = self.__getattribute__(related_name)
|
547
|
+
count = related_objects.count()
|
548
|
+
count_str = f"{count}, {colors.italic(f'{key}')}"
|
549
|
+
try:
|
550
|
+
field = get_default_str_field(related_objects)
|
551
|
+
except ValueError:
|
552
|
+
field = "id"
|
553
|
+
values = list(related_objects.values_list(field, flat=True)[:5])
|
554
|
+
msg_objects = f" 🔗 {row['name']} ({count_str}): {values}\n"
|
555
|
+
msg += msg_objects
|
435
556
|
msg = msg.rstrip("\n")
|
436
|
-
msg = msg.rstrip("
|
437
|
-
|
557
|
+
msg = msg.rstrip("Features:")
|
558
|
+
verbosity = settings.verbosity
|
559
|
+
settings.verbosity = 2
|
560
|
+
logger.info(msg)
|
561
|
+
settings.verbosity = verbosity
|
438
562
|
|
439
563
|
|
440
564
|
def set_abbr(self, value: str):
|
lamindb/_queryset.py
CHANGED
@@ -36,10 +36,10 @@ class QuerySet(models.QuerySet):
|
|
36
36
|
|
37
37
|
Examples:
|
38
38
|
|
39
|
-
>>> ln.
|
40
|
-
>>> queryset = ln.
|
39
|
+
>>> ln.Label(name="my label").save()
|
40
|
+
>>> queryset = ln.Label.select(name="my label")
|
41
41
|
>>> queryset
|
42
|
-
<QuerySet [
|
42
|
+
<QuerySet [Label(id=MIeZISeF, name=my label, updated_at=2023-07-19 19:53:34, created_by_id=DzTjkKse)]> # noqa
|
43
43
|
"""
|
44
44
|
|
45
45
|
def df(self, include: Optional[List[str]] = None):
|
@@ -52,27 +52,27 @@ class QuerySet(models.QuerySet):
|
|
52
52
|
|
53
53
|
Args:
|
54
54
|
include: ``Optional[List[str]] = None`` Additional (many-to-many)
|
55
|
-
fields to include. Takes expressions like ``"
|
55
|
+
fields to include. Takes expressions like ``"labels__name"``
|
56
56
|
``"cell_types__name"``.
|
57
57
|
|
58
58
|
Examples:
|
59
59
|
|
60
|
-
>>> ln.save(ln.
|
61
|
-
>>> ln.
|
60
|
+
>>> ln.save(ln.Label.from_values(["Label1", "Label2", "Label3"], field="name")) # noqa
|
61
|
+
>>> ln.Label.select().df()
|
62
62
|
name external_id updated_at created_by_id
|
63
63
|
id
|
64
|
-
wsCyIq2Z
|
65
|
-
MvpDP8Y3
|
66
|
-
zKFFabCu
|
67
|
-
>>>
|
68
|
-
>>>
|
69
|
-
>>>
|
70
|
-
>>> ln.
|
71
|
-
|
64
|
+
wsCyIq2Z Label1 None 2023-07-19 19:14:08 DzTjkKse
|
65
|
+
MvpDP8Y3 Label2 None 2023-07-19 19:14:08 DzTjkKse
|
66
|
+
zKFFabCu Label3 None 2023-07-19 19:14:08 DzTjkKse
|
67
|
+
>>> label = ln.Label.select(name="Label1").one()
|
68
|
+
>>> label = ln.Label.select(name="benchmark").one()
|
69
|
+
>>> label.parents.add(label)
|
70
|
+
>>> ln.Label.select().df(include=["labels__name", "labels__created_by_id"])
|
71
|
+
labels__name labels__created_by_id name external_id updated_at created_by_id # noqa
|
72
72
|
id
|
73
|
-
wsCyIq2Z [benchmark] [DzTjkKse]
|
74
|
-
MvpDP8Y3 None None
|
75
|
-
zKFFabCu None None
|
73
|
+
wsCyIq2Z [benchmark] [DzTjkKse] Label1 None 2023-07-19 19:14:08 DzTjkKse # noqa
|
74
|
+
MvpDP8Y3 None None Label2 None 2023-07-19 19:14:08 DzTjkKse # noqa
|
75
|
+
zKFFabCu None None Label3 None 2023-07-19 19:14:08 DzTjkKse # noqa
|
76
76
|
"""
|
77
77
|
data = self.values()
|
78
78
|
if len(data) > 0:
|
@@ -100,6 +100,8 @@ class QuerySet(models.QuerySet):
|
|
100
100
|
df.run_at = format_and_convert_to_local_time(df.run_at)
|
101
101
|
if "id" in df.columns:
|
102
102
|
df = df.set_index("id")
|
103
|
+
if len(df) == 0:
|
104
|
+
return df
|
103
105
|
if include is not None:
|
104
106
|
if isinstance(include, str):
|
105
107
|
include = [include]
|
@@ -121,7 +123,7 @@ class QuerySet(models.QuerySet):
|
|
121
123
|
if field.field.model != ORM
|
122
124
|
else field.field.related_model
|
123
125
|
)
|
124
|
-
if
|
126
|
+
if ORM == related_ORM:
|
125
127
|
left_side_link_model = f"from_{ORM.__name__.lower()}"
|
126
128
|
values_expression = f"to_{ORM.__name__.lower()}__{lookup_str}"
|
127
129
|
else:
|
@@ -135,7 +137,7 @@ class QuerySet(models.QuerySet):
|
|
135
137
|
link_groupby = link_df.groupby(left_side_link_model)[
|
136
138
|
values_expression
|
137
139
|
].apply(list)
|
138
|
-
df = pd.concat((link_groupby, df), axis=1)
|
140
|
+
df = pd.concat((link_groupby, df), axis=1, join="inner")
|
139
141
|
df.rename(columns={values_expression: expression}, inplace=True)
|
140
142
|
return df
|
141
143
|
|
@@ -144,14 +146,14 @@ class QuerySet(models.QuerySet):
|
|
144
146
|
|
145
147
|
Examples:
|
146
148
|
|
147
|
-
>>> ln.save(ln.
|
148
|
-
>>> queryset = ln.
|
149
|
+
>>> ln.save(ln.Label.from_values(["Label1", "Label2", "Label3"], field="name")) # noqa
|
150
|
+
>>> queryset = ln.Label.select(name__icontains = "project")
|
149
151
|
>>> queryset.list()
|
150
|
-
[
|
151
|
-
|
152
|
-
|
152
|
+
[Label(id=NAgTZxoo, name=Label1, updated_at=2023-07-19 19:25:48, created_by_id=DzTjkKse), # noqa
|
153
|
+
Label(id=bnsAgKRC, name=Label2, updated_at=2023-07-19 19:25:48, created_by_id=DzTjkKse), # noqa
|
154
|
+
Label(id=R8xhAJNE, name=Label3, updated_at=2023-07-19 19:25:48, created_by_id=DzTjkKse)] # noqa
|
153
155
|
>>> queryset.list("name")
|
154
|
-
['
|
156
|
+
['Label1', 'Label2', 'Label3']
|
155
157
|
"""
|
156
158
|
if field is None:
|
157
159
|
return [item for item in self]
|
@@ -162,10 +164,10 @@ class QuerySet(models.QuerySet):
|
|
162
164
|
"""If non-empty, the first result in the query set, otherwise None.
|
163
165
|
|
164
166
|
Examples:
|
165
|
-
>>> ln.save(ln.
|
166
|
-
>>> queryset = ln.
|
167
|
+
>>> ln.save(ln.Label.from_values(["Label1", "Label2", "Label3"], field="name")) # noqa
|
168
|
+
>>> queryset = ln.Label.select(name__icontains = "project")
|
167
169
|
>>> queryset.first()
|
168
|
-
|
170
|
+
Label(id=NAgTZxoo, name=Label1, updated_at=2023-07-19 19:25:48, created_by_id=DzTjkKse) # noqa
|
169
171
|
"""
|
170
172
|
if len(self) == 0:
|
171
173
|
return None
|
@@ -175,9 +177,9 @@ class QuerySet(models.QuerySet):
|
|
175
177
|
"""Exactly one result. Throws error if there are more or none.
|
176
178
|
|
177
179
|
Examples:
|
178
|
-
>>> ln.
|
179
|
-
>>> ln.
|
180
|
-
|
180
|
+
>>> ln.Label(name="benchmark").save()
|
181
|
+
>>> ln.Label.select(name="benchmark").one()
|
182
|
+
Label(id=gznl0GZk, name=benchmark, updated_at=2023-07-19 19:39:01, created_by_id=DzTjkKse) # noqa
|
181
183
|
"""
|
182
184
|
if len(self) == 0:
|
183
185
|
raise NoResultFound
|
@@ -190,10 +192,10 @@ class QuerySet(models.QuerySet):
|
|
190
192
|
"""At most one result. Returns it if there is one, otherwise returns None.
|
191
193
|
|
192
194
|
Examples:
|
193
|
-
>>> ln.
|
194
|
-
>>> ln.
|
195
|
-
|
196
|
-
>>> ln.
|
195
|
+
>>> ln.Label(name="benchmark").save()
|
196
|
+
>>> ln.Label.select(name="benchmark").one_or_none()
|
197
|
+
Label(id=gznl0GZk, name=benchmark, updated_at=2023-07-19 19:39:01, created_by_id=DzTjkKse) # noqa
|
198
|
+
>>> ln.Label.select(name="non existing label").one_or_none()
|
197
199
|
None
|
198
200
|
"""
|
199
201
|
if len(self) == 0:
|
lamindb/_save.py
CHANGED
@@ -7,7 +7,7 @@ from typing import Iterable, List, Optional, Tuple, Union, overload # noqa
|
|
7
7
|
|
8
8
|
import lamindb_setup
|
9
9
|
from django.db import transaction
|
10
|
-
from
|
10
|
+
from lamin_utils import logger
|
11
11
|
from lnschema_core.models import ORM, File
|
12
12
|
|
13
13
|
from lamindb.dev.storage import store_object
|
@@ -45,7 +45,7 @@ def save(records: Iterable[ORM], **kwargs) -> None: # type: ignore
|
|
45
45
|
Save a collection of records in one transaction, which is much faster
|
46
46
|
than writing a loop over calls ``projects.save()``:
|
47
47
|
|
48
|
-
>>>
|
48
|
+
>>> labels = [ln.Label(f"Label {i}") for i in range(10)]
|
49
49
|
>>> ln.save(projects)
|
50
50
|
|
51
51
|
For a single record, use ``.save()``:
|
@@ -76,13 +76,23 @@ def save(records: Iterable[ORM], **kwargs) -> None: # type: ignore
|
|
76
76
|
non_files_with_parents = {r for r in non_files if hasattr(r, "_parents")}
|
77
77
|
|
78
78
|
if len(non_files_with_parents) > 0 and kwargs.get("parents") is not False:
|
79
|
-
#
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
)
|
84
|
-
|
85
|
-
|
79
|
+
# this can only happen within lnschema_bionty right now!!
|
80
|
+
# we might extend to core lamindb later
|
81
|
+
import lnschema_bionty as lb
|
82
|
+
|
83
|
+
if kwargs.get("parents") or (
|
84
|
+
kwargs.get("parents") is None and lb.settings.auto_save_parents
|
85
|
+
):
|
86
|
+
# save the record with parents one by one
|
87
|
+
logger.warning(
|
88
|
+
"Now recursing through parents: "
|
89
|
+
"this only happens once, but is much slower than bulk saving"
|
90
|
+
)
|
91
|
+
logger.hint(
|
92
|
+
"You can switch this off via: lb.settings.auto_save_parents = False"
|
93
|
+
)
|
94
|
+
for record in non_files_with_parents:
|
95
|
+
record._save_ontology_parents()
|
86
96
|
|
87
97
|
if files:
|
88
98
|
with transaction.atomic():
|
lamindb/_transform.py
CHANGED
@@ -1,19 +1,28 @@
|
|
1
|
+
import hashlib
|
2
|
+
|
1
3
|
from lnschema_core.ids import base62
|
2
4
|
from lnschema_core.models import Transform
|
3
5
|
|
6
|
+
from .dev.hashing import to_b64_str
|
7
|
+
|
4
8
|
|
5
9
|
def __init__(transform, *args, **kwargs):
|
6
10
|
if len(args) > 0: # initialize with all fields from db as args
|
7
11
|
super(Transform, transform).__init__(*args, **kwargs)
|
8
12
|
return None
|
9
13
|
else: # user-facing calling signature
|
14
|
+
if "version" not in kwargs:
|
15
|
+
kwargs["version"] = "0"
|
16
|
+
elif not isinstance(kwargs["version"], str):
|
17
|
+
raise ValueError("version must be str, e.g., '0', '1', etc.")
|
18
|
+
id_ext = to_b64_str(hashlib.md5(kwargs["version"].encode()).digest())[:2]
|
10
19
|
# set default ids
|
11
20
|
if "id" not in kwargs and "stem_id" not in kwargs:
|
12
|
-
kwargs["
|
13
|
-
kwargs["
|
21
|
+
kwargs["stem_id"] = base62(12)
|
22
|
+
kwargs["id"] = kwargs["stem_id"] + id_ext
|
14
23
|
elif "stem_id" in kwargs:
|
15
24
|
assert isinstance(kwargs["stem_id"], str) and len(kwargs["stem_id"]) == 12
|
16
|
-
kwargs["id"] = kwargs["stem_id"] +
|
25
|
+
kwargs["id"] = kwargs["stem_id"] + id_ext
|
17
26
|
elif "id" in kwargs:
|
18
27
|
assert isinstance(kwargs["id"], str) and len(kwargs["id"]) == 14
|
19
28
|
kwargs["stem_id"] = kwargs["id"][:12]
|
lamindb/_view.py
CHANGED
@@ -3,7 +3,7 @@ import inspect
|
|
3
3
|
from typing import List, Optional
|
4
4
|
|
5
5
|
from IPython.display import display
|
6
|
-
from
|
6
|
+
from lamin_utils import colors
|
7
7
|
from lamindb_setup import settings
|
8
8
|
from lamindb_setup.dev._setup_schema import get_schema_module_name
|
9
9
|
from lnschema_core import ORM
|
lamindb/dev/__init__.py
CHANGED
@@ -6,16 +6,20 @@
|
|
6
6
|
ORM
|
7
7
|
QuerySet
|
8
8
|
Manager
|
9
|
+
FeatureManager
|
9
10
|
datasets
|
10
11
|
hashing
|
11
12
|
storage
|
12
13
|
Settings
|
14
|
+
run_context
|
13
15
|
"""
|
14
16
|
|
15
17
|
from lnschema_core.models import ORM
|
16
18
|
|
19
|
+
from lamindb._feature_manager import FeatureManager
|
17
20
|
from lamindb._manager import Manager
|
18
21
|
from lamindb._queryset import QuerySet
|
19
22
|
|
23
|
+
from .._context import run_context
|
20
24
|
from . import datasets # noqa
|
21
25
|
from ._settings import Settings
|