lamindb_setup 1.8.3__py3-none-any.whl → 1.9.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 +107 -107
- lamindb_setup/_cache.py +87 -87
- lamindb_setup/_check_setup.py +166 -166
- lamindb_setup/_connect_instance.py +328 -342
- lamindb_setup/_delete.py +141 -141
- lamindb_setup/_disconnect.py +32 -32
- lamindb_setup/_init_instance.py +440 -440
- lamindb_setup/_migrate.py +266 -259
- lamindb_setup/_register_instance.py +35 -35
- lamindb_setup/_schema_metadata.py +441 -441
- lamindb_setup/_set_managed_storage.py +70 -70
- lamindb_setup/_setup_user.py +133 -133
- lamindb_setup/core/__init__.py +21 -21
- lamindb_setup/core/_aws_options.py +223 -211
- lamindb_setup/core/_hub_client.py +248 -243
- lamindb_setup/core/_hub_core.py +665 -663
- lamindb_setup/core/_hub_crud.py +227 -227
- lamindb_setup/core/_private_django_api.py +83 -83
- lamindb_setup/core/_settings.py +377 -364
- lamindb_setup/core/_settings_instance.py +569 -568
- lamindb_setup/core/_settings_load.py +141 -141
- lamindb_setup/core/_settings_save.py +95 -95
- lamindb_setup/core/_settings_storage.py +429 -429
- lamindb_setup/core/_settings_store.py +91 -91
- 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 +305 -291
- 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 +1013 -1009
- lamindb_setup/errors.py +70 -70
- lamindb_setup/types.py +20 -20
- {lamindb_setup-1.8.3.dist-info → lamindb_setup-1.9.1.dist-info}/METADATA +1 -1
- lamindb_setup-1.9.1.dist-info/RECORD +50 -0
- lamindb_setup-1.8.3.dist-info/RECORD +0 -50
- {lamindb_setup-1.8.3.dist-info → lamindb_setup-1.9.1.dist-info}/LICENSE +0 -0
- {lamindb_setup-1.8.3.dist-info → lamindb_setup-1.9.1.dist-info}/WHEEL +0 -0
lamindb_setup/core/_settings.py
CHANGED
|
@@ -1,364 +1,377 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import os
|
|
4
|
-
import sys
|
|
5
|
-
from typing import TYPE_CHECKING
|
|
6
|
-
|
|
7
|
-
from lamin_utils import logger
|
|
8
|
-
from platformdirs import user_cache_dir
|
|
9
|
-
|
|
10
|
-
from ._settings_load import (
|
|
11
|
-
load_cache_path_from_settings,
|
|
12
|
-
load_instance_settings,
|
|
13
|
-
load_or_create_user_settings,
|
|
14
|
-
)
|
|
15
|
-
from ._settings_store import (
|
|
16
|
-
current_instance_settings_file,
|
|
17
|
-
settings_dir,
|
|
18
|
-
system_settings_dir,
|
|
19
|
-
)
|
|
20
|
-
from .upath import LocalPathClasses, UPath
|
|
21
|
-
|
|
22
|
-
if TYPE_CHECKING:
|
|
23
|
-
from pathlib import Path
|
|
24
|
-
|
|
25
|
-
from lamindb.models import Branch, Space
|
|
26
|
-
|
|
27
|
-
from lamindb_setup.core import InstanceSettings, StorageSettings, UserSettings
|
|
28
|
-
from lamindb_setup.types import UPathStr
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
DEFAULT_CACHE_DIR = UPath(user_cache_dir(appname="lamindb", appauthor="laminlabs"))
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
def _process_cache_path(cache_path: UPathStr | None) -> UPath | None:
|
|
35
|
-
if cache_path is None or cache_path == "null":
|
|
36
|
-
return None
|
|
37
|
-
cache_dir = UPath(cache_path)
|
|
38
|
-
if not isinstance(cache_dir, LocalPathClasses):
|
|
39
|
-
raise ValueError("cache dir should be a local path.")
|
|
40
|
-
if cache_dir.exists() and not cache_dir.is_dir():
|
|
41
|
-
raise ValueError("cache dir should be a directory.")
|
|
42
|
-
if not cache_dir.is_absolute():
|
|
43
|
-
raise ValueError("A path to the cache dir should be absolute.")
|
|
44
|
-
return cache_dir
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
class SetupSettings:
|
|
48
|
-
"""Setup settings."""
|
|
49
|
-
|
|
50
|
-
_using_key: str | None = None # set through lamindb.settings
|
|
51
|
-
|
|
52
|
-
_user_settings: UserSettings | None = None
|
|
53
|
-
_instance_settings: InstanceSettings | None = None
|
|
54
|
-
|
|
55
|
-
_user_settings_env: str | None = None
|
|
56
|
-
_instance_settings_env: str | None = None
|
|
57
|
-
|
|
58
|
-
_auto_connect_path: Path = settings_dir / "auto_connect"
|
|
59
|
-
_private_django_api_path: Path = settings_dir / "private_django_api"
|
|
60
|
-
|
|
61
|
-
_cache_dir: Path | None = None
|
|
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
|
-
|
|
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
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
return
|
|
165
|
-
|
|
166
|
-
@
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
if
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
)
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
self.
|
|
242
|
-
self.
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
repr
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
local_filepath
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import sys
|
|
5
|
+
from typing import TYPE_CHECKING
|
|
6
|
+
|
|
7
|
+
from lamin_utils import logger
|
|
8
|
+
from platformdirs import user_cache_dir
|
|
9
|
+
|
|
10
|
+
from ._settings_load import (
|
|
11
|
+
load_cache_path_from_settings,
|
|
12
|
+
load_instance_settings,
|
|
13
|
+
load_or_create_user_settings,
|
|
14
|
+
)
|
|
15
|
+
from ._settings_store import (
|
|
16
|
+
current_instance_settings_file,
|
|
17
|
+
settings_dir,
|
|
18
|
+
system_settings_dir,
|
|
19
|
+
)
|
|
20
|
+
from .upath import LocalPathClasses, UPath
|
|
21
|
+
|
|
22
|
+
if TYPE_CHECKING:
|
|
23
|
+
from pathlib import Path
|
|
24
|
+
|
|
25
|
+
from lamindb.models import Branch, Space
|
|
26
|
+
|
|
27
|
+
from lamindb_setup.core import InstanceSettings, StorageSettings, UserSettings
|
|
28
|
+
from lamindb_setup.types import UPathStr
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
DEFAULT_CACHE_DIR = UPath(user_cache_dir(appname="lamindb", appauthor="laminlabs"))
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _process_cache_path(cache_path: UPathStr | None) -> UPath | None:
|
|
35
|
+
if cache_path is None or cache_path == "null":
|
|
36
|
+
return None
|
|
37
|
+
cache_dir = UPath(cache_path)
|
|
38
|
+
if not isinstance(cache_dir, LocalPathClasses):
|
|
39
|
+
raise ValueError("cache dir should be a local path.")
|
|
40
|
+
if cache_dir.exists() and not cache_dir.is_dir():
|
|
41
|
+
raise ValueError("cache dir should be a directory.")
|
|
42
|
+
if not cache_dir.is_absolute():
|
|
43
|
+
raise ValueError("A path to the cache dir should be absolute.")
|
|
44
|
+
return cache_dir
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class SetupSettings:
|
|
48
|
+
"""Setup settings."""
|
|
49
|
+
|
|
50
|
+
_using_key: str | None = None # set through lamindb.settings
|
|
51
|
+
|
|
52
|
+
_user_settings: UserSettings | None = None
|
|
53
|
+
_instance_settings: InstanceSettings | None = None
|
|
54
|
+
|
|
55
|
+
_user_settings_env: str | None = None
|
|
56
|
+
_instance_settings_env: str | None = None
|
|
57
|
+
|
|
58
|
+
_auto_connect_path: Path = settings_dir / "auto_connect"
|
|
59
|
+
_private_django_api_path: Path = settings_dir / "private_django_api"
|
|
60
|
+
|
|
61
|
+
_cache_dir: Path | None = None
|
|
62
|
+
|
|
63
|
+
_branch = None # do not have types here
|
|
64
|
+
_space = None # do not have types here
|
|
65
|
+
|
|
66
|
+
@property
|
|
67
|
+
def _instance_settings_path(self) -> Path:
|
|
68
|
+
return current_instance_settings_file()
|
|
69
|
+
|
|
70
|
+
@property
|
|
71
|
+
def settings_dir(self) -> Path:
|
|
72
|
+
"""The directory that holds locally persisted settings."""
|
|
73
|
+
return settings_dir
|
|
74
|
+
|
|
75
|
+
@property
|
|
76
|
+
def auto_connect(self) -> bool:
|
|
77
|
+
"""Auto-connect to current instance upon `import lamindb`.
|
|
78
|
+
|
|
79
|
+
Upon installing `lamindb`, this setting is `False`.
|
|
80
|
+
|
|
81
|
+
Upon calling `lamin init` or `lamin connect` on the CLI, this setting is switched to `True`.
|
|
82
|
+
|
|
83
|
+
`ln.connect()` doesn't change the value of this setting.
|
|
84
|
+
|
|
85
|
+
You can manually change this setting
|
|
86
|
+
|
|
87
|
+
- in Python: `ln.setup.settings.auto_connect = True/False`
|
|
88
|
+
- via the CLI: `lamin settings set auto-connect true/false`
|
|
89
|
+
"""
|
|
90
|
+
return self._auto_connect_path.exists()
|
|
91
|
+
|
|
92
|
+
@auto_connect.setter
|
|
93
|
+
def auto_connect(self, value: bool) -> None:
|
|
94
|
+
if value:
|
|
95
|
+
self._auto_connect_path.touch()
|
|
96
|
+
else:
|
|
97
|
+
self._auto_connect_path.unlink(missing_ok=True)
|
|
98
|
+
|
|
99
|
+
@property
|
|
100
|
+
def _branch_path(self) -> Path:
|
|
101
|
+
return (
|
|
102
|
+
settings_dir
|
|
103
|
+
/ f"current-branch--{self.instance.owner}--{self.instance.name}.txt"
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
def _read_branch_idlike_name(self) -> tuple[int | str, str]:
|
|
107
|
+
idlike: str | int = 1
|
|
108
|
+
name: str = "main"
|
|
109
|
+
try:
|
|
110
|
+
branch_path = self._branch_path
|
|
111
|
+
except SystemExit: # in case no instance setup
|
|
112
|
+
return idlike, name
|
|
113
|
+
if branch_path.exists():
|
|
114
|
+
idlike, name = branch_path.read_text().split("\n")
|
|
115
|
+
return idlike, name
|
|
116
|
+
|
|
117
|
+
@property
|
|
118
|
+
# TODO: refactor so that it returns a BranchMock object
|
|
119
|
+
# and we never need a DB request
|
|
120
|
+
def branch(self) -> Branch:
|
|
121
|
+
"""Default branch."""
|
|
122
|
+
if self._branch is None:
|
|
123
|
+
from lamindb import Branch
|
|
124
|
+
|
|
125
|
+
idlike, _ = self._read_branch_idlike_name()
|
|
126
|
+
self._branch = Branch.get(idlike)
|
|
127
|
+
return self._branch
|
|
128
|
+
|
|
129
|
+
@branch.setter
|
|
130
|
+
def branch(self, value: str | Branch) -> None:
|
|
131
|
+
from lamindb import Branch, Q
|
|
132
|
+
from lamindb.errors import DoesNotExist
|
|
133
|
+
|
|
134
|
+
if isinstance(value, Branch):
|
|
135
|
+
assert value._state.adding is False, "Branch must be saved"
|
|
136
|
+
branch_record = value
|
|
137
|
+
else:
|
|
138
|
+
branch_record = Branch.filter(Q(name=value) | Q(uid=value)).one_or_none()
|
|
139
|
+
if branch_record is None:
|
|
140
|
+
raise DoesNotExist(
|
|
141
|
+
f"Branch '{value}', please check on the hub UI whether you have the correct `uid` or `name`."
|
|
142
|
+
)
|
|
143
|
+
# we are sure that the current instance is setup because
|
|
144
|
+
# it will error on lamindb import otherwise
|
|
145
|
+
self._branch_path.write_text(f"{branch_record.uid}\n{branch_record.name}")
|
|
146
|
+
self._branch = branch_record
|
|
147
|
+
|
|
148
|
+
@property
|
|
149
|
+
def _space_path(self) -> Path:
|
|
150
|
+
return (
|
|
151
|
+
settings_dir
|
|
152
|
+
/ f"current-space--{self.instance.owner}--{self.instance.name}.txt"
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
def _read_space_idlike_name(self) -> tuple[int | str, str]:
|
|
156
|
+
idlike: str | int = 1
|
|
157
|
+
name: str = "all"
|
|
158
|
+
try:
|
|
159
|
+
space_path = self._space_path
|
|
160
|
+
except SystemExit: # in case no instance setup
|
|
161
|
+
return idlike, name
|
|
162
|
+
if space_path.exists():
|
|
163
|
+
idlike, name = space_path.read_text().split("\n")
|
|
164
|
+
return idlike, name
|
|
165
|
+
|
|
166
|
+
@property
|
|
167
|
+
# TODO: refactor so that it returns a BranchMock object
|
|
168
|
+
# and we never need a DB request
|
|
169
|
+
def space(self) -> Space:
|
|
170
|
+
"""Default space."""
|
|
171
|
+
if self._space is None:
|
|
172
|
+
from lamindb import Space
|
|
173
|
+
|
|
174
|
+
idlike, _ = self._read_space_idlike_name()
|
|
175
|
+
self._space = Space.get(idlike)
|
|
176
|
+
return self._space
|
|
177
|
+
|
|
178
|
+
@space.setter
|
|
179
|
+
def space(self, value: str | Space) -> None:
|
|
180
|
+
from lamindb import Q, Space
|
|
181
|
+
from lamindb.errors import DoesNotExist
|
|
182
|
+
|
|
183
|
+
if isinstance(value, Space):
|
|
184
|
+
assert value._state.adding is False, "Space must be saved"
|
|
185
|
+
space_record = value
|
|
186
|
+
else:
|
|
187
|
+
space_record = Space.filter(Q(name=value) | Q(uid=value)).one_or_none()
|
|
188
|
+
if space_record is None:
|
|
189
|
+
raise DoesNotExist(
|
|
190
|
+
f"Space '{value}', please check on the hub UI whether you have the correct `uid` or `name`."
|
|
191
|
+
)
|
|
192
|
+
# we are sure that the current instance is setup because
|
|
193
|
+
# it will error on lamindb import otherwise
|
|
194
|
+
self._space_path.write_text(f"{space_record.uid}\n{space_record.name}")
|
|
195
|
+
self._space = space_record
|
|
196
|
+
|
|
197
|
+
@property
|
|
198
|
+
def is_connected(self) -> bool:
|
|
199
|
+
"""Determine whether the current instance is fully connected and ready to use.
|
|
200
|
+
|
|
201
|
+
If `True`, the current instance is connected, meaning that the db and other settings
|
|
202
|
+
are properly configured for use.
|
|
203
|
+
"""
|
|
204
|
+
from .django import IS_SETUP # always import to protect from assignment
|
|
205
|
+
|
|
206
|
+
return IS_SETUP
|
|
207
|
+
|
|
208
|
+
@property
|
|
209
|
+
def private_django_api(self) -> bool:
|
|
210
|
+
"""Turn internal Django API private to clean up the API (default `False`).
|
|
211
|
+
|
|
212
|
+
This patches your local pip-installed django installation. You can undo
|
|
213
|
+
the patch by setting this back to `False`.
|
|
214
|
+
"""
|
|
215
|
+
return self._private_django_api_path.exists()
|
|
216
|
+
|
|
217
|
+
@private_django_api.setter
|
|
218
|
+
def private_django_api(self, value: bool) -> None:
|
|
219
|
+
from ._private_django_api import private_django_api
|
|
220
|
+
|
|
221
|
+
# we don't want to call private_django_api() twice
|
|
222
|
+
if value and not self.private_django_api:
|
|
223
|
+
private_django_api()
|
|
224
|
+
self._private_django_api_path.touch()
|
|
225
|
+
elif not value and self.private_django_api:
|
|
226
|
+
private_django_api(reverse=True)
|
|
227
|
+
self._private_django_api_path.unlink(missing_ok=True)
|
|
228
|
+
|
|
229
|
+
@property
|
|
230
|
+
def user(self) -> UserSettings:
|
|
231
|
+
"""Settings of current user."""
|
|
232
|
+
env_changed = (
|
|
233
|
+
self._user_settings_env is not None
|
|
234
|
+
and self._user_settings_env != get_env_name()
|
|
235
|
+
)
|
|
236
|
+
if self._user_settings is None or env_changed:
|
|
237
|
+
# only uses LAMIN_API_KEY if there is no current_user.env
|
|
238
|
+
self._user_settings = load_or_create_user_settings(
|
|
239
|
+
api_key=os.environ.get("LAMIN_API_KEY")
|
|
240
|
+
)
|
|
241
|
+
self._user_settings_env = get_env_name()
|
|
242
|
+
if self._user_settings and self._user_settings.uid is None:
|
|
243
|
+
raise RuntimeError("Need to login, first: lamin login")
|
|
244
|
+
return self._user_settings # type: ignore
|
|
245
|
+
|
|
246
|
+
@property
|
|
247
|
+
def instance(self) -> InstanceSettings:
|
|
248
|
+
"""Settings of current LaminDB instance."""
|
|
249
|
+
env_changed = (
|
|
250
|
+
self._instance_settings_env is not None
|
|
251
|
+
and self._instance_settings_env != get_env_name()
|
|
252
|
+
)
|
|
253
|
+
if self._instance_settings is None or env_changed:
|
|
254
|
+
self._instance_settings = load_instance_settings()
|
|
255
|
+
self._instance_settings_env = get_env_name()
|
|
256
|
+
return self._instance_settings # type: ignore
|
|
257
|
+
|
|
258
|
+
@property
|
|
259
|
+
def storage(self) -> StorageSettings:
|
|
260
|
+
"""Settings of default storage."""
|
|
261
|
+
return self.instance.storage
|
|
262
|
+
|
|
263
|
+
@property
|
|
264
|
+
def _instance_exists(self):
|
|
265
|
+
try:
|
|
266
|
+
self.instance # noqa
|
|
267
|
+
return True
|
|
268
|
+
# this is implicit logic that catches if no instance is loaded
|
|
269
|
+
except SystemExit:
|
|
270
|
+
return False
|
|
271
|
+
|
|
272
|
+
@property
|
|
273
|
+
def cache_dir(self) -> UPath:
|
|
274
|
+
"""Cache root, a local directory to cache cloud files."""
|
|
275
|
+
if "LAMIN_CACHE_DIR" in os.environ:
|
|
276
|
+
cache_dir = UPath(os.environ["LAMIN_CACHE_DIR"])
|
|
277
|
+
elif self._cache_dir is None:
|
|
278
|
+
cache_path = load_cache_path_from_settings()
|
|
279
|
+
cache_dir = _process_cache_path(cache_path)
|
|
280
|
+
if cache_dir is None:
|
|
281
|
+
cache_dir = DEFAULT_CACHE_DIR
|
|
282
|
+
self._cache_dir = cache_dir
|
|
283
|
+
else:
|
|
284
|
+
cache_dir = self._cache_dir
|
|
285
|
+
try:
|
|
286
|
+
cache_dir.mkdir(parents=True, exist_ok=True)
|
|
287
|
+
# we don not want this to error
|
|
288
|
+
# beause no actual writing happens on just getting the cache dir
|
|
289
|
+
# in cloud_to_local_no_update for example
|
|
290
|
+
# so it should not fail on read-only systems
|
|
291
|
+
except Exception as e:
|
|
292
|
+
logger.warning(
|
|
293
|
+
f"Failed to create lamin cache directory at {cache_dir}: {e}"
|
|
294
|
+
)
|
|
295
|
+
return cache_dir
|
|
296
|
+
|
|
297
|
+
@property
|
|
298
|
+
def paths(self) -> type[SetupPaths]:
|
|
299
|
+
"""Convert cloud paths to lamindb local paths.
|
|
300
|
+
|
|
301
|
+
Use `settings.paths.cloud_to_local_no_update`
|
|
302
|
+
or `settings.paths.cloud_to_local`.
|
|
303
|
+
"""
|
|
304
|
+
return SetupPaths
|
|
305
|
+
|
|
306
|
+
def __repr__(self) -> str:
|
|
307
|
+
"""Rich string representation."""
|
|
308
|
+
# do not show current setting representation when building docs
|
|
309
|
+
if "sphinx" in sys.modules:
|
|
310
|
+
return object.__repr__(self)
|
|
311
|
+
repr = ""
|
|
312
|
+
if self._instance_exists:
|
|
313
|
+
repr += "Current branch & space:\n"
|
|
314
|
+
repr += f" - branch: {self._read_branch_idlike_name()[1]}\n"
|
|
315
|
+
repr += f" - space: {self._read_space_idlike_name()[1]}\n"
|
|
316
|
+
repr += self.instance.__repr__()
|
|
317
|
+
else:
|
|
318
|
+
repr += "Current instance: None"
|
|
319
|
+
repr += "\nConfig:\n"
|
|
320
|
+
repr += f" - auto-connect in Python: {self.auto_connect}\n"
|
|
321
|
+
repr += f" - private Django API: {self.private_django_api}\n"
|
|
322
|
+
repr += "Local directories:\n"
|
|
323
|
+
repr += f" - cache: {self.cache_dir.as_posix()}\n"
|
|
324
|
+
repr += f" - user settings: {settings_dir.as_posix()}\n"
|
|
325
|
+
repr += f" - system settings: {system_settings_dir.as_posix()}\n"
|
|
326
|
+
repr += self.user.__repr__()
|
|
327
|
+
return repr
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
class SetupPaths:
|
|
331
|
+
"""A static class for conversion of cloud paths to lamindb local paths."""
|
|
332
|
+
|
|
333
|
+
@staticmethod
|
|
334
|
+
def cloud_to_local_no_update(
|
|
335
|
+
filepath: UPathStr, cache_key: str | None = None
|
|
336
|
+
) -> UPath:
|
|
337
|
+
"""Local (or local cache) filepath from filepath without synchronization."""
|
|
338
|
+
if not isinstance(filepath, UPath):
|
|
339
|
+
filepath = UPath(filepath)
|
|
340
|
+
# cache_key is ignored if filepath is a local path
|
|
341
|
+
if not isinstance(filepath, LocalPathClasses):
|
|
342
|
+
# settings is defined further in this file
|
|
343
|
+
if cache_key is None:
|
|
344
|
+
local_key = filepath.path # type: ignore
|
|
345
|
+
protocol = filepath.protocol # type: ignore
|
|
346
|
+
if protocol in {"http", "https"}:
|
|
347
|
+
local_key = local_key.removeprefix(protocol + "://")
|
|
348
|
+
else:
|
|
349
|
+
local_key = cache_key
|
|
350
|
+
local_filepath = settings.cache_dir / local_key
|
|
351
|
+
else:
|
|
352
|
+
local_filepath = filepath
|
|
353
|
+
return local_filepath
|
|
354
|
+
|
|
355
|
+
@staticmethod
|
|
356
|
+
def cloud_to_local(
|
|
357
|
+
filepath: UPathStr, cache_key: str | None = None, **kwargs
|
|
358
|
+
) -> UPath:
|
|
359
|
+
"""Local (or local cache) filepath from filepath."""
|
|
360
|
+
if not isinstance(filepath, UPath):
|
|
361
|
+
filepath = UPath(filepath)
|
|
362
|
+
# cache_key is ignored in cloud_to_local_no_update if filepath is local
|
|
363
|
+
local_filepath = SetupPaths.cloud_to_local_no_update(filepath, cache_key)
|
|
364
|
+
if not isinstance(filepath, LocalPathClasses):
|
|
365
|
+
local_filepath.parent.mkdir(parents=True, exist_ok=True)
|
|
366
|
+
filepath.synchronize_to(local_filepath, **kwargs) # type: ignore
|
|
367
|
+
return local_filepath
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
def get_env_name():
|
|
371
|
+
if "LAMIN_ENV" in os.environ:
|
|
372
|
+
return os.environ["LAMIN_ENV"]
|
|
373
|
+
else:
|
|
374
|
+
return "prod"
|
|
375
|
+
|
|
376
|
+
|
|
377
|
+
settings = SetupSettings()
|