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/__init__.py CHANGED
@@ -40,7 +40,7 @@ Modules & settings:
40
40
 
41
41
  """
42
42
 
43
- __version__ = "0.69.7" # denote a release candidate for 0.1.0 with 0.1rc1
43
+ __version__ = "0.69.9" # denote a release candidate for 0.1.0 with 0.1rc1
44
44
 
45
45
  import os as _os
46
46
 
lamindb/_annotate.py CHANGED
@@ -1,11 +1,15 @@
1
- from typing import Dict, Iterable, List, Optional, Tuple, Union
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING, Iterable
2
4
 
3
5
  import anndata as ad
4
6
  import lamindb_setup as ln_setup
5
7
  import pandas as pd
6
8
  from lamin_utils import colors, logger
7
9
  from lnschema_core import Artifact, Collection, Feature, Registry, Run, ULabel
8
- from lnschema_core.types import FieldAttr
10
+
11
+ if TYPE_CHECKING:
12
+ from lnschema_core.types import FieldAttr
9
13
 
10
14
 
11
15
  class ValidationError(ValueError):
@@ -19,9 +23,9 @@ class AnnotateLookup:
19
23
 
20
24
  def __init__(
21
25
  self,
22
- categorials: Dict[str, FieldAttr],
23
- slots: Dict[str, FieldAttr] = None,
24
- using: Optional[str] = None,
26
+ categorials: dict[str, FieldAttr],
27
+ slots: dict[str, FieldAttr] = None,
28
+ using: str | None = None,
25
29
  ) -> None:
26
30
  if slots is None:
27
31
  slots = {}
@@ -91,8 +95,8 @@ class DataFrameAnnotator:
91
95
  self,
92
96
  df: pd.DataFrame,
93
97
  columns: FieldAttr = Feature.name,
94
- categoricals: Optional[Dict[str, FieldAttr]] = None,
95
- using: Optional[str] = None,
98
+ categoricals: dict[str, FieldAttr] | None = None,
99
+ using: str | None = None,
96
100
  verbosity: str = "hint",
97
101
  **kwargs,
98
102
  ) -> None:
@@ -106,15 +110,15 @@ class DataFrameAnnotator:
106
110
  self._artifact = None
107
111
  self._collection = None
108
112
  self._validated = False
109
- self._kwargs: Dict = kwargs
113
+ self._kwargs: dict = kwargs
110
114
  self._save_columns()
111
115
 
112
116
  @property
113
- def fields(self) -> Dict:
117
+ def fields(self) -> dict:
114
118
  """Return the columns fields to validate against."""
115
119
  return self._fields
116
120
 
117
- def lookup(self, using: Optional[str] = None) -> AnnotateLookup:
121
+ def lookup(self, using: str | None = None) -> AnnotateLookup:
118
122
  """Lookup features and labels.
119
123
 
120
124
  Args:
@@ -260,11 +264,11 @@ class DataFrameAnnotator:
260
264
 
261
265
  def save_collection(
262
266
  self,
263
- artifact: Union[Artifact, Iterable[Artifact]],
267
+ artifact: Artifact | Iterable[Artifact],
264
268
  name: str,
265
- description: Optional[str] = None,
266
- reference: Optional[str] = None,
267
- reference_type: Optional[str] = None,
269
+ description: str | None = None,
270
+ reference: str | None = None,
271
+ reference_type: str | None = None,
268
272
  ) -> Collection:
269
273
  """Save a collection from artifact/artifacts.
270
274
 
@@ -319,7 +323,7 @@ class AnnDataAnnotator(DataFrameAnnotator):
319
323
  self,
320
324
  adata: ad.AnnData,
321
325
  var_index: FieldAttr,
322
- categoricals: Dict[str, FieldAttr],
326
+ categoricals: dict[str, FieldAttr],
323
327
  using: str = "default",
324
328
  verbosity: str = "hint",
325
329
  **kwargs,
@@ -342,11 +346,11 @@ class AnnDataAnnotator(DataFrameAnnotator):
342
346
  return self._var_field
343
347
 
344
348
  @property
345
- def categoricals(self) -> Dict:
349
+ def categoricals(self) -> dict:
346
350
  """Return the obs fields to validate against."""
347
351
  return self._obs_fields
348
352
 
349
- def lookup(self, using: Optional[str] = None) -> AnnotateLookup:
353
+ def lookup(self, using: str | None = None) -> AnnotateLookup:
350
354
  """Lookup features and labels."""
351
355
  return AnnotateLookup(
352
356
  categorials=self._obs_fields,
@@ -413,9 +417,9 @@ class Annotate:
413
417
  def from_df(
414
418
  cls,
415
419
  df: pd.DataFrame,
416
- categoricals: Optional[Dict[str, FieldAttr]] = None,
420
+ categoricals: dict[str, FieldAttr] | None = None,
417
421
  columns: FieldAttr = Feature.name,
418
- using: Optional[str] = None,
422
+ using: str | None = None,
419
423
  verbosity: str = "hint",
420
424
  **kwargs,
421
425
  ) -> DataFrameAnnotator:
@@ -433,7 +437,7 @@ class Annotate:
433
437
  cls,
434
438
  adata: ad.AnnData,
435
439
  var_index: FieldAttr,
436
- categoricals: Dict[str, FieldAttr],
440
+ categoricals: dict[str, FieldAttr],
437
441
  using: str = "default",
438
442
  verbosity: str = "hint",
439
443
  **kwargs,
@@ -448,7 +452,7 @@ class Annotate:
448
452
  )
449
453
 
450
454
 
451
- def get_registry_instance(registry: Registry, using: Optional[str] = None) -> Registry:
455
+ def get_registry_instance(registry: Registry, using: str | None = None) -> Registry:
452
456
  """Get a registry instance using a specific instance."""
453
457
  if using is not None and using != "default":
454
458
  return registry.using(using)
@@ -465,8 +469,8 @@ def standardize_and_inspect(
465
469
 
466
470
 
467
471
  def check_registry_organism(
468
- registry: Registry, organism: Optional[str] = None
469
- ) -> Optional[str]:
472
+ registry: Registry, organism: str | None = None
473
+ ) -> str | None:
470
474
  """Check if a registry needs an organism and return the organism name."""
471
475
  if hasattr(registry, "organism_id"):
472
476
  import bionty as bt
@@ -484,7 +488,7 @@ def validate_categories(
484
488
  values: Iterable[str],
485
489
  field: FieldAttr,
486
490
  key: str,
487
- using: Optional[str] = None,
491
+ using: str | None = None,
488
492
  **kwargs,
489
493
  ) -> bool:
490
494
  """Validate ontology terms in a pandas series using LaminDB registries."""
@@ -560,8 +564,8 @@ def validate_categories(
560
564
 
561
565
  def validate_categories_in_df(
562
566
  df: pd.DataFrame,
563
- fields: Dict[str, FieldAttr],
564
- using: Optional[str] = None,
567
+ fields: dict[str, FieldAttr],
568
+ using: str | None = None,
565
569
  **kwargs,
566
570
  ) -> bool:
567
571
  """Validate categories in DataFrame columns using LaminDB registries."""
@@ -580,8 +584,8 @@ def validate_categories_in_df(
580
584
  def validate_anndata(
581
585
  adata: ad.AnnData,
582
586
  var_field: FieldAttr,
583
- obs_fields: Dict[str, FieldAttr],
584
- using: Optional[str] = None,
587
+ obs_fields: dict[str, FieldAttr],
588
+ using: str | None = None,
585
589
  **kwargs,
586
590
  ) -> bool:
587
591
  """Inspect metadata in an AnnData object using LaminDB registries."""
@@ -604,9 +608,9 @@ def validate_anndata(
604
608
 
605
609
 
606
610
  def save_artifact(
607
- data: Union[pd.DataFrame, ad.AnnData],
611
+ data: pd.DataFrame | ad.AnnData,
608
612
  description: str,
609
- fields: Dict[str, FieldAttr],
613
+ fields: dict[str, FieldAttr],
610
614
  columns_field: FieldAttr,
611
615
  **kwargs,
612
616
  ) -> Artifact:
@@ -631,7 +635,7 @@ def save_artifact(
631
635
  raise ValueError("data must be a DataFrame or AnnData object")
632
636
  artifact.save()
633
637
 
634
- feature_kwargs: Dict = {}
638
+ feature_kwargs: dict = {}
635
639
  organism = check_registry_organism(
636
640
  columns_field.field.model, kwargs.pop("organism", None)
637
641
  )
@@ -662,14 +666,14 @@ def save_artifact(
662
666
 
663
667
 
664
668
  def update_registry(
665
- values: List[str],
669
+ values: list[str],
666
670
  field: FieldAttr,
667
671
  key: str,
668
672
  save_function: str = "add_new_from",
669
- using: Optional[str] = None,
673
+ using: str | None = None,
670
674
  validated_only: bool = True,
671
- kwargs: Optional[Dict] = None,
672
- df: Optional[pd.DataFrame] = None,
675
+ kwargs: dict | None = None,
676
+ df: pd.DataFrame | None = None,
673
677
  ) -> None:
674
678
  """Save features or labels records in the default instance from the using instance.
675
679
 
@@ -703,7 +707,7 @@ def update_registry(
703
707
  settings.verbosity = verbosity
704
708
  return
705
709
 
706
- labels_saved: Dict = {"from public": [], "without reference": []}
710
+ labels_saved: dict = {"from public": [], "without reference": []}
707
711
 
708
712
  (
709
713
  labels_saved[f"from {using}"],
@@ -757,7 +761,7 @@ def update_registry(
757
761
 
758
762
 
759
763
  def log_saved_labels(
760
- labels_saved: Dict,
764
+ labels_saved: dict,
761
765
  key: str,
762
766
  save_function: str,
763
767
  model_field: str,
@@ -795,7 +799,7 @@ def log_saved_labels(
795
799
  )
796
800
 
797
801
 
798
- def save_ulabels_with_parent(values: List[str], field: FieldAttr, key: str) -> None:
802
+ def save_ulabels_with_parent(values: list[str], field: FieldAttr, key: str) -> None:
799
803
  """Save a parent label for the given labels."""
800
804
  registry = field.field.model
801
805
  assert registry == ULabel
@@ -808,11 +812,11 @@ def save_ulabels_with_parent(values: List[str], field: FieldAttr, key: str) -> N
808
812
 
809
813
 
810
814
  def update_registry_from_using_instance(
811
- values: List[str],
815
+ values: list[str],
812
816
  field: FieldAttr,
813
- using: Optional[str] = None,
814
- kwargs: Optional[Dict] = None,
815
- ) -> Tuple[List[str], List[str]]:
817
+ using: str | None = None,
818
+ kwargs: dict | None = None,
819
+ ) -> tuple[list[str], list[str]]:
816
820
  """Save features or labels records from the using instance.
817
821
 
818
822
  Args:
lamindb/_artifact.py CHANGED
@@ -1,5 +1,7 @@
1
+ from __future__ import annotations
2
+
1
3
  from pathlib import Path, PurePath, PurePosixPath
2
- from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple, Union
4
+ from typing import TYPE_CHECKING, Any
3
5
 
4
6
  import fsspec
5
7
  import lamindb_setup as ln_setup
@@ -11,7 +13,6 @@ from lamindb_setup._init_instance import register_storage
11
13
  from lamindb_setup.core import StorageSettings
12
14
  from lamindb_setup.core._docs import doc_args
13
15
  from lamindb_setup.core.hashing import b16_to_b64, hash_file, hash_md5s_from_dir
14
- from lamindb_setup.core.types import UPathStr
15
16
  from lamindb_setup.core.upath import (
16
17
  create_path,
17
18
  extract_suffix_from_path,
@@ -21,7 +22,6 @@ from lamindb_setup.core.upath import (
21
22
  from lnschema_core import Artifact, Run, Storage
22
23
  from lnschema_core.models import IsTree
23
24
  from lnschema_core.types import (
24
- DataLike,
25
25
  VisibilityChoice,
26
26
  )
27
27
 
@@ -53,15 +53,17 @@ from .core._data import (
53
53
  from .core.storage.file import AUTO_KEY_PREFIX
54
54
 
55
55
  if TYPE_CHECKING:
56
+ from lamindb_setup.core.types import UPathStr
57
+
56
58
  from lamindb.core.storage._backed_access import AnnDataAccessor, BackedAccessor
57
59
 
58
60
 
59
61
  def process_pathlike(
60
62
  filepath: UPath,
61
63
  default_storage: Storage,
62
- using_key: Optional[str],
64
+ using_key: str | None,
63
65
  skip_existence_check: bool = False,
64
- ) -> Tuple[Storage, bool]:
66
+ ) -> tuple[Storage, bool]:
65
67
  if not skip_existence_check:
66
68
  try: # check if file exists
67
69
  if not filepath.exists():
@@ -111,13 +113,13 @@ def process_pathlike(
111
113
 
112
114
  def process_data(
113
115
  provisional_uid: str,
114
- data: Union[UPathStr, DataLike],
115
- format: Optional[str],
116
- key: Optional[str],
116
+ data: UPathStr | pd.DataFrame | AnnData,
117
+ format: str | None,
118
+ key: str | None,
117
119
  default_storage: Storage,
118
- using_key: Optional[str],
120
+ using_key: str | None,
119
121
  skip_existence_check: bool = False,
120
- ) -> Tuple[Any, Union[Path, UPath], str, Storage, bool]:
122
+ ) -> tuple[Any, Path | UPath, str, Storage, bool]:
121
123
  """Serialize a data object that's provided as file or in memory."""
122
124
  # if not overwritten, data gets stored in default storage
123
125
  if isinstance(data, (str, Path, UPath)): # UPathStr, spelled out
@@ -135,7 +137,7 @@ def process_data(
135
137
  )
136
138
  suffix = extract_suffix_from_path(path)
137
139
  memory_rep = None
138
- elif isinstance(data, (pd.DataFrame, AnnData)): # DataLike, spelled out
140
+ elif isinstance(data, (pd.DataFrame, AnnData)):
139
141
  storage = default_storage
140
142
  memory_rep = data
141
143
  if key is not None:
@@ -170,10 +172,10 @@ def process_data(
170
172
  def get_stat_or_artifact(
171
173
  path: UPath,
172
174
  suffix: str,
173
- memory_rep: Optional[Any] = None,
175
+ memory_rep: Any | None = None,
174
176
  check_hash: bool = True,
175
- using_key: Optional[str] = None,
176
- ) -> Union[Tuple[int, Optional[str], Optional[str], Optional[int]], Artifact]:
177
+ using_key: str | None = None,
178
+ ) -> tuple[int, str | None, str | None, int | None] | Artifact:
177
179
  n_objects = None
178
180
  if settings.upon_file_create_skip_size_hash:
179
181
  return None, None, None, n_objects
@@ -245,8 +247,8 @@ def get_stat_or_artifact(
245
247
 
246
248
 
247
249
  def check_path_in_existing_storage(
248
- path: Union[Path, UPath], using_key: Optional[str]
249
- ) -> Union[Storage, bool]:
250
+ path: Path | UPath, using_key: str | None
251
+ ) -> Storage | bool:
250
252
  for storage in Storage.objects.using(using_key).filter().all():
251
253
  # if path is part of storage, return it
252
254
  if check_path_is_child_of_root(path, root=create_path(storage.root)):
@@ -254,9 +256,7 @@ def check_path_in_existing_storage(
254
256
  return False
255
257
 
256
258
 
257
- def check_path_is_child_of_root(
258
- path: Union[Path, UPath], root: Optional[Union[Path, UPath]]
259
- ) -> bool:
259
+ def check_path_is_child_of_root(path: Path | UPath, root: Path | UPath | None) -> bool:
260
260
  path = UPath(str(path)) if not isinstance(path, UPath) else path
261
261
  root = UPath(str(root)) if not isinstance(root, UPath) else root
262
262
 
@@ -276,8 +276,8 @@ def check_path_is_child_of_root(
276
276
 
277
277
 
278
278
  def get_relative_path_to_directory(
279
- path: Union[PurePath, Path, UPath], directory: Union[PurePath, Path, UPath]
280
- ) -> Union[PurePath, Path]:
279
+ path: PurePath | Path | UPath, directory: PurePath | Path | UPath
280
+ ) -> PurePath | Path:
281
281
  if isinstance(directory, UPath) and not isinstance(directory, LocalPathClasses):
282
282
  # UPath.relative_to() is not behaving as it should (2023-04-07)
283
283
  # need to lstrip otherwise inconsistent behavior across trailing slashes
@@ -296,13 +296,13 @@ def get_relative_path_to_directory(
296
296
 
297
297
  def get_artifact_kwargs_from_data(
298
298
  *,
299
- data: Union[Path, UPath, str, pd.DataFrame, AnnData],
300
- key: Optional[str],
301
- run: Optional[Run],
302
- format: Optional[str],
299
+ data: Path | UPath | str | pd.DataFrame | AnnData,
300
+ key: str | None,
301
+ run: Run | None,
302
+ format: str | None,
303
303
  provisional_uid: str,
304
304
  default_storage: Storage,
305
- using_key: Optional[str] = None,
305
+ using_key: str | None = None,
306
306
  skip_check_exists: bool = False,
307
307
  ):
308
308
  run = get_run(run)
@@ -399,8 +399,8 @@ def get_artifact_kwargs_from_data(
399
399
  def log_storage_hint(
400
400
  *,
401
401
  check_path_in_storage: bool,
402
- storage: Optional[Storage],
403
- key: Optional[str],
402
+ storage: Storage | None,
403
+ key: str | None,
404
404
  uid: str,
405
405
  suffix: str,
406
406
  is_dir: bool,
@@ -426,7 +426,7 @@ def log_storage_hint(
426
426
  logger.hint(hint)
427
427
 
428
428
 
429
- def data_is_anndata(data: DataLike):
429
+ def data_is_anndata(data: AnnData | UPathStr):
430
430
  if isinstance(data, AnnData):
431
431
  return True
432
432
  if isinstance(data, (str, Path, UPath)):
@@ -434,7 +434,7 @@ def data_is_anndata(data: DataLike):
434
434
  return False # pragma: no cover
435
435
 
436
436
 
437
- def data_is_mudata(data: DataLike): # pragma: no cover
437
+ def data_is_mudata(data: Any | UPathStr): # pragma: no cover
438
438
  try:
439
439
  from mudata import MuData
440
440
  except ModuleNotFoundError:
@@ -447,7 +447,7 @@ def data_is_mudata(data: DataLike): # pragma: no cover
447
447
  return False
448
448
 
449
449
 
450
- def _check_accessor_artifact(data: Any, accessor: Optional[str] = None):
450
+ def _check_accessor_artifact(data: Any, accessor: str | None = None):
451
451
  if accessor is None and not isinstance(data, (str, Path, UPath)):
452
452
  if isinstance(data, pd.DataFrame):
453
453
  logger.warning("data is a DataFrame, please use .from_df()")
@@ -476,17 +476,17 @@ def __init__(artifact: Artifact, *args, **kwargs):
476
476
  if len(args) > 1:
477
477
  raise ValueError("Only one non-keyword arg allowed: data")
478
478
 
479
- data: Union[str, Path] = kwargs.pop("data") if len(args) == 0 else args[0]
480
- key: Optional[str] = kwargs.pop("key") if "key" in kwargs else None
481
- run: Optional[Run] = kwargs.pop("run") if "run" in kwargs else None
482
- description: Optional[str] = (
479
+ data: str | Path = kwargs.pop("data") if len(args) == 0 else args[0]
480
+ key: str | None = kwargs.pop("key") if "key" in kwargs else None
481
+ run: Run | None = kwargs.pop("run") if "run" in kwargs else None
482
+ description: str | None = (
483
483
  kwargs.pop("description") if "description" in kwargs else None
484
484
  )
485
- is_new_version_of: Optional[Artifact] = (
485
+ is_new_version_of: Artifact | None = (
486
486
  kwargs.pop("is_new_version_of") if "is_new_version_of" in kwargs else None
487
487
  )
488
- version: Optional[str] = kwargs.pop("version") if "version" in kwargs else None
489
- visibility: Optional[int] = (
488
+ version: str | None = kwargs.pop("version") if "version" in kwargs else None
489
+ visibility: int | None = (
490
490
  kwargs.pop("visibility")
491
491
  if "visibility" in kwargs
492
492
  else VisibilityChoice.default.value
@@ -571,14 +571,14 @@ def __init__(artifact: Artifact, *args, **kwargs):
571
571
  @doc_args(Artifact.from_df.__doc__)
572
572
  def from_df(
573
573
  cls,
574
- df: "pd.DataFrame",
575
- key: Optional[str] = None,
576
- description: Optional[str] = None,
577
- run: Optional[Run] = None,
578
- version: Optional[str] = None,
579
- is_new_version_of: Optional["Artifact"] = None,
574
+ df: pd.DataFrame,
575
+ key: str | None = None,
576
+ description: str | None = None,
577
+ run: Run | None = None,
578
+ version: str | None = None,
579
+ is_new_version_of: Artifact | None = None,
580
580
  **kwargs,
581
- ) -> "Artifact":
581
+ ) -> Artifact:
582
582
  """{}."""
583
583
  artifact = Artifact(
584
584
  data=df,
@@ -597,14 +597,14 @@ def from_df(
597
597
  @doc_args(Artifact.from_anndata.__doc__)
598
598
  def from_anndata(
599
599
  cls,
600
- adata: "AnnData",
601
- key: Optional[str] = None,
602
- description: Optional[str] = None,
603
- run: Optional[Run] = None,
604
- version: Optional[str] = None,
605
- is_new_version_of: Optional["Artifact"] = None,
600
+ adata: AnnData,
601
+ key: str | None = None,
602
+ description: str | None = None,
603
+ run: Run | None = None,
604
+ version: str | None = None,
605
+ is_new_version_of: Artifact | None = None,
606
606
  **kwargs,
607
- ) -> "Artifact":
607
+ ) -> Artifact:
608
608
  """{}."""
609
609
  artifact = Artifact(
610
610
  data=adata,
@@ -624,10 +624,10 @@ def from_anndata(
624
624
  def from_dir(
625
625
  cls,
626
626
  path: UPathStr,
627
- key: Optional[str] = None,
627
+ key: str | None = None,
628
628
  *,
629
- run: Optional[Run] = None,
630
- ) -> List["Artifact"]:
629
+ run: Run | None = None,
630
+ ) -> list[Artifact]:
631
631
  """{}."""
632
632
  logger.warning(
633
633
  "this creates one artifact per file in the directory - you might simply call"
@@ -639,7 +639,7 @@ def from_dir(
639
639
  storage, use_existing_storage = process_pathlike(
640
640
  folderpath, default_storage, using_key
641
641
  )
642
- folder_key_path: Union[PurePath, Path]
642
+ folder_key_path: PurePath | Path
643
643
  if key is None:
644
644
  if not use_existing_storage:
645
645
  logger.warning(
@@ -724,9 +724,9 @@ def from_dir(
724
724
  # docstring handled through attach_func_to_class_method
725
725
  def replace(
726
726
  self,
727
- data: Union[UPathStr, DataLike],
728
- run: Optional[Run] = None,
729
- format: Optional[str] = None,
727
+ data: UPathStr,
728
+ run: Run | None = None,
729
+ format: str | None = None,
730
730
  ) -> None:
731
731
  default_storage = settings._storage_settings.record
732
732
  kwargs, privates = get_artifact_kwargs_from_data(
@@ -784,9 +784,7 @@ def replace(
784
784
 
785
785
 
786
786
  # docstring handled through attach_func_to_class_method
787
- def backed(
788
- self, is_run_input: Optional[bool] = None
789
- ) -> Union["AnnDataAccessor", "BackedAccessor"]:
787
+ def backed(self, is_run_input: bool | None = None) -> AnnDataAccessor | BackedAccessor:
790
788
  suffixes = (".h5", ".hdf5", ".h5ad", ".zrad", ".zarr")
791
789
  if self.suffix not in suffixes:
792
790
  raise ValueError(
@@ -809,9 +807,7 @@ def backed(
809
807
 
810
808
 
811
809
  # docstring handled through attach_func_to_class_method
812
- def load(
813
- self, is_run_input: Optional[bool] = None, stream: bool = False, **kwargs
814
- ) -> DataLike:
810
+ def load(self, is_run_input: bool | None = None, stream: bool = False, **kwargs) -> Any:
815
811
  _track_run_input(self, is_run_input)
816
812
  if hasattr(self, "_memory_rep") and self._memory_rep is not None:
817
813
  return self._memory_rep
@@ -822,7 +818,7 @@ def load(
822
818
 
823
819
 
824
820
  # docstring handled through attach_func_to_class_method
825
- def stage(self, is_run_input: Optional[bool] = None) -> Path:
821
+ def stage(self, is_run_input: bool | None = None) -> Path:
826
822
  _track_run_input(self, is_run_input)
827
823
 
828
824
  using_key = settings._using_key
@@ -833,9 +829,9 @@ def stage(self, is_run_input: Optional[bool] = None) -> Path:
833
829
  # docstring handled through attach_func_to_class_method
834
830
  def delete(
835
831
  self,
836
- permanent: Optional[bool] = None,
837
- storage: Optional[bool] = None,
838
- using_key: Optional[str] = None,
832
+ permanent: bool | None = None,
833
+ storage: bool | None = None,
834
+ using_key: str | None = None,
839
835
  ) -> None:
840
836
  # by default, we only move artifacts into the trash (visibility = -1)
841
837
  trash_visibility = VisibilityChoice.trash.value
@@ -927,7 +923,7 @@ def _save_skip_storage(file, *args, **kwargs) -> None:
927
923
 
928
924
  @property # type: ignore
929
925
  @doc_args(Artifact.path.__doc__)
930
- def path(self) -> Union[Path, UPath]:
926
+ def path(self) -> Path | UPath:
931
927
  """{}."""
932
928
  using_key = settings._using_key
933
929
  return filepath_from_artifact(self, using_key)