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