lamindb_setup 0.69.5__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.
Files changed (44) hide show
  1. lamindb_setup/__init__.py +15 -15
  2. lamindb_setup/_add_remote_storage.py +22 -33
  3. lamindb_setup/_cache.py +4 -1
  4. lamindb_setup/_check.py +3 -0
  5. lamindb_setup/_check_setup.py +13 -7
  6. lamindb_setup/_close.py +2 -0
  7. lamindb_setup/_connect_instance.py +50 -34
  8. lamindb_setup/_delete.py +121 -22
  9. lamindb_setup/_django.py +4 -1
  10. lamindb_setup/_exportdb.py +4 -2
  11. lamindb_setup/_importdb.py +5 -1
  12. lamindb_setup/_init_instance.py +58 -46
  13. lamindb_setup/_migrate.py +20 -14
  14. lamindb_setup/_register_instance.py +10 -3
  15. lamindb_setup/_schema.py +6 -3
  16. lamindb_setup/_setup_user.py +8 -8
  17. lamindb_setup/_silence_loggers.py +4 -2
  18. lamindb_setup/core/__init__.py +4 -3
  19. lamindb_setup/core/_aws_storage.py +3 -0
  20. lamindb_setup/core/_deprecated.py +2 -7
  21. lamindb_setup/core/_docs.py +2 -0
  22. lamindb_setup/core/_hub_client.py +12 -10
  23. lamindb_setup/core/_hub_core.py +206 -85
  24. lamindb_setup/core/_hub_crud.py +15 -11
  25. lamindb_setup/core/_hub_utils.py +11 -8
  26. lamindb_setup/core/_settings.py +23 -26
  27. lamindb_setup/core/_settings_instance.py +164 -42
  28. lamindb_setup/core/_settings_load.py +13 -8
  29. lamindb_setup/core/_settings_save.py +11 -8
  30. lamindb_setup/core/_settings_storage.py +104 -95
  31. lamindb_setup/core/_settings_store.py +3 -2
  32. lamindb_setup/core/_settings_user.py +10 -6
  33. lamindb_setup/core/_setup_bionty_sources.py +9 -2
  34. lamindb_setup/core/cloud_sqlite_locker.py +13 -10
  35. lamindb_setup/core/django.py +5 -0
  36. lamindb_setup/core/exceptions.py +4 -2
  37. lamindb_setup/core/hashing.py +15 -5
  38. lamindb_setup/core/types.py +5 -2
  39. lamindb_setup/core/upath.py +202 -92
  40. {lamindb_setup-0.69.5.dist-info → lamindb_setup-0.71.0.dist-info}/METADATA +6 -4
  41. lamindb_setup-0.71.0.dist-info/RECORD +43 -0
  42. lamindb_setup-0.69.5.dist-info/RECORD +0 -43
  43. {lamindb_setup-0.69.5.dist-info → lamindb_setup-0.71.0.dist-info}/LICENSE +0 -0
  44. {lamindb_setup-0.69.5.dist-info → lamindb_setup-0.71.0.dist-info}/WHEEL +0 -0
@@ -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 ._settings_instance import InstanceSettings
12
- from ._settings_storage import StorageSettings, base62
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
- select_instance_by_owner_name,
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,78 +50,188 @@ 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
- logger.important(f"deleting storage {storage_uuid.hex}")
48
- client.table("storage").delete().eq("id", storage_uuid.hex).execute()
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 init_storage(
52
- ssettings: StorageSettings,
53
- ) -> UUID:
58
+ def update_instance_record(instance_uuid: UUID, fields: dict) -> None:
54
59
  return call_with_fallback_auth(
55
- _init_storage,
56
- ssettings=ssettings,
60
+ _update_instance_record, instance_id=instance_uuid.hex, instance_fields=fields
61
+ )
62
+
63
+
64
+ def get_storage_records_for_instance(
65
+ instance_id: UUID,
66
+ ) -> list[dict[str, str | int]]:
67
+ return call_with_fallback_auth(
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()
57
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
111
+
112
+
113
+ def init_storage(
114
+ ssettings: StorageSettings,
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.")
58
129
 
59
130
 
60
- def _init_storage(ssettings: StorageSettings, client: Client) -> UUID:
131
+ def _init_storage(ssettings: StorageSettings, client: Client) -> None:
61
132
  from lamindb_setup import settings
62
133
 
63
134
  # storage roots are always stored without the trailing slash in the SQL
64
135
  # database
65
136
  root = ssettings.root_as_str
66
- # in the future, we could also encode a prefix to model local storage
67
- # locations
68
- # f"{prefix}{root}"
69
- id = uuid.uuid5(uuid.NAMESPACE_URL, root)
70
- fields = dict(
71
- id=id.hex,
72
- lnid=ssettings.uid,
73
- created_by=settings.user.uuid.hex, # type: ignore
74
- root=root,
75
- region=ssettings.region,
76
- type=ssettings.type,
77
- aws_account_id=ssettings._aws_account_id,
78
- description=ssettings._description,
79
- )
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
80
163
  client.table("storage").upsert(fields).execute()
81
- return id
164
+ ssettings._uuid_ = id
165
+ return None
166
+
167
+
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
+ )
82
172
 
83
173
 
84
- def delete_instance(identifier: Union[UUID, str]):
174
+ def _delete_instance(
175
+ identifier: UUID | str, require_empty: bool, client: Client
176
+ ) -> str | None:
85
177
  """Fully delete an instance in the hub.
86
178
 
87
179
  This function deletes the relevant instance and storage records in the hub,
88
180
  conditional on the emptiness of the storage location.
89
181
  """
90
- from .upath import check_s3_storage_location_empty, create_path, hosted_buckets
91
182
  from ._settings_storage import mark_storage_root
183
+ from .upath import check_storage_is_empty, create_path
92
184
 
93
- if isinstance(identifier, UUID):
94
- instance_with_storage = call_with_fallback_auth(
95
- select_instance_by_id_with_storage,
96
- instance_id=identifier,
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
97
193
  )
98
194
  else:
99
195
  owner, name = identifier.split("/")
100
- instance_with_storage = call_with_fallback_auth(
101
- select_instance_by_owner_name,
102
- owner=owner,
103
- name=name,
196
+ instance_with_storage = select_instance_by_owner_name(
197
+ owner=owner, name=name, client=client
104
198
  )
105
199
 
106
- if instance_with_storage is not None:
107
- root_string = instance_with_storage["storage"]["root"]
108
- # gate storage and instance deletion on empty storage location for
109
- # both hosted and non-hosted s3 instances
110
- if root_string.startswith("s3://"):
111
- root_path = create_path(root_string)
112
- # only mark hosted instances
113
- if root_string.startswith(hosted_buckets):
114
- mark_storage_root(root_path)
115
- check_s3_storage_location_empty(root_path)
200
+ if instance_with_storage is None:
201
+ logger.important("not deleting instance from hub as instance not found there")
202
+ return "instance-not-found"
116
203
 
117
- delete_instance_record(UUID(instance_with_storage["id"]))
118
- delete_storage_record(UUID(instance_with_storage["storage_id"]))
204
+ storage_records = _get_storage_records_for_instance(
205
+ UUID(instance_with_storage["id"]),
206
+ client,
207
+ )
208
+ if require_empty:
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)
234
+ return None
119
235
 
120
236
 
121
237
  def delete_instance_record(
@@ -138,25 +254,25 @@ def _init_instance(isettings: InstanceSettings, client: Client) -> None:
138
254
  lamindb_version = metadata.version("lamindb")
139
255
  except metadata.PackageNotFoundError:
140
256
  lamindb_version = None
141
- fields = dict(
142
- id=isettings.id.hex,
143
- account_id=settings.user.uuid.hex, # type: ignore
144
- name=isettings.name,
145
- storage_id=isettings.storage.uuid.hex, # type: ignore
146
- schema_str=isettings._schema_str,
147
- lamindb_version=lamindb_version,
148
- public=False,
149
- )
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
+ }
150
267
  if isettings.dialect != "sqlite":
151
268
  db_dsn = LaminDsnModel(db=isettings.db)
152
- fields.update(
153
- {
154
- "db_scheme": db_dsn.db.scheme,
155
- "db_host": db_dsn.db.host,
156
- "db_port": db_dsn.db.port,
157
- "db_database": db_dsn.db.database,
158
- }
159
- )
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)
160
276
  # I'd like the following to be an upsert, but this seems to violate RLS
161
277
  # Similarly, if we don't specify `returning="minimal"`, we'll violate RLS
162
278
  # we could make this idempotent by catching an error, but this seems dangerous
@@ -166,6 +282,9 @@ def _init_instance(isettings: InstanceSettings, client: Client) -> None:
166
282
  except APIError as e:
167
283
  logger.warning("instance likely already exists")
168
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
169
288
  logger.save(f"browse to: https://lamin.ai/{isettings.owner}/{isettings.name}")
170
289
 
171
290
 
@@ -173,7 +292,7 @@ def connect_instance(
173
292
  *,
174
293
  owner: str, # account_handle
175
294
  name: str, # instance_name
176
- ) -> Union[Tuple[dict, dict], str]:
295
+ ) -> tuple[dict, dict] | str:
177
296
  from ._settings import settings
178
297
 
179
298
  if settings.user.handle != "anonymous":
@@ -187,7 +306,7 @@ def _connect_instance(
187
306
  owner: str, # account_handle
188
307
  name: str, # instance_name
189
308
  client: Client,
190
- ) -> Union[Tuple[dict, dict], str]:
309
+ ) -> tuple[dict, dict] | str:
191
310
  instance_account_storage = select_instance_by_owner_name(owner, name, client)
192
311
  if instance_account_storage is None:
193
312
  # try the via single requests, will take more time
@@ -196,7 +315,7 @@ def _connect_instance(
196
315
  return "account-not-exists"
197
316
  instance = select_instance_by_name(account["id"], name, client)
198
317
  if instance is None:
199
- return "instance-not-reachable"
318
+ return "instance-not-found"
200
319
  # get default storage
201
320
  storage = select_storage(instance["storage_id"], client)
202
321
  if storage is None:
@@ -227,7 +346,7 @@ def _connect_instance(
227
346
  return instance, storage
228
347
 
229
348
 
230
- def access_aws(storage_root: str, access_token: Optional[str] = None) -> Dict[str, str]:
349
+ def access_aws(storage_root: str, access_token: str | None = None) -> dict[str, str]:
231
350
  from ._settings import settings
232
351
 
233
352
  if settings.user.handle != "anonymous" or access_token is not None:
@@ -239,7 +358,9 @@ def access_aws(storage_root: str, access_token: Optional[str] = None) -> Dict[st
239
358
  raise RuntimeError("Can only get access to AWS if authenticated.")
240
359
 
241
360
 
242
- def _access_aws(*, storage_root: str, client: Client) -> Dict[str, str]:
361
+ def _access_aws(*, storage_root: str, client: Client) -> dict[str, str]:
362
+ import lamindb_setup
363
+
243
364
  response = client.functions.invoke(
244
365
  "access-aws",
245
366
  invoke_options={"body": {"storage_root": storage_root}},
@@ -265,7 +386,7 @@ def get_lamin_site_base_url():
265
386
  return "https://lamin.ai"
266
387
 
267
388
 
268
- def sign_up_local_hub(email) -> Union[str, Tuple[str, str, str]]:
389
+ def sign_up_local_hub(email) -> str | tuple[str, str, str]:
269
390
  # raises gotrue.errors.AuthApiError: User already registered
270
391
  password = base62(40) # generate new password
271
392
  sign_up_kwargs = {"email": email, "password": password}
@@ -279,7 +400,7 @@ def sign_up_local_hub(email) -> Union[str, Tuple[str, str, str]]:
279
400
  )
280
401
 
281
402
 
282
- def _sign_in_hub(email: str, password: str, handle: Optional[str], client: Client):
403
+ def _sign_in_hub(email: str, password: str, handle: str | None, client: Client):
283
404
  auth = client.auth.sign_in_with_password(
284
405
  {
285
406
  "email": email,
@@ -309,8 +430,8 @@ def _sign_in_hub(email: str, password: str, handle: Optional[str], client: Clien
309
430
 
310
431
 
311
432
  def sign_in_hub(
312
- email: str, password: str, handle: Optional[str] = None
313
- ) -> Union[Exception, Tuple[UUID, str, str, str, str]]:
433
+ email: str, password: str, handle: str | None = None
434
+ ) -> Exception | tuple[UUID, str, str, str, str]:
314
435
  try:
315
436
  result = call_with_fallback(
316
437
  _sign_in_hub, email=email, password=password, handle=handle
@@ -1,20 +1,23 @@
1
- from supabase.client import Client
2
- from typing import Optional, Dict
3
- from lamin_utils import logger
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
- ) -> Optional[Dict]:
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").select("*, storage(*)").eq("id", instance_id).execute()
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
- logger.important(f"deleting instance {instance_id.hex}")
182
- client.table("instance").delete().eq("id", instance_id.hex).execute()
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}")
@@ -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: Optional[str] = None) -> str:
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: Optional[str]) -> None:
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: Optional[str] = None,
47
- password: Optional[str] = None,
49
+ user: str | None = None,
50
+ password: str | None = None,
48
51
  host: str,
49
- port: Optional[str] = None,
50
- database: Optional[str] = None,
51
- query: Optional[str] = None,
52
- fragment: Optional[str] = None,
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(
@@ -1,30 +1,30 @@
1
+ from __future__ import annotations
2
+
1
3
  import os
2
- from typing import Union, Optional
3
- from lamindb_setup.core import InstanceSettings, StorageSettings, UserSettings
4
- from lamindb_setup.core._settings_load import (
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
- class SetupSettings:
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
- _using_key: Optional[str] = None # set through lamindb.settings
18
+ class SetupSettings:
19
+ """Setup settings."""
22
20
 
23
- _user_settings: Union[UserSettings, None] = None
24
- _instance_settings: Union[InstanceSettings, None] = None
21
+ _using_key: str | None = None # set through lamindb.settings
25
22
 
26
- _user_settings_env: Union[str, None] = None
27
- _instance_settings_env: Union[str, None] = None
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
- """User."""
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
- """Instance."""
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() # noqa
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
- """Storage."""
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: