.oO SearXNG Developer Documentation Oo.
Loading...
Searching...
No Matches
searx.plugins.unit_converter Namespace Reference

Functions

 symbol_to_si ()
 
str|None _parse_text_and_convert (from_query, to_query)
 
list[Answerpost_search (_request, search)
 

Variables

str name = "Unit converter plugin"
 
 description = gettext("Convert between units")
 
bool default_on = True
 
str plugin_id = "unit_converter"
 
str preference_section = "general"
 
list CONVERT_KEYWORDS = ["in", "to", "as"]
 
str RE_MEASURE
 
list ADDITIONAL_UNITS
 
dict ALIAS_SYMBOLS
 
list SYMBOL_TO_SI = []
 

Detailed Description

A plugin for converting measured values from one unit to another unit (a
unit converter).

The plugin looks up the symbols (given in the query term) in a list of
converters, each converter is one item in the list (compare
:py:obj:`ADDITIONAL_UNITS`).  If the symbols are ambiguous, the matching units
of measurement are evaluated.  The weighting in the evaluation results from the
sorting of the :py:obj:`list of unit converters<symbol_to_si>`.

Enable in ``settings.yml``:

.. code:: yaml

  enabled_plugins:
    ..
    - 'Unit converter plugin'

Function Documentation

◆ _parse_text_and_convert()

str | None searx.plugins.unit_converter._parse_text_and_convert ( from_query,
to_query )
protected

Definition at line 177 of file unit_converter.py.

177def _parse_text_and_convert(from_query, to_query) -> str | None:
178
179 # pylint: disable=too-many-branches, too-many-locals
180
181 if not (from_query and to_query):
182 return None
183
184 measured = re.match(RE_MEASURE, from_query, re.VERBOSE)
185 if not (measured and measured.group('number'), measured.group('unit')):
186 return None
187
188 # Symbols are not unique, if there are several hits for the from-unit, then
189 # the correct one must be determined by comparing it with the to-unit
190 # https://github.com/searxng/searxng/pull/3378#issuecomment-2080974863
191
192 # first: collecting possible units
193
194 source_list, target_list = [], []
195
196 for symbol, si_name, from_si, to_si, orig_symbol in symbol_to_si():
197
198 if symbol == measured.group('unit'):
199 source_list.append((si_name, to_si))
200 if symbol == to_query:
201 target_list.append((si_name, from_si, orig_symbol))
202
203 if not (source_list and target_list):
204 return None
205
206 source_to_si = target_from_si = target_symbol = None
207
208 # second: find the right unit by comparing list of from-units with list of to-units
209
210 for source in source_list:
211 for target in target_list:
212 if source[0] == target[0]: # compare si_name
213 source_to_si = source[1]
214 target_from_si = target[1]
215 target_symbol = target[2]
216
217 if not (source_to_si and target_from_si):
218 return None
219
220 _locale = get_locale() or 'en_US'
221
222 value = measured.group('sign') + measured.group('number') + (measured.group('E') or '')
223 value = babel.numbers.parse_decimal(value, locale=_locale)
224
225 # convert value to SI unit
226
227 if isinstance(source_to_si, (float, int)):
228 value = float(value) * source_to_si
229 else:
230 value = source_to_si(float(value))
231
232 # convert value from SI unit to target unit
233
234 if isinstance(target_from_si, (float, int)):
235 value = float(value) * target_from_si
236 else:
237 value = target_from_si(float(value))
238
239 if measured.group('E'):
240 # when incoming notation is scientific, outgoing notation is scientific
241 result = babel.numbers.format_scientific(value, locale=_locale)
242 else:
243 result = babel.numbers.format_decimal(value, locale=_locale, format='#,##0.##########;-#')
244
245 return f'{result} {target_symbol}'
246
247

References symbol_to_si().

Referenced by post_search().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ post_search()

list[Answer] searx.plugins.unit_converter.post_search ( _request,
search )

Definition at line 248 of file unit_converter.py.

248def post_search(_request, search) -> list[Answer]:
249 results = []
250
251 # only convert between units on the first page
252 if search.search_query.pageno > 1:
253 return results
254
255 query = search.search_query.query
256 query_parts = query.split(" ")
257
258 if len(query_parts) < 3:
259 return results
260
261 for query_part in query_parts:
262 for keyword in CONVERT_KEYWORDS:
263 if query_part == keyword:
264 from_query, to_query = query.split(keyword, 1)
265 target_val = _parse_text_and_convert(from_query.strip(), to_query.strip())
266 if target_val:
267 Answer(results=results, answer=target_val)
268
269 return results

References _parse_text_and_convert().

+ Here is the call graph for this function:

◆ symbol_to_si()

searx.plugins.unit_converter.symbol_to_si ( )
Generates a list of tuples, each tuple is a measure unit and the fields
in the tuple are:

0. Symbol of the measure unit (e.g. 'mi' for measure unit 'miles' Q253276)

1. SI name of the measure unit (e.g. Q11573 for SI unit 'metre')

2. Factor to get SI value from measure unit (e.g. 1mi is equal to SI 1m
   multiplied by 1609.344)

3. Factor to get measure value from from SI value (e.g. SI 100m is equal to
   100mi divided by 1609.344)

The returned list is sorted, the first items are created from
``WIKIDATA_UNITS``, the second group of items is build from
:py:obj:`ADDITIONAL_UNITS` and items created from :py:obj:`ALIAS_SYMBOLS`.

If you search this list for a symbol, then a match with a symbol from
Wikidata has the highest weighting (first hit in the list), followed by the
symbols from the :py:obj:`ADDITIONAL_UNITS` and the lowest weighting is
given to the symbols resulting from the aliases :py:obj:`ALIAS_SYMBOLS`.

Definition at line 105 of file unit_converter.py.

105def symbol_to_si():
106 """Generates a list of tuples, each tuple is a measure unit and the fields
107 in the tuple are:
108
109 0. Symbol of the measure unit (e.g. 'mi' for measure unit 'miles' Q253276)
110
111 1. SI name of the measure unit (e.g. Q11573 for SI unit 'metre')
112
113 2. Factor to get SI value from measure unit (e.g. 1mi is equal to SI 1m
114 multiplied by 1609.344)
115
116 3. Factor to get measure value from from SI value (e.g. SI 100m is equal to
117 100mi divided by 1609.344)
118
119 The returned list is sorted, the first items are created from
120 ``WIKIDATA_UNITS``, the second group of items is build from
121 :py:obj:`ADDITIONAL_UNITS` and items created from :py:obj:`ALIAS_SYMBOLS`.
122
123 If you search this list for a symbol, then a match with a symbol from
124 Wikidata has the highest weighting (first hit in the list), followed by the
125 symbols from the :py:obj:`ADDITIONAL_UNITS` and the lowest weighting is
126 given to the symbols resulting from the aliases :py:obj:`ALIAS_SYMBOLS`.
127
128 """
129
130 global SYMBOL_TO_SI # pylint: disable=global-statement
131 if SYMBOL_TO_SI:
132 return SYMBOL_TO_SI
133
134 # filter out units which can't be normalized to a SI unit and filter out
135 # units without a symbol / arcsecond does not have a symbol
136 # https://www.wikidata.org/wiki/Q829073
137
138 for item in data.WIKIDATA_UNITS.values():
139 if item['to_si_factor'] and item['symbol']:
140 SYMBOL_TO_SI.append(
141 (
142 item['symbol'],
143 item['si_name'],
144 1 / item['to_si_factor'], # from_si
145 item['to_si_factor'], # to_si
146 item['symbol'],
147 )
148 )
149
150 for item in ADDITIONAL_UNITS:
151 SYMBOL_TO_SI.append(
152 (
153 item['symbol'],
154 item['si_name'],
155 item['from_si'],
156 item['to_si'],
157 item['symbol'],
158 )
159 )
160
161 alias_items = []
162 for item in SYMBOL_TO_SI:
163 for alias in ALIAS_SYMBOLS.get(item[0], ()):
164 alias_items.append(
165 (
166 alias,
167 item[1],
168 item[2], # from_si
169 item[3], # to_si
170 item[0], # origin unit
171 )
172 )
173 SYMBOL_TO_SI = SYMBOL_TO_SI + alias_items
174 return SYMBOL_TO_SI
175
176

Referenced by _parse_text_and_convert().

+ Here is the caller graph for this function:

Variable Documentation

◆ ADDITIONAL_UNITS

list searx.plugins.unit_converter.ADDITIONAL_UNITS
Initial value:
1= [
2 {
3 "si_name": "Q11579",
4 "symbol": "°C",
5 "to_si": lambda val: val + 273.15,
6 "from_si": lambda val: val - 273.15,
7 },
8 {
9 "si_name": "Q11579",
10 "symbol": "°F",
11 "to_si": lambda val: (val + 459.67) * 5 / 9,
12 "from_si": lambda val: (val * 9 / 5) - 459.67,
13 },
14]

Definition at line 51 of file unit_converter.py.

◆ ALIAS_SYMBOLS

dict searx.plugins.unit_converter.ALIAS_SYMBOLS
Initial value:
1= {
2 '°C': ('C',),
3 '°F': ('F',),
4 'mi': ('L',),
5}

Definition at line 89 of file unit_converter.py.

◆ CONVERT_KEYWORDS

list searx.plugins.unit_converter.CONVERT_KEYWORDS = ["in", "to", "as"]

Definition at line 38 of file unit_converter.py.

◆ default_on

bool searx.plugins.unit_converter.default_on = True

Definition at line 33 of file unit_converter.py.

◆ description

searx.plugins.unit_converter.description = gettext("Convert between units")

Definition at line 32 of file unit_converter.py.

◆ name

str searx.plugins.unit_converter.name = "Unit converter plugin"

Definition at line 31 of file unit_converter.py.

◆ plugin_id

str searx.plugins.unit_converter.plugin_id = "unit_converter"

Definition at line 35 of file unit_converter.py.

◆ preference_section

str searx.plugins.unit_converter.preference_section = "general"

Definition at line 36 of file unit_converter.py.

◆ RE_MEASURE

str searx.plugins.unit_converter.RE_MEASURE
Initial value:
1= r'''
2(?P<sign>[-+]?) # +/- or nothing for positive
3(\s*) # separator: white space or nothing
4(?P<number>[\d\.,]*) # number: 1,000.00 (en) or 1.000,00 (de)
5(?P<E>[eE][-+]?\d+)? # scientific notation: e(+/-)2 (*10^2)
6(\s*) # separator: white space or nothing
7(?P<unit>\S+) # unit of measure
8'''

Definition at line 41 of file unit_converter.py.

◆ SYMBOL_TO_SI

list searx.plugins.unit_converter.SYMBOL_TO_SI = []

Definition at line 102 of file unit_converter.py.