lamindb 1.12.0__py3-none-any.whl → 1.13.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 +2 -2
- lamindb/_finish.py +1 -1
- lamindb/_tracked.py +3 -15
- lamindb/core/_context.py +45 -19
- lamindb/curators/_legacy.py +1 -1
- lamindb/curators/core.py +51 -21
- lamindb/errors.py +6 -0
- lamindb/examples/datasets/_core.py +1 -1
- lamindb/integrations/__init__.py +0 -18
- lamindb/integrations/lightning.py +13 -10
- lamindb/migrations/0134_run_params.py +17 -0
- lamindb/migrations/{0133_squashed.py → 0134_squashed.py} +93 -90
- lamindb/models/_feature_manager.py +30 -20
- lamindb/models/_label_manager.py +3 -5
- lamindb/models/artifact.py +250 -291
- lamindb/models/artifact_set.py +4 -4
- lamindb/models/block.py +11 -9
- lamindb/models/can_curate.py +1 -1
- lamindb/models/collection.py +16 -17
- lamindb/models/feature.py +2 -2
- lamindb/models/has_parents.py +1 -3
- lamindb/models/query_manager.py +7 -7
- lamindb/models/query_set.py +38 -12
- lamindb/models/run.py +53 -49
- lamindb/models/schema.py +79 -65
- lamindb/models/sqlrecord.py +32 -17
- lamindb/models/transform.py +6 -3
- {lamindb-1.12.0.dist-info → lamindb-1.13.0.dist-info}/METADATA +26 -22
- {lamindb-1.12.0.dist-info → lamindb-1.13.0.dist-info}/RECORD +31 -30
- {lamindb-1.12.0.dist-info → lamindb-1.13.0.dist-info}/LICENSE +0 -0
- {lamindb-1.12.0.dist-info → lamindb-1.13.0.dist-info}/WHEEL +0 -0
@@ -1,4 +1,4 @@
|
|
1
|
-
# Generated by Django 5.
|
1
|
+
# Generated by Django 5.2 on 2025-10-13 07:43
|
2
2
|
|
3
3
|
import django.core.validators
|
4
4
|
import django.db.models.deletion
|
@@ -210,6 +210,7 @@ class Migration(migrations.Migration):
|
|
210
210
|
("lamindb", "0131_record_unique_name_type_space"),
|
211
211
|
("lamindb", "0132_record_parents_record_reference_and_more"),
|
212
212
|
("lamindb", "0133_artifactuser_artifact_users"),
|
213
|
+
("lamindb", "0134_run_params"),
|
213
214
|
]
|
214
215
|
|
215
216
|
dependencies = [] # type: ignore
|
@@ -2086,6 +2087,7 @@ class Migration(migrations.Migration):
|
|
2086
2087
|
blank=True, db_index=True, default=None, null=True
|
2087
2088
|
),
|
2088
2089
|
),
|
2090
|
+
("params", models.JSONField(null=True)),
|
2089
2091
|
(
|
2090
2092
|
"reference",
|
2091
2093
|
lamindb.base.fields.CharField(
|
@@ -5098,6 +5100,85 @@ class Migration(migrations.Migration):
|
|
5098
5100
|
to="lamindb.user",
|
5099
5101
|
),
|
5100
5102
|
),
|
5103
|
+
migrations.CreateModel(
|
5104
|
+
name="ArtifactUser",
|
5105
|
+
fields=[
|
5106
|
+
(
|
5107
|
+
"created_at",
|
5108
|
+
lamindb.base.fields.DateTimeField(
|
5109
|
+
blank=True,
|
5110
|
+
db_default=django.db.models.functions.datetime.Now(),
|
5111
|
+
db_index=True,
|
5112
|
+
editable=False,
|
5113
|
+
),
|
5114
|
+
),
|
5115
|
+
("id", models.BigAutoField(primary_key=True, serialize=False)),
|
5116
|
+
(
|
5117
|
+
"label_ref_is_name",
|
5118
|
+
lamindb.base.fields.BooleanField(
|
5119
|
+
blank=True, default=None, null=True
|
5120
|
+
),
|
5121
|
+
),
|
5122
|
+
(
|
5123
|
+
"feature_ref_is_name",
|
5124
|
+
lamindb.base.fields.BooleanField(
|
5125
|
+
blank=True, default=None, null=True
|
5126
|
+
),
|
5127
|
+
),
|
5128
|
+
(
|
5129
|
+
"artifact",
|
5130
|
+
lamindb.base.fields.ForeignKey(
|
5131
|
+
blank=True,
|
5132
|
+
on_delete=django.db.models.deletion.CASCADE,
|
5133
|
+
related_name="links_user",
|
5134
|
+
to="lamindb.artifact",
|
5135
|
+
),
|
5136
|
+
),
|
5137
|
+
(
|
5138
|
+
"feature",
|
5139
|
+
lamindb.base.fields.ForeignKey(
|
5140
|
+
blank=True,
|
5141
|
+
default=None,
|
5142
|
+
null=True,
|
5143
|
+
on_delete=django.db.models.deletion.PROTECT,
|
5144
|
+
related_name="links_artifactuser",
|
5145
|
+
to="lamindb.feature",
|
5146
|
+
),
|
5147
|
+
),
|
5148
|
+
(
|
5149
|
+
"run",
|
5150
|
+
lamindb.base.fields.ForeignKey(
|
5151
|
+
blank=True,
|
5152
|
+
default=lamindb.models.run.current_run,
|
5153
|
+
null=True,
|
5154
|
+
on_delete=django.db.models.deletion.PROTECT,
|
5155
|
+
related_name="+",
|
5156
|
+
to="lamindb.run",
|
5157
|
+
),
|
5158
|
+
),
|
5159
|
+
(
|
5160
|
+
"created_by",
|
5161
|
+
lamindb.base.fields.ForeignKey(
|
5162
|
+
blank=True,
|
5163
|
+
default=lamindb.base.users.current_user_id,
|
5164
|
+
editable=False,
|
5165
|
+
on_delete=django.db.models.deletion.PROTECT,
|
5166
|
+
related_name="+",
|
5167
|
+
to="lamindb.user",
|
5168
|
+
),
|
5169
|
+
),
|
5170
|
+
(
|
5171
|
+
"user",
|
5172
|
+
lamindb.base.fields.ForeignKey(
|
5173
|
+
blank=True,
|
5174
|
+
on_delete=django.db.models.deletion.PROTECT,
|
5175
|
+
related_name="links_artifact",
|
5176
|
+
to="lamindb.user",
|
5177
|
+
),
|
5178
|
+
),
|
5179
|
+
],
|
5180
|
+
bases=(lamindb.models.sqlrecord.IsLink, models.Model),
|
5181
|
+
),
|
5101
5182
|
migrations.AddField(
|
5102
5183
|
model_name="artifactreference",
|
5103
5184
|
name="created_by",
|
@@ -5215,6 +5296,13 @@ class Migration(migrations.Migration):
|
|
5215
5296
|
to="lamindb.user",
|
5216
5297
|
),
|
5217
5298
|
),
|
5299
|
+
migrations.AddField(
|
5300
|
+
model_name="artifact",
|
5301
|
+
name="users",
|
5302
|
+
field=models.ManyToManyField(
|
5303
|
+
related_name="+", through="lamindb.ArtifactUser", to="lamindb.user"
|
5304
|
+
),
|
5305
|
+
),
|
5218
5306
|
migrations.AlterUniqueTogether(
|
5219
5307
|
name="artifactrecord",
|
5220
5308
|
unique_together={("artifact", "record", "feature")},
|
@@ -5346,6 +5434,10 @@ class Migration(migrations.Migration):
|
|
5346
5434
|
name="unique_branch_name_lower",
|
5347
5435
|
),
|
5348
5436
|
),
|
5437
|
+
migrations.AlterUniqueTogether(
|
5438
|
+
name="artifactuser",
|
5439
|
+
unique_together={("artifact", "user", "feature")},
|
5440
|
+
),
|
5349
5441
|
migrations.AlterUniqueTogether(
|
5350
5442
|
name="artifactulabel",
|
5351
5443
|
unique_together={("artifact", "ulabel", "feature")},
|
@@ -5382,95 +5474,6 @@ class Migration(migrations.Migration):
|
|
5382
5474
|
name="unique_artifact_storage_hash_null_key",
|
5383
5475
|
),
|
5384
5476
|
),
|
5385
|
-
migrations.CreateModel(
|
5386
|
-
name="ArtifactUser",
|
5387
|
-
fields=[
|
5388
|
-
(
|
5389
|
-
"created_at",
|
5390
|
-
lamindb.base.fields.DateTimeField(
|
5391
|
-
blank=True,
|
5392
|
-
db_default=django.db.models.functions.datetime.Now(),
|
5393
|
-
db_index=True,
|
5394
|
-
editable=False,
|
5395
|
-
),
|
5396
|
-
),
|
5397
|
-
("id", models.BigAutoField(primary_key=True, serialize=False)),
|
5398
|
-
(
|
5399
|
-
"label_ref_is_name",
|
5400
|
-
lamindb.base.fields.BooleanField(
|
5401
|
-
blank=True, default=None, null=True
|
5402
|
-
),
|
5403
|
-
),
|
5404
|
-
(
|
5405
|
-
"feature_ref_is_name",
|
5406
|
-
lamindb.base.fields.BooleanField(
|
5407
|
-
blank=True, default=None, null=True
|
5408
|
-
),
|
5409
|
-
),
|
5410
|
-
(
|
5411
|
-
"artifact",
|
5412
|
-
lamindb.base.fields.ForeignKey(
|
5413
|
-
blank=True,
|
5414
|
-
on_delete=django.db.models.deletion.CASCADE,
|
5415
|
-
related_name="links_user",
|
5416
|
-
to="lamindb.artifact",
|
5417
|
-
),
|
5418
|
-
),
|
5419
|
-
(
|
5420
|
-
"created_by",
|
5421
|
-
lamindb.base.fields.ForeignKey(
|
5422
|
-
blank=True,
|
5423
|
-
default=lamindb.base.users.current_user_id,
|
5424
|
-
editable=False,
|
5425
|
-
on_delete=django.db.models.deletion.PROTECT,
|
5426
|
-
related_name="+",
|
5427
|
-
to="lamindb.user",
|
5428
|
-
),
|
5429
|
-
),
|
5430
|
-
(
|
5431
|
-
"feature",
|
5432
|
-
lamindb.base.fields.ForeignKey(
|
5433
|
-
blank=True,
|
5434
|
-
default=None,
|
5435
|
-
null=True,
|
5436
|
-
on_delete=django.db.models.deletion.PROTECT,
|
5437
|
-
related_name="links_artifactuser",
|
5438
|
-
to="lamindb.feature",
|
5439
|
-
),
|
5440
|
-
),
|
5441
|
-
(
|
5442
|
-
"run",
|
5443
|
-
lamindb.base.fields.ForeignKey(
|
5444
|
-
blank=True,
|
5445
|
-
default=lamindb.models.run.current_run,
|
5446
|
-
null=True,
|
5447
|
-
on_delete=django.db.models.deletion.PROTECT,
|
5448
|
-
related_name="+",
|
5449
|
-
to="lamindb.run",
|
5450
|
-
),
|
5451
|
-
),
|
5452
|
-
(
|
5453
|
-
"user",
|
5454
|
-
lamindb.base.fields.ForeignKey(
|
5455
|
-
blank=True,
|
5456
|
-
on_delete=django.db.models.deletion.PROTECT,
|
5457
|
-
related_name="links_artifact",
|
5458
|
-
to="lamindb.user",
|
5459
|
-
),
|
5460
|
-
),
|
5461
|
-
],
|
5462
|
-
options={
|
5463
|
-
"unique_together": {("artifact", "user", "feature")},
|
5464
|
-
},
|
5465
|
-
bases=(lamindb.models.sqlrecord.IsLink, models.Model),
|
5466
|
-
),
|
5467
|
-
migrations.AddField(
|
5468
|
-
model_name="artifact",
|
5469
|
-
name="users",
|
5470
|
-
field=models.ManyToManyField(
|
5471
|
-
related_name="+", through="lamindb.ArtifactUser", to="lamindb.user"
|
5472
|
-
),
|
5473
|
-
),
|
5474
5477
|
migrations.RunPython(
|
5475
5478
|
apply_postgres_constraint, reverse_code=revert_postgres_constraint
|
5476
5479
|
),
|
@@ -345,7 +345,7 @@ def describe_features(
|
|
345
345
|
|
346
346
|
internal_feature_names: dict[str, str] = {}
|
347
347
|
if isinstance(self, Artifact):
|
348
|
-
feature_sets = self.feature_sets.filter(itype="Feature")
|
348
|
+
feature_sets = self.feature_sets.filter(itype="Feature")
|
349
349
|
internal_feature_names = {}
|
350
350
|
if len(feature_sets) > 0:
|
351
351
|
for schema in feature_sets:
|
@@ -470,7 +470,7 @@ def describe_features(
|
|
470
470
|
for child in int_features_tree_children:
|
471
471
|
dataset_tree.add(child)
|
472
472
|
|
473
|
-
#
|
473
|
+
# External features
|
474
474
|
ext_features_tree_children = []
|
475
475
|
if external_data:
|
476
476
|
ext_features_tree_children.append(
|
@@ -481,7 +481,7 @@ def describe_features(
|
|
481
481
|
)
|
482
482
|
)
|
483
483
|
# ext_features_tree = None
|
484
|
-
ext_features_header = Text("
|
484
|
+
ext_features_header = Text("External features", style="bold dark_orange")
|
485
485
|
if ext_features_tree_children:
|
486
486
|
ext_features_tree = tree.add(ext_features_header)
|
487
487
|
for child in ext_features_tree_children:
|
@@ -584,7 +584,7 @@ def filter_base(
|
|
584
584
|
f"Some keys in the filter expression are not registered as features: {np.array(keys_normalized)[~validated]}"
|
585
585
|
)
|
586
586
|
new_expression = {}
|
587
|
-
features = model.using(db).filter(name__in=keys_normalized).
|
587
|
+
features = model.using(db).filter(name__in=keys_normalized).distinct()
|
588
588
|
feature_param = "feature"
|
589
589
|
for key, value in expression.items():
|
590
590
|
split_key = key.split("__")
|
@@ -650,7 +650,7 @@ def filter_base(
|
|
650
650
|
# we need the comparator here because users might query like so
|
651
651
|
# ln.Artifact.filter(experiment__contains="Experi")
|
652
652
|
expression = {f"{field_name}{comparator}": value}
|
653
|
-
labels = result["registry"].using(db).filter(**expression)
|
653
|
+
labels = result["registry"].using(db).filter(**expression)
|
654
654
|
if len(labels) == 0:
|
655
655
|
raise DoesNotExist(
|
656
656
|
f"Did not find a {label_registry.__name__} matching `{field_name}{comparator}={value}`"
|
@@ -702,8 +702,8 @@ def filter_with_features(
|
|
702
702
|
|
703
703
|
if expressions:
|
704
704
|
keys_normalized = [key.split("__")[0] for key in expressions]
|
705
|
-
|
706
|
-
if
|
705
|
+
field_or_feature = keys_normalized[0]
|
706
|
+
if field_or_feature in registry.__get_available_fields__():
|
707
707
|
qs = queryset.filter(*queries, **expressions, **filter_kwargs)
|
708
708
|
elif all(
|
709
709
|
features_validated := Feature.objects.using(queryset.db).validate(
|
@@ -896,7 +896,7 @@ class FeatureManager:
|
|
896
896
|
"feature_id": None,
|
897
897
|
f"{field_name}__in": [l.id for _, l in registry_features_labels],
|
898
898
|
}
|
899
|
-
).
|
899
|
+
).delete()
|
900
900
|
|
901
901
|
def add_values(
|
902
902
|
self,
|
@@ -928,11 +928,9 @@ class FeatureManager:
|
|
928
928
|
model_name = "Feature"
|
929
929
|
|
930
930
|
if schema is not None:
|
931
|
-
from lamindb.curators import
|
931
|
+
from lamindb.curators.core import ExperimentalDictCurator
|
932
932
|
|
933
|
-
|
934
|
-
curator = DataFrameCurator(temp_df, schema)
|
935
|
-
curator.validate()
|
933
|
+
ExperimentalDictCurator(values, schema).validate()
|
936
934
|
records = schema.members.filter(name__in=keys)
|
937
935
|
else:
|
938
936
|
records = registry.from_values(keys, field=feature_field, mute=True)
|
@@ -990,13 +988,25 @@ class FeatureManager:
|
|
990
988
|
raise TypeError(
|
991
989
|
f"Value for feature '{feature.name}' with dtype '{feature.dtype}' must be a string or record, but is {value} with dtype {inferred_type}"
|
992
990
|
)
|
993
|
-
elif (
|
994
|
-
feature.dtype
|
991
|
+
elif (
|
992
|
+
(feature.dtype == "str" and inferred_type != "cat ? str")
|
993
|
+
or (feature.dtype == "list[str]" and inferred_type != "list[cat ? str]")
|
994
|
+
or (
|
995
|
+
feature.dtype.startswith("list[cat")
|
996
|
+
and inferred_type != "list[cat ? str]"
|
997
|
+
)
|
998
|
+
or (
|
999
|
+
feature.dtype not in {"str", "list[str]"}
|
1000
|
+
and not feature.dtype.startswith("list[cat")
|
1001
|
+
and feature.dtype != inferred_type
|
1002
|
+
)
|
995
1003
|
):
|
996
1004
|
raise ValidationError(
|
997
1005
|
f"Expected dtype for '{feature.name}' is '{feature.dtype}', got '{inferred_type}'"
|
998
1006
|
)
|
999
|
-
if not
|
1007
|
+
if not (
|
1008
|
+
feature.dtype.startswith("cat") or feature.dtype.startswith("list[cat")
|
1009
|
+
):
|
1000
1010
|
filter_kwargs = {model_name.lower(): feature, "value": converted_value}
|
1001
1011
|
feature_value, _ = value_model.get_or_create(**filter_kwargs)
|
1002
1012
|
_feature_values.append(feature_value)
|
@@ -1078,7 +1088,7 @@ class FeatureManager:
|
|
1078
1088
|
f"{model_name.lower()}__in": dict_typed_features,
|
1079
1089
|
}
|
1080
1090
|
try:
|
1081
|
-
value_model.filter(**kwargs).
|
1091
|
+
value_model.filter(**kwargs).delete()
|
1082
1092
|
except ProtectedError:
|
1083
1093
|
pass
|
1084
1094
|
# add new feature links
|
@@ -1140,7 +1150,7 @@ class FeatureManager:
|
|
1140
1150
|
if obj.related_model.__get_name_with_module__()
|
1141
1151
|
in link_models_on_models
|
1142
1152
|
}.pop()
|
1143
|
-
getattr(self._host, link_attribute).filter(**filter_kwargs).
|
1153
|
+
getattr(self._host, link_attribute).filter(**filter_kwargs).delete()
|
1144
1154
|
else:
|
1145
1155
|
if value is not None:
|
1146
1156
|
filter_kwargs["value"] = value
|
@@ -1215,7 +1225,7 @@ class FeatureManager:
|
|
1215
1225
|
member_uids = list(members.values_list(field, flat=True))
|
1216
1226
|
validated = registry.validate(member_uids, field=field, mute=True)
|
1217
1227
|
new_members_uids = list(compress(member_uids, ~validated))
|
1218
|
-
new_members = members.filter(**{f"{field}__in": new_members_uids})
|
1228
|
+
new_members = members.filter(**{f"{field}__in": new_members_uids})
|
1219
1229
|
n_new_members = len(new_members)
|
1220
1230
|
if len(members) > settings.annotation.n_max_records:
|
1221
1231
|
logger.warning(
|
@@ -1275,9 +1285,9 @@ class FeatureManager:
|
|
1275
1285
|
"""
|
1276
1286
|
if not isinstance(feature, Feature):
|
1277
1287
|
raise TypeError("feature must be a Feature record!")
|
1278
|
-
feature_sets = Schema.filter(features=feature)
|
1288
|
+
feature_sets = Schema.filter(features=feature)
|
1279
1289
|
for fs in feature_sets:
|
1280
|
-
f = Feature.filter(uid=feature.uid)
|
1290
|
+
f = Feature.filter(uid=feature.uid)
|
1281
1291
|
features_updated = fs.members.difference(f)
|
1282
1292
|
if len(features_updated) > 0:
|
1283
1293
|
# re-compute the hash of feature sets based on the updated members
|
lamindb/models/_label_manager.py
CHANGED
@@ -231,7 +231,7 @@ class LabelManager:
|
|
231
231
|
>>> artifact2 = ln.Artifact(pd.DataFrame(index=[2, 3])).save()
|
232
232
|
>>> ulabels = ln.ULabel.from_values(["Label1", "Label2"], field="name")
|
233
233
|
>>> ln.save(ulabels)
|
234
|
-
>>> labels = ln.ULabel.filter(name__icontains = "label")
|
234
|
+
>>> labels = ln.ULabel.filter(name__icontains = "label")
|
235
235
|
>>> artifact1.ulabels.set(labels)
|
236
236
|
>>> artifact2.labels.add_from(artifact1)
|
237
237
|
"""
|
@@ -260,10 +260,8 @@ class LabelManager:
|
|
260
260
|
key = None
|
261
261
|
keys.append(key)
|
262
262
|
else:
|
263
|
-
links = (
|
264
|
-
|
265
|
-
.filter(**{f"{data_name_lower}_id": data.id})
|
266
|
-
.all()
|
263
|
+
links = getattr(label, f"links_{data_name_lower}").filter(
|
264
|
+
**{f"{data_name_lower}_id": data.id}
|
267
265
|
)
|
268
266
|
for link in links:
|
269
267
|
if link.feature is not None:
|