]> git.openstreetmap.org Git - nominatim.git/blobdiff - test/python/api/test_api_reverse.py
Merge pull request #3467 from mtmail/docs-datrie
[nominatim.git] / test / python / api / test_api_reverse.py
index 3296e98fdd6055ad0beb2571e4da2877b6d37f7d..ff7f402b72f000d9364d716752b992a5e7514b3d 100644 (file)
@@ -2,7 +2,7 @@
 #
 # This file is part of Nominatim. (https://nominatim.org)
 #
-# Copyright (C) 2023 by the Nominatim developer community.
+# Copyright (C) 2024 by the Nominatim developer community.
 # For a full list of authors see the git log.
 """
 Tests for reverse API call.
@@ -14,22 +14,25 @@ import json
 
 import pytest
 
-import nominatim.api as napi
+import nominatim_api as napi
 
-def test_reverse_rank_30(apiobj):
+API_OPTIONS = {'reverse'}
+
+def test_reverse_rank_30(apiobj, frontend):
     apiobj.add_placex(place_id=223, class_='place', type='house',
                       housenumber='1',
                       centroid=(1.3, 0.7),
                       geometry='POINT(1.3 0.7)')
 
-    result = apiobj.api.reverse((1.3, 0.7))
+    api = frontend(apiobj, options=API_OPTIONS)
+    result = api.reverse((1.3, 0.7))
 
     assert result is not None
     assert result.place_id == 223
 
 
 @pytest.mark.parametrize('country', ['de', 'us'])
-def test_reverse_street(apiobj, country):
+def test_reverse_street(apiobj, frontend, country):
     apiobj.add_placex(place_id=990, class_='highway', type='service',
                       rank_search=27, rank_address=27,
                       name = {'name': 'My Street'},
@@ -37,17 +40,19 @@ def test_reverse_street(apiobj, country):
                       country_code=country,
                       geometry='LINESTRING(9.995 10, 10.005 10)')
 
-    assert apiobj.api.reverse((9.995, 10)).place_id == 990
+    api = frontend(apiobj, options=API_OPTIONS)
+    assert api.reverse((9.995, 10)).place_id == 990
 
 
-def test_reverse_ignore_unindexed(apiobj):
+def test_reverse_ignore_unindexed(apiobj, frontend):
     apiobj.add_placex(place_id=223, class_='place', type='house',
                       housenumber='1',
                       indexed_status=2,
                       centroid=(1.3, 0.7),
                       geometry='POINT(1.3 0.7)')
 
-    result = apiobj.api.reverse((1.3, 0.7))
+    api = frontend(apiobj, options=API_OPTIONS)
+    result = api.reverse((1.3, 0.7))
 
     assert result is None
 
@@ -60,45 +65,54 @@ def test_reverse_ignore_unindexed(apiobj):
                                               (0.7, napi.DataLayer.RAILWAY, 226),
                                               (0.7, napi.DataLayer.NATURAL, 227),
                                               (0.70003, napi.DataLayer.MANMADE | napi.DataLayer.RAILWAY, 225),
-                                              (0.70003, napi.DataLayer.MANMADE | napi.DataLayer.NATURAL, 225)])
-def test_reverse_rank_30_layers(apiobj, y, layer, place_id):
-    apiobj.add_placex(place_id=223, class_='place', type='house',
+                                              (0.70003, napi.DataLayer.MANMADE | napi.DataLayer.NATURAL, 225),
+                                              (5, napi.DataLayer.ADDRESS, 229)])
+def test_reverse_rank_30_layers(apiobj, frontend, y, layer, place_id):
+    apiobj.add_placex(place_id=223, osm_type='N', class_='place', type='house',
                       housenumber='1',
                       rank_address=30,
                       rank_search=30,
                       centroid=(1.3, 0.70001))
-    apiobj.add_placex(place_id=224, class_='amenity', type='toilet',
+    apiobj.add_placex(place_id=224, osm_type='N', class_='amenity', type='toilet',
                       rank_address=30,
                       rank_search=30,
                       centroid=(1.3, 0.7))
-    apiobj.add_placex(place_id=225, class_='man_made', type='tower',
+    apiobj.add_placex(place_id=225, osm_type='N', class_='man_made', type='tower',
                       rank_address=0,
                       rank_search=30,
                       centroid=(1.3, 0.70003))
-    apiobj.add_placex(place_id=226, class_='railway', type='station',
+    apiobj.add_placex(place_id=226, osm_type='N', class_='railway', type='station',
                       rank_address=0,
                       rank_search=30,
                       centroid=(1.3, 0.70004))
-    apiobj.add_placex(place_id=227, class_='natural', type='cave',
+    apiobj.add_placex(place_id=227, osm_type='N', class_='natural', type='cave',
                       rank_address=0,
                       rank_search=30,
                       centroid=(1.3, 0.70005))
+    apiobj.add_placex(place_id=229, class_='place', type='house',
+                      name={'addr:housename': 'Old Cottage'},
+                      rank_address=30,
+                      rank_search=30,
+                      centroid=(1.3, 5))
 
-    assert apiobj.api.reverse((1.3, y), layers=layer).place_id == place_id
+    api = frontend(apiobj, options=API_OPTIONS)
+    assert api.reverse((1.3, y), layers=layer).place_id == place_id
 
 
-def test_reverse_poi_layer_with_no_pois(apiobj):
+def test_reverse_poi_layer_with_no_pois(apiobj, frontend):
     apiobj.add_placex(place_id=223, class_='place', type='house',
                       housenumber='1',
                       rank_address=30,
                       rank_search=30,
                       centroid=(1.3, 0.70001))
 
-    assert apiobj.api.reverse((1.3, 0.70001), max_rank=29,
+    api = frontend(apiobj, options=API_OPTIONS)
+    assert api.reverse((1.3, 0.70001), max_rank=29,
                               layers=napi.DataLayer.POI) is None
 
 
-def test_reverse_housenumber_on_street(apiobj):
+@pytest.mark.parametrize('with_geom', [True, False])
+def test_reverse_housenumber_on_street(apiobj, frontend, with_geom):
     apiobj.add_placex(place_id=990, class_='highway', type='service',
                       rank_search=27, rank_address=27,
                       name = {'name': 'My Street'},
@@ -109,13 +123,28 @@ def test_reverse_housenumber_on_street(apiobj):
                       rank_search=30, rank_address=30,
                       housenumber='23',
                       centroid=(10.0, 10.00001))
+    apiobj.add_placex(place_id=1990, class_='highway', type='service',
+                      rank_search=27, rank_address=27,
+                      name = {'name': 'Other Street'},
+                      centroid=(10.0, 1.0),
+                      geometry='LINESTRING(9.995 1, 10.005 1)')
+    apiobj.add_placex(place_id=1991, class_='place', type='house',
+                      parent_place_id=1990,
+                      rank_search=30, rank_address=30,
+                      housenumber='23',
+                      centroid=(10.0, 1.00001))
+
+    params = {'geometry_output': napi.GeometryFormat.TEXT} if with_geom else {}
 
-    assert apiobj.api.reverse((10.0, 10.0), max_rank=30).place_id == 991
-    assert apiobj.api.reverse((10.0, 10.0), max_rank=27).place_id == 990
-    assert apiobj.api.reverse((10.0, 10.00001), max_rank=30).place_id == 991
+    api = frontend(apiobj, options=API_OPTIONS)
+    assert api.reverse((10.0, 10.0), max_rank=30, **params).place_id == 991
+    assert api.reverse((10.0, 10.0), max_rank=27).place_id == 990
+    assert api.reverse((10.0, 10.00001), max_rank=30).place_id == 991
+    assert api.reverse((10.0, 1.0), **params).place_id == 1991
 
 
-def test_reverse_housenumber_interpolation(apiobj):
+@pytest.mark.parametrize('with_geom', [True, False])
+def test_reverse_housenumber_interpolation(apiobj, frontend, with_geom):
     apiobj.add_placex(place_id=990, class_='highway', type='service',
                       rank_search=27, rank_address=27,
                       name = {'name': 'My Street'},
@@ -131,11 +160,25 @@ def test_reverse_housenumber_interpolation(apiobj):
                        startnumber=1, endnumber=3, step=1,
                        centroid=(10.0, 10.00001),
                        geometry='LINESTRING(9.995 10.00001, 10.005 10.00001)')
+    apiobj.add_placex(place_id=1990, class_='highway', type='service',
+                      rank_search=27, rank_address=27,
+                      name = {'name': 'Other Street'},
+                      centroid=(10.0, 20.0),
+                      geometry='LINESTRING(9.995 20, 10.005 20)')
+    apiobj.add_osmline(place_id=1992,
+                       parent_place_id=1990,
+                       startnumber=1, endnumber=3, step=1,
+                       centroid=(10.0, 20.00001),
+                       geometry='LINESTRING(9.995 20.00001, 10.005 20.00001)')
+
+    params = {'geometry_output': napi.GeometryFormat.TEXT} if with_geom else {}
 
-    assert apiobj.api.reverse((10.0, 10.0)).place_id == 992
+    api = frontend(apiobj, options=API_OPTIONS)
+    assert api.reverse((10.0, 10.0), **params).place_id == 992
+    assert api.reverse((10.0, 20.0), **params).place_id == 1992
 
 
-def test_reverse_housenumber_point_interpolation(apiobj):
+def test_reverse_housenumber_point_interpolation(apiobj, frontend):
     apiobj.add_placex(place_id=990, class_='highway', type='service',
                       rank_search=27, rank_address=27,
                       name = {'name': 'My Street'},
@@ -147,12 +190,13 @@ def test_reverse_housenumber_point_interpolation(apiobj):
                        centroid=(10.0, 10.00001),
                        geometry='POINT(10.0 10.00001)')
 
-    res = apiobj.api.reverse((10.0, 10.0))
+    api = frontend(apiobj, options=API_OPTIONS)
+    res = api.reverse((10.0, 10.0))
     assert res.place_id == 992
     assert res.housenumber == '42'
 
 
-def test_reverse_tiger_number(apiobj):
+def test_reverse_tiger_number(apiobj, frontend):
     apiobj.add_placex(place_id=990, class_='highway', type='service',
                       rank_search=27, rank_address=27,
                       name = {'name': 'My Street'},
@@ -165,11 +209,12 @@ def test_reverse_tiger_number(apiobj):
                      centroid=(10.0, 10.00001),
                      geometry='LINESTRING(9.995 10.00001, 10.005 10.00001)')
 
-    assert apiobj.api.reverse((10.0, 10.0)).place_id == 992
-    assert apiobj.api.reverse((10.0, 10.00001)).place_id == 992
+    api = frontend(apiobj, options=API_OPTIONS)
+    assert api.reverse((10.0, 10.0)).place_id == 992
+    assert api.reverse((10.0, 10.00001)).place_id == 992
 
 
-def test_reverse_point_tiger(apiobj):
+def test_reverse_point_tiger(apiobj, frontend):
     apiobj.add_placex(place_id=990, class_='highway', type='service',
                       rank_search=27, rank_address=27,
                       name = {'name': 'My Street'},
@@ -182,12 +227,13 @@ def test_reverse_point_tiger(apiobj):
                      centroid=(10.0, 10.00001),
                      geometry='POINT(10.0 10.00001)')
 
-    res = apiobj.api.reverse((10.0, 10.0))
+    api = frontend(apiobj, options=API_OPTIONS)
+    res = api.reverse((10.0, 10.0))
     assert res.place_id == 992
     assert res.housenumber == '1'
 
 
-def test_reverse_low_zoom_address(apiobj):
+def test_reverse_low_zoom_address(apiobj, frontend):
     apiobj.add_placex(place_id=1001, class_='place', type='house',
                       housenumber='1',
                       rank_address=30,
@@ -201,11 +247,12 @@ def test_reverse_low_zoom_address(apiobj):
                       geometry="""POLYGON((59.3 80.70001, 59.3001 80.70001,
                                         59.3001 80.70101, 59.3 80.70101, 59.3 80.70001))""")
 
-    assert apiobj.api.reverse((59.30005, 80.7005)).place_id == 1001
-    assert apiobj.api.reverse((59.30005, 80.7005), max_rank=18).place_id == 1002
+    api = frontend(apiobj, options=API_OPTIONS)
+    assert api.reverse((59.30005, 80.7005)).place_id == 1001
+    assert api.reverse((59.30005, 80.7005), max_rank=18).place_id == 1002
 
 
-def test_reverse_place_node_in_area(apiobj):
+def test_reverse_place_node_in_area(apiobj, frontend):
     apiobj.add_placex(place_id=1002, class_='place', type='town',
                       name={'name': 'Town Area'},
                       rank_address=16,
@@ -220,7 +267,8 @@ def test_reverse_place_node_in_area(apiobj):
                       rank_search=18,
                       centroid=(59.30004, 80.70055))
 
-    assert apiobj.api.reverse((59.30004, 80.70055)).place_id == 1003
+    api = frontend(apiobj, options=API_OPTIONS)
+    assert api.reverse((59.30004, 80.70055)).place_id == 1003
 
 
 @pytest.mark.parametrize('layer,place_id', [(napi.DataLayer.MANMADE, 225),
@@ -228,7 +276,7 @@ def test_reverse_place_node_in_area(apiobj):
                                             (napi.DataLayer.NATURAL, 227),
                                             (napi.DataLayer.MANMADE | napi.DataLayer.RAILWAY, 225),
                                             (napi.DataLayer.MANMADE | napi.DataLayer.NATURAL, 225)])
-def test_reverse_larger_area_layers(apiobj, layer, place_id):
+def test_reverse_larger_area_layers(apiobj, frontend, layer, place_id):
     apiobj.add_placex(place_id=225, class_='man_made', type='dam',
                       name={'name': 'Dam'},
                       rank_address=0,
@@ -245,18 +293,22 @@ def test_reverse_larger_area_layers(apiobj, layer, place_id):
                       rank_search=16,
                       centroid=(1.3, 0.70005))
 
-    assert apiobj.api.reverse((1.3, 0.7), layers=layer).place_id == place_id
+    api = frontend(apiobj, options=API_OPTIONS)
+    assert api.reverse((1.3, 0.7), layers=layer).place_id == place_id
 
 
-def test_reverse_country_lookup_no_objects(apiobj):
+def test_reverse_country_lookup_no_objects(apiobj, frontend):
     apiobj.add_country('xx', 'POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))')
 
-    assert apiobj.api.reverse((0.5, 0.5)) is None
+    api = frontend(apiobj, options=API_OPTIONS)
+    assert api.reverse((0.5, 0.5)) is None
 
 
 @pytest.mark.parametrize('rank', [4, 30])
-def test_reverse_country_lookup_country_only(apiobj, rank):
+@pytest.mark.parametrize('with_geom', [True, False])
+def test_reverse_country_lookup_country_only(apiobj, frontend, rank, with_geom):
     apiobj.add_country('xx', 'POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))')
+    apiobj.add_country('yy', 'POLYGON((10 0, 10 1, 11 1, 11 0, 10 0))')
     apiobj.add_placex(place_id=225, class_='place', type='country',
                       name={'name': 'My Country'},
                       rank_address=4,
@@ -264,11 +316,19 @@ def test_reverse_country_lookup_country_only(apiobj, rank):
                       country_code='xx',
                       centroid=(0.7, 0.7))
 
-    assert apiobj.api.reverse((0.5, 0.5), max_rank=rank).place_id == 225
+    params = {'max_rank': rank}
+    if with_geom:
+        params['geometry_output'] = napi.GeometryFormat.TEXT
 
+    api = frontend(apiobj, options=API_OPTIONS)
+    assert api.reverse((0.5, 0.5), **params).place_id == 225
+    assert api.reverse((10.5, 0.5), **params) is None
 
-def test_reverse_country_lookup_place_node_inside(apiobj):
+
+@pytest.mark.parametrize('with_geom', [True, False])
+def test_reverse_country_lookup_place_node_inside(apiobj, frontend, with_geom):
     apiobj.add_country('xx', 'POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))')
+    apiobj.add_country('yy', 'POLYGON((10 0, 10 1, 11 1, 11 0, 10 0))')
     apiobj.add_placex(place_id=225, class_='place', type='state',
                       osm_type='N',
                       name={'name': 'My State'},
@@ -276,12 +336,23 @@ def test_reverse_country_lookup_place_node_inside(apiobj):
                       rank_search=6,
                       country_code='xx',
                       centroid=(0.5, 0.505))
+    apiobj.add_placex(place_id=425, class_='place', type='state',
+                      osm_type='N',
+                      name={'name': 'Other State'},
+                      rank_address=6,
+                      rank_search=6,
+                      country_code='yy',
+                      centroid=(10.5, 0.505))
+
+    params = {'geometry_output': napi.GeometryFormat.KML} if with_geom else {}
 
-    assert apiobj.api.reverse((0.5, 0.5)).place_id == 225
+    api = frontend(apiobj, options=API_OPTIONS)
+    assert api.reverse((0.5, 0.5), **params).place_id == 225
+    assert api.reverse((10.5, 0.5), **params).place_id == 425
 
 
 @pytest.mark.parametrize('gtype', list(napi.GeometryFormat))
-def test_reverse_geometry_output_placex(apiobj, gtype):
+def test_reverse_geometry_output_placex(apiobj, frontend, gtype):
     apiobj.add_country('xx', 'POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))')
     apiobj.add_placex(place_id=1001, class_='place', type='house',
                       housenumber='1',
@@ -296,34 +367,37 @@ def test_reverse_geometry_output_placex(apiobj, gtype):
                       country_code='xx',
                       centroid=(0.5, 0.5))
 
-    assert apiobj.api.reverse((59.3, 80.70001), geometry_output=gtype).place_id == 1001
-    assert apiobj.api.reverse((0.5, 0.5), geometry_output=gtype).place_id == 1003
+    api = frontend(apiobj, options=API_OPTIONS)
+    assert api.reverse((59.3, 80.70001), geometry_output=gtype).place_id == 1001
+    assert api.reverse((0.5, 0.5), geometry_output=gtype).place_id == 1003
 
 
-def test_reverse_simplified_geometry(apiobj):
+def test_reverse_simplified_geometry(apiobj, frontend):
     apiobj.add_placex(place_id=1001, class_='place', type='house',
                       housenumber='1',
                       rank_address=30,
                       rank_search=30,
                       centroid=(59.3, 80.70001))
 
+    api = frontend(apiobj, options=API_OPTIONS)
     details = dict(geometry_output=napi.GeometryFormat.GEOJSON,
                    geometry_simplification=0.1)
-    assert apiobj.api.reverse((59.3, 80.70001), **details).place_id == 1001
+    assert api.reverse((59.3, 80.70001), **details).place_id == 1001
 
 
-def test_reverse_interpolation_geometry(apiobj):
+def test_reverse_interpolation_geometry(apiobj, frontend):
     apiobj.add_osmline(place_id=992,
                        parent_place_id=990,
                        startnumber=1, endnumber=3, step=1,
                        centroid=(10.0, 10.00001),
                        geometry='LINESTRING(9.995 10.00001, 10.005 10.00001)')
 
-    assert apiobj.api.reverse((10.0, 10.0), geometry_output=napi.GeometryFormat.TEXT)\
+    api = frontend(apiobj, options=API_OPTIONS)
+    assert api.reverse((10.0, 10.0), geometry_output=napi.GeometryFormat.TEXT)\
                      .geometry['text'] == 'POINT(10 10.00001)'
 
 
-def test_reverse_tiger_geometry(apiobj):
+def test_reverse_tiger_geometry(apiobj, frontend):
     apiobj.add_placex(place_id=990, class_='highway', type='service',
                       rank_search=27, rank_address=27,
                       name = {'name': 'My Street'},
@@ -335,9 +409,25 @@ def test_reverse_tiger_geometry(apiobj):
                      startnumber=1, endnumber=3, step=1,
                      centroid=(10.0, 10.00001),
                      geometry='LINESTRING(9.995 10.00001, 10.005 10.00001)')
+    apiobj.add_placex(place_id=1000, class_='highway', type='service',
+                      rank_search=27, rank_address=27,
+                      name = {'name': 'My Street'},
+                      centroid=(11.0, 11.0),
+                      country_code='us',
+                      geometry='LINESTRING(10.995 11, 11.005 11)')
+    apiobj.add_tiger(place_id=1001,
+                     parent_place_id=1000,
+                     startnumber=1, endnumber=3, step=1,
+                     centroid=(11.0, 11.00001),
+                     geometry='LINESTRING(10.995 11.00001, 11.005 11.00001)')
+
+    api = frontend(apiobj, options=API_OPTIONS)
+
+    params = {'geometry_output': napi.GeometryFormat.GEOJSON}
 
-    output = apiobj.api.reverse((10.0, 10.0),
-                                geometry_output=napi.GeometryFormat.GEOJSON).geometry['geojson']
+    output = api.reverse((10.0, 10.0), **params)
+    assert json.loads(output.geometry['geojson']) == {'coordinates': [10, 10.00001], 'type': 'Point'}
 
-    assert json.loads(output) == {'coordinates': [10, 10.00001], 'type': 'Point'}
+    output = api.reverse((11.0, 11.0), **params)
+    assert json.loads(output.geometry['geojson']) == {'coordinates': [11, 11.00001], 'type': 'Point'}