lamindb 1.6.2__py3-none-any.whl → 1.7.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- lamindb/__init__.py +1 -3
- lamindb/_finish.py +32 -16
- lamindb/base/types.py +6 -4
- lamindb/core/_context.py +127 -57
- lamindb/core/_mapped_collection.py +1 -1
- lamindb/core/_settings.py +44 -4
- lamindb/core/_track_environment.py +5 -2
- lamindb/core/loaders.py +1 -1
- lamindb/core/storage/_anndata_accessor.py +1 -1
- lamindb/core/storage/_tiledbsoma.py +14 -8
- lamindb/core/storage/_valid_suffixes.py +0 -1
- lamindb/core/storage/_zarr.py +1 -1
- lamindb/core/storage/objects.py +13 -8
- lamindb/core/storage/paths.py +9 -6
- lamindb/core/types.py +1 -1
- lamindb/curators/_legacy.py +2 -1
- lamindb/curators/core.py +106 -105
- lamindb/errors.py +9 -0
- lamindb/examples/fixtures/__init__.py +0 -0
- lamindb/examples/fixtures/sheets.py +224 -0
- lamindb/migrations/0103_remove_writelog_migration_state_and_more.py +1 -1
- lamindb/migrations/0105_record_unique_name.py +20 -0
- lamindb/migrations/0106_transfer_data_migration.py +25 -0
- lamindb/migrations/0107_add_schema_to_record.py +68 -0
- lamindb/migrations/0108_remove_record_sheet_remove_sheetproject_sheet_and_more.py +30 -0
- lamindb/migrations/0109_record_input_of_runs_alter_record_run_and_more.py +123 -0
- lamindb/migrations/0110_rename_values_artifacts_record_linked_artifacts.py +17 -0
- lamindb/migrations/0111_remove_record__sort_order.py +148 -0
- lamindb/migrations/0112_alter_recordartifact_feature_and_more.py +105 -0
- lamindb/migrations/0113_lower_case_branch_and_space_names.py +62 -0
- lamindb/migrations/0114_alter_run__status_code.py +24 -0
- lamindb/migrations/0115_alter_space_uid.py +52 -0
- lamindb/migrations/{0104_squashed.py → 0115_squashed.py} +261 -257
- lamindb/models/__init__.py +4 -3
- lamindb/models/_describe.py +88 -31
- lamindb/models/_feature_manager.py +627 -658
- lamindb/models/_label_manager.py +1 -3
- lamindb/models/artifact.py +214 -99
- lamindb/models/collection.py +7 -1
- lamindb/models/feature.py +288 -60
- lamindb/models/has_parents.py +3 -3
- lamindb/models/project.py +32 -15
- lamindb/models/query_manager.py +7 -1
- lamindb/models/query_set.py +118 -41
- lamindb/models/record.py +140 -94
- lamindb/models/run.py +42 -42
- lamindb/models/save.py +102 -16
- lamindb/models/schema.py +41 -8
- lamindb/models/sqlrecord.py +105 -40
- lamindb/models/storage.py +278 -0
- lamindb/models/transform.py +10 -2
- lamindb/models/ulabel.py +9 -1
- lamindb/py.typed +0 -0
- lamindb/setup/__init__.py +2 -1
- lamindb/setup/_switch.py +16 -0
- lamindb/setup/errors/__init__.py +4 -0
- lamindb/setup/types/__init__.py +4 -0
- {lamindb-1.6.2.dist-info → lamindb-1.7.0.dist-info}/METADATA +5 -5
- {lamindb-1.6.2.dist-info → lamindb-1.7.0.dist-info}/RECORD +61 -44
- lamindb/models/core.py +0 -135
- {lamindb-1.6.2.dist-info → lamindb-1.7.0.dist-info}/LICENSE +0 -0
- {lamindb-1.6.2.dist-info → lamindb-1.7.0.dist-info}/WHEEL +0 -0
lamindb/models/record.py
CHANGED
@@ -4,6 +4,7 @@ from typing import TYPE_CHECKING, Any, overload
|
|
4
4
|
|
5
5
|
from django.db import models
|
6
6
|
from django.db.models import CASCADE, PROTECT
|
7
|
+
from lamin_utils import logger
|
7
8
|
|
8
9
|
from lamindb.base.fields import (
|
9
10
|
BooleanField,
|
@@ -13,21 +14,29 @@ from lamindb.base.fields import (
|
|
13
14
|
)
|
14
15
|
from lamindb.errors import FieldValidationError
|
15
16
|
|
16
|
-
from ..base.ids import
|
17
|
+
from ..base.ids import base62_16
|
17
18
|
from .artifact import Artifact
|
18
19
|
from .can_curate import CanCurate
|
19
20
|
from .feature import Feature
|
21
|
+
from .has_parents import _query_relatives
|
22
|
+
from .query_set import reorder_subset_columns_in_df
|
20
23
|
from .run import Run, TracksRun, TracksUpdates
|
21
24
|
from .sqlrecord import BaseSQLRecord, IsLink, SQLRecord, _get_record_kwargs
|
25
|
+
from .transform import Transform
|
22
26
|
from .ulabel import ULabel
|
23
27
|
|
24
28
|
if TYPE_CHECKING:
|
25
|
-
|
29
|
+
import pandas as pd
|
30
|
+
|
31
|
+
from .project import Person, Project, Reference
|
32
|
+
from .query_set import QuerySet
|
26
33
|
from .schema import Schema
|
27
34
|
|
28
35
|
|
29
36
|
class Record(SQLRecord, CanCurate, TracksRun, TracksUpdates):
|
30
|
-
"""Flexible records
|
37
|
+
"""Flexible records as you find them in Excel-like sheets.
|
38
|
+
|
39
|
+
Useful register, e.g., samples, donors, cells, compounds, sequences.
|
31
40
|
|
32
41
|
This is currently more convenient to use through the UI.
|
33
42
|
|
@@ -39,12 +48,8 @@ class Record(SQLRecord, CanCurate, TracksRun, TracksUpdates):
|
|
39
48
|
description: `str` A description.
|
40
49
|
|
41
50
|
See Also:
|
42
|
-
:meth:`~lamindb.Sheet`
|
43
|
-
Sheets to group records.
|
44
51
|
:meth:`~lamindb.Feature`
|
45
|
-
Dimensions of measurement.
|
46
|
-
:attr:`~lamindb.Artifact.features`
|
47
|
-
Feature manager for an artifact.
|
52
|
+
Dimensions of measurement (e.g. column of a sheet).
|
48
53
|
"""
|
49
54
|
|
50
55
|
class Meta(SQLRecord.Meta, TracksRun.Meta, TracksUpdates.Meta):
|
@@ -67,11 +72,20 @@ class Record(SQLRecord, CanCurate, TracksRun, TracksUpdates):
|
|
67
72
|
"""
|
68
73
|
records: Record
|
69
74
|
"""Records of this type (can only be non-empty if `is_type` is `True`)."""
|
70
|
-
is_type: bool = BooleanField(default=False, db_index=True
|
71
|
-
"""
|
75
|
+
is_type: bool = BooleanField(default=False, db_index=True)
|
76
|
+
"""Indicates if record is a `type`.
|
72
77
|
|
73
78
|
For example, if a record "Compound" is a `type`, the actual compounds "darerinib", "tramerinib", would be instances of that `type`.
|
74
79
|
"""
|
80
|
+
schema: Schema | None = ForeignKey(
|
81
|
+
"Schema", CASCADE, null=True, related_name="records"
|
82
|
+
)
|
83
|
+
"""A schema to enforce for a type (optional).
|
84
|
+
|
85
|
+
This is mostly parallel to the `schema` attribute of `Artifact`.
|
86
|
+
|
87
|
+
If `is_type` is `True`, the schema is used to enforce certain features for each records of this type.
|
88
|
+
"""
|
75
89
|
# naming convention in analogy with Schema
|
76
90
|
components: Record = models.ManyToManyField(
|
77
91
|
"Record", through="RecordRecord", symmetrical=False, related_name="composites"
|
@@ -79,26 +93,43 @@ class Record(SQLRecord, CanCurate, TracksRun, TracksUpdates):
|
|
79
93
|
"""Record-like components of this record."""
|
80
94
|
composites: Record
|
81
95
|
"""Record-like composites of this record."""
|
82
|
-
sheet: Sheet | None = ForeignKey(
|
83
|
-
"Sheet", CASCADE, null=True, related_name="records"
|
84
|
-
)
|
85
|
-
"""Group records by sheet."""
|
86
96
|
description: str | None = CharField(null=True)
|
87
97
|
"""A description (optional)."""
|
88
|
-
|
89
|
-
Artifact, through="RecordArtifact", related_name="
|
98
|
+
linked_artifacts: Artifact = models.ManyToManyField(
|
99
|
+
Artifact, through="RecordArtifact", related_name="linked_in_records"
|
90
100
|
)
|
91
101
|
"""Linked artifacts."""
|
92
|
-
|
102
|
+
artifacts: Artifact = models.ManyToManyField(
|
103
|
+
Artifact, through="ArtifactRecord", related_name="records"
|
104
|
+
)
|
105
|
+
"""Annotated artifacts."""
|
106
|
+
linked_runs: Run = models.ManyToManyField(
|
107
|
+
Run, through="RecordRun", related_name="records"
|
108
|
+
)
|
93
109
|
"""Linked runs."""
|
110
|
+
run: Run | None = ForeignKey(
|
111
|
+
Run,
|
112
|
+
PROTECT,
|
113
|
+
related_name="output_records",
|
114
|
+
null=True,
|
115
|
+
default=None,
|
116
|
+
editable=False,
|
117
|
+
)
|
118
|
+
"""Run that created the record."""
|
119
|
+
input_of_runs: Run = models.ManyToManyField(Run, related_name="input_records")
|
120
|
+
"""Runs that use this record as an input."""
|
94
121
|
ulabels: ULabel = models.ManyToManyField(
|
95
122
|
ULabel,
|
96
123
|
through="RecordULabel",
|
97
124
|
related_name="_records", # in transition period
|
98
125
|
)
|
99
126
|
"""Linked runs."""
|
100
|
-
|
127
|
+
linked_projects: Project
|
101
128
|
"""Linked projects."""
|
129
|
+
linked_references: Reference
|
130
|
+
"""Linked references."""
|
131
|
+
linked_people: Person
|
132
|
+
"""Linked people."""
|
102
133
|
|
103
134
|
@overload
|
104
135
|
def __init__(
|
@@ -128,10 +159,14 @@ class Record(SQLRecord, CanCurate, TracksRun, TracksUpdates):
|
|
128
159
|
name: str = kwargs.pop("name", None)
|
129
160
|
type: str | None = kwargs.pop("type", None)
|
130
161
|
is_type: bool = kwargs.pop("is_type", False)
|
131
|
-
sheet: Sheet = kwargs.pop("sheet", None)
|
132
162
|
description: str | None = kwargs.pop("description", None)
|
163
|
+
schema = kwargs.pop("schema", None)
|
164
|
+
branch = kwargs.pop("branch", None)
|
165
|
+
branch_id = kwargs.pop("branch_id", 1)
|
166
|
+
space = kwargs.pop("space", None)
|
167
|
+
space_id = kwargs.pop("space_id", 1)
|
133
168
|
_skip_validation = kwargs.pop(
|
134
|
-
"_skip_validation",
|
169
|
+
"_skip_validation", False
|
135
170
|
) # should not validate records
|
136
171
|
_aux = kwargs.pop("_aux", None)
|
137
172
|
if len(kwargs) > 0:
|
@@ -139,90 +174,85 @@ class Record(SQLRecord, CanCurate, TracksRun, TracksUpdates):
|
|
139
174
|
raise FieldValidationError(
|
140
175
|
f"Only {valid_keywords} are valid keyword arguments"
|
141
176
|
)
|
177
|
+
if schema and not is_type:
|
178
|
+
logger.important("passing schema, treating as type")
|
179
|
+
is_type = True
|
142
180
|
super().__init__(
|
143
181
|
name=name,
|
144
182
|
type=type,
|
145
183
|
is_type=is_type,
|
146
|
-
sheet=sheet,
|
147
184
|
description=description,
|
185
|
+
schema=schema,
|
186
|
+
branch=branch,
|
187
|
+
branch_id=branch_id,
|
188
|
+
space=space,
|
189
|
+
space_id=space_id,
|
148
190
|
_skip_validation=_skip_validation,
|
149
191
|
_aux=_aux,
|
150
192
|
)
|
151
193
|
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
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,
|
194
|
+
@property
|
195
|
+
def is_form(self) -> bool:
|
196
|
+
"""Check if record is a form (a record type with a validating schema)."""
|
197
|
+
return self.schema is not None and self.is_type
|
198
|
+
|
199
|
+
def query_children(self) -> QuerySet:
|
200
|
+
"""Query all children of a record type recursively.
|
201
|
+
|
202
|
+
While `.records` retrieves the direct children, this method
|
203
|
+
retrieves all descendants of a record type.
|
204
|
+
"""
|
205
|
+
return _query_relatives([self], "records", self.__class__) # type: ignore
|
206
|
+
|
207
|
+
def to_pandas(self) -> pd.DataFrame:
|
208
|
+
"""Export all children of a record type recursively to a pandas DataFrame."""
|
209
|
+
assert self.is_type, "Only types can be exported as dataframes" # noqa: S101
|
210
|
+
df = self.query_children().df(features="queryset")
|
211
|
+
df.columns.values[0] = "__lamindb_record_uid__"
|
212
|
+
df.columns.values[1] = "__lamindb_record_name__"
|
213
|
+
if self.schema is not None:
|
214
|
+
desired_order = self.schema.members.list("name") # only members is ordered!
|
215
|
+
else:
|
216
|
+
# sort alphabetically for now
|
217
|
+
desired_order = df.columns[2:].tolist()
|
218
|
+
desired_order.sort()
|
219
|
+
df = reorder_subset_columns_in_df(df, desired_order, position=0) # type: ignore
|
220
|
+
return df.sort_index() # order by id for now
|
221
|
+
|
222
|
+
def to_artifact(self, key: str = None) -> Artifact:
|
223
|
+
"""Export all children of a record type as a `.csv` artifact."""
|
224
|
+
from lamindb.core._context import context
|
225
|
+
|
226
|
+
assert self.is_type, "Only types can be exported as artifacts" # noqa: S101
|
227
|
+
if key is None:
|
228
|
+
file_suffix = ".csv"
|
229
|
+
key = f"sheet_exports/{self.name}{file_suffix}"
|
230
|
+
description = f": {self.description}" if self.description is not None else ""
|
231
|
+
format: dict[str, Any] = {"suffix": ".csv"} if key.endswith(".csv") else {}
|
232
|
+
format["index"] = False
|
233
|
+
transform, _ = Transform.objects.get_or_create(
|
234
|
+
key="__lamindb_record_export__", type="function"
|
215
235
|
)
|
236
|
+
run = Run(transform, initiated_by_run=context.run).save()
|
237
|
+
run.input_records.add(self)
|
238
|
+
return Artifact.from_df(
|
239
|
+
self.to_pandas(),
|
240
|
+
key=key,
|
241
|
+
description=f"Export of sheet {self.uid}{description}",
|
242
|
+
schema=self.schema,
|
243
|
+
format=format,
|
244
|
+
run=run,
|
245
|
+
).save()
|
216
246
|
|
217
247
|
|
218
248
|
class RecordJson(BaseSQLRecord, IsLink):
|
219
249
|
id: int = models.BigAutoField(primary_key=True)
|
220
250
|
record: Record = ForeignKey(Record, CASCADE, related_name="values_json")
|
221
|
-
feature: Feature = ForeignKey(Feature,
|
251
|
+
feature: Feature = ForeignKey(Feature, PROTECT, related_name="links_recordjson")
|
222
252
|
value: Any = JSONField(default=None, db_default=None)
|
223
253
|
|
224
254
|
class Meta:
|
225
|
-
unique_together = ("record", "feature")
|
255
|
+
unique_together = ("record", "feature") # a list is modeled as a list in json
|
226
256
|
|
227
257
|
|
228
258
|
class RecordRecord(SQLRecord, IsLink):
|
@@ -230,43 +260,59 @@ class RecordRecord(SQLRecord, IsLink):
|
|
230
260
|
record: Record = ForeignKey(
|
231
261
|
Record, CASCADE, related_name="values_record"
|
232
262
|
) # composite
|
233
|
-
feature: Feature = ForeignKey(Feature,
|
263
|
+
feature: Feature = ForeignKey(Feature, PROTECT, related_name="links_recordrecord")
|
234
264
|
value: Record = ForeignKey(
|
235
265
|
Record, PROTECT, related_name="links_record"
|
236
266
|
) # component
|
237
267
|
|
238
268
|
class Meta:
|
239
|
-
unique_together = ("record", "feature")
|
269
|
+
unique_together = ("record", "feature", "value")
|
240
270
|
|
241
271
|
|
242
272
|
class RecordULabel(BaseSQLRecord, IsLink):
|
243
273
|
id: int = models.BigAutoField(primary_key=True)
|
244
274
|
record: Record = ForeignKey(Record, CASCADE, related_name="values_ulabel")
|
245
|
-
feature: Feature = ForeignKey(Feature,
|
275
|
+
feature: Feature = ForeignKey(Feature, PROTECT, related_name="links_recordulabel")
|
246
276
|
value: ULabel = ForeignKey(ULabel, PROTECT, related_name="links_record")
|
247
277
|
|
248
278
|
class Meta:
|
249
279
|
# allows linking exactly one record to one ulabel per feature, because we likely don't want to have Many
|
250
|
-
unique_together = ("record", "feature")
|
280
|
+
unique_together = ("record", "feature", "value")
|
251
281
|
|
252
282
|
|
253
283
|
class RecordRun(BaseSQLRecord, IsLink):
|
254
284
|
id: int = models.BigAutoField(primary_key=True)
|
255
285
|
record: Record = ForeignKey(Record, CASCADE, related_name="values_run")
|
256
|
-
feature: Feature = ForeignKey(Feature,
|
286
|
+
feature: Feature = ForeignKey(Feature, PROTECT, related_name="links_recordrun")
|
257
287
|
value: Run = ForeignKey(Run, PROTECT, related_name="links_record")
|
258
288
|
|
259
289
|
class Meta:
|
260
290
|
# allows linking several records to a single run for the same feature because we'll likely need this
|
261
|
-
unique_together = ("record", "feature")
|
291
|
+
unique_together = ("record", "feature", "value")
|
262
292
|
|
263
293
|
|
264
294
|
class RecordArtifact(BaseSQLRecord, IsLink):
|
265
295
|
id: int = models.BigAutoField(primary_key=True)
|
266
296
|
record: Record = ForeignKey(Record, CASCADE, related_name="values_artifact")
|
267
|
-
feature: Feature = ForeignKey(Feature,
|
268
|
-
value: Artifact = ForeignKey(Artifact, PROTECT, related_name="
|
297
|
+
feature: Feature = ForeignKey(Feature, PROTECT, related_name="links_recordartifact")
|
298
|
+
value: Artifact = ForeignKey(Artifact, PROTECT, related_name="links_in_record")
|
269
299
|
|
270
300
|
class Meta:
|
271
301
|
# allows linking several records to a single artifact for the same feature because we'll likely need this
|
272
302
|
unique_together = ("record", "feature", "value")
|
303
|
+
|
304
|
+
|
305
|
+
# like ArtifactULabel, for annotation
|
306
|
+
class ArtifactRecord(BaseSQLRecord, IsLink):
|
307
|
+
id: int = models.BigAutoField(primary_key=True)
|
308
|
+
artifact: Artifact = ForeignKey(Artifact, CASCADE, related_name="links_record")
|
309
|
+
record: Record = ForeignKey(Record, PROTECT, related_name="links_artifact")
|
310
|
+
feature: Feature = ForeignKey(
|
311
|
+
Feature, PROTECT, null=True, related_name="links_artifactrecord"
|
312
|
+
)
|
313
|
+
label_ref_is_name: bool | None = BooleanField(null=True)
|
314
|
+
feature_ref_is_name: bool | None = BooleanField(null=True)
|
315
|
+
|
316
|
+
class Meta:
|
317
|
+
# allows linking several records to a single artifact for the same feature because we'll likely need this
|
318
|
+
unique_together = ("artifact", "record", "feature")
|
lamindb/models/run.py
CHANGED
@@ -27,11 +27,13 @@ from .sqlrecord import BaseSQLRecord, IsLink, SQLRecord
|
|
27
27
|
if TYPE_CHECKING:
|
28
28
|
from datetime import datetime
|
29
29
|
|
30
|
+
from ._feature_manager import FeatureManager
|
30
31
|
from .artifact import Artifact
|
31
32
|
from .collection import Collection
|
32
33
|
from .feature import FeatureValue
|
33
34
|
from .project import Project
|
34
35
|
from .query_set import QuerySet
|
36
|
+
from .record import Record
|
35
37
|
from .transform import Transform
|
36
38
|
from .ulabel import ULabel
|
37
39
|
|
@@ -39,18 +41,6 @@ if TYPE_CHECKING:
|
|
39
41
|
_TRACKING_READY: bool | None = None
|
40
42
|
|
41
43
|
|
42
|
-
class FeatureManager:
|
43
|
-
"""Feature manager."""
|
44
|
-
|
45
|
-
pass
|
46
|
-
|
47
|
-
|
48
|
-
class FeatureManagerRun(FeatureManager):
|
49
|
-
"""Feature manager."""
|
50
|
-
|
51
|
-
pass
|
52
|
-
|
53
|
-
|
54
44
|
def current_run() -> Run | None:
|
55
45
|
global _TRACKING_READY
|
56
46
|
|
@@ -206,12 +196,13 @@ class Run(SQLRecord):
|
|
206
196
|
|
207
197
|
Args:
|
208
198
|
transform: `Transform` A :class:`~lamindb.Transform` record.
|
199
|
+
initiated_by_run: `Run | None = None` The run that triggers this run.
|
209
200
|
reference: `str | None = None` For instance, an external ID or a download URL.
|
210
201
|
reference_type: `str | None = None` For instance, `redun_id`, `nextflow_id` or `url`.
|
211
202
|
|
212
203
|
See Also:
|
213
|
-
:
|
214
|
-
|
204
|
+
:func:`~lamindb.track`
|
205
|
+
Globally track a script or notebook run.
|
215
206
|
|
216
207
|
Examples:
|
217
208
|
|
@@ -234,26 +225,6 @@ class Run(SQLRecord):
|
|
234
225
|
|
235
226
|
_name_field: str = "started_at"
|
236
227
|
|
237
|
-
features: FeatureManager = FeatureManagerRun # type: ignore
|
238
|
-
"""Features manager.
|
239
|
-
|
240
|
-
Run parameters are tracked via the `Feature` registry, just like all other variables.
|
241
|
-
|
242
|
-
Guide: :ref:`track-run-parameters`
|
243
|
-
|
244
|
-
Example::
|
245
|
-
|
246
|
-
run.features.add_values({
|
247
|
-
"learning_rate": 0.01,
|
248
|
-
"input_dir": "s3://my-bucket/mydataset",
|
249
|
-
"downsample": True,
|
250
|
-
"preprocess_params": {
|
251
|
-
"normalization_type": "cool",
|
252
|
-
"subset_highlyvariable": True,
|
253
|
-
},
|
254
|
-
})
|
255
|
-
"""
|
256
|
-
|
257
228
|
id: int = models.BigAutoField(primary_key=True)
|
258
229
|
"""Internal id, valid only in one DB instance."""
|
259
230
|
# default uid was changed from base62_20 to base62_16 in 1.6.0
|
@@ -302,6 +273,10 @@ class Run(SQLRecord):
|
|
302
273
|
"""The collections serving as input for this run."""
|
303
274
|
output_collections: Collection
|
304
275
|
"""The collections generated by this run."""
|
276
|
+
input_records: Record
|
277
|
+
"""The collections serving as input for this run."""
|
278
|
+
output_records: Record
|
279
|
+
"""The collections generated by this run."""
|
305
280
|
"""Parameter values."""
|
306
281
|
_feature_values: FeatureValue = models.ManyToManyField(
|
307
282
|
"FeatureValue", through="RunFeatureValue", related_name="runs"
|
@@ -338,14 +313,15 @@ class Run(SQLRecord):
|
|
338
313
|
"""Linked projects."""
|
339
314
|
_is_consecutive: bool | None = BooleanField(null=True)
|
340
315
|
"""Indicates whether code was consecutively executed. Is relevant for notebooks."""
|
341
|
-
_status_code: int = models.SmallIntegerField(default=
|
316
|
+
_status_code: int = models.SmallIntegerField(default=None, db_index=True, null=True)
|
342
317
|
"""Status code of the run.
|
343
318
|
|
344
|
-
-
|
345
|
-
-
|
346
|
-
-
|
347
|
-
-
|
348
|
-
-
|
319
|
+
- -3: scheduled
|
320
|
+
- -2: re-started
|
321
|
+
- -1: started
|
322
|
+
- 0: completed
|
323
|
+
- 1: errored
|
324
|
+
- 2: aborted
|
349
325
|
"""
|
350
326
|
|
351
327
|
@overload
|
@@ -354,6 +330,7 @@ class Run(SQLRecord):
|
|
354
330
|
transform: Transform,
|
355
331
|
reference: str | None = None,
|
356
332
|
reference_type: str | None = None,
|
333
|
+
initiated_by_run: Run | None = None,
|
357
334
|
): ...
|
358
335
|
|
359
336
|
@overload
|
@@ -367,7 +344,6 @@ class Run(SQLRecord):
|
|
367
344
|
*args,
|
368
345
|
**kwargs,
|
369
346
|
):
|
370
|
-
self.features = FeatureManager(self) # type: ignore
|
371
347
|
if len(args) == len(self._meta.concrete_fields):
|
372
348
|
super().__init__(*args, **kwargs)
|
373
349
|
return None
|
@@ -402,6 +378,30 @@ class Run(SQLRecord):
|
|
402
378
|
def params(self) -> FeatureManager:
|
403
379
|
return self.features
|
404
380
|
|
381
|
+
@property
|
382
|
+
def features(self) -> FeatureManager:
|
383
|
+
"""Features manager.
|
384
|
+
|
385
|
+
Run parameters are tracked via the `Feature` registry, just like all other variables.
|
386
|
+
|
387
|
+
Guide: :ref:`track-run-parameters`
|
388
|
+
|
389
|
+
Example::
|
390
|
+
|
391
|
+
run.features.add_values({
|
392
|
+
"learning_rate": 0.01,
|
393
|
+
"input_dir": "s3://my-bucket/mydataset",
|
394
|
+
"downsample": True,
|
395
|
+
"preprocess_params": {
|
396
|
+
"normalization_type": "cool",
|
397
|
+
"subset_highlyvariable": True,
|
398
|
+
},
|
399
|
+
})
|
400
|
+
"""
|
401
|
+
from ._feature_manager import FeatureManager
|
402
|
+
|
403
|
+
return FeatureManager(self)
|
404
|
+
|
405
405
|
@classmethod
|
406
406
|
def filter(
|
407
407
|
cls,
|
@@ -441,7 +441,7 @@ class Run(SQLRecord):
|
|
441
441
|
keys_normalized, field="name", mute=True
|
442
442
|
)
|
443
443
|
):
|
444
|
-
return filter_base(
|
444
|
+
return filter_base(Run, **expressions)
|
445
445
|
else:
|
446
446
|
params = ", ".join(sorted(np.array(keys_normalized)[~params_validated]))
|
447
447
|
message = f"feature names: {params}"
|