lamindb 0.70.1__py3-none-any.whl → 0.70.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/__init__.py +1 -1
- lamindb/_annotate.py +4 -4
- lamindb/_artifact.py +51 -18
- lamindb/_collection.py +2 -1
- lamindb/_finish.py +31 -29
- lamindb/core/_run_context.py +5 -0
- lamindb/core/storage/__init__.py +1 -0
- lamindb/core/storage/_backed_access.py +3 -3
- lamindb/core/storage/_valid_suffixes.py +3 -0
- lamindb/core/storage/_zarr.py +27 -11
- lamindb/core/storage/paths.py +2 -2
- lamindb/integrations/_vitessce.py +44 -24
- {lamindb-0.70.1.dist-info → lamindb-0.70.3.dist-info}/METADATA +3 -3
- {lamindb-0.70.1.dist-info → lamindb-0.70.3.dist-info}/RECORD +16 -15
- {lamindb-0.70.1.dist-info → lamindb-0.70.3.dist-info}/LICENSE +0 -0
- {lamindb-0.70.1.dist-info → lamindb-0.70.3.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
@@ -1,7 +1,7 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
3
|
from pathlib import Path, PurePath, PurePosixPath
|
4
|
-
from typing import TYPE_CHECKING, Any
|
4
|
+
from typing import TYPE_CHECKING, Any, Mapping
|
5
5
|
|
6
6
|
import fsspec
|
7
7
|
import lamindb_setup as ln_setup
|
@@ -26,7 +26,7 @@ from lnschema_core.types import (
|
|
26
26
|
)
|
27
27
|
|
28
28
|
from lamindb._utils import attach_func_to_class_method
|
29
|
-
from lamindb.core._data import _track_run_input
|
29
|
+
from lamindb.core._data import Data, _track_run_input
|
30
30
|
from lamindb.core._settings import settings
|
31
31
|
from lamindb.core.storage import (
|
32
32
|
LocalPathClasses,
|
@@ -53,6 +53,14 @@ from .core._data import (
|
|
53
53
|
from .core.storage.objects import _mudata_is_installed
|
54
54
|
from .core.storage.paths import AUTO_KEY_PREFIX
|
55
55
|
|
56
|
+
try:
|
57
|
+
from .core.storage._zarr import zarr_is_adata
|
58
|
+
except ImportError:
|
59
|
+
|
60
|
+
def zarr_is_adata(storepath): # type: ignore
|
61
|
+
raise ImportError("Please install zarr: pip install zarr")
|
62
|
+
|
63
|
+
|
56
64
|
if TYPE_CHECKING:
|
57
65
|
from lamindb_setup.core.types import UPathStr
|
58
66
|
from mudata import MuData
|
@@ -329,16 +337,17 @@ def get_artifact_kwargs_from_data(
|
|
329
337
|
using_key=using_key,
|
330
338
|
)
|
331
339
|
if isinstance(stat_or_artifact, Artifact):
|
340
|
+
artifact = stat_or_artifact
|
332
341
|
# update the run of the existing artifact
|
333
342
|
if run is not None:
|
334
343
|
# save the information that this artifact was previously
|
335
344
|
# produced by another run
|
336
|
-
if
|
337
|
-
|
345
|
+
if artifact.run is not None:
|
346
|
+
artifact.run.replicated_output_artifacts.add(artifact)
|
338
347
|
# update the run of the artifact with the latest run
|
339
348
|
stat_or_artifact.run = run
|
340
349
|
stat_or_artifact.transform = run.transform
|
341
|
-
return
|
350
|
+
return artifact, None
|
342
351
|
else:
|
343
352
|
size, hash, hash_type, n_objects = stat_or_artifact
|
344
353
|
|
@@ -446,12 +455,19 @@ def data_is_anndata(data: AnnData | UPathStr):
|
|
446
455
|
if isinstance(data, AnnData):
|
447
456
|
return True
|
448
457
|
if isinstance(data, (str, Path, UPath)):
|
449
|
-
|
458
|
+
data_path = UPath(data)
|
459
|
+
if data_path.suffix == ".h5ad":
|
450
460
|
return True
|
451
|
-
elif
|
452
|
-
|
453
|
-
|
454
|
-
|
461
|
+
elif data_path.suffix == ".zarr":
|
462
|
+
# ".anndata.zarr" is a valid suffix (core.storage._valid_suffixes)
|
463
|
+
if ".anndata" in data_path.suffixes:
|
464
|
+
return True
|
465
|
+
# check only for local, expensive for cloud
|
466
|
+
if fsspec.utils.get_protocol(data_path) == "file":
|
467
|
+
return zarr_is_adata(data_path)
|
468
|
+
else:
|
469
|
+
logger.warning("We do not check if cloud zarr is AnnData or not.")
|
470
|
+
return False
|
455
471
|
return False
|
456
472
|
|
457
473
|
|
@@ -461,27 +477,39 @@ def data_is_mudata(data: MuData | UPathStr):
|
|
461
477
|
|
462
478
|
if isinstance(data, MuData):
|
463
479
|
return True
|
464
|
-
if isinstance(data, (str, Path
|
465
|
-
return
|
480
|
+
if isinstance(data, (str, Path)):
|
481
|
+
return UPath(data).suffix in {".h5mu"}
|
466
482
|
return False
|
467
483
|
|
468
484
|
|
469
485
|
def _check_accessor_artifact(data: Any, accessor: str | None = None):
|
470
|
-
if accessor is None
|
486
|
+
if accessor is None:
|
471
487
|
if isinstance(data, pd.DataFrame):
|
472
488
|
logger.warning("data is a DataFrame, please use .from_df()")
|
473
489
|
accessor = "DataFrame"
|
474
|
-
|
475
|
-
|
490
|
+
return accessor
|
491
|
+
|
492
|
+
data_is_path = isinstance(data, (str, Path))
|
493
|
+
if data_is_anndata(data):
|
494
|
+
if not data_is_path:
|
495
|
+
logger.warning("data is an AnnData, please use .from_anndata()")
|
476
496
|
accessor = "AnnData"
|
477
497
|
elif data_is_mudata(data):
|
478
|
-
|
498
|
+
if not data_is_path:
|
499
|
+
logger.warning("data is a MuData, please use .from_mudata()")
|
479
500
|
accessor = "MuData"
|
480
|
-
|
501
|
+
elif not data_is_path: # UPath is a subclass of Path
|
481
502
|
raise TypeError("data has to be a string, Path, UPath")
|
482
503
|
return accessor
|
483
504
|
|
484
505
|
|
506
|
+
def update_attributes(data: Data, attributes: Mapping[str, str]):
|
507
|
+
for key, value in attributes.items():
|
508
|
+
if getattr(data, key) != value:
|
509
|
+
logger.warning(f"updated {key} from {getattr(data, key)} to {value}")
|
510
|
+
setattr(data, key, value)
|
511
|
+
|
512
|
+
|
485
513
|
def __init__(artifact: Artifact, *args, **kwargs):
|
486
514
|
# Below checks for the Django-internal call in from_db()
|
487
515
|
# it'd be better if we could avoid this, but not being able to create a Artifact
|
@@ -558,8 +586,13 @@ def __init__(artifact: Artifact, *args, **kwargs):
|
|
558
586
|
if isinstance(kwargs_or_artifact, Artifact):
|
559
587
|
from ._registry import init_self_from_db
|
560
588
|
|
561
|
-
# kwargs_or_artifact is an existing file
|
562
589
|
init_self_from_db(artifact, kwargs_or_artifact)
|
590
|
+
# adding "key" here is dangerous because key might be auto-populated
|
591
|
+
update_attributes(artifact, {"description": description})
|
592
|
+
if artifact.key != key:
|
593
|
+
logger.warning(
|
594
|
+
f"key {artifact.key} on existing artifact differs from passed key {key}"
|
595
|
+
)
|
563
596
|
return None
|
564
597
|
else:
|
565
598
|
kwargs = kwargs_or_artifact
|
lamindb/_collection.py
CHANGED
@@ -18,13 +18,13 @@ from lamindb_setup.core.hashing import hash_set
|
|
18
18
|
from lnschema_core.models import Collection, CollectionArtifact, FeatureSet
|
19
19
|
from lnschema_core.types import VisibilityChoice
|
20
20
|
|
21
|
+
from lamindb._artifact import update_attributes
|
21
22
|
from lamindb._utils import attach_func_to_class_method
|
22
23
|
from lamindb.core._data import _track_run_input
|
23
24
|
from lamindb.core._mapped_collection import MappedCollection
|
24
25
|
from lamindb.core.versioning import get_uid_from_old_version, init_uid
|
25
26
|
|
26
27
|
from . import Artifact, Run
|
27
|
-
from ._artifact import data_is_anndata
|
28
28
|
from ._registry import init_self_from_db
|
29
29
|
from .core._data import (
|
30
30
|
add_transform_to_kwargs,
|
@@ -128,6 +128,7 @@ def __init__(
|
|
128
128
|
existing_collection.run = run
|
129
129
|
existing_collection.transform = run.transform
|
130
130
|
init_self_from_db(collection, existing_collection)
|
131
|
+
update_attributes(collection, {"description": description, "name": name})
|
131
132
|
for slot, feature_set in collection.features._feature_set_by_slot.items():
|
132
133
|
if slot in feature_sets:
|
133
134
|
if not feature_sets[slot] == feature_set:
|
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/core/_run_context.py
CHANGED
@@ -306,6 +306,11 @@ class run_context:
|
|
306
306
|
if not is_tracked:
|
307
307
|
raise_transform_settings_error()
|
308
308
|
else:
|
309
|
+
if transform.type in {"notebook", "script"}:
|
310
|
+
raise ValueError(
|
311
|
+
"Use ln.track() without passing transform in a notebook or script"
|
312
|
+
" - metadata is automatically parsed"
|
313
|
+
)
|
309
314
|
transform_exists = None
|
310
315
|
if transform.id is not None:
|
311
316
|
# transform has an id but unclear whether already saved
|
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 ._valid_suffixes import VALID_SUFFIXES
|
13
14
|
from .objects import infer_suffix, write_to_file
|
14
15
|
from .paths import delete_storage, load_to_memory
|
@@ -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)
|
@@ -747,11 +747,11 @@ def backed_access(
|
|
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":
|
lamindb/core/storage/_zarr.py
CHANGED
@@ -7,28 +7,44 @@ import scipy.sparse as sparse
|
|
7
7
|
import zarr
|
8
8
|
from anndata._io import read_zarr
|
9
9
|
from anndata._io.specs import write_elem
|
10
|
+
from anndata._io.specs.registry import get_spec
|
11
|
+
from fsspec.implementations.local import LocalFileSystem
|
10
12
|
from lamindb_setup.core.upath import create_mapper, infer_filesystem
|
11
13
|
|
12
14
|
from ._anndata_sizes import _size_elem, _size_raw, size_adata
|
13
15
|
|
14
16
|
if TYPE_CHECKING:
|
15
17
|
from anndata import AnnData
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
18
|
+
from lamindb_setup.core.types import UPathStr
|
19
|
+
|
20
|
+
|
21
|
+
def zarr_is_adata(storepath: UPathStr) -> bool:
|
22
|
+
fs, storepath_str = infer_filesystem(storepath)
|
23
|
+
if isinstance(fs, LocalFileSystem):
|
24
|
+
# this is faster than through an fsspec mapper for local
|
25
|
+
open_obj = storepath_str
|
26
|
+
else:
|
27
|
+
open_obj = create_mapper(fs, storepath_str, check=True)
|
28
|
+
storage = zarr.open(open_obj, mode="r")
|
29
|
+
return get_spec(storage).encoding_type == "anndata"
|
30
|
+
|
31
|
+
|
32
|
+
def read_adata_zarr(storepath: UPathStr) -> AnnData:
|
33
|
+
fs, storepath_str = infer_filesystem(storepath)
|
34
|
+
if isinstance(fs, LocalFileSystem):
|
35
|
+
# this is faster than through an fsspec mapper for local
|
36
|
+
open_obj = storepath_str
|
37
|
+
else:
|
38
|
+
open_obj = create_mapper(fs, storepath_str, check=True)
|
39
|
+
adata = read_zarr(open_obj)
|
24
40
|
return adata
|
25
41
|
|
26
42
|
|
27
43
|
def write_adata_zarr(
|
28
|
-
adata: AnnData, storepath, callback=None, chunks=None, **dataset_kwargs
|
44
|
+
adata: AnnData, storepath: UPathStr, callback=None, chunks=None, **dataset_kwargs
|
29
45
|
):
|
30
|
-
fs,
|
31
|
-
store = create_mapper(fs,
|
46
|
+
fs, storepath_str = infer_filesystem(storepath)
|
47
|
+
store = create_mapper(fs, storepath_str, create=True)
|
32
48
|
|
33
49
|
f = zarr.open(store, mode="w")
|
34
50
|
|
lamindb/core/storage/paths.py
CHANGED
@@ -29,7 +29,7 @@ try:
|
|
29
29
|
from ._zarr import read_adata_zarr
|
30
30
|
except ImportError:
|
31
31
|
|
32
|
-
def read_adata_zarr(
|
32
|
+
def read_adata_zarr(storepath): # type: ignore
|
33
33
|
raise ImportError("Please install zarr: pip install zarr")
|
34
34
|
|
35
35
|
|
@@ -114,7 +114,7 @@ def store_file_or_folder(local_path: UPathStr, storage_path: UPath) -> None:
|
|
114
114
|
local_path = Path(local_path)
|
115
115
|
if not isinstance(storage_path, LocalPathClasses):
|
116
116
|
# this uploads files and directories
|
117
|
-
storage_path.upload_from(local_path,
|
117
|
+
storage_path.upload_from(local_path, dir_inplace=True, print_progress=True)
|
118
118
|
else: # storage path is local
|
119
119
|
storage_path.parent.mkdir(parents=True, exist_ok=True)
|
120
120
|
if local_path.is_file():
|
@@ -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.3
|
4
4
|
Summary: A data framework for biology.
|
5
5
|
Author-email: Lamin Labs <open-source@lamin.ai>
|
6
6
|
Requires-Python: >=3.8
|
@@ -10,8 +10,8 @@ Classifier: Programming Language :: Python :: 3.9
|
|
10
10
|
Classifier: Programming Language :: Python :: 3.10
|
11
11
|
Classifier: Programming Language :: Python :: 3.11
|
12
12
|
Requires-Dist: lnschema_core==0.65.1
|
13
|
-
Requires-Dist: lamindb_setup==0.69.
|
14
|
-
Requires-Dist: lamin_utils==0.13.
|
13
|
+
Requires-Dist: lamindb_setup==0.69.5
|
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
|
@@ -1,12 +1,12 @@
|
|
1
|
-
lamindb/__init__.py,sha256=
|
2
|
-
lamindb/_annotate.py,sha256=
|
3
|
-
lamindb/_artifact.py,sha256=
|
1
|
+
lamindb/__init__.py,sha256=y-amn3quDKMdf4F0-sm8mFvjJButkNAFPpwMP5bZNj0,2163
|
2
|
+
lamindb/_annotate.py,sha256=B0KSvo5S2kJPeMMqy2SSFkqRJCS2QRC4NtI0_vWEZMs,43080
|
3
|
+
lamindb/_artifact.py,sha256=SoGsS-uZP7AdrlEWuMC0l50EkNYSvtzrEiXzU5R6NWY,38557
|
4
4
|
lamindb/_can_validate.py,sha256=nvoZG-35n3HofkY4Xc6hBv9AV54_RDan7Hzp5TuqY9I,14709
|
5
|
-
lamindb/_collection.py,sha256=
|
5
|
+
lamindb/_collection.py,sha256=SDM35R_5WHrgLKjVb14Q8-Rz_gn5hdZLJobPcanm4PM,14627
|
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=
|
9
|
+
lamindb/_finish.py,sha256=oR7oe6By3vEhF0twDBqSdT1EF28MPhyiS_cfZP0CcCw,8040
|
10
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
|
@@ -25,7 +25,7 @@ lamindb/core/_data.py,sha256=En3v29eiJARy5l7nSsttAsDsqDLTZ4-xM8fCNyVzExI,17465
|
|
25
25
|
lamindb/core/_feature_manager.py,sha256=LlYgU71AoTnrseWFCq-oZkUAYWITtRR7BNFm0AhHe-c,15773
|
26
26
|
lamindb/core/_label_manager.py,sha256=0RtegYnK3zIisOnd970EobOrHMpp7OCH-mEoPrPXw2c,9075
|
27
27
|
lamindb/core/_mapped_collection.py,sha256=_OwFZh5SePDUD70XIK5kngv3we_Z5-YdGHNfpUSatSQ,19469
|
28
|
-
lamindb/core/_run_context.py,sha256=
|
28
|
+
lamindb/core/_run_context.py,sha256=tqKPNkryy4yc7vtYSIfGjUu_pJSBQt1Kx8Cbq9vwXK8,17726
|
29
29
|
lamindb/core/_settings.py,sha256=r9si7wJb31tI4vfz9dUN4iXe6QQU7FjnqAEsHy2UDzM,5727
|
30
30
|
lamindb/core/_sync_git.py,sha256=IlTqw55inPp_RZbN_YScaCeKza7LeF9mClQw55W3_d4,3921
|
31
31
|
lamindb/core/_track_environment.py,sha256=xLZ6kgzxWS6MWZ5LQ_wkbJX99vmYOT8iQ-Fz4OHCgWw,754
|
@@ -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=
|
44
|
-
lamindb/core/storage/
|
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
|
45
|
+
lamindb/core/storage/_zarr.py,sha256=5ceEz6YIvgvUnVVNWhK5Z4W0WfrvyvY82Yna5jSX1_E,3661
|
45
46
|
lamindb/core/storage/objects.py,sha256=5LbBeZVKuOOB8DceSE-PN8elKY0N9OhFXZPQJE4lK48,1538
|
46
|
-
lamindb/core/storage/paths.py,sha256=
|
47
|
+
lamindb/core/storage/paths.py,sha256=kvu4Xi4dvreXpg4iuskN_nd2yyGmEdCmoIfi3nCrTyo,7728
|
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.3.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
53
|
+
lamindb-0.70.3.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81
|
54
|
+
lamindb-0.70.3.dist-info/METADATA,sha256=CYkk_Pk8Xqup7tDkwgd2qiuibHZqAlMG3we02vXTIV8,2835
|
55
|
+
lamindb-0.70.3.dist-info/RECORD,,
|
File without changes
|
File without changes
|