[chore] complete and normalize the attributes of engine objects (#6258)

Drop outdated engine attributes: supported_languages, language_aliases

Complete, normalize and document the type definitions for the engine-module and
engine-class.

For the ``engine.about`` section of the configuration, a type check is performed
based on structure ``searx.enginelib.EngineAbout``.

The property ``engine.about.language`` no longer exists; existing values have
been migrated to ``engine.language``.

Signed-off-by: Markus Heiser <markus.heiser@darmarit.de>
This commit is contained in:
Markus Heiser
2026-06-14 15:16:26 +02:00
committed by Markus Heiser
parent b3e08f2a44
commit 6c9dcd4242
45 changed files with 210 additions and 159 deletions
+2 -2
View File
@@ -58,8 +58,8 @@ Configured Engines
{% for mod in engines %}
* - `{{mod.name}} <{{mod.about and mod.about.website}}>`_
{%- if mod.about and mod.about.language %}
({{mod.about.language | upper}})
{%- if mod.language %}
({{mod.language | upper}})
{%- endif %}
- ``!{{mod.shortcut}}``
- {%- if 'searx.engines.' + mod.__name__ in documented_modules %}
+76 -63
View File
@@ -41,7 +41,7 @@ if t.TYPE_CHECKING:
from searx.enginelib.traits import EngineTraits
from searx.extended_types import SXNG_Response
from searx.result_types import EngineResults
from searx.search.processors import OfflineParamTypes, OnlineParamTypes
from searx.search.processors import OfflineParamTypes, OnlineParamTypes, ProcessorType
ENGINES_CACHE: ExpireCacheSQLite = ExpireCacheSQLite.build_cache(
ExpireCacheCfg(
@@ -180,7 +180,7 @@ class EngineCache:
return ENGINES_CACHE.secret_hash(name=name)
class EngineAbout(msgspec.Struct):
class EngineAbout(msgspec.Struct, kw_only=True):
"""Additional fields describing the engine.
.. code:: yaml
@@ -213,12 +213,11 @@ class EngineAbout(msgspec.Struct):
results: str = ""
"""Data format of the source (online-engines: of the response)."""
language: str = ""
"""If the engine supports only one language, this language is specified
here (``en``, ``de``, ``"no"`` or ..); otherwise, the value remains empty.
description: str = ""
"""Brief description of the engine and where it gets its data from.
For the YAML configuration: think of the `YAML-Norway problem
<https://ruuda.nl/2023/the-yaml-document-from-hell#the-norway-problem>`_
This value should only be set as long as no description of the data source
is available via a :py:obj:`EngineAbout.wikidata_id`.
"""
@@ -227,6 +226,8 @@ class Engine(abc.ABC): # pylint: disable=too-few-public-methods
Further documentation see :ref:`general engine configuration`.
The defaults are taken from :py:obj:`searx.engines.ENGINE_DEFAULT_ARGS`.
.. hint::
This class is currently never initialized and only used for type hinting.
@@ -234,49 +235,27 @@ class Engine(abc.ABC): # pylint: disable=too-few-public-methods
logger: logging.Logger
# Common options in the engine module
# Common options of the engine module
engine_type: str
engine_type: "ProcessorType" = "online"
"""Type of the engine (:ref:`searx.search.processors`)"""
paging: bool
paging: bool = False
"""Engine supports multiple pages."""
max_page: int = 0
"""If the engine supports paging, then this is the value for the last page
that is still supported. ``0`` means unlimited numbers of pages."""
time_range_support: bool
time_range_support: bool = False
"""Engine supports search time range."""
safesearch: bool
safesearch: bool = False
"""Engine supports SafeSearch"""
language_support: bool
language_support: bool = False
"""Engine supports languages (locales) search."""
language: str
"""For an engine, when there is ``language: ...`` in the YAML settings the engine
does support only this one language:
.. code:: yaml
- name: google french
engine: google
language: fr
"""
region: str
"""For an engine, when there is ``region: ...`` in the YAML settings the engine
does support only this one region::
.. code:: yaml
- name: google belgium
engine: google
region: fr-BE
"""
fetch_traits: "Callable[[EngineTraits, bool], None]"
"""Function to to fetch engine's traits from origin."""
@@ -285,9 +264,6 @@ class Engine(abc.ABC): # pylint: disable=too-few-public-methods
# settings.yml
categories: list[str]
"""Specifies to which :ref:`engine categories` the engine should be added."""
name: str
"""Name that will be used across SearXNG to define this engine. In settings, on
the result page .."""
@@ -297,6 +273,43 @@ class Engine(abc.ABC): # pylint: disable=too-few-public-methods
this search engine (file name from :origin:`searx/engines` without
``.py``)."""
categories: list[str] = ["general"]
"""Specifies to which :ref:`engine categories` the engine should be added."""
language: str = ""
"""If the engine supports only one language, this language is specified here
(``en``, ``de``, ``"no"`` or ..); otherwise, the value remains empty. For
the YAML configuration: think of the `YAML-Norway problem
<https://ruuda.nl/2023/the-yaml-document-from-hell#the-norway-problem>`_
.. code:: yaml
- name: google norway
engine: google
language: "no"
Depending on ``language_support``, this value has similar but also slightly
different meanings.
- When ``language_support`` is **true**, the map of
:py:obj:`traits.EngineTraits.languages` is reduced to the selected
language
- When ``language_support`` is **false**, then the implementation of the
engine only supports this one ``language``
"""
region: str = ""
"""For an engine, when there is ``region: ...`` in the YAML settings the engine
does support only this one region::
.. code:: yaml
- name: google belgium
engine: google
region: fr-BE
"""
enable_http: bool
"""Enable HTTP (by default only HTTPS is enabled)."""
@@ -309,6 +322,31 @@ class Engine(abc.ABC): # pylint: disable=too-few-public-methods
display_error_messages: bool
"""Display error messages on the web UI."""
disabled: bool = False
"""To disable by default the engine, but not deleting it. It will allow the
user to manually activate it in the settings."""
inactive: bool = False
"""Remove the engine from the settings (*disabled & removed*)."""
about: EngineAbout = EngineAbout()
"""Additional fields describing the engine."""
using_tor_proxy: bool = False
"""Using tor proxy (``true``) or not (``false``) for this engine."""
send_accept_language_header: bool = True
"""When this option is activated (default), the language (locale) that is
selected by the user is used to build and send a ``Accept-Language`` header
in the request to the origin search engine."""
tokens: list[str] = []
"""A list of secret tokens to make this engine *private*, more details see
:ref:`private engines`."""
weight: float = 1.0
"""Weighting of the results of this engine (:ref:`weight <settings engines>`)."""
proxies: dict[str, dict[str, str]]
"""Set proxies for a specific engine (YAML):
@@ -319,31 +357,6 @@ class Engine(abc.ABC): # pylint: disable=too-few-public-methods
https: socks5://proxy:port
"""
disabled: bool
"""To disable by default the engine, but not deleting it. It will allow the
user to manually activate it in the settings."""
inactive: bool
"""Remove the engine from the settings (*disabled & removed*)."""
about: EngineAbout
"""Additional fields describing the engine."""
using_tor_proxy: bool
"""Using tor proxy (``true``) or not (``false``) for this engine."""
send_accept_language_header: bool
"""When this option is activated (default), the language (locale) that is
selected by the user is used to build and send a ``Accept-Language`` header
in the request to the origin search engine."""
tokens: list[str]
"""A list of secret tokens to make this engine *private*, more details see
:ref:`private engines`."""
weight: int
"""Weighting of the results of this engine (:ref:`weight <settings engines>`)."""
def setup(self, engine_settings: dict[str, t.Any]) -> bool: # pylint: disable=unused-argument
"""Dynamic setup of the engine settings.
+14 -11
View File
@@ -142,11 +142,11 @@ class EngineTraits:
"""
if self.data_type == "traits_v1":
self._set_traits_v1(engine)
self._set_traits_v1(engine) # pyright: ignore[reportArgumentType]
else:
raise TypeError("engine traits of type %s is unknown" % self.data_type)
def _set_traits_v1(self, engine: "Engine | types.ModuleType") -> None:
def _set_traits_v1(self, engine: "Engine") -> None:
# For an engine, when there is `language: ...` in the YAML settings the engine
# does support only this one language (region)::
#
@@ -159,22 +159,25 @@ class EngineTraits:
_msg = "settings.yml - engine: '%s' / %s: '%s' not supported"
languages = traits.languages
if hasattr(engine, "language"):
if engine.language not in languages:
if engine.language:
if engine.language_support:
if not len(traits.languages) > 1:
raise ValueError(
f"engine {engine.name}: activated language_support with just one or less languages"
)
if engine.language not in traits.languages:
raise ValueError(_msg % (engine.name, "language", engine.language))
traits.languages = {engine.language: languages[engine.language]}
traits.languages = {engine.language: traits.languages[engine.language]}
regions = traits.regions
if hasattr(engine, "region"):
if engine.region not in regions:
if engine.region:
if engine.region not in traits.regions:
raise ValueError(_msg % (engine.name, "region", engine.region))
traits.regions = {engine.region: regions[engine.region]}
traits.regions = {engine.region: traits.regions[engine.region]}
engine.language_support = bool(traits.languages or traits.regions)
# set the copied & modified traits in engine's namespace
engine.traits = traits # pyright: ignore[reportAttributeAccessIssue]
engine.traits = traits
class EngineTraitsMap(dict[str, EngineTraits]):
+1 -1
View File
@@ -22,8 +22,8 @@ about = {
"use_official_api": False,
"require_api_key": False,
"results": "HTML",
"language": "zh",
}
language = "zh"
# Engine Configuration
categories = ["general"]
+6 -6
View File
@@ -5,19 +5,19 @@ intended monkey patching of the engine modules.
.. attention::
Monkey-patching modules is a practice from the past that shouldn't be
expanded upon. In the long run, there should be an engine class that can be
inherited. However, as long as this class doesn't exist, and as long as all
engine modules aren't converted to an engine class, these builtin types will
still be needed.
expanded upon. In the long run, engines should be instances of
:py:obj:`searx.enginelib.Engine`. However, as long as long as all engine
modules aren't converted to this class, these builtin types will still be
needed.
"""
import logging
from searx.enginelib import traits as _traits
logger: logging.Logger
supported_languages: str
language_aliases: str
language_support: bool
language: str
region: str
traits: _traits.EngineTraits
# from searx.engines.ENGINE_DEFAULT_ARGS
+28 -7
View File
@@ -17,37 +17,44 @@ from os.path import realpath, dirname
import types
import inspect
import msgspec
from searx import logger, settings
from searx.utils import load_module
if t.TYPE_CHECKING:
from searx.enginelib import Engine
from searx.enginelib import Engine, EngineAbout
logger = logger.getChild('engines')
ENGINE_DIR = dirname(realpath(__file__))
# Defaults for the namespace of an engine module, see load_engine()
ENGINE_DEFAULT_ARGS: dict[str, int | str | list[t.Any] | dict[str, t.Any] | bool] = {
ENGINE_DEFAULT_ARGS: dict[str, t.Any] = {
# Common options in the engine module
"engine_type": "online",
"paging": False,
"max_page": 0,
"time_range_support": False,
"safesearch": False,
"language_support": False,
# settings.yml
"categories": ["general"],
"language": "",
"region": "",
"enable_http": False,
"shortcut": "-",
"timeout": settings["outgoing"]["request_timeout"],
"display_error_messages": True,
"disabled": False,
"inactive": False,
"about": {},
"about": EngineAbout(),
"using_tor_proxy": False,
"send_accept_language_header": True,
"tokens": [],
"max_page": 0,
"weight": 1.0,
}
"""Default values that are set in an engine of type *module*, please compare
with the class :py:obj:`searx.enginelib.Engine`."""
# set automatically when an engine does not have any tab category
DEFAULT_CATEGORY = 'other'
@@ -178,13 +185,27 @@ def set_loggers(engine: "Engine|types.ModuleType", engine_name: str):
def update_engine_attributes(engine: "Engine | types.ModuleType", engine_data: dict[str, t.Any]):
# set engine attributes from engine_data
kvargs: dict[str, t.Any]
if isinstance(engine.about, EngineAbout):
kvargs = {**msgspec.to_builtins(engine.about), **engine_data.get("about", {})}
else:
kvargs = {**engine.about, **engine_data.get("about", {})}
try:
engine.about = EngineAbout(**kvargs)
except TypeError as exc:
raise TypeError(
f"engine {engine_data['name']} ({engine_data['engine']}) - in the about section --> {exc}"
) from exc
for param_name, param_value in engine_data.items():
if param_name == "about":
continue
if param_name == 'categories':
if isinstance(param_value, str):
param_value = list(map(str.strip, param_value.split(',')))
engine.categories = param_value # type: ignore
elif hasattr(engine, 'about') and param_name == 'about':
engine.about = {**engine.about, **engine_data['about']} # type: ignore
else:
setattr(engine, param_name, param_value)
+1 -1
View File
@@ -16,12 +16,12 @@ about = {
"use_official_api": False,
"require_api_key": False,
"results": "HTML",
"language": "zh",
}
# Engine Configuration
categories = ["videos"]
paging = True
language = "zh"
# Base URL
base_url = "https://www.acfun.cn"
+1 -1
View File
@@ -42,8 +42,8 @@ about = {
'use_official_api': False,
'require_api_key': False,
'results': 'HTML',
'language': 'it',
}
language = "it"
def request(query, params):
+1 -1
View File
@@ -54,8 +54,8 @@ about = {
"use_official_api": True,
"require_api_key": True,
"results": "JSON",
"language": "en",
}
language = "en"
CACHE: EngineCache
"""Persistent (SQLite) key/value cache that deletes its values after ``expire``
+1 -1
View File
@@ -23,8 +23,8 @@ about = {
"use_official_api": False,
"require_api_key": False,
"results": "JSON",
"language": "zh",
}
language = "zh"
paging = True
categories = []
+1 -1
View File
@@ -13,8 +13,8 @@ about = {
'use_official_api': False,
'require_api_key': False,
'results': 'JSON',
'language': 'de',
}
language = "de"
paging = True
categories = ['general']
+1 -1
View File
@@ -10,8 +10,8 @@ about = {
'use_official_api': False,
'require_api_key': False,
'results': 'JSON',
'language': 'de',
}
language = "de"
paging = True
categories = []
+1 -1
View File
@@ -70,13 +70,13 @@ about = {
"use_official_api": False,
"require_api_key": False,
"results": "JSON",
"language": "zh",
}
paging = True
time_range_support = True
results_per_page = 10
categories = []
language = "zh"
ChinasoCategoryType = t.Literal['news', 'videos', 'images']
"""ChinaSo supports news, videos, images search.
+6 -8
View File
@@ -24,7 +24,7 @@ import typing as t
import json
from searx.result_types import EngineResults
from searx.enginelib import EngineCache
from searx.enginelib import EngineCache, EngineAbout
if t.TYPE_CHECKING:
from searx.search.processors import RequestParams
@@ -35,13 +35,11 @@ categories = ["general"]
disabled = True
timeout = 2.0
about = {
"wikidata_id": None,
"official_api_documentation": None,
"use_official_api": False,
"require_api_key": False,
"results": "JSON",
}
language = "en"
about = EngineAbout(
results="JSON",
description="Demo offline engine Engine with results in the English language.",
)
# if there is a need for globals, use a leading underline
_my_offline_engine: str = ""
+9 -8
View File
@@ -25,6 +25,7 @@ import typing as t
from urllib.parse import urlencode
from searx.result_types import EngineResults
from searx.enginelib import EngineAbout
if t.TYPE_CHECKING:
from searx.extended_types import SXNG_Response
@@ -43,14 +44,14 @@ page_size = 20
search_api = "https://api.artic.edu/api/v1/artworks/search"
image_api = "https://www.artic.edu/iiif/2/"
about = {
"website": "https://www.artic.edu",
"wikidata_id": "Q239303",
"official_api_documentation": "http://api.artic.edu/docs/",
"use_official_api": True,
"require_api_key": False,
"results": "JSON",
}
about = EngineAbout(
website="https://www.artic.edu",
wikidata_id="Q239303",
official_api_documentation="http://api.artic.edu/docs/",
use_official_api=True,
require_api_key=False,
results="JSON",
)
# if there is a need for globals, use a leading underline
+1 -1
View File
@@ -11,8 +11,8 @@ about = {
'use_official_api': False,
'require_api_key': False,
'results': 'HTML',
'language': 'de',
}
language = "de"
categories = []
paging = True
+1 -1
View File
@@ -14,8 +14,8 @@ about = {
"use_official_api": False,
"require_api_key": False,
"results": 'HTML',
"language": 'de',
}
language = "de"
categories = ['dictionaries']
paging = True
+1 -1
View File
@@ -55,7 +55,7 @@ about = {
'official_api_documentation': 'https://www.elastic.co/guide/en/elasticsearch/reference/current/search-search.html',
'use_official_api': True,
'require_api_key': False,
'format': 'JSON',
"results": "JSON",
}
base_url = 'http://localhost:9200'
+1 -1
View File
@@ -27,8 +27,8 @@ about = {
'official_api_documentation': None,
'require_api_key': False,
'results': 'HTML',
'language': 'de',
}
language = "de"
paging = True
categories = ['shopping']
+1 -1
View File
@@ -34,8 +34,8 @@ about = {
"use_official_api": True,
"require_api_key": False,
"results": "JSON",
"language": "it",
}
language = "it"
def request(query, params):
+1 -1
View File
@@ -16,8 +16,8 @@ about = {
"use_official_api": False,
"require_api_key": False,
"results": 'HTML',
"language": 'fr',
}
language = "fr"
# engine dependent config
categories = ['videos']
+1 -1
View File
@@ -14,9 +14,9 @@ about = {
"use_official_api": False,
"require_api_key": False,
"results": "JSON",
"language": "zh",
}
language = "zh"
paging = True
time_range_support = True
categories = ["videos"]
+1 -1
View File
@@ -13,8 +13,8 @@ about = {
"use_official_api": True,
"require_api_key": False,
"results": 'JSON',
"language": 'ja',
}
language = "ja"
categories = ['dictionaries']
paging = False
+3
View File
@@ -79,6 +79,9 @@ from json import loads
from urllib.parse import urlencode
from searx.utils import to_string, html_to_text
from searx.network import raise_for_httperror
from searx.enginelib import EngineAbout
about = EngineAbout()
search_url = None
"""
+1 -1
View File
@@ -11,9 +11,9 @@ about = {
"use_official_api": True,
"require_api_key": False,
"results": 'JSON',
"language": "de",
}
language = "de"
categories = ['videos']
paging = True
time_range_support = False
+2 -1
View File
@@ -35,8 +35,9 @@ about = {
'use_official_api': False,
'require_api_key': False,
'results': 'JSON',
'language': 'de',
}
language = "de"
paging = True
categories = ["movies"]
+1 -1
View File
@@ -26,8 +26,8 @@ about = {
"use_official_api": False,
"require_api_key": False,
"results": "HTML",
"language": "ko",
}
language = "ko"
categories = []
paging = True
+1 -1
View File
@@ -13,8 +13,8 @@ about = {
"use_official_api": False,
"require_api_key": False,
"results": "HTML",
"language": "ja",
}
language = "ja"
categories = ["videos"]
paging = True
+2 -2
View File
@@ -28,7 +28,7 @@ search_string = 'api/?{query}&limit={limit}'
result_base_url = 'https://openstreetmap.org/{osm_type}/{osm_id}'
# list of supported languages
supported_languages = ['de', 'en', 'fr', 'it']
photon_supported_languages = ["de", "en", "fr", "it"]
# do search-request
@@ -37,7 +37,7 @@ def request(query, params):
if params['language'] != 'all':
language = params['language'].split('_')[0]
if language in supported_languages:
if language in photon_supported_languages:
params['url'] = params['url'] + "&lang=" + language
# using SearXNG User-Agent
+1 -1
View File
@@ -77,7 +77,7 @@ from searx.utils import gen_useragent, html_to_text, parse_duration_string
about = {
"website": "https://presearch.io",
"wikidiata_id": "Q7240905",
"wikidata_id": "Q7240905",
"official_api_documentation": "https://docs.presearch.io/nodes/api",
"use_official_api": False,
"require_api_key": False,
+1 -1
View File
@@ -16,8 +16,8 @@ about = {
"use_official_api": False,
"require_api_key": False,
"results": "HTML",
"language": "zh",
}
language = "zh"
# Engine Configuration
categories = []
+1 -1
View File
@@ -13,8 +13,8 @@ about = {
"use_official_api": False,
"require_api_key": False,
"results": 'JSON',
'language': 'fr',
}
language = "fr"
categories = ['movies']
paging = True
+1 -1
View File
@@ -19,8 +19,8 @@ about = {
"use_official_api": False,
"require_api_key": False,
"results": "HTML",
"language": "cz",
}
language = "cz"
categories = ['general', 'web']
base_url = 'https://search.seznam.cz/'
+1 -1
View File
@@ -16,8 +16,8 @@ about = {
"use_official_api": False,
"require_api_key": False,
"results": "HTML",
"language": "zh",
}
language = "zh"
# Engine Configuration
categories = ["general"]
+1 -1
View File
@@ -11,8 +11,8 @@ about = {
"use_official_api": False,
"require_api_key": False,
"results": "JSON",
"language": "zh",
}
language = "zh"
categories = ["videos"]
paging = True
+1 -1
View File
@@ -14,8 +14,8 @@ about = {
"use_official_api": False,
"require_api_key": False,
"results": "HTML",
"language": "zh",
}
language = "zh"
# Engine Configuration
categories = ["news"]
+2 -1
View File
@@ -27,8 +27,9 @@ about = {
'use_official_api': True,
'require_api_key': False,
'results': 'JSON',
'language': 'de',
}
language = "de"
categories = ['general', 'news']
paging = True
+8 -9
View File
@@ -16,20 +16,17 @@ from lxml import html
from searx.utils import eval_xpath_list, eval_xpath, extract_text, get_embeded_stream_url, ElementType
from searx.result_types import EngineResults
from searx.enginelib import EngineAbout
if t.TYPE_CHECKING:
from searx.extended_types import SXNG_Response
from searx.search.processors import OnlineParams
about = {
"website": "https://www.t-online.de",
"wikidata_id": "Q590940",
"official_api_documentation": None,
"use_official_api": False,
"require_api_key": False,
"results": "HTML",
"language": "de",
}
about = EngineAbout(
website="https://www.t-online.de",
wikidata_id="Q590940",
results="HTML",
)
paging = True
time_range_support = True
@@ -44,6 +41,8 @@ time_range_map = {"day": "d", "week": "w", "month": "m", "year": "y"}
# use "tonline" to only search for results from t-online news articles
tonline_channel_map = {"images": "flickr", "videos": "yt"}
language = "de"
def init(_):
if tonline_categ not in ("web", "images", "videos", "news"):
+3
View File
@@ -76,6 +76,9 @@ from lxml import html
from searx.utils import extract_text, extract_url, eval_xpath, eval_xpath_list
from searx.network import raise_for_httperror
from searx.result_types import EngineResults
from searx.enginelib import EngineAbout
about = EngineAbout()
search_url = None
"""
+9
View File
@@ -11,6 +11,7 @@ __all__ = [
"PROCESSORS",
"ParamTypes",
"RequestParams",
"ProcessorType",
]
import typing as t
@@ -27,6 +28,14 @@ from .online_url_search import OnlineUrlSearchProcessor, OnlineUrlSearchParams
logger = logger.getChild("search.processors")
ProcessorType = t.Literal[
"offline",
"online",
"online_currency",
"online_dictionary",
"online_url_search",
]
OnlineParamTypes: t.TypeAlias = OnlineParams | OnlineDictParams | OnlineCurrenciesParams | OnlineUrlSearchParams
OfflineParamTypes: t.TypeAlias = RequestParams
ParamTypes: t.TypeAlias = OfflineParamTypes | OnlineParamTypes
+4 -4
View File
@@ -330,12 +330,12 @@ engines:
url_xpath: ./a/@href
title_xpath: ./a/h3
content_xpath: ./div
language: "no"
about:
website: https://abcnyheter.no
use_official_api: false
require_api_key: false
results: HTML
language: "no"
- name: acfun
engine: acfun
@@ -2808,13 +2808,13 @@ engines:
shortcut: rel
categories: general
disabled: true
language: de
about:
website: https://reloado.com
official_api_documentation:
use_official_api: false
require_api_key: false
results: HTML
language: de
- name: repology
engine: repology
@@ -2927,13 +2927,13 @@ engines:
content_xpath: //div[@class="synonyms-list-group"]
title_xpath: //div[@class="upper-synonyms"]/a
no_result_for_http_status: [404]
language: de
about:
website: https://www.woxikon.de/
wikidata_id: # No Wikidata ID
use_official_api: false
require_api_key: false
results: HTML
language: de
- name: tootfinder
engine: tootfinder
@@ -2988,13 +2988,13 @@ engines:
content_xpath: //li/div[@class="searchresult"]
categories: general
disabled: true
language: fr
about:
website: https://wikimini.org/
wikidata_id: Q3568032
use_official_api: false
require_api_key: false
results: HTML
language: fr
- name: wttr.in
engine: wttr
@@ -60,8 +60,8 @@
{%- endif -%}
<label for="{{ engine_id }}">
{{- ' ' -}}{{- search_engine.name -}}
{%- if search_engine.about and search_engine.about.language -%}
{{- ' ' -}}({{search_engine.about.language | upper}})
{%- if search_engine.language -%}
{{- ' ' -}}({{search_engine.language | upper}})
{%- endif -%}
</label>
{{- engine_about(search_engine) -}}
+3 -4
View File
@@ -1075,10 +1075,9 @@ def engine_descriptions():
result[engine] = description
# overwrite by about:description (from settings)
for engine_name, engine_mod in engines.items():
descr = getattr(engine_mod, 'about', {}).get('description', None)
if descr is not None:
result[engine_name] = [descr, "SearXNG config"]
for eng_name, eng_obj in engines.items():
if eng_obj.about.description:
result[eng_name] = [eng_obj.about.description, "SearXNG config"]
return jsonify(result)
+1 -1
View File
@@ -323,7 +323,7 @@ def group_engines_in_tab(engines: "Iterable[Engine]") -> List[Tuple[str, "Iterab
return (group[0] == NO_SUBGROUPING, group[0].lower())
def engine_sort_key(engine):
return (engine.about.get('language', ''), engine.name)
return (engine.language, engine.name)
tabs = list(get_setting('categories_as_tabs').keys())
subgroups = itertools.groupby(sorted(engines, key=get_subgroup), get_subgroup)
+1 -1
View File
@@ -36,7 +36,7 @@ test.pylint() {
build_msg TEST "[pylint] ./searx/engines"
# shellcheck disable=SC2086
pylint ${PYLINT_OPTIONS} ${PYLINT_VERBOSE} \
--additional-builtins="traits,supported_languages,language_aliases,logger,categories" \
--additional-builtins="traits,logger,categories" \
searx/engines
build_msg TEST "[pylint] ./searx ./searxng_extra ./tests"