lamindb 1.1.1__py3-none-any.whl → 1.2.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.
Files changed (66) hide show
  1. lamindb/__init__.py +30 -25
  2. lamindb/_tracked.py +1 -1
  3. lamindb/_view.py +2 -3
  4. lamindb/base/__init__.py +1 -1
  5. lamindb/base/ids.py +1 -10
  6. lamindb/core/__init__.py +7 -65
  7. lamindb/core/_compat.py +60 -0
  8. lamindb/core/_context.py +43 -20
  9. lamindb/core/_settings.py +6 -6
  10. lamindb/core/_sync_git.py +1 -1
  11. lamindb/core/loaders.py +30 -19
  12. lamindb/core/storage/_backed_access.py +4 -2
  13. lamindb/core/storage/_tiledbsoma.py +8 -6
  14. lamindb/core/storage/_zarr.py +104 -25
  15. lamindb/core/storage/objects.py +63 -28
  16. lamindb/core/storage/paths.py +4 -1
  17. lamindb/core/types.py +10 -0
  18. lamindb/curators/__init__.py +100 -85
  19. lamindb/errors.py +1 -1
  20. lamindb/integrations/_vitessce.py +4 -4
  21. lamindb/migrations/0089_subsequent_runs.py +159 -0
  22. lamindb/migrations/0090_runproject_project_runs.py +73 -0
  23. lamindb/migrations/{0088_squashed.py → 0090_squashed.py} +245 -177
  24. lamindb/models/__init__.py +79 -0
  25. lamindb/{core → models}/_describe.py +3 -3
  26. lamindb/{core → models}/_django.py +8 -5
  27. lamindb/{core → models}/_feature_manager.py +103 -87
  28. lamindb/{_from_values.py → models/_from_values.py} +5 -2
  29. lamindb/{core/versioning.py → models/_is_versioned.py} +94 -6
  30. lamindb/{core → models}/_label_manager.py +10 -17
  31. lamindb/{core/relations.py → models/_relations.py} +8 -1
  32. lamindb/models/artifact.py +2602 -0
  33. lamindb/{_can_curate.py → models/can_curate.py} +349 -180
  34. lamindb/models/collection.py +683 -0
  35. lamindb/models/core.py +135 -0
  36. lamindb/models/feature.py +643 -0
  37. lamindb/models/flextable.py +163 -0
  38. lamindb/{_parents.py → models/has_parents.py} +55 -49
  39. lamindb/models/project.py +384 -0
  40. lamindb/{_query_manager.py → models/query_manager.py} +10 -8
  41. lamindb/{_query_set.py → models/query_set.py} +40 -26
  42. lamindb/models/record.py +1762 -0
  43. lamindb/models/run.py +563 -0
  44. lamindb/{_save.py → models/save.py} +9 -7
  45. lamindb/models/schema.py +732 -0
  46. lamindb/models/transform.py +360 -0
  47. lamindb/models/ulabel.py +249 -0
  48. {lamindb-1.1.1.dist-info → lamindb-1.2.0.dist-info}/METADATA +6 -6
  49. {lamindb-1.1.1.dist-info → lamindb-1.2.0.dist-info}/RECORD +51 -51
  50. lamindb/_artifact.py +0 -1379
  51. lamindb/_collection.py +0 -440
  52. lamindb/_feature.py +0 -316
  53. lamindb/_is_versioned.py +0 -40
  54. lamindb/_record.py +0 -1064
  55. lamindb/_run.py +0 -60
  56. lamindb/_schema.py +0 -347
  57. lamindb/_storage.py +0 -15
  58. lamindb/_transform.py +0 -170
  59. lamindb/_ulabel.py +0 -56
  60. lamindb/_utils.py +0 -9
  61. lamindb/base/validation.py +0 -63
  62. lamindb/core/_data.py +0 -491
  63. lamindb/core/fields.py +0 -12
  64. lamindb/models.py +0 -4475
  65. {lamindb-1.1.1.dist-info → lamindb-1.2.0.dist-info}/LICENSE +0 -0
  66. {lamindb-1.1.1.dist-info → lamindb-1.2.0.dist-info}/WHEEL +0 -0
@@ -1,15 +1,104 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import TYPE_CHECKING, Literal
3
+ from typing import TYPE_CHECKING, Literal, overload
4
4
 
5
+ from django.db import models
5
6
  from lamin_utils import logger
6
7
  from lamin_utils._base62 import increment_base62
7
8
  from lamindb_setup.core.upath import LocalPathClasses, UPath
8
9
 
9
10
  from lamindb.base import ids
11
+ from lamindb.base.fields import (
12
+ BooleanField,
13
+ CharField,
14
+ )
10
15
 
11
- if TYPE_CHECKING:
12
- from lamindb.models import IsVersioned
16
+ if TYPE_CHECKING: # noqa
17
+ from lamindb.models.query_set import QuerySet
18
+
19
+
20
+ class IsVersioned(models.Model):
21
+ """Base class for versioned models."""
22
+
23
+ class Meta:
24
+ abstract = True
25
+
26
+ _len_stem_uid: int
27
+
28
+ version: str | None = CharField(max_length=30, null=True, db_index=True)
29
+ """Version (default `None`).
30
+
31
+ Defines version of a family of records characterized by the same `stem_uid`.
32
+
33
+ Consider using `semantic versioning <https://semver.org>`__
34
+ with `Python versioning <https://peps.python.org/pep-0440/>`__.
35
+ """
36
+ is_latest: bool = BooleanField(default=True, db_index=True)
37
+ """Boolean flag that indicates whether a record is the latest in its version family."""
38
+
39
+ @overload
40
+ def __init__(self): ...
41
+
42
+ @overload
43
+ def __init__(
44
+ self,
45
+ *db_args,
46
+ ): ...
47
+
48
+ def __init__(
49
+ self,
50
+ *args,
51
+ **kwargs,
52
+ ):
53
+ self._revises = kwargs.pop("revises") if "revises" in kwargs else None
54
+ super().__init__(*args, **kwargs)
55
+
56
+ @property
57
+ def stem_uid(self) -> str:
58
+ """Universal id characterizing the version family.
59
+
60
+ The full uid of a record is obtained via concatenating the stem uid and version information::
61
+
62
+ stem_uid = random_base62(n_char) # a random base62 sequence of length 12 (transform) or 16 (artifact, collection)
63
+ version_uid = "0000" # an auto-incrementing 4-digit base62 number
64
+ uid = f"{stem_uid}{version_uid}" # concatenate the stem_uid & version_uid
65
+
66
+ """
67
+ return self.uid[: self._len_stem_uid] # type: ignore
68
+
69
+ @property
70
+ def versions(self) -> QuerySet:
71
+ """Lists all records of the same version family.
72
+
73
+ >>> new_artifact = ln.Artifact(df2, revises=artifact).save()
74
+ >>> new_artifact.versions()
75
+ """
76
+ db = self._state.db
77
+ if db is not None and db != "default":
78
+ return self.__class__.using(db).filter(uid__startswith=self.stem_uid) # type: ignore
79
+ else:
80
+ return self.__class__.filter(uid__startswith=self.stem_uid) # type: ignore
81
+
82
+ def _add_to_version_family(self, revises: IsVersioned, version: str | None = None):
83
+ """Add current record to a version family.
84
+
85
+ Args:
86
+ revises: a record that belongs to the version family.
87
+ version: semantic version of the record.
88
+ """
89
+ old_uid = self.uid # type: ignore
90
+ new_uid, revises = create_uid(revises=revises, version=version)
91
+ if self.__class__.__name__ == "Artifact" and self._key_is_virtual:
92
+ old_path = self.path
93
+ new_path = get_new_path_from_uid(
94
+ old_path=old_path, old_uid=old_uid, new_uid=new_uid
95
+ )
96
+ new_path = UPath(old_path).rename(new_path)
97
+ logger.success(f"updated path from {old_path} to {new_path}!")
98
+ self.uid = new_uid
99
+ self.version = version
100
+ self.save()
101
+ logger.success(f"updated uid from {old_uid} to {new_uid}!")
13
102
 
14
103
 
15
104
  def message_update_key_in_version_family(
@@ -102,15 +191,14 @@ def create_uid(
102
191
  f"didn't pass the latest version in `revises`, retrieved it: {revises}"
103
192
  )
104
193
  suid = revises.stem_uid
105
- vuid = increment_base62(revises.uid[-4:])
194
+ vuid = increment_base62(revises.uid[-4:]) # type: ignore
106
195
  else:
107
196
  suid = ids.base62(n_full_id - 4)
108
197
  vuid = "0000"
109
198
  if version is not None:
110
199
  if not isinstance(version, str):
111
200
  raise ValueError(
112
- "`version` parameter must be `None` or `str`, e.g., '0.1', '1', '2',"
113
- " etc."
201
+ "`version` parameter must be `None` or `str`, e.g., '0.1', '1', '2', etc."
114
202
  )
115
203
  if revises is not None:
116
204
  if version == revises.version:
@@ -1,6 +1,5 @@
1
1
  from __future__ import annotations
2
2
 
3
- import warnings
4
3
  from collections import defaultdict
5
4
  from typing import TYPE_CHECKING
6
5
 
@@ -10,15 +9,15 @@ from rich.table import Column, Table
10
9
  from rich.text import Text
11
10
  from rich.tree import Tree
12
11
 
13
- from lamindb._from_values import _format_values
14
- from lamindb._record import (
12
+ from lamindb.models import CanCurate, Feature
13
+ from lamindb.models._from_values import _format_values
14
+ from lamindb.models.record import (
15
15
  REGISTRY_UNIQUE_FIELD,
16
16
  get_name_field,
17
17
  transfer_fk_to_default_db_bulk,
18
18
  transfer_to_default_db,
19
19
  )
20
- from lamindb._save import save
21
- from lamindb.models import CanCurate, Feature
20
+ from lamindb.models.save import save
22
21
 
23
22
  from ._describe import (
24
23
  NAME_WIDTH,
@@ -28,12 +27,11 @@ from ._describe import (
28
27
  print_rich_tree,
29
28
  )
30
29
  from ._django import get_artifact_with_related, get_related_model
31
- from ._settings import settings
32
- from .relations import dict_related_model_to_related_name
30
+ from ._relations import dict_related_model_to_related_name
33
31
 
34
32
  if TYPE_CHECKING:
35
- from lamindb._query_set import QuerySet
36
33
  from lamindb.models import Artifact, Collection, Record
34
+ from lamindb.models.query_set import QuerySet
37
35
 
38
36
  EXCLUDE_LABELS = {"feature_sets"}
39
37
 
@@ -75,17 +73,10 @@ def _get_labels_postgres(
75
73
  def describe_labels(
76
74
  self: Artifact | Collection,
77
75
  labels_data: dict | None = None,
78
- print_types: bool = False, # deprecated
79
76
  tree: Tree | None = None,
80
77
  as_subtree: bool = False,
81
78
  ):
82
79
  """Describe labels associated with an artifact or collection."""
83
- if print_types:
84
- warnings.warn(
85
- "`print_types` parameter is deprecated and will be removed in a future version. Types are now always printed.",
86
- DeprecationWarning,
87
- stacklevel=2,
88
- )
89
80
  if not self._state.adding and connections[self._state.db].vendor == "postgresql":
90
81
  labels_data = _get_labels_postgres(self, labels_data)
91
82
  if not labels_data:
@@ -205,7 +196,7 @@ class LabelManager:
205
196
  records: Label records to add.
206
197
  feature: Feature under which to group the labels.
207
198
  """
208
- from ._data import add_labels
199
+ from .artifact import add_labels
209
200
 
210
201
  return add_labels(self._host, records=records, feature=feature)
211
202
 
@@ -222,7 +213,7 @@ class LabelManager:
222
213
  mute: Show no logging.
223
214
  flat_names: Flatten list to names rather than returning records.
224
215
  """
225
- from ._data import get_labels
216
+ from .artifact import get_labels
226
217
 
227
218
  return get_labels(self._host, feature=feature, mute=mute, flat_names=flat_names)
228
219
 
@@ -240,6 +231,8 @@ class LabelManager:
240
231
  """
241
232
  if transfer_logs is None:
242
233
  transfer_logs = {"mapped": [], "transferred": [], "run": None}
234
+ from lamindb import settings
235
+
243
236
  using_key = settings._using_key
244
237
  for related_name, labels in _get_labels(data, instance=data._state.db).items():
245
238
  labels = labels.all()
@@ -1,5 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
+ from typing import TYPE_CHECKING
4
+
3
5
  import lamindb_setup as ln_setup
4
6
  from django.db.models import ManyToManyField
5
7
  from lamindb_setup._connect_instance import (
@@ -8,7 +10,10 @@ from lamindb_setup._connect_instance import (
8
10
  )
9
11
  from lamindb_setup.core._settings_store import instance_settings_file
10
12
 
11
- from lamindb.models import LinkORM, Record, Registry, Schema
13
+ from lamindb.models.record import LinkORM
14
+
15
+ if TYPE_CHECKING:
16
+ from lamindb.models.record import Record, Registry
12
17
 
13
18
 
14
19
  def get_schema_modules(instance: str | None) -> set[str]:
@@ -84,6 +89,8 @@ def dict_related_model_to_related_name(
84
89
 
85
90
 
86
91
  def get_related_name(features_type: type[Record]) -> str:
92
+ from lamindb.models.schema import Schema
93
+
87
94
  candidates = [
88
95
  field.related_name
89
96
  for field in Schema._meta.related_objects