.oO SearXNG Developer Documentation Oo.
Loading...
Searching...
No Matches
answer.py
Go to the documentation of this file.
1# SPDX-License-Identifier: AGPL-3.0-or-later
2"""
3Typification of the *answer* results. Results of this type are rendered in
4the :origin:`answers.html <searx/templates/simple/elements/answers.html>`
5template.
6
7----
8
9.. autoclass:: BaseAnswer
10 :members:
11 :show-inheritance:
12
13.. autoclass:: Answer
14 :members:
15 :show-inheritance:
16
17.. autoclass:: Translations
18 :members:
19 :show-inheritance:
20
21.. autoclass:: WeatherAnswer
22 :members:
23 :show-inheritance:
24
25.. autoclass:: AnswerSet
26 :members:
27 :show-inheritance:
28"""
29# pylint: disable=too-few-public-methods
30
31from __future__ import annotations
32
33__all__ = ["AnswerSet", "Answer", "Translations", "WeatherAnswer"]
34
35from flask_babel import gettext
36import msgspec
37
38from searx import weather
39from ._base import Result
40
41
42class BaseAnswer(Result, kw_only=True):
43 """Base class of all answer types. It is not intended to build instances of
44 this class (aka *abstract*)."""
45
46
48 """Aggregator for :py:obj:`BaseAnswer` items in a result container."""
49
50 def __init__(self):
51 self._answerlist = []
52
53 def __len__(self):
54 return len(self._answerlist)
55
56 def __bool__(self):
57 return bool(self._answerlist)
58
59 def add(self, answer: BaseAnswer) -> None:
60 a_hash = hash(answer)
61 for i in self._answerlist:
62 if hash(i) == a_hash:
63 return
64 self._answerlist.append(answer)
65
66 def __iter__(self):
67 """Sort items in this set and iterate over the items."""
68 self._answerlist.sort(key=lambda answer: answer.template)
69 yield from self._answerlist
70
71 def __contains__(self, answer: BaseAnswer) -> bool:
72 a_hash = hash(answer)
73 for i in self._answerlist:
74 if hash(i) == a_hash:
75 return True
76 return False
77
78
79class Answer(BaseAnswer, kw_only=True):
80 """Simple answer type where the *answer* is a simple string with an optional
81 :py:obj:`url field <Result.url>` field to link a resource (article, map, ..)
82 related to the answer."""
83
84 template: str = "answer/legacy.html"
85
86 answer: str
87 """Text of the answer."""
88
89 def __hash__(self):
90 """The hash value of field *answer* is the hash value of the
91 :py:obj:`Answer` object. :py:obj:`Answer <Result.__eq__>` objects are
92 equal, when the hash values of both objects are equal."""
93 return hash(self.answer)
94
95
96class Translations(BaseAnswer, kw_only=True):
97 """Answer type with a list of translations.
98
99 The items in the list of :py:obj:`Translations.translations` are of type
100 :py:obj:`Translations.Item`:
101
102 .. code:: python
103
104 def response(resp):
105 results = []
106 ...
107 foo_1 = Translations.Item(
108 text="foobar",
109 synonyms=["bar", "foo"],
110 examples=["foo and bar are placeholders"],
111 )
112 foo_url="https://www.deepl.com/de/translator#en/de/foo"
113 ...
114 Translations(results=results, translations=[foo], url=foo_url)
115
116 """
117
118 template: str = "answer/translations.html"
119 """The template in :origin:`answer/translations.html
120 <searx/templates/simple/answer/translations.html>`"""
121
122 translations: list[Translations.Item]
123 """List of translations."""
124
125 def __post_init__(self):
126 if not self.translations:
127 raise ValueError("Translation does not have an item in the list translations")
128
129 class Item(msgspec.Struct, kw_only=True):
130 """A single element of the translations / a translation. A translation
131 consists of at least a mandatory ``text`` property (the translation) ,
132 optional properties such as *definitions*, *synonyms* and *examples* are
133 possible."""
134
135 text: str
136 """Translated text."""
137
138 transliteration: str = ""
139 """Transliteration_ of the requested translation.
140
141 .. _Transliteration: https://en.wikipedia.org/wiki/Transliteration
142 """
143
144 examples: list[str] = []
145 """List of examples for the requested translation."""
146
147 definitions: list[str] = []
148 """List of definitions for the requested translation."""
149
150 synonyms: list[str] = []
151 """List of synonyms for the requested translation."""
152
153
154class WeatherAnswer(BaseAnswer, kw_only=True):
155 """Answer type for weather data."""
156
157 template: str = "answer/weather.html"
158 """The template is located at :origin:`answer/weather.html
159 <searx/templates/simple/answer/weather.html>`"""
160
162 """Current weather at ``location``."""
163
164 forecasts: list[WeatherAnswer.Item] = []
165 """Weather forecasts for ``location``."""
166
167 service: str = ""
168 """Weather service from which this information was provided."""
169
170 class Item(msgspec.Struct, kw_only=True):
171 """Weather parameters valid for a specific point in time."""
172
174 """The geo-location the weather data is from (e.g. `Berlin, Germany`)."""
175
177 """Air temperature at 2m above the ground."""
178
179 condition: weather.WeatherConditionType
180 """Standardized designations that summarize the weather situation
181 (e.g. ``light sleet showers and thunder``)."""
182
183 # optional fields
184
185 datetime: weather.DateTime | None = None
186 """Time of the forecast - not needed for the current weather."""
187
188 summary: str | None = None
189 """One-liner about the weather forecast / current weather conditions.
190 If unset, a summary is build up from temperature and current weather
191 conditions.
192 """
193
194 feels_like: weather.Temperature | None = None
195 """Apparent temperature, the temperature equivalent perceived by
196 humans, caused by the combined effects of air temperature, relative
197 humidity and wind speed. The measure is most commonly applied to the
198 perceived outdoor temperature.
199 """
200
201 pressure: weather.Pressure | None = None
202 """Air pressure at sea level (e.g. 1030 hPa) """
203
204 humidity: weather.RelativeHumidity | None = None
205 """Amount of relative humidity in the air at 2m above the ground. The
206 unit is ``%``, e.g. 60%)
207 """
208
210 """The directon which moves towards / direction the wind is coming from."""
211
212 wind_speed: weather.WindSpeed | None = None
213 """Speed of wind / wind speed at 10m above the ground (10 min average)."""
214
215 cloud_cover: int | None = None
216 """Amount of sky covered by clouds / total cloud cover for all heights
217 (cloudiness, unit: %)"""
218
219 # attributes: dict[str, str | int] = {}
220 # """Key-Value dict of additional typeless weather attributes."""
221
222 def __post_init__(self):
223 if not self.summary:
224 self.summary = gettext("{location}: {temperature}, {condition}").format(
225 location=self.location,
226 temperature=self.temperature,
227 condition=gettext(self.condition.capitalize()),
228 )
229
230 @property
231 def url(self) -> str | None:
232 """Determines a `data URL`_ with a symbol for the weather
233 conditions. If no symbol can be assigned, ``None`` is returned.
234
235 .. _data URL:
236 https://developer.mozilla.org/en-US/docs/Web/URI/Reference/Schemes/data
237 """
238 return weather.symbol_url(self.condition)
None add(self, BaseAnswer answer)
Definition answer.py:59
bool __contains__(self, BaseAnswer answer)
Definition answer.py:71