lamindb 1.6.1__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.
Files changed (62) hide show
  1. lamindb/__init__.py +1 -3
  2. lamindb/_finish.py +32 -16
  3. lamindb/base/types.py +6 -4
  4. lamindb/core/_context.py +127 -57
  5. lamindb/core/_mapped_collection.py +1 -1
  6. lamindb/core/_settings.py +44 -4
  7. lamindb/core/_track_environment.py +5 -2
  8. lamindb/core/loaders.py +1 -1
  9. lamindb/core/storage/_anndata_accessor.py +1 -1
  10. lamindb/core/storage/_tiledbsoma.py +14 -8
  11. lamindb/core/storage/_valid_suffixes.py +0 -1
  12. lamindb/core/storage/_zarr.py +1 -1
  13. lamindb/core/storage/objects.py +13 -8
  14. lamindb/core/storage/paths.py +9 -6
  15. lamindb/core/types.py +1 -1
  16. lamindb/curators/_legacy.py +2 -1
  17. lamindb/curators/core.py +106 -105
  18. lamindb/errors.py +9 -0
  19. lamindb/examples/fixtures/__init__.py +0 -0
  20. lamindb/examples/fixtures/sheets.py +224 -0
  21. lamindb/migrations/0103_remove_writelog_migration_state_and_more.py +1 -1
  22. lamindb/migrations/0105_record_unique_name.py +20 -0
  23. lamindb/migrations/0106_transfer_data_migration.py +25 -0
  24. lamindb/migrations/0107_add_schema_to_record.py +68 -0
  25. lamindb/migrations/0108_remove_record_sheet_remove_sheetproject_sheet_and_more.py +30 -0
  26. lamindb/migrations/0109_record_input_of_runs_alter_record_run_and_more.py +123 -0
  27. lamindb/migrations/0110_rename_values_artifacts_record_linked_artifacts.py +17 -0
  28. lamindb/migrations/0111_remove_record__sort_order.py +148 -0
  29. lamindb/migrations/0112_alter_recordartifact_feature_and_more.py +105 -0
  30. lamindb/migrations/0113_lower_case_branch_and_space_names.py +62 -0
  31. lamindb/migrations/0114_alter_run__status_code.py +24 -0
  32. lamindb/migrations/0115_alter_space_uid.py +52 -0
  33. lamindb/migrations/{0104_squashed.py → 0115_squashed.py} +261 -257
  34. lamindb/models/__init__.py +4 -3
  35. lamindb/models/_describe.py +88 -31
  36. lamindb/models/_feature_manager.py +627 -658
  37. lamindb/models/_label_manager.py +1 -3
  38. lamindb/models/artifact.py +214 -99
  39. lamindb/models/collection.py +7 -1
  40. lamindb/models/feature.py +288 -60
  41. lamindb/models/has_parents.py +3 -3
  42. lamindb/models/project.py +32 -15
  43. lamindb/models/query_manager.py +7 -1
  44. lamindb/models/query_set.py +118 -41
  45. lamindb/models/record.py +140 -94
  46. lamindb/models/run.py +42 -42
  47. lamindb/models/save.py +102 -16
  48. lamindb/models/schema.py +41 -8
  49. lamindb/models/sqlrecord.py +105 -40
  50. lamindb/models/storage.py +278 -0
  51. lamindb/models/transform.py +10 -2
  52. lamindb/models/ulabel.py +9 -1
  53. lamindb/py.typed +0 -0
  54. lamindb/setup/__init__.py +2 -1
  55. lamindb/setup/_switch.py +16 -0
  56. lamindb/setup/errors/__init__.py +4 -0
  57. lamindb/setup/types/__init__.py +4 -0
  58. {lamindb-1.6.1.dist-info → lamindb-1.7.0.dist-info}/METADATA +5 -5
  59. {lamindb-1.6.1.dist-info → lamindb-1.7.0.dist-info}/RECORD +61 -44
  60. lamindb/models/core.py +0 -135
  61. {lamindb-1.6.1.dist-info → lamindb-1.7.0.dist-info}/LICENSE +0 -0
  62. {lamindb-1.6.1.dist-info → lamindb-1.7.0.dist-info}/WHEEL +0 -0
@@ -41,7 +41,7 @@ from .sqlrecord import (
41
41
  record_repr,
42
42
  IsLink,
43
43
  )
44
- from .core import Storage
44
+ from .storage import Storage
45
45
  from .transform import Transform
46
46
  from .run import Run, TracksRun, TracksUpdates, current_run, User
47
47
  from .feature import Feature, FeatureValue
@@ -73,10 +73,11 @@ from .project import (
73
73
  SchemaProject,
74
74
  ArtifactReference,
75
75
  CollectionReference,
76
- SheetProject,
77
76
  RunProject,
78
77
  RecordProject,
79
78
  PersonProject,
79
+ RecordPerson,
80
+ RecordReference,
80
81
  )
81
82
  from .run import RunFeatureValue
82
83
  from .schema import (
@@ -89,12 +90,12 @@ from .ulabel import ArtifactULabel, TransformULabel, RunULabel, CollectionULabel
89
90
 
90
91
  from .record import (
91
92
  Record,
92
- Sheet,
93
93
  RecordJson,
94
94
  RecordRecord,
95
95
  RecordULabel,
96
96
  RecordRun,
97
97
  RecordArtifact,
98
+ ArtifactRecord,
98
99
  )
99
100
 
100
101
 
@@ -27,12 +27,12 @@ def highlight_time(iso: str):
27
27
  # raises ValueError: Invalid isoformat string: '<django.db.models.expressions.DatabaseDefault object at 0x1128ac440>'
28
28
  # but can't be caught with `isinstance(iso, DatabaseDefault)` for unkown reasons
29
29
  return Text("timestamp of unsaved record not available", style="dim")
30
- return Text(res, style="dim")
30
+ return Text(res)
31
31
 
32
32
 
33
33
  # Define consistent column widths
34
- NAME_WIDTH = 25
35
- TYPE_WIDTH = 25
34
+ NAME_WIDTH = 30
35
+ TYPE_WIDTH = 35 # types can get long, e.g. cat[Record[Treatment]]
36
36
  VALUES_WIDTH = 40
37
37
 
38
38
 
@@ -97,8 +97,11 @@ def describe_header(self: Artifact | Collection | Run) -> Tree:
97
97
  # initialize tree
98
98
  suffix = self.suffix if hasattr(self, "suffix") and self.suffix else ""
99
99
  accessor = self.otype if hasattr(self, "otype") and self.otype else ""
100
+ kind = f" · {self.kind}" if hasattr(self, "kind") and self.kind else ""
100
101
  suffix_accessor = (
101
- f"{suffix}/{accessor}" if suffix and accessor else suffix or accessor or ""
102
+ f"{suffix} · {accessor}{kind}"
103
+ if suffix and accessor
104
+ else suffix or accessor or ""
102
105
  )
103
106
 
104
107
  tree = Tree(
@@ -110,40 +113,59 @@ def describe_header(self: Artifact | Collection | Run) -> Tree:
110
113
  return tree
111
114
 
112
115
 
116
+ def format_bytes(bytes_value):
117
+ """Convert bytes to human readable format."""
118
+ if bytes_value < 1024:
119
+ return f"{bytes_value} B"
120
+ elif bytes_value < 1024**2:
121
+ return f"{bytes_value / 1024:.1f} KB"
122
+ elif bytes_value < 1024**3:
123
+ return f"{bytes_value / (1024**2):.1f} MB"
124
+ elif bytes_value < 1024**4:
125
+ return f"{bytes_value / (1024**3):.1f} GB"
126
+ else:
127
+ return f"{bytes_value / (1024**4):.1f} TB"
128
+
129
+
113
130
  def describe_general(self: Artifact | Collection, tree: Tree | None = None) -> Tree:
114
131
  if tree is None:
115
132
  tree = describe_header(self)
116
133
 
117
134
  # add general information (order is the same as in API docs)
118
135
  general = tree.add(Text("General", style="bold bright_cyan"))
119
- general.add(f".uid = '{self.uid}'")
120
- if hasattr(self, "key") and self.key:
121
- general.add(f".key = '{self.key}'")
122
- if hasattr(self, "size") and self.size:
123
- general.add(f".size = {self.size}")
136
+
137
+ # Two column items (short content)
138
+ two_column_items = []
139
+
140
+ two_column_items.append(Text.assemble(("uid: ", "dim"), f"{self.uid}"))
124
141
  if hasattr(self, "hash") and self.hash:
125
- general.add(f".hash = '{self.hash}'")
142
+ two_column_items.append(Text.assemble(("hash: ", "dim"), f"{self.hash}"))
143
+ if hasattr(self, "size") and self.size:
144
+ two_column_items.append(
145
+ Text.assemble(("size: ", "dim"), f"{format_bytes(self.size)}")
146
+ )
126
147
  if hasattr(self, "n_files") and self.n_files:
127
- general.add(f".n_files = {self.n_files}")
148
+ two_column_items.append(Text.assemble(("n_files: ", "dim"), f"{self.n_files}"))
128
149
  if hasattr(self, "n_observations") and self.n_observations:
129
- general.add(Text(f".n_observations = {self.n_observations}"))
150
+ two_column_items.append(
151
+ Text.assemble(("n_observations: ", "dim"), f"{self.n_observations}")
152
+ )
130
153
  if hasattr(self, "version") and self.version:
131
- general.add(Text(f".version = '{self.version}'"))
132
-
133
- if hasattr(self, "storage"):
134
- storage_root = self.storage.root
135
- # general.add(f".storage = {storage_root}")
136
- general.add(
137
- Text.assemble(
138
- ".path = ",
139
- (storage_root, "dim"),
140
- f"{str(self.path).removeprefix(storage_root)}",
141
- )
154
+ two_column_items.append(Text.assemble(("version: ", "dim"), f"{self.version}"))
155
+ if hasattr(self, "space"):
156
+ two_column_items.append(Text.assemble(("space: ", "dim"), f"{self.space.name}"))
157
+ if hasattr(self, "branch"):
158
+ two_column_items.append(
159
+ Text.assemble(("branch: ", "dim"), f"{self.branch.name}")
160
+ )
161
+ if hasattr(self, "created_at") and self.created_at:
162
+ two_column_items.append(
163
+ Text.assemble(("created_at: ", "dim"), highlight_time(str(self.created_at)))
142
164
  )
143
165
  if hasattr(self, "created_by") and self.created_by:
144
- general.add(
166
+ two_column_items.append(
145
167
  Text.assemble(
146
- ".created_by = ",
168
+ ("created_by: ", "dim"),
147
169
  (
148
170
  self.created_by.handle
149
171
  if self.created_by.name is None
@@ -151,15 +173,50 @@ def describe_general(self: Artifact | Collection, tree: Tree | None = None) -> T
151
173
  ),
152
174
  )
153
175
  )
154
- if hasattr(self, "created_at") and self.created_at:
176
+
177
+ # Add two-column items in pairs
178
+ for i in range(0, len(two_column_items), 2):
179
+ if i + 1 < len(two_column_items):
180
+ # Two items side by side
181
+ left_item = two_column_items[i]
182
+ right_item = two_column_items[i + 1]
183
+
184
+ # Create padded version by calculating the plain text length
185
+ left_plain_text = (
186
+ left_item.plain if hasattr(left_item, "plain") else str(left_item)
187
+ )
188
+ padding_needed = max(0, 35 - len(left_plain_text))
189
+ padding = " " * padding_needed
190
+
191
+ general.add(Text.assemble(left_item, padding, right_item))
192
+ else:
193
+ # Single item (odd number)
194
+ general.add(two_column_items[i])
195
+
196
+ # Single column items (long content)
197
+ if hasattr(self, "key") and self.key:
198
+ general.add(Text.assemble(("key: ", "dim"), f"{self.key}"))
199
+ if hasattr(self, "storage"):
200
+ storage_root = self.storage.root
155
201
  general.add(
156
- Text.assemble(".created_at = ", highlight_time(str(self.created_at)))
202
+ Text.assemble(
203
+ ("storage location / path: ", "dim"),
204
+ (storage_root, "cyan3"),
205
+ f"{str(self.path).removeprefix(storage_root)}",
206
+ )
157
207
  )
158
- if hasattr(self, "transform") and self.transform:
208
+ if hasattr(self, "description") and self.description is not None:
159
209
  general.add(
160
- Text(
161
- f".transform = '{self.transform.description}'",
162
- style="cyan3",
210
+ Text.assemble(
211
+ ("description: ", "dim"),
212
+ f"{self.description}",
213
+ )
214
+ )
215
+ if hasattr(self, "transform") and self.transform is not None:
216
+ general.add(
217
+ Text.assemble(
218
+ ("transform: ", "dim"),
219
+ f"{self.transform.key}",
163
220
  )
164
221
  )
165
222