lamindb_setup 0.78.0__py3-none-any.whl → 0.80.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__ = "0.78.0" # denote a release candidate for 0.1.0 with 0.1rc1
36
+ __version__ = "0.80.0" # denote a release candidate for 0.1.0 with 0.1rc1
37
37
 
38
38
  import os as _os
39
39
  import sys as _sys
@@ -9,7 +9,11 @@ from lamin_utils import logger
9
9
 
10
10
  from ._check_setup import _check_instance_setup
11
11
  from ._close import close as close_instance
12
- from ._init_instance import MESSAGE_NO_MULTIPLE_INSTANCE, load_from_isettings
12
+ from ._init_instance import (
13
+ MESSAGE_CANNOT_SWITCH_DEFAULT_INSTANCE,
14
+ CannotSwitchDefaultInstance,
15
+ load_from_isettings,
16
+ )
13
17
  from ._silence_loggers import silence_loggers
14
18
  from .core._hub_core import connect_instance_hub
15
19
  from .core._hub_utils import (
@@ -224,7 +228,9 @@ def connect(slug: str, **kwargs) -> str | tuple | None:
224
228
  logger.info(f"connected lamindb: {settings.instance.slug}")
225
229
  return None
226
230
  else:
227
- raise RuntimeError(MESSAGE_NO_MULTIPLE_INSTANCE)
231
+ raise CannotSwitchDefaultInstance(
232
+ MESSAGE_CANNOT_SWITCH_DEFAULT_INSTANCE
233
+ )
228
234
  elif (
229
235
  _write_settings
230
236
  and settings._instance_exists
@@ -26,7 +26,7 @@ if TYPE_CHECKING:
26
26
  from .core.types import UPathStr
27
27
 
28
28
 
29
- def get_schema_module_name(schema_name) -> str:
29
+ def get_schema_module_name(schema_name, raise_import_error: bool = True) -> str | None:
30
30
  import importlib.util
31
31
 
32
32
  name_attempts = [f"lnschema_{schema_name.replace('-', '_')}", schema_name]
@@ -34,9 +34,11 @@ def get_schema_module_name(schema_name) -> str:
34
34
  module_spec = importlib.util.find_spec(name)
35
35
  if module_spec is not None:
36
36
  return name
37
- raise ImportError(
38
- f"Python package for '{schema_name}' is not installed.\nIf your package is on PyPI, run `pip install {schema_name}`"
39
- )
37
+ message = f"Schema module '{schema_name}' is not installed → no access to its labels & registries (resolve via `pip install {schema_name}`)"
38
+ if raise_import_error:
39
+ raise ImportError(message)
40
+ logger.warning(message.lower())
41
+ return None
40
42
 
41
43
 
42
44
  def register_storage_in_instance(ssettings: StorageSettings):
@@ -180,6 +182,8 @@ def validate_init_args(
180
182
  validate_schema_arg,
181
183
  )
182
184
 
185
+ if storage is None:
186
+ raise SystemExit("✗ `storage` argument can't be `None`")
183
187
  # should be called as the first thing
184
188
  name_str = infer_instance_name(storage=storage, name=name, db=db)
185
189
  owner_str = settings.user.handle if _user is None else _user.handle
@@ -206,10 +210,18 @@ def validate_init_args(
206
210
  return name_str, instance_id, instance_state, instance_slug
207
211
 
208
212
 
209
- MESSAGE_NO_MULTIPLE_INSTANCE = """
210
- Currently don't support subsequent connection to different databases in the same
211
- Python session.\n
212
- Try running on the CLI: lamin settings set auto-connect false
213
+ class CannotSwitchDefaultInstance(SystemExit):
214
+ pass
215
+
216
+
217
+ MESSAGE_CANNOT_SWITCH_DEFAULT_INSTANCE = """
218
+ You cannot write to different instances in the same Python session.
219
+
220
+ Do you want to read from another instance via `Record.using()`? For example:
221
+
222
+ ln.Artifact.using("laminlabs/cellxgene").filter()
223
+
224
+ Or do you want to switch off auto-connect via `lamin settings set auto-connect false`?
213
225
  """
214
226
 
215
227
 
@@ -248,7 +260,7 @@ def init(
248
260
  from ._check_setup import _check_instance_setup
249
261
 
250
262
  if _check_instance_setup() and not _test:
251
- raise RuntimeError(MESSAGE_NO_MULTIPLE_INSTANCE)
263
+ raise CannotSwitchDefaultInstance(MESSAGE_CANNOT_SWITCH_DEFAULT_INSTANCE)
252
264
  elif _write_settings:
253
265
  close_instance(mute=True)
254
266
  from .core._hub_core import init_instance as init_instance_hub
@@ -48,14 +48,14 @@ def load_user(email: str | None = None, handle: str | None = None) -> UserSettin
48
48
 
49
49
 
50
50
  def login(
51
- user: str | None = None, *, key: str | None = None, api_key: str | None = None
51
+ user: str | None = None, *, api_key: str | None = None, key: str | None = None
52
52
  ) -> None:
53
53
  """Log in user.
54
54
 
55
55
  Args:
56
56
  user: handle or email
57
- key: API key
58
- api_key: Beta API key
57
+ api_key: API key
58
+ key: legacy API key
59
59
  """
60
60
  if user is None and api_key is None:
61
61
  if "LAMIN_API_KEY" in os.environ:
@@ -10,6 +10,8 @@ from pydantic_settings import BaseSettings
10
10
  from supabase import Client, create_client # type: ignore
11
11
  from supabase.lib.client_options import ClientOptions
12
12
 
13
+ from ._settings_save import save_user_settings
14
+
13
15
 
14
16
  class Connector(BaseSettings):
15
17
  url: str
@@ -129,14 +131,17 @@ def call_with_fallback_auth(
129
131
 
130
132
  for renew_token, fallback_env in [(False, False), (True, False), (False, True)]:
131
133
  try:
132
- if renew_token:
133
- logger.warning(
134
- "renewing expired lamin token: call `lamin login <your-handle>` to avoid this"
135
- )
136
134
  client = connect_hub_with_auth(
137
135
  renew_token=renew_token, fallback_env=fallback_env
138
136
  )
139
137
  result = callable(**kwargs, client=client)
138
+ # we update access_token here
139
+ # because at this point the call has been successfully resolved
140
+ if renew_token:
141
+ from lamindb_setup import settings
142
+
143
+ # here settings.user contains an updated access_token
144
+ save_user_settings(settings.user)
140
145
  break
141
146
  # we use Exception here as the ways in which the client fails upon 401
142
147
  # are not consistent and keep changing
@@ -161,6 +161,15 @@ class SetupSettings:
161
161
  cache_dir.mkdir(parents=True, exist_ok=True)
162
162
  return cache_dir
163
163
 
164
+ @property
165
+ def paths(self) -> type[SetupPaths]:
166
+ """Convert cloud paths to lamidb local paths.
167
+
168
+ Use `settings.paths.cloud_to_local_no_update`
169
+ or `settings.paths.cloud_to_local`.
170
+ """
171
+ return SetupPaths
172
+
164
173
  def __repr__(self) -> str:
165
174
  """Rich string representation."""
166
175
  repr = self.user.__repr__()
@@ -174,6 +183,38 @@ class SetupSettings:
174
183
  return repr
175
184
 
176
185
 
186
+ class SetupPaths:
187
+ """A static class for conversion of cloud paths to lamindb local paths."""
188
+
189
+ @staticmethod
190
+ def cloud_to_local_no_update(
191
+ filepath: UPathStr, cache_key: str | None = None
192
+ ) -> UPath:
193
+ """Local (or local cache) filepath from filepath without synchronization."""
194
+ # cache_key is ignored if filepath is a string or a local path
195
+ # ignores a mere string even if it represents a cloud path
196
+ if isinstance(filepath, UPath) and not isinstance(filepath, LocalPathClasses):
197
+ # settings is defined further in this file
198
+ local_filepath = settings.cache_dir / (
199
+ filepath.path if cache_key is None else cache_key
200
+ )
201
+ else:
202
+ local_filepath = filepath
203
+ return UPath(local_filepath)
204
+
205
+ @staticmethod
206
+ def cloud_to_local(
207
+ filepath: UPathStr, cache_key: str | None = None, **kwargs
208
+ ) -> UPath:
209
+ """Local (or local cache) filepath from filepath."""
210
+ # cache_key is ignored in cloud_to_local_no_update if filepath is local or a string
211
+ local_filepath = SetupPaths.cloud_to_local_no_update(filepath, cache_key)
212
+ if isinstance(filepath, UPath) and not isinstance(filepath, LocalPathClasses):
213
+ local_filepath.parent.mkdir(parents=True, exist_ok=True)
214
+ filepath.synchronize(local_filepath, **kwargs)
215
+ return local_filepath
216
+
217
+
177
218
  def get_env_name():
178
219
  if "LAMIN_ENV" in os.environ:
179
220
  return os.environ["LAMIN_ENV"]
@@ -85,8 +85,8 @@ def init_storage(
85
85
  StorageSettings,
86
86
  Literal["hub-record-not-created", "hub-record-retireved", "hub-record-created"],
87
87
  ]:
88
- if root is None:
89
- raise ValueError("`storage` argument can't be `None`")
88
+ assert root is not None, "`root` argument can't be `None`"
89
+
90
90
  root_str = str(root) # ensure we have a string
91
91
  if ".lamindb" in root_str:
92
92
  raise ValueError(
@@ -322,24 +322,20 @@ class StorageSettings:
322
322
  self, filepath: UPathStr, cache_key: str | None = None, **kwargs
323
323
  ) -> UPath:
324
324
  """Local (or local cache) filepath from filepath."""
325
- # cache_key is ignored in cloud_to_local_no_update if filepath is local
326
- local_filepath = self.cloud_to_local_no_update(filepath, cache_key)
327
- if isinstance(filepath, UPath) and not isinstance(filepath, LocalPathClasses):
328
- local_filepath.parent.mkdir(parents=True, exist_ok=True)
329
- filepath.synchronize(local_filepath, **kwargs)
330
- return local_filepath
325
+ from lamindb_setup import settings
326
+
327
+ return settings.paths.cloud_to_local(
328
+ filepath=filepath, cache_key=cache_key, **kwargs
329
+ )
331
330
 
332
331
  def cloud_to_local_no_update(
333
332
  self, filepath: UPathStr, cache_key: str | None = None
334
333
  ) -> UPath:
335
- # cache_key is ignored if filepath is local
336
- if isinstance(filepath, UPath) and not isinstance(filepath, LocalPathClasses):
337
- local_filepath = self.cache_dir / (
338
- filepath.path if cache_key is None else cache_key
339
- )
340
- else:
341
- local_filepath = filepath
342
- return UPath(local_filepath)
334
+ from lamindb_setup import settings
335
+
336
+ return settings.paths.cloud_to_local_no_update(
337
+ filepath=filepath, cache_key=cache_key
338
+ )
343
339
 
344
340
  def key_to_filepath(self, filekey: UPathStr) -> UPath:
345
341
  """Cloud or local filepath from filekey."""
@@ -24,9 +24,9 @@ class UserSettings:
24
24
  email: str | None = None
25
25
  """User email."""
26
26
  api_key: str | None = None
27
- """Beta API key."""
27
+ """API key."""
28
28
  password: str | None = None
29
- """API key or legacy password."""
29
+ """legacy API key or legacy password."""
30
30
  access_token: str | None = None
31
31
  """User access token."""
32
32
  uid: str = "null"
@@ -55,7 +55,17 @@ def setup_django(
55
55
  from .._init_instance import get_schema_module_name
56
56
 
57
57
  schema_names = ["core"] + list(isettings.schema)
58
- installed_apps = [get_schema_module_name(n) for n in schema_names]
58
+ raise_import_error = True if init else False
59
+ installed_apps = [
60
+ package_name
61
+ for n in schema_names
62
+ if (
63
+ package_name := get_schema_module_name(
64
+ n, raise_import_error=raise_import_error
65
+ )
66
+ )
67
+ is not None
68
+ ]
59
69
  if view_schema:
60
70
  installed_apps = installed_apps[::-1] # to fix how apps appear
61
71
  installed_apps += ["schema_graph", "django.contrib.staticfiles"]
@@ -763,13 +763,9 @@ def check_storage_is_empty(
763
763
  if raise_error
764
764
  else "consider deleting them"
765
765
  )
766
- hint = "'_is_initialized'"
767
- if n_offset_objects == 2:
768
- hint += " & SQLite file"
769
- hint += " ignored"
770
766
  message = (
771
- f"Storage {directory_string} contains {n_objects - n_offset_objects} objects "
772
- f"({hint}) - {ask_for_deletion}"
767
+ f"Storage '{directory_string}' contains {n_objects - n_offset_objects} objects"
768
+ f" - {ask_for_deletion}"
773
769
  )
774
770
  if n_diff > 0:
775
771
  if raise_error:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: lamindb_setup
3
- Version: 0.78.0
3
+ Version: 0.80.0
4
4
  Summary: Setup & configure LaminDB.
5
5
  Author-email: Lamin Labs <open-source@lamin.ai>
6
6
  Requires-Python: >=3.9
@@ -1,47 +1,47 @@
1
- lamindb_setup/__init__.py,sha256=1cQI4LfbQGWZfXA1PJS8wEvzt5kSbcuQVuUuJz9sJkg,1714
1
+ lamindb_setup/__init__.py,sha256=hCbASHI6nzxl7Xre0B3sTSQaCJ5mWkjI2xSF2odlJ8Q,1714
2
2
  lamindb_setup/_cache.py,sha256=1XnM-V_KprbjpgPY7Bg3FYn53Iz_2_fEgcMOaSdKKbg,1332
3
3
  lamindb_setup/_check.py,sha256=28PcG8Kp6OpjSLSi1r2boL2Ryeh6xkaCL87HFbjs6GA,129
4
4
  lamindb_setup/_check_setup.py,sha256=6cSfpmVOSgU7YiVHfJpBTGTQ7rrnwunt1pJT_jkgNM8,3196
5
5
  lamindb_setup/_close.py,sha256=cXNwK7QTTyNFt2XTpLnO3KHljJ7ShOcISk95np_dltE,1239
6
- lamindb_setup/_connect_instance.py,sha256=RvH3wR1B82FqMSSe1dzq5ZpnIeERCBU3ttZ8zVlIzPI,15951
6
+ lamindb_setup/_connect_instance.py,sha256=ClSM1zQAqVmNBapmB7H3dzmnWdn1dkpr_y5HAsF74XU,16070
7
7
  lamindb_setup/_delete.py,sha256=yjLIegM2Lh6sWRSTTybI17wK_kA4_pF_k3iVUkkgEAE,5681
8
8
  lamindb_setup/_django.py,sha256=DWUTjjVhEViX0S-zIkeqQgKovWqVgWMl4Y0ANwlA3Pw,1505
9
9
  lamindb_setup/_entry_points.py,sha256=Hs2oJQOCTaGUdWn-1mufM6qUZr9W_EJ_Oc3f0_Vc0Yw,616
10
10
  lamindb_setup/_exportdb.py,sha256=43g77-tH-vAlTn8ig1mMD9-KXLKvxUeDLaq0gVu3l-c,2114
11
11
  lamindb_setup/_importdb.py,sha256=yYYShzUajTsR-cTW4CZ-UNDWZY2uE5PAgNbp-wn8Ogc,1874
12
- lamindb_setup/_init_instance.py,sha256=A7rvd6Btzu0i57OrY58OEFCsjHNCmWNO2hiMqq-cZiM,13885
12
+ lamindb_setup/_init_instance.py,sha256=6Db289T2A2464KqW0NsfSKg59zrhfny9RZxBgb9kPVs,14340
13
13
  lamindb_setup/_migrate.py,sha256=x_b4k4XRfLSD-EEFMc324yK6DIK7goW33wUytbIWlNs,8917
14
14
  lamindb_setup/_register_instance.py,sha256=alQuYp2f8Ct8xvRC1gt8p_HZ0tqCd3gZD3kiPBLPpsI,1269
15
15
  lamindb_setup/_schema.py,sha256=b3uzhhWpV5mQtDwhMINc2MabGCnGLESy51ito3yl6Wc,679
16
16
  lamindb_setup/_schema_metadata.py,sha256=49wDLbhRhatDeADjHOPfQURt65lf_OZ7lob1ZiAT_ac,13773
17
17
  lamindb_setup/_set_managed_storage.py,sha256=4tDxXQMt8Gw028uY3vIQxZQ7qBNXhQMc8saarNK_Z-s,2043
18
- lamindb_setup/_setup_user.py,sha256=LB1MuhMZRpkCJBjvM7U656r1QnYFioJx7QQwxsf-CqY,4584
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
21
21
  lamindb_setup/core/_aws_credentials.py,sha256=uKMQO9q42Hnepz8aj3RxwLKDWUJx8pNOYrFnnNh5X40,5325
22
22
  lamindb_setup/core/_aws_storage.py,sha256=nEjeUv4xUVpoV0Lx-zjjmyb9w804bDyaeiM-OqbfwM0,1799
23
23
  lamindb_setup/core/_deprecated.py,sha256=3qxUI1dnDlSeR0BYrv7ucjqRBEojbqotPgpShXs4KF8,2520
24
24
  lamindb_setup/core/_docs.py,sha256=3k-YY-oVaJd_9UIY-LfBg_u8raKOCNfkZQPA73KsUhs,276
25
- lamindb_setup/core/_hub_client.py,sha256=P11Ma0nDsBHlKcnyOmq75dHDzYYJfmfpTePJ-0348Wo,6117
25
+ lamindb_setup/core/_hub_client.py,sha256=cN19XbZmvLCxL_GKdOcKbedNRL7kR47vmLmA--NMv-U,6306
26
26
  lamindb_setup/core/_hub_core.py,sha256=eUxRz9iJj6RA5-MWgQqqZYAU-di5LQDamRZn6t-VOiM,19838
27
27
  lamindb_setup/core/_hub_crud.py,sha256=eZErpq9t1Cp2ULBSi457ekrcqfesw4Y6IJgaqyrINMY,5276
28
28
  lamindb_setup/core/_hub_utils.py,sha256=08NwQsb53-tXa_pr-f0tPTN0FeeVf_i1p3dEbEWD0F4,3016
29
29
  lamindb_setup/core/_private_django_api.py,sha256=KIn43HOhiRjkbTbddyJqv-WNTTa1bAizbM1tWXoXPBg,2869
30
- lamindb_setup/core/_settings.py,sha256=ZIcQ3aLNRsAkoaCmse9QuMc2atDWkiraApZn0ZMOWwQ,6128
30
+ lamindb_setup/core/_settings.py,sha256=Iv2FUz1l92V4AcuyvRsYlJxoY1oB-UB4gAaA6QgWioE,7792
31
31
  lamindb_setup/core/_settings_instance.py,sha256=ajcq9zRNE598tTqyMkMqaEOubVfFeE998DPtbgyzK3A,18801
32
32
  lamindb_setup/core/_settings_load.py,sha256=5OpghcbkrK9KBM_0Iu-61FTI76UbOpPkkJpUittXS-w,4098
33
33
  lamindb_setup/core/_settings_save.py,sha256=rxGxgaK5i9exKqSJERQQyY1WZio20meoQJoYXlVW-1w,3138
34
- lamindb_setup/core/_settings_storage.py,sha256=8uzC_OVzVL66Sa09QhHK1vYYRmFfnKUB7uxj1iRFArg,12330
34
+ lamindb_setup/core/_settings_storage.py,sha256=15B7taJF1zxJ1_qAb67NuXkTFvO2TRTWMt6KTzDf1mw,11875
35
35
  lamindb_setup/core/_settings_store.py,sha256=WcsgOmgnu9gztcrhp-N4OONNZyxICHV8M0HdJllTaEo,2219
36
- lamindb_setup/core/_settings_user.py,sha256=vmh8-SDJqlF4zRqAH2loS21_TEYWX4tiG-grQys6-0c,1474
36
+ lamindb_setup/core/_settings_user.py,sha256=iz0MqFLKXqm8LYx_CHmr02_oNvYWFLIxKkJLdpS5W08,1476
37
37
  lamindb_setup/core/_setup_bionty_sources.py,sha256=o2L5Ww8TKgSqJtL4cGUcpJwLNYxA9BZgddhCMCu_E2g,3428
38
38
  lamindb_setup/core/cloud_sqlite_locker.py,sha256=i6TrT7HG0lqliPvZTlsZ_uplPaqhPBbabyfeR32SkA8,7107
39
- lamindb_setup/core/django.py,sha256=GTWF0yV2tp7EnvPtOzIWbLuhTxmqaZAxq1xnwd54hho,3600
39
+ lamindb_setup/core/django.py,sha256=E4U9nUlV2kHd-G5v6iSdFGAAWixlQDxOFwMwOMG9xfw,3864
40
40
  lamindb_setup/core/exceptions.py,sha256=4NpLUNUIfXYVTFX2FvLZF8RW34exk2Vn2X3G4YhnTRg,276
41
41
  lamindb_setup/core/hashing.py,sha256=bkuvZyAuC7-Y_qZumJd_rybF-upJ5J3KxnKiymRUifw,3148
42
42
  lamindb_setup/core/types.py,sha256=zJii2le38BJUmsNVvzDrbzGYr0yaeb-9Rw9IKmsBr3k,523
43
- lamindb_setup/core/upath.py,sha256=EPLLm62q-Y3hZzd-286cynFMttXKDNXNOKL3_QGkeug,27215
44
- lamindb_setup-0.78.0.dist-info/LICENSE,sha256=UOZ1F5fFDe3XXvG4oNnkL1-Ecun7zpHzRxjp-XsMeAo,11324
45
- lamindb_setup-0.78.0.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81
46
- lamindb_setup-0.78.0.dist-info/METADATA,sha256=9cxGpRkLet-9MZj6c6SBEe-obH0lAFQiOQK6M1woQ_0,1743
47
- lamindb_setup-0.78.0.dist-info/RECORD,,
43
+ lamindb_setup/core/upath.py,sha256=DJ0S3JufnCmG6EAGy2eqTp5rVX3Oqw-bUlh9-9ipKYI,27091
44
+ lamindb_setup-0.80.0.dist-info/LICENSE,sha256=UOZ1F5fFDe3XXvG4oNnkL1-Ecun7zpHzRxjp-XsMeAo,11324
45
+ lamindb_setup-0.80.0.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81
46
+ lamindb_setup-0.80.0.dist-info/METADATA,sha256=IBWXhrRyGmMeYdgByW0TJV2h70cSVssuxA1Do6cmfLM,1743
47
+ lamindb_setup-0.80.0.dist-info/RECORD,,