lamindb_setup 1.10.0__tar.gz → 1.10.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.10.0 → lamindb_setup-1.10.2}/PKG-INFO +2 -2
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/docs/hub-cloud/02-connect-local-instance.ipynb +15 -11
- lamindb_setup-1.10.2/docs/hub-cloud/09-test-migrate.ipynb +94 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/docs/hub-prod/test-import-schema.ipynb +3 -4
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/lamindb_setup/__init__.py +1 -1
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/lamindb_setup/_connect_instance.py +44 -26
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/lamindb_setup/_migrate.py +7 -7
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/lamindb_setup/core/_deprecated.py +1 -1
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/lamindb_setup/core/_hub_core.py +30 -7
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/lamindb_setup/core/_hub_crud.py +40 -20
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/lamindb_setup/core/_settings.py +4 -14
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/lamindb_setup/core/_settings_instance.py +32 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/lamindb_setup/core/django.py +3 -7
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/pyproject.toml +1 -1
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/tests/hub-cloud/test_connect_instance.py +4 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/tests/hub-cloud/test_init_instance.py +3 -1
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/tests/hub-local/scripts/script-connect-fine-grained-access.py +4 -1
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/tests/hub-local/test_all.py +93 -53
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/tests/hub-prod/test_django.py +0 -4
- lamindb_setup-1.10.2/tests/hub-prod/test_migrate.py +13 -0
- lamindb_setup-1.10.0/tests/hub-cloud/test_migrate.py +0 -22
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/.github/workflows/build.yml +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/.github/workflows/doc-changes.yml +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/.gitignore +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/.pre-commit-config.yaml +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/LICENSE +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/README.md +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/docs/changelog.md +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/docs/hub-cloud/01-init-local-instance.ipynb +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/docs/hub-cloud/03-add-managed-storage.ipynb +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/docs/hub-cloud/04-test-bionty.ipynb +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/docs/hub-cloud/05-init-hosted-instance.ipynb +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/docs/hub-cloud/06-connect-hosted-instance.ipynb +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/docs/hub-cloud/07-keep-artifacts-local.ipynb +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/docs/hub-cloud/08-test-multi-session.ipynb +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/docs/hub-cloud/test_notebooks.py +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/docs/hub-prod/test-cache-management.ipynb +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/docs/hub-prod/test-cloud-sync.ipynb +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/docs/hub-prod/test-connect-anonymously.ipynb +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/docs/hub-prod/test-empty-init.ipynb +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/docs/hub-prod/test-init-load-local-anonymously.ipynb +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/docs/hub-prod/test-insufficient-user-info.ipynb +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/docs/hub-prod/test-invalid-schema.ipynb +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/docs/hub-prod/test-sqlite-lock.ipynb +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/docs/hub-prod/test_notebooks2.py +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/docs/index.md +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/docs/notebooks.md +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/docs/reference.md +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/lamindb_setup/_cache.py +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/lamindb_setup/_check.py +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/lamindb_setup/_check_setup.py +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/lamindb_setup/_delete.py +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/lamindb_setup/_disconnect.py +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/lamindb_setup/_django.py +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/lamindb_setup/_entry_points.py +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/lamindb_setup/_exportdb.py +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/lamindb_setup/_importdb.py +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/lamindb_setup/_init_instance.py +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/lamindb_setup/_register_instance.py +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/lamindb_setup/_schema.py +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/lamindb_setup/_schema_metadata.py +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/lamindb_setup/_set_managed_storage.py +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/lamindb_setup/_setup_user.py +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/lamindb_setup/_silence_loggers.py +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/lamindb_setup/core/__init__.py +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/lamindb_setup/core/_aws_options.py +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/lamindb_setup/core/_aws_storage.py +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/lamindb_setup/core/_docs.py +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/lamindb_setup/core/_hub_client.py +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/lamindb_setup/core/_hub_utils.py +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/lamindb_setup/core/_private_django_api.py +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/lamindb_setup/core/_settings_load.py +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/lamindb_setup/core/_settings_save.py +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/lamindb_setup/core/_settings_storage.py +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/lamindb_setup/core/_settings_store.py +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/lamindb_setup/core/_settings_user.py +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/lamindb_setup/core/_setup_bionty_sources.py +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/lamindb_setup/core/cloud_sqlite_locker.py +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/lamindb_setup/core/exceptions.py +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/lamindb_setup/core/hashing.py +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/lamindb_setup/core/types.py +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/lamindb_setup/core/upath.py +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/lamindb_setup/errors.py +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/lamindb_setup/py.typed +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/lamindb_setup/types.py +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/noxfile.py +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/tests/hub-cloud/scripts/script-init-pass-user-no-writes.py +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/tests/hub-cloud/scripts/script-to-fail-managed-storage.py +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/tests/hub-cloud/test_delete_instance.py +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/tests/hub-cloud/test_edge_request.py +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/tests/hub-cloud/test_fail_managed_storage.py +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/tests/hub-cloud/test_init_pass_user_no_writes.py +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/tests/hub-cloud/test_login.py +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/tests/hub-cloud/test_set_storage.py +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/tests/hub-local/conftest.py +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/tests/hub-local/test_update_schema_in_hub.py +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/tests/hub-prod/conftest.py +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/tests/hub-prod/test_aws_options_manager.py +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/tests/hub-prod/test_global_settings.py +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/tests/hub-prod/test_switch_and_fallback_env.py +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/tests/hub-prod/test_upath.py +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/tests/storage/test_entry_point.py +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/tests/storage/test_hashing.py +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/tests/storage/test_storage_access.py +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/tests/storage/test_storage_basis.py +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/tests/storage/test_storage_settings.py +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/tests/storage/test_storage_stats.py +0 -0
- {lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/tests/storage/test_to_url.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: lamindb_setup
|
|
3
|
-
Version: 1.10.
|
|
3
|
+
Version: 1.10.2
|
|
4
4
|
Summary: Setup & configure LaminDB.
|
|
5
5
|
Author-email: Lamin Labs <open-source@lamin.ai>
|
|
6
6
|
Requires-Python: >=3.10
|
|
@@ -27,7 +27,7 @@ Requires-Dist: psycopg2-binary ; extra == "dev"
|
|
|
27
27
|
Requires-Dist: python-dotenv ; extra == "dev"
|
|
28
28
|
Requires-Dist: nox ; extra == "dev"
|
|
29
29
|
Requires-Dist: pytest>=6.0 ; extra == "dev"
|
|
30
|
-
Requires-Dist: pytest-cov ; extra == "dev"
|
|
30
|
+
Requires-Dist: pytest-cov<7.0.0 ; extra == "dev"
|
|
31
31
|
Requires-Dist: pytest-xdist ; extra == "dev"
|
|
32
32
|
Requires-Dist: nbproject-test>=0.4.3 ; extra == "dev"
|
|
33
33
|
Requires-Dist: pandas ; extra == "dev"
|
{lamindb_setup-1.10.0 → lamindb_setup-1.10.2}/docs/hub-cloud/02-connect-local-instance.ipynb
RENAMED
|
@@ -60,10 +60,7 @@
|
|
|
60
60
|
"metadata": {},
|
|
61
61
|
"outputs": [],
|
|
62
62
|
"source": [
|
|
63
|
-
"#
|
|
64
|
-
"# _check_instance_setup is called inside with from_module=None\n",
|
|
65
|
-
"# the branch where django is not setup yet\n",
|
|
66
|
-
"# as from_module=None it won't connect to an instance here\n",
|
|
63
|
+
"# no instance connected, prompts to connect\n",
|
|
67
64
|
"import bionty"
|
|
68
65
|
]
|
|
69
66
|
},
|
|
@@ -79,6 +76,17 @@
|
|
|
79
76
|
") # also test passing _reload_lamindb explicitly"
|
|
80
77
|
]
|
|
81
78
|
},
|
|
79
|
+
{
|
|
80
|
+
"cell_type": "code",
|
|
81
|
+
"execution_count": null,
|
|
82
|
+
"id": "5a59b8d0",
|
|
83
|
+
"metadata": {},
|
|
84
|
+
"outputs": [],
|
|
85
|
+
"source": [
|
|
86
|
+
"# this is a local intstance, no spaces needed\n",
|
|
87
|
+
"assert ln_setup.settings.instance.available_spaces is None"
|
|
88
|
+
]
|
|
89
|
+
},
|
|
82
90
|
{
|
|
83
91
|
"cell_type": "code",
|
|
84
92
|
"execution_count": null,
|
|
@@ -88,8 +96,7 @@
|
|
|
88
96
|
"source": [
|
|
89
97
|
"# wetlab is not in the (schema) modules of mydata\n",
|
|
90
98
|
"with pytest.raises(ModuleWasntConfigured):\n",
|
|
91
|
-
" # _check_instance_setup is called inside
|
|
92
|
-
" # the branch where django is setup\n",
|
|
99
|
+
" # _check_instance_setup is called inside\n",
|
|
93
100
|
" import wetlab"
|
|
94
101
|
]
|
|
95
102
|
},
|
|
@@ -100,12 +107,9 @@
|
|
|
100
107
|
"metadata": {},
|
|
101
108
|
"outputs": [],
|
|
102
109
|
"source": [
|
|
103
|
-
"#
|
|
110
|
+
"# bionty is not in the (schema) modules of mydata\n",
|
|
104
111
|
"with pytest.raises(ModuleWasntConfigured):\n",
|
|
105
|
-
"
|
|
106
|
-
" # the branch where django is setup\n",
|
|
107
|
-
" # in __getattr__ in __init__.py\n",
|
|
108
|
-
" bionty.CellType"
|
|
112
|
+
" import bionty"
|
|
109
113
|
]
|
|
110
114
|
},
|
|
111
115
|
{
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
{
|
|
2
|
+
"cells": [
|
|
3
|
+
{
|
|
4
|
+
"cell_type": "markdown",
|
|
5
|
+
"id": "5acb0094",
|
|
6
|
+
"metadata": {},
|
|
7
|
+
"source": [
|
|
8
|
+
"# Migrate a hosted instance"
|
|
9
|
+
]
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"cell_type": "code",
|
|
13
|
+
"execution_count": null,
|
|
14
|
+
"id": "213594a4",
|
|
15
|
+
"metadata": {},
|
|
16
|
+
"outputs": [],
|
|
17
|
+
"source": [
|
|
18
|
+
"import lamindb_setup as ln_setup"
|
|
19
|
+
]
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"cell_type": "code",
|
|
23
|
+
"execution_count": null,
|
|
24
|
+
"id": "0a310f89",
|
|
25
|
+
"metadata": {},
|
|
26
|
+
"outputs": [],
|
|
27
|
+
"source": [
|
|
28
|
+
"ln_setup.login(\"testuser1\")"
|
|
29
|
+
]
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"cell_type": "code",
|
|
33
|
+
"execution_count": null,
|
|
34
|
+
"id": "eecceaf0",
|
|
35
|
+
"metadata": {},
|
|
36
|
+
"outputs": [],
|
|
37
|
+
"source": [
|
|
38
|
+
"ln_setup.connect(\"laminlabs/lamindata\", use_root_db_user=True)"
|
|
39
|
+
]
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"cell_type": "code",
|
|
43
|
+
"execution_count": null,
|
|
44
|
+
"id": "ffb9b496",
|
|
45
|
+
"metadata": {},
|
|
46
|
+
"outputs": [],
|
|
47
|
+
"source": [
|
|
48
|
+
"# double connect to check migration with django reset\n",
|
|
49
|
+
"ln_setup.connect(\"laminlabs/lamindata\", use_root_db_user=True)"
|
|
50
|
+
]
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"cell_type": "code",
|
|
54
|
+
"execution_count": null,
|
|
55
|
+
"id": "e9887c91",
|
|
56
|
+
"metadata": {},
|
|
57
|
+
"outputs": [],
|
|
58
|
+
"source": [
|
|
59
|
+
"assert \"root\" in ln_setup.settings.instance.db"
|
|
60
|
+
]
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"cell_type": "code",
|
|
64
|
+
"execution_count": null,
|
|
65
|
+
"id": "657de4c6",
|
|
66
|
+
"metadata": {},
|
|
67
|
+
"outputs": [],
|
|
68
|
+
"source": [
|
|
69
|
+
"ln_setup.migrate.deploy()"
|
|
70
|
+
]
|
|
71
|
+
}
|
|
72
|
+
],
|
|
73
|
+
"metadata": {
|
|
74
|
+
"kernelspec": {
|
|
75
|
+
"display_name": "Python 3 (ipykernel)",
|
|
76
|
+
"language": "python",
|
|
77
|
+
"name": "python3"
|
|
78
|
+
},
|
|
79
|
+
"language_info": {
|
|
80
|
+
"codemirror_mode": {
|
|
81
|
+
"name": "ipython",
|
|
82
|
+
"version": 3
|
|
83
|
+
},
|
|
84
|
+
"file_extension": ".py",
|
|
85
|
+
"mimetype": "text/x-python",
|
|
86
|
+
"name": "python",
|
|
87
|
+
"nbconvert_exporter": "python",
|
|
88
|
+
"pygments_lexer": "ipython3",
|
|
89
|
+
"version": "3.10.16"
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
"nbformat": 4,
|
|
93
|
+
"nbformat_minor": 5
|
|
94
|
+
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"cells": [
|
|
3
3
|
{
|
|
4
|
-
"attachments": {},
|
|
5
4
|
"cell_type": "markdown",
|
|
6
5
|
"id": "261ca5e4-f46f-4361-9c3e-f944bbe14484",
|
|
7
6
|
"metadata": {},
|
|
@@ -16,7 +15,7 @@
|
|
|
16
15
|
"source": [
|
|
17
16
|
"Also see the corresponding FAQ notebook in lamindb: `import-modules`.\n",
|
|
18
17
|
"\n",
|
|
19
|
-
"
|
|
18
|
+
"You'll load the instance in the same way as calling `import lamindb` when you import a schema module."
|
|
20
19
|
]
|
|
21
20
|
},
|
|
22
21
|
{
|
|
@@ -60,7 +59,7 @@
|
|
|
60
59
|
"metadata": {},
|
|
61
60
|
"outputs": [],
|
|
62
61
|
"source": [
|
|
63
|
-
"assert
|
|
62
|
+
"assert lamindb_setup.core.django.IS_SETUP"
|
|
64
63
|
]
|
|
65
64
|
},
|
|
66
65
|
{
|
|
@@ -110,7 +109,7 @@
|
|
|
110
109
|
"name": "python",
|
|
111
110
|
"nbconvert_exporter": "python",
|
|
112
111
|
"pygments_lexer": "ipython3",
|
|
113
|
-
"version": "3.10.
|
|
112
|
+
"version": "3.10.16"
|
|
114
113
|
},
|
|
115
114
|
"nbproject": {
|
|
116
115
|
"id": "2lhqA4uTKSFP",
|
|
@@ -3,6 +3,7 @@ from __future__ import annotations
|
|
|
3
3
|
import importlib
|
|
4
4
|
import os
|
|
5
5
|
import sys
|
|
6
|
+
import types
|
|
6
7
|
from typing import TYPE_CHECKING, Any
|
|
7
8
|
from uuid import UUID
|
|
8
9
|
|
|
@@ -24,6 +25,7 @@ from .core._settings_load import load_instance_settings
|
|
|
24
25
|
from .core._settings_storage import StorageSettings
|
|
25
26
|
from .core._settings_store import instance_settings_file, settings_dir
|
|
26
27
|
from .core.cloud_sqlite_locker import unlock_cloud_sqlite_upon_exception
|
|
28
|
+
from .core.django import reset_django
|
|
27
29
|
from .errors import CannotSwitchDefaultInstance
|
|
28
30
|
|
|
29
31
|
if TYPE_CHECKING:
|
|
@@ -101,6 +103,7 @@ def _connect_instance(
|
|
|
101
103
|
*,
|
|
102
104
|
db: str | None = None,
|
|
103
105
|
raise_permission_error: bool = True,
|
|
106
|
+
use_root_db_user: bool = False,
|
|
104
107
|
access_token: str | None = None,
|
|
105
108
|
) -> InstanceSettings:
|
|
106
109
|
settings_file = instance_settings_file(name, owner)
|
|
@@ -120,7 +123,10 @@ def _connect_instance(
|
|
|
120
123
|
# do not call hub if the user is anonymous
|
|
121
124
|
if owner != "anonymous":
|
|
122
125
|
hub_result = connect_instance_hub(
|
|
123
|
-
owner=owner,
|
|
126
|
+
owner=owner,
|
|
127
|
+
name=name,
|
|
128
|
+
access_token=access_token,
|
|
129
|
+
use_root_db_user=use_root_db_user,
|
|
124
130
|
)
|
|
125
131
|
else:
|
|
126
132
|
hub_result = "anonymous-user"
|
|
@@ -155,7 +161,9 @@ def _connect_instance(
|
|
|
155
161
|
schema_id=None
|
|
156
162
|
if (schema_id := instance_result["schema_id"]) is None
|
|
157
163
|
else UUID(schema_id),
|
|
158
|
-
fine_grained_access=
|
|
164
|
+
fine_grained_access=bool(
|
|
165
|
+
instance_result["fine_grained_access"]
|
|
166
|
+
), # can be None
|
|
159
167
|
db_permissions=instance_result.get("db_permissions", None),
|
|
160
168
|
)
|
|
161
169
|
else:
|
|
@@ -177,22 +185,26 @@ def _connect_instance(
|
|
|
177
185
|
def reset_django_module_variables():
|
|
178
186
|
# This function updates all module-level references to Django classes
|
|
179
187
|
# But it will fail to update function level references
|
|
188
|
+
# This is not a problem unless for the function that calls ln.connect() itself
|
|
180
189
|
# So, if a user has
|
|
190
|
+
#
|
|
181
191
|
# def my_function():
|
|
182
192
|
# import lamindb as ln
|
|
183
|
-
# ...
|
|
193
|
+
# ln.connect(...)
|
|
184
194
|
#
|
|
185
|
-
# Then it will **not** work and the `ln` variable
|
|
195
|
+
# Then it will **not** work and the `ln` variable becomes stale and hold a reference
|
|
186
196
|
# to the old classes
|
|
187
|
-
#
|
|
188
|
-
|
|
189
|
-
|
|
197
|
+
# Other functions that dynamically import are no problem because the variables
|
|
198
|
+
# are automatically refreshed when the function runs the next time after ln.connect() was called
|
|
199
|
+
logger.important_hint("resetting django module variables")
|
|
190
200
|
|
|
201
|
+
# django.apps needs to be a local import to refresh variables
|
|
191
202
|
from django.apps import apps
|
|
192
203
|
|
|
193
204
|
app_names = {app.name for app in apps.get_app_configs()}
|
|
194
|
-
|
|
195
|
-
|
|
205
|
+
# always copy before iterations over sys.modules
|
|
206
|
+
# see https://docs.python.org/3/library/sys.html#sys.modules
|
|
207
|
+
for name, module in sys.modules.copy().items():
|
|
196
208
|
if (
|
|
197
209
|
module is not None
|
|
198
210
|
and (not name.startswith("__") or name == "__main__")
|
|
@@ -230,12 +242,11 @@ def reset_django_module_variables():
|
|
|
230
242
|
continue
|
|
231
243
|
|
|
232
244
|
|
|
233
|
-
def _connect_cli(instance: str) -> None:
|
|
245
|
+
def _connect_cli(instance: str, use_root_db_user: bool = False) -> None:
|
|
234
246
|
from lamindb_setup import settings as settings_
|
|
235
247
|
|
|
236
|
-
settings_.auto_connect = True
|
|
237
248
|
owner, name = get_owner_name_from_identifier(instance)
|
|
238
|
-
isettings = _connect_instance(owner, name)
|
|
249
|
+
isettings = _connect_instance(owner, name, use_root_db_user=use_root_db_user)
|
|
239
250
|
isettings._persist(write_to_disk=True)
|
|
240
251
|
if not isettings.is_on_hub or isettings._is_cloud_sqlite:
|
|
241
252
|
# there are two reasons to call the full-blown connect
|
|
@@ -262,6 +273,7 @@ def connect(instance: str | None = None, **kwargs: Any) -> str | tuple | None:
|
|
|
262
273
|
"""
|
|
263
274
|
# validate kwargs
|
|
264
275
|
valid_kwargs = {
|
|
276
|
+
"use_root_db_user",
|
|
265
277
|
"_db",
|
|
266
278
|
"_write_settings",
|
|
267
279
|
"_raise_not_found_error",
|
|
@@ -274,6 +286,7 @@ def connect(instance: str | None = None, **kwargs: Any) -> str | tuple | None:
|
|
|
274
286
|
raise TypeError(f"connect() got unexpected keyword argument '{kwarg}'")
|
|
275
287
|
isettings: InstanceSettings = None # type: ignore
|
|
276
288
|
# _db is still needed because it is called in init
|
|
289
|
+
use_root_db_user: bool = kwargs.get("use_root_db_user", False)
|
|
277
290
|
_db: str | None = kwargs.get("_db", None)
|
|
278
291
|
_write_settings: bool = kwargs.get("_write_settings", False)
|
|
279
292
|
_raise_not_found_error: bool = kwargs.get("_raise_not_found_error", True)
|
|
@@ -289,12 +302,18 @@ def connect(instance: str | None = None, **kwargs: Any) -> str | tuple | None:
|
|
|
289
302
|
|
|
290
303
|
try:
|
|
291
304
|
if instance is None:
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
305
|
+
if settings._instance_exists:
|
|
306
|
+
isettings = settings.instance
|
|
307
|
+
else:
|
|
308
|
+
isettings_or_none = _get_current_instance_settings()
|
|
309
|
+
if isettings_or_none is None:
|
|
310
|
+
raise ValueError(
|
|
311
|
+
"No instance was connected through the CLI, pass a value to `instance` or connect via the CLI."
|
|
312
|
+
)
|
|
313
|
+
isettings = isettings_or_none
|
|
314
|
+
if use_root_db_user:
|
|
315
|
+
reset_django()
|
|
316
|
+
owner, name = isettings.owner, isettings.name
|
|
298
317
|
if _db is not None and isettings.dialect == "postgresql":
|
|
299
318
|
isettings._db = _db
|
|
300
319
|
else:
|
|
@@ -310,14 +329,13 @@ def connect(instance: str | None = None, **kwargs: Any) -> str | tuple | None:
|
|
|
310
329
|
# could be made more specific by checking whether the django
|
|
311
330
|
# configured database is the same as the one in settings
|
|
312
331
|
and connection.settings_dict["NAME"] != ":memory:"
|
|
332
|
+
and not use_root_db_user # always re-connect for root db user
|
|
313
333
|
):
|
|
314
334
|
logger.important(
|
|
315
335
|
f"doing nothing, already connected lamindb: {settings.instance.slug}"
|
|
316
336
|
)
|
|
317
337
|
return None
|
|
318
338
|
else:
|
|
319
|
-
from lamindb_setup.core.django import reset_django
|
|
320
|
-
|
|
321
339
|
if (
|
|
322
340
|
settings._instance_exists
|
|
323
341
|
and settings.instance.slug != "none/none"
|
|
@@ -328,11 +346,6 @@ def connect(instance: str | None = None, **kwargs: Any) -> str | tuple | None:
|
|
|
328
346
|
raise CannotSwitchDefaultInstance(
|
|
329
347
|
"Cannot switch default instance while `ln.track()` is live: call `ln.finish()`"
|
|
330
348
|
)
|
|
331
|
-
else:
|
|
332
|
-
logger.important_hint(
|
|
333
|
-
"switching the default lamindb instance might produce unexpected side effects with function-scoped imports: "
|
|
334
|
-
"please import lamindb at the module level instead of inside functions"
|
|
335
|
-
)
|
|
336
349
|
reset_django()
|
|
337
350
|
elif (
|
|
338
351
|
_write_settings
|
|
@@ -341,9 +354,14 @@ def connect(instance: str | None = None, **kwargs: Any) -> str | tuple | None:
|
|
|
341
354
|
):
|
|
342
355
|
disconnect(mute=True)
|
|
343
356
|
|
|
357
|
+
if instance is not None or use_root_db_user:
|
|
344
358
|
try:
|
|
345
359
|
isettings = _connect_instance(
|
|
346
|
-
owner,
|
|
360
|
+
owner,
|
|
361
|
+
name,
|
|
362
|
+
db=_db,
|
|
363
|
+
access_token=access_token,
|
|
364
|
+
use_root_db_user=use_root_db_user,
|
|
347
365
|
)
|
|
348
366
|
except InstanceNotFoundError as e:
|
|
349
367
|
if _raise_not_found_error:
|
|
@@ -93,17 +93,13 @@ class migrate:
|
|
|
93
93
|
@disable_auto_connect
|
|
94
94
|
def create(cls) -> None:
|
|
95
95
|
"""Create a migration."""
|
|
96
|
-
if _check_instance_setup():
|
|
97
|
-
raise RuntimeError("Restart Python session to create migration or use CLI!")
|
|
98
96
|
setup_django(settings.instance, create_migrations=True)
|
|
99
97
|
|
|
100
98
|
@classmethod
|
|
101
99
|
def deploy(cls, package_name: str | None = None, number: int | None = None) -> None:
|
|
102
100
|
"""Deploy a migration."""
|
|
103
|
-
from .
|
|
104
|
-
|
|
105
|
-
if _check_instance_setup():
|
|
106
|
-
raise RuntimeError("Restart Python session to migrate or use CLI!")
|
|
101
|
+
from lamindb_setup._connect_instance import connect
|
|
102
|
+
from lamindb_setup._schema_metadata import update_schema_in_hub
|
|
107
103
|
from lamindb_setup.core._hub_client import call_with_fallback_auth
|
|
108
104
|
from lamindb_setup.core._hub_crud import (
|
|
109
105
|
select_collaborator,
|
|
@@ -117,12 +113,17 @@ class migrate:
|
|
|
117
113
|
select_collaborator,
|
|
118
114
|
instance_id=settings.instance._id,
|
|
119
115
|
account_id=settings.user._uuid,
|
|
116
|
+
fine_grained_access=settings.instance._fine_grained_access,
|
|
120
117
|
)
|
|
121
118
|
if collaborator is None or collaborator["role"] != "admin":
|
|
122
119
|
raise SystemExit(
|
|
123
120
|
"❌ Only admins can deploy migrations, please ensure that you're an"
|
|
124
121
|
f" admin: https://lamin.ai/{settings.instance.slug}/settings"
|
|
125
122
|
)
|
|
123
|
+
# ensure we connect with the root user
|
|
124
|
+
if "root" not in settings.instance.db:
|
|
125
|
+
connect(use_root_db_user=True)
|
|
126
|
+
assert "root" in (instance_db := settings.instance.db), instance_db
|
|
126
127
|
# we need lamindb to be installed, otherwise we can't populate the version
|
|
127
128
|
# information in the hub
|
|
128
129
|
import lamindb
|
|
@@ -139,7 +140,6 @@ class migrate:
|
|
|
139
140
|
# this populates the hub
|
|
140
141
|
if settings.instance.is_on_hub:
|
|
141
142
|
logger.important(f"updating lamindb version in hub: {lamindb.__version__}")
|
|
142
|
-
# TODO: integrate update of instance table within update_schema_in_hub & below
|
|
143
143
|
if settings.instance.dialect != "sqlite":
|
|
144
144
|
update_schema_in_hub()
|
|
145
145
|
call_with_fallback_auth(
|
|
@@ -51,7 +51,7 @@ def deprecated(new_name: str):
|
|
|
51
51
|
warnings.warn(
|
|
52
52
|
f"Use {new_name} instead of {func.__name__}, "
|
|
53
53
|
f"{func.__name__} will be removed in the future.",
|
|
54
|
-
category=
|
|
54
|
+
category=DeprecationWarning,
|
|
55
55
|
stacklevel=2,
|
|
56
56
|
)
|
|
57
57
|
return func(*args, **kwargs)
|
|
@@ -424,6 +424,7 @@ def _init_instance_hub(
|
|
|
424
424
|
def _connect_instance_hub(
|
|
425
425
|
owner: str, # account_handle
|
|
426
426
|
name: str, # instance_name
|
|
427
|
+
use_root_db_user: bool,
|
|
427
428
|
client: Client,
|
|
428
429
|
) -> tuple[dict, dict] | str:
|
|
429
430
|
response = client.functions.invoke(
|
|
@@ -475,17 +476,29 @@ def _connect_instance_hub(
|
|
|
475
476
|
|
|
476
477
|
if instance["db_scheme"] is not None:
|
|
477
478
|
db_user_name, db_user_password = None, None
|
|
478
|
-
if
|
|
479
|
+
if (
|
|
480
|
+
"db_user_name" in instance
|
|
481
|
+
and "db_user_password" in instance
|
|
482
|
+
and not use_root_db_user
|
|
483
|
+
):
|
|
479
484
|
db_user_name, db_user_password = (
|
|
480
485
|
instance["db_user_name"],
|
|
481
486
|
instance["db_user_password"],
|
|
482
487
|
)
|
|
483
488
|
else:
|
|
484
|
-
|
|
489
|
+
if use_root_db_user:
|
|
490
|
+
fine_grained_access = False
|
|
491
|
+
else:
|
|
492
|
+
fine_grained_access = bool(
|
|
493
|
+
instance["fine_grained_access"]
|
|
494
|
+
) # can be None
|
|
495
|
+
db_user = select_db_user_by_instance(
|
|
496
|
+
instance["id"], fine_grained_access, client
|
|
497
|
+
)
|
|
485
498
|
if db_user is not None:
|
|
486
499
|
db_user_name, db_user_password = (
|
|
487
|
-
db_user["db_user_name"],
|
|
488
|
-
db_user["db_user_password"],
|
|
500
|
+
db_user["name" if fine_grained_access else "db_user_name"],
|
|
501
|
+
db_user["password" if fine_grained_access else "db_user_password"],
|
|
489
502
|
)
|
|
490
503
|
db_dsn = LaminDsn.build(
|
|
491
504
|
scheme=instance["db_scheme"],
|
|
@@ -505,15 +518,25 @@ def connect_instance_hub(
|
|
|
505
518
|
owner: str, # account_handle
|
|
506
519
|
name: str, # instance_name
|
|
507
520
|
access_token: str | None = None,
|
|
521
|
+
use_root_db_user: bool = False,
|
|
508
522
|
) -> tuple[dict, dict] | str:
|
|
509
523
|
from ._settings import settings
|
|
510
524
|
|
|
511
525
|
if settings.user.handle != "anonymous" or access_token is not None:
|
|
512
526
|
return call_with_fallback_auth(
|
|
513
|
-
_connect_instance_hub,
|
|
527
|
+
_connect_instance_hub,
|
|
528
|
+
owner=owner,
|
|
529
|
+
name=name,
|
|
530
|
+
use_root_db_user=use_root_db_user,
|
|
531
|
+
access_token=access_token,
|
|
514
532
|
)
|
|
515
533
|
else:
|
|
516
|
-
return call_with_fallback(
|
|
534
|
+
return call_with_fallback(
|
|
535
|
+
_connect_instance_hub,
|
|
536
|
+
owner=owner,
|
|
537
|
+
name=name,
|
|
538
|
+
use_root_db_user=use_root_db_user,
|
|
539
|
+
)
|
|
517
540
|
|
|
518
541
|
|
|
519
542
|
def access_aws(storage_root: str, access_token: str | None = None) -> dict[str, dict]:
|
|
@@ -570,7 +593,7 @@ def access_db(
|
|
|
570
593
|
if isinstance(instance, InstanceSettings):
|
|
571
594
|
instance_id = instance._id
|
|
572
595
|
instance_slug = instance.slug
|
|
573
|
-
instance_api_url = instance.
|
|
596
|
+
instance_api_url = instance.api_url
|
|
574
597
|
else:
|
|
575
598
|
instance_id = UUID(instance["id"])
|
|
576
599
|
instance_slug = instance["owner"] + "/" + instance["name"]
|
|
@@ -137,10 +137,12 @@ def update_instance(instance_id: str, instance_fields: dict, client: Client):
|
|
|
137
137
|
def select_collaborator(
|
|
138
138
|
instance_id: str,
|
|
139
139
|
account_id: str,
|
|
140
|
+
fine_grained_access: bool,
|
|
140
141
|
client: Client,
|
|
141
142
|
):
|
|
143
|
+
table = "access_instance" if fine_grained_access else "account_instance"
|
|
142
144
|
data = (
|
|
143
|
-
client.table(
|
|
145
|
+
client.table(table)
|
|
144
146
|
.select("*")
|
|
145
147
|
.eq("instance_id", instance_id)
|
|
146
148
|
.eq("account_id", account_id)
|
|
@@ -180,35 +182,53 @@ def insert_db_user(
|
|
|
180
182
|
db_user_name: str,
|
|
181
183
|
db_user_password: str,
|
|
182
184
|
instance_id: UUID,
|
|
185
|
+
fine_grained_access: bool,
|
|
183
186
|
client: Client,
|
|
184
187
|
) -> None:
|
|
185
|
-
fields =
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
188
|
+
fields = {"instance_id": instance_id.hex}
|
|
189
|
+
if fine_grained_access:
|
|
190
|
+
table = "access_db_user"
|
|
191
|
+
fields.update(
|
|
192
|
+
{
|
|
193
|
+
"name": db_user_name,
|
|
194
|
+
"password": db_user_password,
|
|
195
|
+
"type": name,
|
|
196
|
+
}
|
|
197
|
+
)
|
|
198
|
+
else:
|
|
199
|
+
table = "db_user"
|
|
200
|
+
fields.update(
|
|
201
|
+
{
|
|
202
|
+
"id": uuid4().hex,
|
|
203
|
+
"name": name,
|
|
204
|
+
"db_user_name": db_user_name,
|
|
205
|
+
"db_user_password": db_user_password,
|
|
206
|
+
}
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
data = client.table(table).insert(fields).execute().data
|
|
195
210
|
return data[0]
|
|
196
211
|
|
|
197
212
|
|
|
198
|
-
def select_db_user_by_instance(
|
|
213
|
+
def select_db_user_by_instance(
|
|
214
|
+
instance_id: str, fine_grained_access: bool, client: Client
|
|
215
|
+
):
|
|
199
216
|
"""Get db_user for which client has permission."""
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
217
|
+
if fine_grained_access:
|
|
218
|
+
table = "access_db_user"
|
|
219
|
+
type_name = "type"
|
|
220
|
+
type_priority = "jwt"
|
|
221
|
+
else:
|
|
222
|
+
table = "db_user"
|
|
223
|
+
type_name = "name"
|
|
224
|
+
type_priority = "write"
|
|
225
|
+
|
|
226
|
+
data = client.table(table).select("*").eq("instance_id", instance_id).execute().data
|
|
207
227
|
if len(data) == 0:
|
|
208
228
|
return None
|
|
209
229
|
elif len(data) > 1:
|
|
210
230
|
for item in data:
|
|
211
|
-
if item[
|
|
231
|
+
if item[type_name] == type_priority:
|
|
212
232
|
return item
|
|
213
233
|
logger.warning("found multiple db credentials, using the first one")
|
|
214
234
|
return data[0]
|
|
@@ -79,24 +79,15 @@ class SetupSettings:
|
|
|
79
79
|
def auto_connect(self) -> bool:
|
|
80
80
|
"""Auto-connect to current instance upon `import lamindb`.
|
|
81
81
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
Upon calling `lamin init` or `lamin connect` on the CLI, this setting is switched to `True`.
|
|
85
|
-
|
|
86
|
-
`ln.connect()` doesn't change the value of this setting.
|
|
87
|
-
|
|
88
|
-
You can manually change this setting
|
|
89
|
-
|
|
90
|
-
- in Python: `ln.setup.settings.auto_connect = True/False`
|
|
91
|
-
- via the CLI: `lamin settings set auto-connect true/false`
|
|
82
|
+
This setting is always `True` and will be removed in a future version.
|
|
92
83
|
"""
|
|
93
84
|
return True
|
|
94
85
|
|
|
95
86
|
@auto_connect.setter
|
|
96
87
|
def auto_connect(self, value: bool) -> None:
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
88
|
+
logger.warning(
|
|
89
|
+
"setting auto_connect to `False` no longer has an effect and the setting will likely be removed in the future",
|
|
90
|
+
)
|
|
100
91
|
if value:
|
|
101
92
|
self._auto_connect_path.touch()
|
|
102
93
|
else:
|
|
@@ -324,7 +315,6 @@ class SetupSettings:
|
|
|
324
315
|
else:
|
|
325
316
|
repr += "Current instance: None"
|
|
326
317
|
repr += "\nConfig:\n"
|
|
327
|
-
repr += f" - auto-connect in Python: {self.auto_connect}\n"
|
|
328
318
|
repr += f" - private Django API: {self.private_django_api}\n"
|
|
329
319
|
repr += "Local directories:\n"
|
|
330
320
|
repr += f" - cache: {self.cache_dir.as_posix()}\n"
|