lamindb 0.70.2__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/_artifact.py +51 -18
- lamindb/_collection.py +2 -1
- lamindb/core/_run_context.py +5 -0
- lamindb/core/storage/_zarr.py +27 -11
- lamindb/core/storage/paths.py +2 -2
- {lamindb-0.70.2.dist-info → lamindb-0.70.3.dist-info}/METADATA +2 -2
- {lamindb-0.70.2.dist-info → lamindb-0.70.3.dist-info}/RECORD +10 -10
- {lamindb-0.70.2.dist-info → lamindb-0.70.3.dist-info}/LICENSE +0 -0
- {lamindb-0.70.2.dist-info → lamindb-0.70.3.dist-info}/WHEEL +0 -0
lamindb/__init__.py
CHANGED
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/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/_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():
|
@@ -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,7 +10,7 @@ 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.
|
13
|
+
Requires-Dist: lamindb_setup==0.69.5
|
14
14
|
Requires-Dist: lamin_utils==0.13.2
|
15
15
|
Requires-Dist: lamin_cli==0.12.3
|
16
16
|
Requires-Dist: rapidfuzz
|
@@ -1,8 +1,8 @@
|
|
1
|
-
lamindb/__init__.py,sha256=
|
1
|
+
lamindb/__init__.py,sha256=y-amn3quDKMdf4F0-sm8mFvjJButkNAFPpwMP5bZNj0,2163
|
2
2
|
lamindb/_annotate.py,sha256=B0KSvo5S2kJPeMMqy2SSFkqRJCS2QRC4NtI0_vWEZMs,43080
|
3
|
-
lamindb/_artifact.py,sha256=
|
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
|
@@ -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
|
@@ -42,14 +42,14 @@ lamindb/core/storage/__init__.py,sha256=6jnbFj-eBV3xZt04qP-kTsMWoP8YwpM50wlnnxDY
|
|
42
42
|
lamindb/core/storage/_anndata_sizes.py,sha256=aXO3OB--tF5MChenSsigW6Q-RuE8YJJOUTVukkLrv9A,1029
|
43
43
|
lamindb/core/storage/_backed_access.py,sha256=eManrLsu3pSSQAyAKy47FDBm-iHgjaNfHA-zLy59uDs,24536
|
44
44
|
lamindb/core/storage/_valid_suffixes.py,sha256=sewRRU3I6fJ-Jd5ACNcco_o3hic9zmqTs8BuZui-450,133
|
45
|
-
lamindb/core/storage/_zarr.py,sha256=
|
45
|
+
lamindb/core/storage/_zarr.py,sha256=5ceEz6YIvgvUnVVNWhK5Z4W0WfrvyvY82Yna5jSX1_E,3661
|
46
46
|
lamindb/core/storage/objects.py,sha256=5LbBeZVKuOOB8DceSE-PN8elKY0N9OhFXZPQJE4lK48,1538
|
47
|
-
lamindb/core/storage/paths.py,sha256=
|
47
|
+
lamindb/core/storage/paths.py,sha256=kvu4Xi4dvreXpg4iuskN_nd2yyGmEdCmoIfi3nCrTyo,7728
|
48
48
|
lamindb/integrations/__init__.py,sha256=aH2PmO2m4-vwIifMYTB0Fyyr_gZWtVnV71jT0tVWSw0,123
|
49
49
|
lamindb/integrations/_vitessce.py,sha256=Ii2YhGwXH_tNDS9MXzxNekthWoDmDGpgGxAOVcTIbB4,2550
|
50
50
|
lamindb/setup/__init__.py,sha256=OwZpZzPDv5lPPGXZP7-zK6UdO4FHvvuBh439yZvIp3A,410
|
51
51
|
lamindb/setup/core/__init__.py,sha256=SevlVrc2AZWL3uALbE5sopxBnIZPWZ1IB0NBDudiAL8,167
|
52
|
-
lamindb-0.70.
|
53
|
-
lamindb-0.70.
|
54
|
-
lamindb-0.70.
|
55
|
-
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
|