allow None and str for project_dir in NominatimAPI init

This commit is contained in:
Sarah Hoffmann 2024-08-22 22:49:12 +02:00
parent f535340d5a
commit 7f11de0db9
8 changed files with 45 additions and 50 deletions

View 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.

View 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

View 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.
"""

View 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

View 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

View 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

View 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()

View 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