From ab824911584683577e5d4b2c2e83d06cd79601c6 Mon Sep 17 00:00:00 2001 From: Koncopd Date: Thu, 16 Jan 2025 21:27:56 +0100 Subject: [PATCH 1/5] check modules --- lamindb_setup/_check_setup.py | 47 ++++++++++++++++++++---- lamindb_setup/_connect_instance.py | 3 +- lamindb_setup/core/_settings_instance.py | 20 ++++------ 3 files changed, 49 insertions(+), 21 deletions(-) diff --git a/lamindb_setup/_check_setup.py b/lamindb_setup/_check_setup.py index b341b4f2..e8e465e2 100644 --- a/lamindb_setup/_check_setup.py +++ b/lamindb_setup/_check_setup.py @@ -2,13 +2,14 @@ import functools import importlib as il +import inspect import os from typing import TYPE_CHECKING from lamin_utils import logger from ._silence_loggers import silence_loggers -from .core import django +from .core import django as django_lamin from .core._settings import settings from .core._settings_store import current_instance_settings_file from .core.exceptions import DefaultMessageException @@ -70,14 +71,42 @@ def _get_current_instance_settings() -> InstanceSettings | None: return None +def _check_in_modules(module: str, isettings: InstanceSettings | None = None) -> None: + not_in_instance_msg = f"'{module}' is missing from this instance." + + if isettings is not None and module not in isettings.modules: + raise RuntimeError(not_in_instance_msg) + + from django.apps import apps + + for app in apps.get_app_configs(): + if module == app.name: + return + raise RuntimeError(not_in_instance_msg) + + +def _module_name() -> str | None: + stack = inspect.stack() + if len(stack) < 3: + return None + module = inspect.getmodule(stack[2][0]) + return module.__name__ if module is not None else None + + # we make this a private function because in all the places it's used, # users should not see it def _check_instance_setup(from_module: str | None = None) -> bool: - if django.IS_SETUP: + if django_lamin.IS_SETUP: # reload logic here because module might not yet have been imported # upon first setup - if from_module is not None and from_module != "lamindb": - il.reload(il.import_module(from_module)) + if from_module is not None: + if from_module != "lamindb": + _check_in_modules(from_module) + il.reload(il.import_module(from_module)) + else: + from_module = _module_name() + if from_module != "lamindb": + _check_in_modules(from_module) # type: ignore return True silence_loggers() if os.environ.get("LAMINDB_MULTI_INSTANCE") == "true": @@ -91,17 +120,19 @@ def _check_instance_setup(from_module: str | None = None) -> bool: if ( from_module is not None and settings.auto_connect - and not django.IS_SETUP + and not django_lamin.IS_SETUP and not IS_LOADING ): - if not from_module == "lamindb": + if from_module != "lamindb": + _check_in_modules(from_module, isettings) + import lamindb il.reload(il.import_module(from_module)) else: - django.setup_django(isettings) + django_lamin.setup_django(isettings) logger.important(f"connected lamindb: {isettings.slug}") - return django.IS_SETUP + return django_lamin.IS_SETUP else: if from_module is not None and settings.auto_connect: logger.warning(InstanceNotSetupError.default_message) diff --git a/lamindb_setup/_connect_instance.py b/lamindb_setup/_connect_instance.py index 822fb9f9..eb3398b6 100644 --- a/lamindb_setup/_connect_instance.py +++ b/lamindb_setup/_connect_instance.py @@ -311,7 +311,8 @@ def connect(instance: str | None = None, **kwargs) -> str | tuple | None: load_from_isettings(isettings, user=_user, write_settings=_write_settings) if _reload_lamindb: importlib.reload(importlib.import_module("lamindb")) - logger.important(f"connected lamindb: {isettings.slug}") + else: + logger.important(f"connected lamindb: {isettings.slug}") except Exception as e: if isettings is not None: if _write_settings: diff --git a/lamindb_setup/core/_settings_instance.py b/lamindb_setup/core/_settings_instance.py index b30aaede..631767e7 100644 --- a/lamindb_setup/core/_settings_instance.py +++ b/lamindb_setup/core/_settings_instance.py @@ -466,13 +466,11 @@ def _persist(self, write_to_disk: bool = True) -> None: settings._instance_settings = self def _init_db(self): - from lamindb_setup import _check_setup + from lamindb_setup._check_setup import _loading from .django import setup_django - _check_setup.IS_LOADING = True - setup_django(self, init=True) - _check_setup.IS_LOADING = False + _loading(setup_django)(self, init=True) from lamindb.models import Space @@ -482,8 +480,6 @@ def _init_db(self): ) def _load_db(self) -> tuple[bool, str]: - from lamindb_setup import _check_setup - # Is the database available and initialized as LaminDB? # returns a tuple of status code and message if self.dialect == "sqlite" and not self._sqlite_file.exists(): @@ -494,15 +490,15 @@ def _load_db(self) -> tuple[bool, str]: f" {legacy_file} to {self._sqlite_file}" ) return False, f"SQLite file {self._sqlite_file} does not exist" - - from .django import setup_django - # we need the local sqlite to setup django self._update_local_sqlite_file(lock_cloud_sqlite=self._is_cloud_sqlite) # setting up django also performs a check for migrations & prints them # as warnings # this should fail, e.g., if the db is not reachable - _check_setup.IS_LOADING = True - setup_django(self) - _check_setup.IS_LOADING = False + from lamindb_setup._check_setup import _loading + + from .django import setup_django + + _loading(setup_django)(self) + return True, "" From 027e3ec24d080599254d050cb2e4aa9ae527a67b Mon Sep 17 00:00:00 2001 From: Koncopd Date: Thu, 16 Jan 2025 21:52:38 +0100 Subject: [PATCH 2/5] fix --- lamindb_setup/_check_setup.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/lamindb_setup/_check_setup.py b/lamindb_setup/_check_setup.py index e8e465e2..0ca62a5d 100644 --- a/lamindb_setup/_check_setup.py +++ b/lamindb_setup/_check_setup.py @@ -90,7 +90,7 @@ def _module_name() -> str | None: if len(stack) < 3: return None module = inspect.getmodule(stack[2][0]) - return module.__name__ if module is not None else None + return module.__name__.partition(".")[0] if module is not None else None # we make this a private function because in all the places it's used, @@ -104,9 +104,12 @@ def _check_instance_setup(from_module: str | None = None) -> bool: _check_in_modules(from_module) il.reload(il.import_module(from_module)) else: - from_module = _module_name() - if from_module != "lamindb": - _check_in_modules(from_module) # type: ignore + infer_module = _module_name() + if infer_module is not None and infer_module not in { + "lamindb", + "lamindb_setup", + }: + _check_in_modules(infer_module) return True silence_loggers() if os.environ.get("LAMINDB_MULTI_INSTANCE") == "true": From dd09b24a1ce179693edf36c9f5c5f04170cc8bad Mon Sep 17 00:00:00 2001 From: Koncopd Date: Thu, 16 Jan 2025 22:03:53 +0100 Subject: [PATCH 3/5] fix --- lamindb_setup/_check_setup.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lamindb_setup/_check_setup.py b/lamindb_setup/_check_setup.py index 0ca62a5d..9d151490 100644 --- a/lamindb_setup/_check_setup.py +++ b/lamindb_setup/_check_setup.py @@ -74,8 +74,11 @@ def _get_current_instance_settings() -> InstanceSettings | None: def _check_in_modules(module: str, isettings: InstanceSettings | None = None) -> None: not_in_instance_msg = f"'{module}' is missing from this instance." - if isettings is not None and module not in isettings.modules: - raise RuntimeError(not_in_instance_msg) + if isettings is not None: + if module not in isettings.modules: + raise RuntimeError(not_in_instance_msg) + else: + return from django.apps import apps From 0950756df149c8bc9c3dcff5cf2a0d8cbfede6c5 Mon Sep 17 00:00:00 2001 From: Koncopd Date: Fri, 17 Jan 2025 13:55:40 +0100 Subject: [PATCH 4/5] refactor --- lamindb_setup/_check_setup.py | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/lamindb_setup/_check_setup.py b/lamindb_setup/_check_setup.py index 9d151490..bfc8c253 100644 --- a/lamindb_setup/_check_setup.py +++ b/lamindb_setup/_check_setup.py @@ -34,6 +34,10 @@ class InstanceNotSetupError(DefaultMessageException): IS_LOADING: bool = False +class ModuleWasntConfigured(RuntimeError): + pass + + # decorator to disable auto-connect when importing a module such as lamindb def _loading(func: Callable): @functools.wraps(func) @@ -71,12 +75,16 @@ def _get_current_instance_settings() -> InstanceSettings | None: return None -def _check_in_modules(module: str, isettings: InstanceSettings | None = None) -> None: +# checks that the provided modules is in the modules of the provided instance +# or in the apps setup by django +def _check_module_in_instance_modules( + module: str, isettings: InstanceSettings | None = None +) -> None: not_in_instance_msg = f"'{module}' is missing from this instance." if isettings is not None: if module not in isettings.modules: - raise RuntimeError(not_in_instance_msg) + raise ModuleWasntConfigured(not_in_instance_msg) else: return @@ -85,10 +93,11 @@ def _check_in_modules(module: str, isettings: InstanceSettings | None = None) -> for app in apps.get_app_configs(): if module == app.name: return - raise RuntimeError(not_in_instance_msg) + raise ModuleWasntConfigured(not_in_instance_msg) -def _module_name() -> str | None: +# infer the name of the module that calls this function +def _infer_callers_module_name() -> str | None: stack = inspect.stack() if len(stack) < 3: return None @@ -104,15 +113,15 @@ def _check_instance_setup(from_module: str | None = None) -> bool: # upon first setup if from_module is not None: if from_module != "lamindb": - _check_in_modules(from_module) + _check_module_in_instance_modules(from_module) il.reload(il.import_module(from_module)) else: - infer_module = _module_name() + infer_module = _infer_callers_module_name() if infer_module is not None and infer_module not in { "lamindb", "lamindb_setup", }: - _check_in_modules(infer_module) + _check_module_in_instance_modules(infer_module) return True silence_loggers() if os.environ.get("LAMINDB_MULTI_INSTANCE") == "true": @@ -130,7 +139,7 @@ def _check_instance_setup(from_module: str | None = None) -> bool: and not IS_LOADING ): if from_module != "lamindb": - _check_in_modules(from_module, isettings) + _check_module_in_instance_modules(from_module, isettings) import lamindb From e0824f65ac5fa8a66b51dc46cd2aeddf12d5a7b1 Mon Sep 17 00:00:00 2001 From: Koncopd Date: Fri, 17 Jan 2025 14:02:58 +0100 Subject: [PATCH 5/5] msg --- lamindb_setup/_check_setup.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lamindb_setup/_check_setup.py b/lamindb_setup/_check_setup.py index bfc8c253..1d4f2836 100644 --- a/lamindb_setup/_check_setup.py +++ b/lamindb_setup/_check_setup.py @@ -80,7 +80,10 @@ def _get_current_instance_settings() -> InstanceSettings | None: def _check_module_in_instance_modules( module: str, isettings: InstanceSettings | None = None ) -> None: - not_in_instance_msg = f"'{module}' is missing from this instance." + not_in_instance_msg = ( + f"'{module}' is missing from this instance. " + "Please go to your instance settings page and add it under 'schema modules'." + ) if isettings is not None: if module not in isettings.modules: