lamindb 1.0.1__py3-none-any.whl → 1.0.3__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 +1 -1
- lamindb/_finish.py +19 -13
- lamindb/core/_context.py +38 -8
- lamindb/curators/__init__.py +3 -7
- lamindb/migrations/0080_polish_lamindbv1.py +534 -0
- lamindb/models.py +151 -50
- {lamindb-1.0.1.dist-info → lamindb-1.0.3.dist-info}/METADATA +2 -2
- {lamindb-1.0.1.dist-info → lamindb-1.0.3.dist-info}/RECORD +10 -9
- {lamindb-1.0.1.dist-info → lamindb-1.0.3.dist-info}/LICENSE +0 -0
- {lamindb-1.0.1.dist-info → lamindb-1.0.3.dist-info}/WHEEL +0 -0
lamindb/__init__.py
CHANGED
@@ -53,7 +53,7 @@ Modules and settings.
|
|
53
53
|
"""
|
54
54
|
|
55
55
|
# denote a release candidate for 0.1.0 with 0.1rc1, 0.1a1, 0.1b1, etc.
|
56
|
-
__version__ = "1.0.
|
56
|
+
__version__ = "1.0.3"
|
57
57
|
|
58
58
|
from lamindb_setup._check_setup import InstanceNotSetupError as _InstanceNotSetupError
|
59
59
|
from lamindb_setup._check_setup import _check_instance_setup
|
lamindb/_finish.py
CHANGED
@@ -118,9 +118,8 @@ def notebook_to_script(
|
|
118
118
|
def clean_r_notebook_html(file_path: Path) -> tuple[str | None, Path]:
|
119
119
|
import re
|
120
120
|
|
121
|
-
cleaned_content = (
|
122
|
-
|
123
|
-
) # at this point cleaned_content is still raw
|
121
|
+
cleaned_content = file_path.read_text()
|
122
|
+
# remove title from content
|
124
123
|
pattern_title = r"<title>(.*?)</title>"
|
125
124
|
title_match = re.search(pattern_title, cleaned_content)
|
126
125
|
title_text = None
|
@@ -129,9 +128,18 @@ def clean_r_notebook_html(file_path: Path) -> tuple[str | None, Path]:
|
|
129
128
|
pattern_h1 = f"<h1[^>]*>{re.escape(title_text)}</h1>"
|
130
129
|
cleaned_content = re.sub(pattern_title, "", cleaned_content)
|
131
130
|
cleaned_content = re.sub(pattern_h1, "", cleaned_content)
|
132
|
-
|
133
|
-
|
134
|
-
|
131
|
+
# remove error message from content
|
132
|
+
if "NotebookNotSaved" in cleaned_content:
|
133
|
+
orig_error_message = f"NotebookNotSaved: {get_save_notebook_message()}"
|
134
|
+
# coming up with the regex for this is a bit tricky due to all the
|
135
|
+
# escape characters we'd need to insert into the message; hence,
|
136
|
+
# we do this with a replace() instead
|
137
|
+
cleaned_content = cleaned_content.replace(orig_error_message, "")
|
138
|
+
if "NotebookNotSaved" in cleaned_content:
|
139
|
+
orig_error_message = orig_error_message.replace(
|
140
|
+
" `finish()`", "\n`finish()`"
|
141
|
+
) # RStudio might insert a newline
|
142
|
+
cleaned_content = cleaned_content.replace(orig_error_message, "")
|
135
143
|
cleaned_path = file_path.parent / (f"{file_path.stem}.cleaned{file_path.suffix}")
|
136
144
|
cleaned_path.write_text(cleaned_content)
|
137
145
|
return title_text, cleaned_path
|
@@ -151,8 +159,6 @@ def save_context_core(
|
|
151
159
|
format_field_value, # needs to come after lamindb was imported because of CLI use
|
152
160
|
)
|
153
161
|
|
154
|
-
from .core._context import context
|
155
|
-
|
156
162
|
ln.settings.verbosity = "success"
|
157
163
|
|
158
164
|
# for scripts, things are easy
|
@@ -202,7 +208,7 @@ def save_context_core(
|
|
202
208
|
report_path = filepath.with_suffix(".html")
|
203
209
|
else:
|
204
210
|
logger.warning(
|
205
|
-
f"no
|
211
|
+
f"no html report found; to attach one, create an .html export for your {filepath.suffix} file and then run: lamin save {filepath}"
|
206
212
|
)
|
207
213
|
if report_path is not None and not from_cli:
|
208
214
|
if get_seconds_since_modified(report_path) > 2 and not ln_setup._TESTING:
|
@@ -292,10 +298,13 @@ def save_context_core(
|
|
292
298
|
)
|
293
299
|
report_file.save(upload=True, print_progress=False)
|
294
300
|
run.report = report_file
|
301
|
+
if is_r_notebook:
|
302
|
+
# this is the "cleaned" report
|
303
|
+
report_path.unlink()
|
295
304
|
logger.debug(
|
296
305
|
f"saved transform.latest_run.report: {transform.latest_run.report}"
|
297
306
|
)
|
298
|
-
run.
|
307
|
+
run._is_consecutive = is_consecutive
|
299
308
|
|
300
309
|
# save both run & transform records if we arrive here
|
301
310
|
run.save()
|
@@ -324,7 +333,4 @@ def save_context_core(
|
|
324
333
|
logger.important(
|
325
334
|
f"if you want to update your {thing} without re-running it, use `lamin save {filepath}`"
|
326
335
|
)
|
327
|
-
# because run & transform changed, update the global context
|
328
|
-
context._run = run
|
329
|
-
context._transform = transform
|
330
336
|
return None
|
lamindb/core/_context.py
CHANGED
@@ -395,6 +395,11 @@ class Context:
|
|
395
395
|
path = Path(module.__file__)
|
396
396
|
else:
|
397
397
|
path = Path(path)
|
398
|
+
# for Rmd and qmd, we could also extract the title
|
399
|
+
# we don't do this for now as we're setting the title upon `ln.finish()` or `lamin save`
|
400
|
+
# by extracting it from the html while cleaning it: see clean_r_notebook_html()
|
401
|
+
# also see the script_to_notebook() in the CLI _load.py where the title is extracted
|
402
|
+
# from the source code YAML and updated with the transform description
|
398
403
|
transform_type = "notebook" if path.suffix in {".Rmd", ".qmd"} else "script"
|
399
404
|
reference = None
|
400
405
|
reference_type = None
|
@@ -489,14 +494,30 @@ class Context:
|
|
489
494
|
if aux_transform.key in self._path.as_posix():
|
490
495
|
key = aux_transform.key
|
491
496
|
if (
|
497
|
+
# if the transform source code wasn't yet saved
|
492
498
|
aux_transform.source_code is None
|
493
|
-
|
499
|
+
# if the transform source code is unchanged
|
500
|
+
# if aux_transform.type == "notebook", we anticipate the user makes changes to the notebook source code
|
501
|
+
# in an interactive session, hence we *pro-actively bump* the version number by setting `revises`
|
502
|
+
# in the second part of the if condition even though the source code is unchanged at point of running track()
|
503
|
+
or (
|
504
|
+
aux_transform.hash == hash
|
505
|
+
and aux_transform.type != "notebook"
|
506
|
+
)
|
494
507
|
):
|
495
508
|
uid = aux_transform.uid
|
496
509
|
target_transform = aux_transform
|
497
510
|
else:
|
498
511
|
uid = f"{aux_transform.uid[:-4]}{increment_base62(aux_transform.uid[-4:])}"
|
499
|
-
message = f"there already is a
|
512
|
+
message = f"there already is a {aux_transform.type} with `key` '{aux_transform.key}'"
|
513
|
+
if (
|
514
|
+
aux_transform.hash == hash
|
515
|
+
and aux_transform.type == "notebook"
|
516
|
+
):
|
517
|
+
message += " -- notebook source code is unchanged, but anticipating changes during this run"
|
518
|
+
elif aux_transform.hash != hash:
|
519
|
+
message += " -- source code changed"
|
520
|
+
message += f", creating new version '{uid}'"
|
500
521
|
revises = aux_transform
|
501
522
|
found_key = True
|
502
523
|
break
|
@@ -508,7 +529,7 @@ class Context:
|
|
508
529
|
for transform in transforms
|
509
530
|
]
|
510
531
|
)
|
511
|
-
message = f"ignoring transform{plural_s} with same
|
532
|
+
message = f"ignoring transform{plural_s} with same filename:\n{transforms_str}"
|
512
533
|
if message != "":
|
513
534
|
logger.important(message)
|
514
535
|
self.uid, transform = uid, target_transform
|
@@ -581,7 +602,7 @@ class Context:
|
|
581
602
|
# check whether the transform.key is consistent
|
582
603
|
if transform.key != key:
|
583
604
|
raise UpdateContext(get_key_clashing_message(transform, key))
|
584
|
-
elif transform.description != description:
|
605
|
+
elif transform.description != description and description is not None:
|
585
606
|
transform.description = description
|
586
607
|
transform.save()
|
587
608
|
self._logging_message_track += (
|
@@ -597,7 +618,9 @@ class Context:
|
|
597
618
|
# check whether transform source code was already saved
|
598
619
|
if transform_was_saved:
|
599
620
|
bump_revision = False
|
600
|
-
if
|
621
|
+
if transform.type == "notebook":
|
622
|
+
# we anticipate the user makes changes to the notebook source code
|
623
|
+
# in an interactive session, hence we pro-actively bump the version number
|
601
624
|
bump_revision = True
|
602
625
|
else:
|
603
626
|
hash, _ = hash_file(self._path) # ignore hash_type for now
|
@@ -609,12 +632,12 @@ class Context:
|
|
609
632
|
)
|
610
633
|
if bump_revision:
|
611
634
|
change_type = (
|
612
|
-
"re-running saved
|
613
|
-
if
|
635
|
+
"re-running notebook with already-saved source code"
|
636
|
+
if transform.type == "notebook"
|
614
637
|
else "source code changed"
|
615
638
|
)
|
616
639
|
raise UpdateContext(
|
617
|
-
f'✗ {change_type},
|
640
|
+
f'✗ {change_type}, please update the `uid` argument in `track()` to "{uid[:-4]}{increment_base62(uid[-4:])}"'
|
618
641
|
)
|
619
642
|
else:
|
620
643
|
self._logging_message_track += f"loaded Transform('{transform.uid}')"
|
@@ -683,6 +706,13 @@ class Context:
|
|
683
706
|
)
|
684
707
|
if self.transform.type != "notebook":
|
685
708
|
self._stream_tracker.finish()
|
709
|
+
# reset the context attributes so that somebody who runs `track()` after finish
|
710
|
+
# starts fresh
|
711
|
+
self._uid = None
|
712
|
+
self._run = None
|
713
|
+
self._transform = None
|
714
|
+
self._version = None
|
715
|
+
self._description = None
|
686
716
|
|
687
717
|
|
688
718
|
context = Context()
|
lamindb/curators/__init__.py
CHANGED
@@ -13,6 +13,7 @@ from lamin_utils import colors, logger
|
|
13
13
|
from lamindb_setup.core._docs import doc_args
|
14
14
|
from lamindb_setup.core.upath import UPath
|
15
15
|
|
16
|
+
from lamindb.base.types import FieldAttr # noqa
|
16
17
|
from lamindb.models import (
|
17
18
|
Artifact,
|
18
19
|
Feature,
|
@@ -31,11 +32,6 @@ if TYPE_CHECKING:
|
|
31
32
|
|
32
33
|
from lamindb_setup.core.types import UPathStr
|
33
34
|
from mudata import MuData
|
34
|
-
from spatialdata import SpatialData
|
35
|
-
|
36
|
-
from lamindb.base.types import FieldAttr
|
37
|
-
|
38
|
-
from ._spatial import SpatialDataCurator
|
39
35
|
|
40
36
|
|
41
37
|
class CurateLookup:
|
@@ -1720,7 +1716,7 @@ class Curator(BaseCurator):
|
|
1720
1716
|
@classmethod
|
1721
1717
|
def from_spatialdata(
|
1722
1718
|
cls,
|
1723
|
-
sdata
|
1719
|
+
sdata,
|
1724
1720
|
var_index: dict[str, FieldAttr],
|
1725
1721
|
categoricals: dict[str, dict[str, FieldAttr]] | None = None,
|
1726
1722
|
using_key: str | None = None,
|
@@ -1730,7 +1726,7 @@ class Curator(BaseCurator):
|
|
1730
1726
|
verbosity: str = "hint",
|
1731
1727
|
*,
|
1732
1728
|
sample_metadata_key: str = "sample",
|
1733
|
-
)
|
1729
|
+
):
|
1734
1730
|
"""Curation flow for a ``Spatialdata`` object.
|
1735
1731
|
|
1736
1732
|
See also :class:`~lamindb.Curator`.
|
@@ -0,0 +1,534 @@
|
|
1
|
+
# Generated by Django 5.2 on 2025-01-20 04:42
|
2
|
+
|
3
|
+
import django.db.models.deletion
|
4
|
+
import django.db.models.functions.datetime
|
5
|
+
from django.db import migrations, models
|
6
|
+
|
7
|
+
import lamindb.base.fields
|
8
|
+
import lamindb.base.ids
|
9
|
+
import lamindb.base.users
|
10
|
+
import lamindb.models
|
11
|
+
|
12
|
+
|
13
|
+
class Migration(migrations.Migration):
|
14
|
+
dependencies = [
|
15
|
+
("lamindb", "0079_alter_rundata_value_json_and_more"),
|
16
|
+
]
|
17
|
+
|
18
|
+
operations = [
|
19
|
+
migrations.RemoveField(
|
20
|
+
model_name="project",
|
21
|
+
name="persons",
|
22
|
+
),
|
23
|
+
migrations.AddField(
|
24
|
+
model_name="project",
|
25
|
+
name="is_type",
|
26
|
+
field=lamindb.base.fields.BooleanField(
|
27
|
+
blank=True, db_index=True, default=None, null=True
|
28
|
+
),
|
29
|
+
),
|
30
|
+
migrations.AddField(
|
31
|
+
model_name="project",
|
32
|
+
name="predecessors",
|
33
|
+
field=models.ManyToManyField(
|
34
|
+
related_name="successors", to="lamindb.project"
|
35
|
+
),
|
36
|
+
),
|
37
|
+
migrations.AlterField(
|
38
|
+
model_name="artifact",
|
39
|
+
name="uid",
|
40
|
+
field=lamindb.base.fields.CharField(
|
41
|
+
blank=True,
|
42
|
+
db_index=True,
|
43
|
+
default=None,
|
44
|
+
editable=False,
|
45
|
+
max_length=20,
|
46
|
+
unique=True,
|
47
|
+
),
|
48
|
+
),
|
49
|
+
migrations.AlterField(
|
50
|
+
model_name="collection",
|
51
|
+
name="uid",
|
52
|
+
field=lamindb.base.fields.CharField(
|
53
|
+
blank=True,
|
54
|
+
db_index=True,
|
55
|
+
default=lamindb.base.ids.base62_20,
|
56
|
+
editable=False,
|
57
|
+
max_length=20,
|
58
|
+
unique=True,
|
59
|
+
),
|
60
|
+
),
|
61
|
+
migrations.AlterField(
|
62
|
+
model_name="feature",
|
63
|
+
name="uid",
|
64
|
+
field=lamindb.base.fields.CharField(
|
65
|
+
blank=True,
|
66
|
+
db_index=True,
|
67
|
+
default=lamindb.base.ids.base62_12,
|
68
|
+
editable=False,
|
69
|
+
max_length=12,
|
70
|
+
unique=True,
|
71
|
+
),
|
72
|
+
),
|
73
|
+
migrations.AlterField(
|
74
|
+
model_name="person",
|
75
|
+
name="uid",
|
76
|
+
field=lamindb.base.fields.CharField(
|
77
|
+
blank=True,
|
78
|
+
db_index=True,
|
79
|
+
default=lamindb.base.ids.base62_8,
|
80
|
+
editable=False,
|
81
|
+
max_length=8,
|
82
|
+
unique=True,
|
83
|
+
),
|
84
|
+
),
|
85
|
+
migrations.AlterField(
|
86
|
+
model_name="project",
|
87
|
+
name="type",
|
88
|
+
field=lamindb.base.fields.ForeignKey(
|
89
|
+
blank=True,
|
90
|
+
null=True,
|
91
|
+
on_delete=django.db.models.deletion.PROTECT,
|
92
|
+
related_name="records",
|
93
|
+
to="lamindb.project",
|
94
|
+
),
|
95
|
+
),
|
96
|
+
migrations.AlterField(
|
97
|
+
model_name="project",
|
98
|
+
name="uid",
|
99
|
+
field=lamindb.base.fields.CharField(
|
100
|
+
blank=True,
|
101
|
+
db_index=True,
|
102
|
+
default=lamindb.base.ids.base62_12,
|
103
|
+
editable=False,
|
104
|
+
max_length=12,
|
105
|
+
unique=True,
|
106
|
+
),
|
107
|
+
),
|
108
|
+
migrations.AlterField(
|
109
|
+
model_name="reference",
|
110
|
+
name="uid",
|
111
|
+
field=lamindb.base.fields.CharField(
|
112
|
+
blank=True,
|
113
|
+
db_index=True,
|
114
|
+
default=lamindb.base.ids.base62_12,
|
115
|
+
editable=False,
|
116
|
+
max_length=12,
|
117
|
+
unique=True,
|
118
|
+
),
|
119
|
+
),
|
120
|
+
migrations.AlterField(
|
121
|
+
model_name="run",
|
122
|
+
name="uid",
|
123
|
+
field=lamindb.base.fields.CharField(
|
124
|
+
blank=True,
|
125
|
+
db_index=True,
|
126
|
+
default=lamindb.base.ids.base62_20,
|
127
|
+
editable=False,
|
128
|
+
max_length=20,
|
129
|
+
unique=True,
|
130
|
+
),
|
131
|
+
),
|
132
|
+
migrations.AlterField(
|
133
|
+
model_name="schema",
|
134
|
+
name="uid",
|
135
|
+
field=lamindb.base.fields.CharField(
|
136
|
+
blank=True,
|
137
|
+
db_index=True,
|
138
|
+
default=None,
|
139
|
+
editable=False,
|
140
|
+
max_length=20,
|
141
|
+
unique=True,
|
142
|
+
),
|
143
|
+
),
|
144
|
+
migrations.AlterField(
|
145
|
+
model_name="space",
|
146
|
+
name="uid",
|
147
|
+
field=lamindb.base.fields.CharField(
|
148
|
+
blank=True,
|
149
|
+
db_default="00000000",
|
150
|
+
db_index=True,
|
151
|
+
default="00000000",
|
152
|
+
editable=False,
|
153
|
+
max_length=12,
|
154
|
+
unique=True,
|
155
|
+
),
|
156
|
+
),
|
157
|
+
migrations.AlterField(
|
158
|
+
model_name="storage",
|
159
|
+
name="uid",
|
160
|
+
field=lamindb.base.fields.CharField(
|
161
|
+
blank=True,
|
162
|
+
db_index=True,
|
163
|
+
default=lamindb.base.ids.base62_12,
|
164
|
+
editable=False,
|
165
|
+
max_length=12,
|
166
|
+
unique=True,
|
167
|
+
),
|
168
|
+
),
|
169
|
+
migrations.AlterField(
|
170
|
+
model_name="tidytable",
|
171
|
+
name="uid",
|
172
|
+
field=lamindb.base.fields.CharField(
|
173
|
+
blank=True,
|
174
|
+
db_index=True,
|
175
|
+
default=lamindb.base.ids.base62_12,
|
176
|
+
editable=False,
|
177
|
+
max_length=12,
|
178
|
+
unique=True,
|
179
|
+
),
|
180
|
+
),
|
181
|
+
migrations.AlterField(
|
182
|
+
model_name="transform",
|
183
|
+
name="uid",
|
184
|
+
field=lamindb.base.fields.CharField(
|
185
|
+
blank=True,
|
186
|
+
db_index=True,
|
187
|
+
default=None,
|
188
|
+
editable=False,
|
189
|
+
max_length=16,
|
190
|
+
unique=True,
|
191
|
+
),
|
192
|
+
),
|
193
|
+
migrations.AlterField(
|
194
|
+
model_name="ulabel",
|
195
|
+
name="uid",
|
196
|
+
field=lamindb.base.fields.CharField(
|
197
|
+
blank=True,
|
198
|
+
db_index=True,
|
199
|
+
default=lamindb.base.ids.base62_8,
|
200
|
+
editable=False,
|
201
|
+
max_length=8,
|
202
|
+
unique=True,
|
203
|
+
),
|
204
|
+
),
|
205
|
+
migrations.AlterField(
|
206
|
+
model_name="user",
|
207
|
+
name="uid",
|
208
|
+
field=lamindb.base.fields.CharField(
|
209
|
+
blank=True,
|
210
|
+
db_index=True,
|
211
|
+
default=None,
|
212
|
+
editable=False,
|
213
|
+
max_length=8,
|
214
|
+
unique=True,
|
215
|
+
),
|
216
|
+
),
|
217
|
+
migrations.CreateModel(
|
218
|
+
name="PersonProject",
|
219
|
+
fields=[
|
220
|
+
(
|
221
|
+
"created_at",
|
222
|
+
lamindb.base.fields.DateTimeField(
|
223
|
+
blank=True,
|
224
|
+
db_default=django.db.models.functions.datetime.Now(),
|
225
|
+
db_index=True,
|
226
|
+
editable=False,
|
227
|
+
),
|
228
|
+
),
|
229
|
+
("id", models.BigAutoField(primary_key=True, serialize=False)),
|
230
|
+
(
|
231
|
+
"role",
|
232
|
+
lamindb.base.fields.CharField(
|
233
|
+
blank=True, default=None, max_length=255, null=True
|
234
|
+
),
|
235
|
+
),
|
236
|
+
(
|
237
|
+
"created_by",
|
238
|
+
lamindb.base.fields.ForeignKey(
|
239
|
+
blank=True,
|
240
|
+
default=lamindb.base.users.current_user_id,
|
241
|
+
editable=False,
|
242
|
+
on_delete=django.db.models.deletion.PROTECT,
|
243
|
+
related_name="+",
|
244
|
+
to="lamindb.user",
|
245
|
+
),
|
246
|
+
),
|
247
|
+
(
|
248
|
+
"person",
|
249
|
+
lamindb.base.fields.ForeignKey(
|
250
|
+
blank=True,
|
251
|
+
on_delete=django.db.models.deletion.CASCADE,
|
252
|
+
related_name="links_project",
|
253
|
+
to="lamindb.person",
|
254
|
+
),
|
255
|
+
),
|
256
|
+
(
|
257
|
+
"project",
|
258
|
+
lamindb.base.fields.ForeignKey(
|
259
|
+
blank=True,
|
260
|
+
on_delete=django.db.models.deletion.PROTECT,
|
261
|
+
related_name="links_person",
|
262
|
+
to="lamindb.project",
|
263
|
+
),
|
264
|
+
),
|
265
|
+
(
|
266
|
+
"run",
|
267
|
+
lamindb.base.fields.ForeignKey(
|
268
|
+
blank=True,
|
269
|
+
default=lamindb.models.current_run,
|
270
|
+
null=True,
|
271
|
+
on_delete=django.db.models.deletion.PROTECT,
|
272
|
+
related_name="+",
|
273
|
+
to="lamindb.run",
|
274
|
+
),
|
275
|
+
),
|
276
|
+
],
|
277
|
+
options={
|
278
|
+
"unique_together": {("person", "project")},
|
279
|
+
},
|
280
|
+
bases=(lamindb.models.LinkORM, models.Model),
|
281
|
+
),
|
282
|
+
migrations.AddField(
|
283
|
+
model_name="project",
|
284
|
+
name="people",
|
285
|
+
field=models.ManyToManyField(
|
286
|
+
related_name="projects",
|
287
|
+
through="lamindb.PersonProject",
|
288
|
+
to="lamindb.person",
|
289
|
+
),
|
290
|
+
),
|
291
|
+
migrations.AlterField(
|
292
|
+
model_name="rundata",
|
293
|
+
name="run",
|
294
|
+
field=models.ForeignKey(
|
295
|
+
on_delete=django.db.models.deletion.CASCADE,
|
296
|
+
related_name="_rundata",
|
297
|
+
to="lamindb.run",
|
298
|
+
),
|
299
|
+
),
|
300
|
+
migrations.AddField(
|
301
|
+
model_name="schema",
|
302
|
+
name="description",
|
303
|
+
field=lamindb.base.fields.CharField(
|
304
|
+
blank=True, db_index=True, default=None, max_length=255, null=True
|
305
|
+
),
|
306
|
+
),
|
307
|
+
migrations.AlterField(
|
308
|
+
model_name="collection",
|
309
|
+
name="description",
|
310
|
+
field=lamindb.base.fields.CharField(
|
311
|
+
blank=True, db_index=True, default=None, max_length=255, null=True
|
312
|
+
),
|
313
|
+
),
|
314
|
+
migrations.AlterField(
|
315
|
+
model_name="feature",
|
316
|
+
name="description",
|
317
|
+
field=lamindb.base.fields.CharField(
|
318
|
+
blank=True, db_index=True, default=None, max_length=255, null=True
|
319
|
+
),
|
320
|
+
),
|
321
|
+
migrations.AlterField(
|
322
|
+
model_name="paramvalue",
|
323
|
+
name="created_at",
|
324
|
+
field=lamindb.base.fields.DateTimeField(
|
325
|
+
blank=True,
|
326
|
+
db_default=django.db.models.functions.datetime.Now(),
|
327
|
+
db_index=True,
|
328
|
+
editable=False,
|
329
|
+
),
|
330
|
+
),
|
331
|
+
migrations.AlterField(
|
332
|
+
model_name="reference",
|
333
|
+
name="description",
|
334
|
+
field=lamindb.base.fields.CharField(
|
335
|
+
blank=True, db_index=True, default=None, max_length=255, null=True
|
336
|
+
),
|
337
|
+
),
|
338
|
+
migrations.AlterField(
|
339
|
+
model_name="run",
|
340
|
+
name="created_at",
|
341
|
+
field=lamindb.base.fields.DateTimeField(
|
342
|
+
blank=True,
|
343
|
+
db_default=django.db.models.functions.datetime.Now(),
|
344
|
+
db_index=True,
|
345
|
+
editable=False,
|
346
|
+
),
|
347
|
+
),
|
348
|
+
migrations.AlterField(
|
349
|
+
model_name="run",
|
350
|
+
name="started_at",
|
351
|
+
field=lamindb.base.fields.DateTimeField(
|
352
|
+
blank=True,
|
353
|
+
db_default=django.db.models.functions.datetime.Now(),
|
354
|
+
db_index=True,
|
355
|
+
editable=False,
|
356
|
+
),
|
357
|
+
),
|
358
|
+
migrations.AlterField(
|
359
|
+
model_name="runparamvalue",
|
360
|
+
name="created_at",
|
361
|
+
field=lamindb.base.fields.DateTimeField(
|
362
|
+
blank=True,
|
363
|
+
db_default=django.db.models.functions.datetime.Now(),
|
364
|
+
db_index=True,
|
365
|
+
editable=False,
|
366
|
+
),
|
367
|
+
),
|
368
|
+
migrations.AlterField(
|
369
|
+
model_name="schema",
|
370
|
+
name="name",
|
371
|
+
field=lamindb.base.fields.CharField(
|
372
|
+
blank=True, db_index=True, default=None, max_length=150, null=True
|
373
|
+
),
|
374
|
+
),
|
375
|
+
migrations.AlterField(
|
376
|
+
model_name="space",
|
377
|
+
name="created_at",
|
378
|
+
field=lamindb.base.fields.DateTimeField(
|
379
|
+
blank=True,
|
380
|
+
db_default=django.db.models.functions.datetime.Now(),
|
381
|
+
db_index=True,
|
382
|
+
editable=False,
|
383
|
+
),
|
384
|
+
),
|
385
|
+
migrations.AlterField(
|
386
|
+
model_name="tidytable",
|
387
|
+
name="description",
|
388
|
+
field=lamindb.base.fields.CharField(
|
389
|
+
blank=True, db_index=True, default=None, max_length=255, null=True
|
390
|
+
),
|
391
|
+
),
|
392
|
+
migrations.AlterField(
|
393
|
+
model_name="transform",
|
394
|
+
name="created_at",
|
395
|
+
field=lamindb.base.fields.DateTimeField(
|
396
|
+
blank=True,
|
397
|
+
db_default=django.db.models.functions.datetime.Now(),
|
398
|
+
db_index=True,
|
399
|
+
editable=False,
|
400
|
+
),
|
401
|
+
),
|
402
|
+
migrations.AlterField(
|
403
|
+
model_name="transform",
|
404
|
+
name="updated_at",
|
405
|
+
field=lamindb.base.fields.DateTimeField(
|
406
|
+
blank=True,
|
407
|
+
db_default=django.db.models.functions.datetime.Now(),
|
408
|
+
db_index=True,
|
409
|
+
editable=False,
|
410
|
+
),
|
411
|
+
),
|
412
|
+
migrations.AlterField(
|
413
|
+
model_name="ulabel",
|
414
|
+
name="description",
|
415
|
+
field=lamindb.base.fields.CharField(
|
416
|
+
blank=True, db_index=True, default=None, max_length=255, null=True
|
417
|
+
),
|
418
|
+
),
|
419
|
+
migrations.AlterField(
|
420
|
+
model_name="user",
|
421
|
+
name="created_at",
|
422
|
+
field=lamindb.base.fields.DateTimeField(
|
423
|
+
blank=True,
|
424
|
+
db_default=django.db.models.functions.datetime.Now(),
|
425
|
+
db_index=True,
|
426
|
+
editable=False,
|
427
|
+
),
|
428
|
+
),
|
429
|
+
migrations.AlterField(
|
430
|
+
model_name="user",
|
431
|
+
name="updated_at",
|
432
|
+
field=lamindb.base.fields.DateTimeField(
|
433
|
+
blank=True,
|
434
|
+
db_default=django.db.models.functions.datetime.Now(),
|
435
|
+
db_index=True,
|
436
|
+
editable=False,
|
437
|
+
),
|
438
|
+
),
|
439
|
+
migrations.CreateModel(
|
440
|
+
name="RunULabel",
|
441
|
+
fields=[
|
442
|
+
("id", models.BigAutoField(primary_key=True, serialize=False)),
|
443
|
+
(
|
444
|
+
"created_at",
|
445
|
+
lamindb.base.fields.DateTimeField(
|
446
|
+
blank=True,
|
447
|
+
db_default=django.db.models.functions.datetime.Now(),
|
448
|
+
db_index=True,
|
449
|
+
editable=False,
|
450
|
+
),
|
451
|
+
),
|
452
|
+
(
|
453
|
+
"created_by",
|
454
|
+
lamindb.base.fields.ForeignKey(
|
455
|
+
blank=True,
|
456
|
+
default=lamindb.base.users.current_user_id,
|
457
|
+
on_delete=django.db.models.deletion.PROTECT,
|
458
|
+
related_name="+",
|
459
|
+
to="lamindb.user",
|
460
|
+
),
|
461
|
+
),
|
462
|
+
(
|
463
|
+
"run",
|
464
|
+
lamindb.base.fields.ForeignKey(
|
465
|
+
blank=True,
|
466
|
+
on_delete=django.db.models.deletion.CASCADE,
|
467
|
+
related_name="links_ulabel",
|
468
|
+
to="lamindb.run",
|
469
|
+
),
|
470
|
+
),
|
471
|
+
(
|
472
|
+
"ulabel",
|
473
|
+
lamindb.base.fields.ForeignKey(
|
474
|
+
blank=True,
|
475
|
+
on_delete=django.db.models.deletion.PROTECT,
|
476
|
+
related_name="links_run",
|
477
|
+
to="lamindb.ulabel",
|
478
|
+
),
|
479
|
+
),
|
480
|
+
],
|
481
|
+
options={
|
482
|
+
"unique_together": {("run", "ulabel")},
|
483
|
+
},
|
484
|
+
bases=(models.Model, lamindb.models.LinkORM),
|
485
|
+
),
|
486
|
+
migrations.AddField(
|
487
|
+
model_name="run",
|
488
|
+
name="ulabels",
|
489
|
+
field=models.ManyToManyField(
|
490
|
+
related_name="runs", through="lamindb.RunULabel", to="lamindb.ulabel"
|
491
|
+
),
|
492
|
+
),
|
493
|
+
migrations.RenameModel(
|
494
|
+
old_name="TidyTable",
|
495
|
+
new_name="FlexTable",
|
496
|
+
),
|
497
|
+
migrations.RenameModel(
|
498
|
+
old_name="TidyTableData",
|
499
|
+
new_name="FlexTableData",
|
500
|
+
),
|
501
|
+
migrations.RenameIndex(
|
502
|
+
model_name="flextable",
|
503
|
+
new_name="lamindb_fle_uid_e6f216_idx",
|
504
|
+
old_name="lamindb_tid_uid_3a6e54_idx",
|
505
|
+
),
|
506
|
+
migrations.RenameIndex(
|
507
|
+
model_name="flextable",
|
508
|
+
new_name="lamindb_fle_name_568594_idx",
|
509
|
+
old_name="lamindb_tid_name_50c5de_idx",
|
510
|
+
),
|
511
|
+
migrations.RenameIndex(
|
512
|
+
model_name="flextabledata",
|
513
|
+
new_name="lamindb_fle_tidytab_1674c1_idx",
|
514
|
+
old_name="lamindb_tid_tidytab_b35a4d_idx",
|
515
|
+
),
|
516
|
+
migrations.RenameIndex(
|
517
|
+
model_name="flextabledata",
|
518
|
+
new_name="lamindb_fle_feature_830e49_idx",
|
519
|
+
old_name="lamindb_tid_feature_5a0b1f_idx",
|
520
|
+
),
|
521
|
+
migrations.RenameIndex(
|
522
|
+
model_name="flextabledata",
|
523
|
+
new_name="lamindb_fle_param_i_4149cb_idx",
|
524
|
+
old_name="lamindb_tid_param_i_16c884_idx",
|
525
|
+
),
|
526
|
+
migrations.RemoveField(
|
527
|
+
model_name="flextabledata",
|
528
|
+
name="value_upath",
|
529
|
+
),
|
530
|
+
migrations.RemoveField(
|
531
|
+
model_name="rundata",
|
532
|
+
name="value_upath",
|
533
|
+
),
|
534
|
+
]
|
lamindb/models.py
CHANGED
@@ -824,6 +824,7 @@ class Space(BasicRecord):
|
|
824
824
|
name: str = models.CharField(max_length=100, db_index=True)
|
825
825
|
"""Name of space."""
|
826
826
|
uid: str = CharField(
|
827
|
+
editable=False,
|
827
828
|
unique=True,
|
828
829
|
max_length=12,
|
829
830
|
default="00000000",
|
@@ -833,7 +834,9 @@ class Space(BasicRecord):
|
|
833
834
|
"""Universal id."""
|
834
835
|
description: str | None = CharField(null=True)
|
835
836
|
"""Description of space."""
|
836
|
-
created_at: datetime = DateTimeField(
|
837
|
+
created_at: datetime = DateTimeField(
|
838
|
+
editable=False, db_default=models.functions.Now(), db_index=True
|
839
|
+
)
|
837
840
|
"""Time of creation of record."""
|
838
841
|
created_by: User = ForeignKey(
|
839
842
|
"User", CASCADE, default=None, related_name="+", null=True
|
@@ -979,7 +982,7 @@ class User(BasicRecord, CanCurate):
|
|
979
982
|
|
980
983
|
id: int = models.AutoField(primary_key=True)
|
981
984
|
"""Internal id, valid only in one DB instance."""
|
982
|
-
uid: str = CharField(unique=True, db_index=True, max_length=8)
|
985
|
+
uid: str = CharField(editable=False, unique=True, db_index=True, max_length=8)
|
983
986
|
"""Universal id, valid across DB instances."""
|
984
987
|
handle: str = CharField(max_length=30, unique=True, db_index=True)
|
985
988
|
"""Universal handle, valid across DB instances (required)."""
|
@@ -991,9 +994,13 @@ class User(BasicRecord, CanCurate):
|
|
991
994
|
"""Transforms created by user."""
|
992
995
|
created_runs: Run
|
993
996
|
"""Runs created by user."""
|
994
|
-
created_at: datetime = DateTimeField(
|
997
|
+
created_at: datetime = DateTimeField(
|
998
|
+
editable=False, db_default=models.functions.Now(), db_index=True
|
999
|
+
)
|
995
1000
|
"""Time of creation of record."""
|
996
|
-
updated_at: datetime = DateTimeField(
|
1001
|
+
updated_at: datetime = DateTimeField(
|
1002
|
+
editable=False, db_default=models.functions.Now(), db_index=True
|
1003
|
+
)
|
997
1004
|
"""Time of last update to record."""
|
998
1005
|
|
999
1006
|
@overload
|
@@ -1070,12 +1077,14 @@ class Storage(Record, TracksRun, TracksUpdates):
|
|
1070
1077
|
|
1071
1078
|
id: int = models.AutoField(primary_key=True)
|
1072
1079
|
"""Internal id, valid only in one DB instance."""
|
1073
|
-
uid: str = CharField(
|
1080
|
+
uid: str = CharField(
|
1081
|
+
editable=False, unique=True, max_length=12, default=base62_12, db_index=True
|
1082
|
+
)
|
1074
1083
|
"""Universal id, valid across DB instances."""
|
1075
1084
|
# we are very conservative here with 255 characters
|
1076
|
-
root: str = CharField(
|
1085
|
+
root: str = CharField(db_index=True, unique=True)
|
1077
1086
|
"""Root path of storage. n s3 path. local path, etc. (required)."""
|
1078
|
-
description: str | None = CharField(
|
1087
|
+
description: str | None = CharField(db_index=True, null=True)
|
1079
1088
|
"""A description of what the storage location is used for (optional)."""
|
1080
1089
|
type: str = CharField(max_length=30, db_index=True)
|
1081
1090
|
"""Can be "local" vs. "s3" vs. "gs"."""
|
@@ -1198,7 +1207,9 @@ class Transform(Record, IsVersioned):
|
|
1198
1207
|
|
1199
1208
|
id: int = models.AutoField(primary_key=True)
|
1200
1209
|
"""Internal id, valid only in one DB instance."""
|
1201
|
-
uid: str = CharField(
|
1210
|
+
uid: str = CharField(
|
1211
|
+
editable=False, unique=True, db_index=True, max_length=_len_full_uid
|
1212
|
+
)
|
1202
1213
|
"""Universal id."""
|
1203
1214
|
key: str | None = CharField(db_index=True, null=True)
|
1204
1215
|
"""A name or "/"-separated path-like string.
|
@@ -1259,9 +1270,17 @@ class Transform(Record, IsVersioned):
|
|
1259
1270
|
|
1260
1271
|
If you're looking for the outputs of a single run, see :attr:`lamindb.Run.output_collections`.
|
1261
1272
|
"""
|
1262
|
-
|
1273
|
+
projects: Project
|
1274
|
+
"""Associated projects."""
|
1275
|
+
references: Reference
|
1276
|
+
"""Associated references."""
|
1277
|
+
created_at: datetime = DateTimeField(
|
1278
|
+
editable=False, db_default=models.functions.Now(), db_index=True
|
1279
|
+
)
|
1263
1280
|
"""Time of creation of record."""
|
1264
|
-
updated_at: datetime = DateTimeField(
|
1281
|
+
updated_at: datetime = DateTimeField(
|
1282
|
+
editable=False, db_default=models.functions.Now(), db_index=True
|
1283
|
+
)
|
1265
1284
|
"""Time of last update to record."""
|
1266
1285
|
created_by: User = ForeignKey(
|
1267
1286
|
User, PROTECT, default=current_user_id, related_name="created_transforms"
|
@@ -1381,7 +1400,9 @@ class ParamValue(Record):
|
|
1381
1400
|
# hence, ParamValue does _not_ inherit from TracksRun but manually
|
1382
1401
|
# adds created_at & created_by
|
1383
1402
|
# because ParamValue cannot be updated, we don't need updated_at
|
1384
|
-
created_at: datetime = DateTimeField(
|
1403
|
+
created_at: datetime = DateTimeField(
|
1404
|
+
editable=False, db_default=models.functions.Now(), db_index=True
|
1405
|
+
)
|
1385
1406
|
"""Time of creation of record."""
|
1386
1407
|
created_by: User = ForeignKey(
|
1387
1408
|
User, PROTECT, default=current_user_id, related_name="+"
|
@@ -1476,13 +1497,17 @@ class Run(Record):
|
|
1476
1497
|
|
1477
1498
|
id: int = models.BigAutoField(primary_key=True)
|
1478
1499
|
"""Internal id, valid only in one DB instance."""
|
1479
|
-
uid: str = CharField(
|
1500
|
+
uid: str = CharField(
|
1501
|
+
editable=False, unique=True, db_index=True, max_length=20, default=base62_20
|
1502
|
+
)
|
1480
1503
|
"""Universal id, valid across DB instances."""
|
1481
1504
|
name: str | None = CharField(max_length=150, null=True)
|
1482
1505
|
"""A name."""
|
1483
1506
|
transform = ForeignKey(Transform, CASCADE, related_name="runs")
|
1484
1507
|
"""The transform :class:`~lamindb.Transform` that is being run."""
|
1485
|
-
started_at: datetime = DateTimeField(
|
1508
|
+
started_at: datetime = DateTimeField(
|
1509
|
+
editable=False, db_default=models.functions.Now(), db_index=True
|
1510
|
+
)
|
1486
1511
|
"""Start time of run."""
|
1487
1512
|
finished_at: datetime | None = DateTimeField(db_index=True, null=True, default=None)
|
1488
1513
|
"""Finished time of run."""
|
@@ -1525,12 +1550,18 @@ class Run(Record):
|
|
1525
1550
|
"""A reference like a URL or external ID (such as from a workflow manager)."""
|
1526
1551
|
reference_type: str | None = CharField(max_length=25, db_index=True, null=True)
|
1527
1552
|
"""Type of reference such as a workflow manager execution ID."""
|
1528
|
-
created_at: datetime = DateTimeField(
|
1553
|
+
created_at: datetime = DateTimeField(
|
1554
|
+
editable=False, db_default=models.functions.Now(), db_index=True
|
1555
|
+
)
|
1529
1556
|
"""Time of first creation. Mismatches ``started_at`` if the run is re-run."""
|
1530
1557
|
created_by: User = ForeignKey(
|
1531
1558
|
User, CASCADE, default=current_user_id, related_name="created_runs"
|
1532
1559
|
)
|
1533
1560
|
"""Creator of run."""
|
1561
|
+
ulabels: ULabel = models.ManyToManyField(
|
1562
|
+
"ULabel", through="RunULabel", related_name="runs"
|
1563
|
+
)
|
1564
|
+
"""ULabel annotations of this transform."""
|
1534
1565
|
initiated_by_run: Run | None = ForeignKey(
|
1535
1566
|
"Run", CASCADE, null=True, related_name="initiated_runs", default=None
|
1536
1567
|
)
|
@@ -1542,8 +1573,8 @@ class Run(Record):
|
|
1542
1573
|
|
1543
1574
|
Be careful with using this field at this point.
|
1544
1575
|
"""
|
1545
|
-
|
1546
|
-
"""
|
1576
|
+
initiated_runs: Run
|
1577
|
+
"""Runs that were initiated by this run."""
|
1547
1578
|
_is_consecutive: bool | None = BooleanField(null=True)
|
1548
1579
|
"""Indicates whether code was consecutively executed. Is relevant for notebooks."""
|
1549
1580
|
_status_code: int = models.SmallIntegerField(default=0, db_index=True)
|
@@ -1643,7 +1674,9 @@ class ULabel(Record, HasParents, CanCurate, TracksRun, TracksUpdates):
|
|
1643
1674
|
|
1644
1675
|
id: int = models.AutoField(primary_key=True)
|
1645
1676
|
"""Internal id, valid only in one DB instance."""
|
1646
|
-
uid: str = CharField(
|
1677
|
+
uid: str = CharField(
|
1678
|
+
editable=False, unique=True, db_index=True, max_length=8, default=base62_8
|
1679
|
+
)
|
1647
1680
|
"""A universal random id, valid across DB instances."""
|
1648
1681
|
name: str = CharField(max_length=150, db_index=True)
|
1649
1682
|
"""Name or title of ulabel (`unique=True`)."""
|
@@ -1659,7 +1692,7 @@ class ULabel(Record, HasParents, CanCurate, TracksRun, TracksUpdates):
|
|
1659
1692
|
|
1660
1693
|
For example, a ulabel "Project" would be a type, and the actual projects "Project 1", "Project 2", would be records of that `type`.
|
1661
1694
|
"""
|
1662
|
-
description: str | None =
|
1695
|
+
description: str | None = CharField(null=True, db_index=True)
|
1663
1696
|
"""A description (optional)."""
|
1664
1697
|
reference: str | None = CharField(max_length=255, db_index=True, null=True)
|
1665
1698
|
"""A reference like URL or external ID."""
|
@@ -1681,10 +1714,14 @@ class ULabel(Record, HasParents, CanCurate, TracksRun, TracksUpdates):
|
|
1681
1714
|
"""
|
1682
1715
|
transforms: Transform
|
1683
1716
|
"""Transforms annotated with this ulabel."""
|
1717
|
+
runs: Transform
|
1718
|
+
"""Runs annotated with this ulabel."""
|
1684
1719
|
artifacts: Artifact
|
1685
1720
|
"""Artifacts annotated with this ulabel."""
|
1686
1721
|
collections: Collection
|
1687
1722
|
"""Collections annotated with this ulabel."""
|
1723
|
+
projects: Project
|
1724
|
+
"""Associated projects."""
|
1688
1725
|
|
1689
1726
|
@overload
|
1690
1727
|
def __init__(
|
@@ -1801,7 +1838,9 @@ class Feature(Record, CanCurate, TracksRun, TracksUpdates):
|
|
1801
1838
|
|
1802
1839
|
id: int = models.AutoField(primary_key=True)
|
1803
1840
|
"""Internal id, valid only in one DB instance."""
|
1804
|
-
uid: str = CharField(
|
1841
|
+
uid: str = CharField(
|
1842
|
+
editable=False, unique=True, db_index=True, max_length=12, default=base62_12
|
1843
|
+
)
|
1805
1844
|
"""Universal id, valid across DB instances."""
|
1806
1845
|
name: str = CharField(max_length=150, db_index=True, unique=True)
|
1807
1846
|
"""Name of feature (`unique=True`)."""
|
@@ -1825,7 +1864,7 @@ class Feature(Record, CanCurate, TracksRun, TracksUpdates):
|
|
1825
1864
|
"""Distinguish types from instances of the type."""
|
1826
1865
|
unit: str | None = CharField(max_length=30, db_index=True, null=True)
|
1827
1866
|
"""Unit of measure, ideally SI (`m`, `s`, `kg`, etc.) or 'normalized' etc. (optional)."""
|
1828
|
-
description: str | None =
|
1867
|
+
description: str | None = CharField(db_index=True, null=True)
|
1829
1868
|
"""A description."""
|
1830
1869
|
array_rank: int = models.SmallIntegerField(default=0, db_index=True)
|
1831
1870
|
"""Rank of feature.
|
@@ -2051,10 +2090,12 @@ class Schema(Record, CanCurate, TracksRun):
|
|
2051
2090
|
|
2052
2091
|
id: int = models.AutoField(primary_key=True)
|
2053
2092
|
"""Internal id, valid only in one DB instance."""
|
2054
|
-
uid: str = CharField(unique=True, db_index=True, max_length=20)
|
2093
|
+
uid: str = CharField(editable=False, unique=True, db_index=True, max_length=20)
|
2055
2094
|
"""A universal id (hash of the set of feature values)."""
|
2056
|
-
name: str | None = CharField(max_length=150, null=True)
|
2095
|
+
name: str | None = CharField(max_length=150, null=True, db_index=True)
|
2057
2096
|
"""A name."""
|
2097
|
+
description: str | None = CharField(null=True, db_index=True)
|
2098
|
+
"""A description."""
|
2058
2099
|
n = IntegerField()
|
2059
2100
|
"""Number of features in the set."""
|
2060
2101
|
dtype: str | None = CharField(max_length=64, null=True)
|
@@ -2398,7 +2439,9 @@ class Artifact(Record, IsVersioned, TracksRun, TracksUpdates):
|
|
2398
2439
|
|
2399
2440
|
id: int = models.AutoField(primary_key=True)
|
2400
2441
|
"""Internal id, valid only in one DB instance."""
|
2401
|
-
uid: str = CharField(
|
2442
|
+
uid: str = CharField(
|
2443
|
+
editable=False, unique=True, db_index=True, max_length=_len_full_uid
|
2444
|
+
)
|
2402
2445
|
"""A universal random id."""
|
2403
2446
|
key: str | None = CharField(db_index=True, null=True)
|
2404
2447
|
"""A (virtual) relative file path within the artifact's storage location.
|
@@ -2411,10 +2454,7 @@ class Artifact(Record, IsVersioned, TracksRun, TracksUpdates):
|
|
2411
2454
|
actual filepath on the underyling filesytem or object store.
|
2412
2455
|
"""
|
2413
2456
|
description: str | None = CharField(db_index=True, null=True)
|
2414
|
-
"""A description.
|
2415
|
-
|
2416
|
-
LaminDB doesn't require you to pass a key, you can
|
2417
|
-
"""
|
2457
|
+
"""A description."""
|
2418
2458
|
storage: Storage = ForeignKey(Storage, PROTECT, related_name="artifacts")
|
2419
2459
|
"""Storage location, e.g. an S3 or GCP bucket or a local directory."""
|
2420
2460
|
suffix: str = CharField(max_length=30, db_index=True)
|
@@ -2510,6 +2550,10 @@ class Artifact(Record, IsVersioned, TracksRun, TracksUpdates):
|
|
2510
2550
|
|
2511
2551
|
It defaults to False for file-like artifacts and to True for folder-like artifacts.
|
2512
2552
|
"""
|
2553
|
+
projects: Project
|
2554
|
+
"""Associated projects."""
|
2555
|
+
references: Reference
|
2556
|
+
"""Associated references."""
|
2513
2557
|
|
2514
2558
|
@overload
|
2515
2559
|
def __init__(
|
@@ -2955,12 +2999,16 @@ class Collection(Record, IsVersioned, TracksRun, TracksUpdates):
|
|
2955
2999
|
id: int = models.AutoField(primary_key=True)
|
2956
3000
|
"""Internal id, valid only in one DB instance."""
|
2957
3001
|
uid: str = CharField(
|
2958
|
-
|
3002
|
+
editable=False,
|
3003
|
+
unique=True,
|
3004
|
+
db_index=True,
|
3005
|
+
max_length=_len_full_uid,
|
3006
|
+
default=base62_20,
|
2959
3007
|
)
|
2960
3008
|
"""Universal id, valid across DB instances."""
|
2961
3009
|
key: str = CharField(db_index=True)
|
2962
3010
|
"""Name or path-like key."""
|
2963
|
-
description: str | None =
|
3011
|
+
description: str | None = CharField(null=True, db_index=True)
|
2964
3012
|
"""A description or title."""
|
2965
3013
|
hash: str | None = CharField(max_length=HASH_LENGTH, db_index=True, null=True)
|
2966
3014
|
"""Hash of collection content. 86 base64 chars allow to store 64 bytes, 512 bits."""
|
@@ -3239,7 +3287,9 @@ class Person(Record, CanCurate, TracksRun, TracksUpdates, ValidateFields):
|
|
3239
3287
|
|
3240
3288
|
id: int = models.AutoField(primary_key=True)
|
3241
3289
|
"""Internal id, valid only in one DB instance."""
|
3242
|
-
uid: str = CharField(
|
3290
|
+
uid: str = CharField(
|
3291
|
+
editable=False, unique=True, max_length=8, db_index=True, default=base62_8
|
3292
|
+
)
|
3243
3293
|
"""Universal id, valid across DB instances."""
|
3244
3294
|
name: str = CharField(db_index=True)
|
3245
3295
|
"""Name of the person (forename(s) lastname)."""
|
@@ -3265,12 +3315,20 @@ class Project(Record, CanCurate, TracksRun, TracksUpdates, ValidateFields):
|
|
3265
3315
|
|
3266
3316
|
id: int = models.AutoField(primary_key=True)
|
3267
3317
|
"""Internal id, valid only in one DB instance."""
|
3268
|
-
uid: str = CharField(
|
3318
|
+
uid: str = CharField(
|
3319
|
+
editable=False, unique=True, max_length=12, db_index=True, default=base62_12
|
3320
|
+
)
|
3269
3321
|
"""Universal id, valid across DB instances."""
|
3270
3322
|
name: str = CharField(db_index=True)
|
3271
3323
|
"""Title or name of the Project."""
|
3272
|
-
type:
|
3273
|
-
|
3324
|
+
type: Project | None = ForeignKey(
|
3325
|
+
"self", PROTECT, null=True, related_name="records"
|
3326
|
+
)
|
3327
|
+
"""Type of project (e.g., 'Program', 'Project', 'GithubIssue', 'Task')."""
|
3328
|
+
records: Project
|
3329
|
+
"""Records of this type."""
|
3330
|
+
is_type: bool = BooleanField(default=None, db_index=True, null=True)
|
3331
|
+
"""Distinguish types from instances of the type."""
|
3274
3332
|
abbr: str | None = CharField(max_length=32, db_index=True, null=True)
|
3275
3333
|
"""An abbreviation."""
|
3276
3334
|
url: str | None = URLField(max_length=255, null=True, default=None)
|
@@ -3282,12 +3340,25 @@ class Project(Record, CanCurate, TracksRun, TracksUpdates, ValidateFields):
|
|
3282
3340
|
parents: Project = models.ManyToManyField(
|
3283
3341
|
"self", symmetrical=False, related_name="children"
|
3284
3342
|
)
|
3285
|
-
"""Parent projects."""
|
3343
|
+
"""Parent projects, the super-projects owning this project."""
|
3286
3344
|
children: Project
|
3287
|
-
"""Child projects.
|
3345
|
+
"""Child projects, the sub-projects owned by this project.
|
3288
3346
|
|
3289
|
-
Reverse accessor for parents
|
3347
|
+
Reverse accessor for `.parents`.
|
3348
|
+
"""
|
3349
|
+
predecessors: Project = models.ManyToManyField(
|
3350
|
+
"self", symmetrical=False, related_name="successors"
|
3351
|
+
)
|
3352
|
+
"""The preceding projects required by this project."""
|
3353
|
+
successors: Project
|
3354
|
+
"""The succeeding projects requiring this project.
|
3355
|
+
|
3356
|
+
Reverse accessor for `.predecessors`.
|
3290
3357
|
"""
|
3358
|
+
people: Person = models.ManyToManyField(
|
3359
|
+
Person, through="PersonProject", related_name="projects"
|
3360
|
+
)
|
3361
|
+
"""People associated with this project."""
|
3291
3362
|
artifacts: Artifact = models.ManyToManyField(
|
3292
3363
|
Artifact, through="ArtifactProject", related_name="projects"
|
3293
3364
|
)
|
@@ -3312,8 +3383,6 @@ class Project(Record, CanCurate, TracksRun, TracksUpdates, ValidateFields):
|
|
3312
3383
|
Collection, through="CollectionProject", related_name="projects"
|
3313
3384
|
)
|
3314
3385
|
"""Collections associated with this project."""
|
3315
|
-
persons: Person = models.ManyToManyField(Person, related_name="projects")
|
3316
|
-
"""Persons associated with this project."""
|
3317
3386
|
references: Reference = models.ManyToManyField("Reference", related_name="projects")
|
3318
3387
|
"""References associated with this project."""
|
3319
3388
|
_status_code: int = models.SmallIntegerField(default=0, db_index=True)
|
@@ -3341,7 +3410,9 @@ class Reference(Record, CanCurate, TracksRun, TracksUpdates, ValidateFields):
|
|
3341
3410
|
|
3342
3411
|
id: int = models.AutoField(primary_key=True)
|
3343
3412
|
"""Internal id, valid only in one DB instance."""
|
3344
|
-
uid: str = CharField(
|
3413
|
+
uid: str = CharField(
|
3414
|
+
editable=False, unique=True, max_length=12, db_index=True, default=base62_12
|
3415
|
+
)
|
3345
3416
|
"""Universal id, valid across DB instances."""
|
3346
3417
|
name: str = CharField(db_index=True)
|
3347
3418
|
"""Title or name of the reference document."""
|
@@ -3377,7 +3448,7 @@ class Reference(Record, CanCurate, TracksRun, TracksUpdates, ValidateFields):
|
|
3377
3448
|
],
|
3378
3449
|
)
|
3379
3450
|
"""Digital Object Identifier (DOI) for the reference."""
|
3380
|
-
description: str | None =
|
3451
|
+
description: str | None = CharField(null=True, db_index=True)
|
3381
3452
|
"""Description of the reference."""
|
3382
3453
|
text: str | None = TextField(null=True)
|
3383
3454
|
"""Abstract or full text of the reference to make it searchable."""
|
@@ -3421,7 +3492,6 @@ class DataMixin(models.Model):
|
|
3421
3492
|
value_int = models.BigIntegerField(null=True, blank=True)
|
3422
3493
|
value_float = models.FloatField(null=True, blank=True)
|
3423
3494
|
value_str = models.TextField(null=True, blank=True)
|
3424
|
-
value_upath = models.CharField(max_length=255, null=True, blank=True)
|
3425
3495
|
value_datetime = models.DateTimeField(null=True, blank=True)
|
3426
3496
|
value_ulabel = models.ForeignKey(
|
3427
3497
|
ULabel, null=True, blank=True, on_delete=models.CASCADE, related_name="+"
|
@@ -3453,7 +3523,6 @@ class DataMixin(models.Model):
|
|
3453
3523
|
self.value_int,
|
3454
3524
|
self.value_float,
|
3455
3525
|
self.value_str,
|
3456
|
-
self.value_upath,
|
3457
3526
|
self.value_datetime,
|
3458
3527
|
self.value_ulabel,
|
3459
3528
|
self.value_artifact,
|
@@ -3466,7 +3535,7 @@ class DataMixin(models.Model):
|
|
3466
3535
|
|
3467
3536
|
|
3468
3537
|
class RunData(BasicRecord, DataMixin):
|
3469
|
-
run = models.ForeignKey("Run", on_delete=models.CASCADE, related_name="
|
3538
|
+
run = models.ForeignKey("Run", on_delete=models.CASCADE, related_name="_rundata")
|
3470
3539
|
|
3471
3540
|
class Meta:
|
3472
3541
|
constraints = [
|
@@ -3488,13 +3557,15 @@ class RunData(BasicRecord, DataMixin):
|
|
3488
3557
|
]
|
3489
3558
|
|
3490
3559
|
|
3491
|
-
class
|
3492
|
-
uid: str = CharField(
|
3560
|
+
class FlexTable(Record, TracksRun, TracksUpdates):
|
3561
|
+
uid: str = CharField(
|
3562
|
+
editable=False, unique=True, max_length=12, db_index=True, default=base62_12
|
3563
|
+
)
|
3493
3564
|
name = CharField()
|
3494
3565
|
schema: Schema | None = ForeignKey(
|
3495
3566
|
Schema, null=True, on_delete=models.SET_NULL, related_name="_tidytables"
|
3496
3567
|
)
|
3497
|
-
type:
|
3568
|
+
type: FlexTable | None = ForeignKey(
|
3498
3569
|
"self", PROTECT, null=True, related_name="records"
|
3499
3570
|
)
|
3500
3571
|
"""Type of tidy table, e.g., `Cell`, `SampleSheet`, etc."""
|
@@ -3502,7 +3573,8 @@ class TidyTable(Record, TracksRun, TracksUpdates):
|
|
3502
3573
|
"""Records of this type."""
|
3503
3574
|
is_type: bool = BooleanField(default=None, db_index=True, null=True)
|
3504
3575
|
"""Distinguish types from instances of the type."""
|
3505
|
-
description: str =
|
3576
|
+
description: str = CharField(null=True, db_index=True)
|
3577
|
+
"""A description."""
|
3506
3578
|
projects: Project = ManyToManyField(Project, related_name="_tidytables")
|
3507
3579
|
ulabels: Project = ManyToManyField(ULabel, related_name="_tidytables")
|
3508
3580
|
|
@@ -3510,9 +3582,9 @@ class TidyTable(Record, TracksRun, TracksUpdates):
|
|
3510
3582
|
indexes = [models.Index(fields=["uid"]), models.Index(fields=["name"])]
|
3511
3583
|
|
3512
3584
|
|
3513
|
-
class
|
3585
|
+
class FlexTableData(BasicRecord, DataMixin):
|
3514
3586
|
tidytable = models.ForeignKey(
|
3515
|
-
|
3587
|
+
FlexTable, on_delete=models.CASCADE, related_name="data"
|
3516
3588
|
)
|
3517
3589
|
|
3518
3590
|
class Meta:
|
@@ -3612,6 +3684,23 @@ class TransformULabel(BasicRecord, LinkORM, TracksRun):
|
|
3612
3684
|
unique_together = ("transform", "ulabel")
|
3613
3685
|
|
3614
3686
|
|
3687
|
+
class RunULabel(BasicRecord, LinkORM):
|
3688
|
+
id: int = models.BigAutoField(primary_key=True)
|
3689
|
+
run: Run = ForeignKey(Run, CASCADE, related_name="links_ulabel")
|
3690
|
+
ulabel: ULabel = ForeignKey(ULabel, PROTECT, related_name="links_run")
|
3691
|
+
created_at: datetime = DateTimeField(
|
3692
|
+
editable=False, db_default=models.functions.Now(), db_index=True
|
3693
|
+
)
|
3694
|
+
"""Time of creation of record."""
|
3695
|
+
created_by: User = ForeignKey(
|
3696
|
+
"lamindb.User", PROTECT, default=current_user_id, related_name="+"
|
3697
|
+
)
|
3698
|
+
"""Creator of record."""
|
3699
|
+
|
3700
|
+
class Meta:
|
3701
|
+
unique_together = ("run", "ulabel")
|
3702
|
+
|
3703
|
+
|
3615
3704
|
class CollectionULabel(BasicRecord, LinkORM, TracksRun):
|
3616
3705
|
id: int = models.BigAutoField(primary_key=True)
|
3617
3706
|
collection: Collection = ForeignKey(
|
@@ -3643,7 +3732,9 @@ class RunParamValue(BasicRecord, LinkORM):
|
|
3643
3732
|
run: Run = ForeignKey(Run, CASCADE, related_name="+")
|
3644
3733
|
# we follow the lower() case convention rather than snake case for link models
|
3645
3734
|
paramvalue: ParamValue = ForeignKey(ParamValue, PROTECT, related_name="+")
|
3646
|
-
created_at: datetime = DateTimeField(
|
3735
|
+
created_at: datetime = DateTimeField(
|
3736
|
+
editable=False, db_default=models.functions.Now(), db_index=True
|
3737
|
+
)
|
3647
3738
|
"""Time of creation of record."""
|
3648
3739
|
created_by: User = ForeignKey(
|
3649
3740
|
"lamindb.User", PROTECT, default=current_user_id, related_name="+"
|
@@ -3716,6 +3807,16 @@ class ULabelProject(BasicRecord, LinkORM, TracksRun):
|
|
3716
3807
|
unique_together = ("ulabel", "project")
|
3717
3808
|
|
3718
3809
|
|
3810
|
+
class PersonProject(BasicRecord, LinkORM, TracksRun):
|
3811
|
+
id: int = models.BigAutoField(primary_key=True)
|
3812
|
+
person: Transform = ForeignKey(Person, CASCADE, related_name="links_project")
|
3813
|
+
project: Project = ForeignKey(Project, PROTECT, related_name="links_person")
|
3814
|
+
role: str | None = CharField(null=True, default=None)
|
3815
|
+
|
3816
|
+
class Meta:
|
3817
|
+
unique_together = ("person", "project")
|
3818
|
+
|
3819
|
+
|
3719
3820
|
class FeatureProject(BasicRecord, LinkORM, TracksRun):
|
3720
3821
|
id: int = models.BigAutoField(primary_key=True)
|
3721
3822
|
feature: Feature = ForeignKey(Feature, CASCADE, related_name="links_project")
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: lamindb
|
3
|
-
Version: 1.0.
|
3
|
+
Version: 1.0.3
|
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.13
|
@@ -9,7 +9,7 @@ Classifier: Programming Language :: Python :: 3.10
|
|
9
9
|
Classifier: Programming Language :: Python :: 3.11
|
10
10
|
Classifier: Programming Language :: Python :: 3.12
|
11
11
|
Requires-Dist: lamin_utils==0.13.10
|
12
|
-
Requires-Dist: lamin_cli==1.0.
|
12
|
+
Requires-Dist: lamin_cli==1.0.4
|
13
13
|
Requires-Dist: lamindb_setup[aws]==1.0.3
|
14
14
|
Requires-Dist: pyarrow
|
15
15
|
Requires-Dist: typing_extensions!=4.6.0
|
@@ -1,9 +1,9 @@
|
|
1
|
-
lamindb/__init__.py,sha256=
|
1
|
+
lamindb/__init__.py,sha256=uV_nFvYAz9x_edJcb9bqtnDx2C9wHhbDbnvMN2EIQHM,2255
|
2
2
|
lamindb/_artifact.py,sha256=22pKCA05PoIAgP2xszCHUovZ1VbMGIyrQqNLs5xDG_s,46580
|
3
3
|
lamindb/_can_curate.py,sha256=pIu9Ylgq5biUd_67rRbAHg9tkXSQrxMRM8TnVboL9YA,20341
|
4
4
|
lamindb/_collection.py,sha256=j2yTfR9v-NGUI85JfQk7vOQNExkWE5H_ulsSlBh1AOI,14456
|
5
5
|
lamindb/_feature.py,sha256=qpUZfmdxUpQFLq5GciTn6KgALL19tCs0raHhzJgm7Lo,6311
|
6
|
-
lamindb/_finish.py,sha256=
|
6
|
+
lamindb/_finish.py,sha256=aMN9CwTGAXeqWSDvCumVLztHtKttwI9z52mdz4ue5Uw,13362
|
7
7
|
lamindb/_from_values.py,sha256=uO3IfYzAI8VDDTqlbLzsZtawSYFS-Qzd_ZWwKGhH90o,14231
|
8
8
|
lamindb/_is_versioned.py,sha256=6_LBAKD_fng6BReqitJUIxTUaQok3AeIpNnE_D8kHnQ,1293
|
9
9
|
lamindb/_parents.py,sha256=PA--_ZH3PNqIVW0PpuYk9d4DAVlHUBPN-dN0rFUKUN0,17238
|
@@ -18,7 +18,7 @@ lamindb/_transform.py,sha256=LYFf8gScJrYLMZJECLYZ5nrW2vLPObdzRP47md-Tq-s,5731
|
|
18
18
|
lamindb/_ulabel.py,sha256=YTiUCYrcEqyUKD8nZO4iOqiyYnUP5bW_r7yry4KSeWA,2068
|
19
19
|
lamindb/_utils.py,sha256=LGdiW4k3GClLz65vKAVRkL6Tw-Gkx9DWAdez1jyA5bE,428
|
20
20
|
lamindb/_view.py,sha256=c4eN5hcBlg3TVnljKefbyWAq0eBncjMp2xQcb5OaGWg,4982
|
21
|
-
lamindb/models.py,sha256=
|
21
|
+
lamindb/models.py,sha256=85eBwsFmoKfZfefviUt8DmfW1n6kyFQO2VfP3pa-xUc,147536
|
22
22
|
lamindb/base/__init__.py,sha256=J0UpYObi9hJBFyBpAXp4wB3DaJx48R2SaUeB4wjiFvc,267
|
23
23
|
lamindb/base/fields.py,sha256=RdwYHQmB7B-jopD_K2QNL5vjhOelu7DWGgqQItXr3pg,8024
|
24
24
|
lamindb/base/ids.py,sha256=WzHWiHZtlRUKqxz_p-76ks_JSW669ztvriE7Z3A0yHg,1736
|
@@ -26,7 +26,7 @@ lamindb/base/types.py,sha256=JfZk0xmhLsWusU0s4SNjhRnQ52mn-cSiG5Gf4SsACBs,1227
|
|
26
26
|
lamindb/base/users.py,sha256=g4ZLQb6eey66FO9eEumbfDpJi_FZZsiLVe2Frz9JuLI,978
|
27
27
|
lamindb/base/validation.py,sha256=Azz9y2-x0cPum4yULXMG3Yzra03mcVYzcKTiI23HgxE,2287
|
28
28
|
lamindb/core/__init__.py,sha256=4AGZqt5g8k3jFX53IXdezQR4Gf7JmMBLZRyTJJzS4sI,1628
|
29
|
-
lamindb/core/_context.py,sha256=
|
29
|
+
lamindb/core/_context.py,sha256=na1n_Lpj7Dvxjk1KB5Di4jEdhH-d6Jf757fvY1awEGM,28591
|
30
30
|
lamindb/core/_data.py,sha256=xg_St591OPCzLhaZAlGxVd8QkDxZsxDc_yEwY8Kop8w,19017
|
31
31
|
lamindb/core/_describe.py,sha256=3Z1xi9eKIBkYuPW9ctdWvFaGZym8mI9FcwyZF3a6YVo,4885
|
32
32
|
lamindb/core/_django.py,sha256=vPY4wJ4bf3a1uz5bhukCCF_mngR_9w2Ot3nvWZpa204,7629
|
@@ -58,7 +58,7 @@ lamindb/core/storage/objects.py,sha256=5vM2T_upuzrXt2b7fQeQ2FUO710-FRbubxTzKzV2E
|
|
58
58
|
lamindb/core/storage/paths.py,sha256=XXEy51qCw0z497y6ZEN_SULY3oXtA4XlanHo-TGK7jY,6302
|
59
59
|
lamindb/core/subsettings/__init__.py,sha256=j6G9WAJLK-x9FzPSFw-HJUmOseZKGTbK-oLTKI_X_zs,126
|
60
60
|
lamindb/core/subsettings/_creation_settings.py,sha256=54mfMH_osC753hpxcl7Dq1rwBD2LHnWveXtQpkLBITE,1194
|
61
|
-
lamindb/curators/__init__.py,sha256=
|
61
|
+
lamindb/curators/__init__.py,sha256=XGHnTEFB-Q4XphR0AWLXhITqhAZqkqEzuJJq1Ypb-zU,92357
|
62
62
|
lamindb/curators/_spatial.py,sha256=JgveK3aC1kFEplumEwU4Yyj-2tgHGfSAO52lHniJq5s,21212
|
63
63
|
lamindb/integrations/__init__.py,sha256=RWGMYYIzr8zvmNPyVB4m-p4gMDhxdRbjES2Ed23OItw,215
|
64
64
|
lamindb/integrations/_vitessce.py,sha256=nbfOsEO-W4f0BVnpFBDaA45577cfdvQehVx1hAUP544,3978
|
@@ -91,10 +91,11 @@ lamindb/migrations/0076_lamindbv1_part6.py,sha256=G_Wgog-OgquE0-h_CykjiDWUyPdYlC
|
|
91
91
|
lamindb/migrations/0077_lamindbv1_part6b.py,sha256=v7k8OZX9o5ppSJU_yhHlIXGTobTm30bo1dAIi8tUkEI,8211
|
92
92
|
lamindb/migrations/0078_lamindbv1_part6c.py,sha256=RWRXBwyyQ_rFTN5kwstBziV6tqHJcGYI2vsFmuYCCz0,17084
|
93
93
|
lamindb/migrations/0079_alter_rundata_value_json_and_more.py,sha256=yQmbs8yWrFLOVQJqAfzLNMZOqTSnXyG-mQgpO7ls1u8,995
|
94
|
+
lamindb/migrations/0080_polish_lamindbv1.py,sha256=VfCwJtHlBsMPIyFQ2oh24oWkiRXjDvXRpKe5fBZ63aM,17660
|
94
95
|
lamindb/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
95
96
|
lamindb/setup/__init__.py,sha256=OwZpZzPDv5lPPGXZP7-zK6UdO4FHvvuBh439yZvIp3A,410
|
96
97
|
lamindb/setup/core/__init__.py,sha256=SevlVrc2AZWL3uALbE5sopxBnIZPWZ1IB0NBDudiAL8,167
|
97
|
-
lamindb-1.0.
|
98
|
-
lamindb-1.0.
|
99
|
-
lamindb-1.0.
|
100
|
-
lamindb-1.0.
|
98
|
+
lamindb-1.0.3.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
99
|
+
lamindb-1.0.3.dist-info/WHEEL,sha256=CpUCUxeHQbRN5UGRQHYRJorO5Af-Qy_fHMctcQ8DSGI,82
|
100
|
+
lamindb-1.0.3.dist-info/METADATA,sha256=SoOQz-aPtNZiT7IUmNBqKeoj9PZgedTPwNPl_iRyftY,2611
|
101
|
+
lamindb-1.0.3.dist-info/RECORD,,
|
File without changes
|
File without changes
|