lamindb_setup 1.11.0__tar.gz → 1.12.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.11.0 → lamindb_setup-1.12.0}/.github/workflows/build.yml +6 -6
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/.gitignore +3 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/.pre-commit-config.yaml +5 -5
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/PKG-INFO +3 -2
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/docs/hub-cloud/08-test-multi-session.ipynb +83 -6
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/lamindb_setup/__init__.py +1 -1
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/lamindb_setup/_connect_instance.py +51 -37
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/lamindb_setup/_delete.py +3 -1
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/lamindb_setup/_init_instance.py +22 -25
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/lamindb_setup/_migrate.py +2 -2
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/lamindb_setup/_schema_metadata.py +3 -3
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/lamindb_setup/core/_aws_options.py +2 -4
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/lamindb_setup/core/_aws_storage.py +2 -3
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/lamindb_setup/core/_hub_client.py +84 -44
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/lamindb_setup/core/_hub_core.py +27 -10
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/lamindb_setup/core/_settings.py +2 -3
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/lamindb_setup/core/_settings_instance.py +7 -7
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/lamindb_setup/core/_settings_save.py +2 -2
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/lamindb_setup/core/_settings_store.py +9 -9
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/lamindb_setup/core/upath.py +7 -10
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/pyproject.toml +3 -2
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/tests/hub-cloud/test_connect_instance.py +7 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/tests/hub-cloud/test_init_instance.py +6 -2
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/tests/hub-local/conftest.py +0 -1
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/tests/hub-local/test_all.py +5 -1
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/.github/workflows/doc-changes.yml +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/LICENSE +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/README.md +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/docs/changelog.md +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/docs/hub-cloud/01-init-local-instance.ipynb +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/docs/hub-cloud/02-connect-local-instance.ipynb +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/docs/hub-cloud/03-add-managed-storage.ipynb +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/docs/hub-cloud/04-test-bionty.ipynb +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/docs/hub-cloud/05-init-hosted-instance.ipynb +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/docs/hub-cloud/06-connect-hosted-instance.ipynb +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/docs/hub-cloud/07-keep-artifacts-local.ipynb +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/docs/hub-cloud/09-test-migrate.ipynb +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/docs/hub-cloud/test_notebooks.py +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/docs/hub-prod/test-cache-management.ipynb +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/docs/hub-prod/test-cloud-sync.ipynb +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/docs/hub-prod/test-connect-anonymously.ipynb +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/docs/hub-prod/test-empty-init.ipynb +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/docs/hub-prod/test-import-schema.ipynb +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/docs/hub-prod/test-init-load-local-anonymously.ipynb +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/docs/hub-prod/test-insufficient-user-info.ipynb +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/docs/hub-prod/test-invalid-schema.ipynb +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/docs/hub-prod/test-sqlite-lock.ipynb +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/docs/hub-prod/test_notebooks2.py +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/docs/index.md +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/docs/notebooks.md +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/docs/reference.md +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/lamindb_setup/_cache.py +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/lamindb_setup/_check.py +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/lamindb_setup/_check_setup.py +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/lamindb_setup/_disconnect.py +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/lamindb_setup/_django.py +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/lamindb_setup/_entry_points.py +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/lamindb_setup/_exportdb.py +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/lamindb_setup/_importdb.py +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/lamindb_setup/_register_instance.py +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/lamindb_setup/_schema.py +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/lamindb_setup/_set_managed_storage.py +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/lamindb_setup/_setup_user.py +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/lamindb_setup/_silence_loggers.py +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/lamindb_setup/core/__init__.py +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/lamindb_setup/core/_deprecated.py +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/lamindb_setup/core/_docs.py +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/lamindb_setup/core/_hub_crud.py +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/lamindb_setup/core/_hub_utils.py +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/lamindb_setup/core/_private_django_api.py +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/lamindb_setup/core/_settings_load.py +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/lamindb_setup/core/_settings_storage.py +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/lamindb_setup/core/_settings_user.py +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/lamindb_setup/core/_setup_bionty_sources.py +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/lamindb_setup/core/cloud_sqlite_locker.py +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/lamindb_setup/core/django.py +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/lamindb_setup/core/exceptions.py +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/lamindb_setup/core/hashing.py +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/lamindb_setup/core/types.py +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/lamindb_setup/errors.py +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/lamindb_setup/py.typed +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/lamindb_setup/types.py +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/noxfile.py +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/tests/hub-cloud/scripts/script-init-pass-user-no-writes.py +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/tests/hub-cloud/scripts/script-to-fail-managed-storage.py +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/tests/hub-cloud/test_delete_instance.py +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/tests/hub-cloud/test_edge_request.py +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/tests/hub-cloud/test_fail_managed_storage.py +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/tests/hub-cloud/test_init_pass_user_no_writes.py +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/tests/hub-cloud/test_login.py +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/tests/hub-cloud/test_set_storage.py +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/tests/hub-local/scripts/script-connect-fine-grained-access.py +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/tests/hub-local/test_update_schema_in_hub.py +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/tests/hub-prod/conftest.py +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/tests/hub-prod/test_aws_options_manager.py +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/tests/hub-prod/test_django.py +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/tests/hub-prod/test_global_settings.py +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/tests/hub-prod/test_migrate.py +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/tests/hub-prod/test_switch_and_fallback_env.py +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/tests/hub-prod/test_upath.py +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/tests/storage/test_entry_point.py +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/tests/storage/test_hashing.py +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/tests/storage/test_storage_access.py +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/tests/storage/test_storage_basis.py +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/tests/storage/test_storage_settings.py +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/tests/storage/test_storage_stats.py +0 -0
- {lamindb_setup-1.11.0 → lamindb_setup-1.12.0}/tests/storage/test_to_url.py +0 -0
|
@@ -15,7 +15,7 @@ jobs:
|
|
|
15
15
|
timeout-minutes: 12
|
|
16
16
|
steps:
|
|
17
17
|
- uses: actions/checkout@v4
|
|
18
|
-
- uses: actions/setup-python@
|
|
18
|
+
- uses: actions/setup-python@v6
|
|
19
19
|
with:
|
|
20
20
|
python-version: "3.10"
|
|
21
21
|
cache: "pip"
|
|
@@ -52,7 +52,7 @@ jobs:
|
|
|
52
52
|
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
|
53
53
|
aws-region: eu-central-1
|
|
54
54
|
- uses: actions/checkout@v4
|
|
55
|
-
- uses: actions/setup-python@
|
|
55
|
+
- uses: actions/setup-python@v6
|
|
56
56
|
with:
|
|
57
57
|
python-version: ${{ matrix.python-version }}
|
|
58
58
|
cache: "pip"
|
|
@@ -97,7 +97,7 @@ jobs:
|
|
|
97
97
|
timeout-minutes: 12
|
|
98
98
|
steps:
|
|
99
99
|
- uses: actions/checkout@v4
|
|
100
|
-
- uses: actions/setup-python@
|
|
100
|
+
- uses: actions/setup-python@v6
|
|
101
101
|
with:
|
|
102
102
|
python-version: "3.10"
|
|
103
103
|
cache: "pip"
|
|
@@ -139,7 +139,7 @@ jobs:
|
|
|
139
139
|
echo "AWS_ACCESS_KEY_ID_HOSTED_S3=${{ secrets.AWS_ACCESS_KEY_ID }}" >> .env.local
|
|
140
140
|
echo "AWS_SECRET_ACCESS_KEY_HOSTED_S3=${{ secrets.AWS_SECRET_ACCESS_KEY }}" >> .env.local
|
|
141
141
|
working-directory: laminhub/rest-hub/supabase
|
|
142
|
-
- uses: actions/setup-python@
|
|
142
|
+
- uses: actions/setup-python@v6
|
|
143
143
|
with:
|
|
144
144
|
python-version: "3.11" # we need to run everything for coverage on 3.11
|
|
145
145
|
cache: "pip"
|
|
@@ -168,7 +168,7 @@ jobs:
|
|
|
168
168
|
runs-on: ubuntu-latest
|
|
169
169
|
steps:
|
|
170
170
|
- uses: actions/checkout@v4
|
|
171
|
-
- uses: actions/setup-python@
|
|
171
|
+
- uses: actions/setup-python@v6
|
|
172
172
|
with:
|
|
173
173
|
python-version: "3.11"
|
|
174
174
|
cache: "pip"
|
|
@@ -205,7 +205,7 @@ jobs:
|
|
|
205
205
|
ssh-key: ${{ secrets.READ_LNDOCS }}
|
|
206
206
|
path: lndocs
|
|
207
207
|
ref: main
|
|
208
|
-
- uses: actions/setup-python@
|
|
208
|
+
- uses: actions/setup-python@v6
|
|
209
209
|
with:
|
|
210
210
|
python-version: "3.10"
|
|
211
211
|
cache: "pip"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
repos:
|
|
2
2
|
- repo: https://github.com/rbubley/mirrors-prettier
|
|
3
|
-
rev: v3.
|
|
3
|
+
rev: v3.6.2
|
|
4
4
|
hooks:
|
|
5
5
|
- id: prettier
|
|
6
6
|
exclude: |
|
|
@@ -17,13 +17,13 @@ repos:
|
|
|
17
17
|
docs/notes/
|
|
18
18
|
)
|
|
19
19
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
20
|
-
rev: v0.
|
|
20
|
+
rev: v0.14.0
|
|
21
21
|
hooks:
|
|
22
|
-
- id: ruff
|
|
22
|
+
- id: ruff-check
|
|
23
23
|
args: [--fix, --exit-non-zero-on-fix, --unsafe-fixes]
|
|
24
24
|
- id: ruff-format
|
|
25
25
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
26
|
-
rev:
|
|
26
|
+
rev: v6.0.0
|
|
27
27
|
hooks:
|
|
28
28
|
- id: detect-private-key
|
|
29
29
|
- id: check-ast
|
|
@@ -37,7 +37,7 @@ repos:
|
|
|
37
37
|
- id: trailing-whitespace
|
|
38
38
|
- id: check-case-conflict
|
|
39
39
|
- repo: https://github.com/pre-commit/mirrors-mypy
|
|
40
|
-
rev: v1.
|
|
40
|
+
rev: v1.18.1
|
|
41
41
|
hooks:
|
|
42
42
|
- id: mypy
|
|
43
43
|
exclude: |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: lamindb_setup
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.12.0
|
|
4
4
|
Summary: Setup & configure LaminDB.
|
|
5
5
|
Author-email: Lamin Labs <open-source@lamin.ai>
|
|
6
6
|
Requires-Python: >=3.10
|
|
@@ -10,10 +10,11 @@ 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: platformdirs<5.0.0
|
|
13
|
+
Requires-Dist: httpx_retries<1.0.0
|
|
13
14
|
Requires-Dist: requests
|
|
14
15
|
Requires-Dist: universal_pathlib==0.2.6
|
|
15
16
|
Requires-Dist: botocore<2.0.0
|
|
16
|
-
Requires-Dist: supabase>=2.8.1,<=2.
|
|
17
|
+
Requires-Dist: supabase>=2.8.1,<=2.16.0
|
|
17
18
|
Requires-Dist: gotrue<=2.12.0
|
|
18
19
|
Requires-Dist: storage3!=0.11.2; python_version < '3.11'
|
|
19
20
|
Requires-Dist: pyjwt<3.0.0
|
|
@@ -8,10 +8,14 @@
|
|
|
8
8
|
]
|
|
9
9
|
},
|
|
10
10
|
{
|
|
11
|
-
"cell_type": "
|
|
11
|
+
"cell_type": "code",
|
|
12
|
+
"execution_count": null,
|
|
12
13
|
"metadata": {},
|
|
14
|
+
"outputs": [],
|
|
13
15
|
"source": [
|
|
14
|
-
"
|
|
16
|
+
"!lamin login testuser1\n",
|
|
17
|
+
"!lamin init --storage \"./testsetup-prepare\"\n",
|
|
18
|
+
"!lamin disconnect"
|
|
15
19
|
]
|
|
16
20
|
},
|
|
17
21
|
{
|
|
@@ -20,8 +24,16 @@
|
|
|
20
24
|
"metadata": {},
|
|
21
25
|
"outputs": [],
|
|
22
26
|
"source": [
|
|
23
|
-
"
|
|
24
|
-
"
|
|
27
|
+
"import lamindb_setup as ln_setup\n",
|
|
28
|
+
"import lamindb as ln\n",
|
|
29
|
+
"import pytest"
|
|
30
|
+
]
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"cell_type": "markdown",
|
|
34
|
+
"metadata": {},
|
|
35
|
+
"source": [
|
|
36
|
+
"If you try to use lamindb, it will raise an `CurrentInstanceNotConfigured` and ask you to `init` or `connect` an instance via the python API."
|
|
25
37
|
]
|
|
26
38
|
},
|
|
27
39
|
{
|
|
@@ -30,8 +42,8 @@
|
|
|
30
42
|
"metadata": {},
|
|
31
43
|
"outputs": [],
|
|
32
44
|
"source": [
|
|
33
|
-
"
|
|
34
|
-
"
|
|
45
|
+
"with pytest.raises(ln.setup.errors.CurrentInstanceNotConfigured):\n",
|
|
46
|
+
" ln.track()"
|
|
35
47
|
]
|
|
36
48
|
},
|
|
37
49
|
{
|
|
@@ -98,6 +110,71 @@
|
|
|
98
110
|
" User.objects.get(handle=\"testuser2\")"
|
|
99
111
|
]
|
|
100
112
|
},
|
|
113
|
+
{
|
|
114
|
+
"cell_type": "code",
|
|
115
|
+
"execution_count": null,
|
|
116
|
+
"metadata": {},
|
|
117
|
+
"outputs": [],
|
|
118
|
+
"source": [
|
|
119
|
+
"ln.track()"
|
|
120
|
+
]
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
"cell_type": "markdown",
|
|
124
|
+
"metadata": {},
|
|
125
|
+
"source": [
|
|
126
|
+
"Let us try connecting to another instance:"
|
|
127
|
+
]
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
"cell_type": "code",
|
|
131
|
+
"execution_count": null,
|
|
132
|
+
"metadata": {},
|
|
133
|
+
"outputs": [],
|
|
134
|
+
"source": [
|
|
135
|
+
"with pytest.raises(ln.setup.errors.CannotSwitchDefaultInstance) as error:\n",
|
|
136
|
+
" ln.connect(\"testsetup3\")\n",
|
|
137
|
+
"assert error.exconly().endswith(\n",
|
|
138
|
+
" \"Cannot switch default instance while `ln.track()` is live: call `ln.finish()`\"\n",
|
|
139
|
+
")"
|
|
140
|
+
]
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
"cell_type": "markdown",
|
|
144
|
+
"metadata": {},
|
|
145
|
+
"source": [
|
|
146
|
+
"Let us try to init another instance in the same Python session."
|
|
147
|
+
]
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
"cell_type": "code",
|
|
151
|
+
"execution_count": null,
|
|
152
|
+
"metadata": {},
|
|
153
|
+
"outputs": [],
|
|
154
|
+
"source": [
|
|
155
|
+
"with pytest.raises(ln.setup.errors.CannotSwitchDefaultInstance) as error:\n",
|
|
156
|
+
" ln.setup.init(storage=\"./testsetup2\")\n",
|
|
157
|
+
"assert error.exconly().endswith(\n",
|
|
158
|
+
" \"Cannot switch default instance while `ln.track()` is live: call `ln.finish()`\"\n",
|
|
159
|
+
")"
|
|
160
|
+
]
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
"cell_type": "markdown",
|
|
164
|
+
"metadata": {},
|
|
165
|
+
"source": [
|
|
166
|
+
"Switch off `ln.track()`."
|
|
167
|
+
]
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
"cell_type": "code",
|
|
171
|
+
"execution_count": null,
|
|
172
|
+
"metadata": {},
|
|
173
|
+
"outputs": [],
|
|
174
|
+
"source": [
|
|
175
|
+
"ln.context._transform = None"
|
|
176
|
+
]
|
|
177
|
+
},
|
|
101
178
|
{
|
|
102
179
|
"cell_type": "markdown",
|
|
103
180
|
"metadata": {},
|
|
@@ -104,6 +104,7 @@ def _connect_instance(
|
|
|
104
104
|
db: str | None = None,
|
|
105
105
|
raise_permission_error: bool = True,
|
|
106
106
|
use_root_db_user: bool = False,
|
|
107
|
+
use_proxy_db: bool = False,
|
|
107
108
|
access_token: str | None = None,
|
|
108
109
|
) -> InstanceSettings:
|
|
109
110
|
settings_file = instance_settings_file(name, owner)
|
|
@@ -118,8 +119,7 @@ def _connect_instance(
|
|
|
118
119
|
if db is not None and isettings.dialect == "postgresql":
|
|
119
120
|
isettings._db = db
|
|
120
121
|
if make_hub_request:
|
|
121
|
-
# the following will return a string if the instance does not exist
|
|
122
|
-
# on the hub
|
|
122
|
+
# the following will return a string if the instance does not exist on the hub
|
|
123
123
|
# do not call hub if the user is anonymous
|
|
124
124
|
if owner != "anonymous":
|
|
125
125
|
hub_result = connect_instance_hub(
|
|
@@ -127,6 +127,7 @@ def _connect_instance(
|
|
|
127
127
|
name=name,
|
|
128
128
|
access_token=access_token,
|
|
129
129
|
use_root_db_user=use_root_db_user,
|
|
130
|
+
use_proxy_db=use_proxy_db,
|
|
130
131
|
)
|
|
131
132
|
else:
|
|
132
133
|
hub_result = "anonymous-user"
|
|
@@ -192,8 +193,7 @@ def reset_django_module_variables():
|
|
|
192
193
|
# import lamindb as ln
|
|
193
194
|
# ln.connect(...)
|
|
194
195
|
#
|
|
195
|
-
# Then it will **not** work and the `ln` variable becomes stale and hold a reference
|
|
196
|
-
# to the old classes
|
|
196
|
+
# Then it will **not** work and the `ln` variable becomes stale and hold a reference to the old classes
|
|
197
197
|
# Other functions that dynamically import are no problem because the variables
|
|
198
198
|
# are automatically refreshed when the function runs the next time after ln.connect() was called
|
|
199
199
|
logger.debug("resetting django module variables")
|
|
@@ -242,11 +242,15 @@ def reset_django_module_variables():
|
|
|
242
242
|
continue
|
|
243
243
|
|
|
244
244
|
|
|
245
|
-
def _connect_cli(
|
|
245
|
+
def _connect_cli(
|
|
246
|
+
instance: str, use_root_db_user: bool = False, use_proxy_db: bool = False
|
|
247
|
+
) -> None:
|
|
246
248
|
from lamindb_setup import settings as settings_
|
|
247
249
|
|
|
248
250
|
owner, name = get_owner_name_from_identifier(instance)
|
|
249
|
-
isettings = _connect_instance(
|
|
251
|
+
isettings = _connect_instance(
|
|
252
|
+
owner, name, use_root_db_user=use_root_db_user, use_proxy_db=use_proxy_db
|
|
253
|
+
)
|
|
250
254
|
isettings._persist(write_to_disk=True)
|
|
251
255
|
if not isettings.is_on_hub or isettings._is_cloud_sqlite:
|
|
252
256
|
# there are two reasons to call the full-blown connect
|
|
@@ -259,6 +263,36 @@ def _connect_cli(instance: str, use_root_db_user: bool = False) -> None:
|
|
|
259
263
|
return None
|
|
260
264
|
|
|
261
265
|
|
|
266
|
+
def validate_connection_state(
|
|
267
|
+
owner: str, name: str, use_root_db_user: bool = False
|
|
268
|
+
) -> None:
|
|
269
|
+
from django.db import connection
|
|
270
|
+
|
|
271
|
+
if (
|
|
272
|
+
settings._instance_exists
|
|
273
|
+
and f"{owner}/{name}" == settings.instance.slug
|
|
274
|
+
# below is to ensure that if another process interferes
|
|
275
|
+
# we don't use the in-memory mock database
|
|
276
|
+
# could be made more specific by checking whether the django
|
|
277
|
+
# configured database is the same as the one in settings
|
|
278
|
+
and connection.settings_dict["NAME"] != ":memory:"
|
|
279
|
+
and not use_root_db_user # always re-connect for root db user
|
|
280
|
+
):
|
|
281
|
+
logger.important(
|
|
282
|
+
f"doing nothing, already connected lamindb: {settings.instance.slug}"
|
|
283
|
+
)
|
|
284
|
+
return None
|
|
285
|
+
else:
|
|
286
|
+
if settings._instance_exists and settings.instance.slug != "none/none":
|
|
287
|
+
import lamindb as ln
|
|
288
|
+
|
|
289
|
+
if ln.context.transform is not None:
|
|
290
|
+
raise CannotSwitchDefaultInstance(
|
|
291
|
+
"Cannot switch default instance while `ln.track()` is live: call `ln.finish()`"
|
|
292
|
+
)
|
|
293
|
+
reset_django()
|
|
294
|
+
|
|
295
|
+
|
|
262
296
|
@unlock_cloud_sqlite_upon_exception(ignore_prev_locker=True)
|
|
263
297
|
def connect(instance: str | None = None, **kwargs: Any) -> str | tuple | None:
|
|
264
298
|
"""Connect to an instance.
|
|
@@ -274,6 +308,7 @@ def connect(instance: str | None = None, **kwargs: Any) -> str | tuple | None:
|
|
|
274
308
|
# validate kwargs
|
|
275
309
|
valid_kwargs = {
|
|
276
310
|
"use_root_db_user",
|
|
311
|
+
"use_proxy_db",
|
|
277
312
|
"_db",
|
|
278
313
|
"_write_settings",
|
|
279
314
|
"_raise_not_found_error",
|
|
@@ -284,15 +319,18 @@ def connect(instance: str | None = None, **kwargs: Any) -> str | tuple | None:
|
|
|
284
319
|
for kwarg in kwargs:
|
|
285
320
|
if kwarg not in valid_kwargs:
|
|
286
321
|
raise TypeError(f"connect() got unexpected keyword argument '{kwarg}'")
|
|
287
|
-
|
|
288
|
-
# _db is still needed because it is called in init
|
|
322
|
+
|
|
289
323
|
use_root_db_user: bool = kwargs.get("use_root_db_user", False)
|
|
324
|
+
use_proxy_db = kwargs.get("use_proxy_db", False)
|
|
325
|
+
# _db is still needed because it is called in init
|
|
290
326
|
_db: str | None = kwargs.get("_db", None)
|
|
291
327
|
_write_settings: bool = kwargs.get("_write_settings", False)
|
|
292
328
|
_raise_not_found_error: bool = kwargs.get("_raise_not_found_error", True)
|
|
293
329
|
_reload_lamindb: bool = kwargs.get("_reload_lamindb", True)
|
|
294
330
|
_test: bool = kwargs.get("_test", False)
|
|
295
331
|
|
|
332
|
+
isettings: InstanceSettings = None # type: ignore
|
|
333
|
+
|
|
296
334
|
access_token: str | None = None
|
|
297
335
|
_user: UserSettings | None = kwargs.get("_user", None)
|
|
298
336
|
if _user is not None:
|
|
@@ -317,36 +355,11 @@ def connect(instance: str | None = None, **kwargs: Any) -> str | tuple | None:
|
|
|
317
355
|
if _db is not None and isettings.dialect == "postgresql":
|
|
318
356
|
isettings._db = _db
|
|
319
357
|
else:
|
|
320
|
-
from django.db import connection
|
|
321
|
-
|
|
322
358
|
owner, name = get_owner_name_from_identifier(instance)
|
|
323
359
|
if _check_instance_setup() and not _test:
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
# below is to ensure that if another process interferes
|
|
328
|
-
# we don't use the in-memory mock database
|
|
329
|
-
# could be made more specific by checking whether the django
|
|
330
|
-
# configured database is the same as the one in settings
|
|
331
|
-
and connection.settings_dict["NAME"] != ":memory:"
|
|
332
|
-
and not use_root_db_user # always re-connect for root db user
|
|
333
|
-
):
|
|
334
|
-
logger.important(
|
|
335
|
-
f"doing nothing, already connected lamindb: {settings.instance.slug}"
|
|
336
|
-
)
|
|
337
|
-
return None
|
|
338
|
-
else:
|
|
339
|
-
if (
|
|
340
|
-
settings._instance_exists
|
|
341
|
-
and settings.instance.slug != "none/none"
|
|
342
|
-
):
|
|
343
|
-
import lamindb as ln
|
|
344
|
-
|
|
345
|
-
if ln.context.transform is not None:
|
|
346
|
-
raise CannotSwitchDefaultInstance(
|
|
347
|
-
"Cannot switch default instance while `ln.track()` is live: call `ln.finish()`"
|
|
348
|
-
)
|
|
349
|
-
reset_django()
|
|
360
|
+
validate_connection_state(
|
|
361
|
+
owner, name, use_root_db_user=use_root_db_user
|
|
362
|
+
)
|
|
350
363
|
elif (
|
|
351
364
|
_write_settings
|
|
352
365
|
and settings._instance_exists
|
|
@@ -362,6 +375,7 @@ def connect(instance: str | None = None, **kwargs: Any) -> str | tuple | None:
|
|
|
362
375
|
db=_db,
|
|
363
376
|
access_token=access_token,
|
|
364
377
|
use_root_db_user=use_root_db_user,
|
|
378
|
+
use_proxy_db=use_proxy_db,
|
|
365
379
|
)
|
|
366
380
|
except InstanceNotFoundError as e:
|
|
367
381
|
if _raise_not_found_error:
|
|
@@ -416,7 +430,7 @@ def connect(instance: str | None = None, **kwargs: Any) -> str | tuple | None:
|
|
|
416
430
|
return None
|
|
417
431
|
|
|
418
432
|
|
|
419
|
-
def get_owner_name_from_identifier(identifier: str):
|
|
433
|
+
def get_owner_name_from_identifier(identifier: str) -> tuple[str, str]:
|
|
420
434
|
if "/" in identifier:
|
|
421
435
|
if identifier.startswith("https://lamin.ai/"):
|
|
422
436
|
identifier = identifier.replace("https://lamin.ai/", "")
|
|
@@ -21,6 +21,8 @@ if TYPE_CHECKING:
|
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
def delete_cache(isettings: InstanceSettings):
|
|
24
|
+
if isettings.storage is None:
|
|
25
|
+
return
|
|
24
26
|
# avoid init of root
|
|
25
27
|
root = isettings.storage._root_init
|
|
26
28
|
if not isinstance(root, LocalPathClasses):
|
|
@@ -40,7 +42,7 @@ def delete_by_isettings(isettings: InstanceSettings) -> None:
|
|
|
40
42
|
if settings_file.exists():
|
|
41
43
|
settings_file.unlink()
|
|
42
44
|
delete_cache(isettings)
|
|
43
|
-
if isettings.dialect == "sqlite":
|
|
45
|
+
if isettings.dialect == "sqlite" and isettings.storage is not None:
|
|
44
46
|
try:
|
|
45
47
|
if isettings._sqlite_file.exists():
|
|
46
48
|
isettings._sqlite_file.unlink()
|
|
@@ -3,7 +3,6 @@ from __future__ import annotations
|
|
|
3
3
|
import importlib
|
|
4
4
|
import os
|
|
5
5
|
import uuid
|
|
6
|
-
from pathlib import Path
|
|
7
6
|
from typing import TYPE_CHECKING, Literal
|
|
8
7
|
from uuid import UUID
|
|
9
8
|
|
|
@@ -17,12 +16,13 @@ from ._silence_loggers import silence_loggers
|
|
|
17
16
|
from .core import InstanceSettings
|
|
18
17
|
from .core._docs import doc_args
|
|
19
18
|
from .core._settings import settings
|
|
20
|
-
from .core._settings_instance import check_is_instance_remote
|
|
19
|
+
from .core._settings_instance import check_is_instance_remote
|
|
21
20
|
from .core._settings_storage import StorageSettings, init_storage
|
|
22
21
|
from .core.upath import UPath
|
|
23
22
|
from .errors import CannotSwitchDefaultInstance
|
|
24
23
|
|
|
25
24
|
if TYPE_CHECKING:
|
|
25
|
+
from lamindb.models import Storage
|
|
26
26
|
from pydantic import PostgresDsn
|
|
27
27
|
|
|
28
28
|
from .core._settings_user import UserSettings
|
|
@@ -50,7 +50,7 @@ def get_schema_module_name(module_name, raise_import_error: bool = True) -> str
|
|
|
50
50
|
return None
|
|
51
51
|
|
|
52
52
|
|
|
53
|
-
def register_storage_in_instance(ssettings: StorageSettings):
|
|
53
|
+
def register_storage_in_instance(ssettings: StorageSettings) -> Storage:
|
|
54
54
|
from lamindb.models import Storage
|
|
55
55
|
|
|
56
56
|
# how do we ensure that this function is only called passing
|
|
@@ -70,7 +70,7 @@ def register_storage_in_instance(ssettings: StorageSettings):
|
|
|
70
70
|
return storage
|
|
71
71
|
|
|
72
72
|
|
|
73
|
-
def register_user(usettings: UserSettings, update_user: bool = True):
|
|
73
|
+
def register_user(usettings: UserSettings, update_user: bool = True) -> None:
|
|
74
74
|
from lamindb.models import User
|
|
75
75
|
|
|
76
76
|
if not update_user and User.objects.filter(uid=usettings.uid).exists():
|
|
@@ -92,7 +92,9 @@ def register_user(usettings: UserSettings, update_user: bool = True):
|
|
|
92
92
|
pass
|
|
93
93
|
|
|
94
94
|
|
|
95
|
-
def register_initial_records(
|
|
95
|
+
def register_initial_records(
|
|
96
|
+
isettings: InstanceSettings, usettings: UserSettings
|
|
97
|
+
) -> None:
|
|
96
98
|
"""Register space, user & storage in DB."""
|
|
97
99
|
from django.db.utils import OperationalError
|
|
98
100
|
from lamindb.models import Branch, Space
|
|
@@ -246,6 +248,15 @@ def init(
|
|
|
246
248
|
See Also:
|
|
247
249
|
Init an instance for via the CLI, see `here <https://docs.lamin.ai/cli#init>`__.
|
|
248
250
|
"""
|
|
251
|
+
from ._check_setup import _check_instance_setup
|
|
252
|
+
from ._connect_instance import (
|
|
253
|
+
reset_django_module_variables,
|
|
254
|
+
validate_connection_state,
|
|
255
|
+
)
|
|
256
|
+
from .core._hub_core import init_instance_hub
|
|
257
|
+
|
|
258
|
+
silence_loggers()
|
|
259
|
+
|
|
249
260
|
isettings = None
|
|
250
261
|
ssettings = None
|
|
251
262
|
|
|
@@ -262,22 +273,6 @@ def init(
|
|
|
262
273
|
access_token: str | None = None if _user is None else _user.access_token
|
|
263
274
|
|
|
264
275
|
try:
|
|
265
|
-
silence_loggers()
|
|
266
|
-
from ._check_setup import _check_instance_setup
|
|
267
|
-
|
|
268
|
-
if _check_instance_setup() and not _test:
|
|
269
|
-
from lamindb_setup.core.django import reset_django
|
|
270
|
-
|
|
271
|
-
if settings._instance_exists:
|
|
272
|
-
raise CannotSwitchDefaultInstance(
|
|
273
|
-
"Cannot init new instance after connecting to an existing instance."
|
|
274
|
-
)
|
|
275
|
-
reset_django()
|
|
276
|
-
elif _write_settings:
|
|
277
|
-
disconnect(mute=True)
|
|
278
|
-
from ._connect_instance import reset_django_module_variables
|
|
279
|
-
from .core._hub_core import init_instance_hub
|
|
280
|
-
|
|
281
276
|
name_str, instance_id, instance_state, _ = validate_init_args(
|
|
282
277
|
storage=storage,
|
|
283
278
|
name=name,
|
|
@@ -289,6 +284,10 @@ def init(
|
|
|
289
284
|
)
|
|
290
285
|
if instance_state == "connected":
|
|
291
286
|
return None
|
|
287
|
+
if _check_instance_setup() and not _test:
|
|
288
|
+
validate_connection_state(user_handle, name_str)
|
|
289
|
+
elif _write_settings:
|
|
290
|
+
disconnect(mute=True)
|
|
292
291
|
isettings = InstanceSettings(
|
|
293
292
|
id=instance_id, # type: ignore
|
|
294
293
|
owner=user_handle,
|
|
@@ -379,10 +378,8 @@ def load_from_isettings(
|
|
|
379
378
|
else:
|
|
380
379
|
# when loading, django is already set up
|
|
381
380
|
#
|
|
382
|
-
# only register user if the instance is connected
|
|
383
|
-
# for the
|
|
384
|
-
# this is our best proxy for that the user might not
|
|
385
|
-
# yet be registered
|
|
381
|
+
# only register user if the instance is connected for the first time in an environment
|
|
382
|
+
# this is our best proxy for that the user might not yet be registered
|
|
386
383
|
if not isettings._get_settings_file().exists():
|
|
387
384
|
# do not try to update the user on fine grained access instances
|
|
388
385
|
# this is blocked anyways, only select and insert are allowed
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
import httpx
|
|
4
4
|
from django.db import connection
|
|
5
5
|
from django.db.migrations.loader import MigrationLoader
|
|
6
6
|
from lamin_utils import logger
|
|
@@ -146,7 +146,7 @@ class migrate:
|
|
|
146
146
|
logger.warning(
|
|
147
147
|
"clearing instance cache in hub; if this fails, re-run with latest lamindb version"
|
|
148
148
|
)
|
|
149
|
-
|
|
149
|
+
httpx.delete(
|
|
150
150
|
f"{settings.instance.api_url}/cache/instances/{settings.instance._id.hex}",
|
|
151
151
|
headers={"Authorization": f"Bearer {settings.user.access_token}"},
|
|
152
152
|
)
|
|
@@ -71,9 +71,9 @@ def _synchronize_schema(client: Client) -> tuple[bool, UUID, dict]:
|
|
|
71
71
|
.eq("id", settings.instance._id.hex)
|
|
72
72
|
.execute()
|
|
73
73
|
)
|
|
74
|
-
assert (
|
|
75
|
-
|
|
76
|
-
)
|
|
74
|
+
assert len(instance_response.data) == 1, (
|
|
75
|
+
f"schema of instance {settings.instance._id.hex} could not be updated with schema {schema_uuid.hex}"
|
|
76
|
+
)
|
|
77
77
|
|
|
78
78
|
return is_new, schema_uuid, schema
|
|
79
79
|
|
|
@@ -29,8 +29,7 @@ def _keep_trailing_slash(path_str: str) -> str:
|
|
|
29
29
|
AWS_CREDENTIALS_EXPIRATION: int = 11 * 60 * 60 # refresh credentials after 11 hours
|
|
30
30
|
|
|
31
31
|
|
|
32
|
-
# set anon=True for these buckets if credentials fail for a public bucket
|
|
33
|
-
# to be expanded
|
|
32
|
+
# set anon=True for these buckets if credentials fail for a public bucket to be expanded
|
|
34
33
|
PUBLIC_BUCKETS: tuple[str, ...] = ("cellxgene-data-public", "bionty-assets")
|
|
35
34
|
|
|
36
35
|
|
|
@@ -155,8 +154,7 @@ class AWSOptionsManager:
|
|
|
155
154
|
# this option is needed for correct uploads to R2
|
|
156
155
|
path = UPath(path, fixed_upload_size=True)
|
|
157
156
|
return path
|
|
158
|
-
# trailing slash is needed to avoid returning incorrect results
|
|
159
|
-
# with .startswith
|
|
157
|
+
# trailing slash is needed to avoid returning incorrect results with .startswith
|
|
160
158
|
# for example s3://lamindata-eu should not receive cache for s3://lamindata
|
|
161
159
|
path_str = _keep_trailing_slash(path.as_posix())
|
|
162
160
|
root = self._find_root(path_str)
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import httpx
|
|
3
4
|
from lamin_utils import logger
|
|
4
5
|
|
|
5
6
|
|
|
6
7
|
def get_location(ip="ipinfo.io"):
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
response = requests.get(f"http://{ip}/json").json()
|
|
8
|
+
response = httpx.get(f"http://{ip}/json").json()
|
|
10
9
|
loc = response["loc"].split(",")
|
|
11
10
|
return {"latitude": float(loc[0]), "longitude": float(loc[1])}
|
|
12
11
|
|