lamindb 1.1.0__py3-none-any.whl → 1.2.0__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 +33 -26
- lamindb/_finish.py +9 -1
- lamindb/_tracked.py +26 -3
- lamindb/_view.py +2 -3
- lamindb/base/__init__.py +1 -1
- lamindb/base/ids.py +1 -10
- lamindb/base/users.py +1 -4
- lamindb/core/__init__.py +7 -65
- lamindb/core/_compat.py +60 -0
- lamindb/core/_context.py +50 -22
- lamindb/core/_mapped_collection.py +4 -2
- lamindb/core/_settings.py +6 -6
- lamindb/core/_sync_git.py +1 -1
- lamindb/core/_track_environment.py +2 -1
- lamindb/core/datasets/_small.py +3 -3
- lamindb/core/loaders.py +43 -20
- lamindb/core/storage/_anndata_accessor.py +8 -3
- lamindb/core/storage/_backed_access.py +14 -7
- lamindb/core/storage/_pyarrow_dataset.py +24 -9
- lamindb/core/storage/_tiledbsoma.py +8 -6
- lamindb/core/storage/_zarr.py +104 -25
- lamindb/core/storage/objects.py +63 -28
- lamindb/core/storage/paths.py +16 -13
- lamindb/core/types.py +10 -0
- lamindb/curators/__init__.py +176 -149
- lamindb/errors.py +1 -1
- lamindb/integrations/_vitessce.py +4 -4
- lamindb/migrations/0089_subsequent_runs.py +159 -0
- lamindb/migrations/0090_runproject_project_runs.py +73 -0
- lamindb/migrations/{0088_squashed.py → 0090_squashed.py} +245 -177
- lamindb/models/__init__.py +79 -0
- lamindb/{core → models}/_describe.py +3 -3
- lamindb/{core → models}/_django.py +8 -5
- lamindb/{core → models}/_feature_manager.py +103 -87
- lamindb/{_from_values.py → models/_from_values.py} +5 -2
- lamindb/{core/versioning.py → models/_is_versioned.py} +94 -6
- lamindb/{core → models}/_label_manager.py +10 -17
- lamindb/{core/relations.py → models/_relations.py} +8 -1
- lamindb/models/artifact.py +2602 -0
- lamindb/{_can_curate.py → models/can_curate.py} +349 -180
- lamindb/models/collection.py +683 -0
- lamindb/models/core.py +135 -0
- lamindb/models/feature.py +643 -0
- lamindb/models/flextable.py +163 -0
- lamindb/{_parents.py → models/has_parents.py} +55 -49
- lamindb/models/project.py +384 -0
- lamindb/{_query_manager.py → models/query_manager.py} +10 -8
- lamindb/{_query_set.py → models/query_set.py} +64 -32
- lamindb/models/record.py +1762 -0
- lamindb/models/run.py +563 -0
- lamindb/{_save.py → models/save.py} +18 -8
- lamindb/models/schema.py +732 -0
- lamindb/models/transform.py +360 -0
- lamindb/models/ulabel.py +249 -0
- {lamindb-1.1.0.dist-info → lamindb-1.2.0.dist-info}/METADATA +6 -6
- lamindb-1.2.0.dist-info/RECORD +95 -0
- lamindb/_artifact.py +0 -1361
- lamindb/_collection.py +0 -440
- lamindb/_feature.py +0 -316
- lamindb/_is_versioned.py +0 -40
- lamindb/_record.py +0 -1065
- lamindb/_run.py +0 -60
- lamindb/_schema.py +0 -347
- lamindb/_storage.py +0 -15
- lamindb/_transform.py +0 -170
- lamindb/_ulabel.py +0 -56
- lamindb/_utils.py +0 -9
- lamindb/base/validation.py +0 -63
- lamindb/core/_data.py +0 -491
- lamindb/core/fields.py +0 -12
- lamindb/models.py +0 -4435
- lamindb-1.1.0.dist-info/RECORD +0 -95
- {lamindb-1.1.0.dist-info → lamindb-1.2.0.dist-info}/LICENSE +0 -0
- {lamindb-1.1.0.dist-info → lamindb-1.2.0.dist-info}/WHEEL +0 -0
@@ -8,8 +8,6 @@ from lamindb_setup.core._docs import doc_args
|
|
8
8
|
|
9
9
|
from lamindb.models import Record
|
10
10
|
|
11
|
-
from .core._settings import settings
|
12
|
-
|
13
11
|
if TYPE_CHECKING:
|
14
12
|
from lamindb.base.types import StrField
|
15
13
|
|
@@ -19,7 +17,7 @@ class QueryManager(models.Manager):
|
|
19
17
|
|
20
18
|
See Also:
|
21
19
|
|
22
|
-
:class:`lamindb.
|
20
|
+
:class:`lamindb.models.QuerySet`
|
23
21
|
`django Manager <https://docs.djangoproject.com/en/4.2/topics/db/managers/>`__
|
24
22
|
|
25
23
|
Examples:
|
@@ -39,8 +37,12 @@ class QueryManager(models.Manager):
|
|
39
37
|
self.source_field_name == "collection"
|
40
38
|
and self.target_field_name == "artifact"
|
41
39
|
):
|
40
|
+
from lamindb import settings
|
42
41
|
from lamindb.core._context import context
|
43
|
-
from lamindb.
|
42
|
+
from lamindb.models.artifact import (
|
43
|
+
WARNING_RUN_TRANSFORM,
|
44
|
+
_track_run_input,
|
45
|
+
)
|
44
46
|
|
45
47
|
if (
|
46
48
|
context.run is None
|
@@ -71,14 +73,14 @@ class QueryManager(models.Manager):
|
|
71
73
|
def df(self, **kwargs):
|
72
74
|
"""Convert to DataFrame.
|
73
75
|
|
74
|
-
For `**kwargs`, see :meth:`lamindb.
|
76
|
+
For `**kwargs`, see :meth:`lamindb.models.QuerySet.df`.
|
75
77
|
"""
|
76
78
|
return self.all().df(**kwargs)
|
77
79
|
|
78
80
|
def all(self):
|
79
81
|
"""Return QuerySet of all.
|
80
82
|
|
81
|
-
For `**kwargs`, see :meth:`lamindb.
|
83
|
+
For `**kwargs`, see :meth:`lamindb.models.QuerySet.df`.
|
82
84
|
"""
|
83
85
|
self._track_run_input_manager()
|
84
86
|
return self._all_base_class()
|
@@ -86,14 +88,14 @@ class QueryManager(models.Manager):
|
|
86
88
|
@doc_args(Record.search.__doc__)
|
87
89
|
def search(self, string: str, **kwargs):
|
88
90
|
"""{}""" # noqa: D415
|
89
|
-
from .
|
91
|
+
from .record import _search
|
90
92
|
|
91
93
|
return _search(cls=self.all(), string=string, **kwargs)
|
92
94
|
|
93
95
|
@doc_args(Record.lookup.__doc__)
|
94
96
|
def lookup(self, field: StrField | None = None, **kwargs) -> NamedTuple:
|
95
97
|
"""{}""" # noqa: D415
|
96
|
-
from .
|
98
|
+
from .record import _lookup
|
97
99
|
|
98
100
|
return _lookup(cls=self.all(), field=field, **kwargs)
|
99
101
|
|
@@ -5,37 +5,27 @@ import warnings
|
|
5
5
|
from collections import UserList
|
6
6
|
from collections.abc import Iterable
|
7
7
|
from collections.abc import Iterable as IterableType
|
8
|
-
from typing import TYPE_CHECKING, Any, Generic, NamedTuple, TypeVar
|
8
|
+
from typing import TYPE_CHECKING, Any, Generic, NamedTuple, TypeVar, Union
|
9
9
|
|
10
10
|
import pandas as pd
|
11
11
|
from django.core.exceptions import FieldError
|
12
12
|
from django.db import models
|
13
|
-
from django.db.models import F, ForeignKey, ManyToManyField
|
13
|
+
from django.db.models import F, ForeignKey, ManyToManyField, Subquery
|
14
14
|
from django.db.models.fields.related import ForeignObjectRel
|
15
15
|
from lamin_utils import logger
|
16
16
|
from lamindb_setup.core._docs import doc_args
|
17
17
|
|
18
|
-
from lamindb.models import
|
19
|
-
|
20
|
-
CanCurate,
|
21
|
-
Collection,
|
22
|
-
Feature,
|
23
|
-
IsVersioned,
|
24
|
-
Record,
|
25
|
-
Run,
|
26
|
-
Schema,
|
27
|
-
Transform,
|
28
|
-
)
|
18
|
+
from lamindb.models._is_versioned import IsVersioned
|
19
|
+
from lamindb.models.record import Record
|
29
20
|
|
30
|
-
from
|
31
|
-
|
32
|
-
T = TypeVar("T")
|
21
|
+
from ..errors import DoesNotExist
|
22
|
+
from .can_curate import CanCurate
|
33
23
|
|
34
24
|
if TYPE_CHECKING:
|
35
|
-
from collections.abc import Iterable
|
36
|
-
|
37
25
|
from lamindb.base.types import ListLike, StrField
|
38
26
|
|
27
|
+
T = TypeVar("T")
|
28
|
+
|
39
29
|
|
40
30
|
class MultipleResultsFound(Exception):
|
41
31
|
pass
|
@@ -82,6 +72,13 @@ def one_helper(self):
|
|
82
72
|
|
83
73
|
|
84
74
|
def get_backward_compat_filter_kwargs(queryset, expressions):
|
75
|
+
from lamindb.models import (
|
76
|
+
Artifact,
|
77
|
+
Collection,
|
78
|
+
Schema,
|
79
|
+
Transform,
|
80
|
+
)
|
81
|
+
|
85
82
|
if queryset.model in {Collection, Transform}:
|
86
83
|
name_mappings = {
|
87
84
|
"name": "key",
|
@@ -190,7 +187,7 @@ def process_expressions(queryset: QuerySet, expressions: dict) -> dict:
|
|
190
187
|
|
191
188
|
|
192
189
|
def get(
|
193
|
-
registry_or_queryset: type[Record]
|
190
|
+
registry_or_queryset: Union[type[Record], QuerySet],
|
194
191
|
idlike: int | str | None = None,
|
195
192
|
**expressions,
|
196
193
|
) -> Record:
|
@@ -214,10 +211,27 @@ def get(
|
|
214
211
|
else:
|
215
212
|
assert idlike is None # noqa: S101
|
216
213
|
expressions = process_expressions(qs, expressions)
|
214
|
+
# don't want _branch_code here in .get(), only in .filter()
|
215
|
+
expressions.pop("_branch_code", None)
|
217
216
|
# inject is_latest for consistency with idlike
|
218
|
-
|
217
|
+
is_latest_was_not_in_expressions = "is_latest" not in expressions
|
218
|
+
if issubclass(registry, IsVersioned) and is_latest_was_not_in_expressions:
|
219
219
|
expressions["is_latest"] = True
|
220
|
-
|
220
|
+
try:
|
221
|
+
return registry.objects.using(qs.db).get(**expressions)
|
222
|
+
except registry.DoesNotExist:
|
223
|
+
# handle the case in which the is_latest injection led to a missed query
|
224
|
+
if "is_latest" in expressions and is_latest_was_not_in_expressions:
|
225
|
+
expressions.pop("is_latest")
|
226
|
+
result = (
|
227
|
+
registry.objects.using(qs.db)
|
228
|
+
.filter(**expressions)
|
229
|
+
.order_by("-created_at")
|
230
|
+
.first()
|
231
|
+
)
|
232
|
+
if result is not None:
|
233
|
+
return result
|
234
|
+
raise registry.DoesNotExist from registry.DoesNotExist
|
221
235
|
|
222
236
|
|
223
237
|
class RecordList(UserList, Generic[T]):
|
@@ -240,7 +254,7 @@ class RecordList(UserList, Generic[T]):
|
|
240
254
|
|
241
255
|
def save(self) -> RecordList[T]:
|
242
256
|
"""Save all records to the database."""
|
243
|
-
from lamindb.
|
257
|
+
from lamindb.models.save import save
|
244
258
|
|
245
259
|
save(self)
|
246
260
|
return self
|
@@ -288,6 +302,11 @@ def get_basic_field_names(
|
|
288
302
|
|
289
303
|
|
290
304
|
def get_feature_annotate_kwargs(show_features: bool | list[str]) -> dict[str, Any]:
|
305
|
+
from lamindb.models import (
|
306
|
+
Artifact,
|
307
|
+
Feature,
|
308
|
+
)
|
309
|
+
|
291
310
|
features = Feature.filter()
|
292
311
|
if isinstance(show_features, list):
|
293
312
|
features.filter(name__in=show_features)
|
@@ -548,7 +567,17 @@ class QuerySet(models.QuerySet):
|
|
548
567
|
include_kwargs = {s: F(s) for s in include if s not in field_names}
|
549
568
|
annotate_kwargs.update(include_kwargs)
|
550
569
|
if annotate_kwargs:
|
551
|
-
|
570
|
+
id_subquery = self.values("id")
|
571
|
+
# for annotate, we want the queryset without filters so that joins don't affect the annotations
|
572
|
+
query_set_without_filters = self.model.objects.filter(
|
573
|
+
id__in=Subquery(id_subquery)
|
574
|
+
)
|
575
|
+
if self.query.order_by:
|
576
|
+
# Apply the same ordering to the new queryset
|
577
|
+
query_set_without_filters = query_set_without_filters.order_by(
|
578
|
+
*self.query.order_by
|
579
|
+
)
|
580
|
+
queryset = query_set_without_filters.annotate(**annotate_kwargs)
|
552
581
|
else:
|
553
582
|
queryset = self
|
554
583
|
|
@@ -566,6 +595,8 @@ class QuerySet(models.QuerySet):
|
|
566
595
|
|
567
596
|
def delete(self, *args, **kwargs):
|
568
597
|
"""Delete all records in the query set."""
|
598
|
+
from lamindb.models import Artifact, Collection, Run, Transform
|
599
|
+
|
569
600
|
# both Transform & Run might reference artifacts
|
570
601
|
if self.model in {Artifact, Collection, Transform, Run}:
|
571
602
|
for record in self:
|
@@ -641,11 +672,12 @@ class QuerySet(models.QuerySet):
|
|
641
672
|
and value.strip("-").isalpha()
|
642
673
|
and "__" not in field
|
643
674
|
and hasattr(self.model, field)
|
644
|
-
and getattr(self.model, field).field.related_model
|
645
675
|
):
|
646
|
-
|
647
|
-
|
648
|
-
|
676
|
+
field_attr = getattr(self.model, field)
|
677
|
+
if hasattr(field_attr, "field") and field_attr.field.related_model:
|
678
|
+
raise FieldError(
|
679
|
+
f"Invalid lookup '{value}' for {field}. Did you mean {field}__name?"
|
680
|
+
)
|
649
681
|
|
650
682
|
expressions = process_expressions(self, expressions)
|
651
683
|
if len(expressions) > 0:
|
@@ -689,7 +721,7 @@ class QuerySet(models.QuerySet):
|
|
689
721
|
@doc_args(Record.search.__doc__)
|
690
722
|
def search(self, string: str, **kwargs):
|
691
723
|
"""{}""" # noqa: D415
|
692
|
-
from .
|
724
|
+
from .record import _search
|
693
725
|
|
694
726
|
return _search(cls=self, string=string, **kwargs)
|
695
727
|
|
@@ -697,7 +729,7 @@ def search(self, string: str, **kwargs):
|
|
697
729
|
@doc_args(Record.lookup.__doc__)
|
698
730
|
def lookup(self, field: StrField | None = None, **kwargs) -> NamedTuple:
|
699
731
|
"""{}""" # noqa: D415
|
700
|
-
from .
|
732
|
+
from .record import _lookup
|
701
733
|
|
702
734
|
return _lookup(cls=self, field=field, **kwargs)
|
703
735
|
|
@@ -705,7 +737,7 @@ def lookup(self, field: StrField | None = None, **kwargs) -> NamedTuple:
|
|
705
737
|
@doc_args(CanCurate.validate.__doc__)
|
706
738
|
def validate(self, values: ListLike, field: str | StrField | None = None, **kwargs):
|
707
739
|
"""{}""" # noqa: D415
|
708
|
-
from .
|
740
|
+
from .can_curate import _validate
|
709
741
|
|
710
742
|
return _validate(cls=self, values=values, field=field, **kwargs)
|
711
743
|
|
@@ -713,7 +745,7 @@ def validate(self, values: ListLike, field: str | StrField | None = None, **kwar
|
|
713
745
|
@doc_args(CanCurate.inspect.__doc__)
|
714
746
|
def inspect(self, values: ListLike, field: str | StrField | None = None, **kwargs):
|
715
747
|
"""{}""" # noqa: D415
|
716
|
-
from .
|
748
|
+
from .can_curate import _inspect
|
717
749
|
|
718
750
|
return _inspect(cls=self, values=values, field=field, **kwargs)
|
719
751
|
|
@@ -721,7 +753,7 @@ def inspect(self, values: ListLike, field: str | StrField | None = None, **kwarg
|
|
721
753
|
@doc_args(CanCurate.standardize.__doc__)
|
722
754
|
def standardize(self, values: Iterable, field: str | StrField | None = None, **kwargs):
|
723
755
|
"""{}""" # noqa: D415
|
724
|
-
from .
|
756
|
+
from .can_curate import _standardize
|
725
757
|
|
726
758
|
return _standardize(cls=self, values=values, field=field, **kwargs)
|
727
759
|
|