lamindb_setup 0.70.0__py2.py3-none-any.whl → 0.71.1__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/_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 +47 -26
- lamindb_setup/_delete.py +72 -40
- lamindb_setup/_django.py +4 -1
- lamindb_setup/_exportdb.py +4 -2
- lamindb_setup/_importdb.py +5 -1
- lamindb_setup/_init_instance.py +61 -45
- lamindb_setup/_migrate.py +16 -13
- lamindb_setup/_register_instance.py +10 -3
- lamindb_setup/_schema.py +6 -3
- lamindb_setup/_set_managed_storage.py +37 -0
- 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 +203 -88
- lamindb_setup/core/_hub_crud.py +21 -12
- 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 +13 -7
- lamindb_setup/core/_settings_save.py +13 -8
- lamindb_setup/core/_settings_storage.py +76 -42
- lamindb_setup/core/_settings_store.py +4 -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 +191 -88
- {lamindb_setup-0.70.0.dist-info → lamindb_setup-0.71.1.dist-info}/METADATA +6 -4
- lamindb_setup-0.71.1.dist-info/RECORD +43 -0
- lamindb_setup/_add_remote_storage.py +0 -50
- lamindb_setup-0.70.0.dist-info/RECORD +0 -43
- {lamindb_setup-0.70.0.dist-info → lamindb_setup-0.71.1.dist-info}/LICENSE +0 -0
- {lamindb_setup-0.70.0.dist-info → lamindb_setup-0.71.1.dist-info}/WHEEL +0 -0
lamindb_setup/__init__.py
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
"""Setup & configure LaminDB.
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
Typically, you'll want to use the CLI rather than this API.
|
|
3
|
+
Many functions in this "setup API" have a matching command in the :doc:`docs:cli` CLI.
|
|
6
4
|
|
|
7
5
|
Guide: :doc:`docs:setup`.
|
|
8
6
|
|
|
9
|
-
|
|
7
|
+
Basic operations:
|
|
10
8
|
|
|
11
9
|
.. autosummary::
|
|
12
10
|
:toctree:
|
|
@@ -17,7 +15,7 @@ Setup:
|
|
|
17
15
|
close
|
|
18
16
|
delete
|
|
19
17
|
|
|
20
|
-
|
|
18
|
+
Instance operations:
|
|
21
19
|
|
|
22
20
|
.. autosummary::
|
|
23
21
|
:toctree:
|
|
@@ -36,22 +34,22 @@ Modules & settings:
|
|
|
36
34
|
|
|
37
35
|
"""
|
|
38
36
|
|
|
39
|
-
__version__ = "0.
|
|
37
|
+
__version__ = "0.71.1" # denote a release candidate for 0.1.0 with 0.1rc1
|
|
40
38
|
|
|
41
39
|
import sys
|
|
42
40
|
from os import name as _os_name
|
|
43
41
|
|
|
44
42
|
from . import core
|
|
45
|
-
from ._close import close # noqa
|
|
46
|
-
from ._delete import delete # noqa
|
|
47
|
-
from ._init_instance import init # noqa
|
|
48
|
-
from ._connect_instance import connect, load # noqa
|
|
49
|
-
from ._migrate import migrate
|
|
50
|
-
from ._register_instance import register # noqa
|
|
51
|
-
from .core._settings import settings # noqa
|
|
52
|
-
from ._setup_user import login, logout # noqa
|
|
53
|
-
from ._django import django
|
|
54
43
|
from ._check_setup import _check_instance_setup
|
|
44
|
+
from ._close import close
|
|
45
|
+
from ._connect_instance import connect, load
|
|
46
|
+
from ._delete import delete
|
|
47
|
+
from ._django import django
|
|
48
|
+
from ._init_instance import init
|
|
49
|
+
from ._migrate import migrate
|
|
50
|
+
from ._register_instance import register
|
|
51
|
+
from ._setup_user import login, logout
|
|
52
|
+
from .core._settings import settings
|
|
55
53
|
|
|
56
54
|
dev = core # backward compat
|
|
57
55
|
_TESTING = False # used in lamindb tests
|
|
@@ -70,3 +68,5 @@ if _os_name == "nt":
|
|
|
70
68
|
_original_excepthook(args)
|
|
71
69
|
|
|
72
70
|
threading.excepthook = _except_hook
|
|
71
|
+
|
|
72
|
+
settings.__doc__ = """Global :class:`~lamindb.setup.core.SetupSettings`."""
|
lamindb_setup/_cache.py
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import shutil
|
|
4
|
+
|
|
2
5
|
from lamin_utils import logger
|
|
3
6
|
|
|
4
7
|
|
|
5
8
|
def clear_cache_dir():
|
|
6
|
-
from lamindb_setup import
|
|
9
|
+
from lamindb_setup import close, settings
|
|
7
10
|
|
|
8
11
|
if settings.instance._is_cloud_sqlite:
|
|
9
12
|
logger.warning(
|
lamindb_setup/_check.py
CHANGED
lamindb_setup/_check_setup.py
CHANGED
|
@@ -1,12 +1,18 @@
|
|
|
1
|
-
from
|
|
2
|
-
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
3
|
import os
|
|
4
|
+
from typing import TYPE_CHECKING, Optional
|
|
5
|
+
|
|
6
|
+
from lamin_utils import logger
|
|
7
|
+
|
|
4
8
|
from ._silence_loggers import silence_loggers
|
|
9
|
+
from .core import django
|
|
10
|
+
from .core._settings import settings
|
|
5
11
|
from .core._settings_store import current_instance_settings_file
|
|
6
12
|
from .core.exceptions import DefaultMessageException
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
from .core import
|
|
13
|
+
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from .core._settings_instance import InstanceSettings
|
|
10
16
|
|
|
11
17
|
|
|
12
18
|
class InstanceNotSetupError(DefaultMessageException):
|
|
@@ -19,10 +25,10 @@ If you used the CLI to set up lamindb in a notebook, restart the Python session.
|
|
|
19
25
|
"""
|
|
20
26
|
|
|
21
27
|
|
|
22
|
-
CURRENT_ISETTINGS:
|
|
28
|
+
CURRENT_ISETTINGS: InstanceSettings | None = None
|
|
23
29
|
|
|
24
30
|
|
|
25
|
-
def _get_current_instance_settings() ->
|
|
31
|
+
def _get_current_instance_settings() -> InstanceSettings | None:
|
|
26
32
|
global CURRENT_ISETTINGS
|
|
27
33
|
|
|
28
34
|
if CURRENT_ISETTINGS is not None:
|
lamindb_setup/_close.py
CHANGED
|
@@ -1,26 +1,33 @@
|
|
|
1
|
-
from
|
|
2
|
-
|
|
3
|
-
from uuid import UUID
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
4
3
|
import os
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
|
+
from uuid import UUID
|
|
6
|
+
|
|
7
|
+
from django.db import ProgrammingError
|
|
5
8
|
from lamin_utils import logger
|
|
6
|
-
|
|
7
|
-
from
|
|
9
|
+
|
|
10
|
+
from ._check_setup import _check_instance_setup
|
|
11
|
+
from ._close import close as close_instance
|
|
12
|
+
from ._init_instance import MESSAGE_NO_MULTIPLE_INSTANCE, load_from_isettings
|
|
13
|
+
from ._migrate import check_whether_migrations_in_sync
|
|
14
|
+
from ._silence_loggers import silence_loggers
|
|
15
|
+
from .core._hub_core import connect_instance as load_instance_from_hub
|
|
16
|
+
from .core._hub_utils import (
|
|
8
17
|
LaminDsn,
|
|
9
18
|
LaminDsnModel,
|
|
10
19
|
)
|
|
11
|
-
from .
|
|
12
|
-
from .
|
|
13
|
-
from .core._settings import InstanceSettings, settings
|
|
14
|
-
from ._silence_loggers import silence_loggers
|
|
20
|
+
from .core._settings import settings
|
|
21
|
+
from .core._settings_instance import InstanceSettings
|
|
15
22
|
from .core._settings_load import load_instance_settings
|
|
16
23
|
from .core._settings_storage import StorageSettings
|
|
17
24
|
from .core._settings_store import instance_settings_file
|
|
18
25
|
from .core.cloud_sqlite_locker import unlock_cloud_sqlite_upon_exception
|
|
19
|
-
from ._init_instance import MESSAGE_NO_MULTIPLE_INSTANCE
|
|
20
|
-
from ._check_setup import _check_instance_setup
|
|
21
|
-
from .core._hub_core import connect_instance as load_instance_from_hub
|
|
22
|
-
from ._migrate import check_whether_migrations_in_sync
|
|
23
26
|
|
|
27
|
+
if TYPE_CHECKING:
|
|
28
|
+
from pathlib import Path
|
|
29
|
+
|
|
30
|
+
from .core.types import UPathStr
|
|
24
31
|
|
|
25
32
|
# this is for testing purposes only
|
|
26
33
|
# set to True only to test failed load
|
|
@@ -48,8 +55,8 @@ def check_db_dsn_equal_up_to_credentials(db_dsn_hub, db_dsn_local):
|
|
|
48
55
|
|
|
49
56
|
|
|
50
57
|
def update_db_using_local(
|
|
51
|
-
hub_instance_result:
|
|
52
|
-
) ->
|
|
58
|
+
hub_instance_result: dict[str, str], settings_file: Path, db: str | None = None
|
|
59
|
+
) -> str | None:
|
|
53
60
|
db_updated = None
|
|
54
61
|
# check if postgres
|
|
55
62
|
if hub_instance_result["db_scheme"] == "postgresql":
|
|
@@ -98,11 +105,11 @@ def update_db_using_local(
|
|
|
98
105
|
def connect(
|
|
99
106
|
slug: str,
|
|
100
107
|
*,
|
|
101
|
-
db:
|
|
102
|
-
storage:
|
|
108
|
+
db: str | None = None,
|
|
109
|
+
storage: UPathStr | None = None,
|
|
103
110
|
_raise_not_reachable_error: bool = True,
|
|
104
111
|
_test: bool = False,
|
|
105
|
-
) ->
|
|
112
|
+
) -> str | tuple | None:
|
|
106
113
|
"""Connect to instance.
|
|
107
114
|
|
|
108
115
|
Args:
|
|
@@ -133,7 +140,7 @@ def connect(
|
|
|
133
140
|
if settings_file.exists():
|
|
134
141
|
isettings = load_instance_settings(settings_file)
|
|
135
142
|
# mimic instance_result from hub
|
|
136
|
-
instance_result = {"id": isettings.
|
|
143
|
+
instance_result = {"id": isettings._id.hex}
|
|
137
144
|
# skip hub request for a purely local instance
|
|
138
145
|
make_hub_request = isettings.is_remote
|
|
139
146
|
|
|
@@ -152,6 +159,8 @@ def connect(
|
|
|
152
159
|
root=storage_result["root"],
|
|
153
160
|
region=storage_result["region"],
|
|
154
161
|
uid=storage_result["lnid"],
|
|
162
|
+
uuid=UUID(storage_result["id"]),
|
|
163
|
+
instance_id=UUID(instance_result["id"]),
|
|
155
164
|
)
|
|
156
165
|
isettings = InstanceSettings(
|
|
157
166
|
id=UUID(instance_result["id"]),
|
|
@@ -161,7 +170,8 @@ def connect(
|
|
|
161
170
|
db=db_updated,
|
|
162
171
|
schema=instance_result["schema_str"],
|
|
163
172
|
git_repo=instance_result["git_repo"],
|
|
164
|
-
|
|
173
|
+
keep_artifacts_local=bool(instance_result["keep_artifacts_local"]),
|
|
174
|
+
is_on_hub=True,
|
|
165
175
|
)
|
|
166
176
|
check_whether_migrations_in_sync(instance_result["lamindb_version"])
|
|
167
177
|
else:
|
|
@@ -173,12 +183,12 @@ def connect(
|
|
|
173
183
|
if isettings.is_remote:
|
|
174
184
|
if _raise_not_reachable_error:
|
|
175
185
|
raise InstanceNotFoundError(message)
|
|
176
|
-
return "instance-not-
|
|
186
|
+
return "instance-not-found"
|
|
177
187
|
|
|
178
188
|
else:
|
|
179
189
|
if _raise_not_reachable_error:
|
|
180
190
|
raise InstanceNotFoundError(message)
|
|
181
|
-
return "instance-not-
|
|
191
|
+
return "instance-not-found"
|
|
182
192
|
|
|
183
193
|
if storage is not None:
|
|
184
194
|
update_isettings_with_storage(isettings, storage)
|
|
@@ -203,7 +213,7 @@ def connect(
|
|
|
203
213
|
raise SystemExit(msg)
|
|
204
214
|
else:
|
|
205
215
|
logger.warning(
|
|
206
|
-
f"instance exists with id {isettings.
|
|
216
|
+
f"instance exists with id {isettings._id.hex}, but database is not"
|
|
207
217
|
" loadable: re-initializing"
|
|
208
218
|
)
|
|
209
219
|
return "instance-corrupted-or-deleted", instance_result
|
|
@@ -213,6 +223,17 @@ def connect(
|
|
|
213
223
|
|
|
214
224
|
if storage is not None and isettings.dialect == "sqlite":
|
|
215
225
|
update_root_field_in_default_storage(isettings)
|
|
226
|
+
# below is for backfilling the instance_uid value
|
|
227
|
+
# we'll enable it once more people migrated to 0.71.0
|
|
228
|
+
# ssettings_record = isettings.storage.record
|
|
229
|
+
# if ssettings_record.instance_uid is None:
|
|
230
|
+
# ssettings_record.instance_uid = isettings.uid
|
|
231
|
+
# # try saving if not read-only access
|
|
232
|
+
# try:
|
|
233
|
+
# ssettings_record.save()
|
|
234
|
+
# # raised by django when the access is denied
|
|
235
|
+
# except ProgrammingError:
|
|
236
|
+
# pass
|
|
216
237
|
load_from_isettings(isettings)
|
|
217
238
|
except Exception as e:
|
|
218
239
|
if isettings is not None:
|
|
@@ -224,9 +245,9 @@ def connect(
|
|
|
224
245
|
def load(
|
|
225
246
|
slug: str,
|
|
226
247
|
*,
|
|
227
|
-
db:
|
|
228
|
-
storage:
|
|
229
|
-
) ->
|
|
248
|
+
db: str | None = None,
|
|
249
|
+
storage: UPathStr | None = None,
|
|
250
|
+
) -> str | tuple | None:
|
|
230
251
|
"""Connect to instance and set ``auto-connect`` to true.
|
|
231
252
|
|
|
232
253
|
This is exactly the same as ``ln.connect()`` except for that
|
lamindb_setup/_delete.py
CHANGED
|
@@ -1,17 +1,28 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import shutil
|
|
2
|
-
from
|
|
3
|
-
from lamin_utils import logger
|
|
4
|
+
from typing import TYPE_CHECKING, Optional
|
|
4
5
|
from uuid import UUID
|
|
5
|
-
|
|
6
|
-
from
|
|
7
|
-
|
|
6
|
+
|
|
7
|
+
from lamin_utils import logger
|
|
8
|
+
|
|
9
|
+
from ._connect_instance import (
|
|
10
|
+
INSTANCE_NOT_FOUND_MESSAGE,
|
|
11
|
+
InstanceNotFoundError,
|
|
12
|
+
get_owner_name_from_identifier,
|
|
13
|
+
)
|
|
14
|
+
from .core._hub_core import connect_instance as load_instance_from_hub
|
|
15
|
+
from .core._hub_core import delete_instance as delete_instance_on_hub
|
|
16
|
+
from .core._hub_core import get_storage_records_for_instance
|
|
8
17
|
from .core._settings import settings
|
|
18
|
+
from .core._settings_instance import InstanceSettings
|
|
9
19
|
from .core._settings_load import load_instance_settings
|
|
20
|
+
from .core._settings_storage import StorageSettings
|
|
10
21
|
from .core._settings_store import instance_settings_file
|
|
11
|
-
from .core.upath import
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
from
|
|
22
|
+
from .core.upath import HOSTED_BUCKETS, check_storage_is_empty
|
|
23
|
+
|
|
24
|
+
if TYPE_CHECKING:
|
|
25
|
+
from pathlib import Path
|
|
15
26
|
|
|
16
27
|
|
|
17
28
|
def delete_cache(cache_dir: Path):
|
|
@@ -20,7 +31,7 @@ def delete_cache(cache_dir: Path):
|
|
|
20
31
|
|
|
21
32
|
|
|
22
33
|
def delete_exclusion_dir(isettings: InstanceSettings) -> None:
|
|
23
|
-
exclusion_dir = isettings.storage.root / f".lamindb/_exclusion/{isettings.
|
|
34
|
+
exclusion_dir = isettings.storage.root / f".lamindb/_exclusion/{isettings._id.hex}"
|
|
24
35
|
if exclusion_dir.exists():
|
|
25
36
|
exclusion_dir.rmdir()
|
|
26
37
|
|
|
@@ -45,59 +56,50 @@ def delete_by_isettings(isettings: InstanceSettings) -> None:
|
|
|
45
56
|
if settings._instance_settings_path.exists():
|
|
46
57
|
settings._instance_settings_path.unlink()
|
|
47
58
|
settings._instance_settings = None
|
|
48
|
-
if isettings.storage._mark_storage_root.exists():
|
|
49
|
-
isettings.storage._mark_storage_root.unlink()
|
|
50
59
|
|
|
51
60
|
|
|
52
|
-
def delete(
|
|
53
|
-
instance_name: str, force: bool = False, require_empty: bool = True
|
|
54
|
-
) -> Optional[int]:
|
|
61
|
+
def delete(slug: str, force: bool = False, require_empty: bool = True) -> int | None:
|
|
55
62
|
"""Delete a LaminDB instance.
|
|
56
63
|
|
|
57
64
|
Args:
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
65
|
+
slug: The instance slug `account_handle/instance_name` or URL.
|
|
66
|
+
If the instance is owned by you, it suffices to pass the instance name.
|
|
67
|
+
force: Whether to skip the confirmation prompt.
|
|
68
|
+
require_empty: Whether to check if the instance is empty before deleting.
|
|
61
69
|
"""
|
|
62
|
-
|
|
63
|
-
logger.warning(
|
|
64
|
-
"Deleting the instance of another user is currently not supported with the"
|
|
65
|
-
" CLI. Please provide only the instance name when deleting an instance ('/'"
|
|
66
|
-
" delimiter not allowed)."
|
|
67
|
-
)
|
|
68
|
-
raise ValueError("Invalid instance name: '/' delimiter not allowed.")
|
|
69
|
-
instance_slug = f"{settings.user.handle}/{instance_name}"
|
|
70
|
+
instance_owner, instance_name = get_owner_name_from_identifier(slug)
|
|
70
71
|
if settings._instance_exists and settings.instance.name == instance_name:
|
|
71
72
|
isettings = settings.instance
|
|
72
73
|
else:
|
|
73
|
-
settings_file = instance_settings_file(instance_name,
|
|
74
|
+
settings_file = instance_settings_file(instance_name, instance_owner)
|
|
74
75
|
if not settings_file.exists():
|
|
75
76
|
hub_result = load_instance_from_hub(
|
|
76
|
-
owner=
|
|
77
|
+
owner=instance_owner, name=instance_name
|
|
77
78
|
)
|
|
78
79
|
if isinstance(hub_result, str):
|
|
79
80
|
message = INSTANCE_NOT_FOUND_MESSAGE.format(
|
|
80
|
-
owner=
|
|
81
|
+
owner=instance_owner,
|
|
81
82
|
name=instance_name,
|
|
82
83
|
hub_result=hub_result,
|
|
83
84
|
)
|
|
84
|
-
|
|
85
|
-
return None
|
|
85
|
+
raise InstanceNotFoundError(message)
|
|
86
86
|
instance_result, storage_result = hub_result
|
|
87
87
|
ssettings = StorageSettings(
|
|
88
88
|
root=storage_result["root"],
|
|
89
89
|
region=storage_result["region"],
|
|
90
90
|
uid=storage_result["lnid"],
|
|
91
|
+
uuid=UUID(storage_result["id"]),
|
|
91
92
|
)
|
|
92
93
|
isettings = InstanceSettings(
|
|
93
94
|
id=UUID(instance_result["id"]),
|
|
94
|
-
owner=
|
|
95
|
+
owner=instance_owner,
|
|
95
96
|
name=instance_name,
|
|
96
97
|
storage=ssettings,
|
|
97
|
-
|
|
98
|
+
keep_artifacts_local=bool(instance_result["keep_artifacts_local"]),
|
|
98
99
|
db=instance_result["db"] if "db" in instance_result else None,
|
|
99
100
|
schema=instance_result["schema_str"],
|
|
100
101
|
git_repo=instance_result["git_repo"],
|
|
102
|
+
is_on_hub=True,
|
|
101
103
|
)
|
|
102
104
|
else:
|
|
103
105
|
isettings = load_instance_settings(settings_file)
|
|
@@ -105,10 +107,14 @@ def delete(
|
|
|
105
107
|
logger.warning(
|
|
106
108
|
f"delete() does not yet affect your Postgres database at {isettings.db}"
|
|
107
109
|
)
|
|
110
|
+
if isettings.is_on_hub and settings.user.handle == "anonymous":
|
|
111
|
+
logger.warning(
|
|
112
|
+
"won't delete the hub component of this instance because you're not logged in"
|
|
113
|
+
)
|
|
108
114
|
if not force:
|
|
109
115
|
valid_responses = ["y", "yes"]
|
|
110
116
|
user_input = (
|
|
111
|
-
input(f"Are you sure you want to delete instance {
|
|
117
|
+
input(f"Are you sure you want to delete instance {isettings.slug}? (y/n) ")
|
|
112
118
|
.strip()
|
|
113
119
|
.lower()
|
|
114
120
|
)
|
|
@@ -120,25 +126,51 @@ def delete(
|
|
|
120
126
|
# delete the exlusion dir first because it's hard to count its objects
|
|
121
127
|
delete_exclusion_dir(isettings)
|
|
122
128
|
if isettings.storage.type_is_cloud and isettings.storage.root_as_str.startswith(
|
|
123
|
-
|
|
129
|
+
HOSTED_BUCKETS
|
|
124
130
|
):
|
|
125
131
|
if not require_empty:
|
|
126
132
|
logger.warning(
|
|
127
133
|
"hosted storage always has to be empty, ignoring `require_empty`"
|
|
128
134
|
)
|
|
129
135
|
require_empty = True
|
|
136
|
+
# first the default storage
|
|
130
137
|
n_objects = check_storage_is_empty(
|
|
131
138
|
isettings.storage.root,
|
|
132
139
|
raise_error=require_empty,
|
|
133
140
|
account_for_sqlite_file=isettings.dialect == "sqlite",
|
|
134
141
|
)
|
|
135
|
-
|
|
142
|
+
if isettings.storage._mark_storage_root.exists():
|
|
143
|
+
isettings.storage._mark_storage_root.unlink(
|
|
144
|
+
missing_ok=True # this is totally weird, but needed on Py3.11
|
|
145
|
+
)
|
|
146
|
+
# now everything that's on the hub
|
|
147
|
+
if settings.user.handle != "anonymous":
|
|
148
|
+
storage_records = get_storage_records_for_instance(isettings._id)
|
|
149
|
+
for storage_record in storage_records:
|
|
150
|
+
if storage_record["root"] == isettings.storage.root_as_str:
|
|
151
|
+
continue
|
|
152
|
+
check_storage_is_empty(
|
|
153
|
+
storage_record["root"], # type: ignore
|
|
154
|
+
raise_error=require_empty,
|
|
155
|
+
)
|
|
156
|
+
ssettings = StorageSettings(storage_record["root"]) # type: ignore
|
|
157
|
+
if ssettings._mark_storage_root.exists():
|
|
158
|
+
ssettings._mark_storage_root.unlink(
|
|
159
|
+
missing_ok=True # this is totally weird, but needed on Py3.11
|
|
160
|
+
)
|
|
161
|
+
logger.info(f"deleting instance {isettings.slug}")
|
|
136
162
|
# below we can skip check_storage_is_empty() because we already called
|
|
137
163
|
# it above
|
|
138
|
-
|
|
164
|
+
if settings.user.handle != "anonymous" and isettings.is_on_hub:
|
|
165
|
+
# start with deleting things on the hub
|
|
166
|
+
# this will error if the user doesn't have permission
|
|
167
|
+
delete_instance_on_hub(isettings._id, require_empty=False)
|
|
139
168
|
delete_by_isettings(isettings)
|
|
140
|
-
if
|
|
169
|
+
# if .lndb file was delete, then we might count -1
|
|
170
|
+
if n_objects <= 0 and isettings.storage.type == "local":
|
|
141
171
|
# dir is only empty after sqlite file was delete via delete_by_isettings
|
|
142
|
-
(isettings.storage.root / ".lamindb").
|
|
143
|
-
|
|
172
|
+
if (isettings.storage.root / ".lamindb").exists():
|
|
173
|
+
(isettings.storage.root / ".lamindb").rmdir()
|
|
174
|
+
if isettings.storage.root.exists():
|
|
175
|
+
isettings.storage.root.rmdir()
|
|
144
176
|
return None
|
lamindb_setup/_django.py
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
from typing import Optional
|
|
4
|
+
|
|
2
5
|
from .core._settings import settings
|
|
3
6
|
from .core.django import setup_django
|
|
4
7
|
|
|
5
8
|
|
|
6
|
-
def django(command: str, package_name:
|
|
9
|
+
def django(command: str, package_name: str | None = None, **kwargs):
|
|
7
10
|
r"""Manage migrations.
|
|
8
11
|
|
|
9
12
|
Examples:
|
lamindb_setup/_exportdb.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
from
|
|
2
|
-
from importlib import import_module
|
|
1
|
+
from __future__ import annotations
|
|
3
2
|
|
|
3
|
+
from importlib import import_module
|
|
4
|
+
from pathlib import Path
|
|
4
5
|
|
|
5
6
|
MODELS = {
|
|
6
7
|
"core": {
|
|
@@ -46,6 +47,7 @@ def exportdb() -> None:
|
|
|
46
47
|
directory = Path("./lamindb_export/")
|
|
47
48
|
directory.mkdir(parents=True, exist_ok=True)
|
|
48
49
|
import pandas as pd
|
|
50
|
+
|
|
49
51
|
import lamindb_setup as ln_setup
|
|
50
52
|
|
|
51
53
|
def export_registry(registry, directory):
|
lamindb_setup/_importdb.py
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from importlib import import_module
|
|
1
4
|
from pathlib import Path
|
|
5
|
+
|
|
2
6
|
from ._exportdb import MODELS
|
|
3
|
-
from importlib import import_module
|
|
4
7
|
|
|
5
8
|
|
|
6
9
|
def import_registry(registry, directory, connection):
|
|
@@ -26,6 +29,7 @@ def importdb() -> None:
|
|
|
26
29
|
if response != "y":
|
|
27
30
|
return None
|
|
28
31
|
from sqlalchemy import create_engine, text
|
|
32
|
+
|
|
29
33
|
import lamindb_setup as ln_setup
|
|
30
34
|
|
|
31
35
|
engine = create_engine(ln_setup.settings.instance.db, echo=False)
|