lamindb_setup 0.81.2__py3-none-any.whl → 0.81.4__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_setup/__init__.py +1 -1
- lamindb_setup/core/_hub_core.py +4 -1
- lamindb_setup/core/_hub_crud.py +24 -19
- lamindb_setup/core/_settings.py +18 -10
- lamindb_setup/core/_settings_storage.py +15 -14
- lamindb_setup/core/upath.py +36 -26
- {lamindb_setup-0.81.2.dist-info → lamindb_setup-0.81.4.dist-info}/METADATA +3 -4
- {lamindb_setup-0.81.2.dist-info → lamindb_setup-0.81.4.dist-info}/RECORD +10 -10
- {lamindb_setup-0.81.2.dist-info → lamindb_setup-0.81.4.dist-info}/LICENSE +0 -0
- {lamindb_setup-0.81.2.dist-info → lamindb_setup-0.81.4.dist-info}/WHEEL +0 -0
lamindb_setup/__init__.py
CHANGED
lamindb_setup/core/_hub_core.py
CHANGED
|
@@ -239,6 +239,10 @@ def _delete_instance(
|
|
|
239
239
|
)
|
|
240
240
|
root_string = storage_record["root"]
|
|
241
241
|
# gate storage and instance deletion on empty storage location for
|
|
242
|
+
# normally auth.get_session() doesn't have access_token
|
|
243
|
+
# so this block is useless i think (Sergei)
|
|
244
|
+
# the token is received from user settings inside create_path
|
|
245
|
+
# might be needed in the hub though
|
|
242
246
|
if client.auth.get_session() is not None:
|
|
243
247
|
access_token = client.auth.get_session().access_token
|
|
244
248
|
else:
|
|
@@ -251,7 +255,6 @@ def _delete_instance(
|
|
|
251
255
|
check_storage_is_empty(
|
|
252
256
|
root_path, account_for_sqlite_file=account_for_sqlite_file
|
|
253
257
|
)
|
|
254
|
-
_update_instance_record(instance_with_storage["id"], {"storage_id": None}, client)
|
|
255
258
|
# first delete the storage records because we will turn instance_id on
|
|
256
259
|
# storage into a FK soon
|
|
257
260
|
for storage_record in storage_records:
|
lamindb_setup/core/_hub_crud.py
CHANGED
|
@@ -12,25 +12,23 @@ def select_instance_by_owner_name(
|
|
|
12
12
|
name: str,
|
|
13
13
|
client: Client,
|
|
14
14
|
) -> dict | None:
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
)
|
|
22
|
-
.eq("name", name)
|
|
23
|
-
.eq("account.handle", owner)
|
|
24
|
-
.eq("storage.is_default", True)
|
|
25
|
-
.execute()
|
|
26
|
-
.data
|
|
15
|
+
# this won't find an instance without the default storage
|
|
16
|
+
data = (
|
|
17
|
+
client.table("instance")
|
|
18
|
+
.select(
|
|
19
|
+
"*, account!inner!instance_account_id_28936e8f_fk_account_id(*),"
|
|
20
|
+
" storage!inner!storage_instance_id_359fca71_fk_instance_id(*)"
|
|
27
21
|
)
|
|
28
|
-
|
|
29
|
-
|
|
22
|
+
.eq("name", name)
|
|
23
|
+
.eq("account.handle", owner)
|
|
24
|
+
.eq("storage.is_default", True)
|
|
25
|
+
.execute()
|
|
26
|
+
.data
|
|
27
|
+
)
|
|
30
28
|
if len(data) == 0:
|
|
31
29
|
return None
|
|
32
30
|
result = data[0]
|
|
33
|
-
# this is
|
|
31
|
+
# this is a list
|
|
34
32
|
# assume only one default storage
|
|
35
33
|
result["storage"] = result["storage"][0]
|
|
36
34
|
return result
|
|
@@ -89,15 +87,22 @@ def select_instance_by_id_with_storage(
|
|
|
89
87
|
instance_id: str,
|
|
90
88
|
client: Client,
|
|
91
89
|
):
|
|
92
|
-
|
|
90
|
+
# this won't find an instance without the default storage
|
|
91
|
+
data = (
|
|
93
92
|
client.table("instance")
|
|
94
|
-
.select("*, storage!
|
|
93
|
+
.select("*, storage!inner!storage_instance_id_359fca71_fk_instance_id(*)")
|
|
95
94
|
.eq("id", instance_id)
|
|
95
|
+
.eq("storage.is_default", True)
|
|
96
96
|
.execute()
|
|
97
|
+
.data
|
|
97
98
|
)
|
|
98
|
-
if len(
|
|
99
|
+
if len(data) == 0:
|
|
99
100
|
return None
|
|
100
|
-
|
|
101
|
+
result = data[0]
|
|
102
|
+
# this is a list
|
|
103
|
+
# assume only one default storage
|
|
104
|
+
result["storage"] = result["storage"][0]
|
|
105
|
+
return result
|
|
101
106
|
|
|
102
107
|
|
|
103
108
|
def update_instance(instance_id: str, instance_fields: dict, client: Client):
|
lamindb_setup/core/_settings.py
CHANGED
|
@@ -195,27 +195,35 @@ class SetupPaths:
|
|
|
195
195
|
filepath: UPathStr, cache_key: str | None = None
|
|
196
196
|
) -> UPath:
|
|
197
197
|
"""Local (or local cache) filepath from filepath without synchronization."""
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
if
|
|
198
|
+
if not isinstance(filepath, UPath):
|
|
199
|
+
filepath = UPath(filepath)
|
|
200
|
+
# cache_key is ignored if filepath is a local path
|
|
201
|
+
if not isinstance(filepath, LocalPathClasses):
|
|
201
202
|
# settings is defined further in this file
|
|
202
|
-
|
|
203
|
-
filepath.path
|
|
204
|
-
|
|
203
|
+
if cache_key is None:
|
|
204
|
+
local_key = filepath.path # type: ignore
|
|
205
|
+
protocol = filepath.protocol # type: ignore
|
|
206
|
+
if protocol in {"http", "https"}:
|
|
207
|
+
local_key = local_key.removeprefix(protocol + "://")
|
|
208
|
+
else:
|
|
209
|
+
local_key = cache_key
|
|
210
|
+
local_filepath = settings.cache_dir / local_key
|
|
205
211
|
else:
|
|
206
212
|
local_filepath = filepath
|
|
207
|
-
return
|
|
213
|
+
return local_filepath
|
|
208
214
|
|
|
209
215
|
@staticmethod
|
|
210
216
|
def cloud_to_local(
|
|
211
217
|
filepath: UPathStr, cache_key: str | None = None, **kwargs
|
|
212
218
|
) -> UPath:
|
|
213
219
|
"""Local (or local cache) filepath from filepath."""
|
|
214
|
-
|
|
220
|
+
if not isinstance(filepath, UPath):
|
|
221
|
+
filepath = UPath(filepath)
|
|
222
|
+
# cache_key is ignored in cloud_to_local_no_update if filepath is local
|
|
215
223
|
local_filepath = SetupPaths.cloud_to_local_no_update(filepath, cache_key)
|
|
216
|
-
if
|
|
224
|
+
if not isinstance(filepath, LocalPathClasses):
|
|
217
225
|
local_filepath.parent.mkdir(parents=True, exist_ok=True)
|
|
218
|
-
filepath.synchronize(local_filepath, **kwargs)
|
|
226
|
+
filepath.synchronize(local_filepath, **kwargs) # type: ignore
|
|
219
227
|
return local_filepath
|
|
220
228
|
|
|
221
229
|
|
|
@@ -7,6 +7,7 @@ import string
|
|
|
7
7
|
from pathlib import Path
|
|
8
8
|
from typing import TYPE_CHECKING, Any, Literal
|
|
9
9
|
|
|
10
|
+
import fsspec
|
|
10
11
|
from lamin_utils import logger
|
|
11
12
|
|
|
12
13
|
from ._aws_credentials import HOSTED_REGIONS, get_aws_credentials_manager
|
|
@@ -24,6 +25,10 @@ if TYPE_CHECKING:
|
|
|
24
25
|
|
|
25
26
|
IS_INITIALIZED_KEY = ".lamindb/_is_initialized"
|
|
26
27
|
|
|
28
|
+
# a list of supported fsspec protocols
|
|
29
|
+
# rename file to local before showing to a user
|
|
30
|
+
VALID_PROTOCOLS = ("file", "gs", "s3", "hf", "http", "https")
|
|
31
|
+
|
|
27
32
|
|
|
28
33
|
def base62(n_char: int) -> str:
|
|
29
34
|
"""Like nanoid without hyphen and underscore."""
|
|
@@ -114,16 +119,11 @@ def init_storage(
|
|
|
114
119
|
root_str = f"s3://lamin-{region}/{uid}"
|
|
115
120
|
else:
|
|
116
121
|
root_str = f"s3://lamin-hosted-test/{uid}"
|
|
117
|
-
elif
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
except Exception as e:
|
|
123
|
-
logger.error(
|
|
124
|
-
"`storage` is not a valid local, GCP storage, AWS S3 path or Hugging Face path"
|
|
125
|
-
)
|
|
126
|
-
raise e
|
|
122
|
+
elif (input_protocol := fsspec.utils.get_protocol(root_str)) not in VALID_PROTOCOLS:
|
|
123
|
+
valid_protocols = ("local",) + VALID_PROTOCOLS[1:] # show local instead of file
|
|
124
|
+
raise ValueError(
|
|
125
|
+
f"Protocol {input_protocol} is not supported, valid protocols are {', '.join(valid_protocols)}"
|
|
126
|
+
)
|
|
127
127
|
ssettings = StorageSettings(
|
|
128
128
|
uid=uid,
|
|
129
129
|
root=root_str,
|
|
@@ -227,7 +227,7 @@ class StorageSettings:
|
|
|
227
227
|
|
|
228
228
|
@property
|
|
229
229
|
def record(self) -> Any:
|
|
230
|
-
"""Storage record in current instance."""
|
|
230
|
+
"""Storage record in the current instance."""
|
|
231
231
|
if self._record is None:
|
|
232
232
|
# dynamic import because of import order
|
|
233
233
|
from lnschema_core.models import Storage
|
|
@@ -299,14 +299,15 @@ class StorageSettings:
|
|
|
299
299
|
return self._region
|
|
300
300
|
|
|
301
301
|
@property
|
|
302
|
-
def type(self) -> Literal["local", "s3", "gs"]:
|
|
302
|
+
def type(self) -> Literal["local", "s3", "gs", "hf", "http", "https"]:
|
|
303
303
|
"""AWS S3 vs. Google Cloud vs. local.
|
|
304
304
|
|
|
305
|
-
Returns the protocol as a string: "local", "s3", "gs".
|
|
305
|
+
Returns the protocol as a string: "local", "s3", "gs", "http", "https".
|
|
306
306
|
"""
|
|
307
307
|
import fsspec
|
|
308
308
|
|
|
309
309
|
convert = {"file": "local"}
|
|
310
|
+
# init_storage checks that the root protocol belongs to VALID_PROTOCOLS
|
|
310
311
|
protocol = fsspec.utils.get_protocol(self.root_as_str)
|
|
311
312
|
return convert.get(protocol, protocol) # type: ignore
|
|
312
313
|
|
|
@@ -345,5 +346,5 @@ class StorageSettings:
|
|
|
345
346
|
return self.root / filekey
|
|
346
347
|
|
|
347
348
|
def local_filepath(self, filekey: UPathStr) -> UPath:
|
|
348
|
-
"""Local (cache) filepath from filekey
|
|
349
|
+
"""Local (cache) filepath from filekey."""
|
|
349
350
|
return self.cloud_to_local(self.key_to_filepath(filekey))
|
lamindb_setup/core/upath.py
CHANGED
|
@@ -190,7 +190,13 @@ class ProgressCallback(fsspec.callbacks.Callback):
|
|
|
190
190
|
pass
|
|
191
191
|
|
|
192
192
|
def update_relative_value(self, inc=1):
|
|
193
|
-
|
|
193
|
+
if inc != 0:
|
|
194
|
+
self.value += inc
|
|
195
|
+
# this is specific to http filesystem
|
|
196
|
+
# for some reason the last update is 0 always
|
|
197
|
+
# here 100% is forced manually in this case
|
|
198
|
+
elif self.value >= 0.999:
|
|
199
|
+
self.value = self.size
|
|
194
200
|
self.call()
|
|
195
201
|
|
|
196
202
|
def branch(self, path_1, path_2, kwargs):
|
|
@@ -350,27 +356,19 @@ def synchronize(
|
|
|
350
356
|
exists = True
|
|
351
357
|
cloud_mts = timestamp
|
|
352
358
|
else:
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
cloud_mts = self.modified.timestamp()
|
|
367
|
-
is_dir = False
|
|
368
|
-
exists = True
|
|
369
|
-
except FileNotFoundError:
|
|
370
|
-
exists = False
|
|
371
|
-
except IsADirectoryError:
|
|
372
|
-
is_dir = True
|
|
373
|
-
exists = True
|
|
359
|
+
try:
|
|
360
|
+
cloud_stat = self.stat()
|
|
361
|
+
cloud_info = cloud_stat.as_info()
|
|
362
|
+
exists = True
|
|
363
|
+
is_dir = cloud_info["type"] == "directory"
|
|
364
|
+
if not is_dir:
|
|
365
|
+
# hf requires special treatment
|
|
366
|
+
if protocol == "hf":
|
|
367
|
+
cloud_mts = cloud_info["last_commit"].date.timestamp()
|
|
368
|
+
else:
|
|
369
|
+
cloud_mts = cloud_stat.st_mtime
|
|
370
|
+
except FileNotFoundError:
|
|
371
|
+
exists = False
|
|
374
372
|
|
|
375
373
|
if not exists:
|
|
376
374
|
warn_or_error = f"The original path {self} does not exist anymore."
|
|
@@ -386,6 +384,7 @@ def synchronize(
|
|
|
386
384
|
return None
|
|
387
385
|
|
|
388
386
|
# synchronization logic for directories
|
|
387
|
+
# to synchronize directories, it should be possible to get modification times
|
|
389
388
|
if is_dir:
|
|
390
389
|
files = self.fs.find(str(self), detail=True)
|
|
391
390
|
if protocol == "s3":
|
|
@@ -451,8 +450,16 @@ def synchronize(
|
|
|
451
450
|
callback, print_progress, objectpath.name, "synchronizing"
|
|
452
451
|
)
|
|
453
452
|
if objectpath.exists():
|
|
454
|
-
|
|
455
|
-
|
|
453
|
+
if cloud_mts != 0:
|
|
454
|
+
local_mts_obj = objectpath.stat().st_mtime
|
|
455
|
+
need_synchronize = cloud_mts > local_mts_obj
|
|
456
|
+
else:
|
|
457
|
+
# this is true for http for example
|
|
458
|
+
# where size is present but st_mtime is not
|
|
459
|
+
# we assume that any change without the change in size is unlikely
|
|
460
|
+
cloud_size = cloud_stat.st_size
|
|
461
|
+
local_size_obj = objectpath.stat().st_size
|
|
462
|
+
need_synchronize = cloud_size != local_size_obj
|
|
456
463
|
else:
|
|
457
464
|
objectpath.parent.mkdir(parents=True, exist_ok=True)
|
|
458
465
|
need_synchronize = True
|
|
@@ -464,7 +471,8 @@ def synchronize(
|
|
|
464
471
|
self.download_to(
|
|
465
472
|
objectpath, recursive=False, print_progress=False, callback=callback
|
|
466
473
|
)
|
|
467
|
-
|
|
474
|
+
if cloud_mts != 0:
|
|
475
|
+
os.utime(objectpath, times=(cloud_mts, cloud_mts))
|
|
468
476
|
else:
|
|
469
477
|
# nothing happens if parent_update is not defined
|
|
470
478
|
# because of Callback.no_op
|
|
@@ -739,7 +747,9 @@ def get_stat_file_cloud(stat: dict) -> tuple[int, str | None, str | None]:
|
|
|
739
747
|
hash = b16_to_b64(stat["blob_id"])
|
|
740
748
|
hash_type = "sha1"
|
|
741
749
|
# s3
|
|
742
|
-
|
|
750
|
+
# StorageClass is checked to be sure that it is indeed s3
|
|
751
|
+
# because http also has ETag
|
|
752
|
+
elif "ETag" in stat and "StorageClass" in stat:
|
|
743
753
|
etag = stat["ETag"]
|
|
744
754
|
# small files
|
|
745
755
|
if "-" not in etag:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: lamindb_setup
|
|
3
|
-
Version: 0.81.
|
|
3
|
+
Version: 0.81.4
|
|
4
4
|
Summary: Setup & configure LaminDB.
|
|
5
5
|
Author-email: Lamin Labs <open-source@lamin.ai>
|
|
6
6
|
Requires-Python: >=3.9
|
|
@@ -14,12 +14,11 @@ Requires-Dist: appdirs<2.0.0
|
|
|
14
14
|
Requires-Dist: requests
|
|
15
15
|
Requires-Dist: universal_pathlib==0.2.5
|
|
16
16
|
Requires-Dist: botocore<2.0.0
|
|
17
|
-
Requires-Dist:
|
|
18
|
-
Requires-Dist: supabase==2.2.1
|
|
17
|
+
Requires-Dist: supabase>=2.8.1,<=2.10.0
|
|
19
18
|
Requires-Dist: psutil
|
|
20
19
|
Requires-Dist: urllib3<2 ; extra == "aws"
|
|
21
20
|
Requires-Dist: aiobotocore[boto3]>=2.5.4,<3.0.0 ; extra == "aws"
|
|
22
|
-
Requires-Dist: s3fs>=2023.12.2,<=2024.10.0 ; extra == "aws"
|
|
21
|
+
Requires-Dist: s3fs>=2023.12.2,<=2024.10.0,!=2024.10.0 ; extra == "aws"
|
|
23
22
|
Requires-Dist: line_profiler ; extra == "dev"
|
|
24
23
|
Requires-Dist: pyjwt<3.0.0 ; extra == "dev"
|
|
25
24
|
Requires-Dist: psycopg2-binary ; extra == "dev"
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
lamindb_setup/__init__.py,sha256=
|
|
1
|
+
lamindb_setup/__init__.py,sha256=41Rm-lDXIF3ir0Xsj-vpB0EZO5SmkipsRc5pmUzBEvk,1714
|
|
2
2
|
lamindb_setup/_cache.py,sha256=1XnM-V_KprbjpgPY7Bg3FYn53Iz_2_fEgcMOaSdKKbg,1332
|
|
3
3
|
lamindb_setup/_check.py,sha256=28PcG8Kp6OpjSLSi1r2boL2Ryeh6xkaCL87HFbjs6GA,129
|
|
4
4
|
lamindb_setup/_check_setup.py,sha256=6cSfpmVOSgU7YiVHfJpBTGTQ7rrnwunt1pJT_jkgNM8,3196
|
|
@@ -23,15 +23,15 @@ lamindb_setup/core/_aws_storage.py,sha256=nEjeUv4xUVpoV0Lx-zjjmyb9w804bDyaeiM-Oq
|
|
|
23
23
|
lamindb_setup/core/_deprecated.py,sha256=3qxUI1dnDlSeR0BYrv7ucjqRBEojbqotPgpShXs4KF8,2520
|
|
24
24
|
lamindb_setup/core/_docs.py,sha256=3k-YY-oVaJd_9UIY-LfBg_u8raKOCNfkZQPA73KsUhs,276
|
|
25
25
|
lamindb_setup/core/_hub_client.py,sha256=cN19XbZmvLCxL_GKdOcKbedNRL7kR47vmLmA--NMv-U,6306
|
|
26
|
-
lamindb_setup/core/_hub_core.py,sha256=
|
|
27
|
-
lamindb_setup/core/_hub_crud.py,sha256=
|
|
26
|
+
lamindb_setup/core/_hub_core.py,sha256=cZfEDFq2z0cHjyPqwg7K5K3vw9C2nDHnbIHmmAjVbeM,19997
|
|
27
|
+
lamindb_setup/core/_hub_crud.py,sha256=ro4dvZ0EaHs7_QwJH6BoKl69Wc9HEPDkIc9BFyO_DMg,5460
|
|
28
28
|
lamindb_setup/core/_hub_utils.py,sha256=08NwQsb53-tXa_pr-f0tPTN0FeeVf_i1p3dEbEWD0F4,3016
|
|
29
29
|
lamindb_setup/core/_private_django_api.py,sha256=KIn43HOhiRjkbTbddyJqv-WNTTa1bAizbM1tWXoXPBg,2869
|
|
30
|
-
lamindb_setup/core/_settings.py,sha256=
|
|
30
|
+
lamindb_setup/core/_settings.py,sha256=NYrSGtAw68mlQJgzBnV-DECi-RUBn32eeosyYCBtW3I,8232
|
|
31
31
|
lamindb_setup/core/_settings_instance.py,sha256=ajcq9zRNE598tTqyMkMqaEOubVfFeE998DPtbgyzK3A,18801
|
|
32
32
|
lamindb_setup/core/_settings_load.py,sha256=5OpghcbkrK9KBM_0Iu-61FTI76UbOpPkkJpUittXS-w,4098
|
|
33
33
|
lamindb_setup/core/_settings_save.py,sha256=rxGxgaK5i9exKqSJERQQyY1WZio20meoQJoYXlVW-1w,3138
|
|
34
|
-
lamindb_setup/core/_settings_storage.py,sha256=
|
|
34
|
+
lamindb_setup/core/_settings_storage.py,sha256=FOTyi89BZ48a8elCQ91C4B6oMO4tBnva4J6Tk40N9Ww,12249
|
|
35
35
|
lamindb_setup/core/_settings_store.py,sha256=WcsgOmgnu9gztcrhp-N4OONNZyxICHV8M0HdJllTaEo,2219
|
|
36
36
|
lamindb_setup/core/_settings_user.py,sha256=iz0MqFLKXqm8LYx_CHmr02_oNvYWFLIxKkJLdpS5W08,1476
|
|
37
37
|
lamindb_setup/core/_setup_bionty_sources.py,sha256=jZOPXpipW_5IjMO-bLMk-_wVwk7-5MLd72K2rnqqy7U,4001
|
|
@@ -40,8 +40,8 @@ lamindb_setup/core/django.py,sha256=E4U9nUlV2kHd-G5v6iSdFGAAWixlQDxOFwMwOMG9xfw,
|
|
|
40
40
|
lamindb_setup/core/exceptions.py,sha256=4NpLUNUIfXYVTFX2FvLZF8RW34exk2Vn2X3G4YhnTRg,276
|
|
41
41
|
lamindb_setup/core/hashing.py,sha256=26dtak7XgmrWa_D1zuDyxObRQcriMtnc1yEigkKASmM,3142
|
|
42
42
|
lamindb_setup/core/types.py,sha256=zJii2le38BJUmsNVvzDrbzGYr0yaeb-9Rw9IKmsBr3k,523
|
|
43
|
-
lamindb_setup/core/upath.py,sha256=
|
|
44
|
-
lamindb_setup-0.81.
|
|
45
|
-
lamindb_setup-0.81.
|
|
46
|
-
lamindb_setup-0.81.
|
|
47
|
-
lamindb_setup-0.81.
|
|
43
|
+
lamindb_setup/core/upath.py,sha256=X5Jjm50-br1Qq3eRlO6U4ykidptc2QzoQtq-ilaPt4Q,29602
|
|
44
|
+
lamindb_setup-0.81.4.dist-info/LICENSE,sha256=UOZ1F5fFDe3XXvG4oNnkL1-Ecun7zpHzRxjp-XsMeAo,11324
|
|
45
|
+
lamindb_setup-0.81.4.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81
|
|
46
|
+
lamindb_setup-0.81.4.dist-info/METADATA,sha256=xstSHpwOECuKUylOziRLHFHtafUtglGT1CQA0lUGscs,1730
|
|
47
|
+
lamindb_setup-0.81.4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|