lamindb_setup 0.70.0__py2.py3-none-any.whl → 0.71.0__py2.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 +15 -15
- lamindb_setup/_add_remote_storage.py +22 -33
- lamindb_setup/_cache.py +4 -1
- lamindb_setup/_check.py +3 -0
- lamindb_setup/_check_setup.py +13 -7
- lamindb_setup/_close.py +2 -0
- lamindb_setup/_connect_instance.py +33 -26
- lamindb_setup/_delete.py +52 -19
- lamindb_setup/_django.py +4 -1
- lamindb_setup/_exportdb.py +4 -2
- lamindb_setup/_importdb.py +5 -1
- lamindb_setup/_init_instance.py +57 -45
- lamindb_setup/_migrate.py +16 -13
- lamindb_setup/_register_instance.py +10 -3
- lamindb_setup/_schema.py +6 -3
- lamindb_setup/_setup_user.py +7 -7
- lamindb_setup/_silence_loggers.py +4 -2
- lamindb_setup/core/__init__.py +4 -3
- lamindb_setup/core/_aws_storage.py +3 -0
- lamindb_setup/core/_deprecated.py +2 -7
- lamindb_setup/core/_docs.py +2 -0
- lamindb_setup/core/_hub_client.py +12 -10
- lamindb_setup/core/_hub_core.py +198 -88
- lamindb_setup/core/_hub_crud.py +15 -11
- lamindb_setup/core/_hub_utils.py +11 -8
- lamindb_setup/core/_settings.py +23 -26
- lamindb_setup/core/_settings_instance.py +149 -81
- lamindb_setup/core/_settings_load.py +12 -7
- lamindb_setup/core/_settings_save.py +11 -8
- lamindb_setup/core/_settings_storage.py +83 -42
- lamindb_setup/core/_settings_store.py +3 -2
- lamindb_setup/core/_settings_user.py +10 -6
- lamindb_setup/core/_setup_bionty_sources.py +9 -2
- lamindb_setup/core/cloud_sqlite_locker.py +13 -10
- lamindb_setup/core/django.py +3 -1
- lamindb_setup/core/exceptions.py +4 -2
- lamindb_setup/core/hashing.py +15 -5
- lamindb_setup/core/types.py +5 -2
- lamindb_setup/core/upath.py +181 -87
- {lamindb_setup-0.70.0.dist-info → lamindb_setup-0.71.0.dist-info}/METADATA +6 -4
- lamindb_setup-0.71.0.dist-info/RECORD +43 -0
- lamindb_setup-0.70.0.dist-info/RECORD +0 -43
- {lamindb_setup-0.70.0.dist-info → lamindb_setup-0.71.0.dist-info}/LICENSE +0 -0
- {lamindb_setup-0.70.0.dist-info → lamindb_setup-0.71.0.dist-info}/WHEEL +0 -0
lamindb_setup/core/_hub_core.py
CHANGED
|
@@ -1,35 +1,41 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
1
4
|
import os
|
|
2
|
-
from typing import Optional, Tuple, Union, Dict
|
|
3
5
|
import uuid
|
|
4
|
-
from postgrest.exceptions import APIError
|
|
5
|
-
from uuid import UUID
|
|
6
|
-
from lamin_utils import logger
|
|
7
|
-
from supabase import Client
|
|
8
|
-
import lamindb_setup
|
|
9
|
-
import json
|
|
10
6
|
from importlib import metadata
|
|
11
|
-
from
|
|
12
|
-
from
|
|
7
|
+
from typing import TYPE_CHECKING
|
|
8
|
+
from uuid import UUID
|
|
13
9
|
|
|
10
|
+
from lamin_utils import logger
|
|
11
|
+
from postgrest.exceptions import APIError
|
|
14
12
|
|
|
15
13
|
from ._hub_client import (
|
|
16
|
-
connect_hub,
|
|
17
|
-
call_with_fallback_auth,
|
|
18
14
|
call_with_fallback,
|
|
15
|
+
call_with_fallback_auth,
|
|
16
|
+
connect_hub,
|
|
19
17
|
)
|
|
20
18
|
from ._hub_crud import (
|
|
21
|
-
|
|
22
|
-
select_instance_by_id_with_storage,
|
|
19
|
+
_delete_instance_record,
|
|
23
20
|
select_account_by_handle,
|
|
24
21
|
select_db_user_by_instance,
|
|
22
|
+
select_instance_by_id_with_storage,
|
|
25
23
|
select_instance_by_name,
|
|
24
|
+
select_instance_by_owner_name,
|
|
26
25
|
select_storage,
|
|
27
|
-
_delete_instance_record,
|
|
28
26
|
)
|
|
27
|
+
from ._hub_crud import update_instance as _update_instance_record
|
|
29
28
|
from ._hub_utils import (
|
|
30
29
|
LaminDsn,
|
|
31
30
|
LaminDsnModel,
|
|
32
31
|
)
|
|
32
|
+
from ._settings import settings
|
|
33
|
+
from ._settings_storage import StorageSettings, base62
|
|
34
|
+
|
|
35
|
+
if TYPE_CHECKING:
|
|
36
|
+
from supabase import Client # type: ignore
|
|
37
|
+
|
|
38
|
+
from ._settings_instance import InstanceSettings
|
|
33
39
|
|
|
34
40
|
|
|
35
41
|
def delete_storage_record(
|
|
@@ -44,88 +50,187 @@ def delete_storage_record(
|
|
|
44
50
|
def _delete_storage_record(storage_uuid: UUID, client: Client) -> None:
|
|
45
51
|
if storage_uuid is None:
|
|
46
52
|
return None
|
|
47
|
-
|
|
48
|
-
|
|
53
|
+
response = client.table("storage").delete().eq("id", storage_uuid.hex).execute()
|
|
54
|
+
if response.data:
|
|
55
|
+
logger.important(f"deleted storage record on hub {storage_uuid.hex}")
|
|
49
56
|
|
|
50
57
|
|
|
51
|
-
def update_instance_record(instance_uuid: UUID, fields:
|
|
52
|
-
|
|
58
|
+
def update_instance_record(instance_uuid: UUID, fields: dict) -> None:
|
|
59
|
+
return call_with_fallback_auth(
|
|
60
|
+
_update_instance_record, instance_id=instance_uuid.hex, instance_fields=fields
|
|
61
|
+
)
|
|
62
|
+
|
|
53
63
|
|
|
64
|
+
def get_storage_records_for_instance(
|
|
65
|
+
instance_id: UUID,
|
|
66
|
+
) -> list[dict[str, str | int]]:
|
|
54
67
|
return call_with_fallback_auth(
|
|
55
|
-
|
|
68
|
+
_get_storage_records_for_instance,
|
|
69
|
+
instance_id=instance_id,
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def _get_storage_records_for_instance(
|
|
74
|
+
instance_id: UUID, client: Client
|
|
75
|
+
) -> list[dict[str, str | int]]:
|
|
76
|
+
response = (
|
|
77
|
+
client.table("storage").select("*").eq("instance_id", instance_id.hex).execute()
|
|
56
78
|
)
|
|
79
|
+
return response.data
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def _select_storage(
|
|
83
|
+
ssettings: StorageSettings, update_uid: bool, client: Client
|
|
84
|
+
) -> bool:
|
|
85
|
+
root = ssettings.root_as_str
|
|
86
|
+
response = client.table("storage").select("*").eq("root", root).execute()
|
|
87
|
+
if not response.data:
|
|
88
|
+
return False
|
|
89
|
+
else:
|
|
90
|
+
existing_storage = response.data[0]
|
|
91
|
+
if ssettings._instance_id is not None:
|
|
92
|
+
# consider storage settings that are meant to be managed by an instance
|
|
93
|
+
if UUID(existing_storage["instance_id"]) != ssettings._instance_id:
|
|
94
|
+
# everything is alright if the instance_id matches
|
|
95
|
+
# we're probably just switching storage locations
|
|
96
|
+
# below can be turned into a warning and then delegate the error
|
|
97
|
+
# to a unique constraint violation below
|
|
98
|
+
raise ValueError(
|
|
99
|
+
f"Storage root {root} is already managed by instance {existing_storage['instance_id']}."
|
|
100
|
+
)
|
|
101
|
+
else:
|
|
102
|
+
# if the request is agnostic of the instance, that's alright,
|
|
103
|
+
# we'll update the instance_id with what's stored in the hub
|
|
104
|
+
ssettings._instance_id = UUID(existing_storage["instance_id"])
|
|
105
|
+
ssettings._uuid_ = UUID(existing_storage["id"])
|
|
106
|
+
if update_uid:
|
|
107
|
+
ssettings._uid = existing_storage["lnid"]
|
|
108
|
+
else:
|
|
109
|
+
assert ssettings._uid == existing_storage["lnid"]
|
|
110
|
+
return True
|
|
57
111
|
|
|
58
112
|
|
|
59
113
|
def init_storage(
|
|
60
114
|
ssettings: StorageSettings,
|
|
61
|
-
) ->
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
115
|
+
) -> None:
|
|
116
|
+
if settings.user.handle != "anonymous":
|
|
117
|
+
return call_with_fallback_auth(
|
|
118
|
+
_init_storage,
|
|
119
|
+
ssettings=ssettings,
|
|
120
|
+
)
|
|
121
|
+
else:
|
|
122
|
+
storage_exists = call_with_fallback(
|
|
123
|
+
_select_storage, ssettings=ssettings, update_uid=True
|
|
124
|
+
)
|
|
125
|
+
if storage_exists:
|
|
126
|
+
return None
|
|
127
|
+
else:
|
|
128
|
+
raise ValueError("Log in to create a storage location on the hub.")
|
|
66
129
|
|
|
67
130
|
|
|
68
|
-
def _init_storage(ssettings: StorageSettings, client: Client) ->
|
|
131
|
+
def _init_storage(ssettings: StorageSettings, client: Client) -> None:
|
|
69
132
|
from lamindb_setup import settings
|
|
70
133
|
|
|
71
134
|
# storage roots are always stored without the trailing slash in the SQL
|
|
72
135
|
# database
|
|
73
136
|
root = ssettings.root_as_str
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
id=
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
137
|
+
if _select_storage(ssettings, update_uid=True, client=client):
|
|
138
|
+
return None
|
|
139
|
+
if ssettings.type_is_cloud:
|
|
140
|
+
id = uuid.uuid5(uuid.NAMESPACE_URL, root)
|
|
141
|
+
else:
|
|
142
|
+
id = uuid.uuid4()
|
|
143
|
+
if ssettings._instance_id is None:
|
|
144
|
+
logger.warning(
|
|
145
|
+
f"will manage storage location {ssettings.root_as_str} with instance {settings.instance.slug}"
|
|
146
|
+
)
|
|
147
|
+
ssettings._instance_id = settings.instance._id
|
|
148
|
+
fields = {
|
|
149
|
+
"id": id.hex,
|
|
150
|
+
"lnid": ssettings.uid,
|
|
151
|
+
"created_by": settings.user._uuid.hex, # type: ignore
|
|
152
|
+
"root": root,
|
|
153
|
+
"region": ssettings.region,
|
|
154
|
+
"type": ssettings.type,
|
|
155
|
+
"instance_id": ssettings._instance_id.hex,
|
|
156
|
+
# the empty string is important as we want the user flow to be through LaminHub
|
|
157
|
+
# if this errors with unique constraint error, the user has to update
|
|
158
|
+
# the description in LaminHub
|
|
159
|
+
"description": "",
|
|
160
|
+
}
|
|
161
|
+
# TODO: add error message for violated unique constraint
|
|
162
|
+
# on root & description
|
|
88
163
|
client.table("storage").upsert(fields).execute()
|
|
89
|
-
|
|
164
|
+
ssettings._uuid_ = id
|
|
165
|
+
return None
|
|
90
166
|
|
|
91
167
|
|
|
92
|
-
def delete_instance(identifier:
|
|
168
|
+
def delete_instance(identifier: UUID | str, require_empty: bool = True) -> str | None:
|
|
169
|
+
return call_with_fallback_auth(
|
|
170
|
+
_delete_instance, identifier=identifier, require_empty=require_empty
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def _delete_instance(
|
|
175
|
+
identifier: UUID | str, require_empty: bool, client: Client
|
|
176
|
+
) -> str | None:
|
|
93
177
|
"""Fully delete an instance in the hub.
|
|
94
178
|
|
|
95
179
|
This function deletes the relevant instance and storage records in the hub,
|
|
96
180
|
conditional on the emptiness of the storage location.
|
|
97
181
|
"""
|
|
98
|
-
from .upath import check_storage_is_empty, create_path
|
|
99
182
|
from ._settings_storage import mark_storage_root
|
|
183
|
+
from .upath import check_storage_is_empty, create_path
|
|
100
184
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
185
|
+
# the "/" check is for backward compatibility with the old identifier format
|
|
186
|
+
if isinstance(identifier, UUID) or "/" not in identifier:
|
|
187
|
+
if isinstance(identifier, UUID):
|
|
188
|
+
instance_id_str = identifier.hex
|
|
189
|
+
else:
|
|
190
|
+
instance_id_str = identifier
|
|
191
|
+
instance_with_storage = select_instance_by_id_with_storage(
|
|
192
|
+
instance_id=instance_id_str, client=client
|
|
105
193
|
)
|
|
106
194
|
else:
|
|
107
195
|
owner, name = identifier.split("/")
|
|
108
|
-
instance_with_storage =
|
|
109
|
-
|
|
110
|
-
owner=owner,
|
|
111
|
-
name=name,
|
|
196
|
+
instance_with_storage = select_instance_by_owner_name(
|
|
197
|
+
owner=owner, name=name, client=client
|
|
112
198
|
)
|
|
113
199
|
|
|
114
200
|
if instance_with_storage is None:
|
|
115
|
-
logger.
|
|
116
|
-
return
|
|
201
|
+
logger.important("not deleting instance from hub as instance not found there")
|
|
202
|
+
return "instance-not-found"
|
|
117
203
|
|
|
204
|
+
storage_records = _get_storage_records_for_instance(
|
|
205
|
+
UUID(instance_with_storage["id"]),
|
|
206
|
+
client,
|
|
207
|
+
)
|
|
118
208
|
if require_empty:
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
209
|
+
for storage_record in storage_records:
|
|
210
|
+
account_for_sqlite_file = (
|
|
211
|
+
instance_with_storage["db_scheme"] is None
|
|
212
|
+
and instance_with_storage["storage"]["root"] == storage_record["root"]
|
|
213
|
+
)
|
|
214
|
+
root_string = storage_record["root"]
|
|
215
|
+
# gate storage and instance deletion on empty storage location for
|
|
216
|
+
if client.auth.get_session() is not None:
|
|
217
|
+
access_token = client.auth.get_session().access_token
|
|
218
|
+
else:
|
|
219
|
+
access_token = None
|
|
220
|
+
root_path = create_path(root_string, access_token)
|
|
221
|
+
mark_storage_root(
|
|
222
|
+
root_path,
|
|
223
|
+
storage_record["lnid"], # type: ignore
|
|
224
|
+
) # address permission error
|
|
225
|
+
check_storage_is_empty(
|
|
226
|
+
root_path, account_for_sqlite_file=account_for_sqlite_file
|
|
227
|
+
)
|
|
228
|
+
_update_instance_record(instance_with_storage["id"], {"storage_id": None}, client)
|
|
229
|
+
# first delete the storage records because we will turn instance_id on
|
|
230
|
+
# storage into a FK soon
|
|
231
|
+
for storage_record in storage_records:
|
|
232
|
+
_delete_storage_record(UUID(storage_record["id"]), client) # type: ignore
|
|
233
|
+
_delete_instance_record(UUID(instance_with_storage["id"]), client)
|
|
129
234
|
return None
|
|
130
235
|
|
|
131
236
|
|
|
@@ -149,25 +254,25 @@ def _init_instance(isettings: InstanceSettings, client: Client) -> None:
|
|
|
149
254
|
lamindb_version = metadata.version("lamindb")
|
|
150
255
|
except metadata.PackageNotFoundError:
|
|
151
256
|
lamindb_version = None
|
|
152
|
-
fields =
|
|
153
|
-
id
|
|
154
|
-
account_id
|
|
155
|
-
name
|
|
156
|
-
storage_id
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
257
|
+
fields = {
|
|
258
|
+
"id": isettings._id.hex,
|
|
259
|
+
"account_id": settings.user._uuid.hex, # type: ignore
|
|
260
|
+
"name": isettings.name,
|
|
261
|
+
"storage_id": isettings.storage._uuid.hex, # type: ignore
|
|
262
|
+
"lnid": isettings.uid,
|
|
263
|
+
"schema_str": isettings._schema_str,
|
|
264
|
+
"lamindb_version": lamindb_version,
|
|
265
|
+
"public": False,
|
|
266
|
+
}
|
|
161
267
|
if isettings.dialect != "sqlite":
|
|
162
268
|
db_dsn = LaminDsnModel(db=isettings.db)
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
)
|
|
269
|
+
db_fields = {
|
|
270
|
+
"db_scheme": db_dsn.db.scheme,
|
|
271
|
+
"db_host": db_dsn.db.host,
|
|
272
|
+
"db_port": db_dsn.db.port,
|
|
273
|
+
"db_database": db_dsn.db.database,
|
|
274
|
+
}
|
|
275
|
+
fields.update(db_fields)
|
|
171
276
|
# I'd like the following to be an upsert, but this seems to violate RLS
|
|
172
277
|
# Similarly, if we don't specify `returning="minimal"`, we'll violate RLS
|
|
173
278
|
# we could make this idempotent by catching an error, but this seems dangerous
|
|
@@ -177,6 +282,9 @@ def _init_instance(isettings: InstanceSettings, client: Client) -> None:
|
|
|
177
282
|
except APIError as e:
|
|
178
283
|
logger.warning("instance likely already exists")
|
|
179
284
|
raise e
|
|
285
|
+
client.table("storage").update(
|
|
286
|
+
{"instance_id": isettings._id.hex, "is_default": True}
|
|
287
|
+
).eq("id", isettings.storage._uuid.hex).execute() # type: ignore
|
|
180
288
|
logger.save(f"browse to: https://lamin.ai/{isettings.owner}/{isettings.name}")
|
|
181
289
|
|
|
182
290
|
|
|
@@ -184,7 +292,7 @@ def connect_instance(
|
|
|
184
292
|
*,
|
|
185
293
|
owner: str, # account_handle
|
|
186
294
|
name: str, # instance_name
|
|
187
|
-
) ->
|
|
295
|
+
) -> tuple[dict, dict] | str:
|
|
188
296
|
from ._settings import settings
|
|
189
297
|
|
|
190
298
|
if settings.user.handle != "anonymous":
|
|
@@ -198,7 +306,7 @@ def _connect_instance(
|
|
|
198
306
|
owner: str, # account_handle
|
|
199
307
|
name: str, # instance_name
|
|
200
308
|
client: Client,
|
|
201
|
-
) ->
|
|
309
|
+
) -> tuple[dict, dict] | str:
|
|
202
310
|
instance_account_storage = select_instance_by_owner_name(owner, name, client)
|
|
203
311
|
if instance_account_storage is None:
|
|
204
312
|
# try the via single requests, will take more time
|
|
@@ -207,7 +315,7 @@ def _connect_instance(
|
|
|
207
315
|
return "account-not-exists"
|
|
208
316
|
instance = select_instance_by_name(account["id"], name, client)
|
|
209
317
|
if instance is None:
|
|
210
|
-
return "instance-not-
|
|
318
|
+
return "instance-not-found"
|
|
211
319
|
# get default storage
|
|
212
320
|
storage = select_storage(instance["storage_id"], client)
|
|
213
321
|
if storage is None:
|
|
@@ -238,7 +346,7 @@ def _connect_instance(
|
|
|
238
346
|
return instance, storage
|
|
239
347
|
|
|
240
348
|
|
|
241
|
-
def access_aws(storage_root: str, access_token:
|
|
349
|
+
def access_aws(storage_root: str, access_token: str | None = None) -> dict[str, str]:
|
|
242
350
|
from ._settings import settings
|
|
243
351
|
|
|
244
352
|
if settings.user.handle != "anonymous" or access_token is not None:
|
|
@@ -250,7 +358,9 @@ def access_aws(storage_root: str, access_token: Optional[str] = None) -> Dict[st
|
|
|
250
358
|
raise RuntimeError("Can only get access to AWS if authenticated.")
|
|
251
359
|
|
|
252
360
|
|
|
253
|
-
def _access_aws(*, storage_root: str, client: Client) ->
|
|
361
|
+
def _access_aws(*, storage_root: str, client: Client) -> dict[str, str]:
|
|
362
|
+
import lamindb_setup
|
|
363
|
+
|
|
254
364
|
response = client.functions.invoke(
|
|
255
365
|
"access-aws",
|
|
256
366
|
invoke_options={"body": {"storage_root": storage_root}},
|
|
@@ -276,7 +386,7 @@ def get_lamin_site_base_url():
|
|
|
276
386
|
return "https://lamin.ai"
|
|
277
387
|
|
|
278
388
|
|
|
279
|
-
def sign_up_local_hub(email) ->
|
|
389
|
+
def sign_up_local_hub(email) -> str | tuple[str, str, str]:
|
|
280
390
|
# raises gotrue.errors.AuthApiError: User already registered
|
|
281
391
|
password = base62(40) # generate new password
|
|
282
392
|
sign_up_kwargs = {"email": email, "password": password}
|
|
@@ -290,7 +400,7 @@ def sign_up_local_hub(email) -> Union[str, Tuple[str, str, str]]:
|
|
|
290
400
|
)
|
|
291
401
|
|
|
292
402
|
|
|
293
|
-
def _sign_in_hub(email: str, password: str, handle:
|
|
403
|
+
def _sign_in_hub(email: str, password: str, handle: str | None, client: Client):
|
|
294
404
|
auth = client.auth.sign_in_with_password(
|
|
295
405
|
{
|
|
296
406
|
"email": email,
|
|
@@ -320,8 +430,8 @@ def _sign_in_hub(email: str, password: str, handle: Optional[str], client: Clien
|
|
|
320
430
|
|
|
321
431
|
|
|
322
432
|
def sign_in_hub(
|
|
323
|
-
email: str, password: str, handle:
|
|
324
|
-
) ->
|
|
433
|
+
email: str, password: str, handle: str | None = None
|
|
434
|
+
) -> Exception | tuple[UUID, str, str, str, str]:
|
|
325
435
|
try:
|
|
326
436
|
result = call_with_fallback(
|
|
327
437
|
_sign_in_hub, email=email, password=password, handle=handle
|
lamindb_setup/core/_hub_crud.py
CHANGED
|
@@ -1,20 +1,23 @@
|
|
|
1
|
-
from
|
|
2
|
-
|
|
3
|
-
from
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
4
|
from uuid import UUID, uuid4
|
|
5
5
|
|
|
6
|
+
from lamin_utils import logger
|
|
7
|
+
from supabase.client import Client # noqa
|
|
8
|
+
|
|
6
9
|
|
|
7
10
|
def select_instance_by_owner_name(
|
|
8
11
|
owner: str,
|
|
9
12
|
name: str,
|
|
10
13
|
client: Client,
|
|
11
|
-
) ->
|
|
14
|
+
) -> dict | None:
|
|
12
15
|
try:
|
|
13
16
|
data = (
|
|
14
17
|
client.table("instance")
|
|
15
18
|
.select(
|
|
16
19
|
"*, account!inner!instance_account_id_28936e8f_fk_account_id(*),"
|
|
17
|
-
" storage(*)"
|
|
20
|
+
" storage!instance_storage_id_87963cc8_fk_storage_id(*)"
|
|
18
21
|
)
|
|
19
22
|
.eq("account.handle", owner)
|
|
20
23
|
.eq("name", name)
|
|
@@ -82,7 +85,10 @@ def select_instance_by_id_with_storage(
|
|
|
82
85
|
client: Client,
|
|
83
86
|
):
|
|
84
87
|
response = (
|
|
85
|
-
client.table("instance")
|
|
88
|
+
client.table("instance")
|
|
89
|
+
.select("*, storage!instance_storage_id_87963cc8_fk_storage_id(*)")
|
|
90
|
+
.eq("id", instance_id)
|
|
91
|
+
.execute()
|
|
86
92
|
)
|
|
87
93
|
if len(response.data) == 0:
|
|
88
94
|
return None
|
|
@@ -178,8 +184,6 @@ def select_db_user_by_instance(instance_id: str, client: Client):
|
|
|
178
184
|
def _delete_instance_record(instance_id: UUID, client: Client) -> None:
|
|
179
185
|
if not isinstance(instance_id, UUID):
|
|
180
186
|
instance_id = UUID(instance_id)
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
sb_delete_instance = _delete_instance_record
|
|
187
|
+
response = client.table("instance").delete().eq("id", instance_id.hex).execute()
|
|
188
|
+
if response.data:
|
|
189
|
+
logger.important(f"deleted instance record on hub {instance_id.hex}")
|
lamindb_setup/core/_hub_utils.py
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
from typing import Optional
|
|
4
|
+
|
|
2
5
|
from pydantic import BaseModel, validator
|
|
3
6
|
from pydantic.networks import MultiHostDsn
|
|
4
7
|
|
|
5
8
|
|
|
6
|
-
def validate_schema_arg(schema:
|
|
9
|
+
def validate_schema_arg(schema: str | None = None) -> str:
|
|
7
10
|
if schema is None or schema == "":
|
|
8
11
|
return ""
|
|
9
12
|
# currently no actual validation, can add back if we see a need
|
|
@@ -12,7 +15,7 @@ def validate_schema_arg(schema: Optional[str] = None) -> str:
|
|
|
12
15
|
return ",".join(to_be_validated)
|
|
13
16
|
|
|
14
17
|
|
|
15
|
-
def validate_db_arg(db:
|
|
18
|
+
def validate_db_arg(db: str | None) -> None:
|
|
16
19
|
if db is not None:
|
|
17
20
|
LaminDsnModel(db=db)
|
|
18
21
|
|
|
@@ -43,13 +46,13 @@ class LaminDsn(MultiHostDsn):
|
|
|
43
46
|
cls,
|
|
44
47
|
*,
|
|
45
48
|
scheme: str,
|
|
46
|
-
user:
|
|
47
|
-
password:
|
|
49
|
+
user: str | None = None,
|
|
50
|
+
password: str | None = None,
|
|
48
51
|
host: str,
|
|
49
|
-
port:
|
|
50
|
-
database:
|
|
51
|
-
query:
|
|
52
|
-
fragment:
|
|
52
|
+
port: str | None = None,
|
|
53
|
+
database: str | None = None,
|
|
54
|
+
query: str | None = None,
|
|
55
|
+
fragment: str | None = None,
|
|
53
56
|
**_kwargs: str,
|
|
54
57
|
) -> str:
|
|
55
58
|
return super().build(
|
lamindb_setup/core/_settings.py
CHANGED
|
@@ -1,30 +1,30 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import os
|
|
2
|
-
from typing import
|
|
3
|
-
|
|
4
|
-
from
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
from ._settings_load import (
|
|
5
7
|
load_instance_settings,
|
|
6
8
|
load_or_create_user_settings,
|
|
7
9
|
)
|
|
8
|
-
from ._settings_store import current_instance_settings_file
|
|
9
|
-
from pathlib import Path
|
|
10
|
-
from ._settings_store import settings_dir
|
|
10
|
+
from ._settings_store import current_instance_settings_file, settings_dir
|
|
11
11
|
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from pathlib import Path
|
|
12
14
|
|
|
13
|
-
|
|
14
|
-
"""Setup settings.
|
|
15
|
+
from lamindb_setup.core import InstanceSettings, StorageSettings, UserSettings
|
|
15
16
|
|
|
16
|
-
- :class:`~lamindb_setup.core.InstanceSettings`
|
|
17
|
-
- :class:`~lamindb_setup.core.StorageSettings`
|
|
18
|
-
- :class:`~lamindb_setup.core.UserSettings`
|
|
19
|
-
"""
|
|
20
17
|
|
|
21
|
-
|
|
18
|
+
class SetupSettings:
|
|
19
|
+
"""Setup settings."""
|
|
22
20
|
|
|
23
|
-
|
|
24
|
-
_instance_settings: Union[InstanceSettings, None] = None
|
|
21
|
+
_using_key: str | None = None # set through lamindb.settings
|
|
25
22
|
|
|
26
|
-
|
|
27
|
-
|
|
23
|
+
_user_settings: UserSettings | None = None
|
|
24
|
+
_instance_settings: InstanceSettings | None = None
|
|
25
|
+
|
|
26
|
+
_user_settings_env: str | None = None
|
|
27
|
+
_instance_settings_env: str | None = None
|
|
28
28
|
|
|
29
29
|
_auto_connect_path: Path = settings_dir / "auto_connect"
|
|
30
30
|
|
|
@@ -50,11 +50,8 @@ class SetupSettings:
|
|
|
50
50
|
|
|
51
51
|
@property
|
|
52
52
|
def user(self) -> UserSettings:
|
|
53
|
-
"""
|
|
54
|
-
if (
|
|
55
|
-
self._user_settings is None
|
|
56
|
-
or self._user_settings_env != get_env_name() # noqa
|
|
57
|
-
):
|
|
53
|
+
""":class:`~lamindb.setup.core.UserSettings`."""
|
|
54
|
+
if self._user_settings is None or self._user_settings_env != get_env_name():
|
|
58
55
|
self._user_settings = load_or_create_user_settings()
|
|
59
56
|
self._user_settings_env = get_env_name()
|
|
60
57
|
if self._user_settings and self._user_settings.uid is None:
|
|
@@ -63,10 +60,10 @@ class SetupSettings:
|
|
|
63
60
|
|
|
64
61
|
@property
|
|
65
62
|
def instance(self) -> InstanceSettings:
|
|
66
|
-
"""
|
|
63
|
+
""":class:`~lamindb.setup.core.InstanceSettings`."""
|
|
67
64
|
if (
|
|
68
65
|
self._instance_settings is None
|
|
69
|
-
or self._instance_settings_env != get_env_name()
|
|
66
|
+
or self._instance_settings_env != get_env_name()
|
|
70
67
|
):
|
|
71
68
|
self._instance_settings = load_instance_settings()
|
|
72
69
|
self._instance_settings_env = get_env_name()
|
|
@@ -74,13 +71,13 @@ class SetupSettings:
|
|
|
74
71
|
|
|
75
72
|
@property
|
|
76
73
|
def storage(self) -> StorageSettings:
|
|
77
|
-
"""
|
|
74
|
+
""":class:`~lamindb.setup.core.StorageSettings`."""
|
|
78
75
|
return self.instance.storage
|
|
79
76
|
|
|
80
77
|
@property
|
|
81
78
|
def _instance_exists(self):
|
|
82
79
|
try:
|
|
83
|
-
self.instance
|
|
80
|
+
self.instance # noqa
|
|
84
81
|
return True
|
|
85
82
|
# this is implicit logic that catches if no instance is loaded
|
|
86
83
|
except SystemExit:
|