lamindb_setup 1.3.0__tar.gz → 1.3.2__tar.gz
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-1.3.0 → lamindb_setup-1.3.2}/PKG-INFO +2 -2
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/docs/hub-prod/test-connect-anonymously-set-token.ipynb +3 -3
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/lamindb_setup/__init__.py +1 -1
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/lamindb_setup/_connect_instance.py +1 -1
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/lamindb_setup/_init_instance.py +14 -1
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/lamindb_setup/_migrate.py +26 -11
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/lamindb_setup/_register_instance.py +1 -2
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/lamindb_setup/core/_hub_client.py +34 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/lamindb_setup/core/_hub_core.py +39 -6
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/lamindb_setup/core/_settings_instance.py +5 -1
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/lamindb_setup/core/_settings_load.py +3 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/lamindb_setup/core/_settings_save.py +1 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/lamindb_setup/core/_settings_storage.py +2 -2
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/lamindb_setup/core/_settings_store.py +1 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/lamindb_setup/core/django.py +6 -1
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/noxfile.py +4 -2
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/pyproject.toml +1 -1
- lamindb_setup-1.3.2/tests/hub-local/scripts/script-connect-fine-grained-access.py +18 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/tests/hub-local/test_all.py +48 -4
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/tests/storage/test_storage_access.py +11 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/tests/storage/test_storage_stats.py +2 -2
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/.github/workflows/build.yml +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/.github/workflows/doc-changes.yml +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/.gitignore +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/.pre-commit-config.yaml +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/LICENSE +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/README.md +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/docs/changelog.md +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/docs/hub-cloud/01-init-local-instance.ipynb +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/docs/hub-cloud/02-connect-local-instance.ipynb +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/docs/hub-cloud/03-add-managed-storage.ipynb +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/docs/hub-cloud/04-test-bionty.ipynb +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/docs/hub-cloud/05-init-hosted-instance.ipynb +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/docs/hub-cloud/06-connect-hosted-instance.ipynb +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/docs/hub-cloud/07-keep-artifacts-local.ipynb +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/docs/hub-cloud/08-test-multi-session.ipynb +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/docs/hub-cloud/test_notebooks.py +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/docs/hub-prod/test-cache-management.ipynb +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/docs/hub-prod/test-cloud-sync.ipynb +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/docs/hub-prod/test-empty-init.ipynb +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/docs/hub-prod/test-import-schema.ipynb +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/docs/hub-prod/test-init-load-local-anonymously.ipynb +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/docs/hub-prod/test-insufficient-user-info.ipynb +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/docs/hub-prod/test-invalid-schema.ipynb +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/docs/hub-prod/test-sqlite-lock.ipynb +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/docs/hub-prod/test_notebooks2.py +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/docs/index.md +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/docs/notebooks.md +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/docs/reference.md +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/lamindb_setup/_cache.py +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/lamindb_setup/_check.py +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/lamindb_setup/_check_setup.py +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/lamindb_setup/_close.py +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/lamindb_setup/_delete.py +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/lamindb_setup/_django.py +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/lamindb_setup/_entry_points.py +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/lamindb_setup/_exportdb.py +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/lamindb_setup/_importdb.py +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/lamindb_setup/_schema.py +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/lamindb_setup/_schema_metadata.py +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/lamindb_setup/_set_managed_storage.py +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/lamindb_setup/_setup_user.py +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/lamindb_setup/_silence_loggers.py +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/lamindb_setup/core/__init__.py +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/lamindb_setup/core/_aws_options.py +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/lamindb_setup/core/_aws_storage.py +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/lamindb_setup/core/_deprecated.py +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/lamindb_setup/core/_docs.py +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/lamindb_setup/core/_hub_crud.py +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/lamindb_setup/core/_hub_utils.py +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/lamindb_setup/core/_private_django_api.py +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/lamindb_setup/core/_settings.py +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/lamindb_setup/core/_settings_user.py +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/lamindb_setup/core/_setup_bionty_sources.py +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/lamindb_setup/core/cloud_sqlite_locker.py +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/lamindb_setup/core/exceptions.py +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/lamindb_setup/core/hashing.py +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/lamindb_setup/core/types.py +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/lamindb_setup/core/upath.py +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/tests/hub-cloud/scripts/script-init-pass-user-no-writes.py +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/tests/hub-cloud/scripts/script-to-fail-managed-storage.py +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/tests/hub-cloud/test_connect_instance.py +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/tests/hub-cloud/test_delete_instance.py +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/tests/hub-cloud/test_edge_request.py +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/tests/hub-cloud/test_fail_managed_storage.py +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/tests/hub-cloud/test_init_instance.py +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/tests/hub-cloud/test_init_pass_user_no_writes.py +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/tests/hub-cloud/test_login.py +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/tests/hub-cloud/test_migrate.py +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/tests/hub-cloud/test_set_storage.py +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/tests/hub-local/conftest.py +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/tests/hub-local/test_update_schema_in_hub.py +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/tests/hub-prod/conftest.py +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/tests/hub-prod/test_aws_options_manager.py +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/tests/hub-prod/test_django.py +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/tests/hub-prod/test_global_settings.py +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/tests/hub-prod/test_switch_and_fallback_env.py +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/tests/hub-prod/test_upath.py +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/tests/storage/test_entry_point.py +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/tests/storage/test_hashing.py +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/tests/storage/test_storage_basis.py +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/tests/storage/test_storage_settings.py +0 -0
- {lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/tests/storage/test_to_url.py +0 -0
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: lamindb_setup
|
|
3
|
-
Version: 1.3.
|
|
3
|
+
Version: 1.3.2
|
|
4
4
|
Summary: Setup & configure LaminDB.
|
|
5
5
|
Author-email: Lamin Labs <open-source@lamin.ai>
|
|
6
6
|
Requires-Python: >=3.10
|
|
7
7
|
Description-Content-Type: text/markdown
|
|
8
8
|
Requires-Dist: lamin_utils>=0.3.3
|
|
9
|
-
Requires-Dist: django>=5,<5.2
|
|
9
|
+
Requires-Dist: django>=5.1,<5.2
|
|
10
10
|
Requires-Dist: dj_database_url>=1.3.0,<3.0.0
|
|
11
11
|
Requires-Dist: pydantic-settings
|
|
12
12
|
Requires-Dist: appdirs<2.0.0
|
{lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/docs/hub-prod/test-connect-anonymously-set-token.ipynb
RENAMED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"source": [
|
|
16
16
|
"import pytest\n",
|
|
17
17
|
"import lamindb_setup as ln_setup\n",
|
|
18
|
-
"from lamindb_setup.core.django import
|
|
18
|
+
"from lamindb_setup.core.django import set_db_token\n",
|
|
19
19
|
"from psycopg2.errors import UndefinedFunction"
|
|
20
20
|
]
|
|
21
21
|
},
|
|
@@ -55,10 +55,10 @@
|
|
|
55
55
|
"source": [
|
|
56
56
|
"# this just tests that the function is setup properly\n",
|
|
57
57
|
"# the actual functionality is tested in lamindb\n",
|
|
58
|
-
"
|
|
58
|
+
"set_db_token(None)\n",
|
|
59
59
|
"# set_token sql function is not defined\n",
|
|
60
60
|
"with pytest.raises(UndefinedFunction):\n",
|
|
61
|
-
"
|
|
61
|
+
" set_db_token(\"test\")"
|
|
62
62
|
]
|
|
63
63
|
},
|
|
64
64
|
{
|
|
@@ -168,6 +168,7 @@ def _connect_instance(
|
|
|
168
168
|
schema_id=None
|
|
169
169
|
if (schema_id := instance_result["schema_id"]) is None
|
|
170
170
|
else UUID(schema_id),
|
|
171
|
+
fine_grained_access=instance_result.get("fine_grained_access", False),
|
|
171
172
|
)
|
|
172
173
|
else:
|
|
173
174
|
if hub_result != "anonymous-user":
|
|
@@ -205,7 +206,6 @@ def connect(instance: str | None = None, **kwargs) -> str | tuple | None:
|
|
|
205
206
|
for kwarg in kwargs:
|
|
206
207
|
if kwarg not in valid_kwargs:
|
|
207
208
|
raise TypeError(f"connect() got unexpected keyword argument '{kwarg}'")
|
|
208
|
-
|
|
209
209
|
isettings: InstanceSettings = None # type: ignore
|
|
210
210
|
# _db is still needed because it is called in init
|
|
211
211
|
_db: str | None = kwargs.get("_db", None)
|
|
@@ -6,6 +6,7 @@ import uuid
|
|
|
6
6
|
from typing import TYPE_CHECKING, Literal
|
|
7
7
|
from uuid import UUID
|
|
8
8
|
|
|
9
|
+
import click
|
|
9
10
|
from django.core.exceptions import FieldError
|
|
10
11
|
from django.db.utils import OperationalError, ProgrammingError
|
|
11
12
|
from lamin_utils import logger
|
|
@@ -25,6 +26,11 @@ if TYPE_CHECKING:
|
|
|
25
26
|
from .core.types import UPathStr
|
|
26
27
|
|
|
27
28
|
|
|
29
|
+
class InstanceNotCreated(click.ClickException):
|
|
30
|
+
def show(self, file=None):
|
|
31
|
+
pass
|
|
32
|
+
|
|
33
|
+
|
|
28
34
|
def get_schema_module_name(module_name, raise_import_error: bool = True) -> str | None:
|
|
29
35
|
import importlib.util
|
|
30
36
|
|
|
@@ -242,7 +248,7 @@ def init(
|
|
|
242
248
|
raise CannotSwitchDefaultInstance(MESSAGE_CANNOT_SWITCH_DEFAULT_INSTANCE)
|
|
243
249
|
elif _write_settings:
|
|
244
250
|
close_instance(mute=True)
|
|
245
|
-
from .core._hub_core import
|
|
251
|
+
from .core._hub_core import init_instance_hub
|
|
246
252
|
|
|
247
253
|
name_str, instance_id, instance_state, _ = validate_init_args(
|
|
248
254
|
storage=storage,
|
|
@@ -284,6 +290,13 @@ def init(
|
|
|
284
290
|
isettings.is_remote and instance_state != "instance-corrupted-or-deleted"
|
|
285
291
|
)
|
|
286
292
|
if register_on_hub:
|
|
293
|
+
# can't register the instance in the hub
|
|
294
|
+
# if storage is not in the hub
|
|
295
|
+
# raise the exception and initiate cleanups
|
|
296
|
+
if not isettings.storage.is_on_hub:
|
|
297
|
+
raise InstanceNotCreated(
|
|
298
|
+
"Unable to create the instance because failed to register the storage."
|
|
299
|
+
)
|
|
287
300
|
init_instance_hub(
|
|
288
301
|
isettings, account_id=user__uuid, access_token=access_token
|
|
289
302
|
)
|
|
@@ -23,29 +23,44 @@ def check_whether_migrations_in_sync(db_version_str: str):
|
|
|
23
23
|
return None
|
|
24
24
|
installed_version = version.parse(installed_version_str)
|
|
25
25
|
db_version = version.parse(db_version_str)
|
|
26
|
-
if installed_version.major < db_version.major
|
|
26
|
+
if installed_version.major < db_version.major:
|
|
27
|
+
logger.warning(
|
|
28
|
+
f"the database ({db_version_str}) is far ahead of your installed lamindb package ({installed_version_str})"
|
|
29
|
+
)
|
|
30
|
+
logger.important(
|
|
31
|
+
f"please update lamindb: pip install lamindb>={db_version.major}"
|
|
32
|
+
)
|
|
33
|
+
elif (
|
|
27
34
|
installed_version.major == db_version.major
|
|
28
35
|
and installed_version.minor < db_version.minor
|
|
29
36
|
):
|
|
30
37
|
db_version_lower = f"{db_version.major}.{db_version.minor}"
|
|
31
|
-
|
|
32
|
-
logger.warning(
|
|
38
|
+
logger.important(
|
|
33
39
|
f"the database ({db_version_str}) is ahead of your installed lamindb"
|
|
34
40
|
f" package ({installed_version_str})"
|
|
35
41
|
)
|
|
36
42
|
logger.important(
|
|
37
|
-
"
|
|
38
|
-
f' "lamindb>={db_version_lower},<{db_version_upper}"'
|
|
43
|
+
f"consider updating lamindb: pip install lamindb>={db_version_lower}"
|
|
39
44
|
)
|
|
40
|
-
elif installed_version.major > db_version.major
|
|
41
|
-
installed_version.major == db_version.major
|
|
42
|
-
and installed_version.minor > db_version.minor
|
|
43
|
-
):
|
|
45
|
+
elif installed_version.major > db_version.major:
|
|
44
46
|
logger.warning(
|
|
45
|
-
f"the database ({db_version_str}) is behind your installed lamindb package"
|
|
47
|
+
f"the database ({db_version_str}) is far behind your installed lamindb package"
|
|
46
48
|
f" ({installed_version_str})"
|
|
47
49
|
)
|
|
48
|
-
logger.important(
|
|
50
|
+
logger.important(
|
|
51
|
+
"if you are an admin, migrate your database: lamin migrate deploy"
|
|
52
|
+
)
|
|
53
|
+
elif (
|
|
54
|
+
installed_version.major == db_version.major
|
|
55
|
+
and installed_version.minor > db_version.minor
|
|
56
|
+
):
|
|
57
|
+
pass
|
|
58
|
+
# if the database is behind by a minor version, we don't want to spam the user
|
|
59
|
+
# logger.important(
|
|
60
|
+
# f"the database ({db_version_str}) is behind your installed lamindb package"
|
|
61
|
+
# f" ({installed_version_str})"
|
|
62
|
+
# )
|
|
63
|
+
# logger.important("consider migrating your database: lamin migrate deploy")
|
|
49
64
|
|
|
50
65
|
|
|
51
66
|
# for tests, see lamin-cli
|
|
@@ -10,8 +10,7 @@ from .core.django import setup_django
|
|
|
10
10
|
def register(_test: bool = False):
|
|
11
11
|
"""Register an instance on the hub."""
|
|
12
12
|
from ._check_setup import _check_instance_setup
|
|
13
|
-
from .core._hub_core import
|
|
14
|
-
from .core._hub_core import init_storage as init_storage_hub
|
|
13
|
+
from .core._hub_core import init_instance_hub, init_storage_hub
|
|
15
14
|
|
|
16
15
|
logger.warning("""lamin register will be removed soon""")
|
|
17
16
|
|
|
@@ -180,3 +180,37 @@ def call_with_fallback(
|
|
|
180
180
|
except NameError:
|
|
181
181
|
pass
|
|
182
182
|
return result
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def requests_client():
|
|
186
|
+
# local is used in tests
|
|
187
|
+
if os.environ.get("LAMIN_ENV", "prod") == "local":
|
|
188
|
+
from fastapi.testclient import TestClient
|
|
189
|
+
from laminhub_rest.main import app
|
|
190
|
+
|
|
191
|
+
return TestClient(app)
|
|
192
|
+
|
|
193
|
+
import requests # type: ignore
|
|
194
|
+
|
|
195
|
+
return requests
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def request_get_auth(url: str, access_token: str, renew_token: bool = True):
|
|
199
|
+
requests = requests_client()
|
|
200
|
+
|
|
201
|
+
response = requests.get(url, headers={"Authorization": f"Bearer {access_token}"})
|
|
202
|
+
# upate access_token and try again if failed
|
|
203
|
+
if response.status_code != 200 and renew_token:
|
|
204
|
+
from lamindb_setup import settings
|
|
205
|
+
|
|
206
|
+
access_token = get_access_token(
|
|
207
|
+
settings.user.email, settings.user.password, settings.user.api_key
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
settings.user.access_token = access_token
|
|
211
|
+
save_user_settings(settings.user)
|
|
212
|
+
|
|
213
|
+
response = requests.get(
|
|
214
|
+
url, headers={"Authorization": f"Bearer {access_token}"}
|
|
215
|
+
)
|
|
216
|
+
return response
|
|
@@ -16,6 +16,7 @@ from ._hub_client import (
|
|
|
16
16
|
call_with_fallback,
|
|
17
17
|
call_with_fallback_auth,
|
|
18
18
|
connect_hub,
|
|
19
|
+
request_get_auth,
|
|
19
20
|
)
|
|
20
21
|
from ._hub_crud import (
|
|
21
22
|
_delete_instance_record,
|
|
@@ -115,7 +116,7 @@ def _select_storage(
|
|
|
115
116
|
return True
|
|
116
117
|
|
|
117
118
|
|
|
118
|
-
def
|
|
119
|
+
def init_storage_hub(
|
|
119
120
|
ssettings: StorageSettings,
|
|
120
121
|
auto_populate_instance: bool = True,
|
|
121
122
|
created_by: UUID | None = None,
|
|
@@ -123,7 +124,7 @@ def init_storage(
|
|
|
123
124
|
) -> Literal["hub-record-retireved", "hub-record-created"]:
|
|
124
125
|
if settings.user.handle != "anonymous" or access_token is not None:
|
|
125
126
|
return call_with_fallback_auth(
|
|
126
|
-
|
|
127
|
+
_init_storage_hub,
|
|
127
128
|
ssettings=ssettings,
|
|
128
129
|
auto_populate_instance=auto_populate_instance,
|
|
129
130
|
created_by=created_by,
|
|
@@ -139,7 +140,7 @@ def init_storage(
|
|
|
139
140
|
raise ValueError("Log in to create a storage location on the hub.")
|
|
140
141
|
|
|
141
142
|
|
|
142
|
-
def
|
|
143
|
+
def _init_storage_hub(
|
|
143
144
|
client: Client,
|
|
144
145
|
ssettings: StorageSettings,
|
|
145
146
|
auto_populate_instance: bool,
|
|
@@ -269,20 +270,20 @@ def delete_instance_record(instance_id: UUID, access_token: str | None = None) -
|
|
|
269
270
|
)
|
|
270
271
|
|
|
271
272
|
|
|
272
|
-
def
|
|
273
|
+
def init_instance_hub(
|
|
273
274
|
isettings: InstanceSettings,
|
|
274
275
|
account_id: UUID | None = None,
|
|
275
276
|
access_token: str | None = None,
|
|
276
277
|
) -> None:
|
|
277
278
|
return call_with_fallback_auth(
|
|
278
|
-
|
|
279
|
+
_init_instance_hub,
|
|
279
280
|
isettings=isettings,
|
|
280
281
|
account_id=account_id,
|
|
281
282
|
access_token=access_token,
|
|
282
283
|
)
|
|
283
284
|
|
|
284
285
|
|
|
285
|
-
def
|
|
286
|
+
def _init_instance_hub(
|
|
286
287
|
client: Client, isettings: InstanceSettings, account_id: UUID | None = None
|
|
287
288
|
) -> None:
|
|
288
289
|
from ._settings import settings
|
|
@@ -437,6 +438,38 @@ def _access_aws(*, storage_root: str, client: Client) -> dict[str, dict]:
|
|
|
437
438
|
return storage_root_info
|
|
438
439
|
|
|
439
440
|
|
|
441
|
+
def access_db(isettings: InstanceSettings, access_token: str | None = None) -> str:
|
|
442
|
+
if access_token is None:
|
|
443
|
+
if settings.user.handle == "anonymous":
|
|
444
|
+
raise RuntimeError(
|
|
445
|
+
f"Can only get fine-grained access to {isettings.slug} if authenticated."
|
|
446
|
+
)
|
|
447
|
+
else:
|
|
448
|
+
access_token = settings.user.access_token
|
|
449
|
+
renew_token = True
|
|
450
|
+
else:
|
|
451
|
+
renew_token = False
|
|
452
|
+
# local is used in tests
|
|
453
|
+
url = f"/access_v2/instances/{isettings._id}/db_token"
|
|
454
|
+
if os.environ.get("LAMIN_ENV", "prod") != "local":
|
|
455
|
+
api_url = isettings._api_url
|
|
456
|
+
if api_url is None:
|
|
457
|
+
raise RuntimeError(
|
|
458
|
+
f"Can only get fine-grained access to {isettings.slug} if api_url is present."
|
|
459
|
+
)
|
|
460
|
+
url = api_url + url
|
|
461
|
+
|
|
462
|
+
response = request_get_auth(url, access_token, renew_token) # type: ignore
|
|
463
|
+
response_json = response.json()
|
|
464
|
+
if response.status_code != 200:
|
|
465
|
+
raise PermissionError(
|
|
466
|
+
f"Fine-grained access to {isettings.slug} failed: {response_json}"
|
|
467
|
+
)
|
|
468
|
+
if "token" not in response_json:
|
|
469
|
+
raise RuntimeError("The response of access_db does not contain a db token.")
|
|
470
|
+
return response_json["token"]
|
|
471
|
+
|
|
472
|
+
|
|
440
473
|
def get_lamin_site_base_url():
|
|
441
474
|
if "LAMIN_ENV" in os.environ:
|
|
442
475
|
if os.environ["LAMIN_ENV"] == "local":
|
|
@@ -59,6 +59,7 @@ class InstanceSettings:
|
|
|
59
59
|
is_on_hub: bool | None = None, # initialized from hub
|
|
60
60
|
api_url: str | None = None,
|
|
61
61
|
schema_id: UUID | None = None,
|
|
62
|
+
fine_grained_access: bool = False,
|
|
62
63
|
_locker_user: UserSettings | None = None, # user to lock for if cloud sqlite
|
|
63
64
|
):
|
|
64
65
|
from ._hub_utils import validate_db_arg
|
|
@@ -76,9 +77,12 @@ class InstanceSettings:
|
|
|
76
77
|
self._keep_artifacts_local = keep_artifacts_local
|
|
77
78
|
self._storage_local: StorageSettings | None = None
|
|
78
79
|
self._is_on_hub = is_on_hub
|
|
79
|
-
# private, needed for
|
|
80
|
+
# private, needed for api requests
|
|
80
81
|
self._api_url = api_url
|
|
81
82
|
self._schema_id = schema_id
|
|
83
|
+
# private, whether fine grained access is used
|
|
84
|
+
# needed to be set to request jwt etc
|
|
85
|
+
self._fine_grained_access = fine_grained_access
|
|
82
86
|
# if None then settings.user is used
|
|
83
87
|
self._locker_user = _locker_user
|
|
84
88
|
|
|
@@ -101,6 +101,9 @@ def setup_instance_from_store(store: InstanceSettingsStore) -> InstanceSettings:
|
|
|
101
101
|
modules=_null_to_value(store.schema_str),
|
|
102
102
|
git_repo=_null_to_value(store.git_repo),
|
|
103
103
|
keep_artifacts_local=store.keep_artifacts_local, # type: ignore
|
|
104
|
+
api_url=_null_to_value(store.api_url),
|
|
105
|
+
schema_id=None if store.schema_id == "null" else UUID(store.schema_id),
|
|
106
|
+
fine_grained_access=store.fine_grained_access,
|
|
104
107
|
)
|
|
105
108
|
|
|
106
109
|
|
|
@@ -150,8 +150,7 @@ def init_storage(
|
|
|
150
150
|
# the below might update the uid with one that's already taken on the hub
|
|
151
151
|
if not prevent_register_hub:
|
|
152
152
|
if ssettings.type_is_cloud or register_hub:
|
|
153
|
-
from ._hub_core import delete_storage_record
|
|
154
|
-
from ._hub_core import init_storage as init_storage_hub
|
|
153
|
+
from ._hub_core import delete_storage_record, init_storage_hub
|
|
155
154
|
|
|
156
155
|
hub_record_status = init_storage_hub(
|
|
157
156
|
ssettings,
|
|
@@ -175,6 +174,7 @@ def init_storage(
|
|
|
175
174
|
# only newly created
|
|
176
175
|
if hub_record_status == "hub-record-created" and ssettings._uuid is not None:
|
|
177
176
|
delete_storage_record(ssettings._uuid, access_token=access_token) # type: ignore
|
|
177
|
+
ssettings._uuid_ = None
|
|
178
178
|
hub_record_status = "hub-record-not-created"
|
|
179
179
|
ssettings._instance_id = None
|
|
180
180
|
return ssettings, hub_record_status
|
|
@@ -57,6 +57,7 @@ class InstanceSettingsStore(BaseSettings):
|
|
|
57
57
|
db: Optional[str] # doesn't like new types on 3.9 even with future annotations
|
|
58
58
|
schema_str: Optional[str]
|
|
59
59
|
schema_id: Optional[str] = None
|
|
60
|
+
fine_grained_access: bool = False
|
|
60
61
|
id: str
|
|
61
62
|
git_repo: Optional[str]
|
|
62
63
|
keep_artifacts_local: Optional[bool]
|
|
@@ -14,7 +14,7 @@ IS_MIGRATING = False
|
|
|
14
14
|
CONN_MAX_AGE = 299
|
|
15
15
|
|
|
16
16
|
|
|
17
|
-
def
|
|
17
|
+
def set_db_token(token: str | None, connection_name: str = "default"):
|
|
18
18
|
# None to reset
|
|
19
19
|
from django.db import connections
|
|
20
20
|
from django.db.backends.base.base import BaseDatabaseWrapper
|
|
@@ -125,6 +125,11 @@ 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:
|
|
129
|
+
from ._hub_core import access_db
|
|
130
|
+
|
|
131
|
+
set_db_token(access_db(isettings))
|
|
132
|
+
|
|
128
133
|
if configure_only:
|
|
129
134
|
return None
|
|
130
135
|
|
|
@@ -52,7 +52,9 @@ uv pip install --system git+https://github.com/laminlabs/bionty
|
|
|
52
52
|
|
|
53
53
|
# above downgrades django, I don't understand why, try this
|
|
54
54
|
if group == "hub-local":
|
|
55
|
-
cmds +=
|
|
55
|
+
cmds += (
|
|
56
|
+
"\nuv pip install --system -e ./laminhub/rest-hub line_profiler sentry_sdk"
|
|
57
|
+
)
|
|
56
58
|
|
|
57
59
|
run(session, "uv pip install --system pandera") # needed to import lamindb
|
|
58
60
|
[run(session, line) for line in cmds.splitlines()]
|
|
@@ -85,7 +87,7 @@ def hub_local(session: nox.Session):
|
|
|
85
87
|
# the -n 1 is to ensure that supabase thread exits properly
|
|
86
88
|
run(
|
|
87
89
|
session,
|
|
88
|
-
f"pytest
|
|
90
|
+
f"pytest {COVERAGE_ARGS} ./tests/hub-local",
|
|
89
91
|
env=os.environ,
|
|
90
92
|
)
|
|
91
93
|
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
3
|
+
import lamindb_setup as ln_setup
|
|
4
|
+
import pytest
|
|
5
|
+
from lamindb_setup.core._hub_core import access_db
|
|
6
|
+
|
|
7
|
+
assert os.environ["LAMIN_ENV"] == "local"
|
|
8
|
+
|
|
9
|
+
ln_setup.connect("instance_access_v2")
|
|
10
|
+
|
|
11
|
+
assert ln_setup.settings.instance._fine_grained_access
|
|
12
|
+
|
|
13
|
+
# check calling access_db with anonymous user
|
|
14
|
+
ln_setup.settings.user.handle = "anonymous"
|
|
15
|
+
with pytest.raises(RuntimeError):
|
|
16
|
+
access_db(ln_setup.settings.instance)
|
|
17
|
+
# check with providing access_token explicitly
|
|
18
|
+
access_db(ln_setup.settings.instance, ln_setup.settings.user.access_token)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import os
|
|
4
|
+
import subprocess
|
|
4
5
|
from uuid import UUID, uuid4
|
|
5
6
|
|
|
6
7
|
import lamindb_setup as ln_setup
|
|
@@ -13,9 +14,10 @@ from lamindb_setup.core._hub_client import (
|
|
|
13
14
|
)
|
|
14
15
|
from lamindb_setup.core._hub_core import (
|
|
15
16
|
_connect_instance_hub,
|
|
17
|
+
access_db,
|
|
16
18
|
connect_instance_hub,
|
|
17
|
-
|
|
18
|
-
|
|
19
|
+
init_instance_hub,
|
|
20
|
+
init_storage_hub,
|
|
19
21
|
sign_in_hub,
|
|
20
22
|
sign_up_local_hub,
|
|
21
23
|
)
|
|
@@ -35,8 +37,14 @@ from lamindb_setup.core._settings_instance import InstanceSettings
|
|
|
35
37
|
from lamindb_setup.core._settings_save import save_user_settings
|
|
36
38
|
from lamindb_setup.core._settings_storage import base62
|
|
37
39
|
from lamindb_setup.core._settings_storage import init_storage as init_storage_base
|
|
40
|
+
from lamindb_setup.core._settings_store import instance_settings_file
|
|
38
41
|
from lamindb_setup.core._settings_user import UserSettings
|
|
42
|
+
from laminhub_rest.core.access_v2 import OrganizationHandler
|
|
39
43
|
from laminhub_rest.core.instance.collaborator import InstanceCollaboratorHandler
|
|
44
|
+
from laminhub_rest.test.instance.utils import (
|
|
45
|
+
create_hosted_test_instance,
|
|
46
|
+
delete_hosted_test_instance,
|
|
47
|
+
)
|
|
40
48
|
from postgrest.exceptions import APIError
|
|
41
49
|
from supafunc.errors import FunctionsHttpError
|
|
42
50
|
|
|
@@ -127,7 +135,7 @@ def create_myinstance(create_testadmin1_session): # -> Dict
|
|
|
127
135
|
)[0],
|
|
128
136
|
db=db_str,
|
|
129
137
|
)
|
|
130
|
-
|
|
138
|
+
init_instance_hub(isettings)
|
|
131
139
|
# test loading it
|
|
132
140
|
with pytest.raises(PermissionError) as error:
|
|
133
141
|
ln_setup.connect("testadmin1/myinstance", _test=True)
|
|
@@ -159,6 +167,18 @@ def create_myinstance(create_testadmin1_session): # -> Dict
|
|
|
159
167
|
yield instance
|
|
160
168
|
|
|
161
169
|
|
|
170
|
+
@pytest.fixture(scope="session")
|
|
171
|
+
def create_instance_fine_grained_access(create_testadmin1_session):
|
|
172
|
+
client, testadmin1 = create_testadmin1_session
|
|
173
|
+
|
|
174
|
+
org_handler = OrganizationHandler(client)
|
|
175
|
+
org_handler.create(testadmin1._uuid)
|
|
176
|
+
|
|
177
|
+
instance = create_hosted_test_instance("instance_access_v2", access_v2=True)
|
|
178
|
+
yield instance
|
|
179
|
+
delete_hosted_test_instance(instance)
|
|
180
|
+
|
|
181
|
+
|
|
162
182
|
def test_connection_string_decomp(create_myinstance, create_testadmin1_session):
|
|
163
183
|
client, _ = create_testadmin1_session
|
|
164
184
|
assert create_myinstance["db_scheme"] == "postgresql"
|
|
@@ -357,7 +377,7 @@ def test_init_storage_with_non_existing_bucket(create_testadmin1_session):
|
|
|
357
377
|
from botocore.exceptions import ClientError
|
|
358
378
|
|
|
359
379
|
with pytest.raises(ClientError) as error:
|
|
360
|
-
|
|
380
|
+
init_storage_hub(
|
|
361
381
|
ssettings=init_storage_base(
|
|
362
382
|
"s3://non_existing_storage_root", instance_id=uuid4()
|
|
363
383
|
)[0]
|
|
@@ -369,3 +389,27 @@ def test_init_storage_incorrect_protocol():
|
|
|
369
389
|
with pytest.raises(ValueError) as error:
|
|
370
390
|
init_storage_base("incorrect-protocol://some-path/some-path-level")
|
|
371
391
|
assert "Protocol incorrect-protocol is not supported" in error.exconly()
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
def test_fine_grained_access(create_instance_fine_grained_access):
|
|
395
|
+
instance = create_instance_fine_grained_access
|
|
396
|
+
|
|
397
|
+
isettings_file = instance_settings_file(
|
|
398
|
+
instance.name, ln_setup.settings.user.handle
|
|
399
|
+
)
|
|
400
|
+
# the file is written by create_instance_fine_grained_access
|
|
401
|
+
# has fine_grained_access=False because create_instance_fine_grained_access
|
|
402
|
+
# updates the instance after init without updating the settings file
|
|
403
|
+
assert isettings_file.exists()
|
|
404
|
+
# need to delete it, because otheriwse
|
|
405
|
+
# isettings.is_remote evaluates to False
|
|
406
|
+
# and ln_setup.connect doesn't make a hub request
|
|
407
|
+
# thus fine_grained_access stays False
|
|
408
|
+
isettings_file.unlink()
|
|
409
|
+
# run from a script because test_update_schema_in_hub.py has ln_setup.init
|
|
410
|
+
# which fails if we connect here
|
|
411
|
+
subprocess.run(
|
|
412
|
+
"python ./tests/hub-local/scripts/script-connect-fine-grained-access.py",
|
|
413
|
+
shell=True,
|
|
414
|
+
check=True,
|
|
415
|
+
)
|
|
@@ -5,6 +5,7 @@ from uuid import UUID
|
|
|
5
5
|
|
|
6
6
|
import lamindb_setup as ln_setup
|
|
7
7
|
import pytest
|
|
8
|
+
from lamindb_setup._init_instance import InstanceNotCreated
|
|
8
9
|
from lamindb_setup.core._hub_client import connect_hub_with_auth
|
|
9
10
|
from lamindb_setup.core._hub_crud import (
|
|
10
11
|
select_account_by_handle,
|
|
@@ -33,6 +34,16 @@ def test_connect_instance_with_private_storage_and_no_storage_access():
|
|
|
33
34
|
path.fs.call_s3("head_bucket", Bucket=path.drive)
|
|
34
35
|
|
|
35
36
|
|
|
37
|
+
def test_init_instance_with_private_storage_and_no_storage_access():
|
|
38
|
+
ln_setup.login("testuser1@lamin.ai")
|
|
39
|
+
# test creating with no access to a cloud storage
|
|
40
|
+
with pytest.raises(InstanceNotCreated):
|
|
41
|
+
ln_setup.init(
|
|
42
|
+
storage="s3://lndb-setup-ci-eu-central-1/surely-nothing-here",
|
|
43
|
+
_test=True,
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
|
|
36
47
|
def test_connect_instance_with_public_storage():
|
|
37
48
|
# this loads a persistent instance created with a public s3 bucket
|
|
38
49
|
# with s3:GetObject and s3:ListBucket policies enabled for all
|
|
@@ -41,9 +41,9 @@ def test_get_stat_file_cloud_http():
|
|
|
41
41
|
string_path = "https://raw.githubusercontent.com/laminlabs/lamindb-setup/refs/heads/main/README.md"
|
|
42
42
|
path = UPath(string_path)
|
|
43
43
|
size, hash, hash_type = get_stat_file_cloud(path.stat().as_info())
|
|
44
|
-
assert hash == "
|
|
44
|
+
assert hash == "h3XDCTkMambmtSVpTQetLQ"
|
|
45
45
|
assert hash_type == "md5-etag"
|
|
46
|
-
assert size ==
|
|
46
|
+
assert size == 272
|
|
47
47
|
|
|
48
48
|
|
|
49
49
|
def test_get_stat_dir_cloud_aws():
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/docs/hub-prod/test-init-load-local-anonymously.ipynb
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{lamindb_setup-1.3.0 → lamindb_setup-1.3.2}/tests/hub-cloud/test_init_pass_user_no_writes.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|