.oO SearXNG Developer Documentation Oo.
Loading...
Searching...
No Matches
online_currency.py
Go to the documentation of this file.
1# SPDX-License-Identifier: AGPL-3.0-or-later
2"""Processor used for ``online_currency`` engines."""
3
4import typing as t
5
6import unicodedata
7import re
8
9import flask_babel
10import babel
11
12from searx.data import CURRENCIES
13from .online import OnlineProcessor, OnlineParams
14
15if t.TYPE_CHECKING:
16 from .abstract import EngineProcessor
17 from searx.search.models import SearchQuery
18
19
20search_syntax = re.compile(r".*?(\d+(?:\.\d+)?) ([^.0-9]+) (?:in|to) ([^.0-9]+)", re.I)
21"""Search syntax used for from/to currency (e.g. ``10 usd to eur``)"""
22
23
24class CurrenciesParams(t.TypedDict):
25 """Currencies request parameters."""
26
27 amount: float
28 """Currency amount to be converted"""
29
30 to_iso4217: str
31 """ISO_4217_ alpha code of the currency used as the basis for conversion.
32
33 .. _ISO_4217: https://en.wikipedia.org/wiki/ISO_4217
34 """
35
36 from_iso4217: str
37 """ISO_4217_ alpha code of the currency to be converted."""
38
39 from_name: str
40 """Name of the currency used as the basis for conversion."""
41
42 to_name: str
43 """Name of the currency of the currency to be converted."""
44
45
46class OnlineCurrenciesParams(CurrenciesParams, OnlineParams): # pylint: disable=duplicate-bases
47 """Request parameters of a ``online_currency`` engine."""
48
49
51 """Processor class used by ``online_currency`` engines."""
52
53 engine_type: str = "online_currency"
54
55 def initialize(self, callback: t.Callable[["EngineProcessor", bool], bool]):
56 CURRENCIES.init()
57 super().initialize(callback)
58
59 def get_params(self, search_query: "SearchQuery", engine_category: str) -> OnlineCurrenciesParams | None:
60 """Returns a dictionary with the :ref:`request params <engine request
61 online_currency>` (:py:obj:`OnlineCurrenciesParams`). ``None`` is
62 returned if the search query does not match :py:obj:`search_syntax`."""
63
64 online_params: OnlineParams | None = super().get_params(search_query, engine_category)
65
66 if online_params is None:
67 return None
68 m = search_syntax.match(search_query.query)
69 if not m:
70 return None
71
72 amount_str, from_currency, to_currency = m.groups()
73 try:
74 amount = float(amount_str)
75 except ValueError:
76 return None
77
78 # most often $ stands for USD
79 if from_currency == "$":
80 from_currency = "$ us"
81
82 if to_currency == "$":
83 to_currency = "$ us"
84
85 from_iso4217 = from_currency
86 if not CURRENCIES.is_iso4217(from_iso4217):
87 from_iso4217 = CURRENCIES.name_to_iso4217(_normalize_name(from_currency))
88
89 to_iso4217 = to_currency
90 if not CURRENCIES.is_iso4217(to_iso4217):
91 to_iso4217 = CURRENCIES.name_to_iso4217(_normalize_name(to_currency))
92
93 if from_iso4217 is None or to_iso4217 is None:
94 return None
95
96 ui_locale = flask_babel.get_locale() or babel.Locale.parse("en")
97 from_name: str = CURRENCIES.iso4217_to_name(
98 from_iso4217, ui_locale.language
99 ) # pyright: ignore[reportAssignmentType]
100 to_name: str = CURRENCIES.iso4217_to_name(
101 to_iso4217, ui_locale.language
102 ) # pyright: ignore[reportAssignmentType]
103
104 params: OnlineCurrenciesParams = {
105 **online_params,
106 "amount": amount,
107 "from_iso4217": from_iso4217,
108 "to_iso4217": to_iso4217,
109 "from_name": from_name,
110 "to_name": to_name,
111 }
112
113 return params
114
115
116def _normalize_name(name: str):
117 name = name.strip()
118 name = name.lower().replace("-", " ")
119 name = re.sub(" +", " ", name)
120 return unicodedata.normalize("NFKD", name).lower()
OnlineCurrenciesParams|None get_params(self, "SearchQuery" search_query, str engine_category)
initialize(self, t.Callable[["EngineProcessor", bool], bool] callback)