lamindb 0.70.0__py3-none-any.whl → 0.70.2__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/_annotate.py +4 -4
- lamindb/_artifact.py +12 -11
- lamindb/_can_validate.py +6 -3
- lamindb/_collection.py +1 -1
- lamindb/_finish.py +31 -29
- lamindb/_from_values.py +32 -18
- lamindb/_registry.py +2 -0
- lamindb/_save.py +4 -5
- lamindb/core/storage/__init__.py +3 -2
- lamindb/core/storage/_backed_access.py +5 -5
- lamindb/core/storage/_valid_suffixes.py +3 -0
- lamindb/core/storage/{object.py → objects.py} +2 -3
- lamindb/core/storage/{file.py → paths.py} +12 -13
- lamindb/integrations/_vitessce.py +44 -24
- {lamindb-0.70.0.dist-info → lamindb-0.70.2.dist-info}/METADATA +5 -5
- {lamindb-0.70.0.dist-info → lamindb-0.70.2.dist-info}/RECORD +19 -18
- {lamindb-0.70.0.dist-info → lamindb-0.70.2.dist-info}/LICENSE +0 -0
- {lamindb-0.70.0.dist-info → lamindb-0.70.2.dist-info}/WHEEL +0 -0
lamindb/__init__.py
CHANGED
lamindb/_annotate.py
CHANGED
@@ -351,7 +351,7 @@ class AnnDataAnnotator(DataFrameAnnotator):
|
|
351
351
|
self,
|
352
352
|
adata: ad.AnnData,
|
353
353
|
var_index: FieldAttr,
|
354
|
-
categoricals: dict[str, FieldAttr],
|
354
|
+
categoricals: dict[str, FieldAttr] | None = None,
|
355
355
|
using: str = "default",
|
356
356
|
verbosity: str = "hint",
|
357
357
|
organism: str | None = None,
|
@@ -494,7 +494,7 @@ class MuDataAnnotator:
|
|
494
494
|
self,
|
495
495
|
mdata: MuData,
|
496
496
|
var_index: dict[str, dict[str, FieldAttr]],
|
497
|
-
categoricals: dict[str, FieldAttr],
|
497
|
+
categoricals: dict[str, FieldAttr] | None = None,
|
498
498
|
using: str = "default",
|
499
499
|
verbosity: str = "hint",
|
500
500
|
organism: str | None = None,
|
@@ -751,7 +751,7 @@ class Annotate:
|
|
751
751
|
cls,
|
752
752
|
adata: ad.AnnData,
|
753
753
|
var_index: FieldAttr,
|
754
|
-
categoricals: dict[str, FieldAttr],
|
754
|
+
categoricals: dict[str, FieldAttr] | None = None,
|
755
755
|
using: str = "default",
|
756
756
|
verbosity: str = "hint",
|
757
757
|
organism: str | None = None,
|
@@ -772,7 +772,7 @@ class Annotate:
|
|
772
772
|
cls,
|
773
773
|
mdata: MuData,
|
774
774
|
var_index: dict[str, dict[str, FieldAttr]],
|
775
|
-
categoricals: dict[str,
|
775
|
+
categoricals: dict[str, FieldAttr] | None = None,
|
776
776
|
using: str = "default",
|
777
777
|
verbosity: str = "hint",
|
778
778
|
organism: str | None = None,
|
lamindb/_artifact.py
CHANGED
@@ -37,7 +37,7 @@ from lamindb.core.storage import (
|
|
37
37
|
size_adata,
|
38
38
|
write_to_file,
|
39
39
|
)
|
40
|
-
from lamindb.core.storage.
|
40
|
+
from lamindb.core.storage.paths import (
|
41
41
|
auto_storage_key_from_artifact,
|
42
42
|
auto_storage_key_from_artifact_uid,
|
43
43
|
filepath_from_artifact,
|
@@ -50,8 +50,8 @@ from .core._data import (
|
|
50
50
|
save_feature_set_links,
|
51
51
|
save_feature_sets,
|
52
52
|
)
|
53
|
-
from .core.storage.
|
54
|
-
from .core.storage.
|
53
|
+
from .core.storage.objects import _mudata_is_installed
|
54
|
+
from .core.storage.paths import AUTO_KEY_PREFIX
|
55
55
|
|
56
56
|
if TYPE_CHECKING:
|
57
57
|
from lamindb_setup.core.types import UPathStr
|
@@ -167,7 +167,7 @@ def process_data(
|
|
167
167
|
# Alex: I don't understand the line below
|
168
168
|
if path.suffixes == []:
|
169
169
|
path = path.with_suffix(suffix)
|
170
|
-
if suffix
|
170
|
+
if suffix != ".zarr":
|
171
171
|
write_to_file(data, path)
|
172
172
|
use_existing_storage_key = False
|
173
173
|
else:
|
@@ -188,11 +188,7 @@ def get_stat_or_artifact(
|
|
188
188
|
n_objects = None
|
189
189
|
if settings.upon_file_create_skip_size_hash:
|
190
190
|
return None, None, None, n_objects
|
191
|
-
if (
|
192
|
-
suffix in {".zarr", ".zrad"}
|
193
|
-
and memory_rep is not None
|
194
|
-
and isinstance(memory_rep, AnnData)
|
195
|
-
):
|
191
|
+
if suffix == ".zarr" and memory_rep is not None and isinstance(memory_rep, AnnData):
|
196
192
|
size = size_adata(memory_rep)
|
197
193
|
return size, None, None, n_objects
|
198
194
|
stat = path.stat() # one network request
|
@@ -450,7 +446,12 @@ def data_is_anndata(data: AnnData | UPathStr):
|
|
450
446
|
if isinstance(data, AnnData):
|
451
447
|
return True
|
452
448
|
if isinstance(data, (str, Path, UPath)):
|
453
|
-
|
449
|
+
if Path(data).suffix == ".h5ad":
|
450
|
+
return True
|
451
|
+
elif Path(data).suffix == ".zarr":
|
452
|
+
raise NotImplementedError(
|
453
|
+
"auto-detecting AnnData from Zarr is not yet supported"
|
454
|
+
)
|
454
455
|
return False
|
455
456
|
|
456
457
|
|
@@ -832,7 +833,7 @@ def replace(
|
|
832
833
|
|
833
834
|
# docstring handled through attach_func_to_class_method
|
834
835
|
def backed(self, is_run_input: bool | None = None) -> AnnDataAccessor | BackedAccessor:
|
835
|
-
suffixes = (".h5", ".hdf5", ".h5ad", ".
|
836
|
+
suffixes = (".h5", ".hdf5", ".h5ad", ".zarr")
|
836
837
|
if self.suffix not in suffixes:
|
837
838
|
raise ValueError(
|
838
839
|
"Artifact should have a zarr or h5 object as the underlying data, please"
|
lamindb/_can_validate.py
CHANGED
@@ -30,6 +30,7 @@ def inspect(
|
|
30
30
|
*,
|
31
31
|
mute: bool = False,
|
32
32
|
organism: str | Registry | None = None,
|
33
|
+
public_source: Registry | None = None,
|
33
34
|
) -> InspectResult:
|
34
35
|
"""{}."""
|
35
36
|
return _inspect(
|
@@ -38,6 +39,7 @@ def inspect(
|
|
38
39
|
field=field,
|
39
40
|
mute=mute,
|
40
41
|
organism=organism,
|
42
|
+
public_source=public_source,
|
41
43
|
)
|
42
44
|
|
43
45
|
|
@@ -63,6 +65,7 @@ def _inspect(
|
|
63
65
|
mute: bool = False,
|
64
66
|
using_key: str | None = None,
|
65
67
|
organism: str | Registry | None = None,
|
68
|
+
public_source: Registry | None = None,
|
66
69
|
) -> pd.DataFrame | dict[str, list[str]]:
|
67
70
|
"""{}."""
|
68
71
|
from lamin_utils._inspect import inspect
|
@@ -86,9 +89,9 @@ def _inspect(
|
|
86
89
|
|
87
90
|
if len(nonval) > 0 and orm.__get_schema_name__() == "bionty":
|
88
91
|
try:
|
89
|
-
bionty_result = orm.public(
|
90
|
-
|
91
|
-
)
|
92
|
+
bionty_result = orm.public(
|
93
|
+
organism=organism, public_source=public_source
|
94
|
+
).inspect(values=nonval, field=field, mute=True)
|
92
95
|
bionty_validated = bionty_result.validated
|
93
96
|
bionty_mapper = bionty_result.synonyms_mapper
|
94
97
|
hint = False
|
lamindb/_collection.py
CHANGED
@@ -234,7 +234,7 @@ def mapped(
|
|
234
234
|
) -> MappedCollection:
|
235
235
|
path_list = []
|
236
236
|
for artifact in self.artifacts.all():
|
237
|
-
if artifact.suffix not in {".h5ad", ".
|
237
|
+
if artifact.suffix not in {".h5ad", ".zarr"}:
|
238
238
|
logger.warning(f"Ignoring artifact with suffix {artifact.suffix}")
|
239
239
|
continue
|
240
240
|
elif not stream:
|
lamindb/_finish.py
CHANGED
@@ -20,37 +20,40 @@ if TYPE_CHECKING:
|
|
20
20
|
from ._query_set import QuerySet
|
21
21
|
|
22
22
|
|
23
|
-
class
|
23
|
+
class TrackNotCalled(SystemExit):
|
24
24
|
pass
|
25
25
|
|
26
26
|
|
27
|
-
|
28
|
-
|
27
|
+
class NotebookNotSaved(SystemExit):
|
28
|
+
pass
|
29
29
|
|
30
|
-
When run in notebooks, save the run report to your default storage location.
|
31
30
|
|
32
|
-
|
33
|
-
|
34
|
-
editor (JupyterLab, VSCode, etc.).
|
35
|
-
"""
|
36
|
-
if is_run_from_ipython:
|
37
|
-
# notebooks
|
38
|
-
from nbproject.dev import read_notebook
|
39
|
-
from nbproject.dev._check_last_cell import check_last_cell
|
31
|
+
def get_seconds_since_modified(filepath) -> float:
|
32
|
+
return datetime.now().timestamp() - filepath.stat().st_mtime
|
40
33
|
|
41
|
-
|
42
|
-
|
43
|
-
|
34
|
+
|
35
|
+
def finish():
|
36
|
+
"""Mark a tracked run as finished.
|
37
|
+
|
38
|
+
If run in a notebook, it saves the run report & source code to your default storage location.
|
39
|
+
"""
|
40
|
+
if run_context.path is None:
|
41
|
+
raise TrackNotCalled("Please run `ln.track()` before `ln.finish()`")
|
42
|
+
if is_run_from_ipython: # notebooks
|
43
|
+
if (
|
44
|
+
get_seconds_since_modified(run_context.path) > 3
|
45
|
+
and os.getenv("LAMIN_TESTING") is None
|
46
|
+
):
|
47
|
+
raise NotebookNotSaved(
|
48
|
+
"Please save the notebook in your editor right before running `ln.finish()`"
|
44
49
|
)
|
45
|
-
return None
|
46
50
|
save_run_context_core(
|
47
51
|
run=run_context.run,
|
48
52
|
transform=run_context.transform,
|
49
53
|
filepath=run_context.path,
|
50
54
|
finished_at=True,
|
51
55
|
)
|
52
|
-
else:
|
53
|
-
# scripts
|
56
|
+
else: # scripts
|
54
57
|
# save_run_context_core was already called during ln.track()
|
55
58
|
run_context.run.finished_at = datetime.now(timezone.utc) # update run time
|
56
59
|
run_context.run.save()
|
@@ -98,7 +101,7 @@ def save_run_context_core(
|
|
98
101
|
# log_level is set to 40 to silence the nbconvert logging
|
99
102
|
subprocess.run(
|
100
103
|
"jupyter nbconvert --to html"
|
101
|
-
f" {filepath.as_posix()} --Application.log_level=40",
|
104
|
+
f" '{filepath.as_posix()}' --Application.log_level=40",
|
102
105
|
shell=True,
|
103
106
|
check=True,
|
104
107
|
)
|
@@ -118,7 +121,7 @@ def save_run_context_core(
|
|
118
121
|
# first, copy the notebook file to a temporary file in the cache
|
119
122
|
source_code_path = ln_setup.settings.storage.cache_dir / filepath.name
|
120
123
|
shutil.copy2(filepath, source_code_path) # copy
|
121
|
-
subprocess.run(f"nbstripout {source_code_path}", shell=True, check=True)
|
124
|
+
subprocess.run(f"nbstripout '{source_code_path}'", shell=True, check=True)
|
122
125
|
# find initial versions of source codes and html reports
|
123
126
|
prev_report = None
|
124
127
|
prev_source = None
|
@@ -139,9 +142,8 @@ def save_run_context_core(
|
|
139
142
|
if os.getenv("LAMIN_TESTING") is None:
|
140
143
|
# in test, auto-confirm overwrite
|
141
144
|
response = input(
|
142
|
-
"You
|
143
|
-
f" '{transform.version}'
|
144
|
-
f" existing source code {transform.source_code}? (y/n)"
|
145
|
+
f"You are about to overwrite existing source code (hash {transform.source_code.hash}) for transform version"
|
146
|
+
f" '{transform.version}'. Proceed? (y/n)"
|
145
147
|
)
|
146
148
|
else:
|
147
149
|
response = "y"
|
@@ -149,10 +151,7 @@ def save_run_context_core(
|
|
149
151
|
transform.source_code.replace(source_code_path)
|
150
152
|
transform.source_code.save()
|
151
153
|
else:
|
152
|
-
logger.warning(
|
153
|
-
"Please create a new version of the notebook via `lamin track"
|
154
|
-
" <filepath>` and re-run the notebook"
|
155
|
-
)
|
154
|
+
logger.warning("Please re-run `ln.track()` to make a new version")
|
156
155
|
return "rerun-the-notebook"
|
157
156
|
else:
|
158
157
|
source_code = ln.Artifact(
|
@@ -207,8 +206,11 @@ def save_run_context_core(
|
|
207
206
|
transform.save()
|
208
207
|
if transform.type == TransformType.notebook:
|
209
208
|
logger.success(f"saved transform.latest_report: {transform.latest_report}")
|
210
|
-
|
211
|
-
|
209
|
+
if ln_setup.settings.instance.is_remote:
|
210
|
+
identifier = ln_setup.settings.instance.slug
|
211
|
+
logger.success(
|
212
|
+
f"go to: https://lamin.ai/{identifier}/transform/{transform.uid}"
|
213
|
+
)
|
212
214
|
# because run & transform changed, update the global run_context
|
213
215
|
run_context.run = run
|
214
216
|
run_context.transform = transform
|
lamindb/_from_values.py
CHANGED
@@ -21,6 +21,7 @@ def get_or_create_records(
|
|
21
21
|
from_public: bool = False,
|
22
22
|
organism: Registry | str | None = None,
|
23
23
|
public_source: Registry | None = None,
|
24
|
+
mute: bool = False,
|
24
25
|
) -> list[Registry]:
|
25
26
|
"""Get or create records from iterables."""
|
26
27
|
upon_create_search_names = settings.upon_create_search_names
|
@@ -38,14 +39,18 @@ def get_or_create_records(
|
|
38
39
|
|
39
40
|
# returns existing records & non-existing values
|
40
41
|
records, nonexist_values, msg = get_existing_records(
|
41
|
-
iterable_idx=iterable_idx, field=field, **kwargs
|
42
|
+
iterable_idx=iterable_idx, field=field, mute=mute, **kwargs
|
42
43
|
)
|
43
44
|
|
44
45
|
# new records to be created based on new values
|
45
46
|
if len(nonexist_values) > 0:
|
46
47
|
if from_public:
|
47
48
|
records_bionty, unmapped_values = create_records_from_public(
|
48
|
-
iterable_idx=nonexist_values,
|
49
|
+
iterable_idx=nonexist_values,
|
50
|
+
field=field,
|
51
|
+
msg=msg,
|
52
|
+
mute=mute,
|
53
|
+
**kwargs,
|
49
54
|
)
|
50
55
|
if len(records_bionty) > 0:
|
51
56
|
msg = ""
|
@@ -56,16 +61,17 @@ def get_or_create_records(
|
|
56
61
|
unmapped_values = nonexist_values
|
57
62
|
# unmapped new_ids will NOT create records
|
58
63
|
if len(unmapped_values) > 0:
|
59
|
-
if len(msg) > 0:
|
64
|
+
if len(msg) > 0 and not mute:
|
60
65
|
logger.success(msg)
|
61
66
|
s = "" if len(unmapped_values) == 1 else "s"
|
62
67
|
print_values = colors.yellow(_print_values(unmapped_values))
|
63
68
|
name = Registry.__name__
|
64
69
|
n_nonval = colors.yellow(f"{len(unmapped_values)} non-validated")
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
70
|
+
if not mute:
|
71
|
+
logger.warning(
|
72
|
+
f"{colors.red('did not create')} {name} record{s} for "
|
73
|
+
f"{n_nonval} {colors.italic(f'{field.field.name}{s}')}: {print_values}"
|
74
|
+
)
|
69
75
|
if Registry.__module__.startswith("lnschema_bionty.") or Registry == ULabel:
|
70
76
|
if isinstance(iterable, pd.Series):
|
71
77
|
feature = iterable.name
|
@@ -85,6 +91,7 @@ def get_or_create_records(
|
|
85
91
|
def get_existing_records(
|
86
92
|
iterable_idx: pd.Index,
|
87
93
|
field: StrField,
|
94
|
+
mute: bool = False,
|
88
95
|
**kwargs,
|
89
96
|
):
|
90
97
|
model = field.field.model
|
@@ -96,7 +103,11 @@ def get_existing_records(
|
|
96
103
|
# standardize based on the DB reference
|
97
104
|
# log synonyms mapped terms
|
98
105
|
result = model.inspect(
|
99
|
-
iterable_idx,
|
106
|
+
iterable_idx,
|
107
|
+
field=field,
|
108
|
+
organism=kwargs.get("organism"),
|
109
|
+
public_source=kwargs.get("public_source"),
|
110
|
+
mute=True,
|
100
111
|
)
|
101
112
|
syn_mapper = result.synonyms_mapper
|
102
113
|
|
@@ -146,9 +157,10 @@ def get_existing_records(
|
|
146
157
|
# no logging if all values are validated
|
147
158
|
# logs if there are synonyms
|
148
159
|
if len(syn_msg) > 0:
|
149
|
-
if len(msg) > 0:
|
160
|
+
if len(msg) > 0 and not mute:
|
150
161
|
logger.success(msg)
|
151
|
-
|
162
|
+
if not mute:
|
163
|
+
logger.success(syn_msg)
|
152
164
|
msg = ""
|
153
165
|
|
154
166
|
existing_values = iterable_idx.intersection(
|
@@ -163,6 +175,7 @@ def create_records_from_public(
|
|
163
175
|
iterable_idx: pd.Index,
|
164
176
|
field: StrField,
|
165
177
|
msg: str = "",
|
178
|
+
mute: bool = False,
|
166
179
|
**kwargs,
|
167
180
|
):
|
168
181
|
model = field.field.model
|
@@ -219,19 +232,20 @@ def create_records_from_public(
|
|
219
232
|
s = "" if len(validated) == 1 else "s"
|
220
233
|
print_values = colors.purple(_print_values(validated))
|
221
234
|
# this is the success msg for existing records in the DB
|
222
|
-
if len(msg) > 0:
|
235
|
+
if len(msg) > 0 and not mute:
|
223
236
|
logger.success(msg)
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
237
|
+
if not mute:
|
238
|
+
logger.success(
|
239
|
+
"created"
|
240
|
+
f" {colors.purple(f'{len(validated)} {model.__name__} record{s} from Bionty')}"
|
241
|
+
f" matching {colors.italic(f'{field.field.name}')}: {print_values}"
|
242
|
+
)
|
229
243
|
|
230
244
|
# make sure that synonyms logging appears after the field logging
|
231
|
-
if len(msg_syn) > 0:
|
245
|
+
if len(msg_syn) > 0 and not mute:
|
232
246
|
logger.success(msg_syn)
|
233
247
|
# warning about multi matches
|
234
|
-
if len(multi_msg) > 0:
|
248
|
+
if len(multi_msg) > 0 and not mute:
|
235
249
|
logger.warning(multi_msg)
|
236
250
|
|
237
251
|
# return the values that are not found in the bionty reference
|
lamindb/_registry.py
CHANGED
@@ -134,6 +134,7 @@ def from_values(
|
|
134
134
|
field: StrField | None = None,
|
135
135
|
organism: Registry | str | None = None,
|
136
136
|
public_source: Registry | None = None,
|
137
|
+
mute: bool = False,
|
137
138
|
) -> list[Registry]:
|
138
139
|
"""{}."""
|
139
140
|
from_public = True if cls.__module__.startswith("lnschema_bionty.") else False
|
@@ -144,6 +145,7 @@ def from_values(
|
|
144
145
|
from_public=from_public,
|
145
146
|
organism=organism,
|
146
147
|
public_source=public_source,
|
148
|
+
mute=mute,
|
147
149
|
)
|
148
150
|
|
149
151
|
|
lamindb/_save.py
CHANGED
@@ -16,11 +16,11 @@ from lamindb_setup.core.upath import UPath, print_hook
|
|
16
16
|
from lnschema_core.models import Artifact, Registry
|
17
17
|
|
18
18
|
from lamindb.core._settings import settings
|
19
|
-
from lamindb.core.storage.
|
19
|
+
from lamindb.core.storage.paths import (
|
20
20
|
attempt_accessing_path,
|
21
21
|
auto_storage_key_from_artifact,
|
22
22
|
delete_storage_using_key,
|
23
|
-
|
23
|
+
store_file_or_folder,
|
24
24
|
)
|
25
25
|
|
26
26
|
try:
|
@@ -286,7 +286,7 @@ def upload_artifact(
|
|
286
286
|
)
|
287
287
|
msg = f"storing artifact '{artifact.uid}' at '{storage_path}'"
|
288
288
|
if (
|
289
|
-
artifact.suffix
|
289
|
+
artifact.suffix == ".zarr"
|
290
290
|
and hasattr(artifact, "_memory_rep")
|
291
291
|
and artifact._memory_rep is not None
|
292
292
|
):
|
@@ -295,6 +295,5 @@ def upload_artifact(
|
|
295
295
|
write_adata_zarr(artifact._memory_rep, storage_path, callback=print_progress)
|
296
296
|
elif hasattr(artifact, "_to_store") and artifact._to_store:
|
297
297
|
logger.save(msg)
|
298
|
-
|
299
|
-
|
298
|
+
store_file_or_folder(artifact._local_filepath, storage_path)
|
300
299
|
return storage_path
|
lamindb/core/storage/__init__.py
CHANGED
@@ -10,5 +10,6 @@ from lamindb_setup.core.upath import LocalPathClasses, UPath, infer_filesystem
|
|
10
10
|
|
11
11
|
from ._anndata_sizes import size_adata
|
12
12
|
from ._backed_access import AnnDataAccessor, BackedAccessor
|
13
|
-
from .
|
14
|
-
from .
|
13
|
+
from ._valid_suffixes import VALID_SUFFIXES
|
14
|
+
from .objects import infer_suffix, write_to_file
|
15
|
+
from .paths import delete_storage, load_to_memory
|
@@ -22,7 +22,7 @@ from lamindb_setup.core.upath import UPath, create_mapper, infer_filesystem
|
|
22
22
|
from lnschema_core import Artifact
|
23
23
|
from packaging import version
|
24
24
|
|
25
|
-
from lamindb.core.storage.
|
25
|
+
from lamindb.core.storage.paths import filepath_from_artifact
|
26
26
|
|
27
27
|
if TYPE_CHECKING:
|
28
28
|
from pathlib import Path
|
@@ -733,7 +733,7 @@ class BackedAccessor:
|
|
733
733
|
|
734
734
|
|
735
735
|
def backed_access(
|
736
|
-
artifact_or_filepath: Artifact | Path, using_key: str | None
|
736
|
+
artifact_or_filepath: Artifact | Path, using_key: str | None = None
|
737
737
|
) -> AnnDataAccessor | BackedAccessor:
|
738
738
|
if isinstance(artifact_or_filepath, Artifact):
|
739
739
|
filepath = filepath_from_artifact(artifact_or_filepath, using_key=using_key)
|
@@ -743,15 +743,15 @@ def backed_access(
|
|
743
743
|
|
744
744
|
if filepath.suffix in (".h5", ".hdf5", ".h5ad"):
|
745
745
|
conn, storage = registry.open("h5py", filepath)
|
746
|
-
elif filepath.suffix
|
746
|
+
elif filepath.suffix == ".zarr":
|
747
747
|
conn, storage = registry.open("zarr", filepath)
|
748
748
|
else:
|
749
749
|
raise ValueError(
|
750
|
-
"
|
750
|
+
"object should have .h5, .hdf5, .h5ad, .zarr suffix, not"
|
751
751
|
f" {filepath.suffix}."
|
752
752
|
)
|
753
753
|
|
754
|
-
if filepath.suffix
|
754
|
+
if filepath.suffix == ".h5ad":
|
755
755
|
return AnnDataAccessor(conn, storage, name)
|
756
756
|
else:
|
757
757
|
if get_spec(storage).encoding_type == "anndata":
|
@@ -21,11 +21,10 @@ def infer_suffix(dmem, adata_format: str | None = None):
|
|
21
21
|
"""Infer LaminDB storage file suffix from a data object."""
|
22
22
|
if isinstance(dmem, AnnData):
|
23
23
|
if adata_format is not None:
|
24
|
-
|
25
|
-
if adata_format not in ("h5ad", "zarr", "zrad"):
|
24
|
+
if adata_format not in ("h5ad", "zarr"):
|
26
25
|
raise ValueError(
|
27
26
|
"Error when specifying AnnData storage format, it should be"
|
28
|
-
f" 'h5ad', 'zarr'
|
27
|
+
f" 'h5ad', 'zarr', not '{adata_format}'. Check 'format'"
|
29
28
|
" or the suffix of 'key'."
|
30
29
|
)
|
31
30
|
return "." + adata_format
|
@@ -109,23 +109,23 @@ def read_adata_h5ad(filepath, **kwargs) -> ad.AnnData:
|
|
109
109
|
return adata
|
110
110
|
|
111
111
|
|
112
|
-
def
|
113
|
-
"""Store
|
114
|
-
|
115
|
-
if not isinstance(
|
112
|
+
def store_file_or_folder(local_path: UPathStr, storage_path: UPath) -> None:
|
113
|
+
"""Store file or folder (localpath) at storagepath."""
|
114
|
+
local_path = Path(local_path)
|
115
|
+
if not isinstance(storage_path, LocalPathClasses):
|
116
116
|
# this uploads files and directories
|
117
|
-
|
117
|
+
storage_path.upload_from(local_path, recursive=True, print_progress=True)
|
118
118
|
else: # storage path is local
|
119
|
-
|
120
|
-
if
|
119
|
+
storage_path.parent.mkdir(parents=True, exist_ok=True)
|
120
|
+
if local_path.is_file():
|
121
121
|
try:
|
122
|
-
shutil.copyfile(
|
122
|
+
shutil.copyfile(local_path, storage_path)
|
123
123
|
except shutil.SameFileError:
|
124
124
|
pass
|
125
125
|
else:
|
126
|
-
if
|
127
|
-
shutil.rmtree(
|
128
|
-
shutil.copytree(
|
126
|
+
if storage_path.exists():
|
127
|
+
shutil.rmtree(storage_path)
|
128
|
+
shutil.copytree(local_path, storage_path)
|
129
129
|
|
130
130
|
|
131
131
|
def delete_storage_using_key(
|
@@ -212,7 +212,7 @@ def load_to_memory(filepath: UPathStr, stream: bool = False, **kwargs):
|
|
212
212
|
"""
|
213
213
|
filepath = create_path(filepath)
|
214
214
|
|
215
|
-
if filepath.suffix not in {".h5ad", ".zarr"
|
215
|
+
if filepath.suffix not in {".h5ad", ".zarr"}:
|
216
216
|
stream = False
|
217
217
|
|
218
218
|
if not stream:
|
@@ -229,7 +229,6 @@ def load_to_memory(filepath: UPathStr, stream: bool = False, **kwargs):
|
|
229
229
|
".parquet": pd.read_parquet,
|
230
230
|
".fcs": read_fcs,
|
231
231
|
".zarr": read_adata_zarr,
|
232
|
-
".zrad": read_adata_zarr,
|
233
232
|
".html": load_html,
|
234
233
|
".json": load_json,
|
235
234
|
".h5mu": read_mdata_h5mu,
|
@@ -8,6 +8,8 @@ import lamindb_setup as ln_setup
|
|
8
8
|
from lamin_utils import logger
|
9
9
|
|
10
10
|
from lamindb._artifact import Artifact
|
11
|
+
from lamindb._run import Run
|
12
|
+
from lamindb._transform import Transform
|
11
13
|
|
12
14
|
if TYPE_CHECKING:
|
13
15
|
from vitessce import VitessceConfig
|
@@ -15,36 +17,54 @@ if TYPE_CHECKING:
|
|
15
17
|
|
16
18
|
# tested & context in https://github.com/laminlabs/lamin-spatial
|
17
19
|
def save_vitessce_config(vitessce_config: VitessceConfig, description: str) -> Artifact:
|
18
|
-
"""
|
20
|
+
"""Validates and saves a ``VitessceConfig`` object.
|
21
|
+
|
22
|
+
Example: :doc:`docs:vitessce`.
|
19
23
|
|
20
24
|
Args:
|
21
25
|
vitessce_config (``VitessceConfig``): A VitessceConfig object.
|
22
26
|
description: A description for the artifact.
|
23
|
-
"""
|
24
|
-
# can't assume vitessce is installed
|
25
|
-
from vitessce import VitessceConfig
|
26
27
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
vitessce_config.
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
28
|
+
.. versionchanged:: 0.70.2
|
29
|
+
This function no longer saves the dataset. It only saves the VitessceConfig object.
|
30
|
+
"""
|
31
|
+
vc_dict = vitessce_config.to_dict()
|
32
|
+
# validate
|
33
|
+
datasets = vc_dict["datasets"]
|
34
|
+
input_artifacts = []
|
35
|
+
for dataset in datasets:
|
36
|
+
if "files" not in dataset:
|
37
|
+
raise ValueError("Each dataset must have a 'files' key.")
|
38
|
+
for file in dataset["files"]:
|
39
|
+
if "url" not in file:
|
40
|
+
raise ValueError("Each file must have a 'url' key.")
|
41
|
+
filename = file["url"].split("/")[-1]
|
42
|
+
assert filename.endswith((".anndata.zarr", ".spatialdata.zarr", ".zarr"))
|
43
|
+
filestem = (
|
44
|
+
filename.replace(".anndata.zarr", "")
|
45
|
+
.replace(".spatialdata.zarr", "")
|
46
|
+
.replace(".zarr", "")
|
47
|
+
)
|
48
|
+
artifact = Artifact.filter(uid__startswith=filestem).one_or_none()
|
49
|
+
if artifact is None:
|
50
|
+
logger.warning(f"could not find dataset in lamindb: {dataset}")
|
51
|
+
else:
|
52
|
+
input_artifacts.append(artifact)
|
53
|
+
# link inputs
|
54
|
+
with logger.mute():
|
55
|
+
transform = Transform(name="save_vitessce_config", type="function", version="1")
|
56
|
+
transform.save()
|
57
|
+
run = Run(transform=transform)
|
58
|
+
run.save()
|
59
|
+
run.input_artifacts.set(input_artifacts)
|
60
|
+
# create a JSON export
|
61
|
+
config_file_local_path = (
|
62
|
+
ln_setup.settings.storage.cache_dir / "config.vitessce.json"
|
63
|
+
)
|
41
64
|
with open(config_file_local_path, "w") as file:
|
42
|
-
json.dump(
|
43
|
-
|
44
|
-
|
45
|
-
config_file_path.upload_from(config_file_local_path)
|
46
|
-
# log the the URLs
|
47
|
-
logger.important(f"config url: {config_file_path.to_url()}")
|
65
|
+
json.dump(vc_dict, file)
|
66
|
+
artifact = Artifact(config_file_local_path, description=description, run=run)
|
67
|
+
artifact.save()
|
48
68
|
slug = ln_setup.settings.instance.slug
|
49
69
|
logger.important(f"go to: https://lamin.ai/{slug}/artifact/{artifact.uid}")
|
50
70
|
return artifact
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: lamindb
|
3
|
-
Version: 0.70.
|
3
|
+
Version: 0.70.2
|
4
4
|
Summary: A data framework for biology.
|
5
5
|
Author-email: Lamin Labs <open-source@lamin.ai>
|
6
6
|
Requires-Python: >=3.8
|
@@ -9,9 +9,9 @@ Classifier: Programming Language :: Python :: 3.8
|
|
9
9
|
Classifier: Programming Language :: Python :: 3.9
|
10
10
|
Classifier: Programming Language :: Python :: 3.10
|
11
11
|
Classifier: Programming Language :: Python :: 3.11
|
12
|
-
Requires-Dist: lnschema_core==0.65.
|
13
|
-
Requires-Dist: lamindb_setup==0.69.
|
14
|
-
Requires-Dist: lamin_utils==0.13.
|
12
|
+
Requires-Dist: lnschema_core==0.65.1
|
13
|
+
Requires-Dist: lamindb_setup==0.69.4
|
14
|
+
Requires-Dist: lamin_utils==0.13.2
|
15
15
|
Requires-Dist: lamin_cli==0.12.3
|
16
16
|
Requires-Dist: rapidfuzz
|
17
17
|
Requires-Dist: pyarrow
|
@@ -27,7 +27,7 @@ Requires-Dist: urllib3<2 ; extra == "aws"
|
|
27
27
|
Requires-Dist: aiobotocore[boto3]>=2.5.4,<3.0.0 ; extra == "aws"
|
28
28
|
Requires-Dist: s3fs==2023.12.2 ; extra == "aws"
|
29
29
|
Requires-Dist: fsspec[s3]==2023.12.2 ; extra == "aws"
|
30
|
-
Requires-Dist: bionty==0.42.
|
30
|
+
Requires-Dist: bionty==0.42.9 ; extra == "bionty"
|
31
31
|
Requires-Dist: pandas<2 ; extra == "dev"
|
32
32
|
Requires-Dist: pre-commit ; extra == "dev"
|
33
33
|
Requires-Dist: nox ; extra == "dev"
|
@@ -1,20 +1,20 @@
|
|
1
|
-
lamindb/__init__.py,sha256=
|
2
|
-
lamindb/_annotate.py,sha256=
|
3
|
-
lamindb/_artifact.py,sha256=
|
4
|
-
lamindb/_can_validate.py,sha256=
|
5
|
-
lamindb/_collection.py,sha256=
|
1
|
+
lamindb/__init__.py,sha256=JHrhBHkihUcLRbreh9xyafsWang75NJxz9CVIWx6Bc0,2163
|
2
|
+
lamindb/_annotate.py,sha256=B0KSvo5S2kJPeMMqy2SSFkqRJCS2QRC4NtI0_vWEZMs,43080
|
3
|
+
lamindb/_artifact.py,sha256=BUl_3WYwrZ28P93Pb9AiwriVFBSLvBUEQjYEyYCrkZ0,37307
|
4
|
+
lamindb/_can_validate.py,sha256=nvoZG-35n3HofkY4Xc6hBv9AV54_RDan7Hzp5TuqY9I,14709
|
5
|
+
lamindb/_collection.py,sha256=wf7ClfiD3vsetts_iSUk4UihWsHq0IdOF8LdIIHS7JU,14536
|
6
6
|
lamindb/_feature.py,sha256=srAKchY7gqD-h-cWlEiAWuHlpFKFwv0PWIA-JX0Go8c,6758
|
7
7
|
lamindb/_feature_set.py,sha256=AzjOcHzQajpeikPOAic-aj0z_C5b7VpHVegg3ThRSLw,9045
|
8
8
|
lamindb/_filter.py,sha256=xnjJzjF3Zj4dK_Kfymvhgczk27MhhXz5ZYc7XINbgHY,1331
|
9
|
-
lamindb/_finish.py,sha256=
|
10
|
-
lamindb/_from_values.py,sha256=
|
9
|
+
lamindb/_finish.py,sha256=oR7oe6By3vEhF0twDBqSdT1EF28MPhyiS_cfZP0CcCw,8040
|
10
|
+
lamindb/_from_values.py,sha256=DVXjnQ2wwNw-2bFzy0uXLdVlqoprrn95hTnrXwn-KqM,12638
|
11
11
|
lamindb/_is_versioned.py,sha256=0PgRCmxEmYDcAjllLSOYZm132B1lW6QgmBBERhRyFt0,1341
|
12
12
|
lamindb/_parents.py,sha256=N9T8jbd3eaoHDLE9TD1y1QgGcO81E6Brapy8LILzRCQ,14790
|
13
13
|
lamindb/_query_manager.py,sha256=3zokXqxgj9vTJBnN2sbYKS-q69fyDDPF_aGq_rFHzXU,4066
|
14
14
|
lamindb/_query_set.py,sha256=fy6xMK9MPGbD8D_i5iNzR8XA009W05ud4tbgrzd5-Vg,11287
|
15
|
-
lamindb/_registry.py,sha256
|
15
|
+
lamindb/_registry.py,sha256=-Bv10zSr6IY7QM5pu_35NiVjQDJnBcXRECVe9h7GEuY,19336
|
16
16
|
lamindb/_run.py,sha256=b7A52M1On3QzFgIYyfQoz5Kk7V3wcu9p_Prq5bzd8v8,1838
|
17
|
-
lamindb/_save.py,sha256=
|
17
|
+
lamindb/_save.py,sha256=x16FBwltaTd1tnXm_zCxkvuVxyon6vRtekf37CfepXg,11426
|
18
18
|
lamindb/_storage.py,sha256=VW8xq3VRv58-ciholvOdlcgvp_OIlLxx5GxLt-e2Irs,614
|
19
19
|
lamindb/_transform.py,sha256=rxojJ91qQSkeYDHYbwqjFAYxBMgJd3cq_K7Z0n5g8Aw,3482
|
20
20
|
lamindb/_ulabel.py,sha256=e5dw9h1tR0_u-DMn7Gzx0WhUhV5w7j4v3QbnLWQV7eI,1941
|
@@ -38,17 +38,18 @@ lamindb/core/versioning.py,sha256=DsEHpCueNwhRiIaRH5-O8H_1fJVNtWslCRx30YiIS5o,30
|
|
38
38
|
lamindb/core/datasets/__init__.py,sha256=zRP98oqUAaXhqWyKMiH0s_ImVIuNeziQQ2kQ_t0f-DI,1353
|
39
39
|
lamindb/core/datasets/_core.py,sha256=36vUOYFkX_4hBAnM_BujV5BRARMI5b9iI_SM9qS7wGc,20191
|
40
40
|
lamindb/core/datasets/_fake.py,sha256=BZF9R_1iF0HDnvtZNqL2FtsjSMuqDIfuFxnw_LJYIh4,953
|
41
|
-
lamindb/core/storage/__init__.py,sha256=
|
41
|
+
lamindb/core/storage/__init__.py,sha256=6jnbFj-eBV3xZt04qP-kTsMWoP8YwpM50wlnnxDYsZU,415
|
42
42
|
lamindb/core/storage/_anndata_sizes.py,sha256=aXO3OB--tF5MChenSsigW6Q-RuE8YJJOUTVukkLrv9A,1029
|
43
|
-
lamindb/core/storage/_backed_access.py,sha256=
|
43
|
+
lamindb/core/storage/_backed_access.py,sha256=eManrLsu3pSSQAyAKy47FDBm-iHgjaNfHA-zLy59uDs,24536
|
44
|
+
lamindb/core/storage/_valid_suffixes.py,sha256=sewRRU3I6fJ-Jd5ACNcco_o3hic9zmqTs8BuZui-450,133
|
44
45
|
lamindb/core/storage/_zarr.py,sha256=0i9-cJPjieIsp5UpK-IyRPkHAF-iKkWgpkWviSni2MM,2900
|
45
|
-
lamindb/core/storage/
|
46
|
-
lamindb/core/storage/
|
46
|
+
lamindb/core/storage/objects.py,sha256=5LbBeZVKuOOB8DceSE-PN8elKY0N9OhFXZPQJE4lK48,1538
|
47
|
+
lamindb/core/storage/paths.py,sha256=XWfSHK5b3_TFiK-IMvH-srvxO0bZStzA_rwjNaTxQU4,7725
|
47
48
|
lamindb/integrations/__init__.py,sha256=aH2PmO2m4-vwIifMYTB0Fyyr_gZWtVnV71jT0tVWSw0,123
|
48
|
-
lamindb/integrations/_vitessce.py,sha256=
|
49
|
+
lamindb/integrations/_vitessce.py,sha256=Ii2YhGwXH_tNDS9MXzxNekthWoDmDGpgGxAOVcTIbB4,2550
|
49
50
|
lamindb/setup/__init__.py,sha256=OwZpZzPDv5lPPGXZP7-zK6UdO4FHvvuBh439yZvIp3A,410
|
50
51
|
lamindb/setup/core/__init__.py,sha256=SevlVrc2AZWL3uALbE5sopxBnIZPWZ1IB0NBDudiAL8,167
|
51
|
-
lamindb-0.70.
|
52
|
-
lamindb-0.70.
|
53
|
-
lamindb-0.70.
|
54
|
-
lamindb-0.70.
|
52
|
+
lamindb-0.70.2.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
53
|
+
lamindb-0.70.2.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81
|
54
|
+
lamindb-0.70.2.dist-info/METADATA,sha256=KqXBjKMhKMBbx7VYeaWWfP0Xot_OyRRjpFO9vZotb7c,2835
|
55
|
+
lamindb-0.70.2.dist-info/RECORD,,
|
File without changes
|
File without changes
|