lamindb_setup 1.3.2__py3-none-any.whl → 1.4.0__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 CHANGED
@@ -33,7 +33,7 @@ Modules & settings:
33
33
 
34
34
  """
35
35
 
36
- __version__ = "1.3.2" # denote a release candidate for 0.1.0 with 0.1rc1
36
+ __version__ = "1.4.0" # denote a release candidate for 0.1.0 with 0.1rc1
37
37
 
38
38
  import os
39
39
 
lamindb_setup/_close.py CHANGED
@@ -4,7 +4,6 @@ from lamin_utils import logger
4
4
 
5
5
  from .core._settings import settings
6
6
  from .core._settings_store import current_instance_settings_file
7
- from .core._setup_bionty_sources import delete_bionty_sources_yaml
8
7
  from .core.cloud_sqlite_locker import clear_locker
9
8
 
10
9
 
@@ -24,8 +23,6 @@ def close(mute: bool = False) -> None:
24
23
  logger.warning("did not upload cache file - not enough permissions")
25
24
  else:
26
25
  raise e
27
- if "bionty" in settings.instance.modules:
28
- delete_bionty_sources_yaml()
29
26
  current_instance_settings_file().unlink()
30
27
  clear_locker()
31
28
  if not mute:
@@ -169,6 +169,7 @@ def _connect_instance(
169
169
  if (schema_id := instance_result["schema_id"]) is None
170
170
  else UUID(schema_id),
171
171
  fine_grained_access=instance_result.get("fine_grained_access", False),
172
+ db_permissions=instance_result.get("db_permissions", None),
172
173
  )
173
174
  else:
174
175
  if hub_result != "anonymous-user":
lamindb_setup/_delete.py CHANGED
@@ -131,7 +131,7 @@ def delete(slug: str, force: bool = False, require_empty: bool = True) -> int |
131
131
  # this will error if the user doesn't have permission
132
132
  delete_instance_on_hub(isettings._id, require_empty=False)
133
133
  delete_by_isettings(isettings)
134
- # if .lndb file was delete, then we might count -1
134
+ # if lamin.db file was delete, then we might count -1
135
135
  if n_files <= 0 and isettings.storage.type == "local":
136
136
  # dir is only empty after sqlite file was delete via delete_by_isettings
137
137
  if (isettings.storage.root / ".lamindb").exists():
@@ -14,6 +14,7 @@ from lamin_utils import logger
14
14
  from ._close import close as close_instance
15
15
  from ._silence_loggers import silence_loggers
16
16
  from .core import InstanceSettings
17
+ from .core._docs import doc_args
17
18
  from .core._settings import settings
18
19
  from .core._settings_instance import is_local_db_url
19
20
  from .core._settings_storage import StorageSettings, init_storage
@@ -95,11 +96,16 @@ def register_user(usettings):
95
96
  pass
96
97
 
97
98
 
98
- def register_user_and_storage_in_instance(isettings: InstanceSettings, usettings):
99
- """Register user & storage in DB."""
99
+ def register_initial_records(isettings: InstanceSettings, usettings):
100
+ """Register space, user & storage in DB."""
100
101
  from django.db.utils import OperationalError
102
+ from lamindb.models import Space
101
103
 
102
104
  try:
105
+ Space.objects.get_or_create(
106
+ name="All",
107
+ description="Every team & user with access to the instance has access.",
108
+ )
103
109
  register_user(usettings)
104
110
  register_storage_in_instance(isettings.storage)
105
111
  except OperationalError as error:
@@ -208,22 +214,32 @@ ln.Artifact.using("laminlabs/cellxgene").filter()
208
214
  Or do you want to switch off auto-connect via `lamin settings set auto-connect false`?
209
215
  """
210
216
 
217
+ DOC_STORAGE_ARG = "A local or remote folder (`'s3://...'` or `'gs://...'`). Defaults to current working directory."
218
+ DOC_INSTANCE_NAME = (
219
+ "Instance name. If not passed, it will equal the folder name passed to `storage`."
220
+ )
221
+ DOC_DB = "Database connection URL. Defaults to `None`, which implies an SQLite file in the storage location."
222
+ DOC_MODULES = "Comma-separated string of schema modules."
223
+ DOC_LOW_LEVEL_KWARGS = "Keyword arguments for low-level control."
224
+
211
225
 
226
+ @doc_args(DOC_STORAGE_ARG, DOC_INSTANCE_NAME, DOC_DB, DOC_MODULES, DOC_LOW_LEVEL_KWARGS)
212
227
  def init(
213
228
  *,
214
- storage: UPathStr,
229
+ storage: UPathStr = ".",
215
230
  name: str | None = None,
216
231
  db: PostgresDsn | None = None,
217
232
  modules: str | None = None,
218
233
  **kwargs,
219
234
  ) -> None:
220
- """Create and load a LaminDB instance.
235
+ """Init a LaminDB instance.
221
236
 
222
237
  Args:
223
- storage: Either local or remote folder (`"s3://..."` or `"gs://..."`).
224
- name: Instance name.
225
- db: Database connection url, do not pass for SQLite.
226
- modules: Comma-separated string of modules. None if the lamindb registries are enough.
238
+ storage: {}
239
+ name: {}
240
+ db: {}
241
+ modules: {}
242
+ **kwargs: {}
227
243
  """
228
244
  isettings = None
229
245
  ssettings = None
@@ -359,8 +375,8 @@ def load_from_isettings(
359
375
  user = settings.user if user is None else user
360
376
 
361
377
  if init:
362
- # during init both user and storage need to be registered
363
- register_user_and_storage_in_instance(isettings, user)
378
+ # during init space, user and storage need to be registered
379
+ register_initial_records(isettings, user)
364
380
  write_bionty_sources(isettings)
365
381
  isettings._update_cloud_sqlite_file(unlock_cloud_sqlite=False)
366
382
  else:
@@ -31,7 +31,7 @@ def set_managed_storage(root: UPathStr, **fs_kwargs):
31
31
  )
32
32
  # here the storage is registered in the hub
33
33
  # hub_record_status="hub-record-created" if a new record is created
34
- # "hub-record-retireved" if the storage is in the hub already
34
+ # "hub-record-retrieved" if the storage is in the hub already
35
35
  ssettings, hub_record_status = init_storage(
36
36
  root=root, instance_id=settings.instance._id, register_hub=True
37
37
  )
@@ -69,7 +69,9 @@ def connect_hub(
69
69
  # function_client_timeout=5 by default
70
70
  # increase to avoid rare timeouts for edge functions
71
71
  client_options = ClientOptions(
72
- auto_refresh_token=False, function_client_timeout=10
72
+ auto_refresh_token=False,
73
+ function_client_timeout=20,
74
+ postgrest_client_timeout=20,
73
75
  )
74
76
  return create_client(env.supabase_api_url, env.supabase_anon_key, client_options)
75
77
 
@@ -7,6 +7,7 @@ from importlib import metadata
7
7
  from typing import TYPE_CHECKING, Literal
8
8
  from uuid import UUID
9
9
 
10
+ import jwt
10
11
  from lamin_utils import logger
11
12
  from postgrest.exceptions import APIError
12
13
 
@@ -121,7 +122,7 @@ def init_storage_hub(
121
122
  auto_populate_instance: bool = True,
122
123
  created_by: UUID | None = None,
123
124
  access_token: str | None = None,
124
- ) -> Literal["hub-record-retireved", "hub-record-created"]:
125
+ ) -> Literal["hub-record-retrieved", "hub-record-created"]:
125
126
  if settings.user.handle != "anonymous" or access_token is not None:
126
127
  return call_with_fallback_auth(
127
128
  _init_storage_hub,
@@ -135,7 +136,7 @@ def init_storage_hub(
135
136
  _select_storage, ssettings=ssettings, update_uid=True
136
137
  )
137
138
  if storage_exists:
138
- return "hub-record-retireved"
139
+ return "hub-record-retrieved"
139
140
  else:
140
141
  raise ValueError("Log in to create a storage location on the hub.")
141
142
 
@@ -145,7 +146,7 @@ def _init_storage_hub(
145
146
  ssettings: StorageSettings,
146
147
  auto_populate_instance: bool,
147
148
  created_by: UUID | None = None,
148
- ) -> Literal["hub-record-retireved", "hub-record-created"]:
149
+ ) -> Literal["hub-record-retrieved", "hub-record-created"]:
149
150
  from lamindb_setup import settings
150
151
 
151
152
  created_by = settings.user._uuid if created_by is None else created_by
@@ -153,7 +154,7 @@ def _init_storage_hub(
153
154
  # database
154
155
  root = ssettings.root_as_str
155
156
  if _select_storage(ssettings, update_uid=True, client=client):
156
- return "hub-record-retireved"
157
+ return "hub-record-retrieved"
157
158
  if ssettings.type_is_cloud:
158
159
  id = uuid.uuid5(uuid.NAMESPACE_URL, root)
159
160
  else:
@@ -548,7 +549,7 @@ def _sign_in_hub_api_key(api_key: str, client: Client):
548
549
  access_token = json.loads(response)["accessToken"]
549
550
  # probably need more info here to avoid additional queries
550
551
  # like handle, uid etc
551
- account_id = client.auth._decode_jwt(access_token)["sub"]
552
+ account_id = jwt.decode(access_token, options={"verify_signature": False})["sub"]
552
553
  client.postgrest.auth(access_token)
553
554
  # normally public.account.id is equal to auth.user.id
554
555
  data = client.table("account").select("*").eq("id", account_id).execute().data
@@ -13,7 +13,12 @@ from ._hub_client import call_with_fallback
13
13
  from ._hub_crud import select_account_handle_name_by_lnid
14
14
  from ._hub_utils import LaminDsn, LaminDsnModel
15
15
  from ._settings_save import save_instance_settings
16
- from ._settings_storage import StorageSettings, init_storage, mark_storage_root
16
+ from ._settings_storage import (
17
+ LEGACY_STORAGE_UID_FILE_KEY,
18
+ STORAGE_UID_FILE_KEY,
19
+ StorageSettings,
20
+ init_storage,
21
+ )
17
22
  from ._settings_store import current_instance_settings_file, instance_settings_file
18
23
  from .cloud_sqlite_locker import (
19
24
  EXPIRATION_TIME,
@@ -60,6 +65,7 @@ class InstanceSettings:
60
65
  api_url: str | None = None,
61
66
  schema_id: UUID | None = None,
62
67
  fine_grained_access: bool = False,
68
+ db_permissions: str | None = None,
63
69
  _locker_user: UserSettings | None = None, # user to lock for if cloud sqlite
64
70
  ):
65
71
  from ._hub_utils import validate_db_arg
@@ -83,6 +89,8 @@ class InstanceSettings:
83
89
  # private, whether fine grained access is used
84
90
  # needed to be set to request jwt etc
85
91
  self._fine_grained_access = fine_grained_access
92
+ # permissions for db such as jwt, read, write etc.
93
+ self._db_permissions = db_permissions
86
94
  # if None then settings.user is used
87
95
  self._locker_user = _locker_user
88
96
 
@@ -144,32 +152,27 @@ class InstanceSettings:
144
152
  for record in all_local_records:
145
153
  root_path = Path(record.root)
146
154
  if root_path.exists():
147
- marker_path = root_path / ".lamindb/_is_initialized"
148
- if marker_path.exists():
149
- try:
150
- uid = marker_path.read_text()
151
- except PermissionError:
155
+ marker_path = root_path / STORAGE_UID_FILE_KEY
156
+ if not marker_path.exists():
157
+ legacy_filepath = root_path / LEGACY_STORAGE_UID_FILE_KEY
158
+ if legacy_filepath.exists():
152
159
  logger.warning(
153
- f"ignoring the following location because no permission to read it: {marker_path}"
160
+ f"found legacy marker file, renaming it from {legacy_filepath} to {marker_path}"
154
161
  )
155
- continue
156
- if uid == record.uid:
157
- found = True
158
- break
159
- elif uid == "":
160
- try:
161
- # legacy instance that was not yet marked properly
162
- mark_storage_root(record.root, record.uid)
163
- except PermissionError:
164
- logger.warning(
165
- f"ignoring the following location because no permission to write to it: {marker_path}"
166
- )
167
- continue
162
+ legacy_filepath.rename(marker_path)
168
163
  else:
169
- continue
170
- else:
171
- # legacy instance that was not yet marked at all
172
- mark_storage_root(record.root, record.uid)
164
+ raise ValueError(
165
+ f"local storage location '{root_path}' is corrupted, cannot find marker file with storage uid"
166
+ )
167
+ try:
168
+ uid = marker_path.read_text()
169
+ except PermissionError:
170
+ logger.warning(
171
+ f"ignoring the following location because no permission to read it: {marker_path}"
172
+ )
173
+ continue
174
+ if uid == record.uid:
175
+ found = True
173
176
  break
174
177
  if found:
175
178
  return StorageSettings(record.root)
@@ -295,7 +298,8 @@ class InstanceSettings:
295
298
  @property
296
299
  def _sqlite_file(self) -> UPath:
297
300
  """SQLite file."""
298
- return self.storage.key_to_filepath(f"{self._id.hex}.lndb")
301
+ filepath = self.storage.root / ".lamindb/lamin.db"
302
+ return filepath
299
303
 
300
304
  @property
301
305
  def _sqlite_file_local(self) -> Path:
@@ -477,24 +481,18 @@ class InstanceSettings:
477
481
 
478
482
  disable_auto_connect(setup_django)(self, init=True)
479
483
 
480
- from lamindb.models import Space
481
-
482
- Space.objects.get_or_create(
483
- name="All",
484
- description="Every team & user with access to the instance has access.",
485
- )
486
-
487
484
  def _load_db(self) -> tuple[bool, str]:
488
485
  # Is the database available and initialized as LaminDB?
489
486
  # returns a tuple of status code and message
490
487
  if self.dialect == "sqlite" and not self._sqlite_file.exists():
491
- legacy_file = self.storage.key_to_filepath(f"{self.name}.lndb")
488
+ legacy_file = self.storage.key_to_filepath(f"{self._id.hex}.lndb")
492
489
  if legacy_file.exists():
493
- raise RuntimeError(
494
- "The SQLite file has been renamed!\nPlease rename your SQLite file"
495
- f" {legacy_file} to {self._sqlite_file}"
490
+ logger.warning(
491
+ f"The SQLite file is being renamed from {legacy_file} to {self._sqlite_file}"
496
492
  )
497
- return False, f"SQLite file {self._sqlite_file} does not exist"
493
+ legacy_file.rename(self._sqlite_file)
494
+ else:
495
+ return False, f"SQLite file {self._sqlite_file} does not exist"
498
496
  # we need the local sqlite to setup django
499
497
  self._update_local_sqlite_file()
500
498
  # setting up django also performs a check for migrations & prints them
@@ -104,6 +104,7 @@ def setup_instance_from_store(store: InstanceSettingsStore) -> InstanceSettings:
104
104
  api_url=_null_to_value(store.api_url),
105
105
  schema_id=None if store.schema_id == "null" else UUID(store.schema_id),
106
106
  fine_grained_access=store.fine_grained_access,
107
+ db_permissions=_null_to_value(store.db_permissions),
107
108
  )
108
109
 
109
110
 
@@ -61,6 +61,7 @@ def save_settings(
61
61
  "api_url",
62
62
  "schema_id",
63
63
  "fine_grained_access",
64
+ "db_permissions",
64
65
  }:
65
66
  settings_key = f"_{store_key.rstrip('_')}"
66
67
  else:
@@ -23,7 +23,8 @@ if TYPE_CHECKING:
23
23
 
24
24
  from .types import UPathStr
25
25
 
26
- IS_INITIALIZED_KEY = ".lamindb/_is_initialized"
26
+ STORAGE_UID_FILE_KEY = ".lamindb/storage_uid.txt"
27
+ LEGACY_STORAGE_UID_FILE_KEY = ".lamindb/_is_initialized"
27
28
 
28
29
  # a list of supported fsspec protocols
29
30
  # rename file to local before showing to a user
@@ -82,11 +83,15 @@ def get_storage_region(path: UPathStr) -> str | None:
82
83
 
83
84
 
84
85
  def mark_storage_root(root: UPathStr, uid: str):
85
- # we need to touch a 0-byte object in folder-like storage location on S3 to avoid
86
+ # we need a file in folder-like storage locations on S3 to avoid
86
87
  # permission errors from leveraging s3fs on an empty hosted storage location
87
- # for consistency, we write this file everywhere
88
+ # (path.fs.find raises a PermissionError)
89
+ # we also need it in case a storage location is ambiguous because a server / local environment
90
+ # doesn't have a globally unique identifier, then we screen for this file to map the
91
+ # path on a storage location in the registry
92
+
88
93
  root_upath = UPath(root)
89
- mark_upath = root_upath / IS_INITIALIZED_KEY
94
+ mark_upath = root_upath / STORAGE_UID_FILE_KEY
90
95
  mark_upath.write_text(uid)
91
96
 
92
97
 
@@ -100,7 +105,7 @@ def init_storage(
100
105
  access_token: str | None = None,
101
106
  ) -> tuple[
102
107
  StorageSettings,
103
- Literal["hub-record-not-created", "hub-record-retireved", "hub-record-created"],
108
+ Literal["hub-record-not-created", "hub-record-retrieved", "hub-record-created"],
104
109
  ]:
105
110
  assert root is not None, "`root` argument can't be `None`"
106
111
 
@@ -145,38 +150,46 @@ def init_storage(
145
150
  )
146
151
  # this stores the result of init_storage_hub
147
152
  hub_record_status: Literal[
148
- "hub-record-not-created", "hub-record-retireved", "hub-record-created"
153
+ "hub-record-not-created", "hub-record-retrieved", "hub-record-created"
149
154
  ] = "hub-record-not-created"
150
155
  # the below might update the uid with one that's already taken on the hub
151
- if not prevent_register_hub:
152
- if ssettings.type_is_cloud or register_hub:
153
- from ._hub_core import delete_storage_record, init_storage_hub
154
-
155
- hub_record_status = init_storage_hub(
156
- ssettings,
157
- auto_populate_instance=not init_instance,
158
- created_by=created_by,
159
- access_token=access_token,
160
- )
161
- # below comes last only if everything else was successful
162
- try:
163
- # (federated) credentials for AWS access are provisioned under-the-hood
164
- # discussion: https://laminlabs.slack.com/archives/C04FPE8V01W/p1719260587167489
165
- # if access_token was passed in ssettings, it is used here
166
- mark_storage_root(ssettings.root, ssettings.uid) # type: ignore
167
- except Exception:
168
- logger.important(
169
- f"due to lack of write access, LaminDB won't manage storage location: {ssettings.root_as_str}"
156
+ if not prevent_register_hub and (ssettings.type_is_cloud or register_hub):
157
+ from ._hub_core import delete_storage_record, init_storage_hub
158
+
159
+ # this retrieves the storage record if it exists already in the hub
160
+ # and updates uid and instance_id in ssettings
161
+ hub_record_status = init_storage_hub(
162
+ ssettings,
163
+ auto_populate_instance=not init_instance,
164
+ created_by=created_by,
165
+ access_token=access_token,
170
166
  )
171
- # we have to check hub_record_status here because
172
- # _select_storage inside init_storage_hub also populates ssettings._uuid
173
- # and we don't want to delete an existing storage record here
174
- # only newly created
175
- if hub_record_status == "hub-record-created" and ssettings._uuid is not None:
176
- delete_storage_record(ssettings._uuid, access_token=access_token) # type: ignore
177
- ssettings._uuid_ = None
178
- hub_record_status = "hub-record-not-created"
179
- ssettings._instance_id = None
167
+ # below comes last only if everything else was successful
168
+ # we check the write access here only if the storage record has been just created
169
+ # or if the storage is local
170
+ # also we have to check hub_record_status here because
171
+ # _select_storage inside init_storage_hub also populates ssettings._uuid
172
+ # and we don't want to delete an existing storage record here if no write access
173
+ # only newly created
174
+ # local storages not registered in the hub should be also marked
175
+ is_local_not_retrieved = not (
176
+ ssettings.type_is_cloud or hub_record_status == "hub-record-retrieved"
177
+ )
178
+ if hub_record_status == "hub-record-created" or is_local_not_retrieved:
179
+ try:
180
+ # (federated) credentials for AWS access are provisioned under-the-hood
181
+ # discussion: https://laminlabs.slack.com/archives/C04FPE8V01W/p1719260587167489
182
+ # if access_token was passed in ssettings, it is used here
183
+ mark_storage_root(ssettings.root, ssettings.uid) # type: ignore
184
+ except Exception:
185
+ logger.important(
186
+ f"due to lack of write access, LaminDB won't manage storage location: {ssettings.root_as_str}"
187
+ )
188
+ if ssettings._uuid is not None:
189
+ delete_storage_record(ssettings._uuid, access_token=access_token) # type: ignore
190
+ ssettings._uuid_ = None
191
+ hub_record_status = "hub-record-not-created"
192
+ ssettings._instance_id = None
180
193
  return ssettings, hub_record_status
181
194
 
182
195
 
@@ -234,7 +247,14 @@ class StorageSettings:
234
247
 
235
248
  @property
236
249
  def _mark_storage_root(self) -> UPath:
237
- return self.root / IS_INITIALIZED_KEY
250
+ marker_path = self.root / STORAGE_UID_FILE_KEY
251
+ legacy_filepath = self.root / LEGACY_STORAGE_UID_FILE_KEY
252
+ if legacy_filepath.exists():
253
+ logger.warning(
254
+ f"found legacy marker file, renaming it from {legacy_filepath} to {marker_path}"
255
+ )
256
+ legacy_filepath.rename(marker_path)
257
+ return marker_path
238
258
 
239
259
  @property
240
260
  def record(self) -> Any:
@@ -58,6 +58,7 @@ class InstanceSettingsStore(BaseSettings):
58
58
  schema_str: Optional[str]
59
59
  schema_id: Optional[str] = None
60
60
  fine_grained_access: bool = False
61
+ db_permissions: Optional[str] = None
61
62
  id: str
62
63
  git_repo: Optional[str]
63
64
  keep_artifacts_local: Optional[bool]
@@ -1,116 +1,44 @@
1
1
  from __future__ import annotations
2
2
 
3
- import os
4
3
  from typing import TYPE_CHECKING
5
4
 
6
- from django.db.utils import OperationalError, ProgrammingError
7
- from lamin_utils import logger
8
-
9
- from ._settings import settings as setup_settings
10
-
11
5
  if TYPE_CHECKING:
12
6
  from ._settings_instance import InstanceSettings
13
7
 
14
- # bionty.Source -> bionty.base
15
- RENAME = {"name": "source", "description": "source_name"}
16
-
17
8
 
18
9
  def write_bionty_sources(isettings: InstanceSettings) -> None:
19
- """Write bionty sources to Source table."""
10
+ """Write public bionty sources to bt.Source table."""
20
11
  if "bionty" not in isettings.modules:
21
12
  return None
22
- import shutil
23
13
 
24
14
  import bionty
25
15
  import bionty.base as bionty_base
26
- from bionty._bionty import list_biorecord_models
16
+ from bionty._biorecord import list_biorecord_models
27
17
  from bionty.base.dev._handle_sources import parse_sources_yaml
28
18
  from bionty.models import Source
29
19
 
30
20
  bionty_models = list_biorecord_models(bionty)
31
21
 
32
- shutil.copy(
33
- bionty_base.settings.current_sources, bionty_base.settings.lamindb_sources
34
- )
35
-
36
- all_sources = parse_sources_yaml(bionty_base.settings.local_sources)
22
+ all_sources = parse_sources_yaml(bionty_base.settings.public_sources)
37
23
  all_sources_dict = all_sources.to_dict(orient="records")
38
24
 
39
- def _get_currently_used(key: str):
40
- return (
41
- bionty_base.display_currently_used_sources()
42
- .reset_index()
43
- .set_index(["entity", key])
44
- )
45
-
46
- currently_used = _get_currently_used("organism")
25
+ currently_used = (
26
+ bionty_base.display_currently_used_sources(mute=True)
27
+ .reset_index()
28
+ .set_index(["entity", "organism"])
29
+ )
47
30
 
48
31
  all_records = []
49
32
  for kwargs in all_sources_dict:
50
33
  act = currently_used.loc[(kwargs["entity"], kwargs["organism"])].to_dict()
51
- if (act["source"] == kwargs["source"]) and (
52
- act["version"] == kwargs["version"]
53
- ):
34
+ if (act["name"] == kwargs["name"]) and (act["version"] == kwargs["version"]):
54
35
  kwargs["currently_used"] = True
55
36
 
56
- # when the database is not yet migrated but setup is updated
57
- # won't need this once lamindb is released with the new pin
58
37
  kwargs["run"] = None # can't yet access tracking information
59
38
  kwargs["in_db"] = False
60
- for db_field, base_col in RENAME.items():
61
- kwargs[db_field] = kwargs.pop(base_col)
62
39
  if kwargs["entity"] in bionty_models:
63
40
  kwargs["entity"] = f"bionty.{kwargs['entity']}"
64
41
  record = Source(**kwargs)
65
42
  all_records.append(record)
66
43
 
67
44
  Source.objects.bulk_create(all_records, ignore_conflicts=True)
68
-
69
-
70
- def load_bionty_sources(isettings: InstanceSettings | None = None):
71
- """Write currently_used bionty sources to LAMINDB_VERSIONS_PATH in bionty."""
72
- if isettings is None:
73
- if setup_settings._instance_settings is not None:
74
- isettings = setup_settings.instance
75
- else:
76
- logger.warning(
77
- f"Ignoring bionty setup because running in LAMINDB_MULTI_INSTANCE mode = {os.environ.get('LAMINDB_MULTI_INSTANCE')}"
78
- )
79
- # not setting up bionty sources
80
- return None
81
- if isettings is not None:
82
- if "bionty" not in isettings.modules:
83
- # no need to setup anything
84
- return None
85
-
86
- import bionty.base as bionty_base
87
- from bionty.base.dev._handle_sources import parse_currently_used_sources
88
- from bionty.base.dev._io import write_yaml
89
- from bionty.models import Source
90
-
91
- try:
92
- # need try except because of integer primary key migration
93
- active_records = (
94
- Source.objects.filter(currently_used=True).order_by("id").all().values()
95
- )
96
- for kwargs in active_records:
97
- for db_field, base_col in RENAME.items():
98
- kwargs[base_col] = kwargs.pop(db_field)
99
- # TODO: non-bionty modules?
100
- kwargs["entity"] = kwargs["entity"].replace("bionty.", "")
101
- write_yaml(
102
- parse_currently_used_sources(active_records),
103
- bionty_base.settings.lamindb_sources,
104
- )
105
- except (OperationalError, ProgrammingError):
106
- pass
107
-
108
-
109
- def delete_bionty_sources_yaml():
110
- """Delete LAMINDB_SOURCES_PATH in bionty."""
111
- try:
112
- import bionty.base as bionty_base
113
-
114
- bionty_base.settings.lamindb_sources.unlink(missing_ok=True)
115
- except ModuleNotFoundError:
116
- pass
@@ -125,7 +125,7 @@ def setup_django(
125
125
 
126
126
  BaseDatabaseWrapper.close_if_health_check_failed = close_if_health_check_failed
127
127
 
128
- if isettings._fine_grained_access:
128
+ if isettings._fine_grained_access and isettings._db_permissions == "jwt":
129
129
  from ._hub_core import access_db
130
130
 
131
131
  set_db_token(access_db(isettings))
@@ -316,16 +316,26 @@ def upload_from(
316
316
  callback = ProgressCallback(local_path.name, "uploading")
317
317
  kwargs["callback"] = callback
318
318
 
319
- source: str | list[str]
320
- destination: str | list[str]
321
- if local_path_is_dir and not create_folder:
322
- source = [f.as_posix() for f in local_path.rglob("*") if f.is_file()]
323
- destination = fsspec.utils.other_paths(
324
- source, self.as_posix(), exists=False, flatten=False
325
- )
326
- else:
327
- source = local_path.as_posix()
328
- destination = self.as_posix()
319
+ source: str | list[str] = local_path.as_posix()
320
+ destination: str | list[str] = self.as_posix()
321
+ if local_path_is_dir:
322
+ size: int = 0
323
+ files: list[str] = []
324
+ for file in (path for path in local_path.rglob("*") if path.is_file()):
325
+ size += file.stat().st_size
326
+ files.append(file.as_posix())
327
+ # see https://github.com/fsspec/s3fs/issues/897
328
+ # here we reduce batch_size for folders bigger than 8 GiB
329
+ # to avoid the problem in the issue
330
+ # the default batch size for this case is 128
331
+ if "batch_size" not in kwargs and size >= 8 * 2**30:
332
+ kwargs["batch_size"] = 64
333
+
334
+ if not create_folder:
335
+ source = files
336
+ destination = fsspec.utils.other_paths(
337
+ files, self.as_posix(), exists=False, flatten=False
338
+ )
329
339
 
330
340
  # the below lines are to avoid s3fs triggering create_bucket in upload if
331
341
  # dirs are present, it allows to avoid the permission error
@@ -899,17 +909,12 @@ def check_storage_is_empty(
899
909
  ) -> int:
900
910
  root_upath = UPath(root)
901
911
  root_string = root_upath.as_posix() # type: ignore
902
- # we currently touch a 0-byte file in the root of a hosted storage location
903
- # ({storage_root}/.lamindb/_is_initialized) during storage initialization
904
- # since path.fs.find raises a PermissionError on empty hosted
905
- # subdirectories (see lamindb_setup/core/_settings_storage/init_storage).
906
- n_offset_objects = 1 # because of touched dummy file, see mark_storage_root()
912
+ n_offset_objects = 1 # because of storage_uid.txt file, see mark_storage_root()
913
+ if account_for_sqlite_file:
914
+ n_offset_objects += 1 # the SQLite file is in the ".lamindb" directory
907
915
  if root_string.startswith(HOSTED_BUCKETS):
908
916
  # in hosted buckets, count across entire root
909
917
  directory_string = root_string
910
- # the SQLite file is not in the ".lamindb" directory
911
- if account_for_sqlite_file:
912
- n_offset_objects += 1 # because of SQLite file
913
918
  else:
914
919
  # in any other storage location, only count in .lamindb
915
920
  if not root_string.endswith("/"):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: lamindb_setup
3
- Version: 1.3.2
3
+ Version: 1.4.0
4
4
  Summary: Setup & configure LaminDB.
5
5
  Author-email: Lamin Labs <open-source@lamin.ai>
6
6
  Requires-Python: >=3.10
@@ -15,13 +15,13 @@ Requires-Dist: universal_pathlib==0.2.6
15
15
  Requires-Dist: botocore<2.0.0
16
16
  Requires-Dist: supabase>=2.8.1,<=2.11.0
17
17
  Requires-Dist: storage3!=0.11.2; python_version < '3.11'
18
+ Requires-Dist: pyjwt<3.0.0
18
19
  Requires-Dist: psutil
19
20
  Requires-Dist: packaging
20
21
  Requires-Dist: urllib3<2 ; extra == "aws"
21
22
  Requires-Dist: aiobotocore[boto3]>=2.5.4,<3.0.0 ; extra == "aws"
22
23
  Requires-Dist: s3fs>=2023.12.2,<=2025.2.0,!=2024.10.0 ; extra == "aws"
23
24
  Requires-Dist: line_profiler ; extra == "dev"
24
- Requires-Dist: pyjwt<3.0.0 ; extra == "dev"
25
25
  Requires-Dist: psycopg2-binary ; extra == "dev"
26
26
  Requires-Dist: python-dotenv ; extra == "dev"
27
27
  Requires-Dist: nox ; extra == "dev"
@@ -1,20 +1,20 @@
1
- lamindb_setup/__init__.py,sha256=LkDrKl5YfGD2qI3A9fPfHkesr8R0ASCPzKqvNZFtRiE,2692
1
+ lamindb_setup/__init__.py,sha256=2h5njKI5Z4qiixV_epzJ1DfWghCpY8ao29gDHqa3guw,2692
2
2
  lamindb_setup/_cache.py,sha256=aszT-zk3S5dTLKp5g1W-S_FPh2E5YVCALwWSGPJLWBM,1493
3
3
  lamindb_setup/_check.py,sha256=28PcG8Kp6OpjSLSi1r2boL2Ryeh6xkaCL87HFbjs6GA,129
4
4
  lamindb_setup/_check_setup.py,sha256=d1GS1Csy2G9AysfjoyVcNVY0lhHiWSwSLpfgdIQf35s,5477
5
- lamindb_setup/_close.py,sha256=pf8PHrtRBC6TycBtVAXzD9EZSGufoyp5M82o6zLHmt4,1240
6
- lamindb_setup/_connect_instance.py,sha256=IXpU43DO-DWm9twDeuQJeBbKj-oB4SzEqsCjIX4AZMo,18276
7
- lamindb_setup/_delete.py,sha256=4NqJkEA812VWRxTBW1o1h1YX0fF7sQwn08hj1BmvCPs,5673
5
+ lamindb_setup/_close.py,sha256=SFfOO0OjYR3krvya66kK8RRQa7lPH8MnzUtE33yZ6sQ,1082
6
+ lamindb_setup/_connect_instance.py,sha256=lo0EV_PA8YNlerxfPLG0u-YdmyKLAqbIIhTfzmwNDlI,18352
7
+ lamindb_setup/_delete.py,sha256=2KnZOqd5Kgr45XzjiDE9der35LODDUajZD6_hcurGtQ,5676
8
8
  lamindb_setup/_django.py,sha256=uIQflpkp8l3axyPaKURlk3kacgpElVP5KOKmFxYSMGk,1454
9
9
  lamindb_setup/_entry_points.py,sha256=sKwXPX9xjOotoAjvgkU5LBwjjHLWVkh0ZGdiSsrch9k,522
10
10
  lamindb_setup/_exportdb.py,sha256=QLjoH4dEwqa01A12naKaDPglCCzl2_VLKWFfJRE_uSg,2113
11
11
  lamindb_setup/_importdb.py,sha256=fKv9ev5OOj_-bmzC8XZ1GxOcjIjI486yrHSHDWQrJeI,1874
12
- lamindb_setup/_init_instance.py,sha256=wZ1yEnbogduQOXkEbcip9Jm8mys1NtJy2W5RRWJy1lQ,14253
12
+ lamindb_setup/_init_instance.py,sha256=LRtuXf2jiz5zTs47F7TyhCL0wfHA9YqwWHCBMadtnQs,14837
13
13
  lamindb_setup/_migrate.py,sha256=ya-15sc91i4JmEWI4j00T2892x8hdy2fSW-qz4IdxLs,9739
14
14
  lamindb_setup/_register_instance.py,sha256=X7ZGlCVOZKq4zTpi3bxML4jzo6hgN9UYmdTxxf6JLmc,1205
15
15
  lamindb_setup/_schema.py,sha256=b3uzhhWpV5mQtDwhMINc2MabGCnGLESy51ito3yl6Wc,679
16
16
  lamindb_setup/_schema_metadata.py,sha256=cDkNHyFTFZq879UGY6i-rJEXfeBN59AN3Wz86caKnYI,14358
17
- lamindb_setup/_set_managed_storage.py,sha256=4tDxXQMt8Gw028uY3vIQxZQ7qBNXhQMc8saarNK_Z-s,2043
17
+ lamindb_setup/_set_managed_storage.py,sha256=qC3ACD_PWG-MrzcS3fQpjDEOuxAaJBgPqCU_bDvqtXo,2043
18
18
  lamindb_setup/_setup_user.py,sha256=-g7Xj6510BDyM8kuqAsVBZFwehlhBa_uWBSV1rPeuM8,4586
19
19
  lamindb_setup/_silence_loggers.py,sha256=AKF_YcHvX32eGXdsYK8MJlxEaZ-Uo2f6QDRzjKFCtws,1568
20
20
  lamindb_setup/core/__init__.py,sha256=BxIVMX5HQq8oZ1OuY_saUEJz5Tdd7gaCPngxVu5iou4,417
@@ -22,26 +22,26 @@ lamindb_setup/core/_aws_options.py,sha256=Umxu_1AYd-0LJUElZxowvE9vNA7Z8kh_63g3pp
22
22
  lamindb_setup/core/_aws_storage.py,sha256=nEjeUv4xUVpoV0Lx-zjjmyb9w804bDyaeiM-OqbfwM0,1799
23
23
  lamindb_setup/core/_deprecated.py,sha256=HN7iUBdEgahw5e4NHCd1VJooUfieNb6GRzS5x8jU-q8,2549
24
24
  lamindb_setup/core/_docs.py,sha256=3k-YY-oVaJd_9UIY-LfBg_u8raKOCNfkZQPA73KsUhs,276
25
- lamindb_setup/core/_hub_client.py,sha256=Wy3QRJ1mySSu7xHjLZkcQvZpBX03g8oKbxiqxRIpPgo,7456
26
- lamindb_setup/core/_hub_core.py,sha256=8ZdekUtJMPdWLUqiHeT2nZ_F7FV0GJkQ7ixaIOSaAr4,21309
25
+ lamindb_setup/core/_hub_client.py,sha256=XJ9V0th11zcx87tDTDVtYf5YjnEC06_jiSRHcnbFseg,7510
26
+ lamindb_setup/core/_hub_core.py,sha256=FCFvnQsPWUYLJ_GFsuQ8rINQ7Rqth71pDfNJHRjPY_0,21344
27
27
  lamindb_setup/core/_hub_crud.py,sha256=IAuPZes1am8OFwtcf5jSRQPGG1eKwVTEsp9Li-uq0cQ,5377
28
28
  lamindb_setup/core/_hub_utils.py,sha256=6dyDGyzYFgVfR_lE3VN3CP1jGp98gxPtr-T91PAP05U,2687
29
29
  lamindb_setup/core/_private_django_api.py,sha256=By63l3vIEtK1pq246FhHq3tslxsaTJGKm5VakYluWp4,2656
30
30
  lamindb_setup/core/_settings.py,sha256=eslFO84vb5uRRfJ3r_uu4O8677l8lU5BbpZJMSAYw6A,8244
31
- lamindb_setup/core/_settings_instance.py,sha256=OLpwUp4a0SvVQ_r48C7Se2O5rckOE5MC0afAUGRAYMY,19549
32
- lamindb_setup/core/_settings_load.py,sha256=5wzhfCqt5mA9rpgAs9EWgxifrpL7Xwjw2YWaoL4VNeU,4281
33
- lamindb_setup/core/_settings_save.py,sha256=P7TPIi0T7VPdyQX9Z5w9y0Uzq4Y5QHbFCuzWdN2nkfk,3185
34
- lamindb_setup/core/_settings_storage.py,sha256=1-Wso38WN0Pcl3QdkdZc-B01D9Jpl-bjNMmu_FRLPFU,13103
35
- lamindb_setup/core/_settings_store.py,sha256=NhKi7GsC4q5V280Ex7sjiSR2j6VXt1-01xPgBPtS_58,2257
31
+ lamindb_setup/core/_settings_instance.py,sha256=iUoLJj_bl8axs4fiNA5jgLjIEvrMaJBzz-PUDWXmUwg,19395
32
+ lamindb_setup/core/_settings_load.py,sha256=BaII7qH3hKbttHHtB5YECoz0c2SnxL_IcUEMZhuqHCo,4342
33
+ lamindb_setup/core/_settings_save.py,sha256=P04ZnWFSN4Qq_QFWXNvJDs4yxrY9CjQBol_BDku_JEw,3227
34
+ lamindb_setup/core/_settings_storage.py,sha256=op31t12T_fCfTG8OSfnXnIxB9VCQPg8Oo2cnZHVap8Y,14203
35
+ lamindb_setup/core/_settings_store.py,sha256=zyybc6fJXJcFNTjBrgtgbPhriInuhpmQKNoGmy8ScFA,2298
36
36
  lamindb_setup/core/_settings_user.py,sha256=lWqV3HmZCsEq2UsU_iVNW0p9ddsNg7-B6xOaMNH1aw0,1475
37
- lamindb_setup/core/_setup_bionty_sources.py,sha256=qTPMV5TEbNiTB81QqG2rSs6W8j8kQ7kVQMLOXRzAxBI,4004
37
+ lamindb_setup/core/_setup_bionty_sources.py,sha256=ox3X-SHiHa2lNPSWjwZhINypbLacX6kGwH6hVVrSFZc,1505
38
38
  lamindb_setup/core/cloud_sqlite_locker.py,sha256=i6TrT7HG0lqliPvZTlsZ_uplPaqhPBbabyfeR32SkA8,7107
39
- lamindb_setup/core/django.py,sha256=2-btFL9YglV90qNy3bzV6rYBer7GftGINsDbc6u4mD4,4837
39
+ lamindb_setup/core/django.py,sha256=2qIt3t9Ra_24aKU7q1r30JY87TM_rT6Cvh8rNPlqRc8,4876
40
40
  lamindb_setup/core/exceptions.py,sha256=4NpLUNUIfXYVTFX2FvLZF8RW34exk2Vn2X3G4YhnTRg,276
41
41
  lamindb_setup/core/hashing.py,sha256=M3Q1-ywnqh4Uy5zojbQfLju19HU0ySp8Oi7FGIJXfFI,3667
42
42
  lamindb_setup/core/types.py,sha256=zJii2le38BJUmsNVvzDrbzGYr0yaeb-9Rw9IKmsBr3k,523
43
- lamindb_setup/core/upath.py,sha256=AvRmICPBxQx-2iQYsXDFsrJS-AAUNuw6IymLcVmkWvo,33550
44
- lamindb_setup-1.3.2.dist-info/LICENSE,sha256=UOZ1F5fFDe3XXvG4oNnkL1-Ecun7zpHzRxjp-XsMeAo,11324
45
- lamindb_setup-1.3.2.dist-info/WHEEL,sha256=CpUCUxeHQbRN5UGRQHYRJorO5Af-Qy_fHMctcQ8DSGI,82
46
- lamindb_setup-1.3.2.dist-info/METADATA,sha256=LIS6VdKmukplKvZNzFx1KP0bn1cXMTVDlIJ_MCtU3n8,1779
47
- lamindb_setup-1.3.2.dist-info/RECORD,,
43
+ lamindb_setup/core/upath.py,sha256=bjKlQZFe-azlZZZ_VjH9bzfh93G6b88b_IE6E6Dg7cY,33662
44
+ lamindb_setup-1.4.0.dist-info/LICENSE,sha256=UOZ1F5fFDe3XXvG4oNnkL1-Ecun7zpHzRxjp-XsMeAo,11324
45
+ lamindb_setup-1.4.0.dist-info/WHEEL,sha256=CpUCUxeHQbRN5UGRQHYRJorO5Af-Qy_fHMctcQ8DSGI,82
46
+ lamindb_setup-1.4.0.dist-info/METADATA,sha256=eirnixadBvZvh_WfrT4ZnGPcpUcUj5nTTw36NDkEi00,1762
47
+ lamindb_setup-1.4.0.dist-info/RECORD,,