lamindb 1.10.1__py3-none-any.whl → 1.11a1__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 +89 -49
- lamindb/_finish.py +14 -12
- lamindb/_tracked.py +2 -4
- lamindb/_view.py +1 -1
- lamindb/base/__init__.py +2 -1
- lamindb/base/dtypes.py +76 -0
- lamindb/core/_settings.py +45 -2
- lamindb/core/storage/_anndata_accessor.py +118 -26
- lamindb/core/storage/_backed_access.py +10 -7
- lamindb/core/storage/_spatialdata_accessor.py +15 -4
- lamindb/core/storage/_zarr.py +3 -0
- lamindb/curators/_legacy.py +16 -3
- lamindb/curators/core.py +439 -191
- lamindb/examples/cellxgene/__init__.py +8 -3
- lamindb/examples/cellxgene/_cellxgene.py +127 -13
- lamindb/examples/cellxgene/{cxg_schema_versions.csv → cellxgene_schema_versions.csv} +11 -0
- lamindb/examples/croissant/__init__.py +12 -2
- lamindb/examples/datasets/__init__.py +2 -2
- lamindb/examples/datasets/_core.py +1 -1
- lamindb/examples/datasets/_small.py +66 -22
- lamindb/examples/datasets/mini_immuno.py +1 -0
- lamindb/migrations/0118_alter_recordproject_value_projectrecord.py +99 -0
- lamindb/migrations/0119_rename_records_project_linked_in_records.py +26 -0
- lamindb/migrations/{0117_squashed.py → 0119_squashed.py} +92 -5
- lamindb/migrations/0120_add_record_fk_constraint.py +64 -0
- lamindb/migrations/0121_recorduser.py +53 -0
- lamindb/models/__init__.py +3 -1
- lamindb/models/_describe.py +2 -2
- lamindb/models/_feature_manager.py +53 -53
- lamindb/models/_from_values.py +2 -2
- lamindb/models/_is_versioned.py +4 -4
- lamindb/models/_label_manager.py +4 -4
- lamindb/models/artifact.py +336 -136
- lamindb/models/artifact_set.py +36 -1
- lamindb/models/can_curate.py +1 -2
- lamindb/models/collection.py +3 -34
- lamindb/models/feature.py +111 -7
- lamindb/models/has_parents.py +11 -11
- lamindb/models/project.py +42 -2
- lamindb/models/query_manager.py +16 -7
- lamindb/models/query_set.py +59 -34
- lamindb/models/record.py +25 -4
- lamindb/models/run.py +8 -6
- lamindb/models/schema.py +54 -26
- lamindb/models/sqlrecord.py +123 -25
- lamindb/models/storage.py +59 -14
- lamindb/models/transform.py +17 -17
- lamindb/models/ulabel.py +6 -1
- {lamindb-1.10.1.dist-info → lamindb-1.11a1.dist-info}/METADATA +3 -3
- {lamindb-1.10.1.dist-info → lamindb-1.11a1.dist-info}/RECORD +52 -47
- {lamindb-1.10.1.dist-info → lamindb-1.11a1.dist-info}/LICENSE +0 -0
- {lamindb-1.10.1.dist-info → lamindb-1.11a1.dist-info}/WHEEL +0 -0
@@ -1,4 +1,4 @@
|
|
1
|
-
# Generated by Django 5.2 on 2025-
|
1
|
+
# Generated by Django 5.2 on 2025-08-09 13:33
|
2
2
|
|
3
3
|
import django.core.validators
|
4
4
|
import django.db.models.deletion
|
@@ -139,6 +139,8 @@ class Migration(migrations.Migration):
|
|
139
139
|
("lamindb", "0115_alter_space_uid"),
|
140
140
|
("lamindb", "0116_remove_artifact_unique_artifact_storage_key_hash_and_more"),
|
141
141
|
("lamindb", "0117_fix_artifact_storage_hash_unique_constraints"),
|
142
|
+
("lamindb", "0118_alter_recordproject_value_projectrecord"),
|
143
|
+
("lamindb", "0119_rename_records_project_linked_in_records"),
|
142
144
|
]
|
143
145
|
|
144
146
|
dependencies = [] # type: ignore
|
@@ -217,9 +219,8 @@ class Migration(migrations.Migration):
|
|
217
219
|
"uid",
|
218
220
|
lamindb.base.fields.CharField(
|
219
221
|
blank=True,
|
220
|
-
db_default="aaaaaaaaaaaa",
|
221
222
|
db_index=True,
|
222
|
-
default=
|
223
|
+
default=lamindb.base.uids.base62_12,
|
223
224
|
editable=False,
|
224
225
|
max_length=12,
|
225
226
|
unique=True,
|
@@ -1522,6 +1523,60 @@ class Migration(migrations.Migration):
|
|
1522
1523
|
},
|
1523
1524
|
bases=(lamindb.models.can_curate.CanCurate, models.Model),
|
1524
1525
|
),
|
1526
|
+
migrations.CreateModel(
|
1527
|
+
name="ProjectRecord",
|
1528
|
+
fields=[
|
1529
|
+
(
|
1530
|
+
"created_at",
|
1531
|
+
lamindb.base.fields.DateTimeField(
|
1532
|
+
blank=True,
|
1533
|
+
db_default=django.db.models.functions.datetime.Now(),
|
1534
|
+
db_index=True,
|
1535
|
+
editable=False,
|
1536
|
+
),
|
1537
|
+
),
|
1538
|
+
("id", models.BigAutoField(primary_key=True, serialize=False)),
|
1539
|
+
(
|
1540
|
+
"feature",
|
1541
|
+
lamindb.base.fields.ForeignKey(
|
1542
|
+
blank=True,
|
1543
|
+
default=None,
|
1544
|
+
null=True,
|
1545
|
+
on_delete=django.db.models.deletion.PROTECT,
|
1546
|
+
related_name="links_projectrecord",
|
1547
|
+
to="lamindb.feature",
|
1548
|
+
),
|
1549
|
+
),
|
1550
|
+
(
|
1551
|
+
"project",
|
1552
|
+
lamindb.base.fields.ForeignKey(
|
1553
|
+
blank=True,
|
1554
|
+
on_delete=django.db.models.deletion.PROTECT,
|
1555
|
+
related_name="links_record",
|
1556
|
+
to="lamindb.project",
|
1557
|
+
),
|
1558
|
+
),
|
1559
|
+
(
|
1560
|
+
"record",
|
1561
|
+
lamindb.base.fields.ForeignKey(
|
1562
|
+
blank=True,
|
1563
|
+
on_delete=django.db.models.deletion.CASCADE,
|
1564
|
+
related_name="links_project",
|
1565
|
+
to="lamindb.record",
|
1566
|
+
),
|
1567
|
+
),
|
1568
|
+
],
|
1569
|
+
bases=(lamindb.models.sqlrecord.IsLink, models.Model),
|
1570
|
+
),
|
1571
|
+
migrations.AddField(
|
1572
|
+
model_name="project",
|
1573
|
+
name="records",
|
1574
|
+
field=models.ManyToManyField(
|
1575
|
+
related_name="projects",
|
1576
|
+
through="lamindb.ProjectRecord",
|
1577
|
+
to="lamindb.record",
|
1578
|
+
),
|
1579
|
+
),
|
1525
1580
|
migrations.AddField(
|
1526
1581
|
model_name="artifactrecord",
|
1527
1582
|
name="record",
|
@@ -1651,7 +1706,7 @@ class Migration(migrations.Migration):
|
|
1651
1706
|
lamindb.base.fields.ForeignKey(
|
1652
1707
|
blank=True,
|
1653
1708
|
on_delete=django.db.models.deletion.PROTECT,
|
1654
|
-
related_name="
|
1709
|
+
related_name="links_in_record",
|
1655
1710
|
to="lamindb.project",
|
1656
1711
|
),
|
1657
1712
|
),
|
@@ -1663,7 +1718,7 @@ class Migration(migrations.Migration):
|
|
1663
1718
|
),
|
1664
1719
|
migrations.AddField(
|
1665
1720
|
model_name="project",
|
1666
|
-
name="
|
1721
|
+
name="linked_in_records",
|
1667
1722
|
field=models.ManyToManyField(
|
1668
1723
|
related_name="linked_projects",
|
1669
1724
|
through="lamindb.RecordProject",
|
@@ -2198,6 +2253,18 @@ class Migration(migrations.Migration):
|
|
2198
2253
|
to="lamindb.run",
|
2199
2254
|
),
|
2200
2255
|
),
|
2256
|
+
migrations.AddField(
|
2257
|
+
model_name="projectrecord",
|
2258
|
+
name="run",
|
2259
|
+
field=lamindb.base.fields.ForeignKey(
|
2260
|
+
blank=True,
|
2261
|
+
default=lamindb.models.run.current_run,
|
2262
|
+
null=True,
|
2263
|
+
on_delete=django.db.models.deletion.PROTECT,
|
2264
|
+
related_name="+",
|
2265
|
+
to="lamindb.run",
|
2266
|
+
),
|
2267
|
+
),
|
2201
2268
|
migrations.AddField(
|
2202
2269
|
model_name="project",
|
2203
2270
|
name="run",
|
@@ -4174,6 +4241,18 @@ class Migration(migrations.Migration):
|
|
4174
4241
|
to="lamindb.user",
|
4175
4242
|
),
|
4176
4243
|
),
|
4244
|
+
migrations.AddField(
|
4245
|
+
model_name="projectrecord",
|
4246
|
+
name="created_by",
|
4247
|
+
field=lamindb.base.fields.ForeignKey(
|
4248
|
+
blank=True,
|
4249
|
+
default=lamindb.base.users.current_user_id,
|
4250
|
+
editable=False,
|
4251
|
+
on_delete=django.db.models.deletion.PROTECT,
|
4252
|
+
related_name="+",
|
4253
|
+
to="lamindb.user",
|
4254
|
+
),
|
4255
|
+
),
|
4177
4256
|
migrations.AddField(
|
4178
4257
|
model_name="project",
|
4179
4258
|
name="created_by",
|
@@ -4427,6 +4506,10 @@ class Migration(migrations.Migration):
|
|
4427
4506
|
name="runfeaturevalue",
|
4428
4507
|
unique_together={("run", "featurevalue")},
|
4429
4508
|
),
|
4509
|
+
migrations.AlterUniqueTogether(
|
4510
|
+
name="projectrecord",
|
4511
|
+
unique_together={("record", "project", "feature")},
|
4512
|
+
),
|
4430
4513
|
migrations.AlterUniqueTogether(
|
4431
4514
|
name="personproject",
|
4432
4515
|
unique_together={("person", "project")},
|
@@ -4498,4 +4581,8 @@ class Migration(migrations.Migration):
|
|
4498
4581
|
name="unique_artifact_storage_hash_null_key",
|
4499
4582
|
),
|
4500
4583
|
),
|
4584
|
+
migrations.AlterModelOptions(
|
4585
|
+
name="user",
|
4586
|
+
options={},
|
4587
|
+
),
|
4501
4588
|
]
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# Generated by Django 5.2 on 2025-08-07 18:52
|
2
|
+
|
3
|
+
from django.db import migrations
|
4
|
+
|
5
|
+
CREATE_FUNCTION_SQL = """
|
6
|
+
CREATE OR REPLACE FUNCTION is_valid_record_type(record_type_id INTEGER, record_is_type BOOLEAN)
|
7
|
+
RETURNS BOOLEAN AS $$
|
8
|
+
BEGIN
|
9
|
+
-- Record with no type is valid
|
10
|
+
IF record_type_id IS NULL THEN
|
11
|
+
RETURN TRUE;
|
12
|
+
END IF;
|
13
|
+
|
14
|
+
-- If current record is a type, it can only reference schema-less types
|
15
|
+
IF record_is_type THEN
|
16
|
+
RETURN EXISTS (
|
17
|
+
SELECT 1 FROM lamindb_record r
|
18
|
+
WHERE r.id = record_type_id AND r.is_type AND r.schema_id IS NULL
|
19
|
+
);
|
20
|
+
END IF;
|
21
|
+
|
22
|
+
-- Regular records can reference any type
|
23
|
+
RETURN EXISTS (
|
24
|
+
SELECT 1 FROM lamindb_record r
|
25
|
+
WHERE r.id = record_type_id AND r.is_type
|
26
|
+
);
|
27
|
+
END;
|
28
|
+
$$ LANGUAGE plpgsql;
|
29
|
+
"""
|
30
|
+
|
31
|
+
ADD_CONSTRAINT_SQL = """
|
32
|
+
ALTER TABLE lamindb_record
|
33
|
+
ADD CONSTRAINT record_type_is_valid_fk
|
34
|
+
CHECK (is_valid_record_type(type_id, is_type));
|
35
|
+
"""
|
36
|
+
|
37
|
+
DROP_CONSTRAINT_SQL = (
|
38
|
+
"ALTER TABLE lamindb_record DROP CONSTRAINT IF EXISTS record_type_is_valid_fk;"
|
39
|
+
)
|
40
|
+
DROP_FUNCTION_SQL = "DROP FUNCTION IF EXISTS is_valid_record_type(INTEGER, BOOLEAN);"
|
41
|
+
|
42
|
+
|
43
|
+
def apply_postgres_constraint(apps, schema_editor):
|
44
|
+
if schema_editor.connection.vendor == "postgresql":
|
45
|
+
schema_editor.execute(CREATE_FUNCTION_SQL)
|
46
|
+
schema_editor.execute(ADD_CONSTRAINT_SQL)
|
47
|
+
|
48
|
+
|
49
|
+
def revert_postgres_constraint(apps, schema_editor):
|
50
|
+
if schema_editor.connection.vendor == "postgresql":
|
51
|
+
schema_editor.execute(DROP_CONSTRAINT_SQL)
|
52
|
+
schema_editor.execute(DROP_FUNCTION_SQL)
|
53
|
+
|
54
|
+
|
55
|
+
class Migration(migrations.Migration):
|
56
|
+
dependencies = [
|
57
|
+
("lamindb", "0119_squashed"),
|
58
|
+
]
|
59
|
+
|
60
|
+
operations = [
|
61
|
+
migrations.RunPython(
|
62
|
+
apply_postgres_constraint, reverse_code=revert_postgres_constraint
|
63
|
+
),
|
64
|
+
]
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# Generated by Django 5.2 on 2025-09-05 12:25
|
2
|
+
|
3
|
+
import django.db.models.deletion
|
4
|
+
from django.db import migrations, models
|
5
|
+
|
6
|
+
import lamindb.base.fields
|
7
|
+
import lamindb.models.sqlrecord
|
8
|
+
|
9
|
+
|
10
|
+
class Migration(migrations.Migration):
|
11
|
+
dependencies = [
|
12
|
+
("lamindb", "0120_add_record_fk_constraint"),
|
13
|
+
]
|
14
|
+
|
15
|
+
operations = [
|
16
|
+
migrations.CreateModel(
|
17
|
+
name="RecordUser",
|
18
|
+
fields=[
|
19
|
+
("id", models.BigAutoField(primary_key=True, serialize=False)),
|
20
|
+
(
|
21
|
+
"feature",
|
22
|
+
lamindb.base.fields.ForeignKey(
|
23
|
+
blank=True,
|
24
|
+
on_delete=django.db.models.deletion.PROTECT,
|
25
|
+
related_name="links_recorduser",
|
26
|
+
to="lamindb.feature",
|
27
|
+
),
|
28
|
+
),
|
29
|
+
(
|
30
|
+
"record",
|
31
|
+
lamindb.base.fields.ForeignKey(
|
32
|
+
blank=True,
|
33
|
+
on_delete=django.db.models.deletion.CASCADE,
|
34
|
+
related_name="values_user",
|
35
|
+
to="lamindb.record",
|
36
|
+
),
|
37
|
+
),
|
38
|
+
(
|
39
|
+
"value",
|
40
|
+
lamindb.base.fields.ForeignKey(
|
41
|
+
blank=True,
|
42
|
+
on_delete=django.db.models.deletion.PROTECT,
|
43
|
+
related_name="links_record",
|
44
|
+
to="lamindb.user",
|
45
|
+
),
|
46
|
+
),
|
47
|
+
],
|
48
|
+
options={
|
49
|
+
"unique_together": {("record", "feature", "value")},
|
50
|
+
},
|
51
|
+
bases=(models.Model, lamindb.models.sqlrecord.IsLink),
|
52
|
+
),
|
53
|
+
]
|
lamindb/models/__init__.py
CHANGED
@@ -9,6 +9,7 @@
|
|
9
9
|
BasicQuerySet
|
10
10
|
QuerySet
|
11
11
|
ArtifactSet
|
12
|
+
LazyArtifact
|
12
13
|
QueryManager
|
13
14
|
SQLRecordList
|
14
15
|
FeatureManager
|
@@ -49,7 +50,7 @@ from .schema import Schema
|
|
49
50
|
from .ulabel import ULabel
|
50
51
|
|
51
52
|
# should come last as it needs everything else
|
52
|
-
from .artifact import Artifact
|
53
|
+
from .artifact import Artifact, LazyArtifact
|
53
54
|
from ._feature_manager import FeatureManager
|
54
55
|
from ._label_manager import LabelManager
|
55
56
|
from .collection import Collection, CollectionArtifact
|
@@ -78,6 +79,7 @@ from .project import (
|
|
78
79
|
PersonProject,
|
79
80
|
RecordPerson,
|
80
81
|
RecordReference,
|
82
|
+
ProjectRecord,
|
81
83
|
)
|
82
84
|
from .run import RunFeatureValue
|
83
85
|
from .schema import (
|
lamindb/models/_describe.py
CHANGED
@@ -8,8 +8,6 @@ from lamin_utils import logger
|
|
8
8
|
from rich.text import Text
|
9
9
|
from rich.tree import Tree
|
10
10
|
|
11
|
-
from ..core._context import is_run_from_ipython
|
12
|
-
|
13
11
|
if TYPE_CHECKING:
|
14
12
|
from lamindb.models import Artifact, Collection, Run
|
15
13
|
|
@@ -41,6 +39,8 @@ def format_rich_tree(
|
|
41
39
|
) -> str | None:
|
42
40
|
from rich.console import Console
|
43
41
|
|
42
|
+
from ..core._context import is_run_from_ipython
|
43
|
+
|
44
44
|
# If tree has no children, return fallback
|
45
45
|
if not tree.children:
|
46
46
|
return fallback
|
@@ -496,21 +496,11 @@ def describe_features(
|
|
496
496
|
return tree
|
497
497
|
|
498
498
|
|
499
|
-
def is_valid_datetime_str(date_string: str) -> bool | str:
|
500
|
-
try:
|
501
|
-
dt = datetime.fromisoformat(date_string)
|
502
|
-
return dt.isoformat()
|
503
|
-
except ValueError:
|
504
|
-
return False
|
505
|
-
|
506
|
-
|
507
|
-
def is_iterable_of_sqlrecord(value: Any):
|
508
|
-
return isinstance(value, Iterable) and isinstance(next(iter(value)), SQLRecord)
|
509
|
-
|
510
|
-
|
511
499
|
def infer_feature_type_convert_json(
|
512
|
-
key: str, value: Any, mute: bool = False
|
500
|
+
key: str, value: Any, mute: bool = False
|
513
501
|
) -> tuple[str, Any, str]:
|
502
|
+
from lamindb.base.dtypes import is_valid_datetime_str
|
503
|
+
|
514
504
|
message = ""
|
515
505
|
if isinstance(value, bool):
|
516
506
|
return "bool", value, message
|
@@ -719,15 +709,15 @@ def parse_staged_feature_sets_from_anndata(
|
|
719
709
|
data_parse = backed_access(filepath, using_key=using_key)
|
720
710
|
else:
|
721
711
|
data_parse = ad.read_h5ad(filepath, backed="r")
|
722
|
-
|
712
|
+
dtype = "float"
|
723
713
|
else:
|
724
|
-
|
714
|
+
dtype = "float" if adata.X is None else serialize_pandas_dtype(adata.X.dtype)
|
725
715
|
feature_sets = {}
|
726
716
|
if var_field is not None:
|
727
717
|
schema_var = Schema.from_values(
|
728
718
|
data_parse.var.index,
|
729
719
|
var_field,
|
730
|
-
|
720
|
+
dtype=dtype,
|
731
721
|
mute=mute,
|
732
722
|
organism=organism,
|
733
723
|
raise_validation_error=False,
|
@@ -735,7 +725,7 @@ def parse_staged_feature_sets_from_anndata(
|
|
735
725
|
if schema_var is not None:
|
736
726
|
feature_sets["var"] = schema_var
|
737
727
|
if obs_field is not None and len(data_parse.obs.columns) > 0:
|
738
|
-
schema_obs = Schema.
|
728
|
+
schema_obs = Schema.from_dataframe(
|
739
729
|
df=data_parse.obs,
|
740
730
|
field=obs_field,
|
741
731
|
mute=mute,
|
@@ -851,16 +841,17 @@ class FeatureManager:
|
|
851
841
|
self,
|
852
842
|
values: dict[str, str | int | float | bool],
|
853
843
|
feature_field: FieldAttr = Feature.name,
|
854
|
-
|
844
|
+
schema: Schema = None,
|
855
845
|
) -> None:
|
856
846
|
"""Curate artifact with features & values.
|
857
847
|
|
858
848
|
Args:
|
859
849
|
values: A dictionary of keys (features) & values (labels, numbers, booleans).
|
860
|
-
feature_field: The field of a reference registry to map keys of the
|
861
|
-
|
862
|
-
str_as_ulabel: Whether to interpret string values as ulabels.
|
850
|
+
feature_field: The field of a reference registry to map keys of the dictionary.
|
851
|
+
schema: Schema to validate against.
|
863
852
|
"""
|
853
|
+
from lamindb.base.dtypes import is_iterable_of_sqlrecord
|
854
|
+
|
864
855
|
from .._tracked import get_current_tracked_run
|
865
856
|
|
866
857
|
# rename to distinguish from the values inside the dict
|
@@ -870,39 +861,48 @@ class FeatureManager:
|
|
870
861
|
keys = list(keys) # type: ignore
|
871
862
|
# deal with other cases later
|
872
863
|
assert all(isinstance(key, str) for key in keys) # noqa: S101
|
864
|
+
|
873
865
|
registry = feature_field.field.model
|
874
866
|
value_model = FeatureValue
|
875
867
|
model_name = "Feature"
|
876
|
-
records = registry.from_values(keys, field=feature_field, mute=True)
|
877
|
-
if len(records) != len(keys):
|
878
|
-
not_validated_keys = [
|
879
|
-
key for key in keys if key not in records.list("name")
|
880
|
-
]
|
881
|
-
not_validated_keys_dtype_message = [
|
882
|
-
(key, infer_feature_type_convert_json(key, dictionary[key]))
|
883
|
-
for key in not_validated_keys
|
884
|
-
]
|
885
|
-
run = get_current_tracked_run()
|
886
|
-
if run is not None:
|
887
|
-
name = f"{run.transform.type}[{run.transform.key}]"
|
888
|
-
type_hint = f""" {model_name.lower()}_type = ln.{model_name}(name='{name}', is_type=True).save()"""
|
889
|
-
elements = [type_hint]
|
890
|
-
type_kwarg = f", type={model_name.lower()}_type"
|
891
|
-
else:
|
892
|
-
elements = []
|
893
|
-
type_kwarg = ""
|
894
|
-
elements += [
|
895
|
-
f" ln.{model_name}(name='{key}', dtype='{dtype}'{type_kwarg}).save(){message}"
|
896
|
-
for key, (dtype, _, message) in not_validated_keys_dtype_message
|
897
|
-
]
|
898
|
-
hint = "\n".join(elements)
|
899
|
-
msg = (
|
900
|
-
f"These keys could not be validated: {not_validated_keys}\n"
|
901
|
-
f"Here is how to create a {model_name.lower()}:\n\n{hint}"
|
902
|
-
)
|
903
|
-
raise ValidationError(msg)
|
904
868
|
|
905
|
-
|
869
|
+
if schema is not None:
|
870
|
+
from lamindb.curators import DataFrameCurator
|
871
|
+
|
872
|
+
temp_df = pd.DataFrame([values])
|
873
|
+
curator = DataFrameCurator(temp_df, schema)
|
874
|
+
curator.validate()
|
875
|
+
records = schema.members.filter(name__in=keys)
|
876
|
+
else:
|
877
|
+
records = registry.from_values(keys, field=feature_field, mute=True)
|
878
|
+
if len(records) != len(keys):
|
879
|
+
not_validated_keys = [
|
880
|
+
key for key in keys if key not in records.to_list("name")
|
881
|
+
]
|
882
|
+
not_validated_keys_dtype_message = [
|
883
|
+
(key, infer_feature_type_convert_json(key, dictionary[key]))
|
884
|
+
for key in not_validated_keys
|
885
|
+
]
|
886
|
+
run = get_current_tracked_run()
|
887
|
+
if run is not None:
|
888
|
+
name = f"{run.transform.type}[{run.transform.key}]"
|
889
|
+
type_hint = f""" {model_name.lower()}_type = ln.{model_name}(name='{name}', is_type=True).save()"""
|
890
|
+
elements = [type_hint]
|
891
|
+
type_kwarg = f", type={model_name.lower()}_type"
|
892
|
+
else:
|
893
|
+
elements = []
|
894
|
+
type_kwarg = ""
|
895
|
+
elements += [
|
896
|
+
f" ln.{model_name}(name='{key}', dtype='{dtype}'{type_kwarg}).save(){message}"
|
897
|
+
for key, (dtype, _, message) in not_validated_keys_dtype_message
|
898
|
+
]
|
899
|
+
hint = "\n".join(elements)
|
900
|
+
msg = (
|
901
|
+
f"These keys could not be validated: {not_validated_keys}\n"
|
902
|
+
f"Here is how to create a {model_name.lower()}:\n\n{hint}"
|
903
|
+
)
|
904
|
+
raise ValidationError(msg)
|
905
|
+
|
906
906
|
features_labels = defaultdict(list)
|
907
907
|
_feature_values = []
|
908
908
|
not_validated_values: dict[str, list[str]] = defaultdict(list)
|
@@ -912,7 +912,6 @@ class FeatureManager:
|
|
912
912
|
feature.name,
|
913
913
|
value,
|
914
914
|
mute=True,
|
915
|
-
str_as_ulabel=str_as_ulabel,
|
916
915
|
)
|
917
916
|
if feature.dtype == "num":
|
918
917
|
if inferred_type not in {"int", "float"}:
|
@@ -994,6 +993,7 @@ class FeatureManager:
|
|
994
993
|
f"Here is how to create records for them:\n\n{hint}"
|
995
994
|
)
|
996
995
|
raise ValidationError(msg)
|
996
|
+
|
997
997
|
if features_labels:
|
998
998
|
self._add_label_feature_links(features_labels)
|
999
999
|
if _feature_values:
|
@@ -1039,7 +1039,7 @@ class FeatureManager:
|
|
1039
1039
|
feature: str | Feature,
|
1040
1040
|
*,
|
1041
1041
|
value: Any | None = None,
|
1042
|
-
):
|
1042
|
+
) -> None:
|
1043
1043
|
"""Remove value annotations for a given feature.
|
1044
1044
|
|
1045
1045
|
Args:
|
@@ -1262,7 +1262,7 @@ class FeatureManager:
|
|
1262
1262
|
"""Add feature set corresponding to column names of DataFrame."""
|
1263
1263
|
assert self._host.otype == "DataFrame" # noqa: S101
|
1264
1264
|
df = self._host.load(is_run_input=False)
|
1265
|
-
schema = Schema.
|
1265
|
+
schema = Schema.from_dataframe(
|
1266
1266
|
df=df,
|
1267
1267
|
field=field,
|
1268
1268
|
mute=mute,
|
lamindb/models/_from_values.py
CHANGED
@@ -121,7 +121,7 @@ def get_existing_records(
|
|
121
121
|
# ]
|
122
122
|
# )
|
123
123
|
# order by causes a factor 10 in runtime
|
124
|
-
# records = query_set.order_by(preserved).
|
124
|
+
# records = query_set.order_by(preserved).to_list()
|
125
125
|
|
126
126
|
# log validated terms
|
127
127
|
is_validated = model.validate(
|
@@ -165,7 +165,7 @@ def get_existing_records(
|
|
165
165
|
query = {f"{field.field.name}__in": iterable_idx.values} # type: ignore
|
166
166
|
if organism is not None:
|
167
167
|
query["organism"] = organism
|
168
|
-
records = model.filter(**query).
|
168
|
+
records = model.filter(**query).to_list()
|
169
169
|
|
170
170
|
if len(validated) == len(iterable_idx):
|
171
171
|
return records, pd.Index([]), msg
|
lamindb/models/_is_versioned.py
CHANGED
@@ -108,12 +108,12 @@ def bump_version(
|
|
108
108
|
) -> str:
|
109
109
|
"""Bumps the version number by major or minor depending on the bump_type flag.
|
110
110
|
|
111
|
-
|
112
|
-
|
113
|
-
|
111
|
+
Args:
|
112
|
+
version: The current version in "MAJOR" or "MAJOR.MINOR" format.
|
113
|
+
bump_type: The type of version bump, either 'major' or 'minor'.
|
114
114
|
|
115
115
|
Returns:
|
116
|
-
|
116
|
+
The new version string.
|
117
117
|
"""
|
118
118
|
try:
|
119
119
|
# Split the version into major and minor parts if possible
|
lamindb/models/_label_manager.py
CHANGED
@@ -268,7 +268,7 @@ class LabelManager:
|
|
268
268
|
for link in links:
|
269
269
|
if link.feature is not None:
|
270
270
|
features.add(link.feature)
|
271
|
-
key = link.feature.
|
271
|
+
key = link.feature.uid
|
272
272
|
else:
|
273
273
|
key = None
|
274
274
|
keys.append(key)
|
@@ -299,9 +299,9 @@ class LabelManager:
|
|
299
299
|
)
|
300
300
|
save(new_features) # type: ignore
|
301
301
|
if hasattr(self._host, related_name):
|
302
|
-
for
|
303
|
-
if
|
304
|
-
feature_id = Feature.get(
|
302
|
+
for feature_uid, feature_labels in labels_by_features.items():
|
303
|
+
if feature_uid is not None:
|
304
|
+
feature_id = Feature.get(feature_uid).id
|
305
305
|
else:
|
306
306
|
feature_id = None
|
307
307
|
getattr(self._host, related_name).add(
|