summaryrefslogtreecommitdiff
path: root/searx/wikidata_units.py
diff options
context:
space:
mode:
authorMarkus Heiser <markus.heiser@darmarit.de>2025-05-29 11:38:34 +0200
committerMarkus Heiser <markus.heiser@darmarIT.de>2025-05-31 20:34:59 +0200
commitff206e967993bd2e7aa6597b03d0affee20948b9 (patch)
tree1b03b3da44e5db205c55f6ed7783a94c6da3d8d7 /searx/wikidata_units.py
parenta800dd04735c98a293edff00493a5fee3dfeaed7 (diff)
[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 <markus.heiser@darmarit.de>
Diffstat (limited to 'searx/wikidata_units.py')
-rw-r--r--searx/wikidata_units.py79
1 files changed, 70 insertions, 9 deletions
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: