From: Sarah Hoffmann Date: Wed, 21 Jun 2023 08:53:57 +0000 (+0200) Subject: remove support for sanic framework X-Git-Tag: v4.3.0~63^2~2 X-Git-Url: https://git.openstreetmap.org./nominatim.git/commitdiff_plain/b79d5494f915b1b1e1dc4ce12b80680f0b7c53b3?hp=--cc remove support for sanic framework There is no performance gain over falcon or starlette but the special structure of sanic makes it hard to have exchangable code --- b79d5494f915b1b1e1dc4ce12b80680f0b7c53b3 diff --git a/.github/workflows/ci-tests.yml b/.github/workflows/ci-tests.yml index 44141e6c..a22a89c0 100644 --- a/.github/workflows/ci-tests.yml +++ b/.github/workflows/ci-tests.yml @@ -113,7 +113,7 @@ jobs: if: matrix.flavour == 'oldstuff' - name: Install Python webservers - run: pip3 install falcon sanic sanic-testing sanic-cors starlette + run: pip3 install falcon starlette - name: Install latest pylint run: pip3 install -U pylint asgi_lifespan diff --git a/docs/admin/Installation.md b/docs/admin/Installation.md index e55e4b37..61fc1bce 100644 --- a/docs/admin/Installation.md +++ b/docs/admin/Installation.md @@ -67,9 +67,8 @@ For running the experimental Python frontend: * one of the following web frameworks: * [falcon](https://falconframework.org/) (3.0+) - * [sanic](https://sanic.dev) and (optionally) [sanic-cors](https://github.com/ashleysommer/sanic-cors) * [starlette](https://www.starlette.io/) - * [uvicorn](https://www.uvicorn.org/) (only with falcon and starlette framworks) + * [uvicorn](https://www.uvicorn.org/) For dependencies for running tests and building documentation, see the [Development section](../develop/Development-Environment.md). diff --git a/docs/develop/Development-Environment.md b/docs/develop/Development-Environment.md index 3234b8cb..d0369ea1 100644 --- a/docs/develop/Development-Environment.md +++ b/docs/develop/Development-Environment.md @@ -41,7 +41,6 @@ It has the following additional requirements: For testing the Python search frontend, you need to install extra dependencies depending on your choice of webserver framework: -* [sanic-testing](https://sanic.dev/en/plugins/sanic-testing/getting-started.html) (sanic only) * [httpx](https://www.python-httpx.org/) (starlette only) * [asgi-lifespan](https://github.com/florimondmanca/asgi-lifespan) (starlette only) @@ -66,7 +65,7 @@ sudo apt install php-cgi phpunit php-codesniffer \ pip3 install --user behave mkdocs mkdocstrings pytest pytest-asyncio pylint \ mypy types-PyYAML types-jinja2 types-psycopg2 types-psutil \ types-ujson types-requests types-Pygments typing-extensions\ - sanic-testing httpx asgi-lifespan + httpx asgi-lifespan ``` The `mkdocs` executable will be located in `.local/bin`. You may have to add diff --git a/nominatim/cli.py b/nominatim/cli.py index 6a89a8de..836f9037 100644 --- a/nominatim/cli.py +++ b/nominatim/cli.py @@ -215,7 +215,7 @@ class AdminServe: group.add_argument('--server', default='127.0.0.1:8088', help='The address the server will listen to.') group.add_argument('--engine', default='php', - choices=('php', 'sanic', 'falcon', 'starlette'), + choices=('php', 'falcon', 'starlette'), help='Webserver framework to run. (default: php)') @@ -223,6 +223,7 @@ class AdminServe: if args.engine == 'php': run_php_server(args.server, args.project_dir / 'website') else: + import uvicorn # pylint: disable=import-outside-toplevel server_info = args.server.split(':', 1) host = server_info[0] if len(server_info) > 1: @@ -232,21 +233,10 @@ class AdminServe: else: port = 8088 - if args.engine == 'sanic': - server_module = importlib.import_module('nominatim.server.sanic.server') + server_module = importlib.import_module(f'nominatim.server.{args.engine}.server') - app = server_module.get_application(args.project_dir) - app.run(host=host, port=port, debug=True, single_process=True) - else: - import uvicorn # pylint: disable=import-outside-toplevel - - if args.engine == 'falcon': - server_module = importlib.import_module('nominatim.server.falcon.server') - elif args.engine == 'starlette': - server_module = importlib.import_module('nominatim.server.starlette.server') - - app = server_module.get_application(args.project_dir) - uvicorn.run(app, host=host, port=port) + app = server_module.get_application(args.project_dir) + uvicorn.run(app, host=host, port=port) return 0 diff --git a/nominatim/server/sanic/__init__.py b/nominatim/server/sanic/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/nominatim/server/sanic/server.py b/nominatim/server/sanic/server.py deleted file mode 100644 index 15887eef..00000000 --- a/nominatim/server/sanic/server.py +++ /dev/null @@ -1,78 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# -# This file is part of Nominatim. (https://nominatim.org) -# -# Copyright (C) 2023 by the Nominatim developer community. -# For a full list of authors see the git log. -""" -Server implementation using the sanic webserver framework. -""" -from typing import Any, Optional, Mapping, Callable, cast, Coroutine -from pathlib import Path - -from sanic import Request, HTTPResponse, Sanic -from sanic.exceptions import SanicException -from sanic.response import text as TextResponse - -from nominatim.api import NominatimAPIAsync -import nominatim.api.v1 as api_impl -from nominatim.config import Configuration - -class ParamWrapper(api_impl.ASGIAdaptor): - """ Adaptor class for server glue to Sanic framework. - """ - - def __init__(self, request: Request) -> None: - self.request = request - - - def get(self, name: str, default: Optional[str] = None) -> Optional[str]: - return cast(Optional[str], self.request.args.get(name, default)) - - - def get_header(self, name: str, default: Optional[str] = None) -> Optional[str]: - return cast(Optional[str], self.request.headers.get(name, default)) - - - def error(self, msg: str, status: int = 400) -> SanicException: - exception = SanicException(msg, status_code=status) - - return exception - - - def create_response(self, status: int, output: str) -> HTTPResponse: - return TextResponse(output, status=status, content_type=self.content_type) - - - def config(self) -> Configuration: - return cast(Configuration, self.request.app.ctx.api.config) - - -def _wrap_endpoint(func: api_impl.EndpointFunc)\ - -> Callable[[Request], Coroutine[Any, Any, HTTPResponse]]: - async def _callback(request: Request) -> HTTPResponse: - return cast(HTTPResponse, await func(request.app.ctx.api, ParamWrapper(request))) - - return _callback - - -def get_application(project_dir: Path, - environ: Optional[Mapping[str, str]] = None) -> Sanic: - """ Create a Nominatim sanic ASGI application. - """ - app = Sanic("NominatimInstance") - - app.ctx.api = NominatimAPIAsync(project_dir, environ) - - if app.ctx.api.config.get_bool('CORS_NOACCESSCONTROL'): - from sanic_cors import CORS # pylint: disable=import-outside-toplevel - CORS(app) - - legacy_urls = app.ctx.api.config.get_bool('SERVE_LEGACY_URLS') - for name, func in api_impl.ROUTES: - endpoint = _wrap_endpoint(func) - app.add_route(endpoint, f"/{name}", name=f"v1_{name}_simple") - if legacy_urls: - app.add_route(endpoint, f"/{name}.php", name=f"v1_{name}_legacy") - - return app diff --git a/test/bdd/steps/nominatim_environment.py b/test/bdd/steps/nominatim_environment.py index 64b62aba..572c571a 100644 --- a/test/bdd/steps/nominatim_environment.py +++ b/test/bdd/steps/nominatim_environment.py @@ -350,20 +350,6 @@ class NominatimEnvironment: return _request - def create_api_request_func_sanic(self): - import nominatim.server.sanic.server - - async def _request(endpoint, params, project_dir, environ, http_headers): - app = nominatim.server.sanic.server.get_application(project_dir, environ) - - _, response = await app.asgi_client.get(f"/{endpoint}", params=params, - headers=http_headers) - - return response.text, response.status_code - - return _request - - def create_api_request_func_falcon(self): import nominatim.server.falcon.server import falcon.testing diff --git a/test/python/cli/test_cli.py b/test/python/cli/test_cli.py index d0e3307e..f1bb75a9 100644 --- a/test/python/cli/test_cli.py +++ b/test/python/cli/test_cli.py @@ -68,15 +68,6 @@ def test_cli_serve_php(cli_call, mock_func_factory): assert func.called == 1 -def test_cli_serve_sanic(cli_call, mock_func_factory): - mod = pytest.importorskip("sanic") - func = mock_func_factory(mod.Sanic, "run") - - cli_call('serve', '--engine', 'sanic') == 0 - - assert func.called == 1 - - def test_cli_serve_starlette_custom_server(cli_call, mock_func_factory): pytest.importorskip("starlette") mod = pytest.importorskip("uvicorn")