lamindb 1.6a2__py3-none-any.whl → 1.6.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 +2 -1
- lamindb/core/_context.py +29 -7
- lamindb/core/datasets/mini_immuno.py +3 -3
- lamindb/curators/core.py +2 -2
- lamindb/migrations/0101_alter_artifact_hash_alter_feature_name_and_more.py +20 -27
- lamindb/migrations/0104_alter_branch_uid.py +403 -0
- lamindb/migrations/{0103_squashed.py → 0104_squashed.py} +33 -3
- lamindb/models/_feature_manager.py +11 -7
- lamindb/models/collection.py +1 -3
- lamindb/models/project.py +11 -7
- lamindb/models/record.py +45 -0
- lamindb/models/run.py +4 -2
- lamindb/models/sqlrecord.py +42 -40
- {lamindb-1.6a2.dist-info → lamindb-1.6.1.dist-info}/METADATA +5 -4
- {lamindb-1.6a2.dist-info → lamindb-1.6.1.dist-info}/RECORD +17 -16
- {lamindb-1.6a2.dist-info → lamindb-1.6.1.dist-info}/LICENSE +0 -0
- {lamindb-1.6a2.dist-info → lamindb-1.6.1.dist-info}/WHEEL +0 -0
lamindb/__init__.py
CHANGED
@@ -109,7 +109,7 @@ Backwards compatibility.
|
|
109
109
|
|
110
110
|
# ruff: noqa: I001
|
111
111
|
# denote a release candidate for 0.1.0 with 0.1rc1, 0.1a1, 0.1b1, etc.
|
112
|
-
__version__ = "1.
|
112
|
+
__version__ = "1.6.1"
|
113
113
|
|
114
114
|
import warnings
|
115
115
|
|
@@ -153,6 +153,7 @@ if _check_instance_setup(from_module="lamindb"):
|
|
153
153
|
ULabel,
|
154
154
|
User,
|
155
155
|
Space,
|
156
|
+
Branch,
|
156
157
|
Record,
|
157
158
|
Sheet,
|
158
159
|
)
|
lamindb/core/_context.py
CHANGED
@@ -38,7 +38,7 @@ if TYPE_CHECKING:
|
|
38
38
|
from lamindb_setup.core.types import UPathStr
|
39
39
|
|
40
40
|
from lamindb.base.types import TransformType
|
41
|
-
from lamindb.models import Project, Space
|
41
|
+
from lamindb.models import Branch, Project, Space
|
42
42
|
|
43
43
|
is_run_from_ipython = getattr(builtins, "__IPYTHON__", False)
|
44
44
|
|
@@ -193,6 +193,7 @@ class Context:
|
|
193
193
|
"""A local path to the script or notebook that's running."""
|
194
194
|
self._project: Project | None = None
|
195
195
|
self._space: Space | None = None
|
196
|
+
self._branch: Branch | None = None
|
196
197
|
self._logging_message_track: str = ""
|
197
198
|
self._logging_message_imports: str = ""
|
198
199
|
self._stream_tracker: LogStreamTracker = LogStreamTracker()
|
@@ -247,9 +248,14 @@ class Context:
|
|
247
248
|
|
248
249
|
@property
|
249
250
|
def space(self) -> Space | None:
|
250
|
-
"""The space in which
|
251
|
+
"""The space in which artifacts, collections, transforms, and runs are saved during the run."""
|
251
252
|
return self._space
|
252
253
|
|
254
|
+
@property
|
255
|
+
def branch(self) -> Branch | None:
|
256
|
+
"""The branch on which entities are created during the run."""
|
257
|
+
return self._branch
|
258
|
+
|
253
259
|
@property
|
254
260
|
def run(self) -> Run | None:
|
255
261
|
"""Managed run of context."""
|
@@ -261,6 +267,7 @@ class Context:
|
|
261
267
|
*,
|
262
268
|
project: str | Project | None = None,
|
263
269
|
space: str | Space | None = None,
|
270
|
+
branch: str | Branch | None = None,
|
264
271
|
params: dict | None = None,
|
265
272
|
new_run: bool | None = None,
|
266
273
|
path: str | None = None,
|
@@ -273,11 +280,11 @@ class Context:
|
|
273
280
|
|
274
281
|
Args:
|
275
282
|
transform: A transform (stem) `uid` (or record). If `None`, auto-creates a `transform` with its `uid`.
|
276
|
-
project: A project
|
277
|
-
space: A restricted space
|
278
|
-
|
279
|
-
The `space` argument doesn't affect `Storage`, `ULabel`, `Feature`, `Schema`, `Param` and bionty entities as these provide structure that should typically be commonly accessible.
|
283
|
+
project: A project (or its `name` or `uid`) for labeling entities.
|
284
|
+
space: A restricted space (or its `name` or `uid`) in which to store artifacts, collections, transforms, and runs.
|
285
|
+
Default: the `"All"` space.
|
280
286
|
If you want to manually move entities to a different space, set the `.space` field (:doc:`docs:access`).
|
287
|
+
branch: A branch (or its `name` or `uid`) on which to store records.
|
281
288
|
params: A dictionary of parameters to track for the run.
|
282
289
|
new_run: If `False`, loads the latest run of transform
|
283
290
|
(default notebook), if `True`, creates new run (default non-notebook).
|
@@ -299,7 +306,7 @@ class Context:
|
|
299
306
|
|
300
307
|
More examples: :doc:`/track`
|
301
308
|
"""
|
302
|
-
from lamindb.models import Project, Space
|
309
|
+
from lamindb.models import Branch, Project, Space
|
303
310
|
|
304
311
|
instance_settings = ln_setup.settings.instance
|
305
312
|
# similar logic here: https://github.com/laminlabs/lamindb/pull/2527
|
@@ -337,6 +344,21 @@ class Context:
|
|
337
344
|
f"Space '{space}', please check on the hub UI whether you have the correct `uid` or `name`."
|
338
345
|
)
|
339
346
|
self._space = space_record
|
347
|
+
if branch is not None:
|
348
|
+
if isinstance(branch, Branch):
|
349
|
+
assert branch._state.adding is False, ( # noqa: S101
|
350
|
+
"Branch must be saved before passing it to track()"
|
351
|
+
)
|
352
|
+
branch_record = branch
|
353
|
+
else:
|
354
|
+
branch_record = Branch.filter(
|
355
|
+
Q(name=branch) | Q(uid=branch)
|
356
|
+
).one_or_none()
|
357
|
+
if branch_record is None:
|
358
|
+
raise InvalidArgument(
|
359
|
+
f"Space '{branch}', please check on the hub UI whether you have the correct `uid` or `name`."
|
360
|
+
)
|
361
|
+
self._branch = branch_record
|
340
362
|
self._logging_message_track = ""
|
341
363
|
self._logging_message_imports = ""
|
342
364
|
if transform is not None and isinstance(transform, str):
|
@@ -105,9 +105,9 @@ def get_dataset1(
|
|
105
105
|
"treatment_time_h": [24, 24, 6],
|
106
106
|
"donor": ["D0001", "D0002", None],
|
107
107
|
"donor_ethnicity": [
|
108
|
-
["
|
109
|
-
["
|
110
|
-
["
|
108
|
+
["Chinese", "Singaporean Chinese"],
|
109
|
+
["Chinese", "Han Chinese"],
|
110
|
+
["Chinese"],
|
111
111
|
],
|
112
112
|
}
|
113
113
|
# define the dataset-level metadata
|
lamindb/curators/core.py
CHANGED
@@ -823,9 +823,9 @@ class SpatialDataCurator(SlotsCurator):
|
|
823
823
|
|
824
824
|
Example:
|
825
825
|
|
826
|
-
.. literalinclude:: scripts/
|
826
|
+
.. literalinclude:: scripts/curate_mudata.py
|
827
827
|
:language: python
|
828
|
-
:caption:
|
828
|
+
:caption: curate_mudata.py
|
829
829
|
|
830
830
|
See Also:
|
831
831
|
:meth:`~lamindb.Artifact.from_spatialdata`.
|
@@ -8,42 +8,35 @@ import lamindb.base.fields
|
|
8
8
|
|
9
9
|
|
10
10
|
def populate_hash_values(apps, schema_editor):
|
11
|
+
from tqdm import tqdm
|
12
|
+
|
11
13
|
FeatureValue = apps.get_model("lamindb", "FeatureValue")
|
12
14
|
|
13
|
-
|
14
|
-
|
15
|
+
records_queryset = FeatureValue.objects.filter(hash__isnull=True)
|
16
|
+
total_count = records_queryset.count()
|
17
|
+
print(f"\nFound {total_count} FeatureValue records with hash=None. Populating...")
|
15
18
|
|
16
|
-
|
17
|
-
|
18
|
-
)
|
19
|
+
# Convert to list to avoid QuerySet modification issues
|
20
|
+
records_to_update = list(records_queryset)
|
19
21
|
|
22
|
+
batch_size = 1000
|
20
23
|
updated_count = 0
|
21
|
-
skipped_count = 0
|
22
24
|
|
23
|
-
|
24
|
-
|
25
|
-
value = record.value
|
26
|
-
new_hash = None
|
25
|
+
for batch_start in tqdm(range(0, len(records_to_update), batch_size)):
|
26
|
+
batch_records = records_to_update[batch_start : batch_start + batch_size]
|
27
27
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
28
|
+
# Calculate hashes for all records in batch
|
29
|
+
for record in batch_records:
|
30
|
+
if not isinstance(record.value, dict):
|
31
|
+
record.hash = hash_string(str(record.value))
|
32
|
+
else:
|
33
|
+
record.hash = hash_dict(record.value)
|
32
34
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
updated_count += 1
|
37
|
-
except Exception as e:
|
38
|
-
# This will likely catch IntegrityError if a duplicate hash exists
|
39
|
-
# for the same feature. You might want to log these or handle them
|
40
|
-
# based on your data cleanup strategy.
|
41
|
-
print(
|
42
|
-
f" - Could not update record {record.id} (value: {str(value)[:50]}...): {e}"
|
43
|
-
)
|
44
|
-
skipped_count += 1
|
35
|
+
# Bulk update the entire batch
|
36
|
+
FeatureValue.objects.bulk_update(batch_records, ["hash"], batch_size=batch_size)
|
37
|
+
updated_count += len(batch_records)
|
45
38
|
|
46
|
-
print(f"Finished. Updated: {updated_count}
|
39
|
+
print(f"Finished. Updated: {updated_count} records.")
|
47
40
|
|
48
41
|
|
49
42
|
class Migration(migrations.Migration):
|
@@ -0,0 +1,403 @@
|
|
1
|
+
# Generated by Django 5.2 on 2025-06-02 10:53
|
2
|
+
|
3
|
+
import django.db.models.deletion
|
4
|
+
from django.db import migrations
|
5
|
+
|
6
|
+
import lamindb.base.fields
|
7
|
+
import lamindb.base.uids
|
8
|
+
|
9
|
+
|
10
|
+
class Migration(migrations.Migration):
|
11
|
+
dependencies = [
|
12
|
+
("lamindb", "0103_remove_writelog_migration_state_and_more"),
|
13
|
+
]
|
14
|
+
|
15
|
+
operations = [
|
16
|
+
migrations.AlterField(
|
17
|
+
model_name="branch",
|
18
|
+
name="uid",
|
19
|
+
field=lamindb.base.fields.CharField(
|
20
|
+
blank=True,
|
21
|
+
db_index=True,
|
22
|
+
default=lamindb.base.uids.base62_12,
|
23
|
+
editable=False,
|
24
|
+
max_length=12,
|
25
|
+
unique=True,
|
26
|
+
),
|
27
|
+
),
|
28
|
+
migrations.AlterField(
|
29
|
+
model_name="artifact",
|
30
|
+
name="branch",
|
31
|
+
field=lamindb.base.fields.ForeignKey(
|
32
|
+
blank=True,
|
33
|
+
db_column="_branch_code",
|
34
|
+
db_default=1,
|
35
|
+
default=1,
|
36
|
+
on_delete=django.db.models.deletion.PROTECT,
|
37
|
+
related_name="+",
|
38
|
+
to="lamindb.branch",
|
39
|
+
),
|
40
|
+
),
|
41
|
+
migrations.AlterField(
|
42
|
+
model_name="artifact",
|
43
|
+
name="space",
|
44
|
+
field=lamindb.base.fields.ForeignKey(
|
45
|
+
blank=True,
|
46
|
+
db_default=1,
|
47
|
+
default=1,
|
48
|
+
on_delete=django.db.models.deletion.PROTECT,
|
49
|
+
related_name="+",
|
50
|
+
to="lamindb.space",
|
51
|
+
),
|
52
|
+
),
|
53
|
+
migrations.AlterField(
|
54
|
+
model_name="collection",
|
55
|
+
name="branch",
|
56
|
+
field=lamindb.base.fields.ForeignKey(
|
57
|
+
blank=True,
|
58
|
+
db_column="_branch_code",
|
59
|
+
db_default=1,
|
60
|
+
default=1,
|
61
|
+
on_delete=django.db.models.deletion.PROTECT,
|
62
|
+
related_name="+",
|
63
|
+
to="lamindb.branch",
|
64
|
+
),
|
65
|
+
),
|
66
|
+
migrations.AlterField(
|
67
|
+
model_name="collection",
|
68
|
+
name="space",
|
69
|
+
field=lamindb.base.fields.ForeignKey(
|
70
|
+
blank=True,
|
71
|
+
db_default=1,
|
72
|
+
default=1,
|
73
|
+
on_delete=django.db.models.deletion.PROTECT,
|
74
|
+
related_name="+",
|
75
|
+
to="lamindb.space",
|
76
|
+
),
|
77
|
+
),
|
78
|
+
migrations.AlterField(
|
79
|
+
model_name="feature",
|
80
|
+
name="branch",
|
81
|
+
field=lamindb.base.fields.ForeignKey(
|
82
|
+
blank=True,
|
83
|
+
db_column="_branch_code",
|
84
|
+
db_default=1,
|
85
|
+
default=1,
|
86
|
+
on_delete=django.db.models.deletion.PROTECT,
|
87
|
+
related_name="+",
|
88
|
+
to="lamindb.branch",
|
89
|
+
),
|
90
|
+
),
|
91
|
+
migrations.AlterField(
|
92
|
+
model_name="feature",
|
93
|
+
name="space",
|
94
|
+
field=lamindb.base.fields.ForeignKey(
|
95
|
+
blank=True,
|
96
|
+
db_default=1,
|
97
|
+
default=1,
|
98
|
+
on_delete=django.db.models.deletion.PROTECT,
|
99
|
+
related_name="+",
|
100
|
+
to="lamindb.space",
|
101
|
+
),
|
102
|
+
),
|
103
|
+
migrations.AlterField(
|
104
|
+
model_name="featurevalue",
|
105
|
+
name="branch",
|
106
|
+
field=lamindb.base.fields.ForeignKey(
|
107
|
+
blank=True,
|
108
|
+
db_column="_branch_code",
|
109
|
+
db_default=1,
|
110
|
+
default=1,
|
111
|
+
on_delete=django.db.models.deletion.PROTECT,
|
112
|
+
related_name="+",
|
113
|
+
to="lamindb.branch",
|
114
|
+
),
|
115
|
+
),
|
116
|
+
migrations.AlterField(
|
117
|
+
model_name="featurevalue",
|
118
|
+
name="space",
|
119
|
+
field=lamindb.base.fields.ForeignKey(
|
120
|
+
blank=True,
|
121
|
+
db_default=1,
|
122
|
+
default=1,
|
123
|
+
on_delete=django.db.models.deletion.PROTECT,
|
124
|
+
related_name="+",
|
125
|
+
to="lamindb.space",
|
126
|
+
),
|
127
|
+
),
|
128
|
+
migrations.AlterField(
|
129
|
+
model_name="person",
|
130
|
+
name="branch",
|
131
|
+
field=lamindb.base.fields.ForeignKey(
|
132
|
+
blank=True,
|
133
|
+
db_column="_branch_code",
|
134
|
+
db_default=1,
|
135
|
+
default=1,
|
136
|
+
on_delete=django.db.models.deletion.PROTECT,
|
137
|
+
related_name="+",
|
138
|
+
to="lamindb.branch",
|
139
|
+
),
|
140
|
+
),
|
141
|
+
migrations.AlterField(
|
142
|
+
model_name="person",
|
143
|
+
name="space",
|
144
|
+
field=lamindb.base.fields.ForeignKey(
|
145
|
+
blank=True,
|
146
|
+
db_default=1,
|
147
|
+
default=1,
|
148
|
+
on_delete=django.db.models.deletion.PROTECT,
|
149
|
+
related_name="+",
|
150
|
+
to="lamindb.space",
|
151
|
+
),
|
152
|
+
),
|
153
|
+
migrations.AlterField(
|
154
|
+
model_name="project",
|
155
|
+
name="branch",
|
156
|
+
field=lamindb.base.fields.ForeignKey(
|
157
|
+
blank=True,
|
158
|
+
db_column="_branch_code",
|
159
|
+
db_default=1,
|
160
|
+
default=1,
|
161
|
+
on_delete=django.db.models.deletion.PROTECT,
|
162
|
+
related_name="+",
|
163
|
+
to="lamindb.branch",
|
164
|
+
),
|
165
|
+
),
|
166
|
+
migrations.AlterField(
|
167
|
+
model_name="project",
|
168
|
+
name="space",
|
169
|
+
field=lamindb.base.fields.ForeignKey(
|
170
|
+
blank=True,
|
171
|
+
db_default=1,
|
172
|
+
default=1,
|
173
|
+
on_delete=django.db.models.deletion.PROTECT,
|
174
|
+
related_name="+",
|
175
|
+
to="lamindb.space",
|
176
|
+
),
|
177
|
+
),
|
178
|
+
migrations.AlterField(
|
179
|
+
model_name="record",
|
180
|
+
name="branch",
|
181
|
+
field=lamindb.base.fields.ForeignKey(
|
182
|
+
blank=True,
|
183
|
+
db_column="_branch_code",
|
184
|
+
db_default=1,
|
185
|
+
default=1,
|
186
|
+
on_delete=django.db.models.deletion.PROTECT,
|
187
|
+
related_name="+",
|
188
|
+
to="lamindb.branch",
|
189
|
+
),
|
190
|
+
),
|
191
|
+
migrations.AlterField(
|
192
|
+
model_name="record",
|
193
|
+
name="space",
|
194
|
+
field=lamindb.base.fields.ForeignKey(
|
195
|
+
blank=True,
|
196
|
+
db_default=1,
|
197
|
+
default=1,
|
198
|
+
on_delete=django.db.models.deletion.PROTECT,
|
199
|
+
related_name="+",
|
200
|
+
to="lamindb.space",
|
201
|
+
),
|
202
|
+
),
|
203
|
+
migrations.AlterField(
|
204
|
+
model_name="recordrecord",
|
205
|
+
name="branch",
|
206
|
+
field=lamindb.base.fields.ForeignKey(
|
207
|
+
blank=True,
|
208
|
+
db_column="_branch_code",
|
209
|
+
db_default=1,
|
210
|
+
default=1,
|
211
|
+
on_delete=django.db.models.deletion.PROTECT,
|
212
|
+
related_name="+",
|
213
|
+
to="lamindb.branch",
|
214
|
+
),
|
215
|
+
),
|
216
|
+
migrations.AlterField(
|
217
|
+
model_name="recordrecord",
|
218
|
+
name="space",
|
219
|
+
field=lamindb.base.fields.ForeignKey(
|
220
|
+
blank=True,
|
221
|
+
db_default=1,
|
222
|
+
default=1,
|
223
|
+
on_delete=django.db.models.deletion.PROTECT,
|
224
|
+
related_name="+",
|
225
|
+
to="lamindb.space",
|
226
|
+
),
|
227
|
+
),
|
228
|
+
migrations.AlterField(
|
229
|
+
model_name="reference",
|
230
|
+
name="branch",
|
231
|
+
field=lamindb.base.fields.ForeignKey(
|
232
|
+
blank=True,
|
233
|
+
db_column="_branch_code",
|
234
|
+
db_default=1,
|
235
|
+
default=1,
|
236
|
+
on_delete=django.db.models.deletion.PROTECT,
|
237
|
+
related_name="+",
|
238
|
+
to="lamindb.branch",
|
239
|
+
),
|
240
|
+
),
|
241
|
+
migrations.AlterField(
|
242
|
+
model_name="reference",
|
243
|
+
name="space",
|
244
|
+
field=lamindb.base.fields.ForeignKey(
|
245
|
+
blank=True,
|
246
|
+
db_default=1,
|
247
|
+
default=1,
|
248
|
+
on_delete=django.db.models.deletion.PROTECT,
|
249
|
+
related_name="+",
|
250
|
+
to="lamindb.space",
|
251
|
+
),
|
252
|
+
),
|
253
|
+
migrations.AlterField(
|
254
|
+
model_name="run",
|
255
|
+
name="branch",
|
256
|
+
field=lamindb.base.fields.ForeignKey(
|
257
|
+
blank=True,
|
258
|
+
db_column="_branch_code",
|
259
|
+
db_default=1,
|
260
|
+
default=1,
|
261
|
+
on_delete=django.db.models.deletion.PROTECT,
|
262
|
+
related_name="+",
|
263
|
+
to="lamindb.branch",
|
264
|
+
),
|
265
|
+
),
|
266
|
+
migrations.AlterField(
|
267
|
+
model_name="run",
|
268
|
+
name="space",
|
269
|
+
field=lamindb.base.fields.ForeignKey(
|
270
|
+
blank=True,
|
271
|
+
db_default=1,
|
272
|
+
default=1,
|
273
|
+
on_delete=django.db.models.deletion.PROTECT,
|
274
|
+
related_name="+",
|
275
|
+
to="lamindb.space",
|
276
|
+
),
|
277
|
+
),
|
278
|
+
migrations.AlterField(
|
279
|
+
model_name="schema",
|
280
|
+
name="branch",
|
281
|
+
field=lamindb.base.fields.ForeignKey(
|
282
|
+
blank=True,
|
283
|
+
db_column="_branch_code",
|
284
|
+
db_default=1,
|
285
|
+
default=1,
|
286
|
+
on_delete=django.db.models.deletion.PROTECT,
|
287
|
+
related_name="+",
|
288
|
+
to="lamindb.branch",
|
289
|
+
),
|
290
|
+
),
|
291
|
+
migrations.AlterField(
|
292
|
+
model_name="schema",
|
293
|
+
name="space",
|
294
|
+
field=lamindb.base.fields.ForeignKey(
|
295
|
+
blank=True,
|
296
|
+
db_default=1,
|
297
|
+
default=1,
|
298
|
+
on_delete=django.db.models.deletion.PROTECT,
|
299
|
+
related_name="+",
|
300
|
+
to="lamindb.space",
|
301
|
+
),
|
302
|
+
),
|
303
|
+
migrations.AlterField(
|
304
|
+
model_name="sheet",
|
305
|
+
name="branch",
|
306
|
+
field=lamindb.base.fields.ForeignKey(
|
307
|
+
blank=True,
|
308
|
+
db_column="_branch_code",
|
309
|
+
db_default=1,
|
310
|
+
default=1,
|
311
|
+
on_delete=django.db.models.deletion.PROTECT,
|
312
|
+
related_name="+",
|
313
|
+
to="lamindb.branch",
|
314
|
+
),
|
315
|
+
),
|
316
|
+
migrations.AlterField(
|
317
|
+
model_name="sheet",
|
318
|
+
name="space",
|
319
|
+
field=lamindb.base.fields.ForeignKey(
|
320
|
+
blank=True,
|
321
|
+
db_default=1,
|
322
|
+
default=1,
|
323
|
+
on_delete=django.db.models.deletion.PROTECT,
|
324
|
+
related_name="+",
|
325
|
+
to="lamindb.space",
|
326
|
+
),
|
327
|
+
),
|
328
|
+
migrations.AlterField(
|
329
|
+
model_name="storage",
|
330
|
+
name="branch",
|
331
|
+
field=lamindb.base.fields.ForeignKey(
|
332
|
+
blank=True,
|
333
|
+
db_column="_branch_code",
|
334
|
+
db_default=1,
|
335
|
+
default=1,
|
336
|
+
on_delete=django.db.models.deletion.PROTECT,
|
337
|
+
related_name="+",
|
338
|
+
to="lamindb.branch",
|
339
|
+
),
|
340
|
+
),
|
341
|
+
migrations.AlterField(
|
342
|
+
model_name="storage",
|
343
|
+
name="space",
|
344
|
+
field=lamindb.base.fields.ForeignKey(
|
345
|
+
blank=True,
|
346
|
+
db_default=1,
|
347
|
+
default=1,
|
348
|
+
on_delete=django.db.models.deletion.PROTECT,
|
349
|
+
related_name="+",
|
350
|
+
to="lamindb.space",
|
351
|
+
),
|
352
|
+
),
|
353
|
+
migrations.AlterField(
|
354
|
+
model_name="transform",
|
355
|
+
name="branch",
|
356
|
+
field=lamindb.base.fields.ForeignKey(
|
357
|
+
blank=True,
|
358
|
+
db_column="_branch_code",
|
359
|
+
db_default=1,
|
360
|
+
default=1,
|
361
|
+
on_delete=django.db.models.deletion.PROTECT,
|
362
|
+
related_name="+",
|
363
|
+
to="lamindb.branch",
|
364
|
+
),
|
365
|
+
),
|
366
|
+
migrations.AlterField(
|
367
|
+
model_name="transform",
|
368
|
+
name="space",
|
369
|
+
field=lamindb.base.fields.ForeignKey(
|
370
|
+
blank=True,
|
371
|
+
db_default=1,
|
372
|
+
default=1,
|
373
|
+
on_delete=django.db.models.deletion.PROTECT,
|
374
|
+
related_name="+",
|
375
|
+
to="lamindb.space",
|
376
|
+
),
|
377
|
+
),
|
378
|
+
migrations.AlterField(
|
379
|
+
model_name="ulabel",
|
380
|
+
name="branch",
|
381
|
+
field=lamindb.base.fields.ForeignKey(
|
382
|
+
blank=True,
|
383
|
+
db_column="_branch_code",
|
384
|
+
db_default=1,
|
385
|
+
default=1,
|
386
|
+
on_delete=django.db.models.deletion.PROTECT,
|
387
|
+
related_name="+",
|
388
|
+
to="lamindb.branch",
|
389
|
+
),
|
390
|
+
),
|
391
|
+
migrations.AlterField(
|
392
|
+
model_name="ulabel",
|
393
|
+
name="space",
|
394
|
+
field=lamindb.base.fields.ForeignKey(
|
395
|
+
blank=True,
|
396
|
+
db_default=1,
|
397
|
+
default=1,
|
398
|
+
on_delete=django.db.models.deletion.PROTECT,
|
399
|
+
related_name="+",
|
400
|
+
to="lamindb.space",
|
401
|
+
),
|
402
|
+
),
|
403
|
+
]
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# Generated by Django 5.2 on 2025-
|
1
|
+
# Generated by Django 5.2 on 2025-06-03 09:49
|
2
2
|
|
3
3
|
import django.core.validators
|
4
4
|
import django.db.models.deletion
|
@@ -124,6 +124,7 @@ class Migration(migrations.Migration):
|
|
124
124
|
("lamindb", "0101_alter_artifact_hash_alter_feature_name_and_more"),
|
125
125
|
("lamindb", "0102_remove_writelog_branch_code_and_more"),
|
126
126
|
("lamindb", "0103_remove_writelog_migration_state_and_more"),
|
127
|
+
("lamindb", "0104_alter_branch_uid"),
|
127
128
|
]
|
128
129
|
|
129
130
|
dependencies = [] # type: ignore
|
@@ -169,9 +170,8 @@ class Migration(migrations.Migration):
|
|
169
170
|
"uid",
|
170
171
|
lamindb.base.fields.CharField(
|
171
172
|
blank=True,
|
172
|
-
db_default="M",
|
173
173
|
db_index=True,
|
174
|
-
default=
|
174
|
+
default=lamindb.base.uids.base62_12,
|
175
175
|
editable=False,
|
176
176
|
max_length=12,
|
177
177
|
unique=True,
|
@@ -476,6 +476,7 @@ class Migration(migrations.Migration):
|
|
476
476
|
db_default=1,
|
477
477
|
default=1,
|
478
478
|
on_delete=django.db.models.deletion.PROTECT,
|
479
|
+
related_name="+",
|
479
480
|
to="lamindb.branch",
|
480
481
|
),
|
481
482
|
),
|
@@ -594,6 +595,7 @@ class Migration(migrations.Migration):
|
|
594
595
|
db_default=1,
|
595
596
|
default=1,
|
596
597
|
on_delete=django.db.models.deletion.PROTECT,
|
598
|
+
related_name="+",
|
597
599
|
to="lamindb.branch",
|
598
600
|
),
|
599
601
|
),
|
@@ -822,6 +824,7 @@ class Migration(migrations.Migration):
|
|
822
824
|
db_default=1,
|
823
825
|
default=1,
|
824
826
|
on_delete=django.db.models.deletion.PROTECT,
|
827
|
+
related_name="+",
|
825
828
|
to="lamindb.branch",
|
826
829
|
),
|
827
830
|
),
|
@@ -1008,6 +1011,7 @@ class Migration(migrations.Migration):
|
|
1008
1011
|
db_default=1,
|
1009
1012
|
default=1,
|
1010
1013
|
on_delete=django.db.models.deletion.PROTECT,
|
1014
|
+
related_name="+",
|
1011
1015
|
to="lamindb.branch",
|
1012
1016
|
),
|
1013
1017
|
),
|
@@ -1136,6 +1140,7 @@ class Migration(migrations.Migration):
|
|
1136
1140
|
db_default=1,
|
1137
1141
|
default=1,
|
1138
1142
|
on_delete=django.db.models.deletion.PROTECT,
|
1143
|
+
related_name="+",
|
1139
1144
|
to="lamindb.branch",
|
1140
1145
|
),
|
1141
1146
|
),
|
@@ -1272,6 +1277,7 @@ class Migration(migrations.Migration):
|
|
1272
1277
|
db_default=1,
|
1273
1278
|
default=1,
|
1274
1279
|
on_delete=django.db.models.deletion.PROTECT,
|
1280
|
+
related_name="+",
|
1275
1281
|
to="lamindb.branch",
|
1276
1282
|
),
|
1277
1283
|
),
|
@@ -1440,6 +1446,7 @@ class Migration(migrations.Migration):
|
|
1440
1446
|
db_default=1,
|
1441
1447
|
default=1,
|
1442
1448
|
on_delete=django.db.models.deletion.PROTECT,
|
1449
|
+
related_name="+",
|
1443
1450
|
to="lamindb.branch",
|
1444
1451
|
),
|
1445
1452
|
),
|
@@ -1569,6 +1576,7 @@ class Migration(migrations.Migration):
|
|
1569
1576
|
db_default=1,
|
1570
1577
|
default=1,
|
1571
1578
|
on_delete=django.db.models.deletion.PROTECT,
|
1579
|
+
related_name="+",
|
1572
1580
|
to="lamindb.branch",
|
1573
1581
|
),
|
1574
1582
|
),
|
@@ -1606,6 +1614,7 @@ class Migration(migrations.Migration):
|
|
1606
1614
|
db_default=1,
|
1607
1615
|
default=1,
|
1608
1616
|
on_delete=django.db.models.deletion.PROTECT,
|
1617
|
+
related_name="+",
|
1609
1618
|
to="lamindb.space",
|
1610
1619
|
),
|
1611
1620
|
),
|
@@ -1748,6 +1757,7 @@ class Migration(migrations.Migration):
|
|
1748
1757
|
db_default=1,
|
1749
1758
|
default=1,
|
1750
1759
|
on_delete=django.db.models.deletion.PROTECT,
|
1760
|
+
related_name="+",
|
1751
1761
|
to="lamindb.branch",
|
1752
1762
|
),
|
1753
1763
|
),
|
@@ -1903,6 +1913,7 @@ class Migration(migrations.Migration):
|
|
1903
1913
|
db_default=1,
|
1904
1914
|
default=1,
|
1905
1915
|
on_delete=django.db.models.deletion.PROTECT,
|
1916
|
+
related_name="+",
|
1906
1917
|
to="lamindb.branch",
|
1907
1918
|
),
|
1908
1919
|
),
|
@@ -2465,6 +2476,7 @@ class Migration(migrations.Migration):
|
|
2465
2476
|
db_default=1,
|
2466
2477
|
default=1,
|
2467
2478
|
on_delete=django.db.models.deletion.PROTECT,
|
2479
|
+
related_name="+",
|
2468
2480
|
to="lamindb.branch",
|
2469
2481
|
),
|
2470
2482
|
),
|
@@ -2854,6 +2866,7 @@ class Migration(migrations.Migration):
|
|
2854
2866
|
db_default=1,
|
2855
2867
|
default=1,
|
2856
2868
|
on_delete=django.db.models.deletion.PROTECT,
|
2869
|
+
related_name="+",
|
2857
2870
|
to="lamindb.branch",
|
2858
2871
|
),
|
2859
2872
|
),
|
@@ -2885,6 +2898,7 @@ class Migration(migrations.Migration):
|
|
2885
2898
|
db_default=1,
|
2886
2899
|
default=1,
|
2887
2900
|
on_delete=django.db.models.deletion.PROTECT,
|
2901
|
+
related_name="+",
|
2888
2902
|
to="lamindb.space",
|
2889
2903
|
),
|
2890
2904
|
),
|
@@ -2991,6 +3005,7 @@ class Migration(migrations.Migration):
|
|
2991
3005
|
db_default=1,
|
2992
3006
|
default=1,
|
2993
3007
|
on_delete=django.db.models.deletion.PROTECT,
|
3008
|
+
related_name="+",
|
2994
3009
|
to="lamindb.space",
|
2995
3010
|
),
|
2996
3011
|
),
|
@@ -3002,6 +3017,7 @@ class Migration(migrations.Migration):
|
|
3002
3017
|
db_default=1,
|
3003
3018
|
default=1,
|
3004
3019
|
on_delete=django.db.models.deletion.PROTECT,
|
3020
|
+
related_name="+",
|
3005
3021
|
to="lamindb.space",
|
3006
3022
|
),
|
3007
3023
|
),
|
@@ -3013,6 +3029,7 @@ class Migration(migrations.Migration):
|
|
3013
3029
|
db_default=1,
|
3014
3030
|
default=1,
|
3015
3031
|
on_delete=django.db.models.deletion.PROTECT,
|
3032
|
+
related_name="+",
|
3016
3033
|
to="lamindb.space",
|
3017
3034
|
),
|
3018
3035
|
),
|
@@ -3024,6 +3041,7 @@ class Migration(migrations.Migration):
|
|
3024
3041
|
db_default=1,
|
3025
3042
|
default=1,
|
3026
3043
|
on_delete=django.db.models.deletion.PROTECT,
|
3044
|
+
related_name="+",
|
3027
3045
|
to="lamindb.space",
|
3028
3046
|
),
|
3029
3047
|
),
|
@@ -3035,6 +3053,7 @@ class Migration(migrations.Migration):
|
|
3035
3053
|
db_default=1,
|
3036
3054
|
default=1,
|
3037
3055
|
on_delete=django.db.models.deletion.PROTECT,
|
3056
|
+
related_name="+",
|
3038
3057
|
to="lamindb.space",
|
3039
3058
|
),
|
3040
3059
|
),
|
@@ -3046,6 +3065,7 @@ class Migration(migrations.Migration):
|
|
3046
3065
|
db_default=1,
|
3047
3066
|
default=1,
|
3048
3067
|
on_delete=django.db.models.deletion.PROTECT,
|
3068
|
+
related_name="+",
|
3049
3069
|
to="lamindb.space",
|
3050
3070
|
),
|
3051
3071
|
),
|
@@ -3057,6 +3077,7 @@ class Migration(migrations.Migration):
|
|
3057
3077
|
db_default=1,
|
3058
3078
|
default=1,
|
3059
3079
|
on_delete=django.db.models.deletion.PROTECT,
|
3080
|
+
related_name="+",
|
3060
3081
|
to="lamindb.space",
|
3061
3082
|
),
|
3062
3083
|
),
|
@@ -3068,6 +3089,7 @@ class Migration(migrations.Migration):
|
|
3068
3089
|
db_default=1,
|
3069
3090
|
default=1,
|
3070
3091
|
on_delete=django.db.models.deletion.PROTECT,
|
3092
|
+
related_name="+",
|
3071
3093
|
to="lamindb.space",
|
3072
3094
|
),
|
3073
3095
|
),
|
@@ -3079,6 +3101,7 @@ class Migration(migrations.Migration):
|
|
3079
3101
|
db_default=1,
|
3080
3102
|
default=1,
|
3081
3103
|
on_delete=django.db.models.deletion.PROTECT,
|
3104
|
+
related_name="+",
|
3082
3105
|
to="lamindb.space",
|
3083
3106
|
),
|
3084
3107
|
),
|
@@ -3090,6 +3113,7 @@ class Migration(migrations.Migration):
|
|
3090
3113
|
db_default=1,
|
3091
3114
|
default=1,
|
3092
3115
|
on_delete=django.db.models.deletion.PROTECT,
|
3116
|
+
related_name="+",
|
3093
3117
|
to="lamindb.space",
|
3094
3118
|
),
|
3095
3119
|
),
|
@@ -3186,6 +3210,7 @@ class Migration(migrations.Migration):
|
|
3186
3210
|
db_default=1,
|
3187
3211
|
default=1,
|
3188
3212
|
on_delete=django.db.models.deletion.PROTECT,
|
3213
|
+
related_name="+",
|
3189
3214
|
to="lamindb.branch",
|
3190
3215
|
),
|
3191
3216
|
),
|
@@ -3207,6 +3232,7 @@ class Migration(migrations.Migration):
|
|
3207
3232
|
db_default=1,
|
3208
3233
|
default=1,
|
3209
3234
|
on_delete=django.db.models.deletion.PROTECT,
|
3235
|
+
related_name="+",
|
3210
3236
|
to="lamindb.space",
|
3211
3237
|
),
|
3212
3238
|
),
|
@@ -3371,6 +3397,7 @@ class Migration(migrations.Migration):
|
|
3371
3397
|
db_default=1,
|
3372
3398
|
default=1,
|
3373
3399
|
on_delete=django.db.models.deletion.PROTECT,
|
3400
|
+
related_name="+",
|
3374
3401
|
to="lamindb.branch",
|
3375
3402
|
),
|
3376
3403
|
),
|
@@ -3387,6 +3414,7 @@ class Migration(migrations.Migration):
|
|
3387
3414
|
db_default=1,
|
3388
3415
|
default=1,
|
3389
3416
|
on_delete=django.db.models.deletion.PROTECT,
|
3417
|
+
related_name="+",
|
3390
3418
|
to="lamindb.space",
|
3391
3419
|
),
|
3392
3420
|
),
|
@@ -3630,6 +3658,7 @@ class Migration(migrations.Migration):
|
|
3630
3658
|
db_default=1,
|
3631
3659
|
default=1,
|
3632
3660
|
on_delete=django.db.models.deletion.PROTECT,
|
3661
|
+
related_name="+",
|
3633
3662
|
to="lamindb.branch",
|
3634
3663
|
),
|
3635
3664
|
),
|
@@ -3657,6 +3686,7 @@ class Migration(migrations.Migration):
|
|
3657
3686
|
db_default=1,
|
3658
3687
|
default=1,
|
3659
3688
|
on_delete=django.db.models.deletion.PROTECT,
|
3689
|
+
related_name="+",
|
3660
3690
|
to="lamindb.space",
|
3661
3691
|
),
|
3662
3692
|
),
|
@@ -624,7 +624,10 @@ def filter_base(cls, _skip_validation: bool = True, **expression) -> QuerySet:
|
|
624
624
|
if len(split_key) == 2:
|
625
625
|
comparator = f"__{split_key[1]}"
|
626
626
|
feature = features.get(name=normalized_key)
|
627
|
-
|
627
|
+
# non-categorical features
|
628
|
+
if not feature.dtype.startswith("cat") and not feature.dtype.startswith(
|
629
|
+
"list[cat"
|
630
|
+
):
|
628
631
|
if comparator == "__isnull":
|
629
632
|
if cls == FeatureManagerArtifact:
|
630
633
|
from .artifact import ArtifactFeatureValue
|
@@ -653,6 +656,7 @@ def filter_base(cls, _skip_validation: bool = True, **expression) -> QuerySet:
|
|
653
656
|
expression = {feature_param: feature, f"value{comparator}": value}
|
654
657
|
feature_values = value_model.filter(**expression)
|
655
658
|
new_expression[f"_{feature_param}_values__id__in"] = feature_values
|
659
|
+
# categorical features
|
656
660
|
elif isinstance(value, (str, SQLRecord, bool)):
|
657
661
|
if comparator == "__isnull":
|
658
662
|
if cls == FeatureManagerArtifact:
|
@@ -670,22 +674,22 @@ def filter_base(cls, _skip_validation: bool = True, **expression) -> QuerySet:
|
|
670
674
|
# we distinguish cases in which we have multiple label matches vs. one
|
671
675
|
label = None
|
672
676
|
labels = None
|
677
|
+
result = parse_dtype(feature.dtype)[0]
|
678
|
+
label_registry = result["registry"]
|
673
679
|
if isinstance(value, str):
|
680
|
+
field_name = result["field"].field.name
|
674
681
|
# we need the comparator here because users might query like so
|
675
682
|
# ln.Artifact.filter(experiment__contains="Experi")
|
676
|
-
expression = {f"
|
677
|
-
labels =
|
683
|
+
expression = {f"{field_name}{comparator}": value}
|
684
|
+
labels = result["registry"].filter(**expression).all()
|
678
685
|
if len(labels) == 0:
|
679
686
|
raise DoesNotExist(
|
680
|
-
f"Did not find a
|
687
|
+
f"Did not find a {label_registry.__name__} matching `{field_name}{comparator}={value}`"
|
681
688
|
)
|
682
689
|
elif len(labels) == 1:
|
683
690
|
label = labels[0]
|
684
691
|
elif isinstance(value, SQLRecord):
|
685
692
|
label = value
|
686
|
-
label_registry = (
|
687
|
-
label.__class__ if label is not None else labels[0].__class__
|
688
|
-
)
|
689
693
|
accessor_name = (
|
690
694
|
label_registry.artifacts.through.artifact.field._related_name
|
691
695
|
)
|
lamindb/models/collection.py
CHANGED
@@ -129,9 +129,7 @@ def _load_concat_artifacts(
|
|
129
129
|
|
130
130
|
|
131
131
|
class Collection(SQLRecord, IsVersioned, TracksRun, TracksUpdates):
|
132
|
-
"""
|
133
|
-
|
134
|
-
Collections provide a simple way of versioning collections of artifacts.
|
132
|
+
"""Versioned collections of artifacts.
|
135
133
|
|
136
134
|
Args:
|
137
135
|
artifacts: `list[Artifact]` A list of artifacts.
|
lamindb/models/project.py
CHANGED
@@ -191,14 +191,18 @@ class Reference(SQLRecord, CanCurate, TracksRun, TracksUpdates, ValidateFields):
|
|
191
191
|
|
192
192
|
|
193
193
|
class Project(SQLRecord, CanCurate, TracksRun, TracksUpdates, ValidateFields):
|
194
|
-
"""Projects.
|
194
|
+
"""Projects to label artifacts, transforms, and runs.
|
195
|
+
|
196
|
+
Example::
|
197
|
+
|
198
|
+
project = Project(
|
199
|
+
name="My Project Name",
|
200
|
+
abbr="MPN",
|
201
|
+
url="https://example.com/my_project",
|
202
|
+
).save()
|
203
|
+
artifact.projects.add(project) # <-- labels the artifact with the project
|
204
|
+
ln.track(project=project) # <-- automtically labels entities during the run
|
195
205
|
|
196
|
-
Example:
|
197
|
-
>>> project = Project(
|
198
|
-
... name="My Project Name",
|
199
|
-
... abbr="MPN",
|
200
|
-
... url="https://example.com/my_project",
|
201
|
-
... ).save()
|
202
206
|
"""
|
203
207
|
|
204
208
|
class Meta(SQLRecord.Meta, TracksRun.Meta, TracksUpdates.Meta):
|
lamindb/models/record.py
CHANGED
@@ -31,6 +31,9 @@ class Record(SQLRecord, CanCurate, TracksRun, TracksUpdates):
|
|
31
31
|
|
32
32
|
This is currently more convenient to use through the UI.
|
33
33
|
|
34
|
+
A `Record` has a flexible schema: it can store data for arbitrary features.
|
35
|
+
Changing the fields of a :class:`~lamindb.models.SQLRecord`, you need to modify the columns of the underlying table in the database.
|
36
|
+
|
34
37
|
Args:
|
35
38
|
name: `str` A name.
|
36
39
|
description: `str` A description.
|
@@ -169,6 +172,48 @@ class Sheet(SQLRecord, TracksRun, TracksUpdates):
|
|
169
172
|
projects: Project
|
170
173
|
"""Linked projects."""
|
171
174
|
|
175
|
+
@overload
|
176
|
+
def __init__(
|
177
|
+
self,
|
178
|
+
name: str,
|
179
|
+
schema: Schema | None = None,
|
180
|
+
description: str | None = None,
|
181
|
+
): ...
|
182
|
+
|
183
|
+
@overload
|
184
|
+
def __init__(
|
185
|
+
self,
|
186
|
+
*db_args,
|
187
|
+
): ...
|
188
|
+
|
189
|
+
def __init__(
|
190
|
+
self,
|
191
|
+
*args,
|
192
|
+
**kwargs,
|
193
|
+
):
|
194
|
+
if len(args) == len(self._meta.concrete_fields):
|
195
|
+
super().__init__(*args, **kwargs)
|
196
|
+
return None
|
197
|
+
if len(args) > 0:
|
198
|
+
raise ValueError("Only one non-keyword arg allowed")
|
199
|
+
name: str = kwargs.pop("name", None)
|
200
|
+
schema: Schema | None = kwargs.pop("schema", None)
|
201
|
+
description: str | None = kwargs.pop("description", None)
|
202
|
+
_skip_validation = kwargs.pop("_skip_validation", True)
|
203
|
+
_aux = kwargs.pop("_aux", None)
|
204
|
+
if len(kwargs) > 0:
|
205
|
+
valid_keywords = ", ".join([val[0] for val in _get_record_kwargs(Record)])
|
206
|
+
raise FieldValidationError(
|
207
|
+
f"Only {valid_keywords} are valid keyword arguments"
|
208
|
+
)
|
209
|
+
super().__init__(
|
210
|
+
name=name,
|
211
|
+
schema=schema,
|
212
|
+
description=description,
|
213
|
+
_skip_validation=_skip_validation,
|
214
|
+
_aux=_aux,
|
215
|
+
)
|
216
|
+
|
172
217
|
|
173
218
|
class RecordJson(BaseSQLRecord, IsLink):
|
174
219
|
id: int = models.BigAutoField(primary_key=True)
|
lamindb/models/run.py
CHANGED
@@ -139,8 +139,10 @@ class TracksUpdates(models.Model):
|
|
139
139
|
class User(BaseSQLRecord, CanCurate):
|
140
140
|
"""Users.
|
141
141
|
|
142
|
-
|
143
|
-
|
142
|
+
Every :class:`~lamindb.models.SQLRecord` has a `created_by` field that links to the creating user.
|
143
|
+
|
144
|
+
All data in this registry is synchronized from LaminHub to ensure a universal
|
145
|
+
user identity.
|
144
146
|
|
145
147
|
Examples:
|
146
148
|
|
lamindb/models/sqlrecord.py
CHANGED
@@ -49,6 +49,7 @@ from ..base.fields import (
|
|
49
49
|
ForeignKey,
|
50
50
|
JSONField,
|
51
51
|
)
|
52
|
+
from ..base.ids import base62_12
|
52
53
|
from ..base.types import FieldAttr, StrField
|
53
54
|
from ..errors import (
|
54
55
|
FieldValidationError,
|
@@ -654,17 +655,23 @@ class BaseSQLRecord(models.Model, metaclass=Registry):
|
|
654
655
|
def __init__(self, *args, **kwargs):
|
655
656
|
skip_validation = kwargs.pop("_skip_validation", False)
|
656
657
|
if not args:
|
657
|
-
if
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
):
|
658
|
+
if self.__class__.__name__ in {
|
659
|
+
"Artifact",
|
660
|
+
"Collection",
|
661
|
+
"Transform",
|
662
|
+
"Run",
|
663
|
+
}:
|
664
664
|
from lamindb import context as run_context
|
665
665
|
|
666
666
|
if run_context.space is not None:
|
667
667
|
kwargs["space"] = run_context.space
|
668
|
+
if issubclass(
|
669
|
+
self.__class__, SQLRecord
|
670
|
+
) and self.__class__.__name__ not in {"Storage", "Source"}:
|
671
|
+
from lamindb import context as run_context
|
672
|
+
|
673
|
+
if run_context.branch is not None:
|
674
|
+
kwargs["branch"] = run_context.branch
|
668
675
|
if skip_validation:
|
669
676
|
super().__init__(**kwargs)
|
670
677
|
else:
|
@@ -887,12 +894,11 @@ class BaseSQLRecord(models.Model, metaclass=Registry):
|
|
887
894
|
|
888
895
|
|
889
896
|
class Space(BaseSQLRecord):
|
890
|
-
"""
|
897
|
+
"""Workspaces with managed access for specific users or teams.
|
891
898
|
|
892
|
-
|
899
|
+
Guide: :doc:`docs:access`.
|
893
900
|
|
894
|
-
All data in this registry is
|
895
|
-
There is no need to manually create records.
|
901
|
+
All data in this registry is synchronized from LaminHub so that spaces can be shared and reused across multiple LaminDB instances.
|
896
902
|
"""
|
897
903
|
|
898
904
|
id: int = models.SmallAutoField(primary_key=True)
|
@@ -941,7 +947,21 @@ class Space(BaseSQLRecord):
|
|
941
947
|
|
942
948
|
|
943
949
|
class Branch(BaseSQLRecord):
|
944
|
-
"""Branches
|
950
|
+
"""Branches for change management with archive and trash states.
|
951
|
+
|
952
|
+
Every `SQLRecord` has a `branch` field, which dictates where a record appears in queries & searches.
|
953
|
+
"""
|
954
|
+
|
955
|
+
# below isn't fully implemented but a roadmap
|
956
|
+
# - 3: template (hidden in queries & searches)
|
957
|
+
# - 2: locked (same as default, but locked for edits except for space admins)
|
958
|
+
# - 1: default (visible in queries & searches)
|
959
|
+
# - 0: archive (hidden, meant to be kept, locked for edits for everyone)
|
960
|
+
# - -1: trash (hidden, scheduled for deletion)
|
961
|
+
|
962
|
+
# An integer higher than >3 codes a branch that can be used for collaborators to create drafts
|
963
|
+
# that can be merged onto the main branch in an experience akin to a Pull Request. The mapping
|
964
|
+
# onto a semantic branch name is handled through LaminHub.
|
945
965
|
|
946
966
|
id: int = models.AutoField(primary_key=True)
|
947
967
|
"""An integer id that's synchronized for a family of coupled database instances.
|
@@ -954,8 +974,7 @@ class Branch(BaseSQLRecord):
|
|
954
974
|
editable=False,
|
955
975
|
unique=True,
|
956
976
|
max_length=12,
|
957
|
-
default=
|
958
|
-
db_default="M",
|
977
|
+
default=base62_12,
|
959
978
|
db_index=True,
|
960
979
|
)
|
961
980
|
"""Universal id.
|
@@ -1013,33 +1032,16 @@ class SQLRecord(BaseSQLRecord, metaclass=Registry):
|
|
1013
1032
|
machine learning or biological models.
|
1014
1033
|
"""
|
1015
1034
|
|
1016
|
-
branch:
|
1017
|
-
Branch,
|
1035
|
+
branch: Branch = ForeignKey(
|
1036
|
+
Branch,
|
1037
|
+
PROTECT,
|
1038
|
+
default=1,
|
1039
|
+
db_default=1,
|
1040
|
+
db_column="_branch_code",
|
1041
|
+
related_name="+",
|
1018
1042
|
)
|
1019
|
-
"""Whether record is on a branch or in another "special state".
|
1020
|
-
|
1021
|
-
This dictates where a record appears in exploration, queries & searches,
|
1022
|
-
whether a record can be edited, and whether a record acts as a template.
|
1023
|
-
|
1024
|
-
Branch name coding is handled through LaminHub. "Special state" coding is as defined below.
|
1025
|
-
|
1026
|
-
One should note that there is no "main" branch as in git, but that all five special codes
|
1027
|
-
(-1, 0, 1, 2, 3) act as sub-specfications for what git would call the main branch. This also
|
1028
|
-
means that for records that live on a branch only the "default state" exists. E.g., one can only
|
1029
|
-
turn a record into a template, lock it, archive it, or trash it once it's merged onto the main
|
1030
|
-
branch.
|
1031
|
-
|
1032
|
-
- 3: template (hidden in queries & searches)
|
1033
|
-
- 2: locked (same as default, but locked for edits except for space admins)
|
1034
|
-
- 1: default (visible in queries & searches)
|
1035
|
-
- 0: archive (hidden, meant to be kept, locked for edits for everyone)
|
1036
|
-
- -1: trash (hidden, scheduled for deletion)
|
1037
|
-
|
1038
|
-
An integer higher than >3 codes a branch that can be used for collaborators to create drafts
|
1039
|
-
that can be merged onto the main branch in an experience akin to a Pull Request. The mapping
|
1040
|
-
onto a semantic branch name is handled through LaminHub.
|
1041
|
-
"""
|
1042
|
-
space: Space = ForeignKey(Space, PROTECT, default=1, db_default=1)
|
1043
|
+
"""Whether record is on a branch or in another "special state"."""
|
1044
|
+
space: Space = ForeignKey(Space, PROTECT, default=1, db_default=1, related_name="+")
|
1043
1045
|
"""The space in which the record lives."""
|
1044
1046
|
_aux: dict[str, Any] | None = JSONField(default=None, db_default=None, null=True)
|
1045
1047
|
"""Auxiliary field for dictionary-like metadata."""
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: lamindb
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.6.1
|
4
4
|
Summary: A data framework for biology.
|
5
5
|
Author-email: Lamin Labs <open-source@lamin.ai>
|
6
6
|
Requires-Python: >=3.10,<3.14
|
@@ -10,7 +10,7 @@ Classifier: Programming Language :: Python :: 3.11
|
|
10
10
|
Classifier: Programming Language :: Python :: 3.12
|
11
11
|
Classifier: Programming Language :: Python :: 3.13
|
12
12
|
Requires-Dist: lamin_utils==0.14.0
|
13
|
-
Requires-Dist: lamin_cli==1.4.
|
13
|
+
Requires-Dist: lamin_cli==1.4.2
|
14
14
|
Requires-Dist: lamindb_setup[aws]==1.6.0
|
15
15
|
Requires-Dist: pyyaml
|
16
16
|
Requires-Dist: pyarrow
|
@@ -23,7 +23,7 @@ Requires-Dist: anndata>=0.8.0,<=0.11.4
|
|
23
23
|
Requires-Dist: fsspec
|
24
24
|
Requires-Dist: graphviz
|
25
25
|
Requires-Dist: psycopg2-binary
|
26
|
-
Requires-Dist: bionty>=1.
|
26
|
+
Requires-Dist: bionty>=1.5.0 ; extra == "bionty"
|
27
27
|
Requires-Dist: clinicore ; extra == "clinicore"
|
28
28
|
Requires-Dist: tomlkit ; extra == "dev"
|
29
29
|
Requires-Dist: line_profiler ; extra == "dev"
|
@@ -36,6 +36,7 @@ Requires-Dist: pytest-cov ; extra == "dev"
|
|
36
36
|
Requires-Dist: mudata ; extra == "dev"
|
37
37
|
Requires-Dist: nbproject_test>=0.6.0 ; extra == "dev"
|
38
38
|
Requires-Dist: faker-biology ; extra == "dev"
|
39
|
+
Requires-Dist: pronto ; extra == "dev"
|
39
40
|
Requires-Dist: readfcs>=2.0.1 ; extra == "fcs"
|
40
41
|
Requires-Dist: lamindb_setup[gcp] ; extra == "gcp"
|
41
42
|
Requires-Dist: nbproject==0.11.1 ; extra == "jupyter"
|
@@ -43,7 +44,7 @@ Requires-Dist: jupytext ; extra == "jupyter"
|
|
43
44
|
Requires-Dist: nbconvert>=7.2.1 ; extra == "jupyter"
|
44
45
|
Requires-Dist: mistune!=3.1.0 ; extra == "jupyter"
|
45
46
|
Requires-Dist: omop ; extra == "omop"
|
46
|
-
Requires-Dist: wetlab>=1.
|
47
|
+
Requires-Dist: wetlab>=1.3.1 ; extra == "wetlab"
|
47
48
|
Requires-Dist: numcodecs<0.16.0 ; extra == "zarr"
|
48
49
|
Requires-Dist: zarr>=2.16.0,<3.0.0a0 ; extra == "zarr"
|
49
50
|
Project-URL: Home, https://github.com/laminlabs/lamindb
|
@@ -1,4 +1,4 @@
|
|
1
|
-
lamindb/__init__.py,sha256=
|
1
|
+
lamindb/__init__.py,sha256=Vfp0ESD0n9EQHFmC708KHlCcMUcM0suzVEvIC1sqPM0,2928
|
2
2
|
lamindb/_finish.py,sha256=XVEaFQQDeGvAnW3Fx-COcXCSXAvu-bIS3VkmqBS81Gs,20148
|
3
3
|
lamindb/_tracked.py,sha256=-wK7BJv30nf4v2_nH5qDCyxHvug7ih6duQNGxDrj3UE,4447
|
4
4
|
lamindb/_view.py,sha256=cod1RnZoLyzMVJcjWjytg78Sf4qsR8IAdqpwzsi8FTw,4950
|
@@ -11,7 +11,7 @@ lamindb/base/uids.py,sha256=cLBi5mIlsf1ltkTb17r1FLzlOjlGmjvsCygoVJHQ-A8,2116
|
|
11
11
|
lamindb/base/users.py,sha256=8MSmAvCKoUF15YsDE6BGLBXsFWpfoEEg8iDTKZ7kD48,848
|
12
12
|
lamindb/core/__init__.py,sha256=aaBq0UVjNolMynbT1V5hB6UrJm1tK0M6WHu_r6em9_4,604
|
13
13
|
lamindb/core/_compat.py,sha256=NLnKk1qk4xdgMV-QwFDnBnbio02ujjlF86icvhpdv4c,2029
|
14
|
-
lamindb/core/_context.py,sha256=
|
14
|
+
lamindb/core/_context.py,sha256=bmQJPd2UnOQdPkWWMLnG_sZTfXPLuZyXEi3UFmttoYU,36812
|
15
15
|
lamindb/core/_mapped_collection.py,sha256=dxyZ1ZHFn5SBl1xILqN9N6TTUJP0PptVBV-2O0EdZww,25751
|
16
16
|
lamindb/core/_settings.py,sha256=I_h_O06BNlzhHkMiJqDlRhfbRwCWdMDjKdalNIfIZT0,6214
|
17
17
|
lamindb/core/_sync_git.py,sha256=Z7keuyS5X7CAj285sEbZIFExZF9mtjGH8DzKwz3xhHw,5881
|
@@ -23,7 +23,7 @@ lamindb/core/datasets/__init__.py,sha256=x5zn_vn8D4xMJOJ9hVc8wRwQk5ea81Un2tGHb2U
|
|
23
23
|
lamindb/core/datasets/_core.py,sha256=uaP0snoKuAE5nDTL_XIgPeEoXSp5sTrNNAyOPDciZRU,20286
|
24
24
|
lamindb/core/datasets/_fake.py,sha256=BZF9R_1iF0HDnvtZNqL2FtsjSMuqDIfuFxnw_LJYIh4,953
|
25
25
|
lamindb/core/datasets/_small.py,sha256=HBzyTporAl-6Cr4DbDDEtzbU2ILKNxxiRM-GeZofqsw,2290
|
26
|
-
lamindb/core/datasets/mini_immuno.py,sha256=
|
26
|
+
lamindb/core/datasets/mini_immuno.py,sha256=eAtRQ3_4cln5IFzTH0jNufbWcyQKrXmzizbSmvfS-FM,5707
|
27
27
|
lamindb/core/storage/__init__.py,sha256=JOIMu_7unbyhndtH1j0Q-9AvY8knSuc1IJO9sQnyBAQ,498
|
28
28
|
lamindb/core/storage/_anndata_accessor.py,sha256=j7PgAxKL7bumvHja99Ldm6BtWkdGMu2Dh_sYoXocTeQ,26105
|
29
29
|
lamindb/core/storage/_backed_access.py,sha256=LlpRDZ0skseZA5tBFu3-cH1wJwuXm7-NS2RgnTK7wgc,7382
|
@@ -39,7 +39,7 @@ lamindb/core/subsettings/_annotation_settings.py,sha256=o-yTYw-NmjFmtehbKU8qnf7t
|
|
39
39
|
lamindb/core/subsettings/_creation_settings.py,sha256=NGHWKqCFSzVNBxAr2VnmdYguiFdW29XUK7T9wRsVshg,906
|
40
40
|
lamindb/curators/__init__.py,sha256=rv5Xrhv0jS1NMpuRVUHEMAsu6pXhBdDP8PBlO4FXrsE,662
|
41
41
|
lamindb/curators/_legacy.py,sha256=p0jn3VcH-yrCGreKtmbntiJcgxXSOo7KDbP-jgynxyo,76238
|
42
|
-
lamindb/curators/core.py,sha256=
|
42
|
+
lamindb/curators/core.py,sha256=YjKWeCiH90QI6Rzntj39i8iiXP3V01ouvQFLIoUCn2I,66827
|
43
43
|
lamindb/curators/_cellxgene_schemas/__init__.py,sha256=iw6PrzhBQpAR7aQ4_MXopSAVX2hdderHH3LRWeQy7Hk,7511
|
44
44
|
lamindb/curators/_cellxgene_schemas/schema_versions.csv,sha256=X9rmO88TW1Fht1f5mJs0JdW-VPvyKSajpf8lHNeECj4,1680
|
45
45
|
lamindb/examples/__init__.py,sha256=DGImiuWYDvwxh78p5FCwQWClEwsE3ODLU49i_NqbW0c,533
|
@@ -80,15 +80,16 @@ lamindb/migrations/0097_remove_schemaparam_param_remove_paramvalue_param_and_mor
|
|
80
80
|
lamindb/migrations/0098_alter_feature_type_alter_project_type_and_more.py,sha256=wy3CZNwE6mVG65AmAUyE-AIjcTQjHLv8jgFDUJCh9h0,23626
|
81
81
|
lamindb/migrations/0099_alter_writelog_seqno.py,sha256=Sg4jbLO3dP69_A53EL2L3rwfMZ0vEZ0dNkBUso8syb4,572
|
82
82
|
lamindb/migrations/0100_branch_alter_artifact__branch_code_and_more.py,sha256=dC1b1ntEVayNxBVEvJVVpVjqjV6qnzZxZ7Ez0qy_9j4,3158
|
83
|
-
lamindb/migrations/0101_alter_artifact_hash_alter_feature_name_and_more.py,sha256=
|
83
|
+
lamindb/migrations/0101_alter_artifact_hash_alter_feature_name_and_more.py,sha256=yxnVzVcoRxd-Xc2KIkR07EtlBxd3LyY4C7F8enBHBYY,14154
|
84
84
|
lamindb/migrations/0102_remove_writelog_branch_code_and_more.py,sha256=LkedZIweHHQGytJbo3OhshLFZLMKAbp22EuW-YqoTp0,2222
|
85
85
|
lamindb/migrations/0103_remove_writelog_migration_state_and_more.py,sha256=pipVgTTq6kmsi0ePCmfT2ajbrPrjJ1O6W5nC1DTG614,1195
|
86
|
-
lamindb/migrations/
|
86
|
+
lamindb/migrations/0104_alter_branch_uid.py,sha256=YHhQHblFoOG5jphqbtPg69gnkiBqw9wdVIFKVrzoRhk,12863
|
87
|
+
lamindb/migrations/0104_squashed.py,sha256=H5Yjj2pONWw9DjPjvp8YHsuDGgrofshze9yVElzT3so,162357
|
87
88
|
lamindb/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
88
89
|
lamindb/models/__init__.py,sha256=Pu7ugwrc_xTxaY4ZnjD5lU2RlCVF4cAa-3bKWRNbI8I,2386
|
89
90
|
lamindb/models/_describe.py,sha256=DF_AyjxrkBqKM4E1Ym5crvyYc6oJ-EaeOda9KJKBVAU,5482
|
90
91
|
lamindb/models/_django.py,sha256=bBu1yBJcE7RvPWor1Fp2sU0IEyrgTHxJbrDILDAvVFM,9029
|
91
|
-
lamindb/models/_feature_manager.py,sha256=
|
92
|
+
lamindb/models/_feature_manager.py,sha256=8AI3iWFmPBcClbwDqBsoKWSQ8ToWcB2FVM8Ny8Xvo4w,52974
|
92
93
|
lamindb/models/_from_values.py,sha256=cCGPMDlAbBrdhFW-XrIQVZ10q1LNg4MycYPLOkF0fTc,13366
|
93
94
|
lamindb/models/_is_versioned.py,sha256=Th2_cBf9UWh27E6ANxg6LGmjBOumXFy7AjH0GG4FoXA,7601
|
94
95
|
lamindb/models/_label_manager.py,sha256=ZcZuajBX7MRAbXyzkhOHypLeCYAjGJe39cP8I9cVt9M,12304
|
@@ -96,23 +97,23 @@ lamindb/models/_relations.py,sha256=zHYLujy9vkuB9jVq5844TpzLSP__iYNCQcsl-FzK1Jw,
|
|
96
97
|
lamindb/models/artifact.py,sha256=eByxq8IpKJqs3OJzMcKqojQ17MmJ7JUQnDKHT5c_LSs,111207
|
97
98
|
lamindb/models/artifact_set.py,sha256=VOZEGDo3m_9Yg_ftx3I2fwdydjHN61X_qV18N6xG4kM,4117
|
98
99
|
lamindb/models/can_curate.py,sha256=ShEva1GGpJcCg7k95t99RzWfz28OFSorPFXLrGoXavE,29266
|
99
|
-
lamindb/models/collection.py,sha256=
|
100
|
+
lamindb/models/collection.py,sha256=BWoSzc5GQDFtMTXl-OjY8WhQgYR6YDe9hctibk96z24,28142
|
100
101
|
lamindb/models/core.py,sha256=BIpqguoZwaoZ8JshHz5dZWM7u3GwObYjmN2_vLaICH8,4030
|
101
102
|
lamindb/models/feature.py,sha256=RZG_82HS20esb8dmCW8VH-j6kiR2A9bMmJmDVaATlo8,29392
|
102
103
|
lamindb/models/has_parents.py,sha256=aqYlCN0P8njmEt5CK5AqS_M5S1ttQz8r6FsT-t3WUTk,20328
|
103
|
-
lamindb/models/project.py,sha256=
|
104
|
+
lamindb/models/project.py,sha256=V_ooZavXIGSq1iwGQMP9zpvbs7Bg5dT_rQ1u6hZSTS4,16614
|
104
105
|
lamindb/models/query_manager.py,sha256=4s0BNB_XaYnNaDNQgk-nzNYq2bOCEr4JsV1e1wLWzoY,10727
|
105
106
|
lamindb/models/query_set.py,sha256=pQ5yRCYB7DkJIXBaUo_oDUTMC4Z8tapiv7sze-yqiNw,31472
|
106
|
-
lamindb/models/record.py,sha256=
|
107
|
-
lamindb/models/run.py,sha256=
|
107
|
+
lamindb/models/record.py,sha256=mQKIEEikmbemQjNAwEwlZagQ_Xnuu-OfrUbOhzdeKJE,9518
|
108
|
+
lamindb/models/run.py,sha256=Frdcjg9-xROo4KmRaiXczztAST718-rC9aa56b_zh4o,15274
|
108
109
|
lamindb/models/save.py,sha256=JtrEAy1D20EpRm6UmjCfZtCTBeq1RNtqzkq9mfhLFtE,13360
|
109
110
|
lamindb/models/schema.py,sha256=oFXVxQU0GjM4ivbPYSOQaIDoC376_1vlQ-AZoQm39eM,47529
|
110
|
-
lamindb/models/sqlrecord.py,sha256=
|
111
|
+
lamindb/models/sqlrecord.py,sha256=by38XCpnLXlnBR1dqPq9GEqFTnTOXHFnw5IVf2pSAOM,64691
|
111
112
|
lamindb/models/transform.py,sha256=lmBkk20tRoOByX3kd5DEbszT1REhBRm1NMNfQgtziKk,12203
|
112
113
|
lamindb/models/ulabel.py,sha256=b9_wY-nsLDBuLvXdEiChjteDf0DkEQxTiLErd1qTABw,9027
|
113
114
|
lamindb/setup/__init__.py,sha256=OwZpZzPDv5lPPGXZP7-zK6UdO4FHvvuBh439yZvIp3A,410
|
114
115
|
lamindb/setup/core/__init__.py,sha256=SevlVrc2AZWL3uALbE5sopxBnIZPWZ1IB0NBDudiAL8,167
|
115
|
-
lamindb-1.
|
116
|
-
lamindb-1.
|
117
|
-
lamindb-1.
|
118
|
-
lamindb-1.
|
116
|
+
lamindb-1.6.1.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
117
|
+
lamindb-1.6.1.dist-info/WHEEL,sha256=CpUCUxeHQbRN5UGRQHYRJorO5Af-Qy_fHMctcQ8DSGI,82
|
118
|
+
lamindb-1.6.1.dist-info/METADATA,sha256=kcfzF8LUHz1Itf4fbJ0MzkZSVeIbHxQWPgMYI0UJEfE,2669
|
119
|
+
lamindb-1.6.1.dist-info/RECORD,,
|
File without changes
|
File without changes
|