lamindb_setup 1.6.1__py3-none-any.whl → 1.7.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- lamindb_setup/__init__.py +5 -3
- lamindb_setup/_cache.py +46 -11
- lamindb_setup/_check_setup.py +9 -22
- lamindb_setup/_connect_instance.py +9 -157
- lamindb_setup/_init_instance.py +39 -53
- lamindb_setup/_register_instance.py +1 -1
- lamindb_setup/_schema_metadata.py +4 -0
- lamindb_setup/_set_managed_storage.py +6 -4
- lamindb_setup/core/__init__.py +1 -1
- lamindb_setup/core/_aws_options.py +3 -3
- lamindb_setup/core/_hub_client.py +2 -3
- lamindb_setup/core/_hub_core.py +68 -35
- lamindb_setup/core/_hub_crud.py +17 -3
- lamindb_setup/core/_settings.py +28 -10
- lamindb_setup/core/_settings_instance.py +8 -5
- lamindb_setup/core/_settings_load.py +23 -14
- lamindb_setup/core/_settings_save.py +5 -4
- lamindb_setup/core/_settings_storage.py +105 -46
- lamindb_setup/core/_settings_store.py +11 -2
- lamindb_setup/core/cloud_sqlite_locker.py +2 -6
- lamindb_setup/core/django.py +7 -2
- lamindb_setup/core/exceptions.py +1 -10
- lamindb_setup/core/hashing.py +1 -1
- lamindb_setup/core/types.py +1 -17
- lamindb_setup/core/upath.py +16 -10
- lamindb_setup/errors.py +70 -0
- lamindb_setup/types.py +20 -0
- {lamindb_setup-1.6.1.dist-info → lamindb_setup-1.7.0.dist-info}/METADATA +2 -2
- lamindb_setup-1.7.0.dist-info/RECORD +50 -0
- lamindb_setup-1.6.1.dist-info/RECORD +0 -48
- {lamindb_setup-1.6.1.dist-info → lamindb_setup-1.7.0.dist-info}/LICENSE +0 -0
- {lamindb_setup-1.6.1.dist-info → lamindb_setup-1.7.0.dist-info}/WHEEL +0 -0
lamindb_setup/core/__init__.py
CHANGED
|
@@ -31,7 +31,7 @@ AWS_CREDENTIALS_EXPIRATION: int = 11 * 60 * 60 # refresh credentials after 11 h
|
|
|
31
31
|
|
|
32
32
|
# set anon=True for these buckets if credentials fail for a public bucket
|
|
33
33
|
# to be expanded
|
|
34
|
-
PUBLIC_BUCKETS: tuple[str] = ("cellxgene-data-public",)
|
|
34
|
+
PUBLIC_BUCKETS: tuple[str, ...] = ("cellxgene-data-public", "bionty-assets")
|
|
35
35
|
|
|
36
36
|
|
|
37
37
|
# s3-comaptible endpoints managed by lamin
|
|
@@ -79,8 +79,8 @@ class AWSOptionsManager:
|
|
|
79
79
|
# use lamindata public bucket for this test
|
|
80
80
|
fs.call_s3("head_bucket", Bucket="lamindata")
|
|
81
81
|
self.anon_public = False
|
|
82
|
-
except Exception
|
|
83
|
-
self.anon_public =
|
|
82
|
+
except Exception:
|
|
83
|
+
self.anon_public = True
|
|
84
84
|
|
|
85
85
|
def _find_root(self, path_str: str) -> str | None:
|
|
86
86
|
roots = self._credentials_cache.keys()
|
|
@@ -5,7 +5,6 @@ import os
|
|
|
5
5
|
from typing import Literal
|
|
6
6
|
from urllib.request import urlretrieve
|
|
7
7
|
|
|
8
|
-
from gotrue.errors import AuthUnknownError
|
|
9
8
|
from lamin_utils import logger
|
|
10
9
|
from pydantic_settings import BaseSettings
|
|
11
10
|
from supabase import Client, create_client # type: ignore
|
|
@@ -26,7 +25,7 @@ def load_fallback_connector() -> Connector:
|
|
|
26
25
|
return connector
|
|
27
26
|
|
|
28
27
|
|
|
29
|
-
PROD_URL = "https://
|
|
28
|
+
PROD_URL = "https://hub.lamin.ai"
|
|
30
29
|
PROD_ANON_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImxhZXNhdW1tZHlkbGxwcGdmY2h1Iiwicm9sZSI6ImFub24iLCJpYXQiOjE2NTY4NDA1NTEsImV4cCI6MTk3MjQxNjU1MX0.WUeCRiun0ExUxKIv5-CtjF6878H8u26t0JmCWx3_2-c"
|
|
31
30
|
|
|
32
31
|
|
|
@@ -173,7 +172,7 @@ def call_with_fallback(
|
|
|
173
172
|
client = connect_hub(fallback_env=fallback_env)
|
|
174
173
|
result = callable(**kwargs, client=client)
|
|
175
174
|
break
|
|
176
|
-
except
|
|
175
|
+
except Exception as e:
|
|
177
176
|
if fallback_env:
|
|
178
177
|
raise e
|
|
179
178
|
finally:
|
lamindb_setup/core/_hub_core.py
CHANGED
|
@@ -35,28 +35,36 @@ from ._hub_utils import (
|
|
|
35
35
|
)
|
|
36
36
|
from ._settings import settings
|
|
37
37
|
from ._settings_instance import InstanceSettings
|
|
38
|
-
from ._settings_storage import StorageSettings, base62
|
|
38
|
+
from ._settings_storage import StorageSettings, base62, instance_uid_from_uuid
|
|
39
39
|
from .hashing import hash_and_encode_as_b62
|
|
40
40
|
|
|
41
41
|
if TYPE_CHECKING:
|
|
42
42
|
from supabase import Client # type: ignore
|
|
43
43
|
|
|
44
44
|
|
|
45
|
-
def delete_storage_record(
|
|
45
|
+
def delete_storage_record(
|
|
46
|
+
storage_info: dict[str, str] | StorageSettings,
|
|
47
|
+
access_token: str | None = None,
|
|
48
|
+
) -> None:
|
|
49
|
+
if isinstance(storage_info, StorageSettings):
|
|
50
|
+
storage_info = {"id": storage_info._uuid.hex, "root": storage_info.root_as_str} # type: ignore
|
|
46
51
|
return call_with_fallback_auth(
|
|
47
|
-
_delete_storage_record,
|
|
52
|
+
_delete_storage_record, storage_info=storage_info, access_token=access_token
|
|
48
53
|
)
|
|
49
54
|
|
|
50
55
|
|
|
51
|
-
def _delete_storage_record(
|
|
56
|
+
def _delete_storage_record(storage_info: dict[str, str], client: Client) -> None:
|
|
57
|
+
storage_uuid = UUID(storage_info["id"])
|
|
52
58
|
if storage_uuid is None:
|
|
53
59
|
return None
|
|
54
60
|
response = client.table("storage").delete().eq("id", storage_uuid.hex).execute()
|
|
55
61
|
if response.data:
|
|
56
|
-
logger.important(
|
|
62
|
+
logger.important(
|
|
63
|
+
f"deleted storage record on hub {storage_uuid.hex} | {storage_info['root']}"
|
|
64
|
+
)
|
|
57
65
|
else:
|
|
58
66
|
raise PermissionError(
|
|
59
|
-
f"Deleting of storage
|
|
67
|
+
f"Deleting of storage {storage_uuid.hex} ({storage_info['root']}) was not successful. Probably, you"
|
|
60
68
|
" don't have sufficient permissions."
|
|
61
69
|
)
|
|
62
70
|
|
|
@@ -94,21 +102,21 @@ def _select_storage(
|
|
|
94
102
|
return False
|
|
95
103
|
else:
|
|
96
104
|
existing_storage = response.data[0]
|
|
97
|
-
if existing_storage["instance_id"] is
|
|
98
|
-
if
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
105
|
+
if existing_storage["instance_id"] is None:
|
|
106
|
+
# if there is no instance_id, the storage location should not be on the hub
|
|
107
|
+
# this can only occur if instance init fails halfway through and is not cleaned up
|
|
108
|
+
# we're patching the situation here
|
|
109
|
+
existing_storage["instance_id"] = (
|
|
110
|
+
ssettings._instance_id.hex
|
|
111
|
+
if ssettings._instance_id is not None
|
|
112
|
+
else None
|
|
113
|
+
)
|
|
114
|
+
if ssettings._instance_id is not None:
|
|
115
|
+
if UUID(existing_storage["instance_id"]) != ssettings._instance_id:
|
|
116
|
+
logger.debug(
|
|
117
|
+
f"referencing storage location {root}, which is managed by instance {existing_storage['instance_id']}"
|
|
118
|
+
)
|
|
119
|
+
ssettings._instance_id = UUID(existing_storage["instance_id"])
|
|
112
120
|
ssettings._uuid_ = UUID(existing_storage["id"])
|
|
113
121
|
if update_uid:
|
|
114
122
|
ssettings._uid = existing_storage["lnid"]
|
|
@@ -122,9 +130,7 @@ def _select_storage_or_parent(path: str, client: Client) -> dict | None:
|
|
|
122
130
|
if result["root"] is None:
|
|
123
131
|
return None
|
|
124
132
|
result["uid"] = result.pop("lnid")
|
|
125
|
-
result["instance_uid"] =
|
|
126
|
-
UUID(result.pop("instance_id")).hex
|
|
127
|
-
)[:12]
|
|
133
|
+
result["instance_uid"] = instance_uid_from_uuid(UUID(result.pop("instance_id")))
|
|
128
134
|
return result
|
|
129
135
|
|
|
130
136
|
|
|
@@ -144,7 +150,9 @@ def init_storage_hub(
|
|
|
144
150
|
auto_populate_instance: bool = True,
|
|
145
151
|
created_by: UUID | None = None,
|
|
146
152
|
access_token: str | None = None,
|
|
147
|
-
|
|
153
|
+
prevent_creation: bool = False,
|
|
154
|
+
) -> Literal["hub-record-retrieved", "hub-record-created", "hub-record-not-created"]:
|
|
155
|
+
"""Creates or retrieves an existing storage record from the hub."""
|
|
148
156
|
if settings.user.handle != "anonymous" or access_token is not None:
|
|
149
157
|
return call_with_fallback_auth(
|
|
150
158
|
_init_storage_hub,
|
|
@@ -152,6 +160,7 @@ def init_storage_hub(
|
|
|
152
160
|
auto_populate_instance=auto_populate_instance,
|
|
153
161
|
created_by=created_by,
|
|
154
162
|
access_token=access_token,
|
|
163
|
+
prevent_creation=prevent_creation,
|
|
155
164
|
)
|
|
156
165
|
else:
|
|
157
166
|
storage_exists = call_with_fallback(
|
|
@@ -160,7 +169,7 @@ def init_storage_hub(
|
|
|
160
169
|
if storage_exists:
|
|
161
170
|
return "hub-record-retrieved"
|
|
162
171
|
else:
|
|
163
|
-
|
|
172
|
+
return "hub-record-not-created"
|
|
164
173
|
|
|
165
174
|
|
|
166
175
|
def _init_storage_hub(
|
|
@@ -168,7 +177,8 @@ def _init_storage_hub(
|
|
|
168
177
|
ssettings: StorageSettings,
|
|
169
178
|
auto_populate_instance: bool,
|
|
170
179
|
created_by: UUID | None = None,
|
|
171
|
-
|
|
180
|
+
prevent_creation: bool = False,
|
|
181
|
+
) -> Literal["hub-record-retrieved", "hub-record-created", "hub-record-not-created"]:
|
|
172
182
|
from lamindb_setup import settings
|
|
173
183
|
|
|
174
184
|
created_by = settings.user._uuid if created_by is None else created_by
|
|
@@ -177,6 +187,8 @@ def _init_storage_hub(
|
|
|
177
187
|
root = ssettings.root_as_str
|
|
178
188
|
if _select_storage(ssettings, update_uid=True, client=client):
|
|
179
189
|
return "hub-record-retrieved"
|
|
190
|
+
if prevent_creation:
|
|
191
|
+
return "hub-record-not-created"
|
|
180
192
|
if ssettings.type_is_cloud:
|
|
181
193
|
id = uuid.uuid5(uuid.NAMESPACE_URL, root)
|
|
182
194
|
else:
|
|
@@ -272,17 +284,11 @@ def _delete_instance(
|
|
|
272
284
|
else:
|
|
273
285
|
access_token = None
|
|
274
286
|
root_path = create_path(root_string, access_token)
|
|
275
|
-
mark_storage_root(
|
|
276
|
-
root_path,
|
|
277
|
-
storage_record["lnid"], # type: ignore
|
|
278
|
-
) # address permission error
|
|
279
287
|
check_storage_is_empty(
|
|
280
288
|
root_path, account_for_sqlite_file=account_for_sqlite_file
|
|
281
289
|
)
|
|
282
|
-
# first delete the storage records because we will turn instance_id on
|
|
283
|
-
# storage into a FK soon
|
|
284
290
|
for storage_record in storage_records:
|
|
285
|
-
_delete_storage_record(
|
|
291
|
+
_delete_storage_record(storage_record, client) # type: ignore
|
|
286
292
|
_delete_instance_record(UUID(instance_with_storage["id"]), client)
|
|
287
293
|
return None
|
|
288
294
|
|
|
@@ -361,6 +367,27 @@ def _connect_instance_hub(
|
|
|
361
367
|
"get-instance-settings-v1",
|
|
362
368
|
invoke_options={"body": {"owner": owner, "name": name}},
|
|
363
369
|
)
|
|
370
|
+
# check instance renames
|
|
371
|
+
if response == b"{}":
|
|
372
|
+
data = (
|
|
373
|
+
client.table("instance_previous_name")
|
|
374
|
+
.select(
|
|
375
|
+
"instance!instance_previous_name_instance_id_17ac5d61_fk_instance_id(name, account!instance_account_id_28936e8f_fk_account_id(handle))"
|
|
376
|
+
)
|
|
377
|
+
.eq("instance.account.handle", owner)
|
|
378
|
+
.eq("previous_name", name)
|
|
379
|
+
.execute()
|
|
380
|
+
.data
|
|
381
|
+
)
|
|
382
|
+
if len(data) != 0 and (instance_data := data[0]["instance"]) is not None:
|
|
383
|
+
new_name = instance_data["name"] # the instance was renamed
|
|
384
|
+
logger.warning(
|
|
385
|
+
f"'{owner}/{name}' was renamed, please use '{owner}/{new_name}'"
|
|
386
|
+
)
|
|
387
|
+
response = client.functions.invoke(
|
|
388
|
+
"get-instance-settings-v1",
|
|
389
|
+
invoke_options={"body": {"owner": owner, "name": new_name}},
|
|
390
|
+
)
|
|
364
391
|
# no instance found, check why is that
|
|
365
392
|
if response == b"{}":
|
|
366
393
|
# try the via single requests, will take more time
|
|
@@ -375,7 +402,7 @@ def _connect_instance_hub(
|
|
|
375
402
|
if storage is None:
|
|
376
403
|
return "default-storage-does-not-exist-on-hub"
|
|
377
404
|
logger.warning(
|
|
378
|
-
"
|
|
405
|
+
"could not find instance via API, but found directly querying hub"
|
|
379
406
|
)
|
|
380
407
|
else:
|
|
381
408
|
instance = json.loads(response)
|
|
@@ -467,6 +494,12 @@ def access_db(
|
|
|
467
494
|
instance_id: UUID
|
|
468
495
|
instance_slug: str
|
|
469
496
|
instance_api_url: str | None
|
|
497
|
+
if (
|
|
498
|
+
"LAMIN_TEST_DB_TOKEN" in os.environ
|
|
499
|
+
and (env_db_token := os.environ["LAMIN_TEST_DB_TOKEN"]) != ""
|
|
500
|
+
):
|
|
501
|
+
return env_db_token
|
|
502
|
+
|
|
470
503
|
if isinstance(instance, InstanceSettings):
|
|
471
504
|
instance_id = instance._id
|
|
472
505
|
instance_slug = instance.slug
|
lamindb_setup/core/_hub_crud.py
CHANGED
|
@@ -68,9 +68,23 @@ def select_instance_by_name(
|
|
|
68
68
|
.execute()
|
|
69
69
|
.data
|
|
70
70
|
)
|
|
71
|
-
if len(data)
|
|
72
|
-
return
|
|
73
|
-
|
|
71
|
+
if len(data) != 0:
|
|
72
|
+
return data[0]
|
|
73
|
+
|
|
74
|
+
data = (
|
|
75
|
+
client.table("instance_previous_name")
|
|
76
|
+
.select(
|
|
77
|
+
"instance!instance_previous_name_instance_id_17ac5d61_fk_instance_id(*)"
|
|
78
|
+
)
|
|
79
|
+
.eq("instance.account_id", account_id)
|
|
80
|
+
.eq("previous_name", name)
|
|
81
|
+
.execute()
|
|
82
|
+
.data
|
|
83
|
+
)
|
|
84
|
+
if len(data) != 0:
|
|
85
|
+
return data[0]["instance"]
|
|
86
|
+
|
|
87
|
+
return None
|
|
74
88
|
|
|
75
89
|
|
|
76
90
|
def select_instance_by_id(
|
lamindb_setup/core/_settings.py
CHANGED
|
@@ -4,29 +4,32 @@ import os
|
|
|
4
4
|
import sys
|
|
5
5
|
from typing import TYPE_CHECKING
|
|
6
6
|
|
|
7
|
-
from appdirs import AppDirs
|
|
8
7
|
from lamin_utils import logger
|
|
8
|
+
from platformdirs import user_cache_dir
|
|
9
9
|
|
|
10
10
|
from ._settings_load import (
|
|
11
|
+
load_cache_path_from_settings,
|
|
11
12
|
load_instance_settings,
|
|
12
13
|
load_or_create_user_settings,
|
|
13
|
-
load_system_storage_settings,
|
|
14
14
|
)
|
|
15
|
-
from ._settings_store import
|
|
15
|
+
from ._settings_store import (
|
|
16
|
+
current_instance_settings_file,
|
|
17
|
+
settings_dir,
|
|
18
|
+
system_settings_dir,
|
|
19
|
+
)
|
|
16
20
|
from .upath import LocalPathClasses, UPath
|
|
17
21
|
|
|
18
22
|
if TYPE_CHECKING:
|
|
19
23
|
from pathlib import Path
|
|
20
24
|
|
|
21
25
|
from lamindb_setup.core import InstanceSettings, StorageSettings, UserSettings
|
|
22
|
-
|
|
23
|
-
from .types import UPathStr
|
|
26
|
+
from lamindb_setup.types import UPathStr
|
|
24
27
|
|
|
25
28
|
|
|
26
|
-
DEFAULT_CACHE_DIR = UPath(
|
|
29
|
+
DEFAULT_CACHE_DIR = UPath(user_cache_dir(appname="lamindb", appauthor="laminlabs"))
|
|
27
30
|
|
|
28
31
|
|
|
29
|
-
def _process_cache_path(cache_path: UPathStr | None):
|
|
32
|
+
def _process_cache_path(cache_path: UPathStr | None) -> UPath | None:
|
|
30
33
|
if cache_path is None or cache_path == "null":
|
|
31
34
|
return None
|
|
32
35
|
cache_dir = UPath(cache_path)
|
|
@@ -34,6 +37,8 @@ def _process_cache_path(cache_path: UPathStr | None):
|
|
|
34
37
|
raise ValueError("cache dir should be a local path.")
|
|
35
38
|
if cache_dir.exists() and not cache_dir.is_dir():
|
|
36
39
|
raise ValueError("cache dir should be a directory.")
|
|
40
|
+
if not cache_dir.is_absolute():
|
|
41
|
+
raise ValueError("A path to the cache dir should be absolute.")
|
|
37
42
|
return cache_dir
|
|
38
43
|
|
|
39
44
|
|
|
@@ -86,6 +91,17 @@ class SetupSettings:
|
|
|
86
91
|
else:
|
|
87
92
|
self._auto_connect_path.unlink(missing_ok=True)
|
|
88
93
|
|
|
94
|
+
@property
|
|
95
|
+
def is_connected(self) -> bool:
|
|
96
|
+
"""Determine whether the current instance is fully connected and ready to use.
|
|
97
|
+
|
|
98
|
+
If `True`, the current instance is connected, meaning that the db and other settings
|
|
99
|
+
are properly configured for use.
|
|
100
|
+
"""
|
|
101
|
+
from .django import IS_SETUP # always import to protect from assignment
|
|
102
|
+
|
|
103
|
+
return IS_SETUP
|
|
104
|
+
|
|
89
105
|
@property
|
|
90
106
|
def private_django_api(self) -> bool:
|
|
91
107
|
"""Turn internal Django API private to clean up the API (default `False`).
|
|
@@ -156,7 +172,7 @@ class SetupSettings:
|
|
|
156
172
|
if "LAMIN_CACHE_DIR" in os.environ:
|
|
157
173
|
cache_dir = UPath(os.environ["LAMIN_CACHE_DIR"])
|
|
158
174
|
elif self._cache_dir is None:
|
|
159
|
-
cache_path =
|
|
175
|
+
cache_path = load_cache_path_from_settings()
|
|
160
176
|
cache_dir = _process_cache_path(cache_path)
|
|
161
177
|
if cache_dir is None:
|
|
162
178
|
cache_dir = DEFAULT_CACHE_DIR
|
|
@@ -189,10 +205,12 @@ class SetupSettings:
|
|
|
189
205
|
# do not show current setting representation when building docs
|
|
190
206
|
if "sphinx" in sys.modules:
|
|
191
207
|
return object.__repr__(self)
|
|
192
|
-
repr = self.
|
|
193
|
-
repr += f"\nAuto-connect in Python: {self.auto_connect}\n"
|
|
208
|
+
repr = f"Auto-connect in Python: {self.auto_connect}\n"
|
|
194
209
|
repr += f"Private Django API: {self.private_django_api}\n"
|
|
195
210
|
repr += f"Cache directory: {self.cache_dir.as_posix()}\n"
|
|
211
|
+
repr += f"User settings directory: {settings_dir.as_posix()}\n"
|
|
212
|
+
repr += f"System settings directory: {system_settings_dir.as_posix()}\n"
|
|
213
|
+
repr += self.user.__repr__() + "\n"
|
|
196
214
|
if self._instance_exists:
|
|
197
215
|
repr += self.instance.__repr__()
|
|
198
216
|
else:
|
|
@@ -18,6 +18,7 @@ from ._settings_storage import (
|
|
|
18
18
|
STORAGE_UID_FILE_KEY,
|
|
19
19
|
StorageSettings,
|
|
20
20
|
init_storage,
|
|
21
|
+
instance_uid_from_uuid,
|
|
21
22
|
)
|
|
22
23
|
from ._settings_store import current_instance_settings_file, instance_settings_file
|
|
23
24
|
from .cloud_sqlite_locker import (
|
|
@@ -117,6 +118,8 @@ class InstanceSettings:
|
|
|
117
118
|
else:
|
|
118
119
|
db_print = value
|
|
119
120
|
representation += f"\n- {attr}: {db_print}"
|
|
121
|
+
elif attr == "modules":
|
|
122
|
+
representation += f"\n- {attr}: {value if value else '{}'}"
|
|
120
123
|
else:
|
|
121
124
|
representation += f"\n- {attr}: {value}"
|
|
122
125
|
return representation
|
|
@@ -165,7 +168,7 @@ class InstanceSettings:
|
|
|
165
168
|
f"local storage location '{root_path}' is corrupted, cannot find marker file with storage uid"
|
|
166
169
|
)
|
|
167
170
|
try:
|
|
168
|
-
uid = marker_path.read_text()
|
|
171
|
+
uid = marker_path.read_text().splitlines()[0]
|
|
169
172
|
except PermissionError:
|
|
170
173
|
logger.warning(
|
|
171
174
|
f"ignoring the following location because no permission to read it: {marker_path}"
|
|
@@ -250,7 +253,9 @@ class InstanceSettings:
|
|
|
250
253
|
return None
|
|
251
254
|
local_root = UPath(local_root)
|
|
252
255
|
assert isinstance(local_root, LocalPathClasses)
|
|
253
|
-
self._storage_local, _ = init_storage(
|
|
256
|
+
self._storage_local, _ = init_storage(
|
|
257
|
+
local_root, instance_id=self._id, instance_slug=self.slug, register_hub=True
|
|
258
|
+
) # type: ignore
|
|
254
259
|
register_storage_in_instance(self._storage_local) # type: ignore
|
|
255
260
|
logger.important(f"defaulting to local storage: {self._storage_local.root}")
|
|
256
261
|
|
|
@@ -275,9 +280,7 @@ class InstanceSettings:
|
|
|
275
280
|
@property
|
|
276
281
|
def uid(self) -> str:
|
|
277
282
|
"""The user-facing instance id."""
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
return hash_and_encode_as_b62(self._id.hex)[:12]
|
|
283
|
+
return instance_uid_from_uuid(self._id)
|
|
281
284
|
|
|
282
285
|
@property
|
|
283
286
|
def modules(self) -> set[str]:
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import os
|
|
4
|
+
from pathlib import Path
|
|
4
5
|
from typing import TYPE_CHECKING
|
|
5
6
|
from uuid import UUID, uuid4
|
|
6
7
|
|
|
@@ -8,6 +9,8 @@ from dotenv import dotenv_values
|
|
|
8
9
|
from lamin_utils import logger
|
|
9
10
|
from pydantic import ValidationError
|
|
10
11
|
|
|
12
|
+
from lamindb_setup.errors import SettingsEnvFileOutdated
|
|
13
|
+
|
|
11
14
|
from ._settings_instance import InstanceSettings
|
|
12
15
|
from ._settings_storage import StorageSettings
|
|
13
16
|
from ._settings_store import (
|
|
@@ -15,26 +18,32 @@ from ._settings_store import (
|
|
|
15
18
|
UserSettingsStore,
|
|
16
19
|
current_instance_settings_file,
|
|
17
20
|
current_user_settings_file,
|
|
18
|
-
|
|
21
|
+
platform_user_storage_settings_file,
|
|
22
|
+
system_settings_file,
|
|
19
23
|
)
|
|
20
24
|
from ._settings_user import UserSettings
|
|
21
25
|
|
|
22
|
-
if TYPE_CHECKING:
|
|
23
|
-
from pathlib import Path
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
class SettingsEnvFileOutdated(Exception):
|
|
27
|
-
pass
|
|
28
26
|
|
|
27
|
+
def load_cache_path_from_settings(storage_settings: Path | None = None) -> Path | None:
|
|
28
|
+
if storage_settings is None:
|
|
29
|
+
paltform_user_storage_settings = platform_user_storage_settings_file()
|
|
30
|
+
if paltform_user_storage_settings.exists():
|
|
31
|
+
cache_path = dotenv_values(paltform_user_storage_settings).get(
|
|
32
|
+
"lamindb_cache_path", None
|
|
33
|
+
)
|
|
34
|
+
else:
|
|
35
|
+
cache_path = None
|
|
29
36
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
37
|
+
if cache_path in {None, "null", ""}:
|
|
38
|
+
storage_settings = system_settings_file()
|
|
39
|
+
else:
|
|
40
|
+
return Path(cache_path)
|
|
33
41
|
|
|
34
|
-
if
|
|
35
|
-
|
|
42
|
+
if storage_settings.exists():
|
|
43
|
+
cache_path = dotenv_values(storage_settings).get("lamindb_cache_path", None)
|
|
44
|
+
return Path(cache_path) if cache_path not in {None, "null", ""} else None
|
|
36
45
|
else:
|
|
37
|
-
return
|
|
46
|
+
return None
|
|
38
47
|
|
|
39
48
|
|
|
40
49
|
def load_instance_settings(instance_settings_file: Path | None = None):
|
|
@@ -113,7 +122,7 @@ def setup_instance_from_store(store: InstanceSettingsStore) -> InstanceSettings:
|
|
|
113
122
|
git_repo=_null_to_value(store.git_repo),
|
|
114
123
|
keep_artifacts_local=store.keep_artifacts_local, # type: ignore
|
|
115
124
|
api_url=_null_to_value(store.api_url),
|
|
116
|
-
schema_id=None if store.schema_id
|
|
125
|
+
schema_id=None if store.schema_id in {None, "null"} else UUID(store.schema_id),
|
|
117
126
|
fine_grained_access=store.fine_grained_access,
|
|
118
127
|
db_permissions=_null_to_value(store.db_permissions),
|
|
119
128
|
)
|
|
@@ -8,14 +8,15 @@ from ._settings_store import (
|
|
|
8
8
|
InstanceSettingsStore,
|
|
9
9
|
UserSettingsStore,
|
|
10
10
|
current_user_settings_file,
|
|
11
|
-
|
|
11
|
+
platform_user_storage_settings_file,
|
|
12
12
|
user_settings_file_email,
|
|
13
13
|
user_settings_file_handle,
|
|
14
14
|
)
|
|
15
15
|
|
|
16
16
|
if TYPE_CHECKING:
|
|
17
|
+
from lamindb_setup.types import UPathStr
|
|
18
|
+
|
|
17
19
|
from ._settings_user import UserSettings
|
|
18
|
-
from .types import UPathStr
|
|
19
20
|
|
|
20
21
|
|
|
21
22
|
def save_user_settings(settings: UserSettings):
|
|
@@ -82,13 +83,13 @@ def save_instance_settings(settings: Any, settings_file: Path):
|
|
|
82
83
|
save_settings(settings, settings_file, type_hints, prefix)
|
|
83
84
|
|
|
84
85
|
|
|
85
|
-
def
|
|
86
|
+
def save_platform_user_storage_settings(
|
|
86
87
|
cache_path: UPathStr | None, settings_file: UPathStr | None = None
|
|
87
88
|
):
|
|
88
89
|
cache_path = "null" if cache_path is None else cache_path
|
|
89
90
|
if isinstance(cache_path, Path): # also True for UPath
|
|
90
91
|
cache_path = cache_path.as_posix()
|
|
91
92
|
if settings_file is None:
|
|
92
|
-
settings_file =
|
|
93
|
+
settings_file = platform_user_storage_settings_file()
|
|
93
94
|
with open(settings_file, "w") as f:
|
|
94
95
|
f.write(f"lamindb_cache_path={cache_path}")
|