]> git.openstreetmap.org Git - nominatim.git/blob - test/python/api/test_api_lookup.py
c445085730f34f1b7a84e05b4b0785c93a1bbdb4
[nominatim.git] / test / python / api / test_api_lookup.py
1 # SPDX-License-Identifier: GPL-3.0-or-later
2 #
3 # This file is part of Nominatim. (https://nominatim.org)
4 #
5 # Copyright (C) 2023 by the Nominatim developer community.
6 # For a full list of authors see the git log.
7 """
8 Tests for lookup API call.
9 """
10 import datetime as dt
11
12 import pytest
13
14 import nominatim.api as napi
15
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',
26                      housenumber='4',
27                      postcode='34425', wikipedia='en:Faa',
28                      rank_search=27, rank_address=26,
29                      importance=0.01,
30                      centroid=(23, 34),
31                      indexed_date=import_date,
32                      geometry='LINESTRING(23 34, 23.1 34, 23.1 34.1, 23 34)')
33
34     result = apiobj.api.lookup(idobj, napi.LookupDetails())
35
36     assert result is not None
37
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))
41
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
47
48     assert result.names == {'name': 'Road'}
49     assert result.address == {'city': 'Barrow'}
50     assert result.extratags == {'surface': 'paved'}
51
52     assert result.housenumber == '4'
53     assert result.postcode == '34425'
54     assert result.wikipedia == 'en:Faa'
55
56     assert result.rank_search == 27
57     assert result.rank_address == 26
58     assert result.importance == pytest.approx(0.01)
59
60     assert result.country_code == 'gb'
61     assert result.indexed_date == import_date
62
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
68
69     assert result.geometry == {'type': 'ST_LineString'}
70
71
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',
76                      admin_level=15,
77                      rank_search=27, rank_address=26,
78                      centroid=(23, 34),
79                      indexed_date=import_date,
80                      geometry='LINESTRING(23 34, 23.1 34, 23.1 34.1, 23 34)')
81
82     result = apiobj.api.lookup(napi.PlaceID(332), napi.LookupDetails())
83
84     assert result is not None
85
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))
89
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
95
96     assert result.names is None
97     assert result.address is None
98     assert result.extratags is None
99
100     assert result.housenumber is None
101     assert result.postcode is None
102     assert result.wikipedia is None
103
104     assert result.rank_search == 27
105     assert result.rank_address == 26
106     assert result.importance is None
107
108     assert result.country_code is None
109     assert result.indexed_date == import_date
110
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
116
117     assert result.geometry == {'type': 'ST_LineString'}
118
119
120 def test_lookup_in_placex_with_geometry(apiobj):
121     apiobj.add_placex(place_id=332,
122                       geometry='LINESTRING(23 34, 23.1 34)')
123
124     result = apiobj.api.lookup(napi.PlaceID(332),
125                                napi.LookupDetails(geometry_output=napi.GeometryFormat.GEOJSON))
126
127     assert result.geometry == {'geojson': '{"type":"LineString","coordinates":[[23,34],[23.1,34]]}'}
128
129
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',
133                      country_code='pl',
134                      rank_search=27, rank_address=26)
135     apiobj.add_address_placex(332, fromarea=False, isaddress=False,
136                               distance=0.0034,
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',
144                               country_code='pl',
145                               rank_search=17, rank_address=16)
146
147     result = apiobj.api.lookup(napi.PlaceID(332),
148                                napi.LookupDetails(address_details=True))
149
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)
171
172            ]
173
174
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)
180
181     result = apiobj.api.lookup(napi.PlaceID(332),
182                                napi.LookupDetails(linked_places=True))
183
184     assert result.linked_rows == []
185
186
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)
200
201     result = apiobj.api.lookup(napi.PlaceID(332),
202                                napi.LookupDetails(linked_places=True))
203
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),
215     ]
216
217
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)
223
224     result = apiobj.api.lookup(napi.PlaceID(332),
225                                napi.LookupDetails(parented_places=True))
226
227     assert result.parented_rows == []
228
229
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)
243
244     result = apiobj.api.lookup(napi.PlaceID(332),
245                                napi.LookupDetails(parented_places=True))
246
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),
253     ]
254
255
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,
260                        parent_place_id=12,
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)')
266
267     result = apiobj.api.lookup(idobj, napi.LookupDetails())
268
269     assert result is not None
270
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))
274
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
280
281     assert result.names is None
282     assert result.address == {'city': 'Big'}
283     assert result.extratags == {'startnumber': '1', 'endnumber': '4', 'step': '1'}
284
285     assert result.housenumber is None
286     assert result.postcode == '34425'
287     assert result.wikipedia is None
288
289     assert result.rank_search == 30
290     assert result.rank_address == 30
291     assert result.importance is None
292
293     assert result.country_code == 'gb'
294     assert result.indexed_date == import_date
295
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
301
302     assert result.geometry == {'type': 'ST_LineString'}
303
304
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)
312
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
322
323
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,
327                        parent_place_id=332)
328     apiobj.add_placex(place_id=332, osm_type='W', osm_id=4,
329                      class_='highway', type='residential',  name='Street',
330                      country_code='pl',
331                      rank_search=27, rank_address=26)
332     apiobj.add_address_placex(332, fromarea=False, isaddress=False,
333                               distance=0.0034,
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',
341                               country_code='pl',
342                               rank_search=17, rank_address=16)
343
344     result = apiobj.api.lookup(napi.PlaceID(9000),
345                                napi.LookupDetails(address_details=True))
346
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)
373
374            ]
375
376
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)
382
383     with pytest.raises(ValueError):
384         apiobj.api.lookup(napi.PlaceID(332),
385                           napi.LookupDetails(geometry_output=gtype))