1 # SPDX-License-Identifier: GPL-3.0-or-later
3 # This file is part of Nominatim. (https://nominatim.org)
5 # Copyright (C) 2023 by the Nominatim developer community.
6 # For a full list of authors see the git log.
8 Tests for lookup API call.
14 import nominatim.api as napi
16 @pytest.mark.parametrize('idobj', (napi.PlaceID(332), napi.OsmID('W', 4),
17 napi.OsmID('W', 4, 'highway')))
18 def test_lookup_in_placex(apiobj, idobj):
19 import_date = dt.datetime(2022, 12, 7, 14, 14, 46, 0)
20 apiobj.add_placex(place_id=332, osm_type='W', osm_id=4,
21 class_='highway', type='residential',
22 name={'name': 'Road'}, address={'city': 'Barrow'},
23 extratags={'surface': 'paved'},
24 parent_place_id=34, linked_place_id=55,
25 admin_level=15, country_code='gb',
27 postcode='34425', wikipedia='en:Faa',
28 rank_search=27, rank_address=26,
31 indexed_date=import_date,
32 geometry='LINESTRING(23 34, 23.1 34, 23.1 34.1, 23 34)')
34 result = apiobj.api.lookup(idobj, napi.LookupDetails())
36 assert result is not None
38 assert result.source_table.name == 'PLACEX'
39 assert result.category == ('highway', 'residential')
40 assert result.centroid == (pytest.approx(23.0), pytest.approx(34.0))
42 assert result.place_id == 332
43 assert result.parent_place_id == 34
44 assert result.linked_place_id == 55
45 assert result.osm_object == ('W', 4)
46 assert result.admin_level == 15
48 assert result.names == {'name': 'Road'}
49 assert result.address == {'city': 'Barrow'}
50 assert result.extratags == {'surface': 'paved'}
52 assert result.housenumber == '4'
53 assert result.postcode == '34425'
54 assert result.wikipedia == 'en:Faa'
56 assert result.rank_search == 27
57 assert result.rank_address == 26
58 assert result.importance == pytest.approx(0.01)
60 assert result.country_code == 'gb'
61 assert result.indexed_date == import_date
63 assert result.address_rows is None
64 assert result.linked_rows is None
65 assert result.parented_rows is None
66 assert result.name_keywords is None
67 assert result.address_keywords is None
69 assert result.geometry == {'type': 'ST_LineString'}
72 def test_lookup_in_placex_minimal_info(apiobj):
73 import_date = dt.datetime(2022, 12, 7, 14, 14, 46, 0)
74 apiobj.add_placex(place_id=332, osm_type='W', osm_id=4,
75 class_='highway', type='residential',
77 rank_search=27, rank_address=26,
79 indexed_date=import_date,
80 geometry='LINESTRING(23 34, 23.1 34, 23.1 34.1, 23 34)')
82 result = apiobj.api.lookup(napi.PlaceID(332), napi.LookupDetails())
84 assert result is not None
86 assert result.source_table.name == 'PLACEX'
87 assert result.category == ('highway', 'residential')
88 assert result.centroid == (pytest.approx(23.0), pytest.approx(34.0))
90 assert result.place_id == 332
91 assert result.parent_place_id is None
92 assert result.linked_place_id is None
93 assert result.osm_object == ('W', 4)
94 assert result.admin_level == 15
96 assert result.names is None
97 assert result.address is None
98 assert result.extratags is None
100 assert result.housenumber is None
101 assert result.postcode is None
102 assert result.wikipedia is None
104 assert result.rank_search == 27
105 assert result.rank_address == 26
106 assert result.importance is None
108 assert result.country_code is None
109 assert result.indexed_date == import_date
111 assert result.address_rows is None
112 assert result.linked_rows is None
113 assert result.parented_rows is None
114 assert result.name_keywords is None
115 assert result.address_keywords is None
117 assert result.geometry == {'type': 'ST_LineString'}
120 def test_lookup_in_placex_with_geometry(apiobj):
121 apiobj.add_placex(place_id=332,
122 geometry='LINESTRING(23 34, 23.1 34)')
124 result = apiobj.api.lookup(napi.PlaceID(332),
125 napi.LookupDetails(geometry_output=napi.GeometryFormat.GEOJSON))
127 assert result.geometry == {'geojson': '{"type":"LineString","coordinates":[[23,34],[23.1,34]]}'}
130 def test_lookup_placex_with_address_details(apiobj):
131 apiobj.add_placex(place_id=332, osm_type='W', osm_id=4,
132 class_='highway', type='residential', name='Street',
134 rank_search=27, rank_address=26)
135 apiobj.add_address_placex(332, fromarea=False, isaddress=False,
137 place_id=1000, osm_type='N', osm_id=3333,
138 class_='place', type='suburb', name='Smallplace',
139 country_code='pl', admin_level=13,
140 rank_search=24, rank_address=23)
141 apiobj.add_address_placex(332, fromarea=True, isaddress=True,
142 place_id=1001, osm_type='N', osm_id=3334,
143 class_='place', type='city', name='Bigplace',
145 rank_search=17, rank_address=16)
147 result = apiobj.api.lookup(napi.PlaceID(332),
148 napi.LookupDetails(address_details=True))
150 assert result.address_rows == [
151 napi.AddressLine(place_id=332, osm_object=('W', 4),
152 category=('highway', 'residential'),
153 names={'name': 'Street'}, extratags={},
154 admin_level=15, fromarea=True, isaddress=True,
155 rank_address=26, distance=0.0),
156 napi.AddressLine(place_id=1000, osm_object=('N', 3333),
157 category=('place', 'suburb'),
158 names={'name': 'Smallplace'}, extratags={},
159 admin_level=13, fromarea=False, isaddress=True,
160 rank_address=23, distance=0.0034),
161 napi.AddressLine(place_id=1001, osm_object=('N', 3334),
162 category=('place', 'city'),
163 names={'name': 'Bigplace'}, extratags={},
164 admin_level=15, fromarea=True, isaddress=True,
165 rank_address=16, distance=0.0),
166 napi.AddressLine(place_id=None, osm_object=None,
167 category=('place', 'country_code'),
168 names={'ref': 'pl'}, extratags={},
169 admin_level=None, fromarea=True, isaddress=False,
170 rank_address=4, distance=0.0)
175 def test_lookup_place_with_linked_places_none_existing(apiobj):
176 apiobj.add_placex(place_id=332, osm_type='W', osm_id=4,
177 class_='highway', type='residential', name='Street',
178 country_code='pl', linked_place_id=45,
179 rank_search=27, rank_address=26)
181 result = apiobj.api.lookup(napi.PlaceID(332),
182 napi.LookupDetails(linked_places=True))
184 assert result.linked_rows == []
187 def test_lookup_place_with_linked_places_existing(apiobj):
188 apiobj.add_placex(place_id=332, osm_type='W', osm_id=4,
189 class_='highway', type='residential', name='Street',
190 country_code='pl', linked_place_id=45,
191 rank_search=27, rank_address=26)
192 apiobj.add_placex(place_id=1001, osm_type='W', osm_id=5,
193 class_='highway', type='residential', name='Street',
194 country_code='pl', linked_place_id=332,
195 rank_search=27, rank_address=26)
196 apiobj.add_placex(place_id=1002, osm_type='W', osm_id=6,
197 class_='highway', type='residential', name='Street',
198 country_code='pl', linked_place_id=332,
199 rank_search=27, rank_address=26)
201 result = apiobj.api.lookup(napi.PlaceID(332),
202 napi.LookupDetails(linked_places=True))
204 assert result.linked_rows == [
205 napi.AddressLine(place_id=1001, osm_object=('W', 5),
206 category=('highway', 'residential'),
207 names={'name': 'Street'}, extratags={},
208 admin_level=15, fromarea=False, isaddress=True,
209 rank_address=26, distance=0.0),
210 napi.AddressLine(place_id=1002, osm_object=('W', 6),
211 category=('highway', 'residential'),
212 names={'name': 'Street'}, extratags={},
213 admin_level=15, fromarea=False, isaddress=True,
214 rank_address=26, distance=0.0),
218 def test_lookup_place_with_parented_places_not_existing(apiobj):
219 apiobj.add_placex(place_id=332, osm_type='W', osm_id=4,
220 class_='highway', type='residential', name='Street',
221 country_code='pl', parent_place_id=45,
222 rank_search=27, rank_address=26)
224 result = apiobj.api.lookup(napi.PlaceID(332),
225 napi.LookupDetails(parented_places=True))
227 assert result.parented_rows == []
230 def test_lookup_place_with_parented_places_existing(apiobj):
231 apiobj.add_placex(place_id=332, osm_type='W', osm_id=4,
232 class_='highway', type='residential', name='Street',
233 country_code='pl', parent_place_id=45,
234 rank_search=27, rank_address=26)
235 apiobj.add_placex(place_id=1001, osm_type='N', osm_id=5,
236 class_='place', type='house', housenumber='23',
237 country_code='pl', parent_place_id=332,
238 rank_search=30, rank_address=30)
239 apiobj.add_placex(place_id=1002, osm_type='W', osm_id=6,
240 class_='highway', type='residential', name='Street',
241 country_code='pl', parent_place_id=332,
242 rank_search=27, rank_address=26)
244 result = apiobj.api.lookup(napi.PlaceID(332),
245 napi.LookupDetails(parented_places=True))
247 assert result.parented_rows == [
248 napi.AddressLine(place_id=1001, osm_object=('N', 5),
249 category=('place', 'house'),
250 names={'housenumber': '23'}, extratags={},
251 admin_level=15, fromarea=False, isaddress=True,
252 rank_address=30, distance=0.0),
256 @pytest.mark.parametrize('idobj', (napi.PlaceID(4924), napi.OsmID('W', 9928)))
257 def test_lookup_in_osmline(apiobj, idobj):
258 import_date = dt.datetime(2022, 12, 7, 14, 14, 46, 0)
259 apiobj.add_osmline(place_id=4924, osm_id=9928,
261 startnumber=1, endnumber=4, step=1,
262 country_code='gb', postcode='34425',
263 address={'city': 'Big'},
264 indexed_date=import_date,
265 geometry='LINESTRING(23 34, 23 35)')
267 result = apiobj.api.lookup(idobj, napi.LookupDetails())
269 assert result is not None
271 assert result.source_table.name == 'OSMLINE'
272 assert result.category == ('place', 'houses')
273 assert result.centroid == (pytest.approx(23.0), pytest.approx(34.5))
275 assert result.place_id == 4924
276 assert result.parent_place_id == 12
277 assert result.linked_place_id is None
278 assert result.osm_object == ('W', 9928)
279 assert result.admin_level == 15
281 assert result.names is None
282 assert result.address == {'city': 'Big'}
283 assert result.extratags == {'startnumber': '1', 'endnumber': '4', 'step': '1'}
285 assert result.housenumber is None
286 assert result.postcode == '34425'
287 assert result.wikipedia is None
289 assert result.rank_search == 30
290 assert result.rank_address == 30
291 assert result.importance is None
293 assert result.country_code == 'gb'
294 assert result.indexed_date == import_date
296 assert result.address_rows is None
297 assert result.linked_rows is None
298 assert result.parented_rows is None
299 assert result.name_keywords is None
300 assert result.address_keywords is None
302 assert result.geometry == {'type': 'ST_LineString'}
305 def test_lookup_in_osmline_split_interpolation(apiobj):
306 apiobj.add_osmline(place_id=1000, osm_id=9,
307 startnumber=2, endnumber=4, step=1)
308 apiobj.add_osmline(place_id=1001, osm_id=9,
309 startnumber=6, endnumber=9, step=1)
310 apiobj.add_osmline(place_id=1002, osm_id=9,
311 startnumber=11, endnumber=20, step=1)
313 for i in range(1, 6):
314 result = apiobj.api.lookup(napi.OsmID('W', 9, str(i)), napi.LookupDetails())
315 assert result.place_id == 1000
316 for i in range(7, 11):
317 result = apiobj.api.lookup(napi.OsmID('W', 9, str(i)), napi.LookupDetails())
318 assert result.place_id == 1001
319 for i in range(12, 22):
320 result = apiobj.api.lookup(napi.OsmID('W', 9, str(i)), napi.LookupDetails())
321 assert result.place_id == 1002
324 def test_lookup_osmline_with_address_details(apiobj):
325 apiobj.add_osmline(place_id=9000, osm_id=9,
326 startnumber=2, endnumber=4, step=1,
328 apiobj.add_placex(place_id=332, osm_type='W', osm_id=4,
329 class_='highway', type='residential', name='Street',
331 rank_search=27, rank_address=26)
332 apiobj.add_address_placex(332, fromarea=False, isaddress=False,
334 place_id=1000, osm_type='N', osm_id=3333,
335 class_='place', type='suburb', name='Smallplace',
336 country_code='pl', admin_level=13,
337 rank_search=24, rank_address=23)
338 apiobj.add_address_placex(332, fromarea=True, isaddress=True,
339 place_id=1001, osm_type='N', osm_id=3334,
340 class_='place', type='city', name='Bigplace',
342 rank_search=17, rank_address=16)
344 result = apiobj.api.lookup(napi.PlaceID(9000),
345 napi.LookupDetails(address_details=True))
347 assert result.address_rows == [
348 napi.AddressLine(place_id=None, osm_object=None,
349 category=('place', 'house_number'),
350 names={'ref': '2'}, extratags={},
351 admin_level=None, fromarea=True, isaddress=True,
352 rank_address=28, distance=0.0),
353 napi.AddressLine(place_id=332, osm_object=('W', 4),
354 category=('highway', 'residential'),
355 names={'name': 'Street'}, extratags={},
356 admin_level=15, fromarea=True, isaddress=True,
357 rank_address=26, distance=0.0),
358 napi.AddressLine(place_id=1000, osm_object=('N', 3333),
359 category=('place', 'suburb'),
360 names={'name': 'Smallplace'}, extratags={},
361 admin_level=13, fromarea=False, isaddress=True,
362 rank_address=23, distance=0.0034),
363 napi.AddressLine(place_id=1001, osm_object=('N', 3334),
364 category=('place', 'city'),
365 names={'name': 'Bigplace'}, extratags={},
366 admin_level=15, fromarea=True, isaddress=True,
367 rank_address=16, distance=0.0),
368 napi.AddressLine(place_id=None, osm_object=None,
369 category=('place', 'country_code'),
370 names={'ref': 'pl'}, extratags={},
371 admin_level=None, fromarea=True, isaddress=False,
372 rank_address=4, distance=0.0)
377 @pytest.mark.parametrize('gtype', (napi.GeometryFormat.KML,
378 napi.GeometryFormat.SVG,
379 napi.GeometryFormat.TEXT))
380 def test_lookup_unsupported_geometry(apiobj, gtype):
381 apiobj.add_placex(place_id=332)
383 with pytest.raises(ValueError):
384 apiobj.api.lookup(napi.PlaceID(332),
385 napi.LookupDetails(geometry_output=gtype))