lamindb_setup 1.18.2__py3-none-any.whl → 1.19.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_setup/__init__.py +4 -19
- lamindb_setup/_cache.py +87 -87
- lamindb_setup/_check.py +7 -7
- lamindb_setup/_check_setup.py +131 -131
- lamindb_setup/_connect_instance.py +443 -438
- lamindb_setup/_delete.py +155 -151
- lamindb_setup/_disconnect.py +38 -38
- lamindb_setup/_django.py +39 -39
- lamindb_setup/_entry_points.py +19 -19
- lamindb_setup/_init_instance.py +423 -429
- lamindb_setup/_migrate.py +331 -327
- lamindb_setup/_register_instance.py +32 -32
- lamindb_setup/_schema.py +27 -27
- lamindb_setup/_schema_metadata.py +451 -451
- lamindb_setup/_set_managed_storage.py +81 -80
- lamindb_setup/_setup_user.py +198 -198
- lamindb_setup/_silence_loggers.py +46 -46
- lamindb_setup/core/__init__.py +25 -34
- lamindb_setup/core/_aws_options.py +276 -266
- lamindb_setup/core/_aws_storage.py +57 -55
- lamindb_setup/core/_clone.py +50 -50
- lamindb_setup/core/_deprecated.py +62 -62
- lamindb_setup/core/_docs.py +14 -14
- lamindb_setup/core/_hub_client.py +288 -294
- lamindb_setup/core/_hub_core.py +0 -2
- lamindb_setup/core/_hub_crud.py +247 -247
- lamindb_setup/core/_hub_utils.py +100 -100
- lamindb_setup/core/_private_django_api.py +80 -80
- lamindb_setup/core/_settings.py +440 -434
- lamindb_setup/core/_settings_instance.py +32 -7
- lamindb_setup/core/_settings_load.py +162 -159
- lamindb_setup/core/_settings_save.py +108 -96
- lamindb_setup/core/_settings_storage.py +433 -433
- lamindb_setup/core/_settings_store.py +162 -92
- lamindb_setup/core/_settings_user.py +55 -55
- lamindb_setup/core/_setup_bionty_sources.py +44 -44
- lamindb_setup/core/cloud_sqlite_locker.py +240 -240
- lamindb_setup/core/django.py +414 -413
- lamindb_setup/core/exceptions.py +1 -1
- lamindb_setup/core/hashing.py +134 -134
- lamindb_setup/core/types.py +1 -1
- lamindb_setup/core/upath.py +1031 -1028
- lamindb_setup/errors.py +72 -70
- lamindb_setup/io.py +423 -416
- lamindb_setup/types.py +17 -17
- {lamindb_setup-1.18.2.dist-info → lamindb_setup-1.19.1.dist-info}/METADATA +4 -2
- lamindb_setup-1.19.1.dist-info/RECORD +51 -0
- {lamindb_setup-1.18.2.dist-info → lamindb_setup-1.19.1.dist-info}/WHEEL +1 -1
- {lamindb_setup-1.18.2.dist-info → lamindb_setup-1.19.1.dist-info/licenses}/LICENSE +201 -201
- lamindb_setup-1.18.2.dist-info/RECORD +0 -51
|
@@ -5,14 +5,8 @@ import shutil
|
|
|
5
5
|
from pathlib import Path
|
|
6
6
|
from typing import TYPE_CHECKING, Literal
|
|
7
7
|
|
|
8
|
-
from django.db import connection
|
|
9
|
-
from django.db.utils import ProgrammingError
|
|
10
8
|
from lamin_utils import logger
|
|
11
9
|
|
|
12
|
-
from ._deprecated import deprecated
|
|
13
|
-
from ._hub_client import call_with_fallback
|
|
14
|
-
from ._hub_crud import select_account_handle_name_by_lnid
|
|
15
|
-
from ._hub_utils import LaminDsn, LaminDsnModel
|
|
16
10
|
from ._settings_save import save_instance_settings
|
|
17
11
|
from ._settings_storage import (
|
|
18
12
|
LEGACY_STORAGE_UID_FILE_KEY,
|
|
@@ -85,6 +79,7 @@ class InstanceSettings:
|
|
|
85
79
|
_locker_user: UserSettings | None = None, # user to lock for if cloud sqlite,
|
|
86
80
|
_is_clone: bool = False,
|
|
87
81
|
):
|
|
82
|
+
# dynamic import to avoid importing pydantic at root
|
|
88
83
|
from ._hub_utils import validate_db_arg
|
|
89
84
|
|
|
90
85
|
self._id_: UUID = id
|
|
@@ -135,6 +130,9 @@ class InstanceSettings:
|
|
|
135
130
|
)
|
|
136
131
|
elif attr == "db":
|
|
137
132
|
if self.dialect != "sqlite":
|
|
133
|
+
# dynamic import to avoid importing pydantic at root
|
|
134
|
+
from ._hub_utils import LaminDsn, LaminDsnModel
|
|
135
|
+
|
|
138
136
|
model = LaminDsnModel(db=value)
|
|
139
137
|
db_print = LaminDsn.build(
|
|
140
138
|
scheme=model.db.scheme,
|
|
@@ -166,6 +164,7 @@ class InstanceSettings:
|
|
|
166
164
|
def _search_local_root(
|
|
167
165
|
self, local_root: str | None = None, mute_warning: bool = False
|
|
168
166
|
) -> StorageSettings | None:
|
|
167
|
+
from django.db.utils import ProgrammingError
|
|
169
168
|
from lamindb.models import Storage
|
|
170
169
|
|
|
171
170
|
if local_root is not None:
|
|
@@ -364,6 +363,28 @@ class InstanceSettings:
|
|
|
364
363
|
else:
|
|
365
364
|
return self.api_url.replace("/api", "")
|
|
366
365
|
|
|
366
|
+
@property
|
|
367
|
+
def is_read_only_connection(self) -> bool:
|
|
368
|
+
"""Whether the current connection to the database is read-only."""
|
|
369
|
+
# should we check for self._is_clone?
|
|
370
|
+
if self.dialect == "postgresql":
|
|
371
|
+
db_url = self.db
|
|
372
|
+
if "read" in db_url or "public" in db_url:
|
|
373
|
+
return True
|
|
374
|
+
# works only for the default instance
|
|
375
|
+
if self._db_permissions == "jwt":
|
|
376
|
+
from ._settings import settings
|
|
377
|
+
|
|
378
|
+
db_token = settings._get_db_token()
|
|
379
|
+
# should not happen
|
|
380
|
+
if db_token is None:
|
|
381
|
+
logger.warning("DB token is not set")
|
|
382
|
+
return False
|
|
383
|
+
# inits or refreshes the token if needed
|
|
384
|
+
db_token.token_query # noqa: B018
|
|
385
|
+
return db_token._type == "read-only"
|
|
386
|
+
return False
|
|
387
|
+
|
|
367
388
|
@property
|
|
368
389
|
def available_spaces(self) -> dict | None:
|
|
369
390
|
"""Available spaces with roles for instances fine-grained permissions.
|
|
@@ -375,6 +396,7 @@ class InstanceSettings:
|
|
|
375
396
|
if self._db_permissions != "jwt":
|
|
376
397
|
return None
|
|
377
398
|
|
|
399
|
+
from django.db import connection
|
|
378
400
|
from lamindb.models import Space
|
|
379
401
|
|
|
380
402
|
spaces: dict = {"admin": [], "write": [], "read": []}
|
|
@@ -452,6 +474,9 @@ class InstanceSettings:
|
|
|
452
474
|
sqlite_file.synchronize_to(cache_file, print_progress=True) # type: ignore
|
|
453
475
|
|
|
454
476
|
def _check_sqlite_lock(self):
|
|
477
|
+
from ._hub_client import call_with_fallback
|
|
478
|
+
from ._hub_crud import select_account_handle_name_by_lnid
|
|
479
|
+
|
|
455
480
|
if not self._cloud_sqlite_locker.has_lock:
|
|
456
481
|
locked_by = self._cloud_sqlite_locker._locked_by
|
|
457
482
|
lock_msg = "Cannot load the instance, it is locked by "
|
|
@@ -560,7 +585,7 @@ class InstanceSettings:
|
|
|
560
585
|
Will return `False` in case the user token can't find the instance.
|
|
561
586
|
"""
|
|
562
587
|
if self._is_on_hub is None:
|
|
563
|
-
from ._hub_client import call_with_fallback_auth
|
|
588
|
+
from ._hub_client import call_with_fallback, call_with_fallback_auth
|
|
564
589
|
from ._hub_crud import select_instance_by_id
|
|
565
590
|
from ._settings import settings
|
|
566
591
|
|
|
@@ -1,159 +1,162 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import os
|
|
4
|
-
from importlib.util import find_spec
|
|
5
|
-
from pathlib import Path
|
|
6
|
-
from typing import TYPE_CHECKING
|
|
7
|
-
from uuid import UUID, uuid4
|
|
8
|
-
|
|
9
|
-
from dotenv import dotenv_values
|
|
10
|
-
from lamin_utils import logger
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
from .
|
|
16
|
-
from .
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
paltform_user_storage_settings
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
cache_path
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
""
|
|
52
|
-
candidates
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
f"
|
|
80
|
-
"
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
settings
|
|
154
|
-
settings.
|
|
155
|
-
settings.
|
|
156
|
-
settings.
|
|
157
|
-
settings.
|
|
158
|
-
settings.
|
|
159
|
-
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
from importlib.util import find_spec
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import TYPE_CHECKING
|
|
7
|
+
from uuid import UUID, uuid4
|
|
8
|
+
|
|
9
|
+
from dotenv import dotenv_values
|
|
10
|
+
from lamin_utils import logger
|
|
11
|
+
|
|
12
|
+
from lamindb_setup.errors import CurrentInstanceNotConfigured, SettingsEnvFileOutdated
|
|
13
|
+
|
|
14
|
+
from ._settings_instance import InstanceSettings
|
|
15
|
+
from ._settings_storage import StorageSettings
|
|
16
|
+
from ._settings_store import (
|
|
17
|
+
InstanceSettingsStore,
|
|
18
|
+
UserSettingsStore,
|
|
19
|
+
current_instance_settings_file,
|
|
20
|
+
current_user_settings_file,
|
|
21
|
+
platform_user_storage_settings_file,
|
|
22
|
+
system_settings_file,
|
|
23
|
+
)
|
|
24
|
+
from ._settings_user import UserSettings
|
|
25
|
+
|
|
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
|
|
36
|
+
|
|
37
|
+
if cache_path in {None, "null", ""}:
|
|
38
|
+
storage_settings = system_settings_file()
|
|
39
|
+
else:
|
|
40
|
+
return Path(cache_path)
|
|
41
|
+
|
|
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
|
|
45
|
+
else:
|
|
46
|
+
return None
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def find_module_candidates():
|
|
50
|
+
"""Find all local packages that depend on lamindb."""
|
|
51
|
+
candidates = ["bionty", "pertdb"]
|
|
52
|
+
return [c for c in candidates if find_spec(c) is not None]
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def load_instance_settings(instance_settings_file: Path | None = None):
|
|
56
|
+
if instance_settings_file is None:
|
|
57
|
+
isettings_file = current_instance_settings_file()
|
|
58
|
+
if not isettings_file.exists():
|
|
59
|
+
isettings = InstanceSettings(
|
|
60
|
+
id=UUID("00000000-0000-0000-0000-000000000000"),
|
|
61
|
+
owner="none",
|
|
62
|
+
name="none",
|
|
63
|
+
storage=None,
|
|
64
|
+
modules=",".join(find_module_candidates()),
|
|
65
|
+
)
|
|
66
|
+
return isettings
|
|
67
|
+
else:
|
|
68
|
+
isettings_file = instance_settings_file
|
|
69
|
+
|
|
70
|
+
if not isettings_file.exists():
|
|
71
|
+
# this errors only if the file was explicitly provided
|
|
72
|
+
raise CurrentInstanceNotConfigured
|
|
73
|
+
try:
|
|
74
|
+
settings_store = InstanceSettingsStore.from_env_file(
|
|
75
|
+
isettings_file, "lamindb_instance_"
|
|
76
|
+
)
|
|
77
|
+
except (ValueError, KeyError, TypeError) as error:
|
|
78
|
+
raise SettingsEnvFileOutdated(
|
|
79
|
+
f"\n\n{error}\n\nYour instance settings file with\n\n{isettings_file.read_text()}\nis invalid"
|
|
80
|
+
f" (likely outdated), see validation error. Please delete {isettings_file} &"
|
|
81
|
+
" reload (remote) or re-initialize (local) the instance with the same name & storage location."
|
|
82
|
+
) from error
|
|
83
|
+
isettings = setup_instance_from_store(settings_store)
|
|
84
|
+
return isettings
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def load_or_create_user_settings(api_key: str | None = None) -> UserSettings:
|
|
88
|
+
"""Return current user settings.
|
|
89
|
+
|
|
90
|
+
Args:
|
|
91
|
+
api_key: if provided and there is no current user, perform login and return the user settings.
|
|
92
|
+
"""
|
|
93
|
+
current_user_settings = current_user_settings_file()
|
|
94
|
+
if not current_user_settings.exists():
|
|
95
|
+
if api_key is not None:
|
|
96
|
+
from lamindb_setup._setup_user import login
|
|
97
|
+
|
|
98
|
+
return login(api_key=api_key)
|
|
99
|
+
else:
|
|
100
|
+
logger.warning("using anonymous user (to identify, call: lamin login)")
|
|
101
|
+
usettings = UserSettings(handle="anonymous", uid="00000000")
|
|
102
|
+
from ._settings_save import save_user_settings
|
|
103
|
+
|
|
104
|
+
save_user_settings(usettings)
|
|
105
|
+
else:
|
|
106
|
+
usettings = load_user_settings(current_user_settings)
|
|
107
|
+
return usettings
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def load_user_settings(user_settings_file: Path):
|
|
111
|
+
try:
|
|
112
|
+
settings_store = UserSettingsStore.from_env_file(
|
|
113
|
+
user_settings_file, "lamin_user_"
|
|
114
|
+
)
|
|
115
|
+
except (ValueError, KeyError, TypeError) as error:
|
|
116
|
+
msg = (
|
|
117
|
+
"Your user settings file is invalid, please delete"
|
|
118
|
+
f" {user_settings_file} and log in again."
|
|
119
|
+
)
|
|
120
|
+
print(msg)
|
|
121
|
+
raise SettingsEnvFileOutdated(msg) from error
|
|
122
|
+
settings = setup_user_from_store(settings_store)
|
|
123
|
+
return settings
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def _null_to_value(field, value=None):
|
|
127
|
+
return value if field in (None, "null") else field
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def setup_instance_from_store(store: InstanceSettingsStore) -> InstanceSettings:
|
|
131
|
+
ssettings = StorageSettings(
|
|
132
|
+
root=store.storage_root,
|
|
133
|
+
region=_null_to_value(store.storage_region),
|
|
134
|
+
)
|
|
135
|
+
return InstanceSettings(
|
|
136
|
+
id=UUID(store.id),
|
|
137
|
+
owner=store.owner,
|
|
138
|
+
name=store.name,
|
|
139
|
+
storage=ssettings,
|
|
140
|
+
db=_null_to_value(store.db),
|
|
141
|
+
modules=_null_to_value(store.schema_str),
|
|
142
|
+
git_repo=_null_to_value(store.git_repo),
|
|
143
|
+
keep_artifacts_local=store.keep_artifacts_local, # type: ignore
|
|
144
|
+
api_url=_null_to_value(store.api_url),
|
|
145
|
+
schema_id=None if store.schema_id in {None, "null"} else UUID(store.schema_id),
|
|
146
|
+
fine_grained_access=store.fine_grained_access,
|
|
147
|
+
db_permissions=_null_to_value(store.db_permissions),
|
|
148
|
+
_is_clone=store.is_clone,
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def setup_user_from_store(store: UserSettingsStore) -> UserSettings:
|
|
153
|
+
settings = UserSettings()
|
|
154
|
+
settings.email = _null_to_value(store.email)
|
|
155
|
+
settings.password = _null_to_value(store.password)
|
|
156
|
+
settings.access_token = store.access_token
|
|
157
|
+
settings.api_key = _null_to_value(store.api_key)
|
|
158
|
+
settings.uid = store.uid
|
|
159
|
+
settings.handle = _null_to_value(store.handle, value="anonymous")
|
|
160
|
+
settings.name = _null_to_value(store.name)
|
|
161
|
+
settings._uuid = UUID(store.uuid) if store.uuid not in (None, "null") else None
|
|
162
|
+
return settings
|
|
@@ -1,96 +1,108 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from pathlib import Path
|
|
4
|
-
from typing import TYPE_CHECKING, Any, Optional, get_type_hints
|
|
5
|
-
from uuid import UUID
|
|
6
|
-
|
|
7
|
-
from ._settings_store import (
|
|
8
|
-
InstanceSettingsStore,
|
|
9
|
-
UserSettingsStore,
|
|
10
|
-
current_user_settings_file,
|
|
11
|
-
platform_user_storage_settings_file,
|
|
12
|
-
user_settings_file_email,
|
|
13
|
-
user_settings_file_handle,
|
|
14
|
-
)
|
|
15
|
-
|
|
16
|
-
if TYPE_CHECKING:
|
|
17
|
-
from lamindb_setup.types import UPathStr
|
|
18
|
-
|
|
19
|
-
from ._settings_user import UserSettings
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
def save_user_settings(settings: UserSettings):
|
|
23
|
-
type_hints = get_type_hints(UserSettingsStore)
|
|
24
|
-
prefix = "lamin_user_"
|
|
25
|
-
save_settings(settings, current_user_settings_file(), type_hints, prefix)
|
|
26
|
-
if settings.email is not None:
|
|
27
|
-
save_settings(
|
|
28
|
-
settings, user_settings_file_email(settings.email), type_hints, prefix
|
|
29
|
-
)
|
|
30
|
-
if settings.handle is not None and settings.handle != "anonymous":
|
|
31
|
-
save_settings(
|
|
32
|
-
settings, user_settings_file_handle(settings.handle), type_hints, prefix
|
|
33
|
-
)
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
def
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
)
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import TYPE_CHECKING, Any, Optional, get_args, get_type_hints
|
|
5
|
+
from uuid import UUID
|
|
6
|
+
|
|
7
|
+
from ._settings_store import (
|
|
8
|
+
InstanceSettingsStore,
|
|
9
|
+
UserSettingsStore,
|
|
10
|
+
current_user_settings_file,
|
|
11
|
+
platform_user_storage_settings_file,
|
|
12
|
+
user_settings_file_email,
|
|
13
|
+
user_settings_file_handle,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
if TYPE_CHECKING:
|
|
17
|
+
from lamindb_setup.types import UPathStr
|
|
18
|
+
|
|
19
|
+
from ._settings_user import UserSettings
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def save_user_settings(settings: UserSettings):
|
|
23
|
+
type_hints = get_type_hints(UserSettingsStore)
|
|
24
|
+
prefix = "lamin_user_"
|
|
25
|
+
save_settings(settings, current_user_settings_file(), type_hints, prefix)
|
|
26
|
+
if settings.email is not None:
|
|
27
|
+
save_settings(
|
|
28
|
+
settings, user_settings_file_email(settings.email), type_hints, prefix
|
|
29
|
+
)
|
|
30
|
+
if settings.handle is not None and settings.handle != "anonymous":
|
|
31
|
+
save_settings(
|
|
32
|
+
settings, user_settings_file_handle(settings.handle), type_hints, prefix
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _coerce_type_for_write(type_: Any) -> Any:
|
|
37
|
+
"""Resolve union types to the non-None part for coercion when value is not None."""
|
|
38
|
+
if type_ in (str, bool):
|
|
39
|
+
return type_
|
|
40
|
+
if type_ == Optional[str]: # noqa: UP045
|
|
41
|
+
return str
|
|
42
|
+
if type_ == Optional[bool]: # noqa: UP045
|
|
43
|
+
return bool
|
|
44
|
+
args = get_args(type_) or ()
|
|
45
|
+
if type(None) in args:
|
|
46
|
+
non_none = next((a for a in args if a is not type(None)), type_)
|
|
47
|
+
return non_none if non_none in (str, bool) else type_
|
|
48
|
+
return type_
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def save_settings(
|
|
52
|
+
settings: Any,
|
|
53
|
+
settings_file: Path,
|
|
54
|
+
type_hints: dict[str, Any],
|
|
55
|
+
prefix: str,
|
|
56
|
+
):
|
|
57
|
+
with open(settings_file, "w") as f:
|
|
58
|
+
for store_key, type_ in type_hints.items():
|
|
59
|
+
type_ = _coerce_type_for_write(type_)
|
|
60
|
+
if "__" not in store_key:
|
|
61
|
+
if store_key == "model_config":
|
|
62
|
+
continue
|
|
63
|
+
if store_key == "storage_root":
|
|
64
|
+
value = settings.storage.root_as_str
|
|
65
|
+
elif store_key == "storage_region":
|
|
66
|
+
value = settings.storage.region
|
|
67
|
+
else:
|
|
68
|
+
if store_key in {
|
|
69
|
+
"db",
|
|
70
|
+
"schema_str",
|
|
71
|
+
"name_",
|
|
72
|
+
"uuid",
|
|
73
|
+
"id",
|
|
74
|
+
"api_url",
|
|
75
|
+
"schema_id",
|
|
76
|
+
"fine_grained_access",
|
|
77
|
+
"db_permissions",
|
|
78
|
+
"is_clone",
|
|
79
|
+
}:
|
|
80
|
+
settings_key = f"_{store_key.rstrip('_')}"
|
|
81
|
+
else:
|
|
82
|
+
settings_key = store_key
|
|
83
|
+
value = getattr(settings, settings_key, None)
|
|
84
|
+
if value is None:
|
|
85
|
+
value = "null"
|
|
86
|
+
elif isinstance(value, UUID):
|
|
87
|
+
value = value.hex
|
|
88
|
+
else:
|
|
89
|
+
value = type_(value)
|
|
90
|
+
f.write(f"{prefix}{store_key}={value}\n")
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def save_instance_settings(settings: Any, settings_file: Path):
|
|
94
|
+
type_hints = get_type_hints(InstanceSettingsStore)
|
|
95
|
+
prefix = "lamindb_instance_"
|
|
96
|
+
save_settings(settings, settings_file, type_hints, prefix)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def save_platform_user_storage_settings(
|
|
100
|
+
cache_path: UPathStr | None, settings_file: UPathStr | None = None
|
|
101
|
+
):
|
|
102
|
+
cache_path = "null" if cache_path is None else cache_path
|
|
103
|
+
if isinstance(cache_path, Path): # also True for UPath
|
|
104
|
+
cache_path = cache_path.as_posix()
|
|
105
|
+
if settings_file is None:
|
|
106
|
+
settings_file = platform_user_storage_settings_file()
|
|
107
|
+
with open(settings_file, "w") as f:
|
|
108
|
+
f.write(f"lamindb_cache_path={cache_path}")
|