lamindb 0.76.16__py3-none-any.whl → 0.77.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.
- lamindb/__init__.py +2 -2
- lamindb/{_can_validate.py → _can_curate.py} +7 -7
- lamindb/_curate.py +1 -1
- lamindb/_parents.py +8 -1
- lamindb/_query_set.py +8 -8
- lamindb/_record.py +74 -7
- lamindb/core/__init__.py +4 -2
- lamindb/core/_context.py +11 -6
- lamindb/core/_django.py +2 -2
- lamindb/core/_label_manager.py +2 -2
- lamindb/core/loaders.py +15 -5
- lamindb/core/storage/_zarr.py +8 -1
- {lamindb-0.76.16.dist-info → lamindb-0.77.0.dist-info}/METADATA +5 -5
- {lamindb-0.76.16.dist-info → lamindb-0.77.0.dist-info}/RECORD +16 -16
- {lamindb-0.76.16.dist-info → lamindb-0.77.0.dist-info}/LICENSE +0 -0
- {lamindb-0.76.16.dist-info → lamindb-0.77.0.dist-info}/WHEEL +0 -0
lamindb/__init__.py
CHANGED
@@ -43,7 +43,7 @@ Modules and settings.
|
|
43
43
|
"""
|
44
44
|
|
45
45
|
# denote a release candidate for 0.1.0 with 0.1rc1, 0.1a1, 0.1b1, etc.
|
46
|
-
__version__ = "0.
|
46
|
+
__version__ = "0.77.0"
|
47
47
|
|
48
48
|
import os as _os
|
49
49
|
|
@@ -79,7 +79,7 @@ if _check_instance_setup(from_module="lnschema_core"):
|
|
79
79
|
from . import core # isort: split
|
80
80
|
from . import (
|
81
81
|
_artifact,
|
82
|
-
|
82
|
+
_can_curate,
|
83
83
|
_collection,
|
84
84
|
_curate,
|
85
85
|
_feature,
|
@@ -8,7 +8,7 @@ import pandas as pd
|
|
8
8
|
from django.core.exceptions import FieldDoesNotExist
|
9
9
|
from lamin_utils import colors, logger
|
10
10
|
from lamindb_setup.core._docs import doc_args
|
11
|
-
from lnschema_core import
|
11
|
+
from lnschema_core import CanCurate, Record
|
12
12
|
|
13
13
|
from ._from_values import _has_organism_field, _print_values, get_or_create_records
|
14
14
|
from ._record import _queryset, get_name_field
|
@@ -23,7 +23,7 @@ if TYPE_CHECKING:
|
|
23
23
|
|
24
24
|
# from_values doesn't apply for QuerySet or Manager
|
25
25
|
@classmethod # type:ignore
|
26
|
-
@doc_args(
|
26
|
+
@doc_args(CanCurate.from_values.__doc__)
|
27
27
|
def from_values(
|
28
28
|
cls,
|
29
29
|
values: ListLike,
|
@@ -49,7 +49,7 @@ def from_values(
|
|
49
49
|
|
50
50
|
|
51
51
|
@classmethod # type: ignore
|
52
|
-
@doc_args(
|
52
|
+
@doc_args(CanCurate.inspect.__doc__)
|
53
53
|
def inspect(
|
54
54
|
cls,
|
55
55
|
values: ListLike,
|
@@ -71,7 +71,7 @@ def inspect(
|
|
71
71
|
|
72
72
|
|
73
73
|
@classmethod # type: ignore
|
74
|
-
@doc_args(
|
74
|
+
@doc_args(CanCurate.validate.__doc__)
|
75
75
|
def validate(
|
76
76
|
cls,
|
77
77
|
values: ListLike,
|
@@ -268,7 +268,7 @@ def _validate(
|
|
268
268
|
|
269
269
|
|
270
270
|
@classmethod # type: ignore
|
271
|
-
@doc_args(
|
271
|
+
@doc_args(CanCurate.standardize.__doc__)
|
272
272
|
def standardize(
|
273
273
|
cls,
|
274
274
|
values: ListLike,
|
@@ -621,10 +621,10 @@ if ln_setup._TESTING: # type: ignore
|
|
621
621
|
from inspect import signature
|
622
622
|
|
623
623
|
SIGS = {
|
624
|
-
name: signature(getattr(
|
624
|
+
name: signature(getattr(CanCurate, name))
|
625
625
|
for name in METHOD_NAMES
|
626
626
|
if not name.startswith("__")
|
627
627
|
}
|
628
628
|
|
629
629
|
for name in METHOD_NAMES:
|
630
|
-
attach_func_to_class_method(name,
|
630
|
+
attach_func_to_class_method(name, CanCurate, globals())
|
lamindb/_curate.py
CHANGED
@@ -1731,7 +1731,7 @@ def _save_organism(name: str): # pragma: no cover
|
|
1731
1731
|
|
1732
1732
|
def _ref_is_name(field: FieldAttr) -> bool | None:
|
1733
1733
|
"""Check if the reference field is a name field."""
|
1734
|
-
from .
|
1734
|
+
from ._can_curate import get_name_field
|
1735
1735
|
|
1736
1736
|
name_field = get_name_field(field.field.model)
|
1737
1737
|
return field.field.name == name_field
|
lamindb/_parents.py
CHANGED
@@ -19,7 +19,14 @@ if TYPE_CHECKING:
|
|
19
19
|
LAMIN_GREEN_LIGHTER = "#10b981"
|
20
20
|
LAMIN_GREEN_DARKER = "#065f46"
|
21
21
|
GREEN_FILL = "honeydew"
|
22
|
-
TRANSFORM_EMOJIS = {
|
22
|
+
TRANSFORM_EMOJIS = {
|
23
|
+
"notebook": "📔",
|
24
|
+
"upload": "🖥️",
|
25
|
+
"pipeline": "🧩",
|
26
|
+
"script": "📝",
|
27
|
+
"function": "🔧",
|
28
|
+
"glue": "🧲",
|
29
|
+
}
|
23
30
|
is_run_from_ipython = getattr(builtins, "__IPYTHON__", False)
|
24
31
|
|
25
32
|
|
lamindb/_query_set.py
CHANGED
@@ -12,7 +12,7 @@ from lamin_utils import colors, logger
|
|
12
12
|
from lamindb_setup.core._docs import doc_args
|
13
13
|
from lnschema_core.models import (
|
14
14
|
Artifact,
|
15
|
-
|
15
|
+
CanCurate,
|
16
16
|
Collection,
|
17
17
|
IsVersioned,
|
18
18
|
Record,
|
@@ -354,7 +354,7 @@ class QuerySet(models.QuerySet):
|
|
354
354
|
|
355
355
|
|
356
356
|
# -------------------------------------------------------------------------------------
|
357
|
-
#
|
357
|
+
# CanCurate
|
358
358
|
# -------------------------------------------------------------------------------------
|
359
359
|
|
360
360
|
|
@@ -374,26 +374,26 @@ def lookup(self, field: StrField | None = None, **kwargs) -> NamedTuple:
|
|
374
374
|
return _lookup(cls=self, field=field, **kwargs)
|
375
375
|
|
376
376
|
|
377
|
-
@doc_args(
|
377
|
+
@doc_args(CanCurate.validate.__doc__)
|
378
378
|
def validate(self, values: ListLike, field: str | StrField | None = None, **kwargs):
|
379
379
|
"""{}""" # noqa: D415
|
380
|
-
from .
|
380
|
+
from ._can_curate import _validate
|
381
381
|
|
382
382
|
return _validate(cls=self, values=values, field=field, **kwargs)
|
383
383
|
|
384
384
|
|
385
|
-
@doc_args(
|
385
|
+
@doc_args(CanCurate.inspect.__doc__)
|
386
386
|
def inspect(self, values: ListLike, field: str | StrField | None = None, **kwargs):
|
387
387
|
"""{}""" # noqa: D415
|
388
|
-
from .
|
388
|
+
from ._can_curate import _inspect
|
389
389
|
|
390
390
|
return _inspect(cls=self, values=values, field=field, **kwargs)
|
391
391
|
|
392
392
|
|
393
|
-
@doc_args(
|
393
|
+
@doc_args(CanCurate.standardize.__doc__)
|
394
394
|
def standardize(self, values: Iterable, field: str | StrField | None = None, **kwargs):
|
395
395
|
"""{}""" # noqa: D415
|
396
|
-
from .
|
396
|
+
from ._can_curate import _standardize
|
397
397
|
|
398
398
|
return _standardize(cls=self, values=values, field=field, **kwargs)
|
399
399
|
|
lamindb/_record.py
CHANGED
@@ -7,10 +7,20 @@ from typing import TYPE_CHECKING, NamedTuple
|
|
7
7
|
import dj_database_url
|
8
8
|
import lamindb_setup as ln_setup
|
9
9
|
from django.core.exceptions import FieldDoesNotExist
|
10
|
+
from django.core.exceptions import ValidationError as DjangoValidationError
|
10
11
|
from django.db import connections, transaction
|
11
12
|
from django.db.models import F, IntegerField, Manager, Q, QuerySet, TextField, Value
|
12
13
|
from django.db.models.functions import Cast, Coalesce
|
13
|
-
from django.db.models.lookups import
|
14
|
+
from django.db.models.lookups import (
|
15
|
+
Contains,
|
16
|
+
Exact,
|
17
|
+
IContains,
|
18
|
+
IExact,
|
19
|
+
IRegex,
|
20
|
+
IStartsWith,
|
21
|
+
Regex,
|
22
|
+
StartsWith,
|
23
|
+
)
|
14
24
|
from lamin_utils import colors, logger
|
15
25
|
from lamin_utils._lookup import Lookup
|
16
26
|
from lamindb_setup._connect_instance import (
|
@@ -32,7 +42,9 @@ from lnschema_core.models import (
|
|
32
42
|
Run,
|
33
43
|
Transform,
|
34
44
|
ULabel,
|
45
|
+
ValidateFields,
|
35
46
|
)
|
47
|
+
from lnschema_core.validation import FieldValidationError
|
36
48
|
|
37
49
|
from ._utils import attach_func_to_class_method
|
38
50
|
from .core._settings import settings
|
@@ -62,8 +74,11 @@ def update_attributes(record: Record, attributes: dict[str, str]):
|
|
62
74
|
setattr(record, key, value)
|
63
75
|
|
64
76
|
|
65
|
-
def
|
66
|
-
|
77
|
+
def validate_fields(record: Record, kwargs):
|
78
|
+
from lnschema_core.validation import validate_literal_fields
|
79
|
+
|
80
|
+
# validate required fields
|
81
|
+
# a "required field" is a Django field that has `null=False, default=None`
|
67
82
|
required_fields = {
|
68
83
|
k.name for k in record._meta.fields if not k.null and k.default is None
|
69
84
|
}
|
@@ -92,6 +107,8 @@ def validate_required_fields(record: Record, kwargs):
|
|
92
107
|
raise ValidationError(
|
93
108
|
f'`uid` must be exactly {uid_max_length} characters long, got {len(kwargs["uid"])}.'
|
94
109
|
)
|
110
|
+
# validate literals
|
111
|
+
validate_literal_fields(record, kwargs)
|
95
112
|
|
96
113
|
|
97
114
|
def suggest_records_with_similar_names(record: Record, name_field: str, kwargs) -> bool:
|
@@ -128,7 +145,7 @@ def suggest_records_with_similar_names(record: Record, name_field: str, kwargs)
|
|
128
145
|
|
129
146
|
def __init__(record: Record, *args, **kwargs):
|
130
147
|
if not args:
|
131
|
-
|
148
|
+
validate_fields(record, kwargs)
|
132
149
|
|
133
150
|
# do not search for names if an id is passed; this is important
|
134
151
|
# e.g. when synching ids from the notebook store to lamindb
|
@@ -136,9 +153,7 @@ def __init__(record: Record, *args, **kwargs):
|
|
136
153
|
if "_has_consciously_provided_uid" in kwargs:
|
137
154
|
has_consciously_provided_uid = kwargs.pop("_has_consciously_provided_uid")
|
138
155
|
if settings.creation.search_names and not has_consciously_provided_uid:
|
139
|
-
name_field = (
|
140
|
-
"name" if not hasattr(record, "_name_field") else record._name_field
|
141
|
-
)
|
156
|
+
name_field = getattr(record, "_name_field", "name")
|
142
157
|
match = suggest_records_with_similar_names(record, name_field, kwargs)
|
143
158
|
if match:
|
144
159
|
if "version" in kwargs:
|
@@ -169,6 +184,16 @@ def __init__(record: Record, *args, **kwargs):
|
|
169
184
|
init_self_from_db(record, existing_record)
|
170
185
|
return None
|
171
186
|
super(Record, record).__init__(**kwargs)
|
187
|
+
if isinstance(record, ValidateFields):
|
188
|
+
# this will trigger validation against django validators
|
189
|
+
try:
|
190
|
+
if hasattr(record, "clean_fields"):
|
191
|
+
record.clean_fields()
|
192
|
+
else:
|
193
|
+
record._Model__clean_fields()
|
194
|
+
except DjangoValidationError as e:
|
195
|
+
message = _format_django_validation_error(record, e)
|
196
|
+
raise FieldValidationError(message) from e
|
172
197
|
elif len(args) != len(record._meta.concrete_fields):
|
173
198
|
raise ValueError("please provide keyword arguments, not plain arguments")
|
174
199
|
else:
|
@@ -177,6 +202,37 @@ def __init__(record: Record, *args, **kwargs):
|
|
177
202
|
_store_record_old_name(record)
|
178
203
|
|
179
204
|
|
205
|
+
def _format_django_validation_error(record: Record, e: DjangoValidationError):
|
206
|
+
"""Pretty print Django validation errors."""
|
207
|
+
errors = {}
|
208
|
+
if hasattr(e, "error_dict"):
|
209
|
+
error_dict = e.error_dict
|
210
|
+
else:
|
211
|
+
error_dict = {"__all__": e.error_list}
|
212
|
+
|
213
|
+
for field_name, error_list in error_dict.items():
|
214
|
+
for error in error_list:
|
215
|
+
if hasattr(error, "message"):
|
216
|
+
msg = error.message
|
217
|
+
else:
|
218
|
+
msg = str(error)
|
219
|
+
|
220
|
+
if field_name == "__all__":
|
221
|
+
errors[field_name] = f"{colors.yellow(msg)}"
|
222
|
+
else:
|
223
|
+
current_value = getattr(record, field_name, None)
|
224
|
+
errors[field_name] = (
|
225
|
+
f"{field_name}: {colors.yellow(current_value)} is not valid\n → {msg}"
|
226
|
+
)
|
227
|
+
|
228
|
+
if errors:
|
229
|
+
message = "\n "
|
230
|
+
for _, error in errors.items():
|
231
|
+
message += error + "\n "
|
232
|
+
|
233
|
+
return message
|
234
|
+
|
235
|
+
|
180
236
|
@classmethod # type:ignore
|
181
237
|
@doc_args(Record.filter.__doc__)
|
182
238
|
def filter(cls, *queries, **expressions) -> QuerySet:
|
@@ -230,6 +286,7 @@ def _search(
|
|
230
286
|
) -> QuerySet:
|
231
287
|
input_queryset = _queryset(cls, using_key=using_key)
|
232
288
|
registry = input_queryset.model
|
289
|
+
name_field = getattr(registry, "_name_field", "name")
|
233
290
|
if field is None:
|
234
291
|
fields = [
|
235
292
|
field.name
|
@@ -306,6 +363,16 @@ def _search(
|
|
306
363
|
# also rank by contains
|
307
364
|
contains_rank = Cast(contains_expr, output_field=IntegerField())
|
308
365
|
ranks.append(contains_rank)
|
366
|
+
# additional rule for truncated strings
|
367
|
+
# weight matches from the beginning of the string higher
|
368
|
+
# sometimes whole words get truncated and startswith_expr is not enough
|
369
|
+
if truncate_string and field == name_field:
|
370
|
+
startswith_lookup = StartsWith if case_sensitive else IStartsWith
|
371
|
+
name_startswith_expr = startswith_lookup(field_expr, string)
|
372
|
+
name_startswith_rank = (
|
373
|
+
Cast(name_startswith_expr, output_field=IntegerField()) * 2
|
374
|
+
)
|
375
|
+
ranks.append(name_startswith_rank)
|
309
376
|
|
310
377
|
ranked_queryset = (
|
311
378
|
input_queryset.filter(reduce(lambda a, b: a | b, contains_filters))
|
lamindb/core/__init__.py
CHANGED
@@ -14,13 +14,14 @@ Registries:
|
|
14
14
|
ParamManager
|
15
15
|
LabelManager
|
16
16
|
IsVersioned
|
17
|
-
|
17
|
+
CanCurate
|
18
18
|
HasParents
|
19
19
|
TracksRun
|
20
20
|
TracksUpdates
|
21
21
|
ParamValue
|
22
22
|
FeatureValue
|
23
23
|
InspectResult
|
24
|
+
ValidateFields
|
24
25
|
fields
|
25
26
|
|
26
27
|
Curators:
|
@@ -67,7 +68,7 @@ Modules:
|
|
67
68
|
from lamin_utils import logger
|
68
69
|
from lamin_utils._inspect import InspectResult
|
69
70
|
from lnschema_core.models import (
|
70
|
-
|
71
|
+
CanCurate,
|
71
72
|
FeatureValue,
|
72
73
|
HasParents,
|
73
74
|
IsVersioned,
|
@@ -76,6 +77,7 @@ from lnschema_core.models import (
|
|
76
77
|
Registry,
|
77
78
|
TracksRun,
|
78
79
|
TracksUpdates,
|
80
|
+
ValidateFields,
|
79
81
|
)
|
80
82
|
|
81
83
|
from lamindb._curate import (
|
lamindb/core/_context.py
CHANGED
@@ -280,10 +280,12 @@ class Context:
|
|
280
280
|
transform_ref = None
|
281
281
|
transform_ref_type = None
|
282
282
|
else:
|
283
|
-
|
284
|
-
|
283
|
+
# the below function is typically used for `.py` scripts
|
284
|
+
# it is also used for `.Rmd` and `.qmd` files, which we classify
|
285
|
+
# as "notebook" because they typically come with an .html run report
|
286
|
+
(name, key, transform_type, transform_ref, transform_ref_type) = (
|
287
|
+
self._track_source_code(path=path)
|
285
288
|
)
|
286
|
-
transform_type = "script"
|
287
289
|
if self.uid is not None or transform_settings_are_set:
|
288
290
|
# overwrite whatever is auto-detected in the notebook or script
|
289
291
|
if self.name is not None:
|
@@ -366,11 +368,11 @@ class Context:
|
|
366
368
|
if self._logging_message_imports:
|
367
369
|
logger.important(self._logging_message_imports)
|
368
370
|
|
369
|
-
def
|
371
|
+
def _track_source_code(
|
370
372
|
self,
|
371
373
|
*,
|
372
374
|
path: UPathStr | None,
|
373
|
-
) -> tuple[str, str, str, str]:
|
375
|
+
) -> tuple[str, str, str, str, str]:
|
374
376
|
if path is None:
|
375
377
|
import inspect
|
376
378
|
|
@@ -379,6 +381,9 @@ class Context:
|
|
379
381
|
self._path = Path(module.__file__)
|
380
382
|
else:
|
381
383
|
self._path = Path(path)
|
384
|
+
transform_type = (
|
385
|
+
"notebook" if self._path.suffix in {".Rmd", ".qmd"} else "script"
|
386
|
+
)
|
382
387
|
name = self._path.name
|
383
388
|
key = name
|
384
389
|
reference = None
|
@@ -386,7 +391,7 @@ class Context:
|
|
386
391
|
if settings.sync_git_repo is not None:
|
387
392
|
reference = get_transform_reference_from_git_repo(self._path)
|
388
393
|
reference_type = "url"
|
389
|
-
return name, key, reference, reference_type
|
394
|
+
return name, key, transform_type, reference, reference_type
|
390
395
|
|
391
396
|
def _track_notebook(
|
392
397
|
self,
|
lamindb/core/_django.py
CHANGED
@@ -33,7 +33,7 @@ def get_artifact_with_related(
|
|
33
33
|
include_featureset: bool = False,
|
34
34
|
) -> dict:
|
35
35
|
"""Fetch an artifact with its related data."""
|
36
|
-
from lamindb.
|
36
|
+
from lamindb._can_curate import get_name_field
|
37
37
|
|
38
38
|
from ._label_manager import LABELS_EXCLUDE_SET
|
39
39
|
|
@@ -163,7 +163,7 @@ def get_featureset_m2m_relations(
|
|
163
163
|
artifact: Artifact, slot_featureset: dict, limit: int = 20
|
164
164
|
):
|
165
165
|
"""Fetch all many-to-many relationships for given feature sets."""
|
166
|
-
from lamindb.
|
166
|
+
from lamindb._can_curate import get_name_field
|
167
167
|
|
168
168
|
m2m_relations = [
|
169
169
|
v
|
lamindb/core/_label_manager.py
CHANGED
@@ -6,7 +6,7 @@ from typing import TYPE_CHECKING
|
|
6
6
|
import numpy as np
|
7
7
|
from django.db import connections
|
8
8
|
from lamin_utils import colors, logger
|
9
|
-
from lnschema_core.models import
|
9
|
+
from lnschema_core.models import CanCurate, Feature
|
10
10
|
|
11
11
|
from lamindb._from_values import _print_values
|
12
12
|
from lamindb._record import (
|
@@ -116,7 +116,7 @@ def validate_labels(labels: QuerySet | list | dict):
|
|
116
116
|
label_uids = np.array(
|
117
117
|
[getattr(label, field) for label in labels if label is not None]
|
118
118
|
)
|
119
|
-
if issubclass(registry,
|
119
|
+
if issubclass(registry, CanCurate):
|
120
120
|
validated = registry.validate(label_uids, field=field, mute=True)
|
121
121
|
validated_uids = label_uids[validated]
|
122
122
|
validated_labels = registry.filter(
|
lamindb/core/loaders.py
CHANGED
@@ -24,12 +24,13 @@ from typing import TYPE_CHECKING
|
|
24
24
|
|
25
25
|
import anndata as ad
|
26
26
|
import pandas as pd
|
27
|
+
from lamin_utils import logger
|
27
28
|
from lamindb_setup.core.upath import (
|
28
29
|
create_path,
|
29
30
|
infer_filesystem,
|
30
31
|
)
|
31
32
|
|
32
|
-
from
|
33
|
+
from ._settings import settings
|
33
34
|
|
34
35
|
if TYPE_CHECKING:
|
35
36
|
import mudata as md
|
@@ -79,7 +80,7 @@ def load_h5mu(filepath: UPathStr, **kwargs):
|
|
79
80
|
return md.read_h5mu(path_sanitized, **kwargs)
|
80
81
|
|
81
82
|
|
82
|
-
def load_html(path: UPathStr):
|
83
|
+
def load_html(path: UPathStr) -> None | UPathStr:
|
83
84
|
"""Display `.html` in ipython, otherwise return path."""
|
84
85
|
if is_run_from_ipython:
|
85
86
|
with open(path, encoding="utf-8") as f:
|
@@ -95,6 +96,7 @@ def load_html(path: UPathStr):
|
|
95
96
|
from IPython.display import HTML, display
|
96
97
|
|
97
98
|
display(HTML(data=body_content))
|
99
|
+
return None
|
98
100
|
else:
|
99
101
|
return path
|
100
102
|
|
@@ -108,17 +110,18 @@ def load_json(path: UPathStr) -> dict:
|
|
108
110
|
return data
|
109
111
|
|
110
112
|
|
111
|
-
def load_image(path: UPathStr):
|
113
|
+
def load_image(path: UPathStr) -> None | UPathStr:
|
112
114
|
"""Display `.svg` in ipython, otherwise return path."""
|
113
115
|
if is_run_from_ipython:
|
114
116
|
from IPython.display import Image, display
|
115
117
|
|
116
118
|
display(Image(filename=path))
|
119
|
+
return None
|
117
120
|
else:
|
118
121
|
return path
|
119
122
|
|
120
123
|
|
121
|
-
def load_svg(path: UPathStr) -> None |
|
124
|
+
def load_svg(path: UPathStr) -> None | UPathStr:
|
122
125
|
"""Display `.svg` in ipython, otherwise return path."""
|
123
126
|
if is_run_from_ipython:
|
124
127
|
from IPython.display import SVG, display
|
@@ -129,6 +132,12 @@ def load_svg(path: UPathStr) -> None | Path:
|
|
129
132
|
return path
|
130
133
|
|
131
134
|
|
135
|
+
def load_rds(path: UPathStr) -> UPathStr:
|
136
|
+
"""Just warn when trying to load `.rds`."""
|
137
|
+
logger.warning("Please use `laminr` to load `.rds` files")
|
138
|
+
return path
|
139
|
+
|
140
|
+
|
132
141
|
FILE_LOADERS = {
|
133
142
|
".csv": pd.read_csv,
|
134
143
|
".tsv": load_tsv,
|
@@ -142,9 +151,10 @@ FILE_LOADERS = {
|
|
142
151
|
".jpg": load_image,
|
143
152
|
".png": load_image,
|
144
153
|
".svg": load_svg,
|
154
|
+
".rds": load_rds,
|
145
155
|
}
|
146
156
|
|
147
|
-
SUPPORTED_SUFFIXES =
|
157
|
+
SUPPORTED_SUFFIXES = [sfx for sfx in FILE_LOADERS.keys() if sfx != ".rds"]
|
148
158
|
"""Suffixes with defined artifact loaders."""
|
149
159
|
|
150
160
|
|
lamindb/core/storage/_zarr.py
CHANGED
@@ -5,14 +5,21 @@ from typing import TYPE_CHECKING
|
|
5
5
|
|
6
6
|
import scipy.sparse as sparse
|
7
7
|
import zarr
|
8
|
-
from anndata
|
8
|
+
from anndata import __version__ as anndata_version
|
9
9
|
from anndata._io.specs import write_elem
|
10
10
|
from anndata._io.specs.registry import get_spec
|
11
11
|
from fsspec.implementations.local import LocalFileSystem
|
12
12
|
from lamindb_setup.core.upath import create_mapper, infer_filesystem
|
13
|
+
from packaging import version
|
13
14
|
|
14
15
|
from ._anndata_sizes import _size_elem, _size_raw, size_adata
|
15
16
|
|
17
|
+
if version.parse(anndata_version) < version.parse("0.11.0"):
|
18
|
+
from anndata._io import read_zarr
|
19
|
+
else:
|
20
|
+
from anndata.io import read_zarr
|
21
|
+
|
22
|
+
|
16
23
|
if TYPE_CHECKING:
|
17
24
|
from anndata import AnnData
|
18
25
|
from lamindb_setup.core.types import UPathStr
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: lamindb
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.77.0
|
4
4
|
Summary: A data framework for biology.
|
5
5
|
Author-email: Lamin Labs <open-source@lamin.ai>
|
6
6
|
Requires-Python: >=3.9,<3.13
|
@@ -9,9 +9,9 @@ Classifier: Programming Language :: Python :: 3.9
|
|
9
9
|
Classifier: Programming Language :: Python :: 3.10
|
10
10
|
Classifier: Programming Language :: Python :: 3.11
|
11
11
|
Classifier: Programming Language :: Python :: 3.12
|
12
|
-
Requires-Dist: lnschema_core==0.
|
13
|
-
Requires-Dist: lamin_utils==0.13.
|
14
|
-
Requires-Dist: lamin_cli==0.21.
|
12
|
+
Requires-Dist: lnschema_core==0.77.0
|
13
|
+
Requires-Dist: lamin_utils==0.13.8
|
14
|
+
Requires-Dist: lamin_cli==0.21.3
|
15
15
|
Requires-Dist: lamindb_setup
|
16
16
|
Requires-Dist: rapidfuzz
|
17
17
|
Requires-Dist: pyarrow
|
@@ -22,7 +22,7 @@ Requires-Dist: fsspec
|
|
22
22
|
Requires-Dist: graphviz
|
23
23
|
Requires-Dist: psycopg2-binary
|
24
24
|
Requires-Dist: lamindb_setup[aws] ; extra == "aws"
|
25
|
-
Requires-Dist: bionty==0.
|
25
|
+
Requires-Dist: bionty==0.53.1 ; extra == "bionty"
|
26
26
|
Requires-Dist: cellregistry ; extra == "cellregistry"
|
27
27
|
Requires-Dist: clinicore ; extra == "clinicore"
|
28
28
|
Requires-Dist: line_profiler ; extra == "dev"
|
@@ -1,17 +1,17 @@
|
|
1
|
-
lamindb/__init__.py,sha256=
|
1
|
+
lamindb/__init__.py,sha256=6E6iDqtEpPJwkp-5H-1Om9KnyDYDyFUBKEF3_mXFDhM,2275
|
2
2
|
lamindb/_artifact.py,sha256=4sHLnJQdWAjplB-dk0JXzhrHaaDn2ri5SeyvA7yzajQ,45166
|
3
|
-
lamindb/
|
3
|
+
lamindb/_can_curate.py,sha256=LhF78TqMUMsOXxy8ODZX9FLlH1-zszR9sKh3l6iVQ4o,19942
|
4
4
|
lamindb/_collection.py,sha256=MLOEoOgTu7rTlRD7zkm1k0YIk_gVhQDO17JbmZCptOs,14573
|
5
|
-
lamindb/_curate.py,sha256=
|
5
|
+
lamindb/_curate.py,sha256=BoZgaBBPK8aUggHmZMqbRjRCBL9CDHQCiWw4Kzg-_ww,64491
|
6
6
|
lamindb/_feature.py,sha256=9cgrcHoyOa1jpON-9KiUfFSHcxiGECiefUAqAx4cVvU,5325
|
7
7
|
lamindb/_feature_set.py,sha256=WdXw_YGlMXCs8l0WVHOrqvvrH2hsQLqCiho8LFDYwhI,8161
|
8
8
|
lamindb/_finish.py,sha256=r8q6rhml2vHiDlojCnfSpS8pbfnq7u6MwIcBIwuVq2o,9745
|
9
9
|
lamindb/_from_values.py,sha256=uRtZLaMWKoANMMXm1hrADHfckRCTiK8_d02Yp07nLkw,14119
|
10
10
|
lamindb/_is_versioned.py,sha256=GWZk-usV6aB33Cl9AlrnEGE5nxUkZic7QJzOW_DrwQA,1298
|
11
|
-
lamindb/_parents.py,sha256=
|
11
|
+
lamindb/_parents.py,sha256=GTbDL4P9LnaoNXMe6uOrp4g_Q4ZUAEaW0tHULrBt8tU,17203
|
12
12
|
lamindb/_query_manager.py,sha256=noc05Ad-aADxckOVBVDAiErFB7gL8XTgckELvI4rGmM,3702
|
13
|
-
lamindb/_query_set.py,sha256=
|
14
|
-
lamindb/_record.py,sha256=
|
13
|
+
lamindb/_query_set.py,sha256=dGEJuQsYrzc-mPdHSRjMPHWrri8Fg78I10AsT18jomI,14666
|
14
|
+
lamindb/_record.py,sha256=5zpRt5mCSzlYxHlrMqDnduoRCx5ZiTUJyoJjFMmuVHY,31522
|
15
15
|
lamindb/_run.py,sha256=K_5drpLn3D7y3XtZ3vtAw35rG5RCSvB4bXQZx4ESSI0,1964
|
16
16
|
lamindb/_save.py,sha256=OD052Qr_hiMyAonHTktKETe_Bhnp1RY810y0rwZqpBQ,11352
|
17
17
|
lamindb/_storage.py,sha256=GBVChv-DHVMNEBJL5l_JT6B4RDhZ6NnwgzmUICphYKk,413
|
@@ -19,19 +19,19 @@ lamindb/_transform.py,sha256=HpqRCk0ZTmqxSV4nRbyvDq8fAQEE9wTj31d-CusiL6A,4720
|
|
19
19
|
lamindb/_ulabel.py,sha256=DQQzAPkrOg8W9I77BJ5umajR8MQcFSvXYUy53YNN2HA,1604
|
20
20
|
lamindb/_utils.py,sha256=LGdiW4k3GClLz65vKAVRkL6Tw-Gkx9DWAdez1jyA5bE,428
|
21
21
|
lamindb/_view.py,sha256=4Ln2ItTb3857PAI-70O8eJYqoTJ_NNFc7E_wds6OGns,2412
|
22
|
-
lamindb/core/__init__.py,sha256=
|
23
|
-
lamindb/core/_context.py,sha256=
|
22
|
+
lamindb/core/__init__.py,sha256=GX6MdHsEdrHbm19oDcWVap4k3b0bHj5ekG_J2snsFjs,1558
|
23
|
+
lamindb/core/_context.py,sha256=xqvht5dlqFER6EPwCS6nA0I5_iFlmhPVVeFzB85G5B4,24164
|
24
24
|
lamindb/core/_data.py,sha256=BVZkxK8aloSecH25LivbwnjcG1fz7Gs2UDceO5pWd3I,20049
|
25
|
-
lamindb/core/_django.py,sha256=
|
25
|
+
lamindb/core/_django.py,sha256=cEalbKHCAHp7ElXFtFmUAvzGsk_xCyr4puZ0HElxVAw,7153
|
26
26
|
lamindb/core/_feature_manager.py,sha256=q4WmzJvFLL_fAs-vNRgV2klanAoU6Wu8_g0O2dyIjVg,40027
|
27
|
-
lamindb/core/_label_manager.py,sha256=
|
27
|
+
lamindb/core/_label_manager.py,sha256=eOiHMyRW4p0TUo8d_ihnW9cO0CvGRR2AfDfs5KObbmk,10939
|
28
28
|
lamindb/core/_mapped_collection.py,sha256=EDS0xzOdCc_iGE_Iqv5COTVHNm4jWue7Jtcd8DdXkJU,24591
|
29
29
|
lamindb/core/_settings.py,sha256=6jNadlQdimxCsKR2ZyUD0YJYzOdubTnKktki-MqEWqQ,6137
|
30
30
|
lamindb/core/_sync_git.py,sha256=lIgl6YfpH4rCFT1WILAp7zlemZfxog1d0zp3cX0KIZw,4531
|
31
31
|
lamindb/core/_track_environment.py,sha256=Ywzg_sJ7guI1dcsN7h5orce9VdYl8VGVE3OLITlHBXQ,820
|
32
32
|
lamindb/core/exceptions.py,sha256=Y1XQGbv9MgNLVvoClpcwN4NugrLW3Xgy1up15wZK740,1783
|
33
33
|
lamindb/core/fields.py,sha256=47Jmh3efUr5ZscgimR_yckY-I3cNf8ScLutbwKCK3j4,162
|
34
|
-
lamindb/core/loaders.py,sha256=
|
34
|
+
lamindb/core/loaders.py,sha256=CGgWWtdOCpfdC0hxRQuuGZEgnyRuIvReCYhauw598IA,4338
|
35
35
|
lamindb/core/schema.py,sha256=Y1tGn93B236PtnYZkpgTNFgTXBcVujPM1qh1kNG6Nbs,3441
|
36
36
|
lamindb/core/types.py,sha256=cL4cmJFA1xfxAIFOQqoa_fvVzdUM3A5blHStVwRNtk4,280
|
37
37
|
lamindb/core/versioning.py,sha256=KUpd94F5QpbDxx9eKgZwrpPyQpm9YeHVedrTEO2a_mI,4839
|
@@ -45,7 +45,7 @@ lamindb/core/storage/_backed_access.py,sha256=t9iS9mlZQBy1FfIS-Twt-96npYiShbPwEo
|
|
45
45
|
lamindb/core/storage/_pyarrow_dataset.py,sha256=wuLsEvdblqMdUdDfMtis8AWrE3igzvFWTSTbxuD1Oc8,926
|
46
46
|
lamindb/core/storage/_tiledbsoma.py,sha256=0NPLS5m1icEhzWPfXAv4U2SNiLGqGQd7FM6xCm5wYEc,7269
|
47
47
|
lamindb/core/storage/_valid_suffixes.py,sha256=vUSeQ4s01rdhD_vSd6wKmFBsgMJAKkBMnL_T9Y1znMg,501
|
48
|
-
lamindb/core/storage/_zarr.py,sha256=
|
48
|
+
lamindb/core/storage/_zarr.py,sha256=sVd9jVt2q91maeL6GAqMhT6sqtD04vQRfxY3mvIUQlc,3854
|
49
49
|
lamindb/core/storage/objects.py,sha256=OzvBCS-Urz5mr-O95qYt6RGBDDX5HmjfRRKWPPDn1ZE,1797
|
50
50
|
lamindb/core/storage/paths.py,sha256=bQwRbGTOCx3DSFOQ404uT-3YBXrm8yfKuttNCdWwJpA,5892
|
51
51
|
lamindb/core/subsettings/__init__.py,sha256=KFHPzIE7f7Bj4RgMjGQF4CjTdHVG_VNFBrCndo49ixo,198
|
@@ -55,7 +55,7 @@ lamindb/integrations/__init__.py,sha256=RWGMYYIzr8zvmNPyVB4m-p4gMDhxdRbjES2Ed23O
|
|
55
55
|
lamindb/integrations/_vitessce.py,sha256=uPl45_w4Uu9_BhpBDDVonC1nDOuAnB7DAnzi5w5bZAE,4032
|
56
56
|
lamindb/setup/__init__.py,sha256=OwZpZzPDv5lPPGXZP7-zK6UdO4FHvvuBh439yZvIp3A,410
|
57
57
|
lamindb/setup/core/__init__.py,sha256=SevlVrc2AZWL3uALbE5sopxBnIZPWZ1IB0NBDudiAL8,167
|
58
|
-
lamindb-0.
|
59
|
-
lamindb-0.
|
60
|
-
lamindb-0.
|
61
|
-
lamindb-0.
|
58
|
+
lamindb-0.77.0.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
59
|
+
lamindb-0.77.0.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81
|
60
|
+
lamindb-0.77.0.dist-info/METADATA,sha256=sRvsh2HFemzhSLonVj48xLEsFfSwQZZ_LvE2fbJn-js,2796
|
61
|
+
lamindb-0.77.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|