2"""Unit conversion on the basis of `SPARQL/WIKIDATA Precision, Units and
5.. _SPARQL/WIKIDATA Precision, Units and Coordinates:
6 https://en.wikibooks.org/wiki/SPARQL/WIKIDATA_Precision,_Units_and_Coordinates#Quantities
9__all__ = [
"convert_from_si",
"convert_to_si",
"symbol_to_si"]
18 """The mapping of the Beaufort_ contains values from 0 to 16 (55.6 m/s),
19 wind speeds greater than 200km/h (55.6 m/s) are given as 17 Bft. Thats why
20 a value of 17 Bft cannot be converted to SI.
24 Negative values or values greater 16 Bft (55.6 m/s) will throw a
27 _Beaufort: https://en.wikipedia.org/wiki/Beaufort_scale
31 scale: list[float] = [
32 0.2, 1.5, 3.3, 5.4, 7.9,
33 10.7, 13.8, 17.1, 20.7, 24.4,
34 28.4, 32.6, 32.7, 41.1, 45.8,
41 if value < 0
or value > 55.6:
42 raise ValueError(f
"invalid value {value} / the Beaufort scales from 0 to 16 (55.6 m/s)")
44 for bft, mps
in enumerate(cls.
scale):
52 if idx < 0
or idx > 16:
53 raise ValueError(f
"invalid value {value} / the Beaufort scales from 0 to 16 (55.6 m/s)")
61 "to_si":
lambda val: val + 273.15,
62 "from_si":
lambda val: val - 273.15,
67 "to_si":
lambda val: (val + 459.67) * 5 / 9,
68 "from_si":
lambda val: (val * 9 / 5) - 459.67,
73 "to_si": Beaufort.to_si,
74 "from_si": Beaufort.from_si,
77"""Additional items to convert from a measure unit to a SI unit (vice versa).
82 "si_name": "Q11579", # Wikidata item ID of the SI unit (Kelvin)
83 "symbol": "°C", # symbol of the measure unit
84 "to_si": lambda val: val + 273.15, # convert measure value (val) to SI unit
85 "from_si": lambda val: val - 273.15, # convert SI value (val) measure unit
90 "to_si": 1609.344, # convert measure value (val) to SI unit
91 "from_si": 1 / 1609.344 # convert SI value (val) measure unit
94The values of ``to_si`` and ``from_si`` can be of :py:obj:`float` (a multiplier)
95or a callable_ (val in / converted value returned).
97.. _callable: https://docs.python.org/3/glossary.html#term-callable
107"""Alias symbols for known unit of measure symbols / by example::
109 '°C': ('C', ...), # list of alias symbols for °C (Q69362731)
110 '°F': ('F', ...), # list of alias symbols for °F (Q99490479)
111 'mi': ('L',), # list of alias symbols for mi (Q253276)
116UNITS_BY_SI_NAME: dict = {}
121 if isinstance(from_si, (float, int)):
122 value = float(value) * from_si
124 value = from_si(float(value))
130 if isinstance(to_si, (float, int)):
131 value = float(value) * to_si
133 value = to_si(float(value))
139 global UNITS_BY_SI_NAME
141 return UNITS_BY_SI_NAME[si_name]
146 item_si_name = item[pos_si_name]
147 item_symbol = item[pos_symbol]
149 by_symbol = UNITS_BY_SI_NAME.get(item_si_name)
150 if by_symbol
is None:
152 UNITS_BY_SI_NAME[item_si_name] = by_symbol
153 by_symbol[item_symbol] = item
155 return UNITS_BY_SI_NAME[si_name]
166 """Generates a list of tuples, each tuple is a measure unit and the fields
169 0. Symbol of the measure unit (e.g. 'mi' for measure unit 'miles' Q253276)
171 1. SI name of the measure unit (e.g. Q11573 for SI unit 'metre')
173 2. Factor to get SI value from measure unit (e.g. 1mi is equal to SI 1m
174 multiplied by 1609.344)
176 3. Factor to get measure value from from SI value (e.g. SI 100m is equal to
177 100mi divided by 1609.344)
179 The returned list is sorted, the first items are created from
180 ``WIKIDATA_UNITS``, the second group of items is build from
181 :py:obj:`ADDITIONAL_UNITS` and items created from :py:obj:`ALIAS_SYMBOLS`.
183 If you search this list for a symbol, then a match with a symbol from
184 Wikidata has the highest weighting (first hit in the list), followed by the
185 symbols from the :py:obj:`ADDITIONAL_UNITS` and the lowest weighting is
186 given to the symbols resulting from the aliases :py:obj:`ALIAS_SYMBOLS`.
198 for item
in data.WIKIDATA_UNITS.values():
199 if item[
'to_si_factor']
and item[
'symbol']:
204 1 / item[
'to_si_factor'],
205 item[
'to_si_factor'],
210 for item
in ADDITIONAL_UNITS:
222 for item
in SYMBOL_TO_SI:
223 for alias
in ALIAS_SYMBOLS.get(item[0], ()):
233 SYMBOL_TO_SI = SYMBOL_TO_SI + alias_items
250SELECT DISTINCT ?item ?symbol ?tosi ?tosiUnit
253 ?item wdt:P31/wdt:P279 wd:Q47574 .
254 ?item p:P5061 ?symbolP .
255 ?symbolP ps:P5061 ?symbol ;
256 wikibase:rank ?rank .
258 ?item p:P2370 ?tosistmt .
259 ?tosistmt psv:P2370 ?tosinode .
260 ?tosinode wikibase:quantityAmount ?tosi .
261 ?tosinode wikibase:quantityUnit ?tosiUnit .
263 FILTER(LANG(?symbol) = "en").
265ORDER BY ?item DESC(?rank) ?symbol
270 """Fetch units from Wikidata. Function is used to update persistence of
271 :py:obj:`searx.data.WIKIDATA_UNITS`."""
273 results = collections.OrderedDict()
274 response = wikidata.send_wikidata_query(SARQL_REQUEST)
275 for unit
in response[
'results'][
'bindings']:
277 symbol = unit[
'symbol'][
'value']
278 name = unit[
'item'][
'value'].rsplit(
'/', 1)[1]
279 si_name = unit.get(
'tosiUnit', {}).get(
'value',
'')
281 si_name = si_name.rsplit(
'/', 1)[1]
283 to_si_factor = unit.get(
'tosi', {}).get(
'value',
'')
284 if name
not in results:
288 'si_name': si_name
if si_name
else None,
289 'to_si_factor': float(to_si_factor)
if to_si_factor
else None,
float from_si(cls, value)
float convert_from_si(str si_name, str symbol, float|int value)
float convert_to_si(str si_name, str symbol, float|int value)
units_by_si_name(si_name)