lamindb_setup 1.5.2__tar.gz → 1.6.0__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.5.2 → lamindb_setup-1.6.0}/.github/workflows/build.yml +0 -8
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/PKG-INFO +1 -1
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/docs/hub-cloud/08-test-multi-session.ipynb +45 -4
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/lamindb_setup/__init__.py +1 -1
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/lamindb_setup/_connect_instance.py +19 -14
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/lamindb_setup/_init_instance.py +20 -2
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/lamindb_setup/_schema_metadata.py +6 -6
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/lamindb_setup/core/_hub_core.py +23 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/lamindb_setup/core/_settings.py +11 -1
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/lamindb_setup/core/_settings_store.py +6 -1
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/lamindb_setup/core/django.py +44 -2
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/tests/hub-cloud/test_connect_instance.py +7 -16
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/tests/hub-local/test_all.py +16 -6
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/.github/workflows/doc-changes.yml +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/.gitignore +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/.pre-commit-config.yaml +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/LICENSE +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/README.md +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/docs/changelog.md +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/docs/hub-cloud/01-init-local-instance.ipynb +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/docs/hub-cloud/02-connect-local-instance.ipynb +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/docs/hub-cloud/03-add-managed-storage.ipynb +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/docs/hub-cloud/04-test-bionty.ipynb +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/docs/hub-cloud/05-init-hosted-instance.ipynb +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/docs/hub-cloud/06-connect-hosted-instance.ipynb +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/docs/hub-cloud/07-keep-artifacts-local.ipynb +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/docs/hub-cloud/test_notebooks.py +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/docs/hub-prod/test-cache-management.ipynb +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/docs/hub-prod/test-cloud-sync.ipynb +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/docs/hub-prod/test-connect-anonymously.ipynb +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/docs/hub-prod/test-empty-init.ipynb +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/docs/hub-prod/test-import-schema.ipynb +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/docs/hub-prod/test-init-load-local-anonymously.ipynb +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/docs/hub-prod/test-insufficient-user-info.ipynb +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/docs/hub-prod/test-invalid-schema.ipynb +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/docs/hub-prod/test-sqlite-lock.ipynb +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/docs/hub-prod/test_notebooks2.py +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/docs/index.md +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/docs/notebooks.md +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/docs/reference.md +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/lamindb_setup/_cache.py +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/lamindb_setup/_check.py +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/lamindb_setup/_check_setup.py +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/lamindb_setup/_delete.py +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/lamindb_setup/_disconnect.py +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/lamindb_setup/_django.py +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/lamindb_setup/_entry_points.py +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/lamindb_setup/_exportdb.py +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/lamindb_setup/_importdb.py +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/lamindb_setup/_migrate.py +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/lamindb_setup/_register_instance.py +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/lamindb_setup/_schema.py +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/lamindb_setup/_set_managed_storage.py +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/lamindb_setup/_setup_user.py +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/lamindb_setup/_silence_loggers.py +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/lamindb_setup/core/__init__.py +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/lamindb_setup/core/_aws_options.py +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/lamindb_setup/core/_aws_storage.py +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/lamindb_setup/core/_deprecated.py +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/lamindb_setup/core/_docs.py +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/lamindb_setup/core/_hub_client.py +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/lamindb_setup/core/_hub_crud.py +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/lamindb_setup/core/_hub_utils.py +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/lamindb_setup/core/_private_django_api.py +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/lamindb_setup/core/_settings_instance.py +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/lamindb_setup/core/_settings_load.py +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/lamindb_setup/core/_settings_save.py +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/lamindb_setup/core/_settings_storage.py +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/lamindb_setup/core/_settings_user.py +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/lamindb_setup/core/_setup_bionty_sources.py +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/lamindb_setup/core/cloud_sqlite_locker.py +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/lamindb_setup/core/exceptions.py +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/lamindb_setup/core/hashing.py +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/lamindb_setup/core/types.py +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/lamindb_setup/core/upath.py +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/noxfile.py +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/pyproject.toml +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/tests/hub-cloud/scripts/script-init-pass-user-no-writes.py +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/tests/hub-cloud/scripts/script-to-fail-managed-storage.py +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/tests/hub-cloud/test_delete_instance.py +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/tests/hub-cloud/test_edge_request.py +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/tests/hub-cloud/test_fail_managed_storage.py +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/tests/hub-cloud/test_init_instance.py +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/tests/hub-cloud/test_init_pass_user_no_writes.py +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/tests/hub-cloud/test_login.py +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/tests/hub-cloud/test_migrate.py +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/tests/hub-cloud/test_set_storage.py +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/tests/hub-local/conftest.py +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/tests/hub-local/scripts/script-connect-fine-grained-access.py +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/tests/hub-local/test_update_schema_in_hub.py +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/tests/hub-prod/conftest.py +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/tests/hub-prod/test_aws_options_manager.py +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/tests/hub-prod/test_django.py +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/tests/hub-prod/test_global_settings.py +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/tests/hub-prod/test_switch_and_fallback_env.py +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/tests/hub-prod/test_upath.py +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/tests/storage/test_entry_point.py +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/tests/storage/test_hashing.py +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/tests/storage/test_storage_access.py +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/tests/storage/test_storage_basis.py +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/tests/storage/test_storage_settings.py +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/tests/storage/test_storage_stats.py +0 -0
- {lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/tests/storage/test_to_url.py +0 -0
|
@@ -231,14 +231,6 @@ jobs:
|
|
|
231
231
|
needs: [hub-local, hub-cloud]
|
|
232
232
|
runs-on: ubuntu-latest
|
|
233
233
|
steps:
|
|
234
|
-
- uses: voxmedia/github-action-slack-notify-build@v1
|
|
235
|
-
if: ${{ needs.hub-local.result == 'success' && needs.hub-cloud.result == 'success' && github.event_name == 'repository_dispatch' }}
|
|
236
|
-
env:
|
|
237
|
-
SLACK_BOT_TOKEN: ${{ secrets.SLACK_GITHUB_ACTION }}
|
|
238
|
-
with:
|
|
239
|
-
channel_id: C05S2C02JHM
|
|
240
|
-
status: SUCCESS
|
|
241
|
-
color: good
|
|
242
234
|
- uses: voxmedia/github-action-slack-notify-build@v1
|
|
243
235
|
if: ${{ ( needs.hub-local.result == 'failure' || needs.hub-cloud.result == 'failure' ) && github.event_name == 'repository_dispatch' }}
|
|
244
236
|
env:
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"cells": [
|
|
3
3
|
{
|
|
4
|
-
"attachments": {},
|
|
5
4
|
"cell_type": "markdown",
|
|
6
5
|
"metadata": {},
|
|
7
6
|
"source": [
|
|
@@ -28,6 +27,15 @@
|
|
|
28
27
|
"import pytest"
|
|
29
28
|
]
|
|
30
29
|
},
|
|
30
|
+
{
|
|
31
|
+
"cell_type": "code",
|
|
32
|
+
"execution_count": null,
|
|
33
|
+
"metadata": {},
|
|
34
|
+
"outputs": [],
|
|
35
|
+
"source": [
|
|
36
|
+
"ln_setup.core.django.reset_django() # django is not configured, so no effect"
|
|
37
|
+
]
|
|
38
|
+
},
|
|
31
39
|
{
|
|
32
40
|
"cell_type": "code",
|
|
33
41
|
"execution_count": null,
|
|
@@ -100,7 +108,6 @@
|
|
|
100
108
|
]
|
|
101
109
|
},
|
|
102
110
|
{
|
|
103
|
-
"attachments": {},
|
|
104
111
|
"cell_type": "markdown",
|
|
105
112
|
"metadata": {},
|
|
106
113
|
"source": [
|
|
@@ -127,6 +134,40 @@
|
|
|
127
134
|
"assert ln_setup.settings.instance.slug == \"testuser1/testsetup\""
|
|
128
135
|
]
|
|
129
136
|
},
|
|
137
|
+
{
|
|
138
|
+
"cell_type": "markdown",
|
|
139
|
+
"metadata": {},
|
|
140
|
+
"source": [
|
|
141
|
+
"Reset `django` and connect to another instance:"
|
|
142
|
+
]
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
"cell_type": "code",
|
|
146
|
+
"execution_count": null,
|
|
147
|
+
"metadata": {},
|
|
148
|
+
"outputs": [],
|
|
149
|
+
"source": [
|
|
150
|
+
"ln_setup.core.django.reset_django()"
|
|
151
|
+
]
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
"cell_type": "code",
|
|
155
|
+
"execution_count": null,
|
|
156
|
+
"metadata": {},
|
|
157
|
+
"outputs": [],
|
|
158
|
+
"source": [
|
|
159
|
+
"ln_setup.connect(\"testuser1/testsetup-prepare\")"
|
|
160
|
+
]
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
"cell_type": "code",
|
|
164
|
+
"execution_count": null,
|
|
165
|
+
"metadata": {},
|
|
166
|
+
"outputs": [],
|
|
167
|
+
"source": [
|
|
168
|
+
"assert ln_setup.settings.instance.slug == \"testuser1/testsetup-prepare\""
|
|
169
|
+
]
|
|
170
|
+
},
|
|
130
171
|
{
|
|
131
172
|
"cell_type": "code",
|
|
132
173
|
"execution_count": null,
|
|
@@ -141,7 +182,7 @@
|
|
|
141
182
|
],
|
|
142
183
|
"metadata": {
|
|
143
184
|
"kernelspec": {
|
|
144
|
-
"display_name": "
|
|
185
|
+
"display_name": "Python 3 (ipykernel)",
|
|
145
186
|
"language": "python",
|
|
146
187
|
"name": "python3"
|
|
147
188
|
},
|
|
@@ -155,7 +196,7 @@
|
|
|
155
196
|
"name": "python",
|
|
156
197
|
"nbconvert_exporter": "python",
|
|
157
198
|
"pygments_lexer": "ipython3",
|
|
158
|
-
"version": "3.10.
|
|
199
|
+
"version": "3.10.16"
|
|
159
200
|
}
|
|
160
201
|
},
|
|
161
202
|
"nbformat": 4,
|
|
@@ -67,10 +67,12 @@ def update_db_using_local(
|
|
|
67
67
|
db_updated = None
|
|
68
68
|
# check if postgres
|
|
69
69
|
if hub_instance_result["db_scheme"] == "postgresql":
|
|
70
|
-
db_dsn_hub = LaminDsnModel(db=hub_instance_result["db"])
|
|
71
70
|
if db is not None:
|
|
72
|
-
|
|
71
|
+
# use only the provided db if it is set
|
|
72
|
+
db_dsn_hub = LaminDsnModel(db=db)
|
|
73
|
+
db_dsn_local = db_dsn_hub
|
|
73
74
|
else:
|
|
75
|
+
db_dsn_hub = LaminDsnModel(db=hub_instance_result["db"])
|
|
74
76
|
# read directly from the environment
|
|
75
77
|
if os.getenv("LAMINDB_INSTANCE_DB") is not None:
|
|
76
78
|
logger.important("loading db URL from env variable LAMINDB_INSTANCE_DB")
|
|
@@ -78,16 +80,15 @@ def update_db_using_local(
|
|
|
78
80
|
# read from a cached settings file in case the hub result is only
|
|
79
81
|
# read level or inexistent
|
|
80
82
|
elif settings_file.exists() and (
|
|
81
|
-
db_dsn_hub.db.user
|
|
82
|
-
or (db_dsn_hub.db.user is not None and "read" in db_dsn_hub.db.user)
|
|
83
|
+
db_dsn_hub.db.user in {None, "none"} or "read" in db_dsn_hub.db.user # type:ignore
|
|
83
84
|
):
|
|
84
85
|
isettings = load_instance_settings(settings_file)
|
|
85
86
|
db_dsn_local = LaminDsnModel(db=isettings.db)
|
|
86
87
|
else:
|
|
87
88
|
# just take the default hub result and ensure there is actually a user
|
|
88
89
|
if (
|
|
89
|
-
db_dsn_hub.db.user
|
|
90
|
-
and db_dsn_hub.db.password
|
|
90
|
+
db_dsn_hub.db.user in {None, "none"}
|
|
91
|
+
and db_dsn_hub.db.password in {None, "none"}
|
|
91
92
|
and raise_permission_error
|
|
92
93
|
):
|
|
93
94
|
raise PermissionError(
|
|
@@ -95,13 +96,13 @@ def update_db_using_local(
|
|
|
95
96
|
" a DB URL and pass it via --db <db_url>"
|
|
96
97
|
)
|
|
97
98
|
db_dsn_local = db_dsn_hub
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
99
|
+
if not check_db_dsn_equal_up_to_credentials(db_dsn_hub.db, db_dsn_local.db):
|
|
100
|
+
raise ValueError(
|
|
101
|
+
"The local differs from the hub database information:\n"
|
|
102
|
+
"did your database get updated by an admin?\n"
|
|
103
|
+
"Consider deleting your cached database environment:\nrm"
|
|
104
|
+
f" {settings_file.as_posix()}"
|
|
105
|
+
)
|
|
105
106
|
db_updated = LaminDsn.build(
|
|
106
107
|
scheme=db_dsn_hub.db.scheme,
|
|
107
108
|
user=db_dsn_local.db.user,
|
|
@@ -345,11 +346,15 @@ def migrate_lnschema_core(
|
|
|
345
346
|
if db_type == "sqlite":
|
|
346
347
|
import sqlite3
|
|
347
348
|
|
|
349
|
+
# maybe also use LAMINDB_DJANGO_DATABASE_URL here?
|
|
348
350
|
conn = sqlite3.connect(parsed_uri.path)
|
|
349
351
|
elif db_type in ["postgresql", "postgres"]:
|
|
350
352
|
import psycopg2
|
|
351
353
|
|
|
352
|
-
|
|
354
|
+
# do not ignore LAMINDB_DJANGO_DATABASE_URL if it is set
|
|
355
|
+
conn = psycopg2.connect(
|
|
356
|
+
os.environ.get("LAMINDB_DJANGO_DATABASE_URL", isettings.db)
|
|
357
|
+
)
|
|
353
358
|
else:
|
|
354
359
|
raise ValueError("Unsupported database type. Use 'sqlite' or 'postgresql' URI.")
|
|
355
360
|
|
|
@@ -98,13 +98,31 @@ def register_user(usettings):
|
|
|
98
98
|
def register_initial_records(isettings: InstanceSettings, usettings):
|
|
99
99
|
"""Register space, user & storage in DB."""
|
|
100
100
|
from django.db.utils import OperationalError
|
|
101
|
-
from lamindb.models import Space
|
|
101
|
+
from lamindb.models import Branch, Space
|
|
102
102
|
|
|
103
103
|
try:
|
|
104
104
|
Space.objects.get_or_create(
|
|
105
|
+
uid="A",
|
|
105
106
|
name="All",
|
|
106
107
|
description="Every team & user with access to the instance has access.",
|
|
107
108
|
)
|
|
109
|
+
Branch.objects.get_or_create(
|
|
110
|
+
id=-1,
|
|
111
|
+
uid="T",
|
|
112
|
+
name="Trash",
|
|
113
|
+
description="The trash.",
|
|
114
|
+
)
|
|
115
|
+
Branch.objects.get_or_create(
|
|
116
|
+
id=0,
|
|
117
|
+
uid="A",
|
|
118
|
+
name="Archive",
|
|
119
|
+
description="The archive.",
|
|
120
|
+
)
|
|
121
|
+
Branch.objects.get_or_create(
|
|
122
|
+
uid="M",
|
|
123
|
+
name="Main",
|
|
124
|
+
description="The main & default branch of the instance.",
|
|
125
|
+
)
|
|
108
126
|
register_user(usettings)
|
|
109
127
|
register_storage_in_instance(isettings.storage)
|
|
110
128
|
except OperationalError as error:
|
|
@@ -206,7 +224,7 @@ class CannotSwitchDefaultInstance(SystemExit):
|
|
|
206
224
|
MESSAGE_CANNOT_SWITCH_DEFAULT_INSTANCE = """
|
|
207
225
|
You cannot write to different instances in the same Python session.
|
|
208
226
|
|
|
209
|
-
Do you want to read from another instance via `
|
|
227
|
+
Do you want to read from another instance via `SQLRecord.using()`? For example:
|
|
210
228
|
|
|
211
229
|
ln.Artifact.using("laminlabs/cellxgene").filter()
|
|
212
230
|
|
|
@@ -159,7 +159,7 @@ class FieldMetadata(BaseModel):
|
|
|
159
159
|
|
|
160
160
|
class _ModelHandler:
|
|
161
161
|
def __init__(self, model, module_name: str, included_modules: list[str]) -> None:
|
|
162
|
-
from lamindb.models import
|
|
162
|
+
from lamindb.models import IsLink
|
|
163
163
|
|
|
164
164
|
self.model = model
|
|
165
165
|
self.class_name = model.__name__
|
|
@@ -168,7 +168,7 @@ class _ModelHandler:
|
|
|
168
168
|
self.table_name = model._meta.db_table
|
|
169
169
|
self.included_modules = included_modules
|
|
170
170
|
self.fields = self._get_fields_metadata(self.model)
|
|
171
|
-
self.is_link_table = issubclass(model,
|
|
171
|
+
self.is_link_table = issubclass(model, IsLink)
|
|
172
172
|
self.name_field = model._name_field if hasattr(model, "_name_field") else None
|
|
173
173
|
self.ontology_id_field = (
|
|
174
174
|
model._ontology_id_field if hasattr(model, "_ontology_id_field") else None
|
|
@@ -245,7 +245,7 @@ class _ModelHandler:
|
|
|
245
245
|
return related_fields
|
|
246
246
|
|
|
247
247
|
def _get_field_metadata(self, model, field: Field):
|
|
248
|
-
from lamindb.models import
|
|
248
|
+
from lamindb.models import IsLink
|
|
249
249
|
|
|
250
250
|
internal_type = field.get_internal_type()
|
|
251
251
|
model_name = field.model._meta.model_name
|
|
@@ -296,7 +296,7 @@ class _ModelHandler:
|
|
|
296
296
|
model_name=model_name,
|
|
297
297
|
field_name=field_name,
|
|
298
298
|
type=internal_type,
|
|
299
|
-
is_link_table=issubclass(field.model,
|
|
299
|
+
is_link_table=issubclass(field.model, IsLink),
|
|
300
300
|
is_primary_key=is_primary_key,
|
|
301
301
|
is_editable=is_editable,
|
|
302
302
|
max_length=max_length,
|
|
@@ -400,7 +400,7 @@ class _SchemaHandler:
|
|
|
400
400
|
return self.to_dict(include_django_objects=False)
|
|
401
401
|
|
|
402
402
|
def _get_modules_metadata(self):
|
|
403
|
-
from lamindb.models import
|
|
403
|
+
from lamindb.models import Registry, SQLRecord
|
|
404
404
|
|
|
405
405
|
all_models = {
|
|
406
406
|
module_name: {
|
|
@@ -411,7 +411,7 @@ class _SchemaHandler:
|
|
|
411
411
|
module_name
|
|
412
412
|
).models.__dict__.values()
|
|
413
413
|
if model.__class__ is Registry
|
|
414
|
-
and model is not
|
|
414
|
+
and model is not SQLRecord
|
|
415
415
|
and not model._meta.abstract
|
|
416
416
|
and model.__get_module_name__() == module_name
|
|
417
417
|
}
|
|
@@ -36,6 +36,7 @@ from ._hub_utils import (
|
|
|
36
36
|
from ._settings import settings
|
|
37
37
|
from ._settings_instance import InstanceSettings
|
|
38
38
|
from ._settings_storage import StorageSettings, base62
|
|
39
|
+
from .hashing import hash_and_encode_as_b62
|
|
39
40
|
|
|
40
41
|
if TYPE_CHECKING:
|
|
41
42
|
from supabase import Client # type: ignore
|
|
@@ -116,6 +117,28 @@ def _select_storage(
|
|
|
116
117
|
return True
|
|
117
118
|
|
|
118
119
|
|
|
120
|
+
def _select_storage_or_parent(path: str, client: Client) -> dict | None:
|
|
121
|
+
result = client.rpc("existing_root_or_child", {"_path": path}).execute().data
|
|
122
|
+
if result["root"] is None:
|
|
123
|
+
return None
|
|
124
|
+
result["uid"] = result.pop("lnid")
|
|
125
|
+
result["instance_uid"] = hash_and_encode_as_b62(
|
|
126
|
+
UUID(result.pop("instance_id")).hex
|
|
127
|
+
)[:12]
|
|
128
|
+
return result
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def select_storage_or_parent(path: str, access_token: str | None = None) -> dict | None:
|
|
132
|
+
if settings.user.handle != "anonymous" or access_token is not None:
|
|
133
|
+
return call_with_fallback_auth(
|
|
134
|
+
_select_storage_or_parent,
|
|
135
|
+
path=path,
|
|
136
|
+
access_token=access_token,
|
|
137
|
+
)
|
|
138
|
+
else:
|
|
139
|
+
return call_with_fallback(_select_storage_or_parent, path=path)
|
|
140
|
+
|
|
141
|
+
|
|
119
142
|
def init_storage_hub(
|
|
120
143
|
ssettings: StorageSettings,
|
|
121
144
|
auto_populate_instance: bool = True,
|
|
@@ -5,6 +5,7 @@ import sys
|
|
|
5
5
|
from typing import TYPE_CHECKING
|
|
6
6
|
|
|
7
7
|
from appdirs import AppDirs
|
|
8
|
+
from lamin_utils import logger
|
|
8
9
|
|
|
9
10
|
from ._settings_load import (
|
|
10
11
|
load_instance_settings,
|
|
@@ -162,7 +163,16 @@ class SetupSettings:
|
|
|
162
163
|
self._cache_dir = cache_dir
|
|
163
164
|
else:
|
|
164
165
|
cache_dir = self._cache_dir
|
|
165
|
-
|
|
166
|
+
try:
|
|
167
|
+
cache_dir.mkdir(parents=True, exist_ok=True)
|
|
168
|
+
# we don not want this to error
|
|
169
|
+
# beause no actual writing happens on just getting the cache dir
|
|
170
|
+
# in cloud_to_local_no_update for example
|
|
171
|
+
# so it should not fail on read-only systems
|
|
172
|
+
except Exception as e:
|
|
173
|
+
logger.warning(
|
|
174
|
+
f"Failed to create lamin cache directory at {cache_dir}: {e}"
|
|
175
|
+
)
|
|
166
176
|
return cache_dir
|
|
167
177
|
|
|
168
178
|
@property
|
|
@@ -2,6 +2,7 @@ import os
|
|
|
2
2
|
from pathlib import Path
|
|
3
3
|
from typing import Optional
|
|
4
4
|
|
|
5
|
+
from lamin_utils import logger
|
|
5
6
|
from pydantic_settings import BaseSettings, SettingsConfigDict
|
|
6
7
|
|
|
7
8
|
if "LAMIN_SETTINGS_DIR" in os.environ:
|
|
@@ -12,7 +13,11 @@ else:
|
|
|
12
13
|
# hence, let's take home/.lamin
|
|
13
14
|
settings_dir = Path.home() / ".lamin"
|
|
14
15
|
|
|
15
|
-
|
|
16
|
+
|
|
17
|
+
try:
|
|
18
|
+
settings_dir.mkdir(parents=True, exist_ok=True)
|
|
19
|
+
except Exception as e:
|
|
20
|
+
logger.warning(f"Failed to create lamin settings directory at {settings_dir}: {e}")
|
|
16
21
|
|
|
17
22
|
|
|
18
23
|
def get_settings_file_name_prefix():
|
|
@@ -3,6 +3,8 @@ from __future__ import annotations
|
|
|
3
3
|
# flake8: noqa
|
|
4
4
|
import builtins
|
|
5
5
|
import os
|
|
6
|
+
import sys
|
|
7
|
+
import importlib as il
|
|
6
8
|
import jwt
|
|
7
9
|
import time
|
|
8
10
|
from pathlib import Path
|
|
@@ -170,8 +172,7 @@ def setup_django(
|
|
|
170
172
|
|
|
171
173
|
module_names = ["core"] + list(isettings.modules)
|
|
172
174
|
raise_import_error = True if init else False
|
|
173
|
-
installed_apps = [
|
|
174
|
-
installed_apps += [
|
|
175
|
+
installed_apps = [
|
|
175
176
|
package_name
|
|
176
177
|
for name in module_names
|
|
177
178
|
if (
|
|
@@ -242,3 +243,44 @@ def setup_django(
|
|
|
242
243
|
|
|
243
244
|
if isettings.keep_artifacts_local:
|
|
244
245
|
isettings._search_local_root()
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
# THIS IS NOT SAFE
|
|
249
|
+
# especially if lamindb is imported already
|
|
250
|
+
# django.setup fails if called for the second time
|
|
251
|
+
# reset_django() allows to call setup again,
|
|
252
|
+
# needed to connect to a different instance in the same process if connected already
|
|
253
|
+
# there could be problems if models are already imported from lamindb or other modules
|
|
254
|
+
# these 'old' models can have any number of problems
|
|
255
|
+
def reset_django():
|
|
256
|
+
from django.conf import settings
|
|
257
|
+
from django.apps import apps
|
|
258
|
+
from django.db import connections
|
|
259
|
+
|
|
260
|
+
if not settings.configured:
|
|
261
|
+
return
|
|
262
|
+
|
|
263
|
+
connections.close_all()
|
|
264
|
+
|
|
265
|
+
if getattr(settings, "_wrapped", None) is not None:
|
|
266
|
+
settings._wrapped = None
|
|
267
|
+
|
|
268
|
+
app_names = {"django"} | {app.name for app in apps.get_app_configs()}
|
|
269
|
+
|
|
270
|
+
apps.app_configs.clear()
|
|
271
|
+
apps.apps_ready = apps.models_ready = apps.ready = apps.loading = False
|
|
272
|
+
apps.clear_cache()
|
|
273
|
+
|
|
274
|
+
# i suspect it is enough to just drop django and all the apps from sys.modules
|
|
275
|
+
# the code above is just a precaution
|
|
276
|
+
for module_name in list(sys.modules):
|
|
277
|
+
if module_name.partition(".")[0] in app_names:
|
|
278
|
+
del sys.modules[module_name]
|
|
279
|
+
|
|
280
|
+
il.invalidate_caches()
|
|
281
|
+
|
|
282
|
+
global db_token_manager
|
|
283
|
+
db_token_manager = DBTokenManager()
|
|
284
|
+
|
|
285
|
+
global IS_SETUP
|
|
286
|
+
IS_SETUP = False
|
|
@@ -117,31 +117,22 @@ def test_connect_with_db_parameter():
|
|
|
117
117
|
ln_setup.login("testuser1")
|
|
118
118
|
# test load from hub
|
|
119
119
|
ln_setup.connect("laminlabs/lamindata", _test=True)
|
|
120
|
-
|
|
120
|
+
# this test assumes fine-grained access
|
|
121
|
+
assert ln_setup.settings.instance._db_permissions == "jwt"
|
|
122
|
+
assert "jwt" in ln_setup.settings.instance.db
|
|
121
123
|
# test load from provided db argument
|
|
122
124
|
db = "postgresql://testdbuser:testpwd@database2.cmyfs24wugc3.us-east-1.rds.amazonaws.com:5432/db1"
|
|
123
125
|
ln_setup.connect("laminlabs/lamindata", _db=db, _test=True)
|
|
124
126
|
assert "testdbuser" in ln_setup.settings.instance.db
|
|
125
|
-
# test ignore loading from cache because hub result has
|
|
127
|
+
# test ignore loading from cache because hub result has jwt access
|
|
126
128
|
ln_setup.connect("laminlabs/lamindata", _test=True)
|
|
127
|
-
assert "
|
|
129
|
+
assert "jwt" in ln_setup.settings.instance.db
|
|
128
130
|
|
|
129
131
|
# now take a user that has no collaborator status
|
|
130
132
|
ln_setup.login("testuser2")
|
|
131
|
-
#
|
|
133
|
+
# receives public connection
|
|
132
134
|
ln_setup.connect("laminlabs/lamindata", _test=True)
|
|
133
|
-
assert "
|
|
135
|
+
assert "public" in ln_setup.settings.instance.db
|
|
134
136
|
# now pass the connection string
|
|
135
137
|
ln_setup.connect("laminlabs/lamindata", _db=db, _test=True)
|
|
136
138
|
assert "testdbuser" in ln_setup.settings.instance.db
|
|
137
|
-
# now the cache is used
|
|
138
|
-
ln_setup.connect("laminlabs/lamindata", _test=True)
|
|
139
|
-
assert "testdbuser" in ln_setup.settings.instance.db
|
|
140
|
-
|
|
141
|
-
# test corrupted input
|
|
142
|
-
db_corrupted = "postgresql://testuser:testpwd@wrongserver:5432/db1"
|
|
143
|
-
with pytest.raises(ValueError) as error:
|
|
144
|
-
ln_setup.connect("laminlabs/lamindata", _db=db_corrupted, _test=True)
|
|
145
|
-
assert error.exconly().startswith(
|
|
146
|
-
"ValueError: The local differs from the hub database information"
|
|
147
|
-
)
|
|
@@ -2,6 +2,7 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import os
|
|
4
4
|
import subprocess
|
|
5
|
+
from unittest.mock import patch
|
|
5
6
|
from uuid import UUID, uuid4
|
|
6
7
|
|
|
7
8
|
import lamindb_setup as ln_setup
|
|
@@ -17,6 +18,7 @@ from lamindb_setup.core._hub_core import (
|
|
|
17
18
|
connect_instance_hub,
|
|
18
19
|
init_instance_hub,
|
|
19
20
|
init_storage_hub,
|
|
21
|
+
select_storage_or_parent,
|
|
20
22
|
sign_in_hub,
|
|
21
23
|
sign_up_local_hub,
|
|
22
24
|
)
|
|
@@ -39,7 +41,6 @@ from lamindb_setup.core._settings_storage import init_storage as init_storage_ba
|
|
|
39
41
|
from lamindb_setup.core._settings_store import instance_settings_file
|
|
40
42
|
from lamindb_setup.core._settings_user import UserSettings
|
|
41
43
|
from laminhub_rest.core.legacy._instance_collaborator import InstanceCollaboratorHandler
|
|
42
|
-
from laminhub_rest.core.organization import OrganizationHandler
|
|
43
44
|
from laminhub_rest.test.instance.utils import (
|
|
44
45
|
create_hosted_test_instance,
|
|
45
46
|
delete_hosted_test_instance,
|
|
@@ -168,11 +169,6 @@ def create_myinstance(create_testadmin1_session): # -> Dict
|
|
|
168
169
|
|
|
169
170
|
@pytest.fixture(scope="session")
|
|
170
171
|
def create_instance_fine_grained_access(create_testadmin1_session):
|
|
171
|
-
client, testadmin1 = create_testadmin1_session
|
|
172
|
-
|
|
173
|
-
org_handler = OrganizationHandler(client)
|
|
174
|
-
org_handler.create(testadmin1._uuid)
|
|
175
|
-
|
|
176
172
|
instance = create_hosted_test_instance("instance_access_v2", access_v2=True)
|
|
177
173
|
yield instance
|
|
178
174
|
delete_hosted_test_instance(instance)
|
|
@@ -390,6 +386,20 @@ def test_init_storage_incorrect_protocol():
|
|
|
390
386
|
assert "Protocol incorrect-protocol is not supported" in error.exconly()
|
|
391
387
|
|
|
392
388
|
|
|
389
|
+
def test_select_storage_or_parent(create_myinstance):
|
|
390
|
+
# check not exisitng
|
|
391
|
+
assert select_storage_or_parent("s3://does-not-exist") is None
|
|
392
|
+
|
|
393
|
+
root = "s3://lamindb-ci/myinstance"
|
|
394
|
+
|
|
395
|
+
result = select_storage_or_parent(root)
|
|
396
|
+
assert result["root"] == root
|
|
397
|
+
# check with a child path and anonymous user
|
|
398
|
+
with patch.object(ln_setup.settings.user, "handle", new="anonymous"):
|
|
399
|
+
result = select_storage_or_parent(root + "/subfolder")
|
|
400
|
+
assert result["root"] == root
|
|
401
|
+
|
|
402
|
+
|
|
393
403
|
def test_fine_grained_access(
|
|
394
404
|
create_testadmin1_session, create_instance_fine_grained_access
|
|
395
405
|
):
|
|
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.5.2 → lamindb_setup-1.6.0}/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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{lamindb_setup-1.5.2 → lamindb_setup-1.6.0}/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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|