lamindb 0.74.1__py3-none-any.whl → 0.74.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/_parents.py CHANGED
@@ -5,12 +5,12 @@ from typing import TYPE_CHECKING
5
5
 
6
6
  import lamindb_setup as ln_setup
7
7
  from lamin_utils import logger
8
- from lnschema_core import Artifact, Collection, Registry, Run, Transform
8
+ from lnschema_core import Artifact, Collection, Record, Run, Transform
9
9
  from lnschema_core.models import HasParents, format_field_value
10
10
 
11
11
  from lamindb._utils import attach_func_to_class_method
12
12
 
13
- from ._registry import get_default_str_field
13
+ from ._record import get_default_str_field
14
14
 
15
15
  if TYPE_CHECKING:
16
16
  from lnschema_core.types import StrField
@@ -137,7 +137,7 @@ def view_lineage(data: Artifact | Collection, with_children: bool = True) -> Non
137
137
 
138
138
 
139
139
  def _view_parents(
140
- record: Registry, field: str, with_children: bool = False, distance: int = 100
140
+ record: Record, field: str, with_children: bool = False, distance: int = 100
141
141
  ):
142
142
  """Graph of parents."""
143
143
  if not hasattr(record, "parents"):
@@ -197,7 +197,7 @@ def _view_parents(
197
197
  _view(u)
198
198
 
199
199
 
200
- def _get_parents(record: Registry, field: str, distance: int, children: bool = False):
200
+ def _get_parents(record: Record, field: str, distance: int, children: bool = False):
201
201
  """Recursively get parent records within a distance."""
202
202
  if children:
203
203
  key = "parents"
@@ -228,7 +228,7 @@ def _get_parents(record: Registry, field: str, distance: int, children: bool = F
228
228
 
229
229
 
230
230
  def _df_edges_from_parents(
231
- record: Registry, field: str, distance: int, children: bool = False
231
+ record: Record, field: str, distance: int, children: bool = False
232
232
  ):
233
233
  """Construct a DataFrame of edges as the input of graphviz.Digraph."""
234
234
  key = "children" if children else "parents"
@@ -267,7 +267,7 @@ def _df_edges_from_parents(
267
267
  return df_edges
268
268
 
269
269
 
270
- def _record_label(record: Registry, field: str | None = None):
270
+ def _record_label(record: Record, field: str | None = None):
271
271
  if isinstance(record, Artifact):
272
272
  if record.description is None:
273
273
  name = record.key
@@ -311,7 +311,7 @@ def _record_label(record: Registry, field: str | None = None):
311
311
  )
312
312
 
313
313
 
314
- def _add_emoji(record: Registry, label: str):
314
+ def _add_emoji(record: Record, label: str):
315
315
  if record.__class__.__name__ == "Transform":
316
316
  emoji = TRANSFORM_EMOJIS.get(record.type, "💫")
317
317
  elif record.__class__.__name__ == "Run":
lamindb/_query_manager.py CHANGED
@@ -5,7 +5,7 @@ from typing import TYPE_CHECKING, NamedTuple
5
5
  from django.db import models
6
6
  from lamin_utils import logger
7
7
  from lamindb_setup.core._docs import doc_args
8
- from lnschema_core.models import Registry
8
+ from lnschema_core.models import Record
9
9
 
10
10
  from lamindb.core._settings import settings
11
11
 
@@ -84,17 +84,17 @@ class QueryManager(models.Manager):
84
84
  self._track_run_input_manager()
85
85
  return self._all_base_class()
86
86
 
87
- @doc_args(Registry.search.__doc__)
87
+ @doc_args(Record.search.__doc__)
88
88
  def search(self, string: str, **kwargs):
89
- """{}."""
90
- from ._registry import _search
89
+ """{}""" # noqa: D415
90
+ from ._record import _search
91
91
 
92
92
  return _search(cls=self.all(), string=string, **kwargs)
93
93
 
94
- @doc_args(Registry.lookup.__doc__)
94
+ @doc_args(Record.lookup.__doc__)
95
95
  def lookup(self, field: StrField | None = None, **kwargs) -> NamedTuple:
96
- """{}."""
97
- from ._registry import _lookup
96
+ """{}""" # noqa: D415
97
+ from ._record import _lookup
98
98
 
99
99
  return _lookup(cls=self.all(), field=field, **kwargs)
100
100
 
lamindb/_query_set.py CHANGED
@@ -12,7 +12,7 @@ from lnschema_core.models import (
12
12
  CanValidate,
13
13
  Collection,
14
14
  IsVersioned,
15
- Registry,
15
+ Record,
16
16
  Run,
17
17
  Transform,
18
18
  )
@@ -35,7 +35,7 @@ class MultipleResultsFound(Exception):
35
35
  # return (series + timedelta).dt.strftime("%Y-%m-%d %H:%M:%S %Z")
36
36
 
37
37
 
38
- def get_keys_from_df(data: list, registry: Registry) -> list[str]:
38
+ def get_keys_from_df(data: list, registry: Record) -> list[str]:
39
39
  if len(data) > 0:
40
40
  if isinstance(data[0], dict):
41
41
  keys = list(data[0].keys())
@@ -69,7 +69,7 @@ def one_helper(self):
69
69
  class RecordsList(UserList):
70
70
  """Is ordered, can't be queried, but has `.df()`."""
71
71
 
72
- def __init__(self, records: Iterable[Registry]):
72
+ def __init__(self, records: Iterable[Record]):
73
73
  super().__init__(record for record in records)
74
74
 
75
75
  def df(self) -> pd.DataFrame:
@@ -77,7 +77,7 @@ class RecordsList(UserList):
77
77
  values = [record.__dict__ for record in self.data]
78
78
  return pd.DataFrame(values, columns=keys)
79
79
 
80
- def one(self) -> Registry:
80
+ def one(self) -> Record:
81
81
  """Exactly one result. Throws error if there are more or none."""
82
82
  return one_helper(self)
83
83
 
@@ -96,11 +96,11 @@ class QuerySet(models.QuerySet, CanValidate):
96
96
  >>> queryset
97
97
  """
98
98
 
99
- @doc_args(Registry.df.__doc__)
99
+ @doc_args(Record.df.__doc__)
100
100
  def df(
101
101
  self, include: str | list[str] | None = None, join: str = "inner"
102
102
  ) -> pd.DataFrame:
103
- """{}."""
103
+ """{}""" # noqa: D415
104
104
  # re-order the columns
105
105
  exclude_field_names = ["created_at"]
106
106
  field_names = [
@@ -147,21 +147,21 @@ class QuerySet(models.QuerySet, CanValidate):
147
147
  lookup_str = "__".join(split[1:])
148
148
  else:
149
149
  lookup_str = "id"
150
- Registry = self.model
151
- field = getattr(Registry, field_name)
150
+ Record = self.model
151
+ field = getattr(Record, field_name)
152
152
  if isinstance(field.field, models.ManyToManyField):
153
153
  related_ORM = (
154
154
  field.field.model
155
- if field.field.model != Registry
155
+ if field.field.model != Record
156
156
  else field.field.related_model
157
157
  )
158
- if Registry == related_ORM:
159
- left_side_link_model = f"from_{Registry.__name__.lower()}"
158
+ if Record == related_ORM:
159
+ left_side_link_model = f"from_{Record.__name__.lower()}"
160
160
  values_expression = (
161
- f"to_{Registry.__name__.lower()}__{lookup_str}"
161
+ f"to_{Record.__name__.lower()}__{lookup_str}"
162
162
  )
163
163
  else:
164
- left_side_link_model = f"{Registry.__name__.lower()}"
164
+ left_side_link_model = f"{Record.__name__.lower()}"
165
165
  values_expression = (
166
166
  f"{related_ORM.__name__.lower()}__{lookup_str}"
167
167
  )
@@ -199,7 +199,7 @@ class QuerySet(models.QuerySet, CanValidate):
199
199
  else:
200
200
  self._delete_base_class(*args, **kwargs)
201
201
 
202
- def list(self, field: str | None = None) -> list[Registry]:
202
+ def list(self, field: str | None = None) -> list[Record]:
203
203
  """Populate a list with the results.
204
204
 
205
205
  Examples:
@@ -211,7 +211,7 @@ class QuerySet(models.QuerySet, CanValidate):
211
211
  else:
212
212
  return list(self.values_list(field, flat=True))
213
213
 
214
- def first(self) -> Registry | None:
214
+ def first(self) -> Record | None:
215
215
  """If non-empty, the first result in the query set, otherwise ``None``.
216
216
 
217
217
  Examples:
@@ -221,7 +221,7 @@ class QuerySet(models.QuerySet, CanValidate):
221
221
  return None
222
222
  return self[0]
223
223
 
224
- def one(self) -> Registry:
224
+ def one(self) -> Record:
225
225
  """Exactly one result. Raises error if there are more or none.
226
226
 
227
227
  Examples:
@@ -229,7 +229,7 @@ class QuerySet(models.QuerySet, CanValidate):
229
229
  """
230
230
  return one_helper(self)
231
231
 
232
- def one_or_none(self) -> Registry | None:
232
+ def one_or_none(self) -> Record | None:
233
233
  """At most one result. Returns it if there is one, otherwise returns ``None``.
234
234
 
235
235
  Examples:
@@ -248,32 +248,32 @@ class QuerySet(models.QuerySet, CanValidate):
248
248
  if issubclass(self.model, IsVersioned):
249
249
  return filter_query_set_by_latest_version(self)
250
250
  else:
251
- raise ValueError("Registry isn't subclass of `lamindb.core.IsVersioned`")
251
+ raise ValueError("Record isn't subclass of `lamindb.core.IsVersioned`")
252
252
 
253
- @doc_args(Registry.search.__doc__)
253
+ @doc_args(Record.search.__doc__)
254
254
  def search(self, string: str, **kwargs):
255
- """{}."""
256
- from ._registry import _search
255
+ """{}""" # noqa: D415
256
+ from ._record import _search
257
257
 
258
258
  return _search(cls=self, string=string, **kwargs)
259
259
 
260
- @doc_args(Registry.lookup.__doc__)
260
+ @doc_args(Record.lookup.__doc__)
261
261
  def lookup(self, field: StrField | None = None, **kwargs) -> NamedTuple:
262
- """{}."""
263
- from ._registry import _lookup
262
+ """{}""" # noqa: D415
263
+ from ._record import _lookup
264
264
 
265
265
  return _lookup(cls=self, field=field, **kwargs)
266
266
 
267
267
  @doc_args(CanValidate.validate.__doc__)
268
268
  def validate(self, values: ListLike, field: str | StrField | None = None, **kwargs):
269
- """{}."""
269
+ """{}""" # noqa: D415
270
270
  from ._can_validate import _validate
271
271
 
272
272
  return _validate(cls=self, values=values, field=field, **kwargs)
273
273
 
274
274
  @doc_args(CanValidate.inspect.__doc__)
275
275
  def inspect(self, values: ListLike, field: str | StrField | None = None, **kwargs):
276
- """{}."""
276
+ """{}""" # noqa: D415
277
277
  from ._can_validate import _inspect
278
278
 
279
279
  return _inspect(cls=self, values=values, field=field, **kwargs)
@@ -282,7 +282,7 @@ class QuerySet(models.QuerySet, CanValidate):
282
282
  def standardize(
283
283
  self, values: Iterable, field: str | StrField | None = None, **kwargs
284
284
  ):
285
- """{}."""
285
+ """{}""" # noqa: D415
286
286
  from ._can_validate import _standardize
287
287
 
288
288
  return _standardize(cls=self, values=values, field=field, **kwargs)
@@ -1,7 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import builtins
4
- from typing import TYPE_CHECKING, Iterable, List, NamedTuple
4
+ from typing import TYPE_CHECKING, List, NamedTuple
5
5
 
6
6
  import dj_database_url
7
7
  import lamindb_setup as ln_setup
@@ -12,7 +12,7 @@ from lamin_utils._lookup import Lookup
12
12
  from lamindb_setup._connect_instance import get_owner_name_from_identifier
13
13
  from lamindb_setup.core._docs import doc_args
14
14
  from lamindb_setup.core._hub_core import connect_instance
15
- from lnschema_core import Registry
15
+ from lnschema_core.models import IsVersioned, Record
16
16
 
17
17
  from lamindb._utils import attach_func_to_class_method
18
18
  from lamindb.core._settings import settings
@@ -20,12 +20,14 @@ from lamindb.core._settings import settings
20
20
  from ._from_values import get_or_create_records
21
21
 
22
22
  if TYPE_CHECKING:
23
+ import pandas as pd
23
24
  from lnschema_core.types import ListLike, StrField
24
25
 
26
+
25
27
  IPYTHON = getattr(builtins, "__IPYTHON__", False)
26
28
 
27
29
 
28
- def init_self_from_db(self: Registry, existing_record: Registry):
30
+ def init_self_from_db(self: Record, existing_record: Record):
29
31
  new_args = [
30
32
  getattr(existing_record, field.attname) for field in self._meta.concrete_fields
31
33
  ]
@@ -34,7 +36,7 @@ def init_self_from_db(self: Registry, existing_record: Registry):
34
36
  self._state.db = "default"
35
37
 
36
38
 
37
- def validate_required_fields(orm: Registry, kwargs):
39
+ def validate_required_fields(orm: Record, kwargs):
38
40
  required_fields = {
39
41
  k.name for k in orm._meta.fields if not k.null and k.default is None
40
42
  }
@@ -47,14 +49,16 @@ def validate_required_fields(orm: Registry, kwargs):
47
49
  raise TypeError(f"{missing_fields} are required.")
48
50
 
49
51
 
50
- def suggest_records_with_similar_names(record: Registry, kwargs) -> bool:
52
+ def suggest_records_with_similar_names(record: Record, kwargs) -> bool:
51
53
  """Returns True if found exact match, otherwise False.
52
54
 
53
55
  Logs similar matches if found.
54
56
  """
55
57
  if kwargs.get("name") is None:
56
58
  return False
57
- queryset = _search(record.__class__, kwargs["name"], truncate_words=True, limit=20)
59
+ queryset = _search(
60
+ record.__class__, kwargs["name"], field="name", truncate_words=True, limit=20
61
+ )
58
62
  if not queryset.exists(): # empty queryset
59
63
  return False
60
64
  for alternative_record in queryset:
@@ -73,7 +77,7 @@ def suggest_records_with_similar_names(record: Registry, kwargs) -> bool:
73
77
  return False
74
78
 
75
79
 
76
- def __init__(orm: Registry, *args, **kwargs):
80
+ def __init__(orm: Record, *args, **kwargs):
77
81
  if not args:
78
82
  validate_required_fields(orm, kwargs)
79
83
 
@@ -87,12 +91,12 @@ def __init__(orm: Registry, *args, **kwargs):
87
91
  if match:
88
92
  if "version" in kwargs:
89
93
  version_comment = " and version"
90
- existing_record = orm.filter(
94
+ existing_record = orm.__class__.filter(
91
95
  name=kwargs["name"], version=kwargs["version"]
92
96
  ).one_or_none()
93
97
  else:
94
98
  version_comment = ""
95
- existing_record = orm.filter(name=kwargs["name"]).one()
99
+ existing_record = orm.__class__.filter(name=kwargs["name"]).one()
96
100
  if existing_record is not None:
97
101
  logger.important(
98
102
  f"returning existing {orm.__class__.__name__} record with same"
@@ -100,27 +104,66 @@ def __init__(orm: Registry, *args, **kwargs):
100
104
  )
101
105
  init_self_from_db(orm, existing_record)
102
106
  return None
103
- super(Registry, orm).__init__(**kwargs)
107
+ super(Record, orm).__init__(**kwargs)
104
108
  elif len(args) != len(orm._meta.concrete_fields):
105
109
  raise ValueError("please provide keyword arguments, not plain arguments")
106
110
  else:
107
111
  # object is loaded from DB (**kwargs could be omitted below, I believe)
108
- super(Registry, orm).__init__(*args, **kwargs)
112
+ super(Record, orm).__init__(*args, **kwargs)
113
+
114
+
115
+ @classmethod # type:ignore
116
+ @doc_args(Record.filter.__doc__)
117
+ def filter(cls, **expressions) -> QuerySet:
118
+ """{}""" # noqa: D415
119
+ from lamindb._filter import filter
120
+
121
+ return filter(cls, **expressions)
122
+
123
+
124
+ @classmethod # type:ignore
125
+ @doc_args(Record.get.__doc__)
126
+ def get(cls, idlike: int | str) -> Record:
127
+ """{}""" # noqa: D415
128
+ from lamindb._filter import filter
129
+
130
+ if isinstance(idlike, int):
131
+ return filter(cls, id=idlike).one()
132
+ else:
133
+ qs = filter(cls, uid__startswith=idlike)
134
+ if issubclass(cls, IsVersioned):
135
+ return qs.latest_version().one()
136
+ else:
137
+ return qs.one()
138
+
139
+
140
+ @classmethod # type:ignore
141
+ @doc_args(Record.df.__doc__)
142
+ def df(
143
+ cls, include: str | list[str] | None = None, join: str = "inner"
144
+ ) -> pd.DataFrame:
145
+ """{}""" # noqa: D415
146
+ from lamindb._filter import filter
147
+
148
+ query_set = filter(cls)
149
+ if hasattr(cls, "updated_at"):
150
+ query_set = query_set.order_by("-updated_at")
151
+ return query_set.df(include=include, join=join)
109
152
 
110
153
 
111
154
  # from_values doesn't apply for QuerySet or Manager
112
155
  @classmethod # type:ignore
113
- @doc_args(Registry.from_values.__doc__)
156
+ @doc_args(Record.from_values.__doc__)
114
157
  def from_values(
115
158
  cls,
116
159
  values: ListLike,
117
160
  field: StrField | None = None,
118
161
  create: bool = False,
119
- organism: Registry | str | None = None,
120
- public_source: Registry | None = None,
162
+ organism: Record | str | None = None,
163
+ public_source: Record | None = None,
121
164
  mute: bool = False,
122
- ) -> list[Registry]:
123
- """{}."""
165
+ ) -> list[Record]:
166
+ """{}""" # noqa: D415
124
167
  from_public = True if cls.__module__.startswith("lnschema_bionty.") else False
125
168
  field_str = get_default_str_field(cls, field=field)
126
169
  return get_or_create_records(
@@ -134,14 +177,6 @@ def from_values(
134
177
  )
135
178
 
136
179
 
137
- # From: https://stackoverflow.com/a/37648265
138
- def _order_queryset_by_ids(queryset: QuerySet, ids: Iterable):
139
- from django.db.models import Case, When
140
-
141
- preserved = Case(*[When(uid=pk, then=pos) for pos, pk in enumerate(ids)])
142
- return queryset.filter(uid__in=ids).order_by(preserved)
143
-
144
-
145
180
  def _search(
146
181
  cls,
147
182
  string: str,
@@ -172,7 +207,7 @@ def _search(
172
207
  fields.append(field.field.name)
173
208
  except AttributeError as error:
174
209
  raise TypeError(
175
- "Please pass a Registry string field, e.g., `CellType.name`!"
210
+ "Please pass a Record string field, e.g., `CellType.name`!"
176
211
  ) from error
177
212
  else:
178
213
  fields.append(field)
@@ -187,7 +222,7 @@ def _search(
187
222
  else:
188
223
  return word
189
224
 
190
- decomposed_string = string.split()
225
+ decomposed_string = str(string).split()
191
226
  # add the entire string back
192
227
  decomposed_string += [string]
193
228
  for word in decomposed_string:
@@ -222,7 +257,7 @@ def _search(
222
257
 
223
258
 
224
259
  @classmethod # type: ignore
225
- @doc_args(Registry.search.__doc__)
260
+ @doc_args(Record.search.__doc__)
226
261
  def search(
227
262
  cls,
228
263
  string: str,
@@ -231,7 +266,7 @@ def search(
231
266
  limit: int | None = 20,
232
267
  case_sensitive: bool = False,
233
268
  ) -> QuerySet:
234
- """{}."""
269
+ """{}""" # noqa: D415
235
270
  return _search(
236
271
  cls=cls,
237
272
  string=string,
@@ -247,7 +282,7 @@ def _lookup(
247
282
  return_field: StrField | None = None,
248
283
  using_key: str | None = None,
249
284
  ) -> NamedTuple:
250
- """{}."""
285
+ """{}""" # noqa: D415
251
286
  queryset = _queryset(cls, using_key=using_key)
252
287
  field = get_default_str_field(orm=queryset.model, field=field)
253
288
 
@@ -266,18 +301,18 @@ def _lookup(
266
301
 
267
302
 
268
303
  @classmethod # type: ignore
269
- @doc_args(Registry.lookup.__doc__)
304
+ @doc_args(Record.lookup.__doc__)
270
305
  def lookup(
271
306
  cls,
272
307
  field: StrField | None = None,
273
308
  return_field: StrField | None = None,
274
309
  ) -> NamedTuple:
275
- """{}."""
310
+ """{}""" # noqa: D415
276
311
  return _lookup(cls=cls, field=field, return_field=return_field)
277
312
 
278
313
 
279
314
  def get_default_str_field(
280
- orm: Registry | QuerySet | Manager,
315
+ orm: Record | QuerySet | Manager,
281
316
  *,
282
317
  field: str | StrField | None = None,
283
318
  ) -> str:
@@ -307,7 +342,7 @@ def get_default_str_field(
307
342
  # no default field can be found
308
343
  if field is None:
309
344
  raise ValueError(
310
- "please pass a Registry string field, e.g., `CellType.name`!"
345
+ "please pass a Record string field, e.g., `CellType.name`!"
311
346
  )
312
347
  else:
313
348
  field = field.name # type:ignore
@@ -316,17 +351,20 @@ def get_default_str_field(
316
351
  field = field.field.name
317
352
  except AttributeError:
318
353
  raise TypeError(
319
- "please pass a Registry string field, e.g., `CellType.name`!"
354
+ "please pass a Record string field, e.g., `CellType.name`!"
320
355
  ) from None
321
356
 
322
357
  return field
323
358
 
324
359
 
325
- def _queryset(cls: Registry | QuerySet | Manager, using_key: str) -> QuerySet:
326
- queryset = (
327
- cls.all() if isinstance(cls, QuerySet) else cls.objects.using(using_key).all()
328
- )
329
- return queryset
360
+ def _queryset(cls: Record | QuerySet | Manager, using_key: str) -> QuerySet:
361
+ if isinstance(cls, (QuerySet, Manager)):
362
+ return cls.all()
363
+ elif using_key is None:
364
+ return cls.objects.all()
365
+ else:
366
+ # using must be called on cls, otherwise the connection isn't found
367
+ return cls.using(using_key).all()
330
368
 
331
369
 
332
370
  def add_db_connection(db: str, using: str):
@@ -340,12 +378,12 @@ def add_db_connection(db: str, using: str):
340
378
 
341
379
 
342
380
  @classmethod # type: ignore
343
- @doc_args(Registry.using.__doc__)
381
+ @doc_args(Record.using.__doc__)
344
382
  def using(
345
383
  cls,
346
384
  instance: str,
347
385
  ) -> QuerySet:
348
- """{}."""
386
+ """{}""" # noqa: D415
349
387
  from lamindb_setup._connect_instance import (
350
388
  load_instance_settings,
351
389
  update_db_using_local,
@@ -378,7 +416,7 @@ REGISTRY_UNIQUE_FIELD = {
378
416
 
379
417
 
380
418
  def update_fk_to_default_db(
381
- records: Registry | list[Registry] | QuerySet,
419
+ records: Record | list[Record] | QuerySet,
382
420
  fk: str,
383
421
  using_key: str | None,
384
422
  ):
@@ -418,12 +456,12 @@ def transfer_fk_to_default_db_bulk(records: list | QuerySet, using_key: str | No
418
456
 
419
457
 
420
458
  def transfer_to_default_db(
421
- record: Registry,
459
+ record: Record,
422
460
  using_key: str | None,
423
461
  save: bool = False,
424
462
  mute: bool = False,
425
463
  transfer_fk: bool = True,
426
- ) -> Registry | None:
464
+ ) -> Record | None:
427
465
  db = record._state.db
428
466
  if db is not None and db != "default" and using_key is None:
429
467
  registry = record.__class__
@@ -476,7 +514,7 @@ def transfer_to_default_db(
476
514
 
477
515
 
478
516
  # docstring handled through attach_func_to_class_method
479
- def save(self, *args, **kwargs) -> Registry:
517
+ def save(self, *args, **kwargs) -> Record:
480
518
  using_key = None
481
519
  if "using" in kwargs:
482
520
  using_key = kwargs["using"]
@@ -491,12 +529,7 @@ def save(self, *args, **kwargs) -> Registry:
491
529
  if result is not None:
492
530
  init_self_from_db(self, result)
493
531
  else:
494
- # here, we can't use the parents argument
495
- # parents are not saved for the self record
496
- save_kwargs = kwargs.copy()
497
- if "parents" in save_kwargs:
498
- save_kwargs.pop("parents")
499
- super(Registry, self).save(*args, **save_kwargs)
532
+ super(Record, self).save(*args, **kwargs)
500
533
  # perform transfer of many-to-many fields
501
534
  # only supported for Artifact and Collection records
502
535
  if db is not None and db != "default" and using_key is None:
@@ -516,21 +549,16 @@ def save(self, *args, **kwargs) -> Registry:
516
549
  self_on_db._state.db = db
517
550
  self_on_db.pk = pk_on_db # manually set the primary key
518
551
  self_on_db.features = FeatureManager(self_on_db)
519
- # by default, transfer parents of the labels to maintain ontological hierarchy
520
- try:
521
- import bionty as bt
522
-
523
- parents = kwargs.get("parents", bt.settings.auto_save_parents)
524
- except ImportError:
525
- parents = kwargs.get("parents", True)
526
- add_from_kwargs = {"parents": parents}
527
- self.features._add_from(self_on_db, **add_from_kwargs)
528
- self.labels.add_from(self_on_db, **add_from_kwargs)
552
+ self.features._add_from(self_on_db)
553
+ self.labels.add_from(self_on_db)
529
554
  return self
530
555
 
531
556
 
532
557
  METHOD_NAMES = [
533
558
  "__init__",
559
+ "filter",
560
+ "get",
561
+ "df",
534
562
  "search",
535
563
  "lookup",
536
564
  "save",
@@ -542,10 +570,10 @@ if ln_setup._TESTING: # type: ignore
542
570
  from inspect import signature
543
571
 
544
572
  SIGS = {
545
- name: signature(getattr(Registry, name))
573
+ name: signature(getattr(Record, name))
546
574
  for name in METHOD_NAMES
547
575
  if not name.startswith("__")
548
576
  }
549
577
 
550
578
  for name in METHOD_NAMES:
551
- attach_func_to_class_method(name, Registry, globals())
579
+ attach_func_to_class_method(name, Record, globals())