lamindb 0.69.7__py3-none-any.whl → 0.69.9__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. lamindb/__init__.py +1 -1
  2. lamindb/_annotate.py +46 -42
  3. lamindb/_artifact.py +66 -70
  4. lamindb/_can_validate.py +29 -25
  5. lamindb/_collection.py +30 -34
  6. lamindb/_feature.py +10 -8
  7. lamindb/_feature_set.py +17 -15
  8. lamindb/_filter.py +2 -2
  9. lamindb/_finish.py +14 -8
  10. lamindb/_from_values.py +13 -9
  11. lamindb/_is_versioned.py +2 -2
  12. lamindb/_parents.py +16 -11
  13. lamindb/_query_manager.py +8 -4
  14. lamindb/_query_set.py +15 -15
  15. lamindb/_registry.py +36 -34
  16. lamindb/_run.py +3 -5
  17. lamindb/_save.py +13 -11
  18. lamindb/_transform.py +9 -11
  19. lamindb/_ulabel.py +11 -9
  20. lamindb/_view.py +3 -2
  21. lamindb/core/_data.py +21 -17
  22. lamindb/core/_feature_manager.py +18 -13
  23. lamindb/core/_label_manager.py +13 -9
  24. lamindb/core/_mapped_collection.py +16 -12
  25. lamindb/core/_run_context.py +21 -17
  26. lamindb/core/_settings.py +19 -16
  27. lamindb/core/_sync_git.py +4 -5
  28. lamindb/core/_track_environment.py +6 -1
  29. lamindb/core/_transform_settings.py +3 -3
  30. lamindb/core/_view_tree.py +2 -1
  31. lamindb/core/datasets/_core.py +3 -2
  32. lamindb/core/datasets/_fake.py +2 -2
  33. lamindb/core/storage/_anndata_sizes.py +2 -0
  34. lamindb/core/storage/_backed_access.py +17 -12
  35. lamindb/core/storage/_zarr.py +7 -3
  36. lamindb/core/storage/file.py +13 -6
  37. lamindb/core/storage/object.py +7 -3
  38. lamindb/core/types.py +0 -2
  39. lamindb/core/versioning.py +12 -8
  40. lamindb/integrations/_vitessce.py +2 -0
  41. lamindb/setup/core/__init__.py +3 -14
  42. {lamindb-0.69.7.dist-info → lamindb-0.69.9.dist-info}/METADATA +5 -5
  43. lamindb-0.69.9.dist-info/RECORD +54 -0
  44. lamindb-0.69.7.dist-info/RECORD +0 -54
  45. {lamindb-0.69.7.dist-info → lamindb-0.69.9.dist-info}/LICENSE +0 -0
  46. {lamindb-0.69.7.dist-info → lamindb-0.69.9.dist-info}/WHEEL +0 -0
lamindb/core/_data.py CHANGED
@@ -1,5 +1,7 @@
1
+ from __future__ import annotations
2
+
1
3
  from collections import defaultdict
2
- from typing import Any, Dict, Iterable, List, Optional, Union
4
+ from typing import TYPE_CHECKING, Any, Iterable, List
3
5
 
4
6
  from lamin_utils import colors, logger
5
7
  from lamindb_setup.core._docs import doc_args
@@ -15,7 +17,6 @@ from lnschema_core.models import (
15
17
  __repr__,
16
18
  format_field_value,
17
19
  )
18
- from lnschema_core.types import StrField
19
20
 
20
21
  from lamindb._feature_set import (
21
22
  dict_related_model_to_related_name,
@@ -36,10 +37,13 @@ from ._label_manager import LabelManager, print_labels
36
37
  from ._run_context import run_context
37
38
  from .exceptions import ValidationError
38
39
 
40
+ if TYPE_CHECKING:
41
+ from lnschema_core.types import StrField
42
+
39
43
  WARNING_RUN_TRANSFORM = "no run & transform get linked, consider calling ln.track()"
40
44
 
41
45
 
42
- def get_run(run: Optional[Run]) -> Optional[Run]:
46
+ def get_run(run: Run | None) -> Run | None:
43
47
  if run is None:
44
48
  run = run_context.run
45
49
  if run is None and not settings.silence_file_run_transform_warning:
@@ -50,12 +54,12 @@ def get_run(run: Optional[Run]) -> Optional[Run]:
50
54
  return run
51
55
 
52
56
 
53
- def add_transform_to_kwargs(kwargs: Dict[str, Any], run: Run):
57
+ def add_transform_to_kwargs(kwargs: dict[str, Any], run: Run):
54
58
  if run is not None:
55
59
  kwargs["transform"] = run.transform
56
60
 
57
61
 
58
- def save_feature_sets(self: Union[Artifact, Collection]) -> None:
62
+ def save_feature_sets(self: Artifact | Collection) -> None:
59
63
  if hasattr(self, "_feature_sets"):
60
64
  saved_feature_sets = {}
61
65
  for key, feature_set in self._feature_sets.items():
@@ -73,7 +77,7 @@ def save_feature_sets(self: Union[Artifact, Collection]) -> None:
73
77
  )
74
78
 
75
79
 
76
- def save_feature_set_links(self: Union[Artifact, Collection]) -> None:
80
+ def save_feature_set_links(self: Artifact | Collection) -> None:
77
81
  from lamindb._save import bulk_create
78
82
 
79
83
  Data = self.__class__
@@ -141,7 +145,7 @@ def describe(self: Data):
141
145
  logger.print(msg)
142
146
 
143
147
 
144
- def validate_feature(feature: Feature, records: List[Registry]) -> None:
148
+ def validate_feature(feature: Feature, records: list[Registry]) -> None:
145
149
  """Validate feature record, set feature.registries based on labels records."""
146
150
  if not isinstance(feature, Feature):
147
151
  raise TypeError("feature has to be of type Feature")
@@ -160,7 +164,7 @@ def get_labels(
160
164
  feature: Feature,
161
165
  mute: bool = False,
162
166
  flat_names: bool = False,
163
- ) -> Union[QuerySet, Dict[str, QuerySet], List]:
167
+ ) -> QuerySet | dict[str, QuerySet] | list:
164
168
  """{}."""
165
169
  if not isinstance(feature, Feature):
166
170
  raise TypeError("feature has to be of type Feature")
@@ -202,10 +206,10 @@ def get_labels(
202
206
 
203
207
  def add_labels(
204
208
  self,
205
- records: Union[Registry, List[Registry], QuerySet, Iterable],
206
- feature: Optional[Feature] = None,
209
+ records: Registry | list[Registry] | QuerySet | Iterable,
210
+ feature: Feature | None = None,
207
211
  *,
208
- field: Optional[StrField] = None,
212
+ field: StrField | None = None,
209
213
  ) -> None:
210
214
  """{}."""
211
215
  if self._state.adding:
@@ -253,7 +257,7 @@ def add_labels(
253
257
  if feature is None:
254
258
  d = dict_related_model_to_related_name(self.__class__)
255
259
  # strategy: group records by registry to reduce number of transactions
256
- records_by_related_name: Dict = {}
260
+ records_by_related_name: dict = {}
257
261
  for record in records:
258
262
  related_name = d.get(record.__class__.__get_name_with_schema__())
259
263
  if related_name is None:
@@ -343,9 +347,9 @@ def add_labels(
343
347
 
344
348
 
345
349
  def _track_run_input(
346
- data: Union[Data, Iterable[Data]],
347
- is_run_input: Optional[bool] = None,
348
- run: Optional[Run] = None,
350
+ data: Data | Iterable[Data],
351
+ is_run_input: bool | None = None,
352
+ run: Run | None = None,
349
353
  ):
350
354
  if run is None:
351
355
  run = run_context.run
@@ -430,7 +434,7 @@ def _track_run_input(
430
434
 
431
435
  @property # type: ignore
432
436
  @doc_args(Data.features.__doc__)
433
- def features(self) -> "FeatureManager":
437
+ def features(self) -> FeatureManager:
434
438
  """{}."""
435
439
  from lamindb.core._feature_manager import FeatureManager
436
440
 
@@ -439,7 +443,7 @@ def features(self) -> "FeatureManager":
439
443
 
440
444
  @property # type: ignore
441
445
  @doc_args(Data.labels.__doc__)
442
- def labels(self) -> "LabelManager":
446
+ def labels(self) -> LabelManager:
443
447
  """{}."""
444
448
  from lamindb.core._label_manager import LabelManager
445
449
 
@@ -1,16 +1,16 @@
1
+ from __future__ import annotations
2
+
1
3
  from itertools import compress
2
- from typing import Dict, Iterable, Optional, Union
4
+ from typing import TYPE_CHECKING, Iterable
3
5
 
4
6
  import anndata as ad
5
7
  from anndata import AnnData
6
8
  from lamin_utils import colors, logger
7
9
  from lamindb_setup.core.upath import create_path
8
10
  from lnschema_core.models import Artifact, Collection, Data, Feature, Registry
9
- from lnschema_core.types import AnnDataLike, FieldAttr
10
11
 
11
12
  from lamindb._feature import convert_numpy_dtype_to_lamin_feature_type
12
13
  from lamindb._feature_set import FeatureSet
13
- from lamindb._query_set import QuerySet
14
14
  from lamindb._registry import (
15
15
  REGISTRY_UNIQUE_FIELD,
16
16
  get_default_str_field,
@@ -22,8 +22,13 @@ from lamindb.core.storage import LocalPathClasses
22
22
 
23
23
  from ._settings import settings
24
24
 
25
+ if TYPE_CHECKING:
26
+ from lnschema_core.types import FieldAttr
27
+
28
+ from lamindb._query_set import QuerySet
29
+
25
30
 
26
- def get_host_id_field(host: Union[Artifact, Collection]) -> str:
31
+ def get_host_id_field(host: Artifact | Collection) -> str:
27
32
  if isinstance(host, Artifact):
28
33
  host_id_field = "artifact_id"
29
34
  else:
@@ -31,7 +36,7 @@ def get_host_id_field(host: Union[Artifact, Collection]) -> str:
31
36
  return host_id_field
32
37
 
33
38
 
34
- def get_accessor_by_orm(host: Union[Artifact, Collection]) -> Dict:
39
+ def get_accessor_by_orm(host: Artifact | Collection) -> dict:
35
40
  dictionary = {
36
41
  field.related_model.__get_name_with_schema__(): field.name
37
42
  for field in host._meta.related_objects
@@ -41,7 +46,7 @@ def get_accessor_by_orm(host: Union[Artifact, Collection]) -> Dict:
41
46
  return dictionary
42
47
 
43
48
 
44
- def get_feature_set_by_slot(host) -> Dict:
49
+ def get_feature_set_by_slot(host) -> dict:
45
50
  # if the host is not yet saved
46
51
  if host._state.adding:
47
52
  if hasattr(host, "_feature_sets"):
@@ -64,7 +69,7 @@ def get_feature_set_by_slot(host) -> Dict:
64
69
 
65
70
 
66
71
  def get_label_links(
67
- host: Union[Artifact, Collection], registry: str, feature: Feature
72
+ host: Artifact | Collection, registry: str, feature: Feature
68
73
  ) -> QuerySet:
69
74
  host_id_field = get_host_id_field(host)
70
75
  kwargs = {host_id_field: host.id, "feature_id": feature.id}
@@ -76,7 +81,7 @@ def get_label_links(
76
81
  return link_records
77
82
 
78
83
 
79
- def get_feature_set_links(host: Union[Artifact, Collection]) -> QuerySet:
84
+ def get_feature_set_links(host: Artifact | Collection) -> QuerySet:
80
85
  host_id_field = get_host_id_field(host)
81
86
  kwargs = {host_id_field: host.id}
82
87
  feature_set_links = host.feature_sets.through.objects.filter(**kwargs)
@@ -127,11 +132,11 @@ def print_features(self: Data) -> str:
127
132
 
128
133
 
129
134
  def parse_feature_sets_from_anndata(
130
- adata: AnnDataLike,
135
+ adata: AnnData,
131
136
  var_field: FieldAttr,
132
137
  obs_field: FieldAttr = Feature.name,
133
138
  **kwargs,
134
- ) -> Dict:
139
+ ) -> dict:
135
140
  data_parse = adata
136
141
  if not isinstance(adata, AnnData): # is a path
137
142
  filepath = create_path(adata) # returns Path for local
@@ -183,7 +188,7 @@ class FeatureManager:
183
188
  See :class:`~lamindb.core.Data` for more information.
184
189
  """
185
190
 
186
- def __init__(self, host: Union[Artifact, Collection]):
191
+ def __init__(self, host: Artifact | Collection):
187
192
  self._host = host
188
193
  self._feature_set_by_slot = get_feature_set_by_slot(host)
189
194
  self._accessor_by_orm = get_accessor_by_orm(host)
@@ -210,7 +215,7 @@ class FeatureManager:
210
215
  else:
211
216
  return getattr(feature_set, self._accessor_by_orm[orm_name]).all()
212
217
 
213
- def add(self, features: Iterable[Registry], slot: Optional[str] = None):
218
+ def add(self, features: Iterable[Registry], slot: str | None = None):
214
219
  """Add features stratified by slot."""
215
220
  if (hasattr(self._host, "accessor") and self._host.accessor == "DataFrame") or (
216
221
  hasattr(self._host, "artifact")
@@ -246,7 +251,7 @@ class FeatureManager:
246
251
  def add_from_anndata(
247
252
  self,
248
253
  var_field: FieldAttr,
249
- obs_field: Optional[FieldAttr] = Feature.name,
254
+ obs_field: FieldAttr | None = Feature.name,
250
255
  **kwargs,
251
256
  ):
252
257
  """Add features from AnnData."""
@@ -1,4 +1,6 @@
1
- from typing import Dict, List, Optional, Tuple, Union
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING, Dict
2
4
 
3
5
  import numpy as np
4
6
  from lamin_utils import colors, logger
@@ -6,7 +8,6 @@ from lnschema_core.models import Artifact, Collection, Data, Feature, Registry
6
8
 
7
9
  from lamindb._feature_set import dict_related_model_to_related_name
8
10
  from lamindb._from_values import _print_values
9
- from lamindb._query_set import QuerySet
10
11
  from lamindb._registry import (
11
12
  REGISTRY_UNIQUE_FIELD,
12
13
  get_default_str_field,
@@ -17,6 +18,9 @@ from lamindb._save import save
17
18
 
18
19
  from ._settings import settings
19
20
 
21
+ if TYPE_CHECKING:
22
+ from lamindb._query_set import QuerySet
23
+
20
24
 
21
25
  def get_labels_as_dict(self: Data):
22
26
  labels = {}
@@ -80,10 +84,10 @@ def transfer_add_labels(labels, features_lookup_self, self, row, parents: bool =
80
84
  transfer_single_registry(*result)
81
85
 
82
86
 
83
- def validate_labels(labels: Union[QuerySet, List, Dict], parents: bool = True):
87
+ def validate_labels(labels: QuerySet | list | dict, parents: bool = True):
84
88
  def validate_labels_registry(
85
- labels: Union[QuerySet, List, Dict], parents: bool = True
86
- ) -> Tuple[List[str], List[str]]:
89
+ labels: QuerySet | list | dict, parents: bool = True
90
+ ) -> tuple[list[str], list[str]]:
87
91
  if len(labels) == 0:
88
92
  return [], []
89
93
  registry = labels[0].__class__
@@ -134,7 +138,7 @@ class LabelManager:
134
138
  See :class:`~lamindb.core.Data` for more information.
135
139
  """
136
140
 
137
- def __init__(self, host: Union[Artifact, Collection]):
141
+ def __init__(self, host: Artifact | Collection):
138
142
  self._host = host
139
143
 
140
144
  def __repr__(self) -> str:
@@ -146,8 +150,8 @@ class LabelManager:
146
150
 
147
151
  def add(
148
152
  self,
149
- records: Union[Registry, List[Registry], QuerySet],
150
- feature: Optional[Feature] = None,
153
+ records: Registry | list[Registry] | QuerySet,
154
+ feature: Feature | None = None,
151
155
  ) -> None:
152
156
  """Add one or several labels and associate them with a feature.
153
157
 
@@ -165,7 +169,7 @@ class LabelManager:
165
169
  feature: Feature,
166
170
  mute: bool = False,
167
171
  flat_names: bool = False,
168
- ) -> Union[QuerySet, Dict[str, QuerySet], List]:
172
+ ) -> QuerySet | dict[str, QuerySet] | list:
169
173
  """Get labels given a feature.
170
174
 
171
175
  Args:
@@ -1,12 +1,13 @@
1
+ from __future__ import annotations
2
+
1
3
  from collections import Counter
2
4
  from functools import reduce
3
5
  from pathlib import Path
4
- from typing import Dict, List, Literal, Optional, Union
6
+ from typing import TYPE_CHECKING, Dict, List, Literal, Optional, Union
5
7
 
6
8
  import numpy as np
7
9
  import pandas as pd
8
10
  from lamin_utils import logger
9
- from lamindb_setup.core.types import UPathStr
10
11
  from lamindb_setup.core.upath import UPath
11
12
 
12
13
  from .storage._backed_access import (
@@ -17,6 +18,9 @@ from .storage._backed_access import (
17
18
  registry,
18
19
  )
19
20
 
21
+ if TYPE_CHECKING:
22
+ from lamindb_setup.core.types import UPathStr
23
+
20
24
 
21
25
  class _Connect:
22
26
  def __init__(self, storage):
@@ -81,14 +85,14 @@ class MappedCollection:
81
85
 
82
86
  def __init__(
83
87
  self,
84
- path_list: List[UPathStr],
85
- label_keys: Optional[Union[str, List[str]]] = None,
86
- join: Optional[Literal["inner", "outer"]] = "inner",
87
- encode_labels: Union[bool, List[str]] = True,
88
- unknown_label: Optional[Union[str, Dict[str, str]]] = None,
88
+ path_list: list[UPathStr],
89
+ label_keys: str | list[str] | None = None,
90
+ join: Literal["inner", "outer"] | None = "inner",
91
+ encode_labels: bool | list[str] = True,
92
+ unknown_label: str | dict[str, str] | None = None,
89
93
  cache_categories: bool = True,
90
94
  parallel: bool = False,
91
- dtype: Optional[str] = None,
95
+ dtype: str | None = None,
92
96
  ):
93
97
  assert join in {None, "inner", "outer"}
94
98
 
@@ -248,8 +252,8 @@ class MappedCollection:
248
252
  self,
249
253
  storage: StorageType, # type: ignore
250
254
  idx: int,
251
- var_idxs_join: Optional[list] = None,
252
- layer_key: Optional[str] = None,
255
+ var_idxs_join: list | None = None,
256
+ layer_key: str | None = None,
253
257
  ):
254
258
  """Get the index for the data."""
255
259
  layer = storage["X"] if layer_key is None else storage["layers"][layer_key] # type: ignore
@@ -290,7 +294,7 @@ class MappedCollection:
290
294
  storage: StorageType,
291
295
  idx: int,
292
296
  label_key: str,
293
- categories: Optional[list] = None,
297
+ categories: list | None = None,
294
298
  ):
295
299
  """Get the index for the label by key."""
296
300
  obs = storage["obs"] # type: ignore
@@ -313,7 +317,7 @@ class MappedCollection:
313
317
  label = label.decode("utf-8")
314
318
  return label
315
319
 
316
- def get_label_weights(self, label_keys: Union[str, List[str]]):
320
+ def get_label_weights(self, label_keys: str | list[str]):
317
321
  """Get all weights for the given label keys."""
318
322
  if isinstance(label_keys, str):
319
323
  label_keys = [label_keys]
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  import builtins
2
4
  import hashlib
3
5
  import os
@@ -6,12 +8,11 @@ import subprocess
6
8
  import sys
7
9
  from datetime import datetime, timezone
8
10
  from pathlib import Path, PurePath
9
- from typing import Any, Dict, List, Optional, Tuple, Union
11
+ from typing import TYPE_CHECKING, Any
10
12
 
11
13
  from lamin_utils import logger
12
14
  from lamindb_setup import settings as setup_settings
13
15
  from lamindb_setup.core import InstanceSettings
14
- from lamindb_setup.core.types import UPathStr
15
16
  from lnschema_core import Run, Transform, ids
16
17
  from lnschema_core.types import TransformType
17
18
  from lnschema_core.users import current_user_id
@@ -21,6 +22,9 @@ from lamindb.core._transform_settings import transform as transform_settings
21
22
  from ._settings import settings
22
23
  from ._sync_git import get_transform_reference_from_git_repo
23
24
 
25
+ if TYPE_CHECKING:
26
+ from lamindb_setup.core.types import UPathStr
27
+
24
28
  is_run_from_ipython = getattr(builtins, "__IPYTHON__", False)
25
29
 
26
30
  msg_path_failed = (
@@ -55,7 +59,7 @@ def get_uid_ext(version: str) -> str:
55
59
  return encodebytes(hashlib.md5(version.encode()).digest())[:4]
56
60
 
57
61
 
58
- def get_stem_uid_and_version_from_file(file_path: Path) -> Tuple[str, str]:
62
+ def get_stem_uid_and_version_from_file(file_path: Path) -> tuple[str, str]:
59
63
  # line-by-line matching might be faster, but let's go with this for now
60
64
  with open(file_path) as file:
61
65
  content = file.read()
@@ -215,20 +219,20 @@ def raise_transform_settings_error() -> None:
215
219
  class run_context:
216
220
  """Global run context."""
217
221
 
218
- transform: Optional[Transform] = None
222
+ transform: Transform | None = None
219
223
  """Current transform."""
220
- run: Optional[Run] = None
224
+ run: Run | None = None
221
225
  """Current run."""
222
- path: Optional[Path] = None
226
+ path: Path | None = None
223
227
  """A local path to the script that's running."""
224
228
 
225
229
  @classmethod
226
230
  def _track(
227
231
  cls,
228
232
  *,
229
- transform: Optional[Transform] = None,
230
- new_run: Optional[bool] = None,
231
- path: Optional[str] = None,
233
+ transform: Transform | None = None,
234
+ new_run: bool | None = None,
235
+ path: str | None = None,
232
236
  ) -> None:
233
237
  """Track notebook or script run.
234
238
 
@@ -364,8 +368,8 @@ class run_context:
364
368
  def _track_script(
365
369
  cls,
366
370
  *,
367
- path: Optional[UPathStr],
368
- ) -> Tuple[str, str, str, str]:
371
+ path: UPathStr | None,
372
+ ) -> tuple[str, str, str, str]:
369
373
  if path is None:
370
374
  import inspect
371
375
 
@@ -387,7 +391,7 @@ class run_context:
387
391
  def _track_notebook(
388
392
  cls,
389
393
  *,
390
- path: Optional[str],
394
+ path: str | None,
391
395
  ):
392
396
  if path is None:
393
397
  path = get_notebook_path()
@@ -442,13 +446,13 @@ class run_context:
442
446
  cls,
443
447
  *,
444
448
  stem_uid: str,
445
- version: Optional[str],
449
+ version: str | None,
446
450
  name: str,
447
- transform_ref: Optional[str] = None,
448
- transform_ref_type: Optional[str] = None,
449
- key: Optional[str] = None,
451
+ transform_ref: str | None = None,
452
+ transform_ref_type: str | None = None,
453
+ key: str | None = None,
450
454
  transform_type: TransformType = None,
451
- transform: Optional[Transform] = None,
455
+ transform: Transform | None = None,
452
456
  ):
453
457
  # make a new transform record
454
458
  if transform is None:
lamindb/core/_settings.py CHANGED
@@ -1,16 +1,21 @@
1
+ from __future__ import annotations
2
+
1
3
  import os
2
- from pathlib import Path
3
- from typing import Dict, Literal, Mapping, Optional, Tuple, Union
4
+ from typing import TYPE_CHECKING, Literal, Mapping
4
5
 
5
6
  import lamindb_setup as ln_setup
6
7
  from lamin_utils import logger
7
8
  from lamindb_setup._add_remote_storage import switch_default_storage
8
9
  from lamindb_setup.core._settings import settings as setup_settings
9
10
  from lamindb_setup.core._settings_instance import sanitize_git_repo_url
10
- from upath import UPath
11
11
 
12
12
  from ._transform_settings import TransformSettings, transform
13
13
 
14
+ if TYPE_CHECKING:
15
+ from pathlib import Path
16
+
17
+ from upath import UPath
18
+
14
19
  VERBOSITY_TO_INT = {
15
20
  "error": 0, # 40
16
21
  "warning": 1, # 30
@@ -19,7 +24,7 @@ VERBOSITY_TO_INT = {
19
24
  "hint": 4, # 15
20
25
  "debug": 5, # 10
21
26
  }
22
- VERBOSITY_TO_STR: Dict[int, str] = dict(
27
+ VERBOSITY_TO_STR: dict[int, str] = dict(
23
28
  [reversed(i) for i in VERBOSITY_TO_INT.items()] # type: ignore
24
29
  )
25
30
 
@@ -30,10 +35,10 @@ class Settings:
30
35
  Use ``lamindb.settings`` instead of instantiating this class yourself.
31
36
  """
32
37
 
33
- def __init__(self, git_repo: Optional[str]):
38
+ def __init__(self, git_repo: str | None):
34
39
  self._verbosity_int: int = 1 # warning-level logging
35
40
  logger.set_verbosity(self._verbosity_int)
36
- self._sync_git_repo: Optional[str] = git_repo
41
+ self._sync_git_repo: str | None = git_repo
37
42
 
38
43
  upon_artifact_create_if_hash_exists: Literal[
39
44
  "warn_return_existing", "error", "warn_create_new"
@@ -73,16 +78,16 @@ class Settings:
73
78
  If `True`, the `key` is **not** used to construct file paths, but file paths are
74
79
  based on the `uid` of artifact.
75
80
  """
76
- __using_key: Optional[str] = None
77
- _using_storage: Optional[str] = None
81
+ __using_key: str | None = None
82
+ _using_storage: str | None = None
78
83
 
79
84
  @property
80
- def _using_key(self) -> Optional[str]:
85
+ def _using_key(self) -> str | None:
81
86
  """Key for Django database settings."""
82
87
  return self.__using_key
83
88
 
84
89
  @_using_key.setter
85
- def _using_key(self, value: Optional[str]):
90
+ def _using_key(self, value: str | None):
86
91
  ln_setup.settings._using_key = value
87
92
  self.__using_key = value
88
93
 
@@ -100,7 +105,7 @@ class Settings:
100
105
  return transform
101
106
 
102
107
  @property
103
- def sync_git_repo(self) -> Optional[str]:
108
+ def sync_git_repo(self) -> str | None:
104
109
  """Sync transforms with scripts in git repository.
105
110
 
106
111
  Provide the full git repo URL.
@@ -117,7 +122,7 @@ class Settings:
117
122
  assert self._sync_git_repo.startswith("https://")
118
123
 
119
124
  @property
120
- def storage(self) -> Union[Path, UPath]:
125
+ def storage(self) -> Path | UPath:
121
126
  """Default storage location (a path to its root).
122
127
 
123
128
  Examples:
@@ -137,9 +142,7 @@ class Settings:
137
142
  return self._storage_settings.root
138
143
 
139
144
  @storage.setter
140
- def storage(
141
- self, path_kwargs: Union[str, Path, UPath, Tuple[Union[str, UPath], Mapping]]
142
- ):
145
+ def storage(self, path_kwargs: str | Path | UPath | tuple[str | UPath, Mapping]):
143
146
  logger.warning(
144
147
  "you'll no longer be able to set arbitrary storage locations soon"
145
148
  )
@@ -165,7 +168,7 @@ class Settings:
165
168
  return VERBOSITY_TO_STR[self._verbosity_int]
166
169
 
167
170
  @verbosity.setter
168
- def verbosity(self, verbosity: Union[str, int]):
171
+ def verbosity(self, verbosity: str | int):
169
172
  if isinstance(verbosity, str):
170
173
  verbosity_int = VERBOSITY_TO_INT[verbosity]
171
174
  else:
lamindb/core/_sync_git.py CHANGED
@@ -1,6 +1,7 @@
1
+ from __future__ import annotations
2
+
1
3
  import subprocess
2
4
  from pathlib import Path
3
- from typing import Optional
4
5
 
5
6
  from lamin_utils import logger
6
7
  from lamindb_setup import settings as setup_settings
@@ -52,9 +53,7 @@ def check_local_git_repo() -> bool:
52
53
  return False
53
54
 
54
55
 
55
- def get_git_commit_hash(
56
- blob_hash: str, repo_dir: Optional[Path] = None
57
- ) -> Optional[str]:
56
+ def get_git_commit_hash(blob_hash: str, repo_dir: Path | None = None) -> str | None:
58
57
  command = f"git log --find-object={blob_hash} --pretty=format:%H"
59
58
  result = subprocess.run(
60
59
  command,
@@ -71,7 +70,7 @@ def get_git_commit_hash(
71
70
 
72
71
 
73
72
  def get_filepath_within_git_repo(
74
- commit_hash: str, blob_hash: str, repo_dir: Optional[Path]
73
+ commit_hash: str, blob_hash: str, repo_dir: Path | None
75
74
  ) -> str:
76
75
  # repo_dir might not point to the root of the
77
76
  # the git repository because git log --find-object works
@@ -1,8 +1,13 @@
1
+ from __future__ import annotations
2
+
1
3
  import subprocess
4
+ from typing import TYPE_CHECKING
2
5
 
3
6
  import lamindb_setup as ln_setup
4
7
  from lamin_utils import logger
5
- from lnschema_core.models import Run
8
+
9
+ if TYPE_CHECKING:
10
+ from lnschema_core.models import Run
6
11
 
7
12
 
8
13
  def track_environment(run: Run) -> None:
@@ -1,9 +1,9 @@
1
- from typing import Optional
1
+ from __future__ import annotations
2
2
 
3
3
 
4
4
  class TransformSettings:
5
- stem_uid: Optional[None] = None
6
- version: Optional[None] = None
5
+ stem_uid: None | None = None
6
+ version: None | None = None
7
7
 
8
8
 
9
9
  transform = TransformSettings()
@@ -1,4 +1,5 @@
1
- import os
1
+ from __future__ import annotations
2
+
2
3
  from collections import defaultdict
3
4
  from pathlib import Path
4
5
  from typing import Iterable
@@ -1,5 +1,6 @@
1
+ from __future__ import annotations
2
+
1
3
  from pathlib import Path
2
- from typing import Union
3
4
  from urllib.request import urlretrieve
4
5
 
5
6
  import anndata as ad
@@ -448,7 +449,7 @@ def df_iris_in_meter_study2() -> pd.DataFrame:
448
449
 
449
450
 
450
451
  def dir_scrnaseq_cellranger(
451
- sample_name: str, basedir: Union[str, Path] = "./", output_only: bool = True
452
+ sample_name: str, basedir: str | Path = "./", output_only: bool = True
452
453
  ): # pragma: no cover
453
454
  """Generate mock cell ranger outputs.
454
455
 
@@ -1,7 +1,7 @@
1
- from typing import List
1
+ from __future__ import annotations
2
2
 
3
3
 
4
- def fake_bio_notebook_titles(n=100) -> List[str]:
4
+ def fake_bio_notebook_titles(n=100) -> list[str]:
5
5
  """A fake collection of study titles."""
6
6
  from faker import Faker
7
7