]> git.openstreetmap.org Git - nominatim.git/commitdiff
Merge pull request #3093 from lonvia/remove-sanic
authorSarah Hoffmann <lonvia@denofr.de>
Thu, 22 Jun 2023 07:55:32 +0000 (09:55 +0200)
committerGitHub <noreply@github.com>
Thu, 22 Jun 2023 07:55:32 +0000 (09:55 +0200)
Remove support for Sanic

13 files changed:
.github/workflows/ci-tests.yml
docs/admin/Installation.md
docs/develop/Development-Environment.md
nominatim/api/search/icu_tokenizer.py
nominatim/api/search/legacy_tokenizer.py
nominatim/api/v1/helpers.py
nominatim/cli.py
nominatim/server/sanic/__init__.py [deleted file]
nominatim/server/sanic/server.py [deleted file]
test/bdd/steps/nominatim_environment.py
test/python/api/search/test_icu_query_analyzer.py
test/python/api/search/test_legacy_query_analyzer.py
test/python/cli/test_cli.py

index 44141e6c7bb6a88ad5c9e25583e32e1b6682997a..a22a89c06ae1c53d1ada2fefe9b3d6cf0a6034fe 100644 (file)
@@ -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
index e55e4b3752ea875f64367c02ce681b071044800a..61fc1bcee7c251a9072842466ba7398eb517f0f1 100644 (file)
@@ -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).
index 3234b8cbf3124574591b662606a406d7b75d27e3..d0369ea13839e5123128b4360e9fae8b21776807 100644 (file)
@@ -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
index 17e679057ecb5a4eb63daeb08f38e361f19a3ada..9bd16e1d85350de6d9879bd95af1c2d809f047b1 100644 (file)
@@ -248,12 +248,11 @@ class ICUQueryAnalyzer(AbstractQueryAnalyzer):
                        and (repl.ttype != qmod.TokenType.HOUSENUMBER
                             or len(tlist.tokens[0].lookup_word) > 4):
                         repl.add_penalty(0.39)
-            elif tlist.ttype == qmod.TokenType.HOUSENUMBER:
+            elif tlist.ttype == qmod.TokenType.HOUSENUMBER \
+                 and len(tlist.tokens[0].lookup_word) <= 3:
                 if any(c.isdigit() for c in tlist.tokens[0].lookup_word):
                     for repl in node.starting:
-                        if repl.end == tlist.end and repl.ttype != qmod.TokenType.HOUSENUMBER \
-                           and (repl.ttype != qmod.TokenType.HOUSENUMBER
-                                or len(tlist.tokens[0].lookup_word) <= 3):
+                        if repl.end == tlist.end and repl.ttype != qmod.TokenType.HOUSENUMBER:
                             repl.add_penalty(0.5 - tlist.tokens[0].penalty)
             elif tlist.ttype not in (qmod.TokenType.COUNTRY, qmod.TokenType.PARTIAL):
                 norm = parts[i].normalized
index 96975704f0ce996fc754a3130e0ebbfe2a1e0722..3346584ccd1b35b4e74e4725ee079cb54e45a905 100644 (file)
@@ -233,12 +233,11 @@ class LegacyQueryAnalyzer(AbstractQueryAnalyzer):
                        and (repl.ttype != qmod.TokenType.HOUSENUMBER
                             or len(tlist.tokens[0].lookup_word) > 4):
                         repl.add_penalty(0.39)
-            elif tlist.ttype == qmod.TokenType.HOUSENUMBER:
+            elif tlist.ttype == qmod.TokenType.HOUSENUMBER \
+                 and len(tlist.tokens[0].lookup_word) <= 3:
                 if any(c.isdigit() for c in tlist.tokens[0].lookup_word):
                     for repl in node.starting:
-                        if repl.end == tlist.end and repl.ttype != qmod.TokenType.HOUSENUMBER \
-                           and (repl.ttype != qmod.TokenType.HOUSENUMBER
-                                or len(tlist.tokens[0].lookup_word) <= 3):
+                        if repl.end == tlist.end and repl.ttype != qmod.TokenType.HOUSENUMBER:
                             repl.add_penalty(0.5 - tlist.tokens[0].penalty)
 
 
index 62e5e943441c1b526994a78d7f6bfd0557723ea8..ea7c125d7215540541bb81f4f02faeddfc592a86 100644 (file)
@@ -62,13 +62,13 @@ def extend_query_parts(queryparts: Dict[str, Any], details: Dict[str, Any],
     """
     parsed = SearchDetails.from_kwargs(details)
     if parsed.geometry_output != GeometryFormat.NONE:
-        if parsed.geometry_output & GeometryFormat.GEOJSON:
+        if GeometryFormat.GEOJSON in parsed.geometry_output:
             queryparts['polygon_geojson'] = '1'
-        if parsed.geometry_output & GeometryFormat.KML:
+        if GeometryFormat.KML in parsed.geometry_output:
             queryparts['polygon_kml'] = '1'
-        if parsed.geometry_output & GeometryFormat.SVG:
+        if GeometryFormat.SVG in parsed.geometry_output:
             queryparts['polygon_svg'] = '1'
-        if parsed.geometry_output & GeometryFormat.TEXT:
+        if GeometryFormat.TEXT in parsed.geometry_output:
             queryparts['polygon_text'] = '1'
     if parsed.address_details:
         queryparts['addressdetails'] = '1'
index 6a89a8de4b97d7b43c79444d78fe48451ec080e2..836f9037fd4b9b8916cf7d1563583d4d563e2f56 100644 (file)
@@ -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 (file)
index e69de29..0000000
diff --git a/nominatim/server/sanic/server.py b/nominatim/server/sanic/server.py
deleted file mode 100644 (file)
index 15887ee..0000000
+++ /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
index 64b62abaa88dc5ba0757e0130454534e339a4d4f..572c571a1318e18097311a8fa7c61f7aeedf8ae3 100644 (file)
@@ -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
index 78cd2c4d7beb2c2e13cf5b1634ef84d0ec2ae796..faf8137526106a0e5db77b325c0fa73f30b94a05 100644 (file)
@@ -118,10 +118,10 @@ async def test_penalty_postcodes_and_housenumbers(conn, term, order):
 
     assert query.num_token_slots() == 1
 
-    torder = [(tl.tokens[0].penalty, tl.ttype) for tl in query.nodes[0].starting]
+    torder = [(tl.tokens[0].penalty, tl.ttype.name) for tl in query.nodes[0].starting]
     torder.sort()
 
-    assert [t[1] for t in torder] == [TokenType[o] for o in order]
+    assert [t[1] for t in torder] == order
 
 @pytest.mark.asyncio
 async def test_category_words_only_at_beginning(conn):
index c21158531b3549ec4d54369ff587b7f377810f19..cdea6ede7cd842fa0c0f25b6915b8c0fcb2f0fe9 100644 (file)
@@ -195,11 +195,10 @@ async def test_penalty_postcodes_and_housenumbers(conn, term, order):
 
     assert query.num_token_slots() == 1
 
-    torder = [(tl.tokens[0].penalty, tl.ttype) for tl in query.nodes[0].starting]
-    print(query.nodes[0].starting)
+    torder = [(tl.tokens[0].penalty, tl.ttype.name) for tl in query.nodes[0].starting]
     torder.sort()
 
-    assert [t[1] for t in torder] == [TokenType[o] for o in order]
+    assert [t[1] for t in torder] == order
 
 
 @pytest.mark.asyncio
index d0e3307ebf93be5209e1102e2b7f3e6eac5e0315..f1bb75a97582a790e656746be82443201d178e98 100644 (file)
@@ -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")