lamindb_setup 1.9.0__tar.gz → 1.10.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.9.0 → lamindb_setup-1.10.0}/PKG-INFO +3 -3
  2. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/docs/hub-cloud/08-test-multi-session.ipynb +19 -39
  3. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/docs/hub-prod/test-insufficient-user-info.ipynb +1 -11
  4. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/lamindb_setup/__init__.py +1 -1
  5. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/lamindb_setup/_cache.py +3 -3
  6. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/lamindb_setup/_check_setup.py +40 -14
  7. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/lamindb_setup/_connect_instance.py +117 -44
  8. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/lamindb_setup/_delete.py +3 -0
  9. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/lamindb_setup/_disconnect.py +4 -1
  10. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/lamindb_setup/_init_instance.py +36 -46
  11. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/lamindb_setup/_migrate.py +19 -7
  12. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/lamindb_setup/_register_instance.py +2 -5
  13. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/lamindb_setup/_set_managed_storage.py +0 -1
  14. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/lamindb_setup/_setup_user.py +52 -13
  15. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/lamindb_setup/core/_aws_storage.py +9 -1
  16. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/lamindb_setup/core/_hub_core.py +87 -24
  17. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/lamindb_setup/core/_settings.py +12 -5
  18. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/lamindb_setup/core/_settings_instance.py +23 -15
  19. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/lamindb_setup/core/_settings_load.py +2 -2
  20. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/lamindb_setup/core/_settings_storage.py +4 -6
  21. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/lamindb_setup/core/django.py +21 -2
  22. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/lamindb_setup/core/upath.py +4 -4
  23. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/lamindb_setup/errors.py +10 -0
  24. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/pyproject.toml +2 -2
  25. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/tests/hub-cloud/test_connect_instance.py +2 -6
  26. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/tests/hub-cloud/test_init_instance.py +4 -3
  27. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/tests/hub-cloud/test_login.py +5 -2
  28. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/tests/hub-local/scripts/script-connect-fine-grained-access.py +1 -1
  29. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/tests/hub-local/test_all.py +19 -12
  30. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/.github/workflows/build.yml +0 -0
  31. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/.github/workflows/doc-changes.yml +0 -0
  32. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/.gitignore +0 -0
  33. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/.pre-commit-config.yaml +0 -0
  34. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/LICENSE +0 -0
  35. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/README.md +0 -0
  36. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/docs/changelog.md +0 -0
  37. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/docs/hub-cloud/01-init-local-instance.ipynb +0 -0
  38. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/docs/hub-cloud/02-connect-local-instance.ipynb +0 -0
  39. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/docs/hub-cloud/03-add-managed-storage.ipynb +0 -0
  40. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/docs/hub-cloud/04-test-bionty.ipynb +0 -0
  41. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/docs/hub-cloud/05-init-hosted-instance.ipynb +0 -0
  42. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/docs/hub-cloud/06-connect-hosted-instance.ipynb +0 -0
  43. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/docs/hub-cloud/07-keep-artifacts-local.ipynb +0 -0
  44. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/docs/hub-cloud/test_notebooks.py +0 -0
  45. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/docs/hub-prod/test-cache-management.ipynb +0 -0
  46. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/docs/hub-prod/test-cloud-sync.ipynb +0 -0
  47. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/docs/hub-prod/test-connect-anonymously.ipynb +0 -0
  48. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/docs/hub-prod/test-empty-init.ipynb +0 -0
  49. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/docs/hub-prod/test-import-schema.ipynb +0 -0
  50. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/docs/hub-prod/test-init-load-local-anonymously.ipynb +0 -0
  51. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/docs/hub-prod/test-invalid-schema.ipynb +0 -0
  52. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/docs/hub-prod/test-sqlite-lock.ipynb +0 -0
  53. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/docs/hub-prod/test_notebooks2.py +0 -0
  54. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/docs/index.md +0 -0
  55. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/docs/notebooks.md +0 -0
  56. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/docs/reference.md +0 -0
  57. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/lamindb_setup/_check.py +0 -0
  58. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/lamindb_setup/_django.py +0 -0
  59. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/lamindb_setup/_entry_points.py +0 -0
  60. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/lamindb_setup/_exportdb.py +0 -0
  61. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/lamindb_setup/_importdb.py +0 -0
  62. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/lamindb_setup/_schema.py +0 -0
  63. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/lamindb_setup/_schema_metadata.py +0 -0
  64. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/lamindb_setup/_silence_loggers.py +0 -0
  65. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/lamindb_setup/core/__init__.py +0 -0
  66. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/lamindb_setup/core/_aws_options.py +0 -0
  67. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/lamindb_setup/core/_deprecated.py +0 -0
  68. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/lamindb_setup/core/_docs.py +0 -0
  69. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/lamindb_setup/core/_hub_client.py +0 -0
  70. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/lamindb_setup/core/_hub_crud.py +0 -0
  71. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/lamindb_setup/core/_hub_utils.py +0 -0
  72. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/lamindb_setup/core/_private_django_api.py +0 -0
  73. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/lamindb_setup/core/_settings_save.py +0 -0
  74. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/lamindb_setup/core/_settings_store.py +0 -0
  75. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/lamindb_setup/core/_settings_user.py +0 -0
  76. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/lamindb_setup/core/_setup_bionty_sources.py +0 -0
  77. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/lamindb_setup/core/cloud_sqlite_locker.py +0 -0
  78. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/lamindb_setup/core/exceptions.py +0 -0
  79. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/lamindb_setup/core/hashing.py +0 -0
  80. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/lamindb_setup/core/types.py +0 -0
  81. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/lamindb_setup/py.typed +0 -0
  82. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/lamindb_setup/types.py +0 -0
  83. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/noxfile.py +0 -0
  84. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/tests/hub-cloud/scripts/script-init-pass-user-no-writes.py +0 -0
  85. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/tests/hub-cloud/scripts/script-to-fail-managed-storage.py +0 -0
  86. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/tests/hub-cloud/test_delete_instance.py +0 -0
  87. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/tests/hub-cloud/test_edge_request.py +0 -0
  88. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/tests/hub-cloud/test_fail_managed_storage.py +0 -0
  89. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/tests/hub-cloud/test_init_pass_user_no_writes.py +0 -0
  90. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/tests/hub-cloud/test_migrate.py +0 -0
  91. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/tests/hub-cloud/test_set_storage.py +0 -0
  92. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/tests/hub-local/conftest.py +0 -0
  93. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/tests/hub-local/test_update_schema_in_hub.py +0 -0
  94. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/tests/hub-prod/conftest.py +0 -0
  95. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/tests/hub-prod/test_aws_options_manager.py +0 -0
  96. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/tests/hub-prod/test_django.py +0 -0
  97. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/tests/hub-prod/test_global_settings.py +0 -0
  98. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/tests/hub-prod/test_switch_and_fallback_env.py +0 -0
  99. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/tests/hub-prod/test_upath.py +0 -0
  100. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/tests/storage/test_entry_point.py +0 -0
  101. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/tests/storage/test_hashing.py +0 -0
  102. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/tests/storage/test_storage_access.py +0 -0
  103. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/tests/storage/test_storage_basis.py +0 -0
  104. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/tests/storage/test_storage_settings.py +0 -0
  105. {lamindb_setup-1.9.0 → lamindb_setup-1.10.0}/tests/storage/test_storage_stats.py +0 -0
  106. {lamindb_setup-1.9.0 → lamindb_setup-1.10.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.9.0
3
+ Version: 1.10.0
4
4
  Summary: Setup & configure LaminDB.
5
5
  Author-email: Lamin Labs <open-source@lamin.ai>
6
6
  Requires-Python: >=3.10
@@ -21,7 +21,7 @@ Requires-Dist: psutil
21
21
  Requires-Dist: packaging
22
22
  Requires-Dist: urllib3<2 ; extra == "aws"
23
23
  Requires-Dist: aiobotocore[boto3]>=2.5.4,<3.0.0 ; extra == "aws"
24
- Requires-Dist: s3fs>=2023.12.2,<=2025.3.2,!=2024.10.0 ; extra == "aws"
24
+ Requires-Dist: s3fs>=2023.12.2,<=2025.7.0,!=2024.10.0 ; extra == "aws"
25
25
  Requires-Dist: line_profiler ; extra == "dev"
26
26
  Requires-Dist: psycopg2-binary ; extra == "dev"
27
27
  Requires-Dist: python-dotenv ; extra == "dev"
@@ -32,7 +32,7 @@ Requires-Dist: pytest-xdist ; extra == "dev"
32
32
  Requires-Dist: nbproject-test>=0.4.3 ; extra == "dev"
33
33
  Requires-Dist: pandas ; extra == "dev"
34
34
  Requires-Dist: django-schema-graph ; extra == "erdiagram"
35
- Requires-Dist: gcsfs>=2023.12.2,<=2025.3.2 ; extra == "gcp"
35
+ Requires-Dist: gcsfs>=2023.12.2,<=2025.7.0 ; extra == "gcp"
36
36
  Project-URL: Home, https://github.com/laminlabs/lamindb-setup
37
37
  Provides-Extra: aws
38
38
  Provides-Extra: dev
@@ -7,6 +7,13 @@
7
7
  "# Test multi instance and multi user session"
8
8
  ]
9
9
  },
10
+ {
11
+ "cell_type": "markdown",
12
+ "metadata": {},
13
+ "source": [
14
+ "This notebook is complemented by the `faq/setup.ipynb` notebook in lamindb."
15
+ ]
16
+ },
10
17
  {
11
18
  "cell_type": "code",
12
19
  "execution_count": null,
@@ -54,6 +61,15 @@
54
61
  "ln_setup.init(storage=\"./testsetup\")"
55
62
  ]
56
63
  },
64
+ {
65
+ "cell_type": "code",
66
+ "execution_count": null,
67
+ "metadata": {},
68
+ "outputs": [],
69
+ "source": [
70
+ "assert ln_setup.settings.instance.slug == \"testuser1/testsetup\""
71
+ ]
72
+ },
57
73
  {
58
74
  "cell_type": "code",
59
75
  "execution_count": null,
@@ -111,43 +127,7 @@
111
127
  "cell_type": "markdown",
112
128
  "metadata": {},
113
129
  "source": [
114
- "Let us try to init another instance in the same Python session:"
115
- ]
116
- },
117
- {
118
- "cell_type": "code",
119
- "execution_count": null,
120
- "metadata": {},
121
- "outputs": [],
122
- "source": [
123
- "from lamindb_setup._init_instance import CannotSwitchDefaultInstance\n",
124
- "\n",
125
- "with pytest.raises(CannotSwitchDefaultInstance):\n",
126
- " ln_setup.init(storage=\"./testsetup2\")\n",
127
- "with pytest.raises(CannotSwitchDefaultInstance):\n",
128
- " ln_setup.connect(\"testsetup\")\n",
129
- "with pytest.raises(RuntimeError):\n",
130
- " ln_setup.migrate.create()\n",
131
- "with pytest.raises(RuntimeError):\n",
132
- " ln_setup.migrate.deploy()\n",
133
- "\n",
134
- "assert ln_setup.settings.instance.slug == \"testuser1/testsetup\""
135
- ]
136
- },
137
- {
138
- "cell_type": "markdown",
139
- "metadata": {},
140
- "source": [
141
- "Reset `django` and connect to another instance:"
142
- ]
143
- },
144
- {
145
- "cell_type": "code",
146
- "execution_count": null,
147
- "metadata": {},
148
- "outputs": [],
149
- "source": [
150
- "ln_setup.core.django.reset_django()"
130
+ "Connect to another instance in the same process:"
151
131
  ]
152
132
  },
153
133
  {
@@ -182,7 +162,7 @@
182
162
  ],
183
163
  "metadata": {
184
164
  "kernelspec": {
185
- "display_name": "Python 3 (ipykernel)",
165
+ "display_name": "py312",
186
166
  "language": "python",
187
167
  "name": "python3"
188
168
  },
@@ -196,7 +176,7 @@
196
176
  "name": "python",
197
177
  "nbconvert_exporter": "python",
198
178
  "pygments_lexer": "ipython3",
199
- "version": "3.10.16"
179
+ "version": "3.12.8"
200
180
  }
201
181
  },
202
182
  "nbformat": 4,
@@ -38,16 +38,6 @@
38
38
  "## Log in with in-sufficient information"
39
39
  ]
40
40
  },
41
- {
42
- "cell_type": "code",
43
- "execution_count": null,
44
- "metadata": {},
45
- "outputs": [],
46
- "source": [
47
- "with pytest.raises(ValueError):\n",
48
- " ln_setup.login()"
49
- ]
50
- },
51
41
  {
52
42
  "cell_type": "markdown",
53
43
  "metadata": {},
@@ -179,7 +169,7 @@
179
169
  "name": "python",
180
170
  "nbconvert_exporter": "python",
181
171
  "pygments_lexer": "ipython3",
182
- "version": "3.9.17"
172
+ "version": "3.10.16"
183
173
  },
184
174
  "nbproject": {
185
175
  "id": "vLOmzd6d4Jow",
@@ -35,7 +35,7 @@ Modules & settings:
35
35
 
36
36
  """
37
37
 
38
- __version__ = "1.9.0" # denote a release candidate for 0.1.0 with 0.1rc1
38
+ __version__ = "1.10.0" # denote a release candidate for 0.1.0 with 0.1rc1
39
39
 
40
40
  import os
41
41
 
@@ -8,6 +8,7 @@ from lamin_utils import logger
8
8
 
9
9
  from .core._settings_save import save_platform_user_storage_settings
10
10
  from .core._settings_store import system_settings_file
11
+ from .errors import CurrentInstanceNotConfigured
11
12
 
12
13
 
13
14
  def clear_cache_dir():
@@ -19,9 +20,8 @@ def clear_cache_dir():
19
20
  "disconnecting the current instance to update the cloud sqlite database."
20
21
  )
21
22
  disconnect()
22
- except SystemExit as e:
23
- if str(e) != "No instance connected! Call `lamin connect` or `lamin init`":
24
- raise e
23
+ except CurrentInstanceNotConfigured:
24
+ pass
25
25
 
26
26
  cache_dir = settings.cache_dir
27
27
  if cache_dir.exists():
@@ -4,7 +4,9 @@ import functools
4
4
  import importlib as il
5
5
  import inspect
6
6
  import os
7
+ from importlib.metadata import distributions
7
8
  from typing import TYPE_CHECKING
9
+ from uuid import UUID
8
10
 
9
11
  from lamin_utils import logger
10
12
 
@@ -25,6 +27,7 @@ if TYPE_CHECKING:
25
27
 
26
28
 
27
29
  CURRENT_ISETTINGS: InstanceSettings | None = None
30
+ MODULE_CANDIDATES: set[str] | None = None
28
31
  IS_LOADING: bool = False
29
32
 
30
33
 
@@ -42,7 +45,25 @@ def disable_auto_connect(func: Callable):
42
45
  return wrapper
43
46
 
44
47
 
45
- def _get_current_instance_settings() -> InstanceSettings | None:
48
+ def find_module_candidates():
49
+ """Find all local packages that depend on lamindb."""
50
+ global MODULE_CANDIDATES
51
+ if MODULE_CANDIDATES is not None:
52
+ return MODULE_CANDIDATES
53
+ all_dists = list(distributions())
54
+ lamindb_deps = {
55
+ dist.metadata["Name"].lower()
56
+ for dist in all_dists
57
+ if dist.requires and any("lamindb" in req.lower() for req in dist.requires)
58
+ }
59
+ lamindb_deps.remove("lamindb")
60
+ MODULE_CANDIDATES = lamindb_deps
61
+ return lamindb_deps
62
+
63
+
64
+ def _get_current_instance_settings(from_module: str | None = None) -> InstanceSettings:
65
+ from .core._settings_instance import InstanceSettings
66
+
46
67
  global CURRENT_ISETTINGS
47
68
 
48
69
  if CURRENT_ISETTINGS is not None:
@@ -60,9 +81,17 @@ def _get_current_instance_settings() -> InstanceSettings | None:
60
81
  " command line: `lamin connect <instance>` or `lamin init <...>`"
61
82
  )
62
83
  raise e
63
- return isettings
64
84
  else:
65
- return None
85
+ module_candidates = find_module_candidates()
86
+ isettings = InstanceSettings(
87
+ id=UUID("00000000-0000-0000-0000-000000000000"),
88
+ owner="none",
89
+ name="none",
90
+ storage=None,
91
+ modules=",".join(module_candidates),
92
+ )
93
+ CURRENT_ISETTINGS = isettings
94
+ return isettings
66
95
 
67
96
 
68
97
  def _normalize_module_name(module_name: str) -> str:
@@ -132,12 +161,7 @@ def _check_instance_setup(from_module: str | None = None) -> bool:
132
161
  return True
133
162
  isettings = _get_current_instance_settings()
134
163
  if isettings is not None:
135
- if (
136
- from_module is not None
137
- and settings.auto_connect
138
- and not django_lamin.IS_SETUP
139
- and not IS_LOADING
140
- ):
164
+ if from_module is not None and not django_lamin.IS_SETUP and not IS_LOADING:
141
165
  if from_module != "lamindb":
142
166
  _check_module_in_instance_modules(from_module, isettings)
143
167
 
@@ -146,13 +170,15 @@ def _check_instance_setup(from_module: str | None = None) -> bool:
146
170
  il.reload(il.import_module(from_module))
147
171
  else:
148
172
  django_lamin.setup_django(isettings)
149
- logger.important(f"connected lamindb: {isettings.slug}")
150
- settings._instance_settings = (
151
- isettings # update of local storage location
152
- )
173
+ if isettings.slug != "none/none":
174
+ logger.important(f"connected lamindb: {isettings.slug}")
175
+ # update of local storage location through search_local_root()
176
+ settings._instance_settings = isettings
177
+ else:
178
+ logger.warning("not connected, call: ln.connect('account/name')")
153
179
  return django_lamin.IS_SETUP
154
180
  else:
155
- if from_module is not None and settings.auto_connect:
181
+ if from_module is not None:
156
182
  # the below enables users to auto-connect to an instance
157
183
  # simply by setting an environment variable, bypassing the
158
184
  # need of calling connect() manually
@@ -2,23 +2,22 @@ from __future__ import annotations
2
2
 
3
3
  import importlib
4
4
  import os
5
+ import sys
5
6
  from typing import TYPE_CHECKING, Any
6
7
  from uuid import UUID
7
8
 
8
9
  from lamin_utils import logger
9
10
 
10
- from ._check_setup import _check_instance_setup, _get_current_instance_settings
11
- from ._disconnect import disconnect
12
- from ._init_instance import (
13
- MESSAGE_CANNOT_SWITCH_DEFAULT_INSTANCE,
14
- load_from_isettings,
11
+ from ._check_setup import (
12
+ _check_instance_setup,
13
+ _get_current_instance_settings,
14
+ find_module_candidates,
15
15
  )
16
+ from ._disconnect import disconnect
17
+ from ._init_instance import load_from_isettings
16
18
  from ._silence_loggers import silence_loggers
17
19
  from .core._hub_core import connect_instance_hub
18
- from .core._hub_utils import (
19
- LaminDsn,
20
- LaminDsnModel,
21
- )
20
+ from .core._hub_utils import LaminDsnModel
22
21
  from .core._settings import settings
23
22
  from .core._settings_instance import InstanceSettings
24
23
  from .core._settings_load import load_instance_settings
@@ -69,21 +68,18 @@ def update_db_using_local(
69
68
  if hub_instance_result["db_scheme"] == "postgresql":
70
69
  if db is not None:
71
70
  # use only the provided db if it is set
72
- db_dsn_hub = LaminDsnModel(db=db)
73
- db_dsn_local = db_dsn_hub
74
- else:
75
- db_dsn_hub = LaminDsnModel(db=hub_instance_result["db"])
71
+ db_updated = db
72
+ elif (db_env := os.getenv("LAMINDB_INSTANCE_DB")) is not None:
73
+ logger.important("loading db URL from env variable LAMINDB_INSTANCE_DB")
76
74
  # read directly from the environment
77
- if os.getenv("LAMINDB_INSTANCE_DB") is not None:
78
- logger.important("loading db URL from env variable LAMINDB_INSTANCE_DB")
79
- db_dsn_local = LaminDsnModel(db=os.getenv("LAMINDB_INSTANCE_DB"))
80
- # read from a cached settings file in case the hub result is only
81
- # read level or inexistent
82
- elif settings_file.exists() and (
83
- db_dsn_hub.db.user in {None, "none"} or "read" in db_dsn_hub.db.user # type:ignore
84
- ):
75
+ db_updated = db_env
76
+ else:
77
+ db_hub = hub_instance_result["db"]
78
+ db_dsn_hub = LaminDsnModel(db=db_hub)
79
+ # read from a cached settings file in case the hub result is inexistent
80
+ if db_dsn_hub.db.user in {None, "none"} and settings_file.exists():
85
81
  isettings = load_instance_settings(settings_file)
86
- db_dsn_local = LaminDsnModel(db=isettings.db)
82
+ db_updated = isettings.db
87
83
  else:
88
84
  # just take the default hub result and ensure there is actually a user
89
85
  if (
@@ -95,22 +91,7 @@ def update_db_using_local(
95
91
  "No database access, please ask your admin to provide you with"
96
92
  " a DB URL and pass it via --db <db_url>"
97
93
  )
98
- db_dsn_local = db_dsn_hub
99
- if not check_db_dsn_equal_up_to_credentials(db_dsn_hub.db, db_dsn_local.db):
100
- raise ValueError(
101
- "The local differs from the hub database information:\n"
102
- "did your database get updated by an admin?\n"
103
- "Consider deleting your cached database environment:\nrm"
104
- f" {settings_file.as_posix()}"
105
- )
106
- db_updated = LaminDsn.build(
107
- scheme=db_dsn_hub.db.scheme,
108
- user=db_dsn_local.db.user,
109
- password=db_dsn_local.db.password,
110
- host=db_dsn_hub.db.host, # type: ignore
111
- port=db_dsn_hub.db.port,
112
- database=db_dsn_hub.db.database,
113
- )
94
+ db_updated = db_hub
114
95
  return db_updated
115
96
 
116
97
 
@@ -127,7 +108,12 @@ def _connect_instance(
127
108
  if settings_file.exists():
128
109
  isettings = load_instance_settings(settings_file)
129
110
  # skip hub request for a purely local instance
130
- make_hub_request = isettings.is_remote
111
+ if isettings.is_remote:
112
+ make_hub_request = True
113
+ else:
114
+ make_hub_request = False
115
+ if db is not None and isettings.dialect == "postgresql":
116
+ isettings._db = db
131
117
  if make_hub_request:
132
118
  # the following will return a string if the instance does not exist
133
119
  # on the hub
@@ -188,6 +174,62 @@ def _connect_instance(
188
174
  return isettings
189
175
 
190
176
 
177
+ def reset_django_module_variables():
178
+ # This function updates all module-level references to Django classes
179
+ # But it will fail to update function level references
180
+ # So, if a user has
181
+ # def my_function():
182
+ # import lamindb as ln
183
+ # ...
184
+ #
185
+ # Then it will **not** work and the `ln` variable will become stale and hold a reference
186
+ # to the old classes
187
+ # There doesn't seem to be an easy way to fix this problem
188
+
189
+ import types
190
+
191
+ from django.apps import apps
192
+
193
+ app_names = {app.name for app in apps.get_app_configs()}
194
+
195
+ for name, module in sys.modules.items():
196
+ if (
197
+ module is not None
198
+ and (not name.startswith("__") or name == "__main__")
199
+ and name not in sys.builtin_module_names
200
+ and not (
201
+ hasattr(module, "__file__")
202
+ and module.__file__
203
+ and any(
204
+ path in module.__file__ for path in ["/lib/python", "\\lib\\python"]
205
+ )
206
+ )
207
+ ):
208
+ try:
209
+ for k, v in vars(module).items():
210
+ if (
211
+ isinstance(v, types.ModuleType)
212
+ and not k.startswith("_")
213
+ and getattr(v, "__name__", None) in app_names
214
+ ):
215
+ if v.__name__ in sys.modules:
216
+ vars(module)[k] = sys.modules[v.__name__]
217
+ # Also reset classes from Django apps - but check if the class module starts with any app name
218
+ elif hasattr(v, "__module__") and getattr(v, "__module__", None):
219
+ class_module = v.__module__
220
+ # Check if the class module starts with any of our app names
221
+ if any(
222
+ class_module.startswith(app_name) for app_name in app_names
223
+ ):
224
+ if class_module in sys.modules:
225
+ fresh_module = sys.modules[class_module]
226
+ attr_name = getattr(v, "__name__", k)
227
+ if hasattr(fresh_module, attr_name):
228
+ vars(module)[k] = getattr(fresh_module, attr_name)
229
+ except (AttributeError, TypeError):
230
+ continue
231
+
232
+
191
233
  def _connect_cli(instance: str) -> None:
192
234
  from lamindb_setup import settings as settings_
193
235
 
@@ -214,6 +256,9 @@ def connect(instance: str | None = None, **kwargs: Any) -> str | tuple | None:
214
256
  instance: Pass a slug (`account/name`) or URL (`https://lamin.ai/account/name`).
215
257
  If `None`, looks for an environment variable `LAMIN_CURRENT_INSTANCE` to get the instance identifier.
216
258
  If it doesn't find this variable, it connects to the instance that was connected with `lamin connect` through the CLI.
259
+
260
+ See Also:
261
+ Configure an instance for auto-connect via the CLI, see `here <https://docs.lamin.ai/cli#connect>`__.
217
262
  """
218
263
  # validate kwargs
219
264
  valid_kwargs = {
@@ -250,19 +295,45 @@ def connect(instance: str | None = None, **kwargs: Any) -> str | tuple | None:
250
295
  "No instance was connected through the CLI, pass a value to `instance` or connect via the CLI."
251
296
  )
252
297
  isettings = isettings_or_none
298
+ if _db is not None and isettings.dialect == "postgresql":
299
+ isettings._db = _db
253
300
  else:
301
+ from django.db import connection
302
+
254
303
  owner, name = get_owner_name_from_identifier(instance)
255
304
  if _check_instance_setup() and not _test:
256
305
  if (
257
306
  settings._instance_exists
258
307
  and f"{owner}/{name}" == settings.instance.slug
308
+ # below is to ensure that if another process interferes
309
+ # we don't use the in-memory mock database
310
+ # could be made more specific by checking whether the django
311
+ # configured database is the same as the one in settings
312
+ and connection.settings_dict["NAME"] != ":memory:"
259
313
  ):
260
- logger.important(f"connected lamindb: {settings.instance.slug}")
314
+ logger.important(
315
+ f"doing nothing, already connected lamindb: {settings.instance.slug}"
316
+ )
261
317
  return None
262
318
  else:
263
- raise CannotSwitchDefaultInstance(
264
- MESSAGE_CANNOT_SWITCH_DEFAULT_INSTANCE
265
- )
319
+ from lamindb_setup.core.django import reset_django
320
+
321
+ if (
322
+ settings._instance_exists
323
+ and settings.instance.slug != "none/none"
324
+ ):
325
+ import lamindb as ln
326
+
327
+ if ln.context.transform is not None:
328
+ raise CannotSwitchDefaultInstance(
329
+ "Cannot switch default instance while `ln.track()` is live: call `ln.finish()`"
330
+ )
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
+ reset_django()
266
337
  elif (
267
338
  _write_settings
268
339
  and settings._instance_exists
@@ -315,7 +386,9 @@ def connect(instance: str | None = None, **kwargs: Any) -> str | tuple | None:
315
386
  load_from_isettings(isettings, user=_user, write_settings=_write_settings)
316
387
  if _reload_lamindb:
317
388
  importlib.reload(importlib.import_module("lamindb"))
318
- logger.important(f"connected lamindb: {isettings.slug}")
389
+ reset_django_module_variables()
390
+ if isettings.slug != "none/none":
391
+ logger.important(f"connected lamindb: {isettings.slug}")
319
392
  except Exception as e:
320
393
  if isettings is not None:
321
394
  if _write_settings:
@@ -65,6 +65,9 @@ def delete(slug: str, force: bool = False, require_empty: bool = True) -> int |
65
65
  If the instance is owned by you, it suffices to pass the instance name.
66
66
  force: Whether to skip the confirmation prompt.
67
67
  require_empty: Whether to check if the instance is empty before deleting.
68
+
69
+ See Also:
70
+ Delete an instance via the CLI, see `here <https://docs.lamin.ai/cli#delete>`__.
68
71
  """
69
72
  owner, name = get_owner_name_from_identifier(slug)
70
73
  isettings = _connect_instance(owner, name, raise_permission_error=False)
@@ -8,9 +8,12 @@ from .core.cloud_sqlite_locker import clear_locker
8
8
 
9
9
 
10
10
  def disconnect(mute: bool = False) -> None:
11
- """Disconnect an instance.
11
+ """Clear default instance configuration.
12
12
 
13
13
  Returns `None` if succeeds, otherwise an exception is raised.
14
+
15
+ See Also:
16
+ Clear default instance configuration via the CLI, see `here <https://docs.lamin.ai/cli#disconnect>`__.
14
17
  """
15
18
  if current_instance_settings_file().exists():
16
19
  instance = settings.instance.slug