4from __future__
import annotations
12from dataclasses
import dataclass
18_default = pathlib.Path(__file__).parent
19log: logging.Logger = logging.getLogger(
"searx.answerers")
24 """Object that holds informations about an answerer, these infos are shown
25 to the user in the Preferences menu.
27 To be able to translate the information into other languages, the text must
28 be written in English and translated with :py:obj:`flask_babel.gettext`.
32 """Name of the *answerer*."""
35 """Short description of the *answerer*."""
38 """List of short examples of the usage / of query terms."""
41 """See :py:obj:`Answerer.keywords`"""
45 """Abstract base class of answerers."""
48 """Keywords to which the answerer has *answers*."""
51 def answer(self, query: str) -> list[BaseAnswer]:
52 """Function that returns a list of answers to the question/query."""
55 def info(self) -> AnswererInfo:
56 """Informations about the *answerer*, see :py:obj:`AnswererInfo`."""
59class ModuleAnswerer(Answerer):
60 """A wrapper class for legacy *answerers* where the names (keywords, answer,
61 info) are implemented on the module level (not in a class).
65 For internal use only!
70 for name
in [
"keywords",
"self_info",
"answer"]:
71 if not getattr(mod, name,
None):
73 if not isinstance(mod.keywords, tuple):
79 def answer(self, query: str) -> list[BaseAnswer]:
82 def info(self) -> AnswererInfo:
83 kwargs = self.
module.self_info()
89 """A storage for managing the *answerers* of SearXNG. With the
90 :py:obj:`AnswerStorage.ask`” method, a caller can ask questions to all
91 *answerers* and receives a list of the results."""
93 answerer_list: set[Answerer]
94 """The list of :py:obj:`Answerer` in this storage."""
101 """Loads ``answerer.py`` modules from the python packages in
102 :origin:`searx/answerers`. The python modules are wrapped by
103 :py:obj:`ModuleAnswerer`."""
105 for f
in _default.iterdir():
106 if f.name.startswith(
"_"):
109 if f.is_file()
and f.suffix ==
".py":
115 if f.is_dir()
and (f /
"answerer.py").exists():
117 f
"answerer module {f} is deprecated / migrate to searx.answerers.Answerer", DeprecationWarning
119 mod = load_module(
"answerer.py", str(f))
123 """Register a :py:obj:`Answerer` via its fully qualified class namen(FQN)."""
125 mod_name, _, obj_name = fqn.rpartition(
'.')
126 mod = importlib.import_module(mod_name)
127 code_obj = getattr(mod, obj_name,
None)
130 msg = f
"answerer {fqn} is not implemented"
132 raise ValueError(msg)
137 """Register a :py:obj:`Answerer`."""
140 for _kw
in answerer.keywords:
141 self[_kw] = self.get(_kw, [])
142 self[_kw].append(answerer)
144 def ask(self, query: str) -> list[BaseAnswer]:
145 """An answerer is identified via keywords, if there is a keyword at the
146 first position in the ``query`` for which there is one or more
147 answerers, then these are called, whereby the entire ``query`` is passed
148 as argument to the answerer function."""
152 for keyword
in query.split():
156 if not keyword
or keyword
not in self:
159 for answerer
in self[keyword]:
160 for answer
in answerer.answer(query):
162 answer.engine = f
"answerer: {keyword}"
163 results.append(answer)
168 def info(self) -> list[AnswererInfo]:
register_by_fqn(self, str fqn)
register(self, Answerer answerer)
list[AnswererInfo] info(self)
list[BaseAnswer] ask(self, str query)
list[BaseAnswer] answer(self, str query)
list[BaseAnswer] answer(self, str query)