]> git.openstreetmap.org Git - nominatim.git/commitdiff
Merge pull request #3525 from lonvia/project-dir-less-library
authorSarah Hoffmann <lonvia@denofr.de>
Mon, 26 Aug 2024 11:54:35 +0000 (13:54 +0200)
committerGitHub <noreply@github.com>
Mon, 26 Aug 2024 11:54:35 +0000 (13:54 +0200)
Simplify handling of project directory for Nominatim library

src/nominatim_api/core.py
src/nominatim_db/config.py
src/nominatim_db/tools/convert_sqlite.py
test/python/api/conftest.py
test/python/api/search/test_icu_query_analyzer.py
test/python/api/search/test_legacy_query_analyzer.py
test/python/api/test_api_status.py
test/python/api/test_server_glue_v1.py

index ac5798625cc4900c8de1227892ce67da0716a0bd..ff0db39f820b51585abd3fd4723ee886a455027b 100644 (file)
@@ -7,7 +7,8 @@
 """
 Implementation of classes for API access via libraries.
 """
-from typing import Mapping, Optional, Any, AsyncIterator, Dict, Sequence, List, Tuple, cast
+from typing import Mapping, Optional, Any, AsyncIterator, Dict, Sequence, List,\
+                   Union, Tuple, cast
 import asyncio
 import sys
 import contextlib
@@ -41,7 +42,7 @@ class NominatimAPIAsync: #pylint: disable=too-many-instance-attributes
 
         This class should usually be used as a context manager in 'with' context.
     """
-    def __init__(self, project_dir: Path,
+    def __init__(self, project_dir: Optional[Union[str, Path]] = None,
                  environ: Optional[Mapping[str, str]] = None,
                  loop: Optional[asyncio.AbstractEventLoop] = None) -> None:
         """ Initiate a new frontend object with synchronous API functions.
@@ -365,7 +366,7 @@ class NominatimAPI:
         This class should usually be used as a context manager in 'with' context.
     """
 
-    def __init__(self, project_dir: Path,
+    def __init__(self, project_dir: Optional[Union[str, Path]] = None,
                  environ: Optional[Mapping[str, str]] = None) -> None:
         """ Initiate a new frontend object with synchronous API functions.
 
index 5ae3dea3b3ea8b14dfef655c0edf45e31aab6bdf..2cab02377593a6ce71286199105faf49e12732ff 100644 (file)
@@ -59,15 +59,17 @@ class Configuration:
         other than string.
     """
 
-    def __init__(self, project_dir: Optional[Path],
+    def __init__(self, project_dir: Optional[Union[Path, str]],
                  environ: Optional[Mapping[str, str]] = None) -> None:
         self.environ = environ or os.environ
-        self.project_dir = project_dir
         self.config_dir = paths.CONFIG_DIR
         self._config = dotenv_values(str(self.config_dir / 'env.defaults'))
-        if self.project_dir is not None and (self.project_dir / '.env').is_file():
-            self.project_dir = self.project_dir.resolve()
-            self._config.update(dotenv_values(str(self.project_dir / '.env')))
+        if project_dir is not None:
+            self.project_dir: Optional[Path] = Path(project_dir).resolve()
+            if (self.project_dir / '.env').is_file():
+                self._config.update(dotenv_values(str(self.project_dir / '.env')))
+        else:
+            self.project_dir = None
 
         class _LibDirs:
             module: Path
index 2377abc0b2be5dde5913a742eb5d5af7eac118f1..d53527d181f4f670e9028b0cf27869751e3a9bfa 100644 (file)
@@ -7,7 +7,7 @@
 """
 Exporting a Nominatim database to SQlite.
 """
-from typing import Set, Any
+from typing import Set, Any, Optional, Union
 import datetime as dt
 import logging
 from pathlib import Path
@@ -21,7 +21,8 @@ from nominatim_api.sql.sqlalchemy_types import Geometry, IntArray
 
 LOG = logging.getLogger()
 
-async def convert(project_dir: Path, outfile: Path, options: Set[str]) -> None:
+async def convert(project_dir: Optional[Union[str, Path]],
+                  outfile: Path, options: Set[str]) -> None:
     """ Export an existing database to sqlite. The resulting database
         will be usable against the Python frontend of Nominatim.
     """
index 0c770980acdada423eb2e8879503c53b744a1b01..3ca0720b4da24f76a76b0f30e3084af5e87d2802 100644 (file)
@@ -7,7 +7,6 @@
 """
 Helper fixtures for API call tests.
 """
-from pathlib import Path
 import pytest
 import pytest_asyncio
 import time
@@ -24,7 +23,7 @@ import nominatim_api.logging as loglib
 class APITester:
 
     def __init__(self):
-        self.api = napi.NominatimAPI(Path('/invalid'))
+        self.api = napi.NominatimAPI()
         self.async_to_sync(self.api._async_api.setup_database())
 
 
@@ -229,11 +228,9 @@ def frontend(request, event_loop, tmp_path):
 
             apiobj.async_to_sync(_do_sql())
 
-            event_loop.run_until_complete(convert_sqlite.convert(Path('/invalid'),
-                                                                 db, options))
-            outapi = napi.NominatimAPI(Path('/invalid'),
-                                       {'NOMINATIM_DATABASE_DSN': f"sqlite:dbname={db}",
-                                        'NOMINATIM_USE_US_TIGER_DATA': 'yes'})
+            event_loop.run_until_complete(convert_sqlite.convert(None, db, options))
+            outapi = napi.NominatimAPI(environ={'NOMINATIM_DATABASE_DSN': f"sqlite:dbname={db}",
+                                                'NOMINATIM_USE_US_TIGER_DATA': 'yes'})
             testapis.append(outapi)
 
             return outapi
@@ -249,5 +246,5 @@ def frontend(request, event_loop, tmp_path):
 
 @pytest_asyncio.fixture
 async def api(temp_db):
-    async with napi.NominatimAPIAsync(Path('/invalid')) as api:
+    async with napi.NominatimAPIAsync() as api:
         yield api
index 7f88879c14fd7d8c0a856997432bc64b007b2d96..473bc149de1fbf16959b64f7d2f4dd1b1c226a6e 100644 (file)
@@ -7,8 +7,6 @@
 """
 Tests for query analyzer for ICU tokenizer.
 """
-from pathlib import Path
-
 import pytest
 import pytest_asyncio
 
@@ -40,7 +38,7 @@ async def conn(table_factory):
     table_factory('word',
                   definition='word_id INT, word_token TEXT, type TEXT, word TEXT, info JSONB')
 
-    async with NominatimAPIAsync(Path('/invalid'), {}) as api:
+    async with NominatimAPIAsync(environ={}) as api:
         async with api.begin() as conn:
             yield conn
 
index 0e967c10fa5f8e062825fc19e491352eee087bb1..a99485ead17c95071ec7a280611b96c1bfbe2bf8 100644 (file)
@@ -7,8 +7,6 @@
 """
 Tests for query analyzer for legacy tokenizer.
 """
-from pathlib import Path
-
 import pytest
 import pytest_asyncio
 
@@ -74,7 +72,7 @@ async def conn(table_factory, temp_db_cursor):
     temp_db_cursor.execute("""CREATE OR REPLACE FUNCTION make_standard_name(name TEXT)
                               RETURNS TEXT AS $$ SELECT lower(name); $$ LANGUAGE SQL;""")
 
-    async with NominatimAPIAsync(Path('/invalid'), {}) as api:
+    async with NominatimAPIAsync(environ={}) as api:
         async with api.begin() as conn:
             yield conn
 
index 5412ca6e334fad5f8932379a274a7f65284182d2..29eb34d0c9a8b82a7ab6d66e92b5199e7d3c7569 100644 (file)
@@ -7,7 +7,6 @@
 """
 Tests for the status API call.
 """
-from pathlib import Path
 import datetime as dt
 import pytest
 
@@ -46,7 +45,7 @@ def test_status_full(apiobj, frontend):
 def test_status_database_not_found(monkeypatch):
     monkeypatch.setenv('NOMINATIM_DATABASE_DSN', 'dbname=rgjdfkgjedkrgdfkngdfkg')
 
-    api = napi.NominatimAPI(Path('/invalid'), {})
+    api = napi.NominatimAPI(environ={})
 
     result = api.status()
 
index 5ef169045e0a4712c256bf38d2634a4bbae6e146..6ea790c060b21c740c3ff2e985adeb4bf51ba3b5 100644 (file)
@@ -9,7 +9,6 @@ Tests for the Python web frameworks adaptor, v1 API.
 """
 import json
 import xml.etree.ElementTree as ET
-from pathlib import Path
 
 import pytest
 
@@ -242,7 +241,7 @@ class TestStatusEndpoint:
         a = FakeAdaptor()
         self.status = napi.StatusResult(0, 'foo')
 
-        resp = await glue.status_endpoint(napi.NominatimAPIAsync(Path('/invalid')), a)
+        resp = await glue.status_endpoint(napi.NominatimAPIAsync(), a)
 
         assert isinstance(resp, FakeResponse)
         assert resp.status == 200
@@ -254,7 +253,7 @@ class TestStatusEndpoint:
         a = FakeAdaptor()
         self.status = napi.StatusResult(405, 'foo')
 
-        resp = await glue.status_endpoint(napi.NominatimAPIAsync(Path('/invalid')), a)
+        resp = await glue.status_endpoint(napi.NominatimAPIAsync(), a)
 
         assert isinstance(resp, FakeResponse)
         assert resp.status == 500
@@ -266,7 +265,7 @@ class TestStatusEndpoint:
         a = FakeAdaptor(params={'format': 'json'})
         self.status = napi.StatusResult(405, 'foo')
 
-        resp = await glue.status_endpoint(napi.NominatimAPIAsync(Path('/invalid')), a)
+        resp = await glue.status_endpoint(napi.NominatimAPIAsync(), a)
 
         assert isinstance(resp, FakeResponse)
         assert resp.status == 200
@@ -279,7 +278,7 @@ class TestStatusEndpoint:
         self.status = napi.StatusResult(0, 'foo')
 
         with pytest.raises(FakeError):
-            await glue.status_endpoint(napi.NominatimAPIAsync(Path('/invalid')), a)
+            await glue.status_endpoint(napi.NominatimAPIAsync(), a)
 
 
 # details_endpoint()
@@ -305,14 +304,14 @@ class TestDetailsEndpoint:
         a = FakeAdaptor()
 
         with pytest.raises(FakeError, match='^400 -- .*Missing'):
-            await glue.details_endpoint(napi.NominatimAPIAsync(Path('/invalid')), a)
+            await glue.details_endpoint(napi.NominatimAPIAsync(), a)
 
 
     @pytest.mark.asyncio
     async def test_details_by_place_id(self):
         a = FakeAdaptor(params={'place_id': '4573'})
 
-        await glue.details_endpoint(napi.NominatimAPIAsync(Path('/invalid')), a)
+        await glue.details_endpoint(napi.NominatimAPIAsync(), a)
 
         assert self.lookup_args[0].place_id == 4573
 
@@ -321,7 +320,7 @@ class TestDetailsEndpoint:
     async def test_details_by_osm_id(self):
         a = FakeAdaptor(params={'osmtype': 'N', 'osmid': '45'})
 
-        await glue.details_endpoint(napi.NominatimAPIAsync(Path('/invalid')), a)
+        await glue.details_endpoint(napi.NominatimAPIAsync(), a)
 
         assert self.lookup_args[0].osm_type == 'N'
         assert self.lookup_args[0].osm_id == 45
@@ -332,7 +331,7 @@ class TestDetailsEndpoint:
     async def test_details_with_debugging(self):
         a = FakeAdaptor(params={'osmtype': 'N', 'osmid': '45', 'debug': '1'})
 
-        resp = await glue.details_endpoint(napi.NominatimAPIAsync(Path('/invalid')), a)
+        resp = await glue.details_endpoint(napi.NominatimAPIAsync(), a)
         content = ET.fromstring(resp.output)
 
         assert resp.content_type == 'text/html; charset=utf-8'
@@ -345,7 +344,7 @@ class TestDetailsEndpoint:
         self.result = None
 
         with pytest.raises(FakeError, match='^404 -- .*found'):
-            await glue.details_endpoint(napi.NominatimAPIAsync(Path('/invalid')), a)
+            await glue.details_endpoint(napi.NominatimAPIAsync(), a)
 
 
 # reverse_endpoint()
@@ -370,7 +369,7 @@ class TestReverseEndPoint:
         a.params['format'] = 'xml'
 
         with pytest.raises(FakeError, match='^400 -- (?s:.*)missing'):
-            await glue.reverse_endpoint(napi.NominatimAPIAsync(Path('/invalid')), a)
+            await glue.reverse_endpoint(napi.NominatimAPIAsync(), a)
 
 
     @pytest.mark.asyncio
@@ -380,7 +379,7 @@ class TestReverseEndPoint:
         a.params = params
         a.params['format'] = 'json'
 
-        res = await glue.reverse_endpoint(napi.NominatimAPIAsync(Path('/invalid')), a)
+        res = await glue.reverse_endpoint(napi.NominatimAPIAsync(), a)
 
         assert res == ''
 
@@ -391,7 +390,7 @@ class TestReverseEndPoint:
         a.params['lat'] = '56.3'
         a.params['lon'] = '6.8'
 
-        assert await glue.reverse_endpoint(napi.NominatimAPIAsync(Path('/invalid')), a)
+        assert await glue.reverse_endpoint(napi.NominatimAPIAsync(), a)
 
 
     @pytest.mark.asyncio
@@ -400,7 +399,7 @@ class TestReverseEndPoint:
         a.params['q'] = '34.6 2.56'
         a.params['format'] = 'json'
 
-        res = await glue.search_endpoint(napi.NominatimAPIAsync(Path('/invalid')), a)
+        res = await glue.search_endpoint(napi.NominatimAPIAsync(), a)
 
         assert len(json.loads(res.output)) == 1
 
@@ -425,7 +424,7 @@ class TestLookupEndpoint:
         a = FakeAdaptor()
         a.params['format'] = 'json'
 
-        res = await glue.lookup_endpoint(napi.NominatimAPIAsync(Path('/invalid')), a)
+        res = await glue.lookup_endpoint(napi.NominatimAPIAsync(), a)
 
         assert res.output == '[]'
 
@@ -437,7 +436,7 @@ class TestLookupEndpoint:
         a.params['format'] = 'json'
         a.params['osm_ids'] = f'W34,{param},N33333'
 
-        res = await glue.lookup_endpoint(napi.NominatimAPIAsync(Path('/invalid')), a)
+        res = await glue.lookup_endpoint(napi.NominatimAPIAsync(), a)
 
         assert len(json.loads(res.output)) == 1
 
@@ -449,7 +448,7 @@ class TestLookupEndpoint:
         a.params['format'] = 'json'
         a.params['osm_ids'] = f'W34,{param},N33333'
 
-        res = await glue.lookup_endpoint(napi.NominatimAPIAsync(Path('/invalid')), a)
+        res = await glue.lookup_endpoint(napi.NominatimAPIAsync(), a)
 
         assert len(json.loads(res.output)) == 1
 
@@ -460,7 +459,7 @@ class TestLookupEndpoint:
         a.params['format'] = 'json'
         a.params['osm_ids'] = 'N23,W34'
 
-        res = await glue.lookup_endpoint(napi.NominatimAPIAsync(Path('/invalid')), a)
+        res = await glue.lookup_endpoint(napi.NominatimAPIAsync(), a)
 
         assert len(json.loads(res.output)) == 1
 
@@ -485,7 +484,7 @@ class TestSearchEndPointSearch:
         a = FakeAdaptor()
         a.params['q'] = 'something'
 
-        res = await glue.search_endpoint(napi.NominatimAPIAsync(Path('/invalid')), a)
+        res = await glue.search_endpoint(napi.NominatimAPIAsync(), a)
 
         assert len(json.loads(res.output)) == 1
 
@@ -496,7 +495,7 @@ class TestSearchEndPointSearch:
         a.params['q'] = 'something'
         a.params['format'] = 'xml'
 
-        res = await glue.search_endpoint(napi.NominatimAPIAsync(Path('/invalid')), a)
+        res = await glue.search_endpoint(napi.NominatimAPIAsync(), a)
 
         assert res.status == 200
         assert res.output.index('something') > 0
@@ -509,7 +508,7 @@ class TestSearchEndPointSearch:
         a.params['city'] = 'ignored'
 
         with pytest.raises(FakeError, match='^400 -- .*cannot be used together'):
-            res = await glue.search_endpoint(napi.NominatimAPIAsync(Path('/invalid')), a)
+            res = await glue.search_endpoint(napi.NominatimAPIAsync(), a)
 
 
     @pytest.mark.asyncio
@@ -521,7 +520,7 @@ class TestSearchEndPointSearch:
         if not dedupe:
             a.params['dedupe'] = '0'
 
-        res = await glue.search_endpoint(napi.NominatimAPIAsync(Path('/invalid')), a)
+        res = await glue.search_endpoint(napi.NominatimAPIAsync(), a)
 
         assert len(json.loads(res.output)) == numres
 
@@ -544,7 +543,7 @@ class TestSearchEndPointSearchAddress:
         a = FakeAdaptor()
         a.params['street'] = 'something'
 
-        res = await glue.search_endpoint(napi.NominatimAPIAsync(Path('/invalid')), a)
+        res = await glue.search_endpoint(napi.NominatimAPIAsync(), a)
 
         assert len(json.loads(res.output)) == 1
 
@@ -567,6 +566,6 @@ class TestSearchEndPointSearchCategory:
         a = FakeAdaptor()
         a.params['q'] = '[shop=fog]'
 
-        res = await glue.search_endpoint(napi.NominatimAPIAsync(Path('/invalid')), a)
+        res = await glue.search_endpoint(napi.NominatimAPIAsync(), a)
 
         assert len(json.loads(res.output)) == 1