Merge branch 'searxng:master' into master

This commit is contained in:
anunol 2024-08-28 09:18:07 +08:00 committed by GitHub
commit 1aca24f461
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
20 changed files with 539 additions and 80 deletions

View file

@ -123,7 +123,7 @@ ${fedora_build}
# jump to SearXNG's working tree and install SearXNG into virtualenv
(${SERVICE_USER})$ cd \"$SEARXNG_SRC\"
(${SERVICE_USER})$ pip install -e .
(${SERVICE_USER})$ pip install --use-pep517 --no-build-isolation -e .
.. END manage.sh update_packages

View file

@ -61,7 +61,7 @@ working tree and release a ``make install`` to get a virtualenv with a
$ make install
PYENV [virtualenv] installing ./requirements*.txt into local/py3
...
PYENV [install] pip install -e 'searx[test]'
PYENV [install] pip install --use-pep517 --no-build-isolation -e 'searx[test]'
...
Successfully installed searxng-2023.7.19+a446dea1b
@ -78,7 +78,7 @@ the check fails if you edit the requirements listed in
...
PYENV [virtualenv] installing ./requirements*.txt into local/py3
...
PYENV [install] pip install -e 'searx[test]'
PYENV [install] pip install --use-pep517 --no-build-isolation -e 'searx[test]'
...
Successfully installed searxng-2023.7.19+a446dea1b

6
manage
View file

@ -233,7 +233,7 @@ gecko.driver() {
build_msg INSTALL "geckodriver already installed"
return
fi
PLATFORM="$(python3 -c 'import platform; print(platform.system().lower(), platform.architecture()[0])')"
PLATFORM="$(python -c 'import platform; print(platform.system().lower(), platform.architecture()[0])')"
case "$PLATFORM" in
"linux 32bit" | "linux2 32bit") ARCH="linux32";;
"linux 64bit" | "linux2 64bit") ARCH="linux64";;
@ -299,8 +299,8 @@ pyenv.install() {
( set -e
pyenv
build_msg PYENV "[install] pip install -e 'searx${PY_SETUP_EXTRAS}'"
"${PY_ENV_BIN}/python" -m pip install -e ".${PY_SETUP_EXTRAS}"
build_msg PYENV "[install] pip install --use-pep517 --no-build-isolation -e 'searx${PY_SETUP_EXTRAS}'"
"${PY_ENV_BIN}/python" -m pip install --use-pep517 --no-build-isolation -e ".${PY_SETUP_EXTRAS}"
)
local exit_val=$?
if [ ! $exit_val -eq 0 ]; then

View file

@ -14,10 +14,16 @@ billion images `[tineye.com] <https://tineye.com/how>`_.
"""
from typing import TYPE_CHECKING
from urllib.parse import urlencode
from datetime import datetime
from flask_babel import gettext
if TYPE_CHECKING:
import logging
logger = logging.getLogger()
about = {
"website": 'https://tineye.com',
"wikidata_id": 'Q2382535',
@ -34,7 +40,7 @@ categories = ['general']
paging = True
safesearch = False
base_url = 'https://tineye.com'
search_string = '/result_json/?page={page}&{query}'
search_string = '/api/v1/result_json/?page={page}&{query}'
FORMAT_NOT_SUPPORTED = gettext(
"Could not read that image url. This may be due to an unsupported file"
@ -120,7 +126,7 @@ def parse_tineye_match(match_json):
crawl_date = backlink_json.get("crawl_date")
if crawl_date:
crawl_date = datetime.fromisoformat(crawl_date[:-3])
crawl_date = datetime.strptime(crawl_date, '%Y-%m-%d')
else:
crawl_date = datetime.min
@ -150,29 +156,15 @@ def parse_tineye_match(match_json):
def response(resp):
"""Parse HTTP response from TinEye."""
results = []
try:
# handle the 422 client side errors, and the possible 400 status code error
if resp.status_code in (400, 422):
json_data = resp.json()
except Exception as exc: # pylint: disable=broad-except
msg = "can't parse JSON response // %s" % exc
logger.error(msg)
json_data = {'error': msg}
# handle error codes from Tineye
if resp.is_error:
if resp.status_code in (400, 422):
message = 'HTTP status: %s' % resp.status_code
error = json_data.get('error')
s_key = json_data.get('suggestions', {}).get('key', '')
if error and s_key:
message = "%s (%s)" % (error, s_key)
elif error:
message = error
suggestions = json_data.get('suggestions', {})
message = f'HTTP Status Code: {resp.status_code}'
if resp.status_code == 422:
s_key = suggestions.get('key', '')
if s_key == "Invalid image URL":
# test https://docs.searxng.org/_static/searxng-wordmark.svg
message = FORMAT_NOT_SUPPORTED
@ -182,16 +174,23 @@ def response(resp):
elif s_key == 'Download Error':
# test https://notexists
message = DOWNLOAD_ERROR
else:
logger.warning("Unknown suggestion key encountered: %s", s_key)
else: # 400
description = suggestions.get('description')
if isinstance(description, list):
message = ','.join(description)
# see https://github.com/searxng/searxng/pull/1456#issuecomment-1193105023
# results.append({'answer': message})
logger.error(message)
# see https://github.com/searxng/searxng/pull/1456#issuecomment-1193105023
# results.append({'answer': message})
logger.error(message)
return []
return results
# Raise for all other responses
resp.raise_for_status()
resp.raise_for_status()
# append results from matches
results = []
json_data = resp.json()
for match_json in json_data['matches']:

133
searx/engines/yandex.py Normal file
View file

@ -0,0 +1,133 @@
# SPDX-License-Identifier: AGPL-3.0-or-later
"""Yandex (Web, images)"""
from json import loads
from urllib.parse import urlencode
from html import unescape
from lxml import html
from searx.exceptions import SearxEngineCaptchaException
from searx.utils import humanize_bytes, eval_xpath, eval_xpath_list, extract_text, extr
# Engine metadata
about = {
"website": 'https://yandex.com/',
"wikidata_id": 'Q5281',
"official_api_documentation": "?",
"use_official_api": False,
"require_api_key": False,
"results": 'HTML',
}
# Engine configuration
categories = []
paging = True
search_type = ""
# Search URL
base_url_web = 'https://yandex.com/search/site/'
base_url_images = 'https://yandex.com/images/search'
results_xpath = '//li[contains(@class, "serp-item")]'
url_xpath = './/a[@class="b-serp-item__title-link"]/@href'
title_xpath = './/h3[@class="b-serp-item__title"]/a[@class="b-serp-item__title-link"]/span'
content_xpath = './/div[@class="b-serp-item__content"]//div[@class="b-serp-item__text"]'
def catch_bad_response(resp):
if resp.url.path.startswith('/showcaptcha'):
raise SearxEngineCaptchaException()
def request(query, params):
query_params_web = {
"tmpl_version": "releases",
"text": query,
"web": "1",
"frame": "1",
"searchid": "3131712",
}
query_params_images = {
"text": query,
"uinfo": "sw-1920-sh-1080-ww-1125-wh-999",
}
if params['pageno'] > 1:
query_params_web.update({"p": params["pageno"] - 1})
query_params_images.update({"p": params["pageno"] - 1})
params["cookies"] = {'cookie': "yp=1716337604.sp.family%3A0#1685406411.szm.1:1920x1080:1920x999"}
if search_type == 'web':
params['url'] = f"{base_url_web}?{urlencode(query_params_web)}"
elif search_type == 'images':
params['url'] = f"{base_url_images}?{urlencode(query_params_images)}"
return params
def response(resp):
if search_type == 'web':
catch_bad_response(resp)
dom = html.fromstring(resp.text)
results = []
for result in eval_xpath_list(dom, results_xpath):
results.append(
{
'url': extract_text(eval_xpath(result, url_xpath)),
'title': extract_text(eval_xpath(result, title_xpath)),
'content': extract_text(eval_xpath(result, content_xpath)),
}
)
return results
if search_type == 'images':
catch_bad_response(resp)
html_data = html.fromstring(resp.text)
html_sample = unescape(html.tostring(html_data, encoding='unicode'))
content_between_tags = extr(
html_sample, '{"location":"/images/search/', 'advRsyaSearchColumn":null}}', default="fail"
)
json_data = '{"location":"/images/search/' + content_between_tags + 'advRsyaSearchColumn":null}}'
if content_between_tags == "fail":
content_between_tags = extr(html_sample, '{"location":"/images/search/', 'false}}}')
json_data = '{"location":"/images/search/' + content_between_tags + 'false}}}'
json_resp = loads(json_data)
results = []
for _, item_data in json_resp['initialState']['serpList']['items']['entities'].items():
title = item_data['snippet']['title']
source = item_data['snippet']['url']
thumb = item_data['image']
fullsize_image = item_data['viewerData']['dups'][0]['url']
height = item_data['viewerData']['dups'][0]['h']
width = item_data['viewerData']['dups'][0]['w']
filesize = item_data['viewerData']['dups'][0]['fileSizeInBytes']
humanized_filesize = humanize_bytes(filesize)
results.append(
{
'title': title,
'url': source,
'img_src': fullsize_image,
'filesize': humanized_filesize,
'thumbnail_src': thumb,
'template': 'images.html',
'resolution': f'{width} x {height}',
}
)
return results
return []

View file

@ -0,0 +1,87 @@
# A propos de SearXNG
SearXNG est un [Métamoteur] qui agrège les résultats d'autres
{{link('moteurs de recherche', 'preferences')}} tout en ne sauvegardant
aucune informations à propos de ses utilisateurs.
Le projet SearXNG est maintenu par une communauté ouverte.
Rejoignez-nous sur Matrix si vous avez des questions ou simplement pour
discuter de SearXNG: [#searxng:matrix.org].
Aidez-nous à rendre SearXNG meilleur.
- Vous pouvez améliorer les traductions de SearXNG avec l'outil
[Weblate].
- Suivez le développement, contribuez au projet ou remontez des erreurs
en utilisant le [dépôt de sources].
- Pour obtenir de plus amples informations, consultez la documentation
en ligne du [projet SearXNG].
## Pourquoi l'utiliser ?
- SearXNG ne vous fournira pas de résultats aussi personnalisés que
Google, mais il ne générera pas non plus de suivi sur vous.
- SearXNG ne se soucis pas des recherches que vous faites, ne partage
aucune information avec des tiers et ne peut pas être utilisé contre
vous.
- SearXNG est un logiciel libre. Son code source est 100% ouvert et tout
le mode est encouragé à l'améliorer.
Si vous êtes soucieux du respect de la vie privée et des libertés sur
Internet, faites de SearXNG votre moteur de recherche par défaut. Vous
pouvez aussi installer et utiliser SearXNG sur votre propre serveur.
## Comment le configurer comme moteur de recherche par défaut ?
SearXNG prend en charge [OpenSearch]. Pour plus d'informations sur la
manière de modifier votre moteur de recherche par défaut, veuillez
consulter la documentation de votre navigateur :
- [Firefox]
- [Microsoft Edge] - Ce lien propose aussi les instructions pour les
navigateurs Chrome et Safari.
- Les navigateurs basés sur [Chromium] permettent d'ajouter des sites de
navigation sans même y accéder.
Lorsqu'un moteur de recherche est ajouté, son nom doit être unique. Si
vous ne pouvez pas ajouter un moteur de recherche, veuillez :
- Supprimer le doublon (le nom par défaut est SearXNG) ou bien
- Contacter le propriétaire de l'instance que vous souhaitez utiliser
afin qu'il modifie le nom de celle-ci.
## Comment ça marche ?
SearXNG est une reprise logicielle du projet [searx] [Métamoteur],
lui-même inspiré du [projet Seeks]. Il assure la confidentialité en
mélangeant vos recherches vers d'autres plateformes sans stocker aucune
données de recherche. SearXNG peut être ajouté à la barre de recherche
de votre navigateur et même être utilisé comme moteur de recherche par
défaut.
Le lien "{{link('statistiques des moteurs', 'stats')}}" présente des
informations anonymisées concernant l'utilisation des divers moteurs de
recherche.
## Comment reprendre la main ?
SearXNG apprécie votre préoccupation concernant les traces de recherche.
N'hésitez pas à utiliser le [dépôt de sources] et à maintenir votre
propre instance de recherche.
Ajouter votre instance à la [liste d'instances
publiques]({{get_setting('brand.public_instances')}}) afin d'aider
d'autres personnes à protéger leur vie privée et rendre l'Internet plus
libre. Plus Internet sera décentralisé, plus nous aurons de liberté !
[dépôt de sources]: {{GIT_URL}}
[#searxng:matrix.org]: https://matrix.to/#/#searxng:matrix.org
[projet SearXNG]: {{get_setting('brand.docs_url')}}
[searx]: https://github.com/searx/searx
[Métamoteur]: https://fr.wikipedia.org/wiki/M%C3%A9tamoteur
[Weblate]: https://translate.codeberg.org/projects/searxng/
[projet Seeks]: https://beniz.github.io/seeks/
[OpenSearch]: https://github.com/dewitt/opensearch/blob/master/opensearch-1-1-draft-6.md
[Firefox]: https://support.mozilla.org/en-US/kb/add-or-remove-search-engine-firefox
[Microsoft Edge]: https://support.microsoft.com/en-us/help/4028574/microsoft-edge-change-the-default-search-engine
[Chromium]: https://www.chromium.org/tab-to-search

View file

@ -0,0 +1,97 @@
# Syntaxe de recherche
SearXNG permet de modifier les catégories de recherche, les moteurs
utilisés ou encore la langue de recherche par l'intermédiaire d'une
syntaxe dédiée. La liste des moteurs de recherche, de catégories et de
langues disponibles est accessible depuis la page de
{{link('préférences', 'preferences')}}.
## `!` Spécifier un moteur ou une catégorie
Pour restreindre la recherche à un moteur ou une catégorie, utilisez le
caractère "!". Voici quelques exemples d'utilisation :
- Rechercher **paris** sur Wikipédia.
- {{search('!wp paris')}}
- {{search('!wikipedia paris')}}
- Rechercher **paris** dans la catégorie **Carte**.
- {{search('!map paris')}}
- Rechercher des **Images**.
- {{search('!images Wau Holland')}}
Les abréviations de moteurs et de langues sont aussi valides. Il est
possible d'accumuler les moteurs et catégories dans une requête
complexe. Par exemple, {{search('!map !ddg !wp paris')}} recherchera
**paris** dans la catégorie **Carte** de DuckDuckGo et Wikipédia.
## `:` Spécifier une langue
Utilisez le préfixe ":" pour limiter la recherche à une langue en
particulier. Par exemple :
- Rechercher dans les pages françaises de Wikipédia.
- {{search(':fr !wp Wau Holland')}}
## `!!<bang>` Recherches externes (!Bang)
SearXNG supporte les recherches [DuckDuckGo] de type "!Bang". Utilisez
le préfixe "!!" pour être automatiquement redirigé vers un moteur de
recherche externe. Par exemple :
- Rechercher sur Wikipédia en langue française.
- {{search('!!wfr Wau Holland')}}
Prenez garde au fait que de telles recherches sont exécutées directement
sur le moteur externe. Dans ce cas, SearXNG ne peut pas protéger votre
vie privée.
[DuckDuckGo]: https://duckduckgo.com/bang
## `!!` Redirection automatique
En utilisant "!!" suivi d'un ou plusieurs espaces lors de votre
recherche, vous serez automatiquement redirigé vers le premier résultat
de recherche. Cela correspondant au fonctionnement "J'ai de la chance"
du moteur Google. Par exemple :
- Rechercher et être redirigé directement vers le premier lien
correspondant.
- {{search('!! Wau Holland')}}
Prenez garde au fait qu'aucune vérification ne peut être faite
concernant le premier lien retourné. Il pourrait même s'agir d'un site
dangereux. Dans ce cas, SearXNG ne peut pas protéger votre vie
privée. Soyez prudent en utilisant cette fonctionnalité.
## Requêtes spéciales
Dans la section _requêtes spéciales_ de la page de {{link('préférences',
'preferences')}} se trouve une liste de mots clés à usage particulier.
Par exemple :
- Générer une valeur aléatoire.
- {{search('random uuid')}}
- Calculer une moyenne.
- {{search('avg 123 548 2.04 24.2')}}
- Afficher la valeur de la variable _User-Agent_ utilisée par votre
navigateur (doit être activé manuellement).
- {{search('user-agent')}}
- Convertir une chaîne de caractères en valeurs de hachage ("hash digests")
(doit être activé manuellement).
- {{search('md5 lorem ipsum')}}
- {{search('sha512 lorem ipsum')}}

View file

@ -1,7 +1,19 @@
# SPDX-License-Identifier: AGPL-3.0-or-later
# pylint: disable=too-many-branches
"""In addition to rewriting/replace reslut URLs, the *hoostnames* plugin offers
other features.
"""
.. attention::
The **"Hostname replace"** plugin has been replace by **"Hostnames
plugin"**, see :pull:`3463` & :pull:`3552`.
The **Hostnames plugin** can be enabled by adding it to the
``enabled_plugins`` **list** in the ``setting.yml`` like so.
.. code:: yaml
enabled_plugins:
- 'Hostnames plugin'
...
- ``hostnames.replace``: A **mapping** of regular expressions to hostnames to be
replaced by other hostnames.

View file

@ -1852,6 +1852,22 @@ engines:
engine: unsplash
shortcut: us
- name: yandex
engine: yandex
categories: general
search_type: web
shortcut: yd
disabled: true
inactive: true
- name: yandex images
engine: yandex
categories: images
search_type: images
shortcut: ydi
disabled: true
inactive: true
- name: yandex music
engine: yandex_music
shortcut: ydm

View file

@ -11,18 +11,19 @@
# return42 <return42@users.noreply.translate.codeberg.org>, 2024.
msgid ""
msgstr ""
"Project-Id-Version: searx\n"
"Project-Id-Version: searx\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2024-08-08 10:01+0000\n"
"PO-Revision-Date: 2024-07-30 08:18+0000\n"
"PO-Revision-Date: 2024-08-22 05:18+0000\n"
"Last-Translator: ghose <ghose@users.noreply.translate.codeberg.org>\n"
"Language-Team: Galician <https://translate.codeberg.org/projects/searxng/"
"searxng/gl/>\n"
"Language: gl\n"
"Language-Team: Galician "
"<https://translate.codeberg.org/projects/searxng/searxng/gl/>\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 5.6.2\n"
"Generated-By: Babel 2.15.0\n"
#. CONSTANT_NAMES['NO_SUBGROUPING']
@ -1308,7 +1309,7 @@ msgid ""
"multiple categories"
msgstr ""
"Buscar inmediatamente se hai unha categoría seleccionada. Desactiva para "
"elexir varias categorías"
"elixir varias categorías"
#: searx/templates/simple/preferences/theme.html:2
msgid "Theme"
@ -1953,4 +1954,3 @@ msgstr "agochar vídeo"
#~ msgid "Hostname replace"
#~ msgstr "Substituír servidor"

View file

@ -10,22 +10,23 @@
# SecularSteve <fairfull.playing@gmail.com>, 2022, 2023.
# return42 <markus.heiser@darmarit.de>, 2023.
# return42 <return42@users.noreply.translate.codeberg.org>, 2024.
# crnobog <crnobog@users.noreply.translate.codeberg.org>, 2024.
msgid ""
msgstr ""
"Project-Id-Version: searx\n"
"Project-Id-Version: searx\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2024-08-08 10:01+0000\n"
"PO-Revision-Date: 2024-04-18 13:18+0000\n"
"Last-Translator: return42 <return42@users.noreply.translate.codeberg.org>"
"\n"
"PO-Revision-Date: 2024-08-21 01:18+0000\n"
"Last-Translator: crnobog <crnobog@users.noreply.translate.codeberg.org>\n"
"Language-Team: Serbian <https://translate.codeberg.org/projects/searxng/"
"searxng/sr/>\n"
"Language: sr\n"
"Language-Team: Serbian "
"<https://translate.codeberg.org/projects/searxng/searxng/sr/>\n"
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
"X-Generator: Weblate 5.6.2\n"
"Generated-By: Babel 2.15.0\n"
#. CONSTANT_NAMES['NO_SUBGROUPING']
@ -76,7 +77,7 @@ msgstr "радио"
#. CATEGORY_NAMES['TV']
#: searx/searxng.msg
msgid "tv"
msgstr ""
msgstr "телевизија"
#. CATEGORY_NAMES['IT']
#: searx/searxng.msg
@ -176,62 +177,66 @@ msgstr "О нама"
#. WEATHER_TERMS['AVERAGE TEMP.']
#: searx/searxng.msg
msgid "Average temp."
msgstr ""
msgstr "Просечна температура"
#. WEATHER_TERMS['CLOUD COVER']
#: searx/searxng.msg
msgid "Cloud cover"
msgstr ""
msgstr "Облачност"
#. WEATHER_TERMS['CONDITION']
#: searx/searxng.msg
msgid "Condition"
msgstr ""
msgstr "Стање"
#. WEATHER_TERMS['CURRENT CONDITION']
#: searx/searxng.msg
msgid "Current condition"
msgstr ""
msgstr "Тренутно стање"
#. WEATHER_TERMS['EVENING']
#: searx/engines/wttr.py:100 searx/searxng.msg
#, fuzzy
msgid "Evening"
msgstr "Vece"
msgstr "Вече"
#. WEATHER_TERMS['FEELS LIKE']
#: searx/searxng.msg
msgid "Feels like"
msgstr ""
msgstr "Осећај"
#. WEATHER_TERMS['HUMIDITY']
#: searx/searxng.msg
msgid "Humidity"
msgstr ""
msgstr "Влажност"
#. WEATHER_TERMS['MAX TEMP.']
#: searx/searxng.msg
msgid "Max temp."
msgstr ""
msgstr "Највећа темп."
#. WEATHER_TERMS['MIN TEMP.']
#: searx/searxng.msg
msgid "Min temp."
msgstr ""
msgstr "Најмања темп."
#. WEATHER_TERMS['MORNING']
#: searx/engines/wttr.py:100 searx/searxng.msg
#, fuzzy
msgid "Morning"
msgstr "Jutro"
msgstr "Јутро"
#. WEATHER_TERMS['NIGHT']
#: searx/engines/wttr.py:100 searx/searxng.msg
#, fuzzy
msgid "Night"
msgstr "Noc"
msgstr "Ноћ"
#. WEATHER_TERMS['NOON']
#: searx/engines/wttr.py:100 searx/searxng.msg
#, fuzzy
msgid "Noon"
msgstr "Podne"
msgstr "Подне"
#. WEATHER_TERMS['PRESSURE']
#: searx/searxng.msg
@ -1934,4 +1939,3 @@ msgstr "сакриј видео"
#~ msgid "Hostname replace"
#~ msgstr "Замени име хостинга"

View file

@ -10,6 +10,7 @@ class TestEnginesInit(SearxTestCase): # pylint: disable=missing-class-docstring
def tearDownClass(cls):
settings['outgoing']['using_tor_proxy'] = False
settings['outgoing']['extra_proxy_timeout'] = 0
engines.load_engines([])
def test_initialize_engines_default(self):
engine_list = [

View file

@ -2,6 +2,7 @@
# pylint: disable=missing-module-docstring, invalid-name
from copy import copy
import logging
import searx.search
from searx.search import SearchQuery, EngineRef
@ -46,8 +47,13 @@ class SearchQueryTestCase(SearxTestCase): # pylint: disable=missing-class-docst
class SearchTestCase(SearxTestCase): # pylint: disable=missing-class-docstring
def setUp(self):
log = logging.getLogger("searx")
log_lev = log.level
log.setLevel(logging.ERROR)
from searx import webapp # pylint: disable=import-outside-toplevel
log.setLevel(log_lev)
self.app = webapp.app
@classmethod

102
tests/unit/test_tineye.py Normal file
View file

@ -0,0 +1,102 @@
# SPDX-License-Identifier: AGPL-3.0-or-later
# pylint: disable=missing-module-docstring
from datetime import datetime
from unittest.mock import Mock
from requests import HTTPError
from searx.engines import load_engines, tineye
from tests import SearxTestCase
class TinEyeTests(SearxTestCase): # pylint: disable=missing-class-docstring
def setUp(self):
load_engines([{'name': 'tineye', 'engine': 'tineye', 'shortcut': 'tin', 'timeout': 9.0, 'disabled': True}])
def tearDown(self):
load_engines([])
def test_status_code_raises(self):
response = Mock()
response.status_code = 401
response.raise_for_status.side_effect = HTTPError()
self.assertRaises(HTTPError, lambda: tineye.response(response))
def test_returns_empty_list_for_422(self):
response = Mock()
response.json.return_value = {}
response.status_code = 422
response.raise_for_status.side_effect = HTTPError()
with self.assertLogs(tineye.logger) as _dev_null:
results = tineye.response(response)
self.assertEqual(0, len(results))
def test_logs_format_for_422(self):
response = Mock()
response.json.return_value = {"suggestions": {"key": "Invalid image URL"}}
response.status_code = 422
response.raise_for_status.side_effect = HTTPError()
with self.assertLogs(tineye.logger) as assert_logs_context:
tineye.response(response)
self.assertIn(tineye.FORMAT_NOT_SUPPORTED, ','.join(assert_logs_context.output))
def test_logs_signature_for_422(self):
response = Mock()
response.json.return_value = {"suggestions": {"key": "NO_SIGNATURE_ERROR"}}
response.status_code = 422
response.raise_for_status.side_effect = HTTPError()
with self.assertLogs(tineye.logger) as assert_logs_context:
tineye.response(response)
self.assertIn(tineye.NO_SIGNATURE_ERROR, ','.join(assert_logs_context.output))
def test_logs_download_for_422(self):
response = Mock()
response.json.return_value = {"suggestions": {"key": "Download Error"}}
response.status_code = 422
response.raise_for_status.side_effect = HTTPError()
with self.assertLogs(tineye.logger) as assert_logs_context:
tineye.response(response)
self.assertIn(tineye.DOWNLOAD_ERROR, ','.join(assert_logs_context.output))
def test_empty_list_for_400(self):
response = Mock()
response.json.return_value = {}
response.status_code = 400
response.raise_for_status.side_effect = HTTPError()
with self.assertLogs(tineye.logger) as _dev_null:
results = tineye.response(response)
self.assertEqual(0, len(results))
def test_logs_description_for_400(self):
description = 'There was a problem with that request. Error ID: ad5fc955-a934-43c1-8187-f9a61d301645'
response = Mock()
response.json.return_value = {"suggestions": {"description": [description], "title": "Oops! We're sorry!"}}
response.status_code = 400
response.raise_for_status.side_effect = HTTPError()
with self.assertLogs(tineye.logger) as assert_logs_context:
tineye.response(response)
self.assertIn(description, ','.join(assert_logs_context.output))
def test_crawl_date_parses(self):
date_str = '2020-05-25'
date = datetime.strptime(date_str, '%Y-%m-%d')
response = Mock()
response.json.return_value = {
'matches': [
{
'backlinks': [
{
'crawl_date': date_str,
}
]
}
]
}
response.status_code = 200
results = tineye.response(response)
self.assertEqual(date, results[0]['publishedDate'])

View file

@ -1,6 +1,7 @@
# SPDX-License-Identifier: AGPL-3.0-or-later
# pylint: disable=missing-module-docstring
import logging
import json
from urllib.parse import ParseResult
from mock import Mock
@ -20,8 +21,13 @@ class ViewsTestCase(SearxTestCase): # pylint: disable=missing-class-docstring,
self.setattr4test(searx.search.processors, 'initialize_processor', dummy)
log = logging.getLogger("searx")
log_lev = log.level
log.setLevel(logging.ERROR)
from searx import webapp # pylint: disable=import-outside-toplevel
log.setLevel(log_lev)
webapp.app.config['TESTING'] = True # to get better error messages
self.app = webapp.app.test_client()

View file

@ -663,8 +663,8 @@ pyenv.install() {
pyenv
fi
for i in ${PYOBJECTS}; do
build_msg PYENV "[install] pip install -e '$i${PY_SETUP_EXTRAS}'"
"${PY_ENV_BIN}/python" -m pip install -e "$i${PY_SETUP_EXTRAS}"
build_msg PYENV "[install] pip install --use-pep517 --no-build-isolation -e '$i${PY_SETUP_EXTRAS}'"
"${PY_ENV_BIN}/python" -m pip install --use-pep517 --no-build-isolation -e "$i${PY_SETUP_EXTRAS}"
done
fi
pyenv.install.OK
@ -1674,7 +1674,7 @@ EOF
}
# apt packages
LXC_BASE_PACKAGES_debian="bash git build-essential python3 python3-venv"
LXC_BASE_PACKAGES_debian="bash git build-essential python3 python3-venv python-is-python3"
# pacman packages
LXC_BASE_PACKAGES_arch="bash git base-devel python"

View file

@ -41,7 +41,7 @@ EOF
}
go.ls(){
python3 <<EOF
python <<EOF
import sys, json, requests
resp = requests.get("${GO_DL_URL}/?mode=json&include=all")
for ver in json.loads(resp.text):
@ -67,7 +67,7 @@ go.ver_info(){
# os: [darwin|freebsd|linux|windows]
# arch: [amd64|arm64|386|armv6l|ppc64le|s390x]
python3 - "$@" <<EOF
python - "$@" <<EOF
import sys, json, requests
resp = requests.get("${GO_DL_URL}/?mode=json&include=all")
for ver in json.loads(resp.text):

View file

@ -96,13 +96,8 @@ case $DIST_ID-$DIST_VERS in
SEARXNG_BUILD_PACKAGES="${SEARXNG_BUILD_PACKAGES_debian}"
APACHE_PACKAGES="$APACHE_PACKAGES libapache2-mod-proxy-uwsgi"
;;
ubuntu-20.04)
# https://wiki.ubuntu.com/FocalFossa/ReleaseNotes#Python3_by_default
SEARXNG_PACKAGES="${SEARXNG_PACKAGES_debian} python-is-python3"
SEARXNG_BUILD_PACKAGES="${SEARXNG_BUILD_PACKAGES_debian}"
;;
ubuntu-*|debian-*)
SEARXNG_PACKAGES="${SEARXNG_PACKAGES_debian}"
SEARXNG_PACKAGES="${SEARXNG_PACKAGES_debian} python-is-python3"
SEARXNG_BUILD_PACKAGES="${SEARXNG_BUILD_PACKAGES_debian}"
;;
arch-*)
@ -453,6 +448,7 @@ searxng.install.clone() {
# clone repo and add a safe.directory entry to git's system config / see
# https://github.com/searxng/searxng/issues/1251
git config --system --add safe.directory "${REPO_ROOT}/.git"
git_clone "$REPO_ROOT" "${SEARXNG_SRC}" \
"$GIT_BRANCH" "${SERVICE_USER}"
git config --system --add safe.directory "${SEARXNG_SRC}"
@ -489,7 +485,7 @@ searxng.install.pyenv() {
info_msg "create pyenv in ${SEARXNG_PYENV}"
tee_stderr 0.1 <<EOF | sudo -H -u "${SERVICE_USER}" -i 2>&1 | prefix_stdout "$_service_prefix"
rm -rf "${SEARXNG_PYENV}"
python3 -m venv "${SEARXNG_PYENV}"
python -m venv "${SEARXNG_PYENV}"
grep -qFs -- 'source ${SEARXNG_PYENV}/bin/activate' ~/.profile \
|| echo 'source ${SEARXNG_PYENV}/bin/activate' >> ~/.profile
EOF
@ -505,7 +501,7 @@ pip install -U setuptools
pip install -U wheel
pip install -U pyyaml
cd ${SEARXNG_SRC}
pip install -e .
pip install --use-pep517 --no-build-isolation -e .
EOF
}
@ -573,7 +569,7 @@ pip install -U pip
pip install -U setuptools
pip install -U wheel
pip install -U pyyaml
pip install -U -e .
pip install -U --use-pep517 --no-build-isolation -e .
EOF
rst_para "update instance's settings.yml from ${SEARXNG_SETTINGS_PATH}"
DEFAULT_SELECT=2 \