diff --git a/Makefile b/Makefile index 73cfccd8a..4d9331268 100644 --- a/Makefile +++ b/Makefile @@ -47,7 +47,7 @@ search.checker.%: install $(Q)./manage pyenv.cmd searxng-checker -v "$(subst _, ,$(patsubst search.checker.%,%,$@))" PHONY += test ci.test test.shell -test: test.yamllint test.black test.pyright test.pylint test.unit test.robot test.rst test.shell test.shfmt +test: test.yamllint test.black test.pyright_modified test.pylint test.unit test.robot test.rst test.shell test.shfmt ci.test: test test.pybabel test.shell: $(Q)shellcheck -x -s dash \ @@ -80,7 +80,7 @@ MANAGE += node.env node.env.dev node.clean MANAGE += py.build py.clean MANAGE += pyenv pyenv.install pyenv.uninstall MANAGE += format.python format.shell -MANAGE += test.yamllint test.pylint test.black test.pybabel test.unit test.coverage test.robot test.rst test.clean test.themes test.pyright test.shfmt +MANAGE += test.yamllint test.pylint test.black test.pybabel test.unit test.coverage test.robot test.rst test.clean test.themes test.pyright test.pyright_modified test.shfmt MANAGE += themes.all themes.simple themes.simple.analyze themes.fix themes.lint themes.test MANAGE += static.build.commit static.build.drop static.build.restore MANAGE += nvm.install nvm.clean nvm.status nvm.nodejs diff --git a/package.json b/package.json index 790ab8648..37e3fadb1 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,6 @@ "name": "searxng.org/devtools", "type": "module", "dependencies": { - "pyright": "^1.1.403" }, "scripts": { "clean": "rm -Rf node_modules package-lock.json" diff --git a/pyrightconfig.json b/pyrightconfig.json index 56573c75f..5739cd986 100644 --- a/pyrightconfig.json +++ b/pyrightconfig.json @@ -1,9 +1,48 @@ { - "venvPath": "local", - "venv": "py3", - "include": [ - "searx", - "searxng_extra", - "tests" - ] + "venvPath": "local", + "venv": "py3", + "include": [ + "searx", + "searxng_extra", + "tests" + ], + "reportAny" : "information", + "enableTypeIgnoreComments": true, + "reportIgnoreCommentWithoutRule": true, + "reportImplicitStringConcatenation": false, + "reportUninitializedInstanceVariable": false, + "reportUnnecessaryIsInstance": false, + "reportUnreachable": "information", + "reportUnusedCallResult": false, + "executionEnvironments": [ + { + "root": "searx", + "extraPaths": ["."] + }, + { + "root": "searxng_extra", + "extraPaths": ["."], + "reportAny" : false, + "reportUnknownMemberType": false, + "reportUnknownVariableType": false + }, + { + "root": "tests", + "extraPaths": ["."], + "reportAny" : false, + "reportImplicitOverride": false, + "reportMissingParameterType": false, + "reportMissingTypeArgument": false, + "reportMissingTypeStubs": false, + "reportPrivateLocalImportUsage": false, + "reportPrivateUsage": false, + "reportUnannotatedClassAttribute": false, + "reportUnknownArgumentType": false, + "reportUnknownLambdaType": false, + "reportUnknownMemberType": false, + "reportUnknownParameterType": false, + "reportUnknownVariableType": false, + "reportUnusedParameter": false + } + ] } diff --git a/requirements-dev.txt b/requirements-dev.txt index ea97688b8..5e6012322 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -22,3 +22,4 @@ coloredlogs==15.0.1 docutils>=0.21.2 parameterized==0.9.0 granian[reload]==2.5.0 +basedpyright==1.31.0 diff --git a/searx/enginelib/__init__.py b/searx/enginelib/__init__.py index 9cb49c0cd..3fa4edabb 100644 --- a/searx/enginelib/__init__.py +++ b/searx/enginelib/__init__.py @@ -252,7 +252,7 @@ class Engine: # pylint: disable=too-few-public-methods display_error_messages: bool """Display error messages on the web UI.""" - proxies: dict + proxies: dict[str, dict[str, str]] """Set proxies for a specific engine (YAML): .. code:: yaml diff --git a/searx/engines/__builtins__.pyi b/searx/engines/__builtins__.pyi new file mode 100644 index 000000000..c9c328b0c --- /dev/null +++ b/searx/engines/__builtins__.pyi @@ -0,0 +1,43 @@ +# SPDX-License-Identifier: AGPL-3.0-or-later +"""The builtin types that are added to the global namespace of a module by the +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. +""" +from __future__ import annotations + +import logging + +logger: logging.Logger +supported_languages: str +language_aliases: str + +# from searx.engines.ENGINE_DEFAULT_ARGS +about: dict[str, dict[str, str | None | bool]] +categories: list[str] +disabled: bool +display_error_messages: bool +enable_http: bool +engine_type: str +inactive: bool +max_page: int +paging: int +safesearch: int +send_accept_language_header: bool +shortcut: str +time_range_support: int +timeout: int +tokens: list[str] +using_tor_proxy: bool + +# from searx.engines.check_engine_module +network: str + +# from searx.engines.update_attributes_for_tor +search_url: str diff --git a/searx/engines/__init__.py b/searx/engines/__init__.py index bcbdbe8aa..1138668dd 100644 --- a/searx/engines/__init__.py +++ b/searx/engines/__init__.py @@ -9,24 +9,26 @@ usage:: """ from __future__ import annotations +import typing as t import sys import copy from os.path import realpath, dirname -from typing import TYPE_CHECKING, Dict import types import inspect from searx import logger, settings from searx.utils import load_module -if TYPE_CHECKING: +if t.TYPE_CHECKING: from searx.enginelib import Engine logger = logger.getChild('engines') ENGINE_DIR = dirname(realpath(__file__)) -ENGINE_DEFAULT_ARGS = { + +# 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] = { # Common options in the engine module "engine_type": "online", "paging": False, @@ -49,11 +51,8 @@ ENGINE_DEFAULT_ARGS = { # set automatically when an engine does not have any tab category DEFAULT_CATEGORY = 'other' - -# Defaults for the namespace of an engine module, see :py:func:`load_engine` - -categories = {'general': []} -engines: Dict[str, Engine | types.ModuleType] = {} +categories: dict[str, list[str]] = {'general': []} +engines: dict[str, Engine | types.ModuleType] = {} engine_shortcuts = {} """Simple map of registered *shortcuts* to name of the engine (or ``None``). @@ -77,7 +76,7 @@ def check_engine_module(module: types.ModuleType): raise TypeError(msg) -def load_engine(engine_data: dict) -> Engine | types.ModuleType | None: +def load_engine(engine_data: dict[str, t.Any]) -> Engine | types.ModuleType | None: """Load engine from ``engine_data``. :param dict engine_data: Attributes from YAML ``settings:engines/`` diff --git a/utils/lib_sxng_test.sh b/utils/lib_sxng_test.sh index 0248c3125..22a655722 100755 --- a/utils/lib_sxng_test.sh +++ b/utils/lib_sxng_test.sh @@ -51,25 +51,32 @@ test.pylint() { } test.pyright() { - # use this pyright test for local tests in development / it suppress - # warnings related to intentional monkey patching but gives good hints where - # we need to work on SearXNG's typification. + # For integration into your IDE (editor) use the basedpyright-langserver + # (LSP) installed by 'pipx basedpyright' and read: + # + # - https://docs.basedpyright.com/latest/installation/ides/ + # + # The $REPO_ROOT/pyrightconfig.json uses the virtualenv found in + # $REPO_ROOT/local/py3 and create by a 'make pyenv' - build_msg TEST "[pyright/types] static type check of python sources" - node.env.dev + build_msg TEST "[basedpyright] static type check of python sources" + LANG=C pyenv.cmd basedpyright + # ignore exit value from basedpyright + # dump_return $? + return 0 +} - build_msg TEST "[pyright/types] suppress warnings related to intentional monkey patching" - # We run Pyright in the virtual environment because pyright executes - # "python" to determine the Python version. - pyenv.cmd npx --no-install pyright -p pyrightconfig.json | - grep -E '\.py:[0-9]+:[0-9]+' | - grep -v '/engines/.*.py.* - warning: "logger" is not defined' | - grep -v '/plugins/.*.py.* - error: "logger" is not defined' | - grep -v '/engines/.*.py.* - warning: "supported_languages" is not defined' | - grep -v '/engines/.*.py.* - warning: "language_aliases" is not defined' | - grep -v '/engines/.*.py.* - warning: "categories" is not defined' - # ignore exit value from pyright - # dump_return ${PIPESTATUS[0]} +test.pyright_modified() { + build_msg TEST "[basedpyright] static type check of local modified files" + local pyrigth_files=() + readarray -t pyrigth_files < <(git status --porcelain | awk 'match($2,".py[i]*$") {print $2}') + if [ ${#pyrigth_files[@]} -eq 0 ]; then + echo "there are no locally modified python files that could be checked" + else + pyenv.cmd basedpyright "${pyrigth_files[@]}" + fi + # ignore exit value from basedpyright + # dump_return $? return 0 }