11from dataclasses
import dataclass
17_default = pathlib.Path(__file__).parent
18log: logging.Logger = logging.getLogger(
"searx.answerers")
23 """Object that holds information about an answerer, these infos are shown
24 to the user in the Preferences menu.
26 To be able to translate the information into other languages, the text must
27 be written in English and translated with :py:obj:`flask_babel.gettext`.
31 """Name of the *answerer*."""
34 """Short description of the *answerer*."""
37 """List of short examples of the usage / of query terms."""
40 """See :py:obj:`Answerer.keywords`"""
44 """Abstract base class of answerers."""
47 """Keywords to which the answerer has *answers*."""
50 def answer(self, query: str) -> list[BaseAnswer]:
51 """Function that returns a list of answers to the question/query."""
54 def info(self) -> AnswererInfo:
55 """Information about the *answerer*, see :py:obj:`AnswererInfo`."""
58class ModuleAnswerer(Answerer):
59 """A wrapper class for legacy *answerers* where the names (keywords, answer,
60 info) are implemented on the module level (not in a class).
64 For internal use only!
69 for name
in [
"keywords",
"self_info",
"answer"]:
70 if not getattr(mod, name,
None):
72 if not isinstance(mod.keywords, tuple):
78 def answer(self, query: str) -> list[BaseAnswer]:
81 def info(self) -> AnswererInfo:
82 kwargs = self.
module.self_info()
88 """A storage for managing the *answerers* of SearXNG. With the
89 :py:obj:`AnswerStorage.ask`” method, a caller can ask questions to all
90 *answerers* and receives a list of the results."""
92 answerer_list: set[Answerer]
93 """The list of :py:obj:`Answerer` in this storage."""
100 """Loads ``answerer.py`` modules from the python packages in
101 :origin:`searx/answerers`. The python modules are wrapped by
102 :py:obj:`ModuleAnswerer`."""
104 for f
in _default.iterdir():
105 if f.name.startswith(
"_"):
108 if f.is_file()
and f.suffix ==
".py":
114 if f.is_dir()
and (f /
"answerer.py").exists():
116 f
"answerer module {f} is deprecated / migrate to searx.answerers.Answerer", DeprecationWarning
118 mod = load_module(
"answerer.py", str(f))
122 """Register a :py:obj:`Answerer` via its fully qualified class namen(FQN)."""
124 mod_name, _, obj_name = fqn.rpartition(
'.')
125 mod = importlib.import_module(mod_name)
126 code_obj = getattr(mod, obj_name,
None)
129 msg = f
"answerer {fqn} is not implemented"
131 raise ValueError(msg)
136 """Register a :py:obj:`Answerer`."""
139 for _kw
in answerer.keywords:
140 self[_kw] = self.get(_kw, [])
141 self[_kw].append(answerer)
143 def ask(self, query: str) -> list[BaseAnswer]:
144 """An answerer is identified via keywords, if there is a keyword at the
145 first position in the ``query`` for which there is one or more
146 answerers, then these are called, whereby the entire ``query`` is passed
147 as argument to the answerer function."""
151 for keyword
in query.split():
155 if not keyword
or keyword
not in self:
158 for answerer
in self[keyword]:
159 for answer
in answerer.answer(query):
161 answer.engine = f
"answerer: {keyword}"
162 results.append(answer)
167 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)