From ff206e967993bd2e7aa6597b03d0affee20948b9 Mon Sep 17 00:00:00 2001 From: Markus Heiser Date: Thu, 29 May 2025 11:38:34 +0200 Subject: [mod] weather results: add types, i18n/l10n, symbols & unit conversions The types necessary for weather information such as GeoLocation, DateTime, Temperature,Pressure, WindSpeed, RelativeHumidity, Compass (wind direction) and symbols for the weather have been implemented. There are unit conversions and translations for weather property labels. Signed-off-by: Markus Heiser --- searx/wikidata_units.py | 79 +++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 70 insertions(+), 9 deletions(-) (limited to 'searx/wikidata_units.py') diff --git a/searx/wikidata_units.py b/searx/wikidata_units.py index 9fc94585f..b05ded220 100644 --- a/searx/wikidata_units.py +++ b/searx/wikidata_units.py @@ -5,6 +5,7 @@ Coordinates`_ .. _SPARQL/WIKIDATA Precision, Units and Coordinates: https://en.wikibooks.org/wiki/SPARQL/WIKIDATA_Precision,_Units_and_Coordinates#Quantities """ +from __future__ import annotations __all__ = ["convert_from_si", "convert_to_si", "symbol_to_si"] @@ -13,6 +14,47 @@ import collections from searx import data from searx.engines import wikidata + +class Beaufort: + """The mapping of the Beaufort_ contains values from 0 to 16 (55.6 m/s), + wind speeds greater than 200km/h (55.6 m/s) are given as 17 Bft. Thats why + a value of 17 Bft cannot be converted to SI. + + .. hint:: + + Negative values or values greater 16 Bft (55.6 m/s) will throw a + :py:obj:`ValueError`. + + _Beaufort: https://en.wikipedia.org/wiki/Beaufort_scale + """ + + # fmt: off + scale: list[float] = [ + 0.2, 1.5, 3.3, 5.4, 7.9, + 10.7, 13.8, 17.1, 20.7, 24.4, + 28.4, 32.6, 32.7, 41.1, 45.8, + 50.8, 55.6 + ] + # fmt: on + + @classmethod + def from_si(cls, value) -> float: + if value < 0 or value > 55.6: + raise ValueError(f"invalid value {value} / the Beaufort scales from 0 to 16 (55.6 m/s)") + bft = 0 + for bft, mps in enumerate(cls.scale): + if mps >= value: + break + return bft + + @classmethod + def to_si(cls, value) -> float: + idx = round(value) + if idx < 0 or idx > 16: + raise ValueError(f"invalid value {value} / the Beaufort scales from 0 to 16 (55.6 m/s)") + return cls.scale[idx] + + ADDITIONAL_UNITS = [ { "si_name": "Q11579", @@ -26,6 +68,12 @@ ADDITIONAL_UNITS = [ "to_si": lambda val: (val + 459.67) * 5 / 9, "from_si": lambda val: (val * 9 / 5) - 459.67, }, + { + "si_name": "Q182429", + "symbol": "Bft", + "to_si": Beaufort.to_si, + "from_si": Beaufort.from_si, + }, ] """Additional items to convert from a measure unit to a SI unit (vice versa). @@ -55,6 +103,7 @@ ALIAS_SYMBOLS = { '°C': ('C',), '°F': ('F',), 'mi': ('L',), + 'Bft': ('bft',), } """Alias symbols for known unit of measure symbols / by example:: @@ -65,11 +114,11 @@ ALIAS_SYMBOLS = { SYMBOL_TO_SI = [] -UNITS_BY_SI_NAME: dict | None = None +UNITS_BY_SI_NAME: dict = {} def convert_from_si(si_name: str, symbol: str, value: float | int) -> float: - from_si = units_by_si_name(si_name)[symbol][symbol]["from_si"] + from_si = units_by_si_name(si_name)[symbol][pos_from_si] if isinstance(from_si, (float, int)): value = float(value) * from_si else: @@ -78,7 +127,7 @@ def convert_from_si(si_name: str, symbol: str, value: float | int) -> float: def convert_to_si(si_name: str, symbol: str, value: float | int) -> float: - to_si = units_by_si_name(si_name)[symbol][symbol]["to_si"] + to_si = units_by_si_name(si_name)[symbol][pos_to_si] if isinstance(to_si, (float, int)): value = float(value) * to_si else: @@ -88,20 +137,32 @@ def convert_to_si(si_name: str, symbol: str, value: float | int) -> float: def units_by_si_name(si_name): - global UNITS_BY_SI_NAME - if UNITS_BY_SI_NAME is not None: + global UNITS_BY_SI_NAME # pylint: disable=global-statement,global-variable-not-assigned + if UNITS_BY_SI_NAME: return UNITS_BY_SI_NAME[si_name] - UNITS_BY_SI_NAME = {} + # build the catalog .. for item in symbol_to_si(): - by_symbol = UNITS_BY_SI_NAME.get(si_name) + + item_si_name = item[pos_si_name] + item_symbol = item[pos_symbol] + + by_symbol = UNITS_BY_SI_NAME.get(item_si_name) if by_symbol is None: by_symbol = {} - UNITS_BY_SI_NAME[si_name] = by_symbol - by_symbol[item["symbol"]] = item + UNITS_BY_SI_NAME[item_si_name] = by_symbol + by_symbol[item_symbol] = item + return UNITS_BY_SI_NAME[si_name] +pos_symbol = 0 # (alias) symbol +pos_si_name = 1 # si_name +pos_from_si = 2 # from_si +pos_to_si = 3 # to_si +pos_symbol = 4 # standardized symbol + + def symbol_to_si(): """Generates a list of tuples, each tuple is a measure unit and the fields in the tuple are: -- cgit v1.2.3