rename lookup() API to details and add lookup call

The initial plan to serve /details and /lookup endpoints from
the same API call turned out to be impractical, so the API now
also has deparate functions for both.
This commit is contained in:
Sarah Hoffmann 2023-04-03 11:11:11 +02:00
parent 4607c7ed04
commit 6e81596609
6 changed files with 53 additions and 31 deletions

View File

@ -7,7 +7,7 @@
"""
Implementation of classes for API access via libraries.
"""
from typing import Mapping, Optional, Any, AsyncIterator, Dict
from typing import Mapping, Optional, Any, AsyncIterator, Dict, Sequence
import asyncio
import contextlib
from pathlib import Path
@ -20,10 +20,10 @@ from nominatim.db.sqlalchemy_schema import SearchTables
from nominatim.config import Configuration
from nominatim.api.connection import SearchConnection
from nominatim.api.status import get_status, StatusResult
from nominatim.api.lookup import get_detailed_place
from nominatim.api.lookup import get_detailed_place, get_simple_place
from nominatim.api.reverse import ReverseGeocoder
from nominatim.api.types import PlaceRef, LookupDetails, AnyPoint, DataLayer
from nominatim.api.results import DetailedResult, ReverseResult
from nominatim.api.results import DetailedResult, ReverseResult, SearchResults
class NominatimAPIAsync:
@ -130,8 +130,8 @@ class NominatimAPIAsync:
return status
async def lookup(self, place: PlaceRef,
details: Optional[LookupDetails] = None) -> Optional[DetailedResult]:
async def details(self, place: PlaceRef,
details: Optional[LookupDetails] = None) -> Optional[DetailedResult]:
""" Get detailed information about a place in the database.
Returns None if there is no entry under the given ID.
@ -140,6 +140,19 @@ class NominatimAPIAsync:
return await get_detailed_place(conn, place, details or LookupDetails())
async def lookup(self, places: Sequence[PlaceRef],
details: Optional[LookupDetails] = None) -> SearchResults:
""" Get simple information about a list of places.
Returns a list of place information for all IDs that were found.
"""
if details is None:
details = LookupDetails()
async with self.begin() as conn:
return SearchResults(filter(None,
[await get_simple_place(conn, p, details) for p in places]))
async def reverse(self, coord: AnyPoint, max_rank: Optional[int] = None,
layer: Optional[DataLayer] = None,
details: Optional[LookupDetails] = None) -> Optional[ReverseResult]:
@ -195,11 +208,20 @@ class NominatimAPI:
return self._loop.run_until_complete(self._async_api.status())
def lookup(self, place: PlaceRef,
details: Optional[LookupDetails] = None) -> Optional[DetailedResult]:
def details(self, place: PlaceRef,
details: Optional[LookupDetails] = None) -> Optional[DetailedResult]:
""" Get detailed information about a place in the database.
"""
return self._loop.run_until_complete(self._async_api.lookup(place, details))
return self._loop.run_until_complete(self._async_api.details(place, details))
def lookup(self, places: Sequence[PlaceRef],
details: Optional[LookupDetails] = None) -> SearchResults:
""" Get simple information about a list of places.
Returns a list of place information for all IDs that were found.
"""
return self._loop.run_until_complete(self._async_api.lookup(places, details))
def reverse(self, coord: AnyPoint, max_rank: Optional[int] = None,

View File

@ -268,7 +268,7 @@ async def details_endpoint(api: napi.NominatimAPIAsync, params: ASGIAdaptor) ->
locales = napi.Locales.from_accept_languages(params.get_accepted_languages())
result = await api.lookup(place, details)
result = await api.details(place, details)
if debug:
return params.build_response(loglib.get_and_disable())

View File

@ -292,7 +292,7 @@ class APIDetails:
if args.polygon_geojson:
details.geometry_output = napi.GeometryFormat.GEOJSON
result = api.lookup(place, details)
result = api.details(place, details)
if result:
output = api_output.format_result(

View File

@ -31,7 +31,7 @@ def test_lookup_in_placex(apiobj, idobj):
indexed_date=import_date,
geometry='LINESTRING(23 34, 23.1 34, 23.1 34.1, 23 34)')
result = apiobj.api.lookup(idobj, napi.LookupDetails())
result = apiobj.api.details(idobj, napi.LookupDetails())
assert result is not None
@ -79,7 +79,7 @@ def test_lookup_in_placex_minimal_info(apiobj):
indexed_date=import_date,
geometry='LINESTRING(23 34, 23.1 34, 23.1 34.1, 23 34)')
result = apiobj.api.lookup(napi.PlaceID(332), napi.LookupDetails())
result = apiobj.api.details(napi.PlaceID(332), napi.LookupDetails())
assert result is not None
@ -121,7 +121,7 @@ def test_lookup_in_placex_with_geometry(apiobj):
apiobj.add_placex(place_id=332,
geometry='LINESTRING(23 34, 23.1 34)')
result = apiobj.api.lookup(napi.PlaceID(332),
result = apiobj.api.details(napi.PlaceID(332),
napi.LookupDetails(geometry_output=napi.GeometryFormat.GEOJSON))
assert result.geometry == {'geojson': '{"type":"LineString","coordinates":[[23,34],[23.1,34]]}'}
@ -144,7 +144,7 @@ def test_lookup_placex_with_address_details(apiobj):
country_code='pl',
rank_search=17, rank_address=16)
result = apiobj.api.lookup(napi.PlaceID(332),
result = apiobj.api.details(napi.PlaceID(332),
napi.LookupDetails(address_details=True))
assert result.address_rows == [
@ -177,7 +177,7 @@ def test_lookup_place_with_linked_places_none_existing(apiobj):
country_code='pl', linked_place_id=45,
rank_search=27, rank_address=26)
result = apiobj.api.lookup(napi.PlaceID(332),
result = apiobj.api.details(napi.PlaceID(332),
napi.LookupDetails(linked_places=True))
assert result.linked_rows == []
@ -197,7 +197,7 @@ def test_lookup_place_with_linked_places_existing(apiobj):
country_code='pl', linked_place_id=332,
rank_search=27, rank_address=26)
result = apiobj.api.lookup(napi.PlaceID(332),
result = apiobj.api.details(napi.PlaceID(332),
napi.LookupDetails(linked_places=True))
assert result.linked_rows == [
@ -220,7 +220,7 @@ def test_lookup_place_with_parented_places_not_existing(apiobj):
country_code='pl', parent_place_id=45,
rank_search=27, rank_address=26)
result = apiobj.api.lookup(napi.PlaceID(332),
result = apiobj.api.details(napi.PlaceID(332),
napi.LookupDetails(parented_places=True))
assert result.parented_rows == []
@ -240,7 +240,7 @@ def test_lookup_place_with_parented_places_existing(apiobj):
country_code='pl', parent_place_id=332,
rank_search=27, rank_address=26)
result = apiobj.api.lookup(napi.PlaceID(332),
result = apiobj.api.details(napi.PlaceID(332),
napi.LookupDetails(parented_places=True))
assert result.parented_rows == [
@ -263,7 +263,7 @@ def test_lookup_in_osmline(apiobj, idobj):
indexed_date=import_date,
geometry='LINESTRING(23 34, 23 35)')
result = apiobj.api.lookup(idobj, napi.LookupDetails())
result = apiobj.api.details(idobj, napi.LookupDetails())
assert result is not None
@ -310,13 +310,13 @@ def test_lookup_in_osmline_split_interpolation(apiobj):
startnumber=11, endnumber=20, step=1)
for i in range(1, 6):
result = apiobj.api.lookup(napi.OsmID('W', 9, str(i)), napi.LookupDetails())
result = apiobj.api.details(napi.OsmID('W', 9, str(i)), napi.LookupDetails())
assert result.place_id == 1000
for i in range(7, 11):
result = apiobj.api.lookup(napi.OsmID('W', 9, str(i)), napi.LookupDetails())
result = apiobj.api.details(napi.OsmID('W', 9, str(i)), napi.LookupDetails())
assert result.place_id == 1001
for i in range(12, 22):
result = apiobj.api.lookup(napi.OsmID('W', 9, str(i)), napi.LookupDetails())
result = apiobj.api.details(napi.OsmID('W', 9, str(i)), napi.LookupDetails())
assert result.place_id == 1002
@ -340,7 +340,7 @@ def test_lookup_osmline_with_address_details(apiobj):
country_code='pl',
rank_search=17, rank_address=16)
result = apiobj.api.lookup(napi.PlaceID(9000),
result = apiobj.api.details(napi.PlaceID(9000),
napi.LookupDetails(address_details=True))
assert result.address_rows == [
@ -383,7 +383,7 @@ def test_lookup_in_tiger(apiobj):
osm_type='W', osm_id=6601223,
geometry='LINESTRING(23 34, 23 35)')
result = apiobj.api.lookup(napi.PlaceID(4924), napi.LookupDetails())
result = apiobj.api.details(napi.PlaceID(4924), napi.LookupDetails())
assert result is not None
@ -441,7 +441,7 @@ def test_lookup_tiger_with_address_details(apiobj):
country_code='us',
rank_search=17, rank_address=16)
result = apiobj.api.lookup(napi.PlaceID(9000),
result = apiobj.api.details(napi.PlaceID(9000),
napi.LookupDetails(address_details=True))
assert result.address_rows == [
@ -483,7 +483,7 @@ def test_lookup_in_postcode(apiobj):
indexed_date=import_date,
geometry='POINT(-9.45 5.6)')
result = apiobj.api.lookup(napi.PlaceID(554), napi.LookupDetails())
result = apiobj.api.details(napi.PlaceID(554), napi.LookupDetails())
assert result is not None
@ -537,7 +537,7 @@ def test_lookup_postcode_with_address_details(apiobj):
country_code='gb',
rank_search=17, rank_address=16)
result = apiobj.api.lookup(napi.PlaceID(9000),
result = apiobj.api.details(napi.PlaceID(9000),
napi.LookupDetails(address_details=True))
assert result.address_rows == [
@ -570,7 +570,7 @@ def test_lookup_missing_object(apiobj, objid):
apiobj.add_placex(place_id=1, osm_type='N', osm_id=55,
class_='place', type='suburb')
assert apiobj.api.lookup(objid, napi.LookupDetails()) is None
assert apiobj.api.details(objid, napi.LookupDetails()) is None
@pytest.mark.parametrize('gtype', (napi.GeometryFormat.KML,
@ -580,5 +580,5 @@ def test_lookup_unsupported_geometry(apiobj, gtype):
apiobj.add_placex(place_id=332)
with pytest.raises(ValueError):
apiobj.api.lookup(napi.PlaceID(332),
apiobj.api.details(napi.PlaceID(332),
napi.LookupDetails(geometry_output=gtype))

View File

@ -335,7 +335,7 @@ class TestDetailsEndpoint:
self.lookup_args.extend(args[1:])
return self.result
monkeypatch.setattr(napi.NominatimAPIAsync, 'lookup', _lookup)
monkeypatch.setattr(napi.NominatimAPIAsync, 'details', _lookup)
@pytest.mark.asyncio

View File

@ -81,7 +81,7 @@ class TestCliDetailsCall:
result = napi.DetailedResult(napi.SourceTable.PLACEX, ('place', 'thing'),
napi.Point(1.0, -3.0))
monkeypatch.setattr(napi.NominatimAPI, 'lookup',
monkeypatch.setattr(napi.NominatimAPI, 'details',
lambda *args: result)
@pytest.mark.parametrize("params", [('--node', '1'),