Source code for searx.search.processors.online_currency

# SPDX-License-Identifier: AGPL-3.0-or-later
"""Processor used for ``online_currency`` engines."""

import typing as t

import unicodedata
import re

import flask_babel
import babel

from searx.data import CURRENCIES
from .online import OnlineProcessor, OnlineParams

if t.TYPE_CHECKING:
    from .abstract import EngineProcessor
    from searx.search.models import SearchQuery


search_syntax = re.compile(r".*?(\d+(?:\.\d+)?) ([^.0-9]+) (?:in|to) ([^.0-9]+)", re.I)
"""Search syntax used for from/to currency (e.g. ``10 usd to eur``)"""


[docs] class CurrenciesParams(t.TypedDict): """Currencies request parameters.""" amount: float """Currency amount to be converted""" to_iso4217: str """ISO_4217_ alpha code of the currency used as the basis for conversion. .. _ISO_4217: https://en.wikipedia.org/wiki/ISO_4217 """ from_iso4217: str """ISO_4217_ alpha code of the currency to be converted.""" from_name: str """Name of the currency used as the basis for conversion.""" to_name: str """Name of the currency of the currency to be converted."""
[docs] class OnlineCurrenciesParams(CurrenciesParams, OnlineParams): # pylint: disable=duplicate-bases """Request parameters of a ``online_currency`` engine."""
[docs] class OnlineCurrencyProcessor(OnlineProcessor): """Processor class used by ``online_currency`` engines.""" engine_type: str = "online_currency"
[docs] def get_params(self, search_query: "SearchQuery", engine_category: str) -> OnlineCurrenciesParams | None: """Returns a dictionary with the :ref:`request params <engine request online_currency>` (:py:obj:`OnlineCurrenciesParams`). ``None`` is returned if the search query does not match :py:obj:`search_syntax`.""" online_params: OnlineParams | None = super().get_params(search_query, engine_category) if online_params is None: return None m = search_syntax.match(search_query.query) if not m: return None amount_str, from_currency, to_currency = m.groups() try: amount = float(amount_str) except ValueError: return None # most often $ stands for USD if from_currency == "$": from_currency = "$ us" if to_currency == "$": to_currency = "$ us" from_iso4217 = from_currency if not CURRENCIES.is_iso4217(from_iso4217): from_iso4217 = CURRENCIES.name_to_iso4217(_normalize_name(from_currency)) to_iso4217 = to_currency if not CURRENCIES.is_iso4217(to_iso4217): to_iso4217 = CURRENCIES.name_to_iso4217(_normalize_name(to_currency)) if from_iso4217 is None or to_iso4217 is None: return None ui_locale = flask_babel.get_locale() or babel.Locale.parse("en") from_name: str = CURRENCIES.iso4217_to_name( from_iso4217, ui_locale.language ) # pyright: ignore[reportAssignmentType] to_name: str = CURRENCIES.iso4217_to_name( to_iso4217, ui_locale.language ) # pyright: ignore[reportAssignmentType] params: OnlineCurrenciesParams = { **online_params, "amount": amount, "from_iso4217": from_iso4217, "to_iso4217": to_iso4217, "from_name": from_name, "to_name": to_name, } return params
def _normalize_name(name: str): name = name.strip() name = name.lower().replace("-", " ") name = re.sub(" +", " ", name) return unicodedata.normalize("NFKD", name).lower()