lamindb 1.2a2__py3-none-any.whl → 1.3.1__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 +3 -1
- lamindb/_view.py +2 -2
- lamindb/base/types.py +50 -11
- lamindb/core/_compat.py +60 -0
- lamindb/core/_context.py +15 -12
- lamindb/core/datasets/__init__.py +1 -0
- lamindb/core/datasets/_core.py +23 -0
- lamindb/core/datasets/_small.py +16 -2
- lamindb/core/loaders.py +22 -12
- lamindb/core/storage/_tiledbsoma.py +2 -2
- lamindb/core/storage/_zarr.py +84 -26
- lamindb/core/storage/objects.py +45 -44
- lamindb/core/types.py +11 -1
- lamindb/curators/__init__.py +1430 -1665
- lamindb/curators/_cellxgene_schemas/__init__.py +190 -18
- lamindb/curators/_cellxgene_schemas/schema_versions.csv +43 -0
- lamindb/models/_feature_manager.py +86 -42
- lamindb/models/_from_values.py +110 -119
- lamindb/models/_label_manager.py +17 -10
- lamindb/models/artifact.py +170 -102
- lamindb/models/can_curate.py +200 -231
- lamindb/models/feature.py +76 -47
- lamindb/models/project.py +69 -7
- lamindb/models/query_set.py +12 -2
- lamindb/models/record.py +77 -50
- lamindb/models/run.py +20 -7
- lamindb/models/schema.py +7 -15
- {lamindb-1.2a2.dist-info → lamindb-1.3.1.dist-info}/METADATA +8 -7
- {lamindb-1.2a2.dist-info → lamindb-1.3.1.dist-info}/RECORD +31 -30
- lamindb/curators/_cellxgene_schemas/schema_versions.yml +0 -104
- {lamindb-1.2a2.dist-info → lamindb-1.3.1.dist-info}/LICENSE +0 -0
- {lamindb-1.2a2.dist-info → lamindb-1.3.1.dist-info}/WHEEL +0 -0
lamindb/models/artifact.py
CHANGED
@@ -16,6 +16,7 @@ from django.db.models import CASCADE, PROTECT, Q
|
|
16
16
|
from lamin_utils import colors, logger
|
17
17
|
from lamindb_setup import settings as setup_settings
|
18
18
|
from lamindb_setup._init_instance import register_storage_in_instance
|
19
|
+
from lamindb_setup.core import doc_args
|
19
20
|
from lamindb_setup.core._settings_storage import init_storage
|
20
21
|
from lamindb_setup.core.hashing import HASH_LENGTH, hash_dir, hash_file
|
21
22
|
from lamindb_setup.core.types import UPathStr
|
@@ -37,6 +38,7 @@ from lamindb.errors import FieldValidationError
|
|
37
38
|
from lamindb.models.query_set import QuerySet
|
38
39
|
|
39
40
|
from ..base.users import current_user_id
|
41
|
+
from ..core._compat import is_package_installed
|
40
42
|
from ..core.loaders import load_to_memory
|
41
43
|
from ..core.storage import (
|
42
44
|
LocalPathClasses,
|
@@ -48,7 +50,6 @@ from ..core.storage import (
|
|
48
50
|
from ..core.storage._anndata_accessor import _anndata_n_observations
|
49
51
|
from ..core.storage._pyarrow_dataset import PYARROW_SUFFIXES
|
50
52
|
from ..core.storage._tiledbsoma import _soma_n_observations
|
51
|
-
from ..core.storage.objects import is_package_installed
|
52
53
|
from ..core.storage.paths import (
|
53
54
|
AUTO_KEY_PREFIX,
|
54
55
|
auto_storage_key_from_artifact,
|
@@ -93,6 +94,8 @@ WARNING_RUN_TRANSFORM = "no run & transform got linked, call `ln.track()` & re-r
|
|
93
94
|
|
94
95
|
WARNING_NO_INPUT = "run input wasn't tracked, call `ln.track()` and re-run"
|
95
96
|
|
97
|
+
DEBUG_KWARGS_DOC = "**kwargs: Internal arguments for debugging."
|
98
|
+
|
96
99
|
try:
|
97
100
|
from ..core.storage._zarr import identify_zarr_type
|
98
101
|
except ImportError:
|
@@ -113,6 +116,7 @@ if TYPE_CHECKING:
|
|
113
116
|
|
114
117
|
from lamindb.base.types import StrField
|
115
118
|
from lamindb.core.storage._backed_access import AnnDataAccessor, BackedAccessor
|
119
|
+
from lamindb.core.types import ScverseDataStructures
|
116
120
|
|
117
121
|
from ..base.types import (
|
118
122
|
ArtifactKind,
|
@@ -126,7 +130,7 @@ if TYPE_CHECKING:
|
|
126
130
|
INCONSISTENT_STATE_MSG = (
|
127
131
|
"Trying to read a folder artifact from an outdated version, "
|
128
132
|
"this can result in an incosistent state.\n"
|
129
|
-
"Read from the latest version: artifact.versions.
|
133
|
+
"Read from the latest version: artifact.versions.get(is_latest=True)"
|
130
134
|
)
|
131
135
|
|
132
136
|
|
@@ -364,7 +368,7 @@ def get_relative_path_to_directory(
|
|
364
368
|
|
365
369
|
def get_artifact_kwargs_from_data(
|
366
370
|
*,
|
367
|
-
data: Path | UPath | str | pd.DataFrame |
|
371
|
+
data: Path | UPath | str | pd.DataFrame | ScverseDataStructures,
|
368
372
|
key: str | None,
|
369
373
|
run: Run | None,
|
370
374
|
format: str | None,
|
@@ -554,7 +558,7 @@ def data_is_spatialdata(data: SpatialData | UPathStr) -> bool:
|
|
554
558
|
|
555
559
|
|
556
560
|
def _check_otype_artifact(
|
557
|
-
data: UPathStr | pd.DataFrame |
|
561
|
+
data: UPathStr | pd.DataFrame | ScverseDataStructures,
|
558
562
|
otype: str | None = None,
|
559
563
|
) -> str:
|
560
564
|
if otype is None:
|
@@ -601,10 +605,10 @@ def get_run(run: Run | None) -> Run | None:
|
|
601
605
|
run = context.run
|
602
606
|
if run is None and not settings.creation.artifact_silence_missing_run_warning:
|
603
607
|
# here we check that this is not a read-only connection
|
604
|
-
# normally for our connection strings the read-only role name has
|
608
|
+
# normally for our connection strings the read-only role name has "read" in it
|
605
609
|
# not absolutely safe but the worst case is that the warning is not shown
|
606
610
|
instance = setup_settings.instance
|
607
|
-
if instance.dialect != "postgresql" or "
|
611
|
+
if instance.dialect != "postgresql" or "read" not in instance.db:
|
608
612
|
logger.warning(WARNING_RUN_TRANSFORM)
|
609
613
|
# suppress run by passing False
|
610
614
|
elif not run:
|
@@ -1427,7 +1431,11 @@ class Artifact(Record, IsVersioned, TracksRun, TracksUpdates):
|
|
1427
1431
|
kwargs["uid"] = uid
|
1428
1432
|
|
1429
1433
|
# only set key now so that we don't do a look-up on it in case revises is passed
|
1430
|
-
if revises is not None:
|
1434
|
+
if revises is not None and revises.key is not None:
|
1435
|
+
assert revises.key.endswith(kwargs["suffix"]), ( # noqa: S101
|
1436
|
+
revises.key,
|
1437
|
+
kwargs["suffix"],
|
1438
|
+
)
|
1431
1439
|
kwargs["key"] = revises.key
|
1432
1440
|
|
1433
1441
|
kwargs["kind"] = kind
|
@@ -1467,39 +1475,23 @@ class Artifact(Record, IsVersioned, TracksRun, TracksUpdates):
|
|
1467
1475
|
def n_objects(self) -> int:
|
1468
1476
|
return self.n_files
|
1469
1477
|
|
1470
|
-
# add the below because this is what people will have in their code
|
1471
|
-
# if they implement the recommended migration strategy
|
1472
|
-
# - FeatureSet -> Schema
|
1473
|
-
# - featureset -> schema
|
1474
|
-
# - feature_set -> schema
|
1475
|
-
# @property
|
1476
|
-
# def schemas(self) -> QuerySet[Schema]:
|
1477
|
-
# """Schemas linked to artifact via many-to-many relationship.
|
1478
|
-
|
1479
|
-
# Is now mediating the private `.feature_sets` relationship during
|
1480
|
-
# a transition period to better schema management.
|
1481
|
-
|
1482
|
-
# .. versionchanged: 1.0
|
1483
|
-
# Was previously called `.feature_sets`.
|
1484
|
-
|
1485
|
-
# """
|
1486
|
-
# return self.feature_sets
|
1487
|
-
|
1488
1478
|
@property
|
1489
1479
|
def path(self) -> Path:
|
1490
1480
|
"""Path.
|
1491
1481
|
|
1492
|
-
|
1482
|
+
Example::
|
1493
1483
|
|
1494
|
-
|
1495
|
-
>>> artifact.path
|
1496
|
-
S3QueryPath('s3://my-bucket/my-file.csv')
|
1484
|
+
import lamindb as ln
|
1497
1485
|
|
1498
|
-
|
1486
|
+
# File in cloud storage, here AWS S3:
|
1487
|
+
artifact = ln.Artifact("s3://my-bucket/my-file.csv").save()
|
1488
|
+
artifact.path
|
1489
|
+
#S3QueryPath('s3://my-bucket/my-file.csv')
|
1499
1490
|
|
1500
|
-
|
1501
|
-
|
1502
|
-
|
1491
|
+
# File in local storage:
|
1492
|
+
ln.Artifact("./myfile.csv", key="myfile.csv").save()
|
1493
|
+
artifact.path
|
1494
|
+
#> PosixPath('/home/runner/work/lamindb/lamindb/docs/guide/mydata/myfile.csv')
|
1503
1495
|
"""
|
1504
1496
|
from lamindb import settings
|
1505
1497
|
|
@@ -1519,6 +1511,34 @@ class Artifact(Record, IsVersioned, TracksRun, TracksUpdates):
|
|
1519
1511
|
filepath, cache_key=cache_key
|
1520
1512
|
)
|
1521
1513
|
|
1514
|
+
@classmethod
|
1515
|
+
def get(
|
1516
|
+
cls,
|
1517
|
+
idlike: int | str | None = None,
|
1518
|
+
**expressions,
|
1519
|
+
) -> Artifact:
|
1520
|
+
"""Get a single artifact.
|
1521
|
+
|
1522
|
+
Args:
|
1523
|
+
idlike: Either a uid stub, uid or an integer id.
|
1524
|
+
expressions: Fields and values passed as Django query expressions.
|
1525
|
+
|
1526
|
+
Raises:
|
1527
|
+
:exc:`docs:lamindb.errors.DoesNotExist`: In case no matching record is found.
|
1528
|
+
|
1529
|
+
See Also:
|
1530
|
+
- Guide: :doc:`docs:registries`
|
1531
|
+
- Method in `Record` base class: :meth:`~lamindb.models.Record.get`
|
1532
|
+
|
1533
|
+
Examples::
|
1534
|
+
|
1535
|
+
artifact = ln.Artifact.get("tCUkRcaEjTjhtozp0000")
|
1536
|
+
artifact = ln.Arfifact.get(key="my_datasets/my_file.parquet")
|
1537
|
+
"""
|
1538
|
+
from .query_set import QuerySet
|
1539
|
+
|
1540
|
+
return QuerySet(model=cls).get(idlike, **expressions)
|
1541
|
+
|
1522
1542
|
@classmethod
|
1523
1543
|
def from_df(
|
1524
1544
|
cls,
|
@@ -1546,17 +1566,19 @@ class Artifact(Record, IsVersioned, TracksRun, TracksUpdates):
|
|
1546
1566
|
:class:`~lamindb.Feature`
|
1547
1567
|
Track features.
|
1548
1568
|
|
1549
|
-
|
1550
|
-
|
1551
|
-
|
1552
|
-
|
1553
|
-
|
1554
|
-
|
1555
|
-
|
1556
|
-
|
1557
|
-
|
1558
|
-
|
1559
|
-
|
1569
|
+
Example::
|
1570
|
+
|
1571
|
+
import lamindb as ln
|
1572
|
+
|
1573
|
+
df = ln.core.datasets.df_iris_in_meter_batch1()
|
1574
|
+
df.head()
|
1575
|
+
#> sepal_length sepal_width petal_length petal_width iris_organism_code
|
1576
|
+
#> 0 0.051 0.035 0.014 0.002 0
|
1577
|
+
#> 1 0.049 0.030 0.014 0.002 0
|
1578
|
+
#> 2 0.047 0.032 0.013 0.002 0
|
1579
|
+
#> 3 0.046 0.031 0.015 0.002 0
|
1580
|
+
#> 4 0.050 0.036 0.014 0.002 0
|
1581
|
+
artifact = ln.Artifact.from_df(df, key="iris/result_batch1.parquet").save()
|
1560
1582
|
"""
|
1561
1583
|
artifact = Artifact( # type: ignore
|
1562
1584
|
data=df,
|
@@ -1599,12 +1621,12 @@ class Artifact(Record, IsVersioned, TracksRun, TracksUpdates):
|
|
1599
1621
|
:class:`~lamindb.Feature`
|
1600
1622
|
Track features.
|
1601
1623
|
|
1602
|
-
|
1603
|
-
|
1604
|
-
|
1605
|
-
|
1606
|
-
|
1607
|
-
|
1624
|
+
Example::
|
1625
|
+
|
1626
|
+
import lamindb as ln
|
1627
|
+
|
1628
|
+
adata = ln.core.datasets.anndata_with_obs()
|
1629
|
+
artifact = ln.Artifact.from_anndata(adata, key="mini_anndata_with_obs.h5ad").save()
|
1608
1630
|
"""
|
1609
1631
|
if not data_is_anndata(adata):
|
1610
1632
|
raise ValueError(
|
@@ -1661,12 +1683,12 @@ class Artifact(Record, IsVersioned, TracksRun, TracksUpdates):
|
|
1661
1683
|
:class:`~lamindb.Feature`
|
1662
1684
|
Track features.
|
1663
1685
|
|
1664
|
-
|
1665
|
-
|
1666
|
-
|
1667
|
-
|
1668
|
-
|
1669
|
-
|
1686
|
+
Example::
|
1687
|
+
|
1688
|
+
import lamindb as ln
|
1689
|
+
|
1690
|
+
mdata = ln.core.datasets.mudata_papalexi21_subset()
|
1691
|
+
artifact = ln.Artifact.from_mudata(mdata, key="mudata_papalexi21_subset.h5mu").save()
|
1670
1692
|
"""
|
1671
1693
|
if not data_is_mudata(mdata):
|
1672
1694
|
raise ValueError("data has to be a MuData object or a path to MuData-like")
|
@@ -1711,8 +1733,11 @@ class Artifact(Record, IsVersioned, TracksRun, TracksUpdates):
|
|
1711
1733
|
:class:`~lamindb.Feature`
|
1712
1734
|
Track features.
|
1713
1735
|
|
1714
|
-
|
1715
|
-
|
1736
|
+
Example::
|
1737
|
+
|
1738
|
+
import lamindb as ln
|
1739
|
+
|
1740
|
+
artifact = ln.Artifact.from_spatialdata(sdata, key="my_dataset.zarr").save()
|
1716
1741
|
"""
|
1717
1742
|
if not data_is_spatialdata(sdata):
|
1718
1743
|
raise ValueError(
|
@@ -1753,9 +1778,11 @@ class Artifact(Record, IsVersioned, TracksRun, TracksUpdates):
|
|
1753
1778
|
revises: An old version of the artifact.
|
1754
1779
|
run: The run that creates the artifact.
|
1755
1780
|
|
1756
|
-
|
1757
|
-
|
1758
|
-
|
1781
|
+
Example::
|
1782
|
+
|
1783
|
+
import lamindb as ln
|
1784
|
+
|
1785
|
+
artifact = ln.Artifact.from_tiledbsoma("s3://mybucket/store.tiledbsoma", description="a tiledbsoma store").save()
|
1759
1786
|
"""
|
1760
1787
|
if UPath(path).suffix != ".tiledbsoma":
|
1761
1788
|
raise ValueError(
|
@@ -1797,10 +1824,13 @@ class Artifact(Record, IsVersioned, TracksRun, TracksUpdates):
|
|
1797
1824
|
of a registered storage location, the inferred key defaults to `path.name`.
|
1798
1825
|
run: A `Run` object.
|
1799
1826
|
|
1800
|
-
|
1801
|
-
|
1802
|
-
|
1803
|
-
|
1827
|
+
Example::
|
1828
|
+
|
1829
|
+
import lamindb as ln
|
1830
|
+
|
1831
|
+
dir_path = ln.core.datasets.generate_cell_ranger_files("sample_001", ln.settings.storage)
|
1832
|
+
artifacts = ln.Artifact.from_dir(dir_path)
|
1833
|
+
ln.save(artifacts)
|
1804
1834
|
"""
|
1805
1835
|
from lamindb import settings
|
1806
1836
|
|
@@ -1987,6 +2017,10 @@ class Artifact(Record, IsVersioned, TracksRun, TracksUpdates):
|
|
1987
2017
|
# no need to upload if new file is already in storage
|
1988
2018
|
self._to_store = not check_path_in_storage
|
1989
2019
|
|
2020
|
+
# update old suffix with the new one so that checks in record pass
|
2021
|
+
# replace() supports changing the suffix
|
2022
|
+
self._old_suffix = self.suffix
|
2023
|
+
|
1990
2024
|
def open(
|
1991
2025
|
self, mode: str = "r", is_run_input: bool | None = None, **kwargs
|
1992
2026
|
) -> Union[
|
@@ -2005,19 +2039,24 @@ class Artifact(Record, IsVersioned, TracksRun, TracksUpdates):
|
|
2005
2039
|
Args:
|
2006
2040
|
mode: can only be `"w"` (write mode) for `tiledbsoma` stores,
|
2007
2041
|
otherwise should be always `"r"` (read-only mode).
|
2042
|
+
is_run_input: Whether to track this artifact as run input.
|
2043
|
+
**kwargs: Keyword arguments for the accessor, i.e. `h5py` or `zarr` connection,
|
2044
|
+
`pyarrow.dataset.dataset`.
|
2008
2045
|
|
2009
2046
|
Notes:
|
2010
2047
|
For more info, see tutorial: :doc:`/arrays`.
|
2011
2048
|
|
2012
|
-
|
2049
|
+
Example::
|
2050
|
+
|
2051
|
+
import lamindb as ln
|
2013
2052
|
|
2014
|
-
Read AnnData in backed mode from cloud
|
2053
|
+
# Read AnnData in backed mode from cloud
|
2015
2054
|
|
2016
|
-
|
2017
|
-
|
2018
|
-
AnnDataAccessor object with n_obs × n_vars = 70 × 765
|
2019
|
-
|
2020
|
-
|
2055
|
+
artifact = ln.Artifact.get(key="lndb-storage/pbmc68k.h5ad")
|
2056
|
+
artifact.open()
|
2057
|
+
#> AnnDataAccessor object with n_obs × n_vars = 70 × 765
|
2058
|
+
#> constructed for the AnnData object pbmc68k.h5ad
|
2059
|
+
#> ...
|
2021
2060
|
"""
|
2022
2061
|
if self._overwrite_versions and not self.is_latest:
|
2023
2062
|
raise ValueError(INCONSISTENT_STATE_MSG)
|
@@ -2118,11 +2157,18 @@ class Artifact(Record, IsVersioned, TracksRun, TracksUpdates):
|
|
2118
2157
|
_track_run_input(self, is_run_input)
|
2119
2158
|
return access
|
2120
2159
|
|
2121
|
-
def load(
|
2160
|
+
def load(
|
2161
|
+
self, *, is_run_input: bool | None = None, mute: bool = False, **kwargs
|
2162
|
+
) -> Any:
|
2122
2163
|
"""Cache and load into memory.
|
2123
2164
|
|
2124
2165
|
See all :mod:`~lamindb.core.loaders`.
|
2125
2166
|
|
2167
|
+
Args:
|
2168
|
+
is_run_input: Whether to track this artifact as run input.
|
2169
|
+
mute: Silence logging of caching progress.
|
2170
|
+
**kwargs: Keyword arguments for the loader.
|
2171
|
+
|
2126
2172
|
Examples:
|
2127
2173
|
|
2128
2174
|
Load a `DataFrame`-like artifact:
|
@@ -2156,7 +2202,9 @@ class Artifact(Record, IsVersioned, TracksRun, TracksUpdates):
|
|
2156
2202
|
filepath, cache_key = filepath_cache_key_from_artifact(
|
2157
2203
|
self, using_key=settings._using_key
|
2158
2204
|
)
|
2159
|
-
cache_path = _synchronize_cleanup_on_error(
|
2205
|
+
cache_path = _synchronize_cleanup_on_error(
|
2206
|
+
filepath, cache_key=cache_key, print_progress=not mute
|
2207
|
+
)
|
2160
2208
|
try:
|
2161
2209
|
# cache_path is local so doesn't trigger any sync in load_to_memory
|
2162
2210
|
access_memory = load_to_memory(cache_path, **kwargs)
|
@@ -2177,26 +2225,33 @@ class Artifact(Record, IsVersioned, TracksRun, TracksUpdates):
|
|
2177
2225
|
cache_path.unlink(missing_ok=True)
|
2178
2226
|
# download again and try to load into memory
|
2179
2227
|
cache_path = _synchronize_cleanup_on_error(
|
2180
|
-
filepath, cache_key=cache_key
|
2228
|
+
filepath, cache_key=cache_key, print_progress=not mute
|
2181
2229
|
)
|
2182
2230
|
access_memory = load_to_memory(cache_path, **kwargs)
|
2183
2231
|
# only call if load is successfull
|
2184
2232
|
_track_run_input(self, is_run_input)
|
2185
2233
|
return access_memory
|
2186
2234
|
|
2187
|
-
|
2235
|
+
@doc_args(DEBUG_KWARGS_DOC)
|
2236
|
+
def cache(
|
2237
|
+
self, *, is_run_input: bool | None = None, mute: bool = False, **kwargs
|
2238
|
+
) -> Path:
|
2188
2239
|
"""Download cloud artifact to local cache.
|
2189
2240
|
|
2190
2241
|
Follows synching logic: only caches an artifact if it's outdated in the local cache.
|
2191
2242
|
|
2192
2243
|
Returns a path to a locally cached on-disk object (say a `.jpg` file).
|
2193
2244
|
|
2194
|
-
|
2245
|
+
Args:
|
2246
|
+
mute: Silence logging of caching progress.
|
2247
|
+
is_run_input: Whether to track this artifact as run input.
|
2248
|
+
{}
|
2195
2249
|
|
2196
|
-
|
2250
|
+
Example::
|
2197
2251
|
|
2198
|
-
|
2199
|
-
|
2252
|
+
# Sync file from cloud and return the local path of the cache
|
2253
|
+
artifact.cache()
|
2254
|
+
#> PosixPath('/home/runner/work/Caches/lamindb/lamindb-ci/lndb-storage/pbmc68k.h5ad')
|
2200
2255
|
"""
|
2201
2256
|
from lamindb import settings
|
2202
2257
|
|
@@ -2206,7 +2261,11 @@ class Artifact(Record, IsVersioned, TracksRun, TracksUpdates):
|
|
2206
2261
|
filepath, cache_key = filepath_cache_key_from_artifact(
|
2207
2262
|
self, using_key=settings._using_key
|
2208
2263
|
)
|
2209
|
-
|
2264
|
+
if mute:
|
2265
|
+
kwargs["print_progress"] = False
|
2266
|
+
cache_path = _synchronize_cleanup_on_error(
|
2267
|
+
filepath, cache_key=cache_key, **kwargs
|
2268
|
+
)
|
2210
2269
|
# only call if sync is successfull
|
2211
2270
|
_track_run_input(self, is_run_input)
|
2212
2271
|
return cache_path
|
@@ -2231,18 +2290,19 @@ class Artifact(Record, IsVersioned, TracksRun, TracksUpdates):
|
|
2231
2290
|
permanent: Permanently delete the artifact (skip trash).
|
2232
2291
|
storage: Indicate whether you want to delete the artifact in storage.
|
2233
2292
|
|
2234
|
-
|
2293
|
+
Example::
|
2235
2294
|
|
2236
|
-
|
2295
|
+
import lamindb as ln
|
2237
2296
|
|
2238
|
-
|
2239
|
-
|
2297
|
+
# For an `Artifact` object `artifact`, call:
|
2298
|
+
artifact = ln.Artifact.get(key="some.csv")
|
2299
|
+
artifact.delete() # delete a single file artifact
|
2240
2300
|
|
2241
|
-
|
2242
|
-
|
2301
|
+
artifact = ln.Artifact.filter(key="some.tiledbsoma". is_latest=False).first()
|
2302
|
+
artiact.delete() # delete an old version, the data will not be deleted
|
2243
2303
|
|
2244
|
-
|
2245
|
-
|
2304
|
+
artifact = ln.Artifact.get(key="some.tiledbsoma". is_latest=True)
|
2305
|
+
artiact.delete() # delete all versions, the data will be deleted or prompted for deletion.
|
2246
2306
|
"""
|
2247
2307
|
# this first check means an invalid delete fails fast rather than cascading through
|
2248
2308
|
# database and storage permission errors
|
@@ -2330,15 +2390,19 @@ class Artifact(Record, IsVersioned, TracksRun, TracksUpdates):
|
|
2330
2390
|
if delete_msg != "did-not-delete":
|
2331
2391
|
logger.success(f"deleted {colors.yellow(f'{path}')}")
|
2332
2392
|
|
2393
|
+
@doc_args(DEBUG_KWARGS_DOC)
|
2333
2394
|
def save(self, upload: bool | None = None, **kwargs) -> Artifact:
|
2334
2395
|
"""Save to database & storage.
|
2335
2396
|
|
2336
2397
|
Args:
|
2337
2398
|
upload: Trigger upload to cloud storage in instances with hybrid storage mode.
|
2399
|
+
{}
|
2338
2400
|
|
2339
|
-
|
2340
|
-
|
2341
|
-
|
2401
|
+
Example::
|
2402
|
+
|
2403
|
+
import lamindb as ln
|
2404
|
+
|
2405
|
+
artifact = ln.Artifact("./myfile.csv", key="myfile.parquet").save()
|
2342
2406
|
"""
|
2343
2407
|
state_was_adding = self._state.adding
|
2344
2408
|
print_progress = kwargs.pop("print_progress", True)
|
@@ -2407,8 +2471,9 @@ class Artifact(Record, IsVersioned, TracksRun, TracksUpdates):
|
|
2407
2471
|
def restore(self) -> None:
|
2408
2472
|
"""Restore from trash.
|
2409
2473
|
|
2410
|
-
|
2411
|
-
|
2474
|
+
Example::
|
2475
|
+
|
2476
|
+
artifact.restore()
|
2412
2477
|
"""
|
2413
2478
|
self._branch_code = 1
|
2414
2479
|
self.save()
|
@@ -2416,8 +2481,9 @@ class Artifact(Record, IsVersioned, TracksRun, TracksUpdates):
|
|
2416
2481
|
def describe(self) -> None:
|
2417
2482
|
"""Describe relations of record.
|
2418
2483
|
|
2419
|
-
|
2420
|
-
|
2484
|
+
Example::
|
2485
|
+
|
2486
|
+
artifact.describe()
|
2421
2487
|
"""
|
2422
2488
|
return describe_artifact_collection(self)
|
2423
2489
|
|
@@ -2427,11 +2493,12 @@ class Artifact(Record, IsVersioned, TracksRun, TracksUpdates):
|
|
2427
2493
|
|
2428
2494
|
# can't really just call .cache in .load because of double tracking
|
2429
2495
|
def _synchronize_cleanup_on_error(
|
2430
|
-
filepath: UPath, cache_key: str | None = None
|
2496
|
+
filepath: UPath, cache_key: str | None = None, **kwargs
|
2431
2497
|
) -> UPath:
|
2432
2498
|
try:
|
2499
|
+
print_progress = kwargs.pop("print_progress", True)
|
2433
2500
|
cache_path = setup_settings.paths.cloud_to_local(
|
2434
|
-
filepath, cache_key=cache_key, print_progress=
|
2501
|
+
filepath, cache_key=cache_key, print_progress=print_progress, **kwargs
|
2435
2502
|
)
|
2436
2503
|
except Exception as e:
|
2437
2504
|
if not isinstance(filepath, LocalPathClasses):
|
@@ -2477,8 +2544,9 @@ class ArtifactParamValue(BasicRecord, LinkORM, TracksRun):
|
|
2477
2544
|
|
2478
2545
|
|
2479
2546
|
def _track_run_input(
|
2480
|
-
data:
|
2481
|
-
|
2547
|
+
data: (
|
2548
|
+
Artifact | Iterable[Artifact]
|
2549
|
+
), # can also be Collection | Iterable[Collection]
|
2482
2550
|
is_run_input: bool | Run | None = None,
|
2483
2551
|
run: Run | None = None,
|
2484
2552
|
):
|
@@ -2542,10 +2610,10 @@ def _track_run_input(
|
|
2542
2610
|
if run is None:
|
2543
2611
|
if settings.track_run_inputs:
|
2544
2612
|
# here we check that this is not a read-only connection
|
2545
|
-
# normally for our connection strings the read-only role name has
|
2613
|
+
# normally for our connection strings the read-only role name has "read" in it
|
2546
2614
|
# not absolutely safe but the worst case is that the warning is not shown
|
2547
2615
|
instance = setup_settings.instance
|
2548
|
-
if instance.dialect != "postgresql" or "
|
2616
|
+
if instance.dialect != "postgresql" or "read" not in instance.db:
|
2549
2617
|
logger.warning(WARNING_NO_INPUT)
|
2550
2618
|
# assume we have a run record
|
2551
2619
|
else:
|