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.
Files changed (45) hide show
  1. lamindb_setup/__init__.py +15 -15
  2. lamindb_setup/_cache.py +4 -1
  3. lamindb_setup/_check.py +3 -0
  4. lamindb_setup/_check_setup.py +13 -7
  5. lamindb_setup/_close.py +2 -0
  6. lamindb_setup/_connect_instance.py +47 -26
  7. lamindb_setup/_delete.py +72 -40
  8. lamindb_setup/_django.py +4 -1
  9. lamindb_setup/_exportdb.py +4 -2
  10. lamindb_setup/_importdb.py +5 -1
  11. lamindb_setup/_init_instance.py +61 -45
  12. lamindb_setup/_migrate.py +16 -13
  13. lamindb_setup/_register_instance.py +10 -3
  14. lamindb_setup/_schema.py +6 -3
  15. lamindb_setup/_set_managed_storage.py +37 -0
  16. lamindb_setup/_setup_user.py +7 -7
  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 +203 -88
  24. lamindb_setup/core/_hub_crud.py +21 -12
  25. lamindb_setup/core/_hub_utils.py +11 -8
  26. lamindb_setup/core/_settings.py +23 -26
  27. lamindb_setup/core/_settings_instance.py +149 -81
  28. lamindb_setup/core/_settings_load.py +13 -7
  29. lamindb_setup/core/_settings_save.py +13 -8
  30. lamindb_setup/core/_settings_storage.py +76 -42
  31. lamindb_setup/core/_settings_store.py +4 -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 +3 -1
  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 +191 -88
  40. {lamindb_setup-0.70.0.dist-info → lamindb_setup-0.71.1.dist-info}/METADATA +6 -4
  41. lamindb_setup-0.71.1.dist-info/RECORD +43 -0
  42. lamindb_setup/_add_remote_storage.py +0 -50
  43. lamindb_setup-0.70.0.dist-info/RECORD +0 -43
  44. {lamindb_setup-0.70.0.dist-info → lamindb_setup-0.71.1.dist-info}/LICENSE +0 -0
  45. {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
- Every function in the API has a matching command in the `lamin` CLI.
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
- Setup:
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
- More instance operations:
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.70.0" # denote a release candidate for 0.1.0 with 0.1rc1
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 settings, close
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
@@ -1,3 +1,6 @@
1
+ from __future__ import annotations
2
+
3
+
1
4
  def check():
2
5
  from django.core.management import call_command
3
6
 
@@ -1,12 +1,18 @@
1
- from lamin_utils import logger
2
- from typing import Optional
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
- from .core._settings import settings
8
- from .core._settings_instance import InstanceSettings
9
- from .core import django
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: Optional[InstanceSettings] = None
28
+ CURRENT_ISETTINGS: InstanceSettings | None = None
23
29
 
24
30
 
25
- def _get_current_instance_settings() -> Optional[InstanceSettings]:
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,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  from lamin_utils import logger
2
4
 
3
5
  from .core._settings import settings
@@ -1,26 +1,33 @@
1
- from pathlib import Path
2
- from typing import Optional, Union, Dict, Tuple
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
- from lamindb_setup.core.types import UPathStr
7
- from lamindb_setup.core._hub_utils import (
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 ._close import close as close_instance
12
- from ._init_instance import load_from_isettings
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: Dict[str, str], settings_file: Path, db: Optional[str] = None
52
- ) -> Optional[str]:
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: Optional[str] = None,
102
- storage: Optional[UPathStr] = None,
108
+ db: str | None = None,
109
+ storage: UPathStr | None = None,
103
110
  _raise_not_reachable_error: bool = True,
104
111
  _test: bool = False,
105
- ) -> Optional[Union[str, Tuple]]:
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.id.hex}
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
- local_storage=instance_result["storage_mode"] == "hybrid",
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-reachable"
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-reachable"
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.id.hex}, but database is not"
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: Optional[str] = None,
228
- storage: Optional[UPathStr] = None,
229
- ) -> Optional[Union[str, Tuple]]:
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 pathlib import Path
3
- from lamin_utils import logger
4
+ from typing import TYPE_CHECKING, Optional
4
5
  from uuid import UUID
5
- from typing import Optional
6
- from .core._settings_instance import InstanceSettings
7
- from .core._settings_storage import StorageSettings
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 check_storage_is_empty, hosted_buckets
12
- from .core._hub_core import delete_instance as delete_instance_on_hub
13
- from .core._hub_core import connect_instance as load_instance_from_hub
14
- from ._connect_instance import INSTANCE_NOT_FOUND_MESSAGE
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.id.hex}"
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
- instance_name (str): The name of the instance to delete.
59
- force (bool): Whether to skip the confirmation prompt.
60
- require_empty (bool): Whether to check if the instance is empty before deleting.
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
- if "/" in instance_name:
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, settings.user.handle)
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=settings.user.handle, name=instance_name
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=settings.user.handle,
81
+ owner=instance_owner,
81
82
  name=instance_name,
82
83
  hub_result=hub_result,
83
84
  )
84
- logger.warning(message)
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=settings.user.handle,
95
+ owner=instance_owner,
95
96
  name=instance_name,
96
97
  storage=ssettings,
97
- local_storage=instance_result["storage_mode"] == "hybrid",
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 {instance_slug}? (y/n) ")
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
- hosted_buckets
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
- logger.info(f"deleting instance {instance_slug}")
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
- delete_instance_on_hub(isettings.id, require_empty=False)
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 n_objects == 0 and isettings.storage.type == "local":
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").rmdir()
143
- isettings.storage.root.rmdir()
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: Optional[str] = None, **kwargs):
9
+ def django(command: str, package_name: str | None = None, **kwargs):
7
10
  r"""Manage migrations.
8
11
 
9
12
  Examples:
@@ -1,6 +1,7 @@
1
- from pathlib import Path
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):
@@ -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)