[fix] clarify the mess of Engine.setup and Engine.init (#6343)

Signed-off-by: Markus Heiser <markus.heiser@darmarit.de>
This commit is contained in:
Markus Heiser
2026-06-30 19:22:23 +02:00
committed by GitHub
parent c5b1d066e5
commit d115c61a70
4 changed files with 52 additions and 28 deletions

View File

@@ -361,37 +361,43 @@ class Engine(abc.ABC): # pylint: disable=too-few-public-methods
https: socks5://proxy:port
"""
def setup(self, engine_settings: dict[str, t.Any]) -> bool: # pylint: disable=unused-argument
def setup(self, engine_settings: dict[str, t.Any]) -> bool | None: # pylint: disable=unused-argument
"""Dynamic setup of the engine settings.
With this method, the engine's setup is carried out. For example, to
check or dynamically adapt the values handed over in the parameter
``engine_settings``. The return value (True/False) indicates whether
the setup was successful and the engine can be built or rejected.
``engine_settings``.
The method is optional and is called synchronously as part of the
Whether the initialization was successful can be indicated by the return
value ``True`` or even ``False``.
- If no return value (``None`` ) is given from this method , this is
equivalent to ``True``.
- If an exception is thrown as part of the initialization, this is
equivalent to ``False``.
The method is optional and is called **synchronously** as part of the
initialization of the service and is therefore only suitable for simple
(local) exams/changes at the engine setting. The :py:obj:`Engine.init`
method must be used for longer tasks in which values of a remote must be
determined, for example.
(local) exams/changes at the engine setting.
The :py:obj:`Engine.init` method must be used for longer tasks in which
values of a remote must be determined, for example.
"""
return True
def init(self, engine_settings: dict[str, t.Any]) -> bool | None: # pylint: disable=unused-argument
"""Initialization of the engine.
The method is optional and asynchronous (in a thread). It is suitable,
for example, for setting up a cache (for the engine) or for querying
values (required by the engine) from a remote.
The method is optional and called **asynchronous** (in a thread). The
method is comparable to :py:obj:`Engine.setup`, it is suitable, for
caching data that first needs to be requested from a remote.
Whether the initialization was successful can be indicated by the return
value ``True`` or even ``False``.
The method is optional and runs **asynchronously** (in a thread), it is
comparable to :py:obj:`Engine.setup`. For instance, it is suitable for
caching data that first needs to be requested from a remote source.
- If no return value is given from this init method (``None``), this is
equivalent to ``True``.
- If an exception is thrown as part of the initialization, this is
equivalent to ``False``.
The evaluation of the return value is analogous to :py:obj:`Engine.setup`.
"""
return True

View File

@@ -269,21 +269,27 @@ def is_engine_active(engine: "Engine | types.ModuleType"):
def call_engine_setup(engine: "Engine | types.ModuleType", engine_data: dict[str, t.Any]) -> bool:
setup_ok = False
setup_ok: bool | None = False
setup_func = getattr(engine, "setup", None)
if setup_func is None:
setup_ok = True
elif not callable(setup_func):
logger.error("engine's setup method isn't a callable (is of type: %s)", type(setup_func))
logger.error(f"engine's setup method isn't a callable (is of type: {type(setup_func)})")
else:
try:
setup_ok = engine.setup(engine_data)
except Exception as e: # pylint: disable=broad-except
logger.exception('exception : {0}'.format(e))
logger.exception(f"(PID {os.getpid()}) {engine.name}: engine SETUP failed, exception: {e}")
setup_ok = False
# The evaluation of the return value is analogous to Engine.init
if setup_ok is None:
setup_ok = True
if not setup_ok:
logger.error("%s: Engine setup was not successful, engine is set to inactive.", engine.name)
logger.error(f"(PID {os.getpid()}) {engine.name}: engine setup was not successful")
return setup_ok
@@ -311,14 +317,16 @@ def load_engines(engine_list: list[dict[str, t.Any]]):
for engine_data in engine_list:
if engine_data.get("inactive") is True:
continue
engine = load_engine(engine_data)
if engine:
register_engine(engine)
else:
# if an engine can't be loaded (if for example the engine is missing
# tor or some other requirements) its set to inactive!
logger.error(
f"(PID {os.getpid()}) loading engine %s failed: set engine to inactive!", engine_data.get("name", "???")
f"(PID {os.getpid()}) {engine_data.get('name', '???')}: can't register engine (loading engine failed)"
)
engine_data["inactive"] = True
return engines

View File

@@ -16,6 +16,7 @@ __all__ = [
import typing as t
import os
from searx import logger
from searx import engines
@@ -92,7 +93,9 @@ class ProcessorMap(dict[str, EngineProcessor]):
self[eng_proc.engine.name] = eng_proc
# logger.debug("registered engine processor: %s", eng_proc.engine.name)
else:
logger.error("can't register engine processor: %s (init failed)", eng_proc.engine.name)
logger.error(
f"(PID {os.getpid()}) {eng_proc.engine.name}: can't register engines processor (init engine failed)"
)
return eng_proc_ok

View File

@@ -150,19 +150,26 @@ class EngineProcessor(ABC):
threading.Thread(target=__init_processor_thread, daemon=True).start()
def init_engine(self) -> bool:
eng_setting = get_engine_from_settings(self.engine.name)
init_ok: bool | None = False
try:
init_ok = self.engine.init(eng_setting)
except Exception: # pylint: disable=broad-except
logger.exception(
f"(PID {os.getpid()}) Init method of engine %s failed due to an exception.", self.engine.name
)
except Exception as e: # pylint: disable=broad-except
logger.exception(f"(PID {os.getpid()}) {self.engine.name}: engine INIT failed, exception: {e}")
init_ok = False
# In older engines, None is returned from the init method, which is
# equivalent to indicating that the initialization was successful.
# equivalent to indicating that the initialization was successful
# (compare: Engine.setup).
if init_ok is None:
init_ok = True
if not init_ok:
logger.error(f"(PID {os.getpid()}) {self.engine.name}: engine init was not successful")
return init_ok
def handle_exception(