lamindb_setup 1.16.0__tar.gz → 1.18.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.
Files changed (117) hide show
  1. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/.github/workflows/build.yml +55 -2
  2. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/.gitignore +1 -0
  3. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/PKG-INFO +5 -6
  4. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/docs/hub-cloud/01-init-local-instance.ipynb +16 -4
  5. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/docs/hub-cloud/02-connect-local-instance.ipynb +1 -1
  6. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/docs/hub-cloud/03-add-managed-storage.ipynb +43 -26
  7. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/docs/hub-cloud/05-init-hosted-instance.ipynb +1 -1
  8. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/docs/hub-prod/test-import-schema.ipynb +2 -2
  9. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/lamindb_setup/__init__.py +6 -3
  10. lamindb_setup-1.18.0/lamindb_setup/_check_setup.py +131 -0
  11. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/lamindb_setup/_connect_instance.py +23 -33
  12. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/lamindb_setup/_delete.py +10 -5
  13. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/lamindb_setup/_disconnect.py +12 -9
  14. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/lamindb_setup/_init_instance.py +0 -1
  15. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/lamindb_setup/_migrate.py +56 -30
  16. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/lamindb_setup/_set_managed_storage.py +3 -0
  17. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/lamindb_setup/_setup_user.py +8 -5
  18. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/lamindb_setup/_silence_loggers.py +2 -0
  19. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/lamindb_setup/core/__init__.py +0 -3
  20. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/lamindb_setup/core/_aws_options.py +18 -8
  21. lamindb_setup-1.18.0/lamindb_setup/core/_clone.py +50 -0
  22. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/lamindb_setup/core/_hub_client.py +1 -2
  23. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/lamindb_setup/core/_hub_core.py +9 -6
  24. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/lamindb_setup/core/_private_django_api.py +1 -3
  25. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/lamindb_setup/core/_settings.py +14 -10
  26. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/lamindb_setup/core/_settings_instance.py +40 -24
  27. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/lamindb_setup/core/_settings_load.py +25 -7
  28. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/lamindb_setup/core/_settings_storage.py +0 -5
  29. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/lamindb_setup/core/django.py +42 -14
  30. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/lamindb_setup/core/hashing.py +5 -5
  31. lamindb_setup-1.18.0/lamindb_setup/core/lamin.db.gz +0 -0
  32. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/lamindb_setup/core/upath.py +15 -6
  33. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/lamindb_setup/errors.py +5 -12
  34. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/lamindb_setup/io.py +16 -5
  35. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/noxfile.py +30 -6
  36. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/pyproject.toml +4 -5
  37. lamindb_setup-1.18.0/tests/connectivity/conftest.py +33 -0
  38. lamindb_setup-1.18.0/tests/connectivity/test_proxies_certificates.py +58 -0
  39. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/tests/hub-cloud/test_connect_instance.py +15 -6
  40. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/tests/hub-cloud/test_edge_request.py +1 -1
  41. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/tests/hub-cloud/test_init_instance.py +1 -0
  42. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/tests/hub-cloud/test_login.py +3 -8
  43. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/tests/hub-local/README.md +2 -2
  44. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/tests/hub-local/conftest.py +24 -13
  45. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/tests/hub-local/test_all.py +12 -7
  46. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/tests/hub-local/test_update_schema_in_hub.py +5 -5
  47. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/tests/hub-prod/test_switch_and_fallback_env.py +2 -2
  48. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/tests/storage/test_db_import_export.py +6 -10
  49. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/tests/storage/test_hashing.py +13 -9
  50. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/tests/storage/test_storage_access.py +4 -8
  51. lamindb_setup-1.16.0/docs/hub-prod/test-insufficient-user-info.ipynb +0 -192
  52. lamindb_setup-1.16.0/lamindb_setup/_check_setup.py +0 -192
  53. lamindb_setup-1.16.0/lamindb_setup/core/_clone.py +0 -174
  54. lamindb_setup-1.16.0/tests/hub-cloud/test_clone_instance.py +0 -137
  55. lamindb_setup-1.16.0/tests/storage/test_httpx_client.py +0 -21
  56. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/.github/workflows/doc-changes.yml +0 -0
  57. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/.pre-commit-config.yaml +0 -0
  58. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/LICENSE +0 -0
  59. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/README.md +0 -0
  60. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/docs/changelog.md +0 -0
  61. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/docs/hub-cloud/04-test-bionty.ipynb +0 -0
  62. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/docs/hub-cloud/06-connect-hosted-instance.ipynb +0 -0
  63. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/docs/hub-cloud/07-keep-artifacts-local.ipynb +0 -0
  64. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/docs/hub-cloud/08-test-multi-session.ipynb +0 -0
  65. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/docs/hub-cloud/09-test-migrate.ipynb +0 -0
  66. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/docs/hub-cloud/test_notebooks.py +0 -0
  67. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/docs/hub-prod/test-cache-management.ipynb +0 -0
  68. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/docs/hub-prod/test-cloud-sync.ipynb +0 -0
  69. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/docs/hub-prod/test-connect-anonymously.ipynb +0 -0
  70. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/docs/hub-prod/test-empty-init.ipynb +0 -0
  71. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/docs/hub-prod/test-init-load-local-anonymously.ipynb +0 -0
  72. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/docs/hub-prod/test-invalid-schema.ipynb +0 -0
  73. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/docs/hub-prod/test-sqlite-lock.ipynb +0 -0
  74. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/docs/hub-prod/test_notebooks2.py +0 -0
  75. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/docs/index.md +0 -0
  76. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/docs/notebooks.md +0 -0
  77. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/docs/reference.md +0 -0
  78. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/lamindb_setup/_cache.py +0 -0
  79. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/lamindb_setup/_check.py +0 -0
  80. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/lamindb_setup/_django.py +0 -0
  81. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/lamindb_setup/_entry_points.py +0 -0
  82. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/lamindb_setup/_register_instance.py +0 -0
  83. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/lamindb_setup/_schema.py +0 -0
  84. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/lamindb_setup/_schema_metadata.py +0 -0
  85. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/lamindb_setup/core/_aws_storage.py +0 -0
  86. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/lamindb_setup/core/_deprecated.py +0 -0
  87. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/lamindb_setup/core/_docs.py +0 -0
  88. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/lamindb_setup/core/_hub_crud.py +0 -0
  89. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/lamindb_setup/core/_hub_utils.py +0 -0
  90. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/lamindb_setup/core/_settings_save.py +0 -0
  91. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/lamindb_setup/core/_settings_store.py +0 -0
  92. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/lamindb_setup/core/_settings_user.py +0 -0
  93. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/lamindb_setup/core/_setup_bionty_sources.py +0 -0
  94. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/lamindb_setup/core/cloud_sqlite_locker.py +0 -0
  95. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/lamindb_setup/core/exceptions.py +0 -0
  96. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/lamindb_setup/core/types.py +0 -0
  97. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/lamindb_setup/py.typed +0 -0
  98. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/lamindb_setup/types.py +0 -0
  99. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/tests/hub-cloud/scripts/script-init-pass-user-no-writes.py +0 -0
  100. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/tests/hub-cloud/scripts/script-to-fail-managed-storage.py +0 -0
  101. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/tests/hub-cloud/test_delete_instance.py +0 -0
  102. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/tests/hub-cloud/test_fail_managed_storage.py +0 -0
  103. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/tests/hub-cloud/test_init_pass_user_no_writes.py +0 -0
  104. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/tests/hub-cloud/test_set_storage.py +0 -0
  105. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/tests/hub-local/scripts/script-connect-fine-grained-access.py +0 -0
  106. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/tests/hub-prod/conftest.py +0 -0
  107. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/tests/hub-prod/test_aws_options_manager.py +0 -0
  108. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/tests/hub-prod/test_django.py +0 -0
  109. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/tests/hub-prod/test_global_settings.py +0 -0
  110. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/tests/hub-prod/test_migrate.py +0 -0
  111. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/tests/hub-prod/test_upath.py +0 -0
  112. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/tests/storage/conftest.py +0 -0
  113. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/tests/storage/test_entry_point.py +0 -0
  114. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/tests/storage/test_storage_basis.py +0 -0
  115. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/tests/storage/test_storage_settings.py +0 -0
  116. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/tests/storage/test_storage_stats.py +0 -0
  117. {lamindb_setup-1.16.0 → lamindb_setup-1.18.0}/tests/storage/test_to_url.py +0 -0
@@ -107,7 +107,6 @@ jobs:
107
107
  - run: nox -s lint
108
108
  - run: nox -s storage
109
109
  env:
110
- TEST_INSTANCE_PRIVATE_POSTGRES: ${{ secrets.TEST_INSTANCE_PRIVATE_POSTGRES }}
111
110
  TMP_AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
112
111
  TMP_AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
113
112
  - uses: actions/upload-artifact@v4
@@ -138,7 +137,7 @@ jobs:
138
137
  touch .env.local
139
138
  echo "AWS_ACCESS_KEY_ID_HOSTED_S3=${{ secrets.AWS_ACCESS_KEY_ID }}" >> .env.local
140
139
  echo "AWS_SECRET_ACCESS_KEY_HOSTED_S3=${{ secrets.AWS_SECRET_ACCESS_KEY }}" >> .env.local
141
- working-directory: laminhub/rest-hub/supabase
140
+ working-directory: laminhub/backend/central/supabase
142
141
  - uses: actions/setup-python@v6
143
142
  with:
144
143
  python-version: "3.11" # we need to run everything for coverage on 3.11
@@ -163,6 +162,60 @@ jobs:
163
162
  path: .coverage
164
163
  include-hidden-files: true
165
164
 
165
+ # test custom proxies and certificates
166
+ connectivity:
167
+ runs-on: ubuntu-latest
168
+ timeout-minutes: 13
169
+ steps:
170
+ - uses: aws-actions/configure-aws-credentials@v4
171
+ with:
172
+ aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
173
+ aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
174
+ aws-region: eu-central-1
175
+ - uses: actions/checkout@v4
176
+ - uses: actions/setup-python@v6
177
+ with:
178
+ python-version: "3.11"
179
+ cache: "pip"
180
+ cache-dependency-path: ".github/workflows/build.yml"
181
+ - run: pip install "laminci@git+https://x-access-token:${{ secrets.LAMIN_BUILD_DOCS }}@github.com/laminlabs/laminci"
182
+ - run: nox -s "install(group='connectivity')"
183
+ - name: cache mitmproxy
184
+ id: cache-mitmproxy
185
+ uses: actions/cache@v4
186
+ with:
187
+ path: ~/mitmproxy.tar
188
+ key: cache-mitmproxy-0
189
+ - name: cache mitmproxy miss
190
+ if: ${{ steps.cache-mitmproxy.outputs.cache-hit != 'true' }}
191
+ run: docker pull mitmproxy/mitmproxy:latest && docker image save mitmproxy/mitmproxy:latest --output ~/mitmproxy.tar
192
+ - name: cache mitmproxy use
193
+ if: ${{ steps.cache-mitmproxy.outputs.cache-hit == 'true' }}
194
+ run: docker image load --input ~/mitmproxy.tar
195
+ - name: start mitmproxy
196
+ run: |
197
+ # Start mitmdump (headless mitmproxy) as a forward proxy on 8080
198
+ docker run -d \
199
+ --name mitmproxy \
200
+ -p 8080:8080 \
201
+ mitmproxy/mitmproxy:latest \
202
+ mitmdump --mode regular --listen-port 8080
203
+ # Give it a few seconds to start and generate the CA
204
+ sleep 10
205
+ echo "mitmproxy state:"
206
+ docker ps -a
207
+ echo "Container ~/.mitmproxy contents:"
208
+ docker exec mitmproxy ls -l /home/mitmproxy/.mitmproxy || true
209
+ echo "Container logs (if it still exited):"
210
+ docker logs mitmproxy || true
211
+ - name: export mitmproxy certificate
212
+ run: |
213
+ # Copy CA cert from inside the container to the workspace
214
+ docker cp mitmproxy:/home/mitmproxy/.mitmproxy/mitmproxy-ca-cert.pem ./mitmproxy-ca.pem
215
+ ls -l ./mitmproxy-ca.pem
216
+ - name: run tests
217
+ run: nox -s connectivity
218
+
166
219
  coverage:
167
220
  needs: [hub-prod, hub-cloud, storage, hub-local]
168
221
  runs-on: ubuntu-latest
@@ -115,3 +115,4 @@ storage_uid.txt
115
115
  test.ipynb
116
116
  test2.ipynb
117
117
  *_export
118
+ update_clone.py
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: lamindb_setup
3
- Version: 1.16.0
3
+ Version: 1.18.0
4
4
  Summary: Setup & configure LaminDB.
5
5
  Author-email: Lamin Labs <open-source@lamin.ai>
6
6
  Requires-Python: >=3.10
@@ -15,14 +15,13 @@ Requires-Dist: httpx_retries<1.0.0
15
15
  Requires-Dist: requests
16
16
  Requires-Dist: universal_pathlib==0.2.6
17
17
  Requires-Dist: botocore<2.0.0
18
- Requires-Dist: supabase>=2.8.1,<=2.16.0
19
- Requires-Dist: gotrue<=2.12.0
20
- Requires-Dist: storage3!=0.11.2; python_version < '3.11'
18
+ Requires-Dist: supabase>=2.20.0,<=2.24.0
19
+ Requires-Dist: websockets>=13.0
21
20
  Requires-Dist: pyjwt<3.0.0
22
21
  Requires-Dist: psutil
23
22
  Requires-Dist: packaging
24
23
  Requires-Dist: aiobotocore[boto3]>=2.12.4,<3.0.0 ; extra == "aws"
25
- Requires-Dist: s3fs>=2023.12.2,<=2025.9.0,!=2024.10.0 ; extra == "aws"
24
+ Requires-Dist: s3fs>=2023.12.2,<=2025.12.0,!=2024.10.0 ; extra == "aws"
26
25
  Requires-Dist: line_profiler ; extra == "dev"
27
26
  Requires-Dist: psycopg2-binary ; extra == "dev"
28
27
  Requires-Dist: python-dotenv ; extra == "dev"
@@ -33,7 +32,7 @@ Requires-Dist: pytest-xdist ; extra == "dev"
33
32
  Requires-Dist: nbproject-test>=0.4.3 ; extra == "dev"
34
33
  Requires-Dist: pandas ; extra == "dev"
35
34
  Requires-Dist: django-schema-graph ; extra == "erdiagram"
36
- Requires-Dist: gcsfs>=2023.12.2,<=2025.9.0 ; extra == "gcp"
35
+ Requires-Dist: gcsfs>=2023.12.2,<=2025.12.0 ; extra == "gcp"
37
36
  Project-URL: Home, https://github.com/laminlabs/lamindb-setup
38
37
  Provides-Extra: aws
39
38
  Provides-Extra: dev
@@ -24,7 +24,8 @@
24
24
  "metadata": {},
25
25
  "outputs": [],
26
26
  "source": [
27
- "import lamindb_setup as ln_setup"
27
+ "import lamindb_setup as ln_setup\n",
28
+ "import os"
28
29
  ]
29
30
  },
30
31
  {
@@ -42,7 +43,7 @@
42
43
  "metadata": {},
43
44
  "outputs": [],
44
45
  "source": [
45
- "ln_setup.init(storage=\"./mydata\")"
46
+ "ln_setup.init(storage=\"./mydata\", modules=\"bionty\")"
46
47
  ]
47
48
  },
48
49
  {
@@ -70,10 +71,11 @@
70
71
  "assert ln_setup.settings.instance.storage.type_is_cloud is False\n",
71
72
  "assert ln_setup.settings.instance.owner == ln_setup.settings.user.handle\n",
72
73
  "assert ln_setup.settings.instance.name == \"mydata\"\n",
74
+ "assert ln_setup.settings.instance.modules == {\"bionty\"}\n",
73
75
  "assert ln_setup.settings.storage.root.as_posix() == Path(\"mydata\").resolve().as_posix()\n",
74
76
  "storage_root = ln_setup.settings.storage.root\n",
75
77
  "assert storage_root.exists()\n",
76
- "assert ln_setup.settings.storage.id is not None\n",
78
+ "assert ln_setup.settings.storage._id is not None\n",
77
79
  "assert (\n",
78
80
  " ln_setup.settings.instance.db\n",
79
81
  " == f\"sqlite:///{Path('./mydata').resolve().as_posix()}/.lamindb/lamin.db\"\n",
@@ -85,6 +87,16 @@
85
87
  ")"
86
88
  ]
87
89
  },
90
+ {
91
+ "cell_type": "code",
92
+ "execution_count": null,
93
+ "metadata": {},
94
+ "outputs": [],
95
+ "source": [
96
+ "exit_status = os.system(\"lamin migrate deploy\")\n",
97
+ "assert exit_status == 0"
98
+ ]
99
+ },
88
100
  {
89
101
  "cell_type": "code",
90
102
  "execution_count": null,
@@ -124,7 +136,7 @@
124
136
  "name": "python",
125
137
  "nbconvert_exporter": "python",
126
138
  "pygments_lexer": "ipython3",
127
- "version": "3.10.16"
139
+ "version": "3.11.14"
128
140
  }
129
141
  },
130
142
  "nbformat": 4,
@@ -171,7 +171,7 @@
171
171
  "name": "python",
172
172
  "nbconvert_exporter": "python",
173
173
  "pygments_lexer": "ipython3",
174
- "version": "3.10.16"
174
+ "version": "3.11.14"
175
175
  },
176
176
  "vscode": {
177
177
  "interpreter": {
@@ -7,7 +7,7 @@
7
7
  "tags": []
8
8
  },
9
9
  "source": [
10
- "# Add managed and referenced storage locations"
10
+ "# Add writeable and read-only storage locations to an instance"
11
11
  ]
12
12
  },
13
13
  {
@@ -84,22 +84,12 @@
84
84
  "ln_setup.init(storage=\"./storage1\", name=\"test-add-managed-storage\", db=pgurl)"
85
85
  ]
86
86
  },
87
- {
88
- "cell_type": "code",
89
- "execution_count": null,
90
- "id": "95a61826",
91
- "metadata": {},
92
- "outputs": [],
93
- "source": [
94
- "ln_setup.settings.instance.is_on_hub"
95
- ]
96
- },
97
87
  {
98
88
  "cell_type": "markdown",
99
89
  "id": "b62e84cb",
100
90
  "metadata": {},
101
91
  "source": [
102
- "Test adding referenced storage location."
92
+ "Test adding a referenced read-only storage location."
103
93
  ]
104
94
  },
105
95
  {
@@ -120,7 +110,7 @@
120
110
  "id": "93234f70",
121
111
  "metadata": {},
122
112
  "source": [
123
- "Now continue with managed storage locations."
113
+ "Now continue with writeable storage locations."
124
114
  ]
125
115
  },
126
116
  {
@@ -134,6 +124,14 @@
134
124
  "storage1_uid = ln_setup.settings.storage.uid"
135
125
  ]
136
126
  },
127
+ {
128
+ "cell_type": "markdown",
129
+ "id": "548190d1",
130
+ "metadata": {},
131
+ "source": [
132
+ "This errors at first."
133
+ ]
134
+ },
137
135
  {
138
136
  "cell_type": "code",
139
137
  "execution_count": null,
@@ -149,6 +147,14 @@
149
147
  ")"
150
148
  ]
151
149
  },
150
+ {
151
+ "cell_type": "markdown",
152
+ "id": "845d9c9c",
153
+ "metadata": {},
154
+ "source": [
155
+ "Register the instance on the hub."
156
+ ]
157
+ },
152
158
  {
153
159
  "cell_type": "code",
154
160
  "execution_count": null,
@@ -162,11 +168,12 @@
162
168
  {
163
169
  "cell_type": "code",
164
170
  "execution_count": null,
165
- "id": "825c34b7",
171
+ "id": "1660bb27",
166
172
  "metadata": {},
167
173
  "outputs": [],
168
174
  "source": [
169
- "ln_setup.settings.instance.is_on_hub"
175
+ "assert ln_setup.settings.instance.is_on_hub\n",
176
+ "assert not ln_setup.settings.instance.is_managed_by_hub"
170
177
  ]
171
178
  },
172
179
  {
@@ -417,7 +424,7 @@
417
424
  "outputs": [],
418
425
  "source": [
419
426
  "from lamindb_setup.core._hub_client import connect_hub_with_auth\n",
420
- "from laminhub_rest.core._central_client import SupabaseClientWrapper\n",
427
+ "from lamincentral.client import SupabaseClientWrapper\n",
421
428
  "from laminhub_rest.core.instance_collaborator import InstanceCollaboratorHandler\n",
422
429
  "from laminhub_rest.core.organization import OrganizationMemberHandler\n",
423
430
  "\n",
@@ -432,11 +439,16 @@
432
439
  "account_id = ln_setup.settings.user._uuid\n",
433
440
  "\n",
434
441
  "try:\n",
435
- " organization_member_handler.add(\n",
436
- " organization_id=organization_id,\n",
437
- " account_id=account_id,\n",
438
- " role=\"member\",\n",
439
- " )\n",
442
+ " try:\n",
443
+ " organization_member_handler.add(\n",
444
+ " organization_id=organization_id,\n",
445
+ " account_id=account_id,\n",
446
+ " role=\"member\",\n",
447
+ " )\n",
448
+ " except KeyError:\n",
449
+ " # we don't set LAMIN_API_KEY, so broadcasting cache invalidation fails\n",
450
+ " # it should still be fine with adding to the organization\n",
451
+ " pass\n",
440
452
  " try:\n",
441
453
  " InstanceCollaboratorHandler(admin_hub).add(\n",
442
454
  " account_id=account_id,\n",
@@ -456,10 +468,15 @@
456
468
  " ln_setup.delete(\"testuser1/test-add-managed-storage\", force=True)\n",
457
469
  "\n",
458
470
  "finally:\n",
459
- " organization_member_handler.remove(\n",
460
- " organization_id=organization_id,\n",
461
- " account_id=account_id,\n",
462
- " )\n",
471
+ " try:\n",
472
+ " organization_member_handler.remove(\n",
473
+ " organization_id=organization_id,\n",
474
+ " account_id=account_id,\n",
475
+ " )\n",
476
+ " except KeyError:\n",
477
+ " # we don't set LAMIN_API_KEY, so broadcasting cache invalidation fails\n",
478
+ " # it should still be fine with deletion from the organization\n",
479
+ " pass\n",
463
480
  " admin_hub.auth.sign_out(options={\"scope\": \"local\"})"
464
481
  ]
465
482
  },
@@ -525,7 +542,7 @@
525
542
  "name": "python",
526
543
  "nbconvert_exporter": "python",
527
544
  "pygments_lexer": "ipython3",
528
- "version": "3.10.16"
545
+ "version": "3.11.14"
529
546
  }
530
547
  },
531
548
  "nbformat": 4,
@@ -95,7 +95,7 @@
95
95
  "assert ln_setup.settings.instance.owner == ln_setup.settings.user.handle\n",
96
96
  "assert ln_setup.settings.instance.name == \"my-hosted\"\n",
97
97
  "assert ln_setup.settings.storage.root.as_posix().startswith(HOSTED_BUCKETS)\n",
98
- "assert ln_setup.settings.storage.id is not None\n",
98
+ "assert ln_setup.settings.storage._id is not None\n",
99
99
  "\n",
100
100
  "assert ln_setup.settings.storage._mark_storage_root.exists()"
101
101
  ]
@@ -49,7 +49,7 @@
49
49
  "metadata": {},
50
50
  "outputs": [],
51
51
  "source": [
52
- "import wetlab as lb"
52
+ "import wetlab as wl"
53
53
  ]
54
54
  },
55
55
  {
@@ -69,7 +69,7 @@
69
69
  "metadata": {},
70
70
  "outputs": [],
71
71
  "source": [
72
- "lb.Experiment"
72
+ "wl.Compound"
73
73
  ]
74
74
  },
75
75
  {
@@ -35,14 +35,17 @@ Migration management
35
35
 
36
36
  """
37
37
 
38
- __version__ = "1.16.0" # denote a release candidate for 0.1.0 with 0.1rc1
38
+ __version__ = "1.18.0" # denote a release candidate for 0.1.0 with 0.1rc1
39
39
 
40
40
  import os
41
41
  import warnings
42
42
 
43
- # ignore for now, remove this after supabase upgrade in the deps
43
+ # ignore for now, this is for timeout parameter,
44
+ # it is more convenient to specify it directly for now
44
45
  warnings.filterwarnings("ignore", category=DeprecationWarning, module="supabase")
45
- warnings.filterwarnings("ignore", category=DeprecationWarning, module="supafunc")
46
+ warnings.filterwarnings(
47
+ "ignore", category=DeprecationWarning, module="supabase_functions"
48
+ )
46
49
  warnings.filterwarnings("ignore", category=DeprecationWarning, module="postgrest")
47
50
 
48
51
  from packaging import version as packaging_version
@@ -0,0 +1,131 @@
1
+ from __future__ import annotations
2
+
3
+ import functools
4
+ import importlib as il
5
+ import inspect
6
+ import os
7
+ from typing import TYPE_CHECKING
8
+ from uuid import UUID
9
+
10
+ from lamin_utils import logger
11
+
12
+ from ._silence_loggers import silence_loggers
13
+ from .core import django as django_lamin
14
+ from .core._settings import settings
15
+ from .core._settings_store import current_instance_settings_file
16
+ from .errors import (
17
+ MODULE_WASNT_CONFIGURED_MESSAGE_TEMPLATE,
18
+ ModuleWasntConfigured,
19
+ )
20
+
21
+ if TYPE_CHECKING:
22
+ from collections.abc import Callable
23
+
24
+ from .core._settings_instance import InstanceSettings
25
+
26
+
27
+ IS_LOADING: bool = False
28
+
29
+
30
+ # decorator to disable auto-connect when importing a module such as lamindb
31
+ def disable_auto_connect(func: Callable):
32
+ @functools.wraps(func)
33
+ def wrapper(*args, **kwargs):
34
+ global IS_LOADING
35
+ IS_LOADING = True
36
+ try:
37
+ return func(*args, **kwargs)
38
+ finally:
39
+ IS_LOADING = False
40
+
41
+ return wrapper
42
+
43
+
44
+ def _normalize_module_name(module_name: str) -> str:
45
+ return module_name.replace("lnschema_", "").replace("_", "-")
46
+
47
+
48
+ # checks that the provided modules is in the modules of the provided instance
49
+ # or in the apps setup by django
50
+ def _check_module_in_instance_modules(
51
+ module: str, isettings: InstanceSettings | None = None
52
+ ) -> None:
53
+ if isettings is not None:
54
+ modules_raw = isettings.modules
55
+ modules = set(modules_raw).union(
56
+ _normalize_module_name(module) for module in modules_raw
57
+ )
58
+ if _normalize_module_name(module) not in modules and module not in modules:
59
+ raise ModuleWasntConfigured(
60
+ MODULE_WASNT_CONFIGURED_MESSAGE_TEMPLATE.format(module)
61
+ )
62
+ else:
63
+ return
64
+
65
+ from django.apps import apps
66
+
67
+ for app in apps.get_app_configs():
68
+ # app.name is always unnormalized module (python package) name
69
+ if module == app.name or module == _normalize_module_name(app.name):
70
+ return
71
+ raise ModuleWasntConfigured(MODULE_WASNT_CONFIGURED_MESSAGE_TEMPLATE.format(module))
72
+
73
+
74
+ # infer the name of the module that calls this function
75
+ def _infer_callers_module_name() -> str | None:
76
+ stack = inspect.stack()
77
+ if len(stack) < 3:
78
+ return None
79
+ module = inspect.getmodule(stack[2][0])
80
+ return module.__name__.partition(".")[0] if module is not None else None
81
+
82
+
83
+ # we make this a private function because in all the places it's used,
84
+ # users should not see it
85
+ def _check_instance_setup(from_module: str | None = None) -> bool:
86
+ if django_lamin.IS_SETUP:
87
+ if from_module is not None:
88
+ if from_module != "lamindb":
89
+ _check_module_in_instance_modules(from_module)
90
+ else:
91
+ infer_module = _infer_callers_module_name()
92
+ if infer_module is not None and infer_module not in {
93
+ "lamindb",
94
+ "lamindb_setup",
95
+ "lamin_cli",
96
+ }:
97
+ _check_module_in_instance_modules(infer_module)
98
+ return True
99
+ silence_loggers()
100
+ if os.environ.get("LAMINDB_MULTI_INSTANCE") == "true":
101
+ logger.warning(
102
+ "running LaminDB in multi-instance mode; you'll experience "
103
+ "errors in regular lamindb usage"
104
+ )
105
+ return True
106
+
107
+ if IS_LOADING or from_module is None:
108
+ return False
109
+
110
+ if (
111
+ not settings._instance_exists
112
+ and os.environ.get("LAMIN_CURRENT_INSTANCE") is not None
113
+ ):
114
+ from ._connect_instance import connect
115
+
116
+ connect(_write_settings=False, _reload_lamindb=False)
117
+ return django_lamin.IS_SETUP
118
+ else:
119
+ isettings = settings.instance
120
+ if from_module != "lamindb":
121
+ _check_module_in_instance_modules(from_module, isettings)
122
+
123
+ import lamindb # connect to the instance
124
+ else:
125
+ # disable_auto_connect to avoid triggering _check_instance_setup in modules
126
+ disable_auto_connect(django_lamin.setup_django)(isettings)
127
+ if isettings.slug != "none/none":
128
+ logger.important(f"connected lamindb: {isettings.slug}")
129
+ # update of local storage location through search_local_root()
130
+ settings._instance_settings = isettings
131
+ return django_lamin.IS_SETUP
@@ -9,10 +9,7 @@ from uuid import UUID
9
9
 
10
10
  from lamin_utils import logger
11
11
 
12
- from ._check_setup import (
13
- _check_instance_setup,
14
- _get_current_instance_settings,
15
- )
12
+ from ._check_setup import _check_instance_setup
16
13
  from ._disconnect import disconnect
17
14
  from ._init_instance import load_from_isettings
18
15
  from ._silence_loggers import silence_loggers
@@ -25,7 +22,7 @@ from .core._settings_storage import StorageSettings
25
22
  from .core._settings_store import instance_settings_file
26
23
  from .core.cloud_sqlite_locker import unlock_cloud_sqlite_upon_exception
27
24
  from .core.django import reset_django
28
- from .errors import CannotSwitchDefaultInstance
25
+ from .errors import CannotSwitchDefaultInstance, InstanceNotFoundError
29
26
 
30
27
  if TYPE_CHECKING:
31
28
  from pathlib import Path
@@ -36,8 +33,6 @@ if TYPE_CHECKING:
36
33
  # this is for testing purposes only
37
34
  # set to True only to test failed load
38
35
  _TEST_FAILED_LOAD = False
39
-
40
-
41
36
  INSTANCE_NOT_FOUND_MESSAGE = (
42
37
  "'{owner}/{name}' not found:"
43
38
  " '{hub_result}'\nCheck your permissions:"
@@ -45,10 +40,6 @@ INSTANCE_NOT_FOUND_MESSAGE = (
45
40
  )
46
41
 
47
42
 
48
- class InstanceNotFoundError(SystemExit):
49
- pass
50
-
51
-
52
43
  def check_db_dsn_equal_up_to_credentials(db_dsn_hub, db_dsn_local):
53
44
  return (
54
45
  db_dsn_hub.scheme == db_dsn_local.scheme
@@ -105,6 +96,7 @@ def _connect_instance(
105
96
  use_root_db_user: bool = False,
106
97
  use_proxy_db: bool = False,
107
98
  access_token: str | None = None,
99
+ raise_systemexit: bool = False,
108
100
  ) -> InstanceSettings:
109
101
  settings_file = instance_settings_file(name, owner)
110
102
  make_hub_request = True
@@ -173,12 +165,17 @@ def _connect_instance(
173
165
  )
174
166
  else:
175
167
  message = "It is not possible to load an anonymous-owned instance from the hub"
168
+ exception = (
169
+ SystemExit(message)
170
+ if raise_systemexit
171
+ else InstanceNotFoundError(message)
172
+ )
176
173
  if settings_file.exists():
177
174
  isettings = load_instance_settings(settings_file)
178
175
  if isettings.is_remote:
179
- raise InstanceNotFoundError(message)
176
+ raise exception
180
177
  else:
181
- raise InstanceNotFoundError(message)
178
+ raise exception
182
179
  return isettings
183
180
 
184
181
 
@@ -242,7 +239,11 @@ def _connect_cli(
242
239
 
243
240
  owner, name = get_owner_name_from_identifier(instance)
244
241
  isettings = _connect_instance(
245
- owner, name, use_root_db_user=use_root_db_user, use_proxy_db=use_proxy_db
242
+ owner,
243
+ name,
244
+ use_root_db_user=use_root_db_user,
245
+ use_proxy_db=use_proxy_db,
246
+ raise_systemexit=True,
246
247
  )
247
248
  isettings._persist(write_to_disk=True)
248
249
  if not isettings.is_on_hub or isettings._is_cloud_sqlite:
@@ -266,13 +267,8 @@ def validate_connection_state(
266
267
  from django.db import connection
267
268
 
268
269
  if (
269
- settings._instance_exists
270
+ settings._instance_exists # exists only for real instances, not for none/none
270
271
  and f"{owner}/{name}" == settings.instance.slug
271
- # below is to ensure that if another process interferes
272
- # we don't use the in-memory mock database
273
- # could be made more specific by checking whether the django
274
- # configured database is the same as the one in settings
275
- and connection.settings_dict["NAME"] != ":memory:"
276
272
  and not use_root_db_user # always re-connect for root db user
277
273
  ):
278
274
  logger.important(
@@ -280,7 +276,7 @@ def validate_connection_state(
280
276
  )
281
277
  return None
282
278
  else:
283
- if settings._instance_exists and settings.instance.slug != "none/none":
279
+ if settings._instance_exists:
284
280
  import lamindb as ln
285
281
 
286
282
  if ln.context.transform is not None:
@@ -292,7 +288,9 @@ def validate_connection_state(
292
288
 
293
289
  @unlock_cloud_sqlite_upon_exception(ignore_prev_locker=True)
294
290
  def connect(instance: str | None = None, **kwargs: Any) -> str | tuple | None:
295
- """Connect to an instance.
291
+ """Connect the global default instance.
292
+
293
+ If you want to create a read-only database client, use :class:`~lamindb.DB` instead.
296
294
 
297
295
  Args:
298
296
  instance: Pass a slug (`account/name`) or URL (`https://lamin.ai/account/name`).
@@ -340,12 +338,9 @@ def connect(instance: str | None = None, **kwargs: Any) -> str | tuple | None:
340
338
  if settings._instance_exists:
341
339
  isettings = settings.instance
342
340
  else:
343
- isettings_or_none = _get_current_instance_settings()
344
- if isettings_or_none is None:
345
- raise ValueError(
346
- "No instance was connected through the CLI, pass a value to `instance` or connect via the CLI."
347
- )
348
- isettings = isettings_or_none
341
+ raise ValueError(
342
+ "No instance was connected through the CLI, pass a value to `instance` or connect via the CLI."
343
+ )
349
344
  if use_root_db_user:
350
345
  reset_django()
351
346
  owner, name = isettings.owner, isettings.name
@@ -414,7 +409,6 @@ def connect(instance: str | None = None, **kwargs: Any) -> str | tuple | None:
414
409
 
415
410
  load_from_isettings(isettings, user=_user, write_settings=_write_settings)
416
411
  if _reload_lamindb:
417
- importlib.reload(importlib.import_module("lamindb"))
418
412
  reset_django_module_variables()
419
413
  if isettings.slug != "none/none":
420
414
  logger.important(f"connected lamindb: {isettings.slug}")
@@ -424,10 +418,6 @@ def connect(instance: str | None = None, **kwargs: Any) -> str | tuple | None:
424
418
  isettings._get_settings_file().unlink(missing_ok=True) # type: ignore
425
419
  settings._instance_settings = None
426
420
  raise e
427
- if settings.dev_dir is None:
428
- logger.important_hint(
429
- "to map a local dev directory, set: ln.setup.settings.dev_dir = '.'"
430
- )
431
421
  return None
432
422
 
433
423