lamindb_setup 1.7.3__tar.gz → 1.8.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 (106) hide show
  1. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/PKG-INFO +1 -1
  2. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/docs/hub-cloud/03-add-managed-storage.ipynb +25 -5
  3. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/docs/hub-cloud/07-keep-artifacts-local.ipynb +37 -19
  4. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/lamindb_setup/__init__.py +1 -1
  5. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/lamindb_setup/_set_managed_storage.py +17 -4
  6. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/lamindb_setup/core/_settings_instance.py +60 -33
  7. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/lamindb_setup/core/_settings_storage.py +31 -8
  8. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/lamindb_setup/core/upath.py +7 -3
  9. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/tests/hub-cloud/scripts/script-to-fail-managed-storage.py +1 -1
  10. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/tests/hub-local/conftest.py +3 -6
  11. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/tests/hub-local/scripts/script-connect-fine-grained-access.py +1 -1
  12. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/tests/hub-local/test_all.py +6 -6
  13. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/.github/workflows/build.yml +0 -0
  14. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/.github/workflows/doc-changes.yml +0 -0
  15. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/.gitignore +0 -0
  16. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/.pre-commit-config.yaml +0 -0
  17. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/LICENSE +0 -0
  18. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/README.md +0 -0
  19. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/docs/changelog.md +0 -0
  20. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/docs/hub-cloud/01-init-local-instance.ipynb +0 -0
  21. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/docs/hub-cloud/02-connect-local-instance.ipynb +0 -0
  22. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/docs/hub-cloud/04-test-bionty.ipynb +0 -0
  23. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/docs/hub-cloud/05-init-hosted-instance.ipynb +0 -0
  24. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/docs/hub-cloud/06-connect-hosted-instance.ipynb +0 -0
  25. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/docs/hub-cloud/08-test-multi-session.ipynb +0 -0
  26. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/docs/hub-cloud/test_notebooks.py +0 -0
  27. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/docs/hub-prod/test-cache-management.ipynb +0 -0
  28. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/docs/hub-prod/test-cloud-sync.ipynb +0 -0
  29. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/docs/hub-prod/test-connect-anonymously.ipynb +0 -0
  30. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/docs/hub-prod/test-empty-init.ipynb +0 -0
  31. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/docs/hub-prod/test-import-schema.ipynb +0 -0
  32. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/docs/hub-prod/test-init-load-local-anonymously.ipynb +0 -0
  33. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/docs/hub-prod/test-insufficient-user-info.ipynb +0 -0
  34. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/docs/hub-prod/test-invalid-schema.ipynb +0 -0
  35. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/docs/hub-prod/test-sqlite-lock.ipynb +0 -0
  36. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/docs/hub-prod/test_notebooks2.py +0 -0
  37. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/docs/index.md +0 -0
  38. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/docs/notebooks.md +0 -0
  39. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/docs/reference.md +0 -0
  40. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/lamindb_setup/_cache.py +0 -0
  41. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/lamindb_setup/_check.py +0 -0
  42. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/lamindb_setup/_check_setup.py +0 -0
  43. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/lamindb_setup/_connect_instance.py +0 -0
  44. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/lamindb_setup/_delete.py +0 -0
  45. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/lamindb_setup/_disconnect.py +0 -0
  46. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/lamindb_setup/_django.py +0 -0
  47. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/lamindb_setup/_entry_points.py +0 -0
  48. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/lamindb_setup/_exportdb.py +0 -0
  49. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/lamindb_setup/_importdb.py +0 -0
  50. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/lamindb_setup/_init_instance.py +0 -0
  51. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/lamindb_setup/_migrate.py +0 -0
  52. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/lamindb_setup/_register_instance.py +0 -0
  53. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/lamindb_setup/_schema.py +0 -0
  54. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/lamindb_setup/_schema_metadata.py +0 -0
  55. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/lamindb_setup/_setup_user.py +0 -0
  56. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/lamindb_setup/_silence_loggers.py +0 -0
  57. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/lamindb_setup/core/__init__.py +0 -0
  58. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/lamindb_setup/core/_aws_options.py +0 -0
  59. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/lamindb_setup/core/_aws_storage.py +0 -0
  60. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/lamindb_setup/core/_deprecated.py +0 -0
  61. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/lamindb_setup/core/_docs.py +0 -0
  62. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/lamindb_setup/core/_hub_client.py +0 -0
  63. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/lamindb_setup/core/_hub_core.py +0 -0
  64. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/lamindb_setup/core/_hub_crud.py +0 -0
  65. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/lamindb_setup/core/_hub_utils.py +0 -0
  66. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/lamindb_setup/core/_private_django_api.py +0 -0
  67. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/lamindb_setup/core/_settings.py +0 -0
  68. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/lamindb_setup/core/_settings_load.py +0 -0
  69. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/lamindb_setup/core/_settings_save.py +0 -0
  70. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/lamindb_setup/core/_settings_store.py +0 -0
  71. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/lamindb_setup/core/_settings_user.py +0 -0
  72. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/lamindb_setup/core/_setup_bionty_sources.py +0 -0
  73. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/lamindb_setup/core/cloud_sqlite_locker.py +0 -0
  74. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/lamindb_setup/core/django.py +0 -0
  75. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/lamindb_setup/core/exceptions.py +0 -0
  76. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/lamindb_setup/core/hashing.py +0 -0
  77. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/lamindb_setup/core/types.py +0 -0
  78. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/lamindb_setup/errors.py +0 -0
  79. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/lamindb_setup/py.typed +0 -0
  80. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/lamindb_setup/types.py +0 -0
  81. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/noxfile.py +0 -0
  82. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/pyproject.toml +0 -0
  83. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/tests/hub-cloud/scripts/script-init-pass-user-no-writes.py +0 -0
  84. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/tests/hub-cloud/test_connect_instance.py +0 -0
  85. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/tests/hub-cloud/test_delete_instance.py +0 -0
  86. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/tests/hub-cloud/test_edge_request.py +0 -0
  87. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/tests/hub-cloud/test_fail_managed_storage.py +0 -0
  88. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/tests/hub-cloud/test_init_instance.py +0 -0
  89. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/tests/hub-cloud/test_init_pass_user_no_writes.py +0 -0
  90. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/tests/hub-cloud/test_login.py +0 -0
  91. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/tests/hub-cloud/test_migrate.py +0 -0
  92. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/tests/hub-cloud/test_set_storage.py +0 -0
  93. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/tests/hub-local/test_update_schema_in_hub.py +0 -0
  94. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/tests/hub-prod/conftest.py +0 -0
  95. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/tests/hub-prod/test_aws_options_manager.py +0 -0
  96. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/tests/hub-prod/test_django.py +0 -0
  97. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/tests/hub-prod/test_global_settings.py +0 -0
  98. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/tests/hub-prod/test_switch_and_fallback_env.py +0 -0
  99. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/tests/hub-prod/test_upath.py +0 -0
  100. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/tests/storage/test_entry_point.py +0 -0
  101. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/tests/storage/test_hashing.py +0 -0
  102. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/tests/storage/test_storage_access.py +0 -0
  103. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/tests/storage/test_storage_basis.py +0 -0
  104. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/tests/storage/test_storage_settings.py +0 -0
  105. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/tests/storage/test_storage_stats.py +0 -0
  106. {lamindb_setup-1.7.3 → lamindb_setup-1.8.0}/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.7.3
3
+ Version: 1.8.0
4
4
  Summary: Setup & configure LaminDB.
5
5
  Author-email: Lamin Labs <open-source@lamin.ai>
6
6
  Requires-Python: >=3.10
@@ -83,6 +83,16 @@
83
83
  "ln_setup.init(storage=\"./storage1\", name=\"test-add-managed-storage\", db=pgurl)"
84
84
  ]
85
85
  },
86
+ {
87
+ "cell_type": "code",
88
+ "execution_count": null,
89
+ "id": "95a61826",
90
+ "metadata": {},
91
+ "outputs": [],
92
+ "source": [
93
+ "ln_setup.settings.instance.is_on_hub"
94
+ ]
95
+ },
86
96
  {
87
97
  "cell_type": "markdown",
88
98
  "id": "b62e84cb",
@@ -148,6 +158,16 @@
148
158
  "ln_setup.register()"
149
159
  ]
150
160
  },
161
+ {
162
+ "cell_type": "code",
163
+ "execution_count": null,
164
+ "id": "825c34b7",
165
+ "metadata": {},
166
+ "outputs": [],
167
+ "source": [
168
+ "ln_setup.settings.instance.is_on_hub"
169
+ ]
170
+ },
151
171
  {
152
172
  "cell_type": "markdown",
153
173
  "id": "f7e1bfaa",
@@ -163,7 +183,7 @@
163
183
  "metadata": {},
164
184
  "outputs": [],
165
185
  "source": [
166
- "set_managed_storage(\"./storage2\")"
186
+ "set_managed_storage(\"./storage2\", host=\"testuser1-laptop\")"
167
187
  ]
168
188
  },
169
189
  {
@@ -200,7 +220,7 @@
200
220
  "metadata": {},
201
221
  "outputs": [],
202
222
  "source": [
203
- "set_managed_storage(\"./storage1\")"
223
+ "set_managed_storage(\"./storage1\", host=\"testuser1-laptop\")"
204
224
  ]
205
225
  },
206
226
  {
@@ -233,7 +253,7 @@
233
253
  "metadata": {},
234
254
  "outputs": [],
235
255
  "source": [
236
- "set_managed_storage(\"./storage1\")"
256
+ "set_managed_storage(\"./storage1\", host=\"testuser1-laptop\")"
237
257
  ]
238
258
  },
239
259
  {
@@ -258,7 +278,7 @@
258
278
  "metadata": {},
259
279
  "outputs": [],
260
280
  "source": [
261
- "set_managed_storage(\"./storage2\")"
281
+ "set_managed_storage(\"./storage2\", host=\"testuser1-laptop\")"
262
282
  ]
263
283
  },
264
284
  {
@@ -419,7 +439,7 @@
419
439
  "outputs": [],
420
440
  "source": [
421
441
  "ln_setup.login(\"testuser2\")\n",
422
- "set_managed_storage(\"./storage4\")\n",
442
+ "set_managed_storage(\"./storage4\", host=\"testuser2-laptop\")\n",
423
443
  "assert ln_setup.settings.storage.root_as_str == f\"{Path.cwd()}/storage4\""
424
444
  ]
425
445
  },
@@ -22,6 +22,8 @@
22
22
  "from upath import UPath\n",
23
23
  "from pathlib import Path\n",
24
24
  "\n",
25
+ "# os.environ[\"LAMIN_ENV\"] = \"prod\"\n",
26
+ "\n",
25
27
  "name = f\"keep-artifacts-local-setup-{os.environ['LAMIN_ENV']}\"\n",
26
28
  "storage = UPath(f\"s3://lamindb-ci/{name}\").as_posix()\n",
27
29
  "\n",
@@ -43,7 +45,7 @@
43
45
  "outputs": [],
44
46
  "source": [
45
47
  "with pytest.raises(ValueError) as error:\n",
46
- " ln_setup.settings.instance.storage_local\n",
48
+ " ln_setup.settings.instance.local_storage\n",
47
49
  "assert (\n",
48
50
  " error.exconly()\n",
49
51
  " == \"ValueError: `keep_artifacts_local` is not enabled for this instance.\"\n",
@@ -58,7 +60,11 @@
58
60
  "source": [
59
61
  "ln_setup.settings.instance._keep_artifacts_local = True\n",
60
62
  "with pytest.raises(ValueError) as error:\n",
61
- " ln_setup.settings.instance.storage_local"
63
+ " ln_setup.settings.instance.local_storage\n",
64
+ "assert (\n",
65
+ " error.exconly()\n",
66
+ " == \"ValueError: No storage location found in current environment: create one via, e.g., ln.Storage(root='/dir/our_shared_dir', host='our-server-123).save()\"\n",
67
+ ")"
62
68
  ]
63
69
  },
64
70
  {
@@ -68,16 +74,17 @@
68
74
  "outputs": [],
69
75
  "source": [
70
76
  "# now set local storage location\n",
71
- "ln_setup.settings.instance.storage_local = \"./my_storage_local\"\n",
77
+ "ln_setup.settings.instance.local_storage = \"./my_local_storage\", \"testuser1-laptop\"\n",
72
78
  "\n",
73
79
  "assert (\n",
74
- " ln_setup.settings.instance.storage_local.root.as_posix()\n",
75
- " == UPath(\"./my_storage_local\").resolve().as_posix()\n",
80
+ " ln_setup.settings.instance.local_storage.root.as_posix()\n",
81
+ " == UPath(\"./my_local_storage\").resolve().as_posix()\n",
76
82
  ")\n",
77
83
  "assert (\n",
78
- " ln_setup.settings.instance.storage_local.root / \".lamindb/storage_uid.txt\"\n",
79
- ").read_text().splitlines()[0] == ln_setup.settings.instance.storage_local.uid\n",
80
- "assert ln_setup.settings.instance.storage_local is not None\n",
84
+ " ln_setup.settings.instance.local_storage.root / \".lamindb/storage_uid.txt\"\n",
85
+ ").read_text().splitlines()[0] == ln_setup.settings.instance.local_storage.uid\n",
86
+ "assert ln_setup.settings.instance.local_storage is not None\n",
87
+ "assert ln_setup.settings.instance.local_storage.region == \"testuser1-laptop\"\n",
81
88
  "# the remote storage location is still in the regular slot\n",
82
89
  "assert ln_setup.settings.instance.storage.root.as_posix() == storage"
83
90
  ]
@@ -95,7 +102,7 @@
95
102
  "metadata": {},
96
103
  "outputs": [],
97
104
  "source": [
98
- "ln_setup.settings.instance.storage_local = \"./my_storage_local2\""
105
+ "ln_setup.settings.instance.local_storage = \"./my_local_storage2\", \"testuser1-laptop\""
99
106
  ]
100
107
  },
101
108
  {
@@ -105,12 +112,12 @@
105
112
  "outputs": [],
106
113
  "source": [
107
114
  "assert (\n",
108
- " ln_setup.settings.instance.storage_local.root.as_posix()\n",
109
- " == UPath(\"./my_storage_local2\").resolve().as_posix()\n",
115
+ " ln_setup.settings.instance.local_storage.root.as_posix()\n",
116
+ " == UPath(\"./my_local_storage2\").resolve().as_posix()\n",
110
117
  ")\n",
111
118
  "assert (\n",
112
- " ln_setup.settings.instance.storage_local.root / \".lamindb/storage_uid.txt\"\n",
113
- ").read_text().splitlines()[0] == ln_setup.settings.instance.storage_local.uid"
119
+ " ln_setup.settings.instance.local_storage.root / \".lamindb/storage_uid.txt\"\n",
120
+ ").read_text().splitlines()[0] == ln_setup.settings.instance.local_storage.uid"
114
121
  ]
115
122
  },
116
123
  {
@@ -126,7 +133,7 @@
126
133
  "metadata": {},
127
134
  "outputs": [],
128
135
  "source": [
129
- "ln_setup.settings.instance.storage_local = \"./my_storage_local2\""
136
+ "ln_setup.settings.instance.local_storage = \"./my_local_storage2\", \"testuser1-laptop\""
130
137
  ]
131
138
  },
132
139
  {
@@ -142,7 +149,18 @@
142
149
  "metadata": {},
143
150
  "outputs": [],
144
151
  "source": [
145
- "ln_setup.settings.instance.storage_local = \"./my_storage_local\""
152
+ "ln_setup.settings.instance.local_storage = \"./my_local_storage\", \"testuser1-laptop\""
153
+ ]
154
+ },
155
+ {
156
+ "cell_type": "code",
157
+ "execution_count": null,
158
+ "metadata": {},
159
+ "outputs": [],
160
+ "source": [
161
+ "import lamindb as ln\n",
162
+ "\n",
163
+ "ln.Storage.df()"
146
164
  ]
147
165
  },
148
166
  {
@@ -158,7 +176,7 @@
158
176
  "metadata": {},
159
177
  "outputs": [],
160
178
  "source": [
161
- "test_file = ln_setup.settings.instance.storage_local.root / \".lamindb/test_file.txt\"\n",
179
+ "test_file = ln_setup.settings.instance.local_storage.root / \".lamindb/test_file.txt\"\n",
162
180
  "test_file.write_text(\"test\")"
163
181
  ]
164
182
  },
@@ -168,7 +186,7 @@
168
186
  "metadata": {},
169
187
  "outputs": [],
170
188
  "source": [
171
- "ln_setup.settings.instance.storage_local.root.view_tree()"
189
+ "ln_setup.settings.instance.local_storage.root.view_tree()"
172
190
  ]
173
191
  },
174
192
  {
@@ -227,7 +245,7 @@
227
245
  ],
228
246
  "metadata": {
229
247
  "kernelspec": {
230
- "display_name": "Python 3 (ipykernel)",
248
+ "display_name": "py312",
231
249
  "language": "python",
232
250
  "name": "python3"
233
251
  },
@@ -241,7 +259,7 @@
241
259
  "name": "python",
242
260
  "nbconvert_exporter": "python",
243
261
  "pygments_lexer": "ipython3",
244
- "version": "3.10.16"
262
+ "version": "3.12.8"
245
263
  }
246
264
  },
247
265
  "nbformat": 4,
@@ -35,7 +35,7 @@ Modules & settings:
35
35
 
36
36
  """
37
37
 
38
- __version__ = "1.7.3" # denote a release candidate for 0.1.0 with 0.1rc1
38
+ __version__ = "1.8.0" # denote a release candidate for 0.1.0 with 0.1rc1
39
39
 
40
40
  import os
41
41
 
@@ -7,17 +7,19 @@ from lamin_utils import logger
7
7
  from ._init_instance import register_storage_in_instance
8
8
  from .core._hub_core import delete_storage_record
9
9
  from .core._settings import settings
10
- from .core._settings_storage import init_storage
10
+ from .core._settings_storage import StorageSettings, init_storage
11
11
 
12
12
  if TYPE_CHECKING:
13
13
  from lamindb_setup.types import UPathStr
14
14
 
15
15
 
16
- def set_managed_storage(root: UPathStr, **fs_kwargs):
16
+ def set_managed_storage(root: UPathStr, host: str | None = None, **fs_kwargs):
17
17
  """Add or switch to another managed storage location.
18
18
 
19
19
  Args:
20
20
  root: `UPathStr` - The new storage root, e.g., an S3 bucket.
21
+ host: `str | None = None` For a shared local storage location, pass a globally unique host identifier, e.g. `"my-institute-cluster-1"`, `"my-server-abcd"`, ...
22
+ Discuss the naming convention with an admin.
21
23
  **fs_kwargs: Additional fsspec arguments for cloud root, e.g., profile.
22
24
 
23
25
  """
@@ -29,6 +31,16 @@ def set_managed_storage(root: UPathStr, **fs_kwargs):
29
31
  raise ValueError(
30
32
  "Can't add additional managed storage locations for instances that aren't managed through the hub."
31
33
  )
34
+
35
+ # we do not just query the instance storage table because
36
+ # we might need some information from the hub
37
+ if not StorageSettings(root).type_is_cloud and host is None:
38
+ host = "unspecified-host"
39
+ logger.warning(
40
+ "setting local storage locations with a single path is deprecated, "
41
+ "use a tuple of (local_root, host) instead"
42
+ )
43
+
32
44
  # here the storage is registered in the hub
33
45
  # hub_record_status="hub-record-created" if a new record is created
34
46
  # "hub-record-retrieved" if the storage is in the hub already
@@ -36,13 +48,14 @@ def set_managed_storage(root: UPathStr, **fs_kwargs):
36
48
  root=root,
37
49
  instance_id=settings.instance._id,
38
50
  instance_slug=settings.instance.slug,
39
- register_hub=True,
51
+ register_hub=settings.instance.is_on_hub,
52
+ prevent_register_hub=not settings.instance.is_on_hub,
53
+ region=host,
40
54
  )
41
55
  if ssettings._instance_id is None:
42
56
  raise ValueError(
43
57
  f"Cannot manage storage without write access: {ssettings.root}"
44
58
  )
45
-
46
59
  # here the storage is saved in the instance
47
60
  # if any error happens the record in the hub is deleted
48
61
  # if it was created earlier and not retrieved
@@ -32,6 +32,8 @@ if TYPE_CHECKING:
32
32
 
33
33
  from ._settings_user import UserSettings
34
34
 
35
+ LOCAL_STORAGE_MESSAGE = "No storage location found in current environment: create one via, e.g., ln.Storage(root='/dir/our_shared_dir', host='our-server-123).save()"
36
+
35
37
 
36
38
  def sanitize_git_repo_url(repo_url: str) -> str:
37
39
  assert repo_url.startswith("https://")
@@ -82,7 +84,7 @@ class InstanceSettings:
82
84
  self._git_repo = None if git_repo is None else sanitize_git_repo_url(git_repo)
83
85
  # local storage
84
86
  self._keep_artifacts_local = keep_artifacts_local
85
- self._storage_local: StorageSettings | None = None
87
+ self._local_storage: StorageSettings | None = None
86
88
  self._is_on_hub = is_on_hub
87
89
  # private, needed for api requests
88
90
  self._api_url = api_url
@@ -151,7 +153,7 @@ class InstanceSettings:
151
153
  except ProgrammingError:
152
154
  logger.error("not able to load Storage registry: please migrate")
153
155
  return None
154
- found = False
156
+ found = []
155
157
  for record in all_local_records:
156
158
  root_path = Path(record.root)
157
159
  if root_path.exists():
@@ -175,18 +177,16 @@ class InstanceSettings:
175
177
  )
176
178
  continue
177
179
  if uid == record.uid:
178
- found = True
179
- break
180
+ found.append(record)
180
181
  if found:
182
+ if len(found) > 1:
183
+ found_display = "\n - ".join([f"{record.root}" for record in found])
184
+ logger.important(f"found locations:\n - {found_display}")
185
+ logger.important(f"defaulting to local storage: {record.root}")
181
186
  return StorageSettings(record.root)
182
187
  elif not mute_warning:
183
- logger.warning(
184
- "none of the registered local storage locations were found:\n "
185
- + "\n ".join(r.root for r in all_local_records)
186
- )
187
- logger.important(
188
- "please register a new local storage location via `ln.settings.storage_local = local_root_path` and re-load/connect the instance"
189
- )
188
+ start = LOCAL_STORAGE_MESSAGE[0].lower()
189
+ logger.warning(f"{start}{LOCAL_STORAGE_MESSAGE[1:]}")
190
190
  return None
191
191
 
192
192
  @property
@@ -209,8 +209,8 @@ class InstanceSettings:
209
209
  return self._storage
210
210
 
211
211
  @property
212
- def storage_local(self) -> StorageSettings:
213
- """An additional local default storage.
212
+ def local_storage(self) -> StorageSettings:
213
+ """An additional local storage location.
214
214
 
215
215
  Is only available if :attr:`keep_artifacts_local` is enabled.
216
216
 
@@ -218,46 +218,73 @@ class InstanceSettings:
218
218
  """
219
219
  if not self._keep_artifacts_local:
220
220
  raise ValueError("`keep_artifacts_local` is not enabled for this instance.")
221
- if self._storage_local is None:
222
- self._storage_local = self._search_local_root()
223
- if self._storage_local is None:
224
- # raise an error, there was a warning just before in search_local_root
225
- raise ValueError()
226
- return self._storage_local
227
-
228
- @storage_local.setter
229
- def storage_local(self, local_root: Path | str):
221
+ if self._local_storage is None:
222
+ self._local_storage = self._search_local_root()
223
+ if self._local_storage is None:
224
+ raise ValueError(LOCAL_STORAGE_MESSAGE)
225
+ return self._local_storage
226
+
227
+ @local_storage.setter
228
+ def local_storage(self, local_root_host: tuple[Path | str, str]):
230
229
  from lamindb_setup._init_instance import register_storage_in_instance
231
230
 
231
+ if not isinstance(local_root_host, tuple):
232
+ local_root = local_root_host
233
+ host = "unspecified-host"
234
+ else:
235
+ local_root, host = local_root_host
236
+
232
237
  local_root = Path(local_root)
233
238
  if not self._keep_artifacts_local:
234
239
  raise ValueError("`keep_artifacts_local` is not enabled for this instance.")
235
- storage_local = self._search_local_root(
240
+ local_storage = self._search_local_root(
236
241
  local_root=StorageSettings(local_root).root_as_str, mute_warning=True
237
242
  )
238
- if storage_local is not None:
243
+ if local_storage is not None:
239
244
  # great, we're merely switching storage location
240
- self._storage_local = storage_local
241
- logger.important(f"defaulting to local storage: {storage_local.root}")
245
+ self._local_storage = local_storage
242
246
  return None
243
- storage_local = self._search_local_root(mute_warning=True)
244
- if storage_local is not None:
247
+ local_storage = self._search_local_root(mute_warning=True)
248
+ if local_storage is not None:
245
249
  if os.getenv("LAMIN_TESTING") == "true":
246
250
  response = "y"
247
251
  else:
248
252
  response = input(
249
253
  "You already configured a local storage root for this instance in this"
250
- f" environment: {self.storage_local.root}\nDo you want to register another one? (y/n)"
254
+ f" environment: {self.local_storage.root}\nDo you want to register another one? (y/n)"
251
255
  )
252
256
  if response != "y":
253
257
  return None
258
+ if host == "unspecified-host":
259
+ logger.warning(
260
+ "setting local_storage with a single path is deprecated for creating storage locations"
261
+ )
262
+ logger.warning(
263
+ "use this instead: ln.Storage(root='/dir/our_shared_dir', host='our-server-123').save()"
264
+ )
254
265
  local_root = UPath(local_root)
255
266
  assert isinstance(local_root, LocalPathClasses)
256
- self._storage_local, _ = init_storage(
257
- local_root, instance_id=self._id, instance_slug=self.slug, register_hub=True
267
+ self._local_storage, _ = init_storage(
268
+ local_root,
269
+ instance_id=self._id,
270
+ instance_slug=self.slug,
271
+ register_hub=True,
272
+ region=host,
258
273
  ) # type: ignore
259
- register_storage_in_instance(self._storage_local) # type: ignore
260
- logger.important(f"defaulting to local storage: {self._storage_local.root}")
274
+ register_storage_in_instance(self._local_storage) # type: ignore
275
+ logger.important(
276
+ f"defaulting to local storage: {self._local_storage.root} on host {host}"
277
+ )
278
+
279
+ @property
280
+ @deprecated("local_storage")
281
+ def storage_local(self) -> StorageSettings:
282
+ return self.local_storage
283
+
284
+ @storage_local.setter
285
+ @deprecated("local_storage")
286
+ def storage_local(self, local_root_host: tuple[Path | str, str]):
287
+ self.local_storage = local_root_host # type: ignore
261
288
 
262
289
  @property
263
290
  def slug(self) -> str:
@@ -87,6 +87,15 @@ def get_storage_region(path: UPathStr) -> str | None:
87
87
  return region
88
88
 
89
89
 
90
+ def get_storage_type(root_as_str: str) -> StorageType:
91
+ import fsspec
92
+
93
+ convert = {"file": "local"}
94
+ # init_storage checks that the root protocol belongs to VALID_PROTOCOLS
95
+ protocol = fsspec.utils.get_protocol(root_as_str)
96
+ return convert.get(protocol, protocol) # type: ignore
97
+
98
+
90
99
  def mark_storage_root(
91
100
  root: UPathStr, uid: str, instance_id: UUID, instance_slug: str
92
101
  ) -> Literal["__marked__"] | str:
@@ -125,6 +134,7 @@ def init_storage(
125
134
  init_instance: bool = False,
126
135
  created_by: UUID | None = None,
127
136
  access_token: str | None = None,
137
+ region: str | None = None,
128
138
  ) -> tuple[
129
139
  StorageSettings,
130
140
  Literal["hub-record-not-created", "hub-record-retrieved", "hub-record-created"],
@@ -145,7 +155,6 @@ def init_storage(
145
155
  # this means we constructed a hosted location of shape s3://bucket-name/uid
146
156
  # within LaminHub
147
157
  assert root_str.endswith(uid)
148
- region = None
149
158
  lamin_env = os.getenv("LAMIN_ENV")
150
159
  if root_str.startswith("create-s3"):
151
160
  if root_str != "create-s3":
@@ -177,6 +186,10 @@ def init_storage(
177
186
  register_hub = (
178
187
  register_hub or ssettings.type_is_cloud
179
188
  ) # default to registering cloud storage
189
+ if register_hub and not ssettings.type_is_cloud and ssettings.host is None:
190
+ raise ValueError(
191
+ "`host` must be set for local storage locations that are registered on the hub"
192
+ )
180
193
  hub_record_status = init_storage_hub(
181
194
  ssettings,
182
195
  auto_populate_instance=not init_instance,
@@ -226,7 +239,10 @@ def init_storage(
226
239
 
227
240
 
228
241
  class StorageSettings:
229
- """Settings for a storage location (local or cloud)."""
242
+ """Settings for a storage location (local or cloud).
243
+
244
+ Do not instantiate this class yourself, use `ln.Storage` instead.
245
+ """
230
246
 
231
247
  def __init__(
232
248
  self,
@@ -385,6 +401,18 @@ class StorageSettings:
385
401
  """`True` if `storage_root` is in cloud, `False` otherwise."""
386
402
  return self.type != "local"
387
403
 
404
+ @property
405
+ def host(self) -> str | None:
406
+ """Host identifier for local storage locations.
407
+
408
+ Is `None` for locations with `type != "local"`.
409
+
410
+ A globally unique user-defined host identifier (cluster, server, laptop, etc.).
411
+ """
412
+ if self.type != "local":
413
+ return None
414
+ return self.region
415
+
388
416
  @property
389
417
  def region(self) -> str | None:
390
418
  """Storage region."""
@@ -398,12 +426,7 @@ class StorageSettings:
398
426
 
399
427
  Returns the protocol as a stringe, e.g., "local", "s3", "gs", "http", "https".
400
428
  """
401
- import fsspec
402
-
403
- convert = {"file": "local"}
404
- # init_storage checks that the root protocol belongs to VALID_PROTOCOLS
405
- protocol = fsspec.utils.get_protocol(self.root_as_str)
406
- return convert.get(protocol, protocol) # type: ignore
429
+ return get_storage_type(self.root_as_str)
407
430
 
408
431
  @property
409
432
  def is_on_hub(self) -> bool:
@@ -928,9 +928,13 @@ def check_storage_is_empty(
928
928
  # if the storage_uid.txt was somehow deleted, we restore a dummy version of it
929
929
  # because we need it to count files in an empty directory on S3 (otherwise permission error)
930
930
  if not (root_upath / STORAGE_UID_FILE_KEY).exists():
931
- (root_upath / STORAGE_UID_FILE_KEY).write_text(
932
- "was deleted, restored during delete"
933
- )
931
+ try:
932
+ (root_upath / STORAGE_UID_FILE_KEY).write_text(
933
+ "was deleted, restored during delete"
934
+ )
935
+ except FileNotFoundError:
936
+ # this can happen if the root is a local non-existing path
937
+ pass
934
938
  if account_for_sqlite_file:
935
939
  n_offset_objects += 1 # the SQLite file is in the ".lamindb" directory
936
940
  if root_string.startswith(HOSTED_BUCKETS):
@@ -13,7 +13,7 @@ ln_setup.connect("laminlabs/lamin-site-assets")
13
13
  test_root = Path("./test_script_ci_storage").resolve().as_posix()
14
14
 
15
15
  with pytest.raises(ProgrammingError) as error:
16
- set_managed_storage(test_root)
16
+ set_managed_storage(test_root, host="test-host-1234")
17
17
  assert error.exconly().endswith(
18
18
  "ProgrammingError: permission denied for table lamindb_storage"
19
19
  )
@@ -11,15 +11,12 @@ from laminhub_rest.dev import (
11
11
  supabase_resources = SupabaseResources()
12
12
 
13
13
 
14
- pytest_plugins = [
15
- "laminhub_rest.test.account.fixtures",
16
- "laminhub_rest.test.common_fixtures",
17
- ]
18
-
19
-
20
14
  def pytest_configure():
21
15
  os.environ["LAMIN_ENV"] = "local"
22
16
  os.environ["LAMIN_CLOUD_VERSION"] = "0.1"
17
+ os.environ["LAMIN_TEST_INSTANCE_ACCESS_V2"] = "true"
18
+ os.environ["LAMIN_TEST_INSTANCE_SCHEMA_STR"] = ""
19
+ os.environ["LAMIN_TEST_INSTANCE_PUBLIC"] = "false"
23
20
  remove_lamin_local_settings()
24
21
  supabase_resources.start_local()
25
22
  supabase_resources.reset_local()
@@ -9,7 +9,7 @@ from lamindb_setup.core.django import db_token_manager
9
9
 
10
10
  assert os.environ["LAMIN_ENV"] == "local"
11
11
 
12
- ln_setup.connect("instance_access_v2")
12
+ ln_setup.connect("instance_test__access_v2")
13
13
 
14
14
  isettings = ln_setup.settings.instance
15
15
 
@@ -42,10 +42,7 @@ from lamindb_setup.core._settings_storage import init_storage as init_storage_ba
42
42
  from lamindb_setup.core._settings_store import instance_settings_file
43
43
  from lamindb_setup.core._settings_user import UserSettings
44
44
  from laminhub_rest.core.legacy._instance_collaborator import InstanceCollaboratorHandler
45
- from laminhub_rest.test.instance.utils import (
46
- create_hosted_test_instance,
47
- delete_hosted_test_instance,
48
- )
45
+ from laminhub_rest.test.instance import create_instance
49
46
  from postgrest.exceptions import APIError
50
47
  from supafunc.errors import FunctionsHttpError
51
48
 
@@ -183,10 +180,13 @@ def create_myinstance(create_testadmin1_session): # -> Dict
183
180
 
184
181
  @pytest.fixture(scope="session")
185
182
  def create_instance_fine_grained_access(create_testadmin1_session):
186
- instance = create_hosted_test_instance("instance_access_v2", access_v2=True)
183
+ client, _ = create_testadmin1_session
184
+
185
+ instance = create_instance("instance_test", client=client)
187
186
 
188
187
  yield instance
189
- delete_hosted_test_instance(instance)
188
+
189
+ delete(instance.name, force=True)
190
190
 
191
191
 
192
192
  def test_connection_string_decomp(create_myinstance, create_testadmin1_session):
File without changes
File without changes
File without changes
File without changes