mirror of
https://github.com/osm-search/Nominatim.git
synced 2026-02-15 02:47:59 +00:00
enable flake for Python tests
This commit is contained in:
@@ -2,14 +2,13 @@
|
||||
#
|
||||
# This file is part of Nominatim. (https://nominatim.org)
|
||||
#
|
||||
# Copyright (C) 2024 by the Nominatim developer community.
|
||||
# Copyright (C) 2025 by the Nominatim developer community.
|
||||
# For a full list of authors see the git log.
|
||||
"""
|
||||
Helper fixtures for API call tests.
|
||||
"""
|
||||
import pytest
|
||||
import pytest_asyncio
|
||||
import time
|
||||
import datetime as dt
|
||||
|
||||
import sqlalchemy as sa
|
||||
@@ -20,27 +19,25 @@ from nominatim_api.search.query_analyzer_factory import make_query_analyzer
|
||||
from nominatim_db.tools import convert_sqlite
|
||||
import nominatim_api.logging as loglib
|
||||
|
||||
|
||||
class APITester:
|
||||
|
||||
def __init__(self):
|
||||
self.api = napi.NominatimAPI()
|
||||
self.async_to_sync(self.api._async_api.setup_database())
|
||||
|
||||
|
||||
def async_to_sync(self, func):
|
||||
""" Run an asynchronous function until completion using the
|
||||
internal loop of the API.
|
||||
"""
|
||||
return self.api._loop.run_until_complete(func)
|
||||
|
||||
|
||||
def add_data(self, table, data):
|
||||
""" Insert data into the given table.
|
||||
"""
|
||||
sql = getattr(self.api._async_api._tables, table).insert()
|
||||
self.async_to_sync(self.exec_async(sql, data))
|
||||
|
||||
|
||||
def add_placex(self, **kw):
|
||||
name = kw.get('name')
|
||||
if isinstance(name, str):
|
||||
@@ -50,30 +47,29 @@ class APITester:
|
||||
geometry = kw.get('geometry', 'POINT(%f %f)' % centroid)
|
||||
|
||||
self.add_data('placex',
|
||||
{'place_id': kw.get('place_id', 1000),
|
||||
'osm_type': kw.get('osm_type', 'W'),
|
||||
'osm_id': kw.get('osm_id', 4),
|
||||
'class_': kw.get('class_', 'highway'),
|
||||
'type': kw.get('type', 'residential'),
|
||||
'name': name,
|
||||
'address': kw.get('address'),
|
||||
'extratags': kw.get('extratags'),
|
||||
'parent_place_id': kw.get('parent_place_id'),
|
||||
'linked_place_id': kw.get('linked_place_id'),
|
||||
'admin_level': kw.get('admin_level', 15),
|
||||
'country_code': kw.get('country_code'),
|
||||
'housenumber': kw.get('housenumber'),
|
||||
'postcode': kw.get('postcode'),
|
||||
'wikipedia': kw.get('wikipedia'),
|
||||
'rank_search': kw.get('rank_search', 30),
|
||||
'rank_address': kw.get('rank_address', 30),
|
||||
'importance': kw.get('importance'),
|
||||
'centroid': 'POINT(%f %f)' % centroid,
|
||||
'indexed_status': kw.get('indexed_status', 0),
|
||||
'indexed_date': kw.get('indexed_date',
|
||||
dt.datetime(2022, 12, 7, 14, 14, 46, 0)),
|
||||
'geometry': geometry})
|
||||
|
||||
{'place_id': kw.get('place_id', 1000),
|
||||
'osm_type': kw.get('osm_type', 'W'),
|
||||
'osm_id': kw.get('osm_id', 4),
|
||||
'class_': kw.get('class_', 'highway'),
|
||||
'type': kw.get('type', 'residential'),
|
||||
'name': name,
|
||||
'address': kw.get('address'),
|
||||
'extratags': kw.get('extratags'),
|
||||
'parent_place_id': kw.get('parent_place_id'),
|
||||
'linked_place_id': kw.get('linked_place_id'),
|
||||
'admin_level': kw.get('admin_level', 15),
|
||||
'country_code': kw.get('country_code'),
|
||||
'housenumber': kw.get('housenumber'),
|
||||
'postcode': kw.get('postcode'),
|
||||
'wikipedia': kw.get('wikipedia'),
|
||||
'rank_search': kw.get('rank_search', 30),
|
||||
'rank_address': kw.get('rank_address', 30),
|
||||
'importance': kw.get('importance'),
|
||||
'centroid': 'POINT(%f %f)' % centroid,
|
||||
'indexed_status': kw.get('indexed_status', 0),
|
||||
'indexed_date': kw.get('indexed_date',
|
||||
dt.datetime(2022, 12, 7, 14, 14, 46, 0)),
|
||||
'geometry': geometry})
|
||||
|
||||
def add_address_placex(self, object_id, **kw):
|
||||
self.add_placex(**kw)
|
||||
@@ -85,46 +81,42 @@ class APITester:
|
||||
'fromarea': kw.get('fromarea', False),
|
||||
'isaddress': kw.get('isaddress', True)})
|
||||
|
||||
|
||||
def add_osmline(self, **kw):
|
||||
self.add_data('osmline',
|
||||
{'place_id': kw.get('place_id', 10000),
|
||||
'osm_id': kw.get('osm_id', 4004),
|
||||
'parent_place_id': kw.get('parent_place_id'),
|
||||
'indexed_date': kw.get('indexed_date',
|
||||
dt.datetime(2022, 12, 7, 14, 14, 46, 0)),
|
||||
'startnumber': kw.get('startnumber', 2),
|
||||
'endnumber': kw.get('endnumber', 6),
|
||||
'step': kw.get('step', 2),
|
||||
'address': kw.get('address'),
|
||||
'postcode': kw.get('postcode'),
|
||||
'country_code': kw.get('country_code'),
|
||||
'linegeo': kw.get('geometry', 'LINESTRING(1.1 -0.2, 1.09 -0.22)')})
|
||||
|
||||
{'place_id': kw.get('place_id', 10000),
|
||||
'osm_id': kw.get('osm_id', 4004),
|
||||
'parent_place_id': kw.get('parent_place_id'),
|
||||
'indexed_date': kw.get('indexed_date',
|
||||
dt.datetime(2022, 12, 7, 14, 14, 46, 0)),
|
||||
'startnumber': kw.get('startnumber', 2),
|
||||
'endnumber': kw.get('endnumber', 6),
|
||||
'step': kw.get('step', 2),
|
||||
'address': kw.get('address'),
|
||||
'postcode': kw.get('postcode'),
|
||||
'country_code': kw.get('country_code'),
|
||||
'linegeo': kw.get('geometry', 'LINESTRING(1.1 -0.2, 1.09 -0.22)')})
|
||||
|
||||
def add_tiger(self, **kw):
|
||||
self.add_data('tiger',
|
||||
{'place_id': kw.get('place_id', 30000),
|
||||
'parent_place_id': kw.get('parent_place_id'),
|
||||
'startnumber': kw.get('startnumber', 2),
|
||||
'endnumber': kw.get('endnumber', 6),
|
||||
'step': kw.get('step', 2),
|
||||
'postcode': kw.get('postcode'),
|
||||
'linegeo': kw.get('geometry', 'LINESTRING(1.1 -0.2, 1.09 -0.22)')})
|
||||
|
||||
{'place_id': kw.get('place_id', 30000),
|
||||
'parent_place_id': kw.get('parent_place_id'),
|
||||
'startnumber': kw.get('startnumber', 2),
|
||||
'endnumber': kw.get('endnumber', 6),
|
||||
'step': kw.get('step', 2),
|
||||
'postcode': kw.get('postcode'),
|
||||
'linegeo': kw.get('geometry', 'LINESTRING(1.1 -0.2, 1.09 -0.22)')})
|
||||
|
||||
def add_postcode(self, **kw):
|
||||
self.add_data('postcode',
|
||||
{'place_id': kw.get('place_id', 1000),
|
||||
'parent_place_id': kw.get('parent_place_id'),
|
||||
'country_code': kw.get('country_code'),
|
||||
'postcode': kw.get('postcode'),
|
||||
'rank_search': kw.get('rank_search', 20),
|
||||
'rank_address': kw.get('rank_address', 22),
|
||||
'indexed_date': kw.get('indexed_date',
|
||||
dt.datetime(2022, 12, 7, 14, 14, 46, 0)),
|
||||
'geometry': kw.get('geometry', 'POINT(23 34)')})
|
||||
|
||||
{'place_id': kw.get('place_id', 1000),
|
||||
'parent_place_id': kw.get('parent_place_id'),
|
||||
'country_code': kw.get('country_code'),
|
||||
'postcode': kw.get('postcode'),
|
||||
'rank_search': kw.get('rank_search', 20),
|
||||
'rank_address': kw.get('rank_address', 22),
|
||||
'indexed_date': kw.get('indexed_date',
|
||||
dt.datetime(2022, 12, 7, 14, 14, 46, 0)),
|
||||
'geometry': kw.get('geometry', 'POINT(23 34)')})
|
||||
|
||||
def add_country(self, country_code, geometry):
|
||||
self.add_data('country_grid',
|
||||
@@ -132,14 +124,12 @@ class APITester:
|
||||
'area': 0.1,
|
||||
'geometry': geometry})
|
||||
|
||||
|
||||
def add_country_name(self, country_code, names, partition=0):
|
||||
self.add_data('country_name',
|
||||
{'country_code': country_code,
|
||||
'name': names,
|
||||
'partition': partition})
|
||||
|
||||
|
||||
def add_search_name(self, place_id, **kw):
|
||||
centroid = kw.get('centroid', (23.0, 34.0))
|
||||
self.add_data('search_name',
|
||||
@@ -152,7 +142,6 @@ class APITester:
|
||||
'country_code': kw.get('country_code', 'xx'),
|
||||
'centroid': 'POINT(%f %f)' % centroid})
|
||||
|
||||
|
||||
def add_class_type_table(self, cls, typ):
|
||||
self.async_to_sync(
|
||||
self.exec_async(sa.text(f"""CREATE TABLE place_classtype_{cls}_{typ}
|
||||
@@ -160,7 +149,6 @@ class APITester:
|
||||
WHERE class = '{cls}' AND type = '{typ}')
|
||||
""")))
|
||||
|
||||
|
||||
def add_word_table(self, content):
|
||||
data = [dict(zip(['word_id', 'word_token', 'type', 'word', 'info'], c))
|
||||
for c in content]
|
||||
@@ -176,12 +164,10 @@ class APITester:
|
||||
|
||||
self.async_to_sync(_do_sql())
|
||||
|
||||
|
||||
async def exec_async(self, sql, *args, **kwargs):
|
||||
async with self.api._async_api.begin() as conn:
|
||||
return await conn.execute(sql, *args, **kwargs)
|
||||
|
||||
|
||||
async def create_tables(self):
|
||||
async with self.api._async_api._engine.begin() as conn:
|
||||
await conn.run_sync(self.api._async_api._tables.meta.create_all)
|
||||
@@ -212,11 +198,12 @@ def frontend(request, event_loop, tmp_path):
|
||||
db = str(tmp_path / 'test_nominatim_python_unittest.sqlite')
|
||||
|
||||
def mkapi(apiobj, options={'reverse'}):
|
||||
apiobj.add_data('properties',
|
||||
[{'property': 'tokenizer', 'value': 'icu'},
|
||||
{'property': 'tokenizer_import_normalisation', 'value': ':: lower();'},
|
||||
{'property': 'tokenizer_import_transliteration', 'value': "'1' > '/1/'; 'ä' > 'ä '"},
|
||||
])
|
||||
apiobj.add_data(
|
||||
'properties',
|
||||
[{'property': 'tokenizer', 'value': 'icu'},
|
||||
{'property': 'tokenizer_import_normalisation', 'value': ':: lower();'},
|
||||
{'property': 'tokenizer_import_transliteration',
|
||||
'value': "'1' > '/1/'; 'ä' > 'ä '"}])
|
||||
|
||||
async def _do_sql():
|
||||
async with apiobj.api._async_api.begin() as conn:
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# This file is part of Nominatim. (https://nominatim.org)
|
||||
#
|
||||
# Copyright (C) 2024 by the Nominatim developer community.
|
||||
# Copyright (C) 2025 by the Nominatim developer community.
|
||||
# For a full list of authors see the git log.
|
||||
"""
|
||||
Provides dummy implementations of ASGIAdaptor for testing.
|
||||
@@ -13,6 +13,7 @@ import nominatim_api.v1.server_glue as glue
|
||||
from nominatim_api.v1.format import dispatch as formatting
|
||||
from nominatim_api.config import Configuration
|
||||
|
||||
|
||||
class FakeError(BaseException):
|
||||
|
||||
def __init__(self, msg, status):
|
||||
@@ -22,8 +23,10 @@ class FakeError(BaseException):
|
||||
def __str__(self):
|
||||
return f'{self.status} -- {self.msg}'
|
||||
|
||||
|
||||
FakeResponse = namedtuple('FakeResponse', ['status', 'output', 'content_type'])
|
||||
|
||||
|
||||
class FakeAdaptor(glue.ASGIAdaptor):
|
||||
|
||||
def __init__(self, params=None, headers=None, config=None):
|
||||
@@ -31,23 +34,18 @@ class FakeAdaptor(glue.ASGIAdaptor):
|
||||
self.headers = headers or {}
|
||||
self._config = config or Configuration(None)
|
||||
|
||||
|
||||
def get(self, name, default=None):
|
||||
return self.params.get(name, default)
|
||||
|
||||
|
||||
def get_header(self, name, default=None):
|
||||
return self.headers.get(name, default)
|
||||
|
||||
|
||||
def error(self, msg, status=400):
|
||||
return FakeError(msg, status)
|
||||
|
||||
|
||||
def create_response(self, status, output, num_results):
|
||||
return FakeResponse(status, output, self.content_type)
|
||||
|
||||
|
||||
def base_uri(self):
|
||||
return 'http://test'
|
||||
|
||||
@@ -56,5 +54,3 @@ class FakeAdaptor(glue.ASGIAdaptor):
|
||||
|
||||
def formatting(self):
|
||||
return formatting
|
||||
|
||||
|
||||
|
||||
@@ -2,21 +2,18 @@
|
||||
#
|
||||
# This file is part of Nominatim. (https://nominatim.org)
|
||||
#
|
||||
# Copyright (C) 2024 by the Nominatim developer community.
|
||||
# Copyright (C) 2025 by the Nominatim developer community.
|
||||
# For a full list of authors see the git log.
|
||||
"""
|
||||
Tests for normalizing search queries.
|
||||
"""
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from icu import Transliterator
|
||||
|
||||
import nominatim_api.search.query as qmod
|
||||
from nominatim_api.query_preprocessing.config import QueryConfig
|
||||
from nominatim_api.query_preprocessing import normalize
|
||||
|
||||
|
||||
def run_preprocessor_on(query, norm):
|
||||
normalizer = Transliterator.createFromRules("normalization", norm)
|
||||
proc = normalize.create(QueryConfig().set_normalizer(normalizer))
|
||||
|
||||
@@ -7,16 +7,13 @@
|
||||
"""
|
||||
Tests for japanese phrase splitting.
|
||||
"""
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from icu import Transliterator
|
||||
|
||||
import nominatim_api.search.query as qmod
|
||||
from nominatim_api.query_preprocessing.config import QueryConfig
|
||||
from nominatim_api.query_preprocessing import split_japanese_phrases
|
||||
|
||||
|
||||
def run_preprocessor_on(query):
|
||||
proc = split_japanese_phrases.create(QueryConfig().set_normalizer(None))
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# This file is part of Nominatim. (https://nominatim.org)
|
||||
#
|
||||
# Copyright (C) 2024 by the Nominatim developer community.
|
||||
# Copyright (C) 2025 by the Nominatim developer community.
|
||||
# For a full list of authors see the git log.
|
||||
"""
|
||||
Tests for tokenized query data structures.
|
||||
@@ -11,6 +11,7 @@ import pytest
|
||||
|
||||
from nominatim_api.search import query
|
||||
|
||||
|
||||
class MyToken(query.Token):
|
||||
|
||||
def get_category(self):
|
||||
@@ -21,9 +22,11 @@ def mktoken(tid: int):
|
||||
return MyToken(penalty=3.0, token=tid, count=1, addr_count=1,
|
||||
lookup_word='foo')
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def qnode():
|
||||
return query.QueryNode(query.BREAK_PHRASE, query.PHRASE_ANY, 0.0 ,'', '')
|
||||
return query.QueryNode(query.BREAK_PHRASE, query.PHRASE_ANY, 0.0, '', '')
|
||||
|
||||
|
||||
@pytest.mark.parametrize('ptype,ttype', [(query.PHRASE_ANY, 'W'),
|
||||
(query.PHRASE_AMENITY, 'Q'),
|
||||
@@ -132,4 +135,3 @@ def test_query_struct_amenity_two_words():
|
||||
assert len(q.get_tokens(query.TokenRange(1, 2), query.TOKEN_PARTIAL)) == 1
|
||||
assert len(q.get_tokens(query.TokenRange(1, 2), query.TOKEN_NEAR_ITEM)) == 0
|
||||
assert len(q.get_tokens(query.TokenRange(1, 2), query.TOKEN_QUALIFIER)) == 1
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ from nominatim_api.search.token_assignment import TokenAssignment
|
||||
from nominatim_api.types import SearchDetails
|
||||
import nominatim_api.search.db_searches as dbs
|
||||
|
||||
|
||||
class MyToken(Token):
|
||||
def get_category(self):
|
||||
return 'this', 'that'
|
||||
@@ -36,7 +37,6 @@ def make_query(*args):
|
||||
token=tid, count=1, addr_count=1,
|
||||
lookup_word=word))
|
||||
|
||||
|
||||
return q
|
||||
|
||||
|
||||
@@ -241,8 +241,7 @@ def test_name_and_address():
|
||||
[(2, qmod.TOKEN_PARTIAL, [(2, 'b')]),
|
||||
(2, qmod.TOKEN_WORD, [(101, 'b')])],
|
||||
[(3, qmod.TOKEN_PARTIAL, [(3, 'c')]),
|
||||
(3, qmod.TOKEN_WORD, [(102, 'c')])]
|
||||
)
|
||||
(3, qmod.TOKEN_WORD, [(102, 'c')])])
|
||||
builder = SearchBuilder(q, SearchDetails())
|
||||
|
||||
searches = list(builder.build(TokenAssignment(name=TokenRange(0, 1),
|
||||
@@ -267,8 +266,7 @@ def test_name_and_complex_address():
|
||||
(3, qmod.TOKEN_WORD, [(101, 'bc')])],
|
||||
[(3, qmod.TOKEN_PARTIAL, [(3, 'c')])],
|
||||
[(4, qmod.TOKEN_PARTIAL, [(4, 'd')]),
|
||||
(4, qmod.TOKEN_WORD, [(103, 'd')])]
|
||||
)
|
||||
(4, qmod.TOKEN_WORD, [(103, 'd')])])
|
||||
builder = SearchBuilder(q, SearchDetails())
|
||||
|
||||
searches = list(builder.build(TokenAssignment(name=TokenRange(0, 1),
|
||||
@@ -423,8 +421,8 @@ def test_infrequent_partials_in_name():
|
||||
assert len(search.lookups) == 2
|
||||
assert len(search.rankings) == 2
|
||||
|
||||
assert set((l.column, l.lookup_type.__name__) for l in search.lookups) == \
|
||||
{('name_vector', 'LookupAll'), ('nameaddress_vector', 'Restrict')}
|
||||
assert set((s.column, s.lookup_type.__name__) for s in search.lookups) == \
|
||||
{('name_vector', 'LookupAll'), ('nameaddress_vector', 'Restrict')}
|
||||
|
||||
|
||||
def test_frequent_partials_in_name_and_address():
|
||||
@@ -435,10 +433,10 @@ def test_frequent_partials_in_name_and_address():
|
||||
assert all(isinstance(s, dbs.PlaceSearch) for s in searches)
|
||||
searches.sort(key=lambda s: s.penalty)
|
||||
|
||||
assert set((l.column, l.lookup_type.__name__) for l in searches[0].lookups) == \
|
||||
{('name_vector', 'LookupAny'), ('nameaddress_vector', 'Restrict')}
|
||||
assert set((l.column, l.lookup_type.__name__) for l in searches[1].lookups) == \
|
||||
{('nameaddress_vector', 'LookupAll'), ('name_vector', 'LookupAll')}
|
||||
assert set((s.column, s.lookup_type.__name__) for s in searches[0].lookups) == \
|
||||
{('name_vector', 'LookupAny'), ('nameaddress_vector', 'Restrict')}
|
||||
assert set((s.column, s.lookup_type.__name__) for s in searches[1].lookups) == \
|
||||
{('nameaddress_vector', 'LookupAll'), ('name_vector', 'LookupAll')}
|
||||
|
||||
|
||||
def test_too_frequent_partials_in_name_and_address():
|
||||
@@ -449,5 +447,5 @@ def test_too_frequent_partials_in_name_and_address():
|
||||
assert all(isinstance(s, dbs.PlaceSearch) for s in searches)
|
||||
searches.sort(key=lambda s: s.penalty)
|
||||
|
||||
assert set((l.column, l.lookup_type.__name__) for l in searches[0].lookups) == \
|
||||
{('name_vector', 'LookupAny'), ('nameaddress_vector', 'Restrict')}
|
||||
assert set((s.column, s.lookup_type.__name__) for s in searches[0].lookups) == \
|
||||
{('name_vector', 'LookupAny'), ('nameaddress_vector', 'Restrict')}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# This file is part of Nominatim. (https://nominatim.org)
|
||||
#
|
||||
# Copyright (C) 2024 by the Nominatim developer community.
|
||||
# Copyright (C) 2025 by the Nominatim developer community.
|
||||
# For a full list of authors see the git log.
|
||||
"""
|
||||
Tests for query analyzer for ICU tokenizer.
|
||||
@@ -16,7 +16,8 @@ import nominatim_api.search.query as qmod
|
||||
import nominatim_api.search.icu_tokenizer as tok
|
||||
from nominatim_api.logging import set_log_output, get_and_disable
|
||||
|
||||
async def add_word(conn, word_id, word_token, wtype, word, info = None):
|
||||
|
||||
async def add_word(conn, word_id, word_token, wtype, word, info=None):
|
||||
t = conn.t.meta.tables['word']
|
||||
await conn.execute(t.insert(), {'word_id': word_id,
|
||||
'word_token': word_token,
|
||||
@@ -28,6 +29,7 @@ async def add_word(conn, word_id, word_token, wtype, word, info = None):
|
||||
def make_phrase(query):
|
||||
return [Phrase(qmod.PHRASE_ANY, s) for s in query.split(',')]
|
||||
|
||||
|
||||
@pytest_asyncio.fixture
|
||||
async def conn(table_factory):
|
||||
""" Create an asynchronous SQLAlchemy engine for the test DB.
|
||||
@@ -102,8 +104,7 @@ async def test_splitting_in_transliteration(conn):
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.parametrize('term,order', [('23456', ['P', 'H', 'W', 'w']),
|
||||
('3', ['H', 'W', 'w'])
|
||||
])
|
||||
('3', ['H', 'W', 'w'])])
|
||||
async def test_penalty_postcodes_and_housenumbers(conn, term, order):
|
||||
ana = await tok.create_query_analyzer(conn)
|
||||
|
||||
@@ -120,6 +121,7 @@ async def test_penalty_postcodes_and_housenumbers(conn, term, order):
|
||||
|
||||
assert [t[1] for t in torder] == order
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_category_words_only_at_beginning(conn):
|
||||
ana = await tok.create_query_analyzer(conn)
|
||||
|
||||
@@ -16,6 +16,7 @@ import pytest
|
||||
from nominatim_api.search.postcode_parser import PostcodeParser
|
||||
from nominatim_api.search.query import QueryStruct, PHRASE_ANY, PHRASE_POSTCODE, PHRASE_STREET
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def pc_config(project_env):
|
||||
country_file = project_env.project_dir / 'country_settings.yaml'
|
||||
@@ -55,6 +56,7 @@ ky:
|
||||
|
||||
return project_env
|
||||
|
||||
|
||||
def mk_query(inp):
|
||||
query = QueryStruct([])
|
||||
phrase_split = re.split(r"([ ,:'-])", inp)
|
||||
@@ -80,6 +82,7 @@ def test_simple_postcode(pc_config, query, pos):
|
||||
|
||||
assert result == {(pos, pos + 1, '45325'), (pos, pos + 1, '453 25')}
|
||||
|
||||
|
||||
def test_contained_postcode(pc_config):
|
||||
parser = PostcodeParser(pc_config)
|
||||
|
||||
@@ -87,7 +90,6 @@ def test_contained_postcode(pc_config):
|
||||
(0, 2, '12345 DX')}
|
||||
|
||||
|
||||
|
||||
@pytest.mark.parametrize('query,frm,to', [('345987', 0, 1), ('345 987', 0, 2),
|
||||
('Aina 345 987', 1, 3),
|
||||
('Aina 23 345 987 ff', 2, 4)])
|
||||
@@ -98,6 +100,7 @@ def test_postcode_with_space(pc_config, query, frm, to):
|
||||
|
||||
assert result == {(frm, to, '345987')}
|
||||
|
||||
|
||||
def test_overlapping_postcode(pc_config):
|
||||
parser = PostcodeParser(pc_config)
|
||||
|
||||
@@ -131,6 +134,7 @@ def test_postcode_with_non_matching_country_prefix(pc_config):
|
||||
|
||||
assert not parser.parse(mk_query('ky12233'))
|
||||
|
||||
|
||||
def test_postcode_inside_postcode_phrase(pc_config):
|
||||
parser = PostcodeParser(pc_config)
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# This file is part of Nominatim. (https://nominatim.org)
|
||||
#
|
||||
# Copyright (C) 2024 by the Nominatim developer community.
|
||||
# Copyright (C) 2025 by the Nominatim developer community.
|
||||
# For a full list of authors see the git log.
|
||||
"""
|
||||
Test data types for search queries.
|
||||
@@ -11,14 +11,15 @@ import pytest
|
||||
|
||||
import nominatim_api.search.query as nq
|
||||
|
||||
|
||||
def test_token_range_equal():
|
||||
assert nq.TokenRange(2, 3) == nq.TokenRange(2, 3)
|
||||
assert not (nq.TokenRange(2, 3) != nq.TokenRange(2, 3))
|
||||
|
||||
|
||||
@pytest.mark.parametrize('lop,rop', [((1, 2), (3, 4)),
|
||||
((3, 4), (3, 5)),
|
||||
((10, 12), (11, 12))])
|
||||
((3, 4), (3, 5)),
|
||||
((10, 12), (11, 12))])
|
||||
def test_token_range_unequal(lop, rop):
|
||||
assert not (nq.TokenRange(*lop) == nq.TokenRange(*rop))
|
||||
assert nq.TokenRange(*lop) != nq.TokenRange(*rop)
|
||||
@@ -28,17 +29,17 @@ def test_token_range_lt():
|
||||
assert nq.TokenRange(1, 3) < nq.TokenRange(10, 12)
|
||||
assert nq.TokenRange(5, 6) < nq.TokenRange(7, 8)
|
||||
assert nq.TokenRange(1, 4) < nq.TokenRange(4, 5)
|
||||
assert not(nq.TokenRange(5, 6) < nq.TokenRange(5, 6))
|
||||
assert not(nq.TokenRange(10, 11) < nq.TokenRange(4, 5))
|
||||
assert not (nq.TokenRange(5, 6) < nq.TokenRange(5, 6))
|
||||
assert not (nq.TokenRange(10, 11) < nq.TokenRange(4, 5))
|
||||
|
||||
|
||||
def test_token_rankge_gt():
|
||||
assert nq.TokenRange(3, 4) > nq.TokenRange(1, 2)
|
||||
assert nq.TokenRange(100, 200) > nq.TokenRange(10, 11)
|
||||
assert nq.TokenRange(10, 11) > nq.TokenRange(4, 10)
|
||||
assert not(nq.TokenRange(5, 6) > nq.TokenRange(5, 6))
|
||||
assert not(nq.TokenRange(1, 2) > nq.TokenRange(3, 4))
|
||||
assert not(nq.TokenRange(4, 10) > nq.TokenRange(3, 5))
|
||||
assert not (nq.TokenRange(5, 6) > nq.TokenRange(5, 6))
|
||||
assert not (nq.TokenRange(1, 2) > nq.TokenRange(3, 4))
|
||||
assert not (nq.TokenRange(4, 10) > nq.TokenRange(3, 5))
|
||||
|
||||
|
||||
def test_token_range_unimplemented_ops():
|
||||
@@ -58,8 +59,7 @@ def test_query_extract_words():
|
||||
words = q.extract_words(base_penalty=1.0)
|
||||
|
||||
assert set(words.keys()) \
|
||||
== {'12', 'ab', 'hallo', '12 ab', 'ab 12', '12 ab 12'}
|
||||
== {'12', 'ab', 'hallo', '12 ab', 'ab 12', '12 ab 12'}
|
||||
assert sorted(words['12']) == [nq.TokenRange(0, 1, 1.0), nq.TokenRange(2, 3, 1.0)]
|
||||
assert words['12 ab'] == [nq.TokenRange(0, 2, 1.1)]
|
||||
assert words['hallo'] == [nq.TokenRange(3, 4, 1.0)]
|
||||
|
||||
|
||||
@@ -2,18 +2,17 @@
|
||||
#
|
||||
# This file is part of Nominatim. (https://nominatim.org)
|
||||
#
|
||||
# Copyright (C) 2024 by the Nominatim developer community.
|
||||
# Copyright (C) 2025 by the Nominatim developer community.
|
||||
# For a full list of authors see the git log.
|
||||
"""
|
||||
Tests for query analyzer creation.
|
||||
"""
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from nominatim_api.search.query_analyzer_factory import make_query_analyzer
|
||||
from nominatim_api.search.icu_tokenizer import ICUQueryAnalyzer
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_import_icu_tokenizer(table_factory, api):
|
||||
table_factory('nominatim_properties',
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# This file is part of Nominatim. (https://nominatim.org)
|
||||
#
|
||||
# Copyright (C) 2024 by the Nominatim developer community.
|
||||
# Copyright (C) 2025 by the Nominatim developer community.
|
||||
# For a full list of authors see the git log.
|
||||
"""
|
||||
Tests for running the country searcher.
|
||||
@@ -48,6 +48,7 @@ def test_find_from_placex(apiobj, frontend):
|
||||
assert results[0].place_id == 55
|
||||
assert results[0].accuracy == 0.8
|
||||
|
||||
|
||||
def test_find_from_fallback_countries(apiobj, frontend):
|
||||
apiobj.add_country('ro', 'POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))')
|
||||
apiobj.add_country_name('ro', {'name': 'România'})
|
||||
@@ -87,7 +88,6 @@ class TestCountryParameters:
|
||||
apiobj.add_country('ro', 'POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))')
|
||||
apiobj.add_country_name('ro', {'name': 'România'})
|
||||
|
||||
|
||||
@pytest.mark.parametrize('geom', [napi.GeometryFormat.GEOJSON,
|
||||
napi.GeometryFormat.KML,
|
||||
napi.GeometryFormat.SVG,
|
||||
@@ -100,7 +100,6 @@ class TestCountryParameters:
|
||||
assert len(results) == 1
|
||||
assert geom.name.lower() in results[0].geometry
|
||||
|
||||
|
||||
@pytest.mark.parametrize('pid,rids', [(76, [55]), (55, [])])
|
||||
def test_exclude_place_id(self, apiobj, frontend, pid, rids):
|
||||
results = run_search(apiobj, frontend, 0.5, ['yw', 'ro'],
|
||||
@@ -108,7 +107,6 @@ class TestCountryParameters:
|
||||
|
||||
assert [r.place_id for r in results] == rids
|
||||
|
||||
|
||||
@pytest.mark.parametrize('viewbox,rids', [((9, 9, 11, 11), [55]),
|
||||
((-10, -10, -3, -3), [])])
|
||||
def test_bounded_viewbox_in_placex(self, apiobj, frontend, viewbox, rids):
|
||||
@@ -118,9 +116,8 @@ class TestCountryParameters:
|
||||
|
||||
assert [r.place_id for r in results] == rids
|
||||
|
||||
|
||||
@pytest.mark.parametrize('viewbox,numres', [((0, 0, 1, 1), 1),
|
||||
((-10, -10, -3, -3), 0)])
|
||||
((-10, -10, -3, -3), 0)])
|
||||
def test_bounded_viewbox_in_fallback(self, apiobj, frontend, viewbox, numres):
|
||||
results = run_search(apiobj, frontend, 0.5, ['ro'],
|
||||
details=SearchDetails.from_kwargs({'viewbox': viewbox,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# This file is part of Nominatim. (https://nominatim.org)
|
||||
#
|
||||
# Copyright (C) 2024 by the Nominatim developer community.
|
||||
# Copyright (C) 2025 by the Nominatim developer community.
|
||||
# For a full list of authors see the git log.
|
||||
"""
|
||||
Tests for running the near searcher.
|
||||
@@ -12,8 +12,8 @@ import pytest
|
||||
import nominatim_api as napi
|
||||
from nominatim_api.types import SearchDetails
|
||||
from nominatim_api.search.db_searches import NearSearch, PlaceSearch
|
||||
from nominatim_api.search.db_search_fields import WeightedStrings, WeightedCategories,\
|
||||
FieldLookup, FieldRanking, RankedTokens
|
||||
from nominatim_api.search.db_search_fields import WeightedStrings, WeightedCategories, \
|
||||
FieldLookup
|
||||
from nominatim_api.search.db_search_lookups import LookupAll
|
||||
|
||||
|
||||
@@ -80,7 +80,6 @@ class TestNearSearch:
|
||||
apiobj.add_search_name(101, names=[56], country_code='mx',
|
||||
centroid=(-10.3, 56.9))
|
||||
|
||||
|
||||
def test_near_in_placex(self, apiobj, frontend):
|
||||
apiobj.add_placex(place_id=22, class_='amenity', type='bank',
|
||||
centroid=(5.6001, 4.2994))
|
||||
@@ -91,7 +90,6 @@ class TestNearSearch:
|
||||
|
||||
assert [r.place_id for r in results] == [22]
|
||||
|
||||
|
||||
def test_multiple_types_near_in_placex(self, apiobj, frontend):
|
||||
apiobj.add_placex(place_id=22, class_='amenity', type='bank',
|
||||
importance=0.002,
|
||||
@@ -105,7 +103,6 @@ class TestNearSearch:
|
||||
|
||||
assert [r.place_id for r in results] == [22, 23]
|
||||
|
||||
|
||||
def test_near_in_classtype(self, apiobj, frontend):
|
||||
apiobj.add_placex(place_id=22, class_='amenity', type='bank',
|
||||
centroid=(5.6, 4.34))
|
||||
@@ -118,7 +115,6 @@ class TestNearSearch:
|
||||
|
||||
assert [r.place_id for r in results] == [22]
|
||||
|
||||
|
||||
@pytest.mark.parametrize('cc,rid', [('us', 22), ('mx', 23)])
|
||||
def test_restrict_by_country(self, apiobj, frontend, cc, rid):
|
||||
apiobj.add_placex(place_id=22, class_='amenity', type='bank',
|
||||
@@ -138,7 +134,6 @@ class TestNearSearch:
|
||||
|
||||
assert [r.place_id for r in results] == [rid]
|
||||
|
||||
|
||||
@pytest.mark.parametrize('excluded,rid', [(22, 122), (122, 22)])
|
||||
def test_exclude_place_by_id(self, apiobj, frontend, excluded, rid):
|
||||
apiobj.add_placex(place_id=22, class_='amenity', type='bank',
|
||||
@@ -148,13 +143,11 @@ class TestNearSearch:
|
||||
centroid=(5.6001, 4.2994),
|
||||
country_code='us')
|
||||
|
||||
|
||||
results = run_search(apiobj, frontend, 0.1, [('amenity', 'bank')],
|
||||
details=SearchDetails(excluded=[excluded]))
|
||||
|
||||
assert [r.place_id for r in results] == [rid]
|
||||
|
||||
|
||||
@pytest.mark.parametrize('layer,rids', [(napi.DataLayer.POI, [22]),
|
||||
(napi.DataLayer.MANMADE, [])])
|
||||
def test_with_layer(self, apiobj, frontend, layer, rids):
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# This file is part of Nominatim. (https://nominatim.org)
|
||||
#
|
||||
# Copyright (C) 2024 by the Nominatim developer community.
|
||||
# Copyright (C) 2025 by the Nominatim developer community.
|
||||
# For a full list of authors see the git log.
|
||||
"""
|
||||
Tests for running the generic place searcher.
|
||||
@@ -14,12 +14,13 @@ import pytest
|
||||
import nominatim_api as napi
|
||||
from nominatim_api.types import SearchDetails
|
||||
from nominatim_api.search.db_searches import PlaceSearch
|
||||
from nominatim_api.search.db_search_fields import WeightedStrings, WeightedCategories,\
|
||||
from nominatim_api.search.db_search_fields import WeightedStrings, WeightedCategories, \
|
||||
FieldLookup, FieldRanking, RankedTokens
|
||||
from nominatim_api.search.db_search_lookups import LookupAll, LookupAny, Restrict
|
||||
|
||||
APIOPTIONS = ['search']
|
||||
|
||||
|
||||
def run_search(apiobj, frontend, global_penalty, lookup, ranking, count=2,
|
||||
hnrs=[], pcs=[], ccodes=[], quals=[],
|
||||
details=SearchDetails()):
|
||||
@@ -55,29 +56,27 @@ class TestNameOnlySearches:
|
||||
def fill_database(self, apiobj):
|
||||
apiobj.add_placex(place_id=100, country_code='us',
|
||||
centroid=(5.6, 4.3))
|
||||
apiobj.add_search_name(100, names=[1,2,10,11], country_code='us',
|
||||
apiobj.add_search_name(100, names=[1, 2, 10, 11], country_code='us',
|
||||
centroid=(5.6, 4.3))
|
||||
apiobj.add_placex(place_id=101, country_code='mx',
|
||||
centroid=(-10.3, 56.9))
|
||||
apiobj.add_search_name(101, names=[1,2,20,21], country_code='mx',
|
||||
apiobj.add_search_name(101, names=[1, 2, 20, 21], country_code='mx',
|
||||
centroid=(-10.3, 56.9))
|
||||
|
||||
|
||||
@pytest.mark.parametrize('lookup_type', [LookupAll, Restrict])
|
||||
@pytest.mark.parametrize('rank,res', [([10], [100, 101]),
|
||||
([20], [101, 100])])
|
||||
def test_lookup_all_match(self, apiobj, frontend, lookup_type, rank, res):
|
||||
lookup = FieldLookup('name_vector', [1,2], lookup_type)
|
||||
lookup = FieldLookup('name_vector', [1, 2], lookup_type)
|
||||
ranking = FieldRanking('name_vector', 0.4, [RankedTokens(0.0, rank)])
|
||||
|
||||
results = run_search(apiobj, frontend, 0.1, [lookup], [ranking])
|
||||
|
||||
assert [r.place_id for r in results] == res
|
||||
|
||||
|
||||
@pytest.mark.parametrize('lookup_type', [LookupAll, Restrict])
|
||||
def test_lookup_all_partial_match(self, apiobj, frontend, lookup_type):
|
||||
lookup = FieldLookup('name_vector', [1,20], lookup_type)
|
||||
lookup = FieldLookup('name_vector', [1, 20], lookup_type)
|
||||
ranking = FieldRanking('name_vector', 0.4, [RankedTokens(0.0, [21])])
|
||||
|
||||
results = run_search(apiobj, frontend, 0.1, [lookup], [ranking])
|
||||
@@ -88,14 +87,13 @@ class TestNameOnlySearches:
|
||||
@pytest.mark.parametrize('rank,res', [([10], [100, 101]),
|
||||
([20], [101, 100])])
|
||||
def test_lookup_any_match(self, apiobj, frontend, rank, res):
|
||||
lookup = FieldLookup('name_vector', [11,21], LookupAny)
|
||||
lookup = FieldLookup('name_vector', [11, 21], LookupAny)
|
||||
ranking = FieldRanking('name_vector', 0.4, [RankedTokens(0.0, rank)])
|
||||
|
||||
results = run_search(apiobj, frontend, 0.1, [lookup], [ranking])
|
||||
|
||||
assert [r.place_id for r in results] == res
|
||||
|
||||
|
||||
def test_lookup_any_partial_match(self, apiobj, frontend):
|
||||
lookup = FieldLookup('name_vector', [20], LookupAll)
|
||||
ranking = FieldRanking('name_vector', 0.4, [RankedTokens(0.0, [21])])
|
||||
@@ -105,19 +103,17 @@ class TestNameOnlySearches:
|
||||
assert len(results) == 1
|
||||
assert results[0].place_id == 101
|
||||
|
||||
|
||||
@pytest.mark.parametrize('cc,res', [('us', 100), ('mx', 101)])
|
||||
def test_lookup_restrict_country(self, apiobj, frontend, cc, res):
|
||||
lookup = FieldLookup('name_vector', [1,2], LookupAll)
|
||||
lookup = FieldLookup('name_vector', [1, 2], LookupAll)
|
||||
ranking = FieldRanking('name_vector', 0.4, [RankedTokens(0.0, [10])])
|
||||
|
||||
results = run_search(apiobj, frontend, 0.1, [lookup], [ranking], ccodes=[cc])
|
||||
|
||||
assert [r.place_id for r in results] == [res]
|
||||
|
||||
|
||||
def test_lookup_restrict_placeid(self, apiobj, frontend):
|
||||
lookup = FieldLookup('name_vector', [1,2], LookupAll)
|
||||
lookup = FieldLookup('name_vector', [1, 2], LookupAll)
|
||||
ranking = FieldRanking('name_vector', 0.4, [RankedTokens(0.0, [10])])
|
||||
|
||||
results = run_search(apiobj, frontend, 0.1, [lookup], [ranking],
|
||||
@@ -125,7 +121,6 @@ class TestNameOnlySearches:
|
||||
|
||||
assert [r.place_id for r in results] == [100]
|
||||
|
||||
|
||||
@pytest.mark.parametrize('geom', [napi.GeometryFormat.GEOJSON,
|
||||
napi.GeometryFormat.KML,
|
||||
napi.GeometryFormat.SVG,
|
||||
@@ -139,7 +134,6 @@ class TestNameOnlySearches:
|
||||
|
||||
assert geom.name.lower() in results[0].geometry
|
||||
|
||||
|
||||
@pytest.mark.parametrize('factor,npoints', [(0.0, 3), (1.0, 2)])
|
||||
def test_return_simplified_geometry(self, apiobj, frontend, factor, npoints):
|
||||
apiobj.add_placex(place_id=333, country_code='us',
|
||||
@@ -162,7 +156,6 @@ class TestNameOnlySearches:
|
||||
assert result.place_id == 333
|
||||
assert len(geom['coordinates']) == npoints
|
||||
|
||||
|
||||
@pytest.mark.parametrize('viewbox', ['5.0,4.0,6.0,5.0', '5.7,4.0,6.0,5.0'])
|
||||
@pytest.mark.parametrize('wcount,rids', [(2, [100, 101]), (20000, [100])])
|
||||
def test_prefer_viewbox(self, apiobj, frontend, viewbox, wcount, rids):
|
||||
@@ -177,18 +170,16 @@ class TestNameOnlySearches:
|
||||
details=SearchDetails.from_kwargs({'viewbox': viewbox}))
|
||||
assert [r.place_id for r in results] == rids
|
||||
|
||||
|
||||
@pytest.mark.parametrize('viewbox', ['5.0,4.0,6.0,5.0', '5.55,4.27,5.62,4.31'])
|
||||
def test_force_viewbox(self, apiobj, frontend, viewbox):
|
||||
lookup = FieldLookup('name_vector', [1, 2], LookupAll)
|
||||
|
||||
details=SearchDetails.from_kwargs({'viewbox': viewbox,
|
||||
'bounded_viewbox': True})
|
||||
details = SearchDetails.from_kwargs({'viewbox': viewbox,
|
||||
'bounded_viewbox': True})
|
||||
|
||||
results = run_search(apiobj, frontend, 0.1, [lookup], [], details=details)
|
||||
assert [r.place_id for r in results] == [100]
|
||||
|
||||
|
||||
def test_prefer_near(self, apiobj, frontend):
|
||||
lookup = FieldLookup('name_vector', [1, 2], LookupAll)
|
||||
ranking = FieldRanking('name_vector', 0.4, [RankedTokens(0.0, [21])])
|
||||
@@ -202,13 +193,12 @@ class TestNameOnlySearches:
|
||||
results.sort(key=lambda r: -r.importance)
|
||||
assert [r.place_id for r in results] == [100, 101]
|
||||
|
||||
|
||||
@pytest.mark.parametrize('radius', [0.09, 0.11])
|
||||
def test_force_near(self, apiobj, frontend, radius):
|
||||
lookup = FieldLookup('name_vector', [1, 2], LookupAll)
|
||||
|
||||
details=SearchDetails.from_kwargs({'near': '5.6,4.3',
|
||||
'near_radius': radius})
|
||||
details = SearchDetails.from_kwargs({'near': '5.6,4.3',
|
||||
'near_radius': radius})
|
||||
|
||||
results = run_search(apiobj, frontend, 0.1, [lookup], [], details=details)
|
||||
|
||||
@@ -228,7 +218,7 @@ class TestStreetWithHousenumber:
|
||||
apiobj.add_placex(place_id=1000, class_='highway', type='residential',
|
||||
rank_search=26, rank_address=26,
|
||||
country_code='es')
|
||||
apiobj.add_search_name(1000, names=[1,2,10,11],
|
||||
apiobj.add_search_name(1000, names=[1, 2, 10, 11],
|
||||
search_rank=26, address_rank=26,
|
||||
country_code='es')
|
||||
apiobj.add_placex(place_id=91, class_='place', type='house',
|
||||
@@ -243,26 +233,24 @@ class TestStreetWithHousenumber:
|
||||
apiobj.add_placex(place_id=2000, class_='highway', type='residential',
|
||||
rank_search=26, rank_address=26,
|
||||
country_code='pt')
|
||||
apiobj.add_search_name(2000, names=[1,2,20,21],
|
||||
apiobj.add_search_name(2000, names=[1, 2, 20, 21],
|
||||
search_rank=26, address_rank=26,
|
||||
country_code='pt')
|
||||
|
||||
|
||||
@pytest.mark.parametrize('hnr,res', [('20', [91, 1]), ('20 a', [1]),
|
||||
('21', [2]), ('22', [2, 92]),
|
||||
('24', [93]), ('25', [])])
|
||||
def test_lookup_by_single_housenumber(self, apiobj, frontend, hnr, res):
|
||||
lookup = FieldLookup('name_vector', [1,2], LookupAll)
|
||||
lookup = FieldLookup('name_vector', [1, 2], LookupAll)
|
||||
ranking = FieldRanking('name_vector', 0.3, [RankedTokens(0.0, [10])])
|
||||
|
||||
results = run_search(apiobj, frontend, 0.1, [lookup], [ranking], hnrs=[hnr])
|
||||
|
||||
assert [r.place_id for r in results] == res + [1000, 2000]
|
||||
|
||||
|
||||
@pytest.mark.parametrize('cc,res', [('es', [2, 1000]), ('pt', [92, 2000])])
|
||||
def test_lookup_with_country_restriction(self, apiobj, frontend, cc, res):
|
||||
lookup = FieldLookup('name_vector', [1,2], LookupAll)
|
||||
lookup = FieldLookup('name_vector', [1, 2], LookupAll)
|
||||
ranking = FieldRanking('name_vector', 0.3, [RankedTokens(0.0, [10])])
|
||||
|
||||
results = run_search(apiobj, frontend, 0.1, [lookup], [ranking], hnrs=['22'],
|
||||
@@ -270,9 +258,8 @@ class TestStreetWithHousenumber:
|
||||
|
||||
assert [r.place_id for r in results] == res
|
||||
|
||||
|
||||
def test_lookup_exclude_housenumber_placeid(self, apiobj, frontend):
|
||||
lookup = FieldLookup('name_vector', [1,2], LookupAll)
|
||||
lookup = FieldLookup('name_vector', [1, 2], LookupAll)
|
||||
ranking = FieldRanking('name_vector', 0.3, [RankedTokens(0.0, [10])])
|
||||
|
||||
results = run_search(apiobj, frontend, 0.1, [lookup], [ranking], hnrs=['22'],
|
||||
@@ -280,9 +267,8 @@ class TestStreetWithHousenumber:
|
||||
|
||||
assert [r.place_id for r in results] == [2, 1000, 2000]
|
||||
|
||||
|
||||
def test_lookup_exclude_street_placeid(self, apiobj, frontend):
|
||||
lookup = FieldLookup('name_vector', [1,2], LookupAll)
|
||||
lookup = FieldLookup('name_vector', [1, 2], LookupAll)
|
||||
ranking = FieldRanking('name_vector', 0.3, [RankedTokens(0.0, [10])])
|
||||
|
||||
results = run_search(apiobj, frontend, 0.1, [lookup], [ranking], hnrs=['22'],
|
||||
@@ -290,9 +276,8 @@ class TestStreetWithHousenumber:
|
||||
|
||||
assert [r.place_id for r in results] == [2, 92, 2000]
|
||||
|
||||
|
||||
def test_lookup_only_house_qualifier(self, apiobj, frontend):
|
||||
lookup = FieldLookup('name_vector', [1,2], LookupAll)
|
||||
lookup = FieldLookup('name_vector', [1, 2], LookupAll)
|
||||
ranking = FieldRanking('name_vector', 0.3, [RankedTokens(0.0, [10])])
|
||||
|
||||
results = run_search(apiobj, frontend, 0.1, [lookup], [ranking], hnrs=['22'],
|
||||
@@ -300,9 +285,8 @@ class TestStreetWithHousenumber:
|
||||
|
||||
assert [r.place_id for r in results] == [2, 92]
|
||||
|
||||
|
||||
def test_lookup_only_street_qualifier(self, apiobj, frontend):
|
||||
lookup = FieldLookup('name_vector', [1,2], LookupAll)
|
||||
lookup = FieldLookup('name_vector', [1, 2], LookupAll)
|
||||
ranking = FieldRanking('name_vector', 0.3, [RankedTokens(0.0, [10])])
|
||||
|
||||
results = run_search(apiobj, frontend, 0.1, [lookup], [ranking], hnrs=['22'],
|
||||
@@ -310,10 +294,9 @@ class TestStreetWithHousenumber:
|
||||
|
||||
assert [r.place_id for r in results] == [1000, 2000]
|
||||
|
||||
|
||||
@pytest.mark.parametrize('rank,found', [(26, True), (27, False), (30, False)])
|
||||
def test_lookup_min_rank(self, apiobj, frontend, rank, found):
|
||||
lookup = FieldLookup('name_vector', [1,2], LookupAll)
|
||||
lookup = FieldLookup('name_vector', [1, 2], LookupAll)
|
||||
ranking = FieldRanking('name_vector', 0.3, [RankedTokens(0.0, [10])])
|
||||
|
||||
results = run_search(apiobj, frontend, 0.1, [lookup], [ranking], hnrs=['22'],
|
||||
@@ -321,7 +304,6 @@ class TestStreetWithHousenumber:
|
||||
|
||||
assert [r.place_id for r in results] == ([2, 92, 1000, 2000] if found else [2, 92])
|
||||
|
||||
|
||||
@pytest.mark.parametrize('geom', [napi.GeometryFormat.GEOJSON,
|
||||
napi.GeometryFormat.KML,
|
||||
napi.GeometryFormat.SVG,
|
||||
@@ -343,7 +325,7 @@ def test_very_large_housenumber(apiobj, frontend):
|
||||
apiobj.add_placex(place_id=2000, class_='highway', type='residential',
|
||||
rank_search=26, rank_address=26,
|
||||
country_code='pt')
|
||||
apiobj.add_search_name(2000, names=[1,2],
|
||||
apiobj.add_search_name(2000, names=[1, 2],
|
||||
search_rank=26, address_rank=26,
|
||||
country_code='pt')
|
||||
|
||||
@@ -405,7 +387,6 @@ class TestInterpolations:
|
||||
centroid=(10.0, 10.00001),
|
||||
geometry='LINESTRING(9.995 10.00001, 10.005 10.00001)')
|
||||
|
||||
|
||||
@pytest.mark.parametrize('hnr,res', [('21', [992]), ('22', []), ('23', [991])])
|
||||
def test_lookup_housenumber(self, apiobj, frontend, hnr, res):
|
||||
lookup = FieldLookup('name_vector', [111], LookupAll)
|
||||
@@ -414,7 +395,6 @@ class TestInterpolations:
|
||||
|
||||
assert [r.place_id for r in results] == res + [990]
|
||||
|
||||
|
||||
@pytest.mark.parametrize('geom', [napi.GeometryFormat.GEOJSON,
|
||||
napi.GeometryFormat.KML,
|
||||
napi.GeometryFormat.SVG,
|
||||
@@ -429,7 +409,6 @@ class TestInterpolations:
|
||||
assert geom.name.lower() in results[0].geometry
|
||||
|
||||
|
||||
|
||||
class TestTiger:
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
@@ -453,7 +432,6 @@ class TestTiger:
|
||||
centroid=(10.0, 10.00001),
|
||||
geometry='LINESTRING(9.995 10.00001, 10.005 10.00001)')
|
||||
|
||||
|
||||
@pytest.mark.parametrize('hnr,res', [('21', [992]), ('22', []), ('23', [991])])
|
||||
def test_lookup_housenumber(self, apiobj, frontend, hnr, res):
|
||||
lookup = FieldLookup('name_vector', [111], LookupAll)
|
||||
@@ -462,7 +440,6 @@ class TestTiger:
|
||||
|
||||
assert [r.place_id for r in results] == res + [990]
|
||||
|
||||
|
||||
@pytest.mark.parametrize('geom', [napi.GeometryFormat.GEOJSON,
|
||||
napi.GeometryFormat.KML,
|
||||
napi.GeometryFormat.SVG,
|
||||
@@ -513,15 +490,15 @@ class TestLayersRank30:
|
||||
importance=0.0005,
|
||||
address_rank=0, search_rank=30)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('layer,res', [(napi.DataLayer.ADDRESS, [223]),
|
||||
(napi.DataLayer.POI, [224]),
|
||||
(napi.DataLayer.ADDRESS | napi.DataLayer.POI, [223, 224]),
|
||||
(napi.DataLayer.MANMADE, [225]),
|
||||
(napi.DataLayer.RAILWAY, [226]),
|
||||
(napi.DataLayer.NATURAL, [227]),
|
||||
(napi.DataLayer.MANMADE | napi.DataLayer.NATURAL, [225, 227]),
|
||||
(napi.DataLayer.MANMADE | napi.DataLayer.RAILWAY, [225, 226])])
|
||||
@pytest.mark.parametrize('layer,res',
|
||||
[(napi.DataLayer.ADDRESS, [223]),
|
||||
(napi.DataLayer.POI, [224]),
|
||||
(napi.DataLayer.ADDRESS | napi.DataLayer.POI, [223, 224]),
|
||||
(napi.DataLayer.MANMADE, [225]),
|
||||
(napi.DataLayer.RAILWAY, [226]),
|
||||
(napi.DataLayer.NATURAL, [227]),
|
||||
(napi.DataLayer.MANMADE | napi.DataLayer.NATURAL, [225, 227]),
|
||||
(napi.DataLayer.MANMADE | napi.DataLayer.RAILWAY, [225, 226])])
|
||||
def test_layers_rank30(self, apiobj, frontend, layer, res):
|
||||
lookup = FieldLookup('name_vector', [34], LookupAny)
|
||||
|
||||
|
||||
@@ -2,14 +2,13 @@
|
||||
#
|
||||
# This file is part of Nominatim. (https://nominatim.org)
|
||||
#
|
||||
# Copyright (C) 2024 by the Nominatim developer community.
|
||||
# Copyright (C) 2025 by the Nominatim developer community.
|
||||
# For a full list of authors see the git log.
|
||||
"""
|
||||
Tests for running the POI searcher.
|
||||
"""
|
||||
import pytest
|
||||
|
||||
import nominatim_api as napi
|
||||
from nominatim_api.types import SearchDetails
|
||||
from nominatim_api.search.db_searches import PoiSearch
|
||||
from nominatim_api.search.db_search_fields import WeightedStrings, WeightedCategories
|
||||
@@ -84,14 +83,12 @@ class TestPoiSearchWithRestrictions:
|
||||
else:
|
||||
self.args = {'near': '34.3, 56.100021', 'near_radius': 0.001}
|
||||
|
||||
|
||||
def test_unrestricted(self, apiobj, frontend):
|
||||
results = run_search(apiobj, frontend, 0.1, [('highway', 'bus_stop')], [0.5],
|
||||
details=SearchDetails.from_kwargs(self.args))
|
||||
|
||||
assert [r.place_id for r in results] == [1, 2]
|
||||
|
||||
|
||||
def test_restict_country(self, apiobj, frontend):
|
||||
results = run_search(apiobj, frontend, 0.1, [('highway', 'bus_stop')], [0.5],
|
||||
ccodes=['de', 'nz'],
|
||||
@@ -99,7 +96,6 @@ class TestPoiSearchWithRestrictions:
|
||||
|
||||
assert [r.place_id for r in results] == [2]
|
||||
|
||||
|
||||
def test_restrict_by_viewbox(self, apiobj, frontend):
|
||||
args = {'bounded_viewbox': True, 'viewbox': '34.299,56.0,34.3001,56.10001'}
|
||||
args.update(self.args)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# This file is part of Nominatim. (https://nominatim.org)
|
||||
#
|
||||
# Copyright (C) 2024 by the Nominatim developer community.
|
||||
# Copyright (C) 2025 by the Nominatim developer community.
|
||||
# For a full list of authors see the git log.
|
||||
"""
|
||||
Tests for running the postcode searcher.
|
||||
@@ -15,6 +15,7 @@ from nominatim_api.search.db_searches import PostcodeSearch
|
||||
from nominatim_api.search.db_search_fields import WeightedStrings, FieldLookup, \
|
||||
FieldRanking, RankedTokens
|
||||
|
||||
|
||||
def run_search(apiobj, frontend, global_penalty, pcs, pc_penalties=None,
|
||||
ccodes=[], lookup=[], ranking=[], details=SearchDetails()):
|
||||
if pc_penalties is None:
|
||||
@@ -85,26 +86,24 @@ class TestPostcodeSearchWithAddress:
|
||||
apiobj.add_placex(place_id=1000, class_='place', type='village',
|
||||
rank_search=22, rank_address=22,
|
||||
country_code='ch')
|
||||
apiobj.add_search_name(1000, names=[1,2,10,11],
|
||||
apiobj.add_search_name(1000, names=[1, 2, 10, 11],
|
||||
search_rank=22, address_rank=22,
|
||||
country_code='ch')
|
||||
apiobj.add_placex(place_id=2000, class_='place', type='village',
|
||||
rank_search=22, rank_address=22,
|
||||
country_code='pl')
|
||||
apiobj.add_search_name(2000, names=[1,2,20,21],
|
||||
apiobj.add_search_name(2000, names=[1, 2, 20, 21],
|
||||
search_rank=22, address_rank=22,
|
||||
country_code='pl')
|
||||
|
||||
|
||||
def test_lookup_both(self, apiobj, frontend):
|
||||
lookup = FieldLookup('name_vector', [1,2], 'restrict')
|
||||
lookup = FieldLookup('name_vector', [1, 2], 'restrict')
|
||||
ranking = FieldRanking('name_vector', 0.3, [RankedTokens(0.0, [10])])
|
||||
|
||||
results = run_search(apiobj, frontend, 0.1, ['12345'], lookup=[lookup], ranking=[ranking])
|
||||
|
||||
assert [r.place_id for r in results] == [100, 101]
|
||||
|
||||
|
||||
def test_restrict_by_name(self, apiobj, frontend):
|
||||
lookup = FieldLookup('name_vector', [10], 'restrict')
|
||||
|
||||
@@ -112,11 +111,10 @@ class TestPostcodeSearchWithAddress:
|
||||
|
||||
assert [r.place_id for r in results] == [100]
|
||||
|
||||
|
||||
@pytest.mark.parametrize('coord,place_id', [((16.5, 5), 100),
|
||||
((-45.1, 7.004), 101)])
|
||||
def test_lookup_near(self, apiobj, frontend, coord, place_id):
|
||||
lookup = FieldLookup('name_vector', [1,2], 'restrict')
|
||||
lookup = FieldLookup('name_vector', [1, 2], 'restrict')
|
||||
ranking = FieldRanking('name_vector', 0.3, [RankedTokens(0.0, [10])])
|
||||
|
||||
results = run_search(apiobj, frontend, 0.1, ['12345'],
|
||||
@@ -126,7 +124,6 @@ class TestPostcodeSearchWithAddress:
|
||||
|
||||
assert [r.place_id for r in results] == [place_id]
|
||||
|
||||
|
||||
@pytest.mark.parametrize('geom', [napi.GeometryFormat.GEOJSON,
|
||||
napi.GeometryFormat.KML,
|
||||
napi.GeometryFormat.SVG,
|
||||
@@ -138,18 +135,16 @@ class TestPostcodeSearchWithAddress:
|
||||
assert results
|
||||
assert all(geom.name.lower() in r.geometry for r in results)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('viewbox, rids', [('-46,6,-44,8', [101,100]),
|
||||
('16,4,18,6', [100,101])])
|
||||
@pytest.mark.parametrize('viewbox, rids', [('-46,6,-44,8', [101, 100]),
|
||||
('16,4,18,6', [100, 101])])
|
||||
def test_prefer_viewbox(self, apiobj, frontend, viewbox, rids):
|
||||
results = run_search(apiobj, frontend, 0.1, ['12345'],
|
||||
details=SearchDetails.from_kwargs({'viewbox': viewbox}))
|
||||
|
||||
assert [r.place_id for r in results] == rids
|
||||
|
||||
|
||||
@pytest.mark.parametrize('viewbox, rid', [('-46,6,-44,8', 101),
|
||||
('16,4,18,6', 100)])
|
||||
('16,4,18,6', 100)])
|
||||
def test_restrict_to_viewbox(self, apiobj, frontend, viewbox, rid):
|
||||
results = run_search(apiobj, frontend, 0.1, ['12345'],
|
||||
details=SearchDetails.from_kwargs({'viewbox': viewbox,
|
||||
@@ -157,7 +152,6 @@ class TestPostcodeSearchWithAddress:
|
||||
|
||||
assert [r.place_id for r in results] == [rid]
|
||||
|
||||
|
||||
@pytest.mark.parametrize('coord,rids', [((17.05, 5), [100, 101]),
|
||||
((-45, 7.1), [101, 100])])
|
||||
def test_prefer_near(self, apiobj, frontend, coord, rids):
|
||||
@@ -166,7 +160,6 @@ class TestPostcodeSearchWithAddress:
|
||||
|
||||
assert [r.place_id for r in results] == rids
|
||||
|
||||
|
||||
@pytest.mark.parametrize('pid,rid', [(100, 101), (101, 100)])
|
||||
def test_exclude(self, apiobj, frontend, pid, rid):
|
||||
results = run_search(apiobj, frontend, 0.1, ['12345'],
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# This file is part of Nominatim. (https://nominatim.org)
|
||||
#
|
||||
# Copyright (C) 2024 by the Nominatim developer community.
|
||||
# Copyright (C) 2025 by the Nominatim developer community.
|
||||
# For a full list of authors see the git log.
|
||||
"""
|
||||
Test for creation of token assignments from tokenized queries.
|
||||
@@ -11,7 +11,10 @@ import pytest
|
||||
|
||||
from nominatim_api.search.query import QueryStruct, Phrase, TokenRange, Token
|
||||
import nominatim_api.search.query as qmod
|
||||
from nominatim_api.search.token_assignment import yield_token_assignments, TokenAssignment, PENALTY_TOKENCHANGE
|
||||
from nominatim_api.search.token_assignment import (yield_token_assignments,
|
||||
TokenAssignment,
|
||||
PENALTY_TOKENCHANGE)
|
||||
|
||||
|
||||
class MyToken(Token):
|
||||
def get_category(self):
|
||||
@@ -102,8 +105,7 @@ def test_multiple_simple_words(btype):
|
||||
TokenAssignment(penalty=penalty, name=TokenRange(1, 3),
|
||||
address=[TokenRange(0, 1)]),
|
||||
TokenAssignment(penalty=penalty, name=TokenRange(2, 3),
|
||||
address=[TokenRange(0, 2)])
|
||||
)
|
||||
address=[TokenRange(0, 2)]))
|
||||
|
||||
|
||||
def test_multiple_words_respect_phrase_break():
|
||||
@@ -156,6 +158,7 @@ def test_housenumber_and_postcode():
|
||||
address=[TokenRange(0, 1), TokenRange(2, 3)],
|
||||
postcode=TokenRange(3, 4)))
|
||||
|
||||
|
||||
def test_postcode_and_housenumber():
|
||||
q = make_query((qmod.BREAK_START, qmod.PHRASE_ANY, [(1, qmod.TOKEN_PARTIAL)]),
|
||||
(qmod.BREAK_WORD, qmod.PHRASE_ANY, [(2, qmod.TOKEN_POSTCODE)]),
|
||||
@@ -211,11 +214,11 @@ def test_housenumber_many_phrases():
|
||||
check_assignments(yield_token_assignments(q),
|
||||
TokenAssignment(penalty=0.1,
|
||||
name=TokenRange(4, 5),
|
||||
housenumber=TokenRange(3, 4),\
|
||||
housenumber=TokenRange(3, 4),
|
||||
address=[TokenRange(0, 1), TokenRange(1, 2),
|
||||
TokenRange(2, 3)]),
|
||||
TokenAssignment(penalty=0.1,
|
||||
housenumber=TokenRange(3, 4),\
|
||||
housenumber=TokenRange(3, 4),
|
||||
address=[TokenRange(0, 1), TokenRange(1, 2),
|
||||
TokenRange(2, 3), TokenRange(4, 5)]))
|
||||
|
||||
@@ -299,7 +302,6 @@ def test_qualifier_at_beginning():
|
||||
(qmod.BREAK_WORD, qmod.PHRASE_ANY, [(2, qmod.TOKEN_PARTIAL)]),
|
||||
(qmod.BREAK_WORD, qmod.PHRASE_ANY, [(3, qmod.TOKEN_PARTIAL)]))
|
||||
|
||||
|
||||
check_assignments(yield_token_assignments(q),
|
||||
TokenAssignment(penalty=0.1, name=TokenRange(1, 3),
|
||||
qualifier=TokenRange(0, 1)),
|
||||
@@ -315,7 +317,6 @@ def test_qualifier_after_name():
|
||||
(qmod.BREAK_WORD, qmod.PHRASE_ANY, [(4, qmod.TOKEN_PARTIAL)]),
|
||||
(qmod.BREAK_WORD, qmod.PHRASE_ANY, [(5, qmod.TOKEN_PARTIAL)]))
|
||||
|
||||
|
||||
check_assignments(yield_token_assignments(q),
|
||||
TokenAssignment(penalty=0.2, name=TokenRange(0, 2),
|
||||
qualifier=TokenRange(2, 3),
|
||||
@@ -349,4 +350,3 @@ def test_qualifier_in_middle_of_phrase():
|
||||
(qmod.BREAK_PHRASE, qmod.PHRASE_ANY, [(5, qmod.TOKEN_PARTIAL)]))
|
||||
|
||||
check_assignments(yield_token_assignments(q))
|
||||
|
||||
|
||||
@@ -2,12 +2,11 @@
|
||||
#
|
||||
# This file is part of Nominatim. (https://nominatim.org)
|
||||
#
|
||||
# Copyright (C) 2024 by the Nominatim developer community.
|
||||
# Copyright (C) 2025 by the Nominatim developer community.
|
||||
# For a full list of authors see the git log.
|
||||
"""
|
||||
Tests for enhanced connection class for API functions.
|
||||
"""
|
||||
from pathlib import Path
|
||||
import pytest
|
||||
|
||||
import sqlalchemy as sa
|
||||
@@ -76,7 +75,7 @@ async def test_get_db_property_existing(api):
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_get_db_property_existing(api):
|
||||
async def test_get_db_property_bad_name(api):
|
||||
async with api.begin() as conn:
|
||||
with pytest.raises(ValueError):
|
||||
await conn.get_db_property('dfkgjd.rijg')
|
||||
|
||||
@@ -2,20 +2,20 @@
|
||||
#
|
||||
# This file is part of Nominatim. (https://nominatim.org)
|
||||
#
|
||||
# Copyright (C) 2024 by the Nominatim developer community.
|
||||
# Copyright (C) 2025 by the Nominatim developer community.
|
||||
# For a full list of authors see the git log.
|
||||
"""
|
||||
Tests for the deletable v1 API call.
|
||||
"""
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from fake_adaptor import FakeAdaptor, FakeError, FakeResponse
|
||||
from fake_adaptor import FakeAdaptor
|
||||
|
||||
import nominatim_api.v1.server_glue as glue
|
||||
|
||||
|
||||
class TestDeletableEndPoint:
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
@@ -25,14 +25,13 @@ class TestDeletableEndPoint:
|
||||
content=[(345, 'N', 'boundary', 'administrative'),
|
||||
(781, 'R', 'landuse', 'wood'),
|
||||
(781, 'R', 'landcover', 'grass')])
|
||||
table_factory('placex',
|
||||
definition="""place_id bigint, osm_id bigint, osm_type char(1),
|
||||
class text, type text, name HSTORE, country_code char(2)""",
|
||||
content=[(1, 345, 'N', 'boundary', 'administrative', {'old_name': 'Former'}, 'ab'),
|
||||
(2, 781, 'R', 'landuse', 'wood', {'name': 'Wood'}, 'cd'),
|
||||
(3, 781, 'R', 'landcover', 'grass', None, 'cd')])
|
||||
|
||||
|
||||
table_factory(
|
||||
'placex',
|
||||
definition="""place_id bigint, osm_id bigint, osm_type char(1),
|
||||
class text, type text, name HSTORE, country_code char(2)""",
|
||||
content=[(1, 345, 'N', 'boundary', 'administrative', {'old_name': 'Former'}, 'ab'),
|
||||
(2, 781, 'R', 'landuse', 'wood', {'name': 'Wood'}, 'cd'),
|
||||
(3, 781, 'R', 'landcover', 'grass', None, 'cd')])
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_deletable(self, api):
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# This file is part of Nominatim. (https://nominatim.org)
|
||||
#
|
||||
# Copyright (C) 2024 by the Nominatim developer community.
|
||||
# Copyright (C) 2025 by the Nominatim developer community.
|
||||
# For a full list of authors see the git log.
|
||||
"""
|
||||
Tests for details API call.
|
||||
@@ -13,23 +13,24 @@ import pytest
|
||||
|
||||
import nominatim_api as napi
|
||||
|
||||
|
||||
@pytest.mark.parametrize('idobj', (napi.PlaceID(332), napi.OsmID('W', 4),
|
||||
napi.OsmID('W', 4, 'highway')))
|
||||
def test_lookup_in_placex(apiobj, frontend, idobj):
|
||||
import_date = dt.datetime(2022, 12, 7, 14, 14, 46, 0)
|
||||
apiobj.add_placex(place_id=332, osm_type='W', osm_id=4,
|
||||
class_='highway', type='residential',
|
||||
name={'name': 'Road'}, address={'city': 'Barrow'},
|
||||
extratags={'surface': 'paved'},
|
||||
parent_place_id=34, linked_place_id=55,
|
||||
admin_level=15, country_code='gb',
|
||||
housenumber='4',
|
||||
postcode='34425', wikipedia='en:Faa',
|
||||
rank_search=27, rank_address=26,
|
||||
importance=0.01,
|
||||
centroid=(23, 34),
|
||||
indexed_date=import_date,
|
||||
geometry='LINESTRING(23 34, 23.1 34, 23.1 34.1, 23 34)')
|
||||
class_='highway', type='residential',
|
||||
name={'name': 'Road'}, address={'city': 'Barrow'},
|
||||
extratags={'surface': 'paved'},
|
||||
parent_place_id=34, linked_place_id=55,
|
||||
admin_level=15, country_code='gb',
|
||||
housenumber='4',
|
||||
postcode='34425', wikipedia='en:Faa',
|
||||
rank_search=27, rank_address=26,
|
||||
importance=0.01,
|
||||
centroid=(23, 34),
|
||||
indexed_date=import_date,
|
||||
geometry='LINESTRING(23 34, 23.1 34, 23.1 34.1, 23 34)')
|
||||
|
||||
api = frontend(apiobj, options={'details'})
|
||||
result = api.details(idobj)
|
||||
@@ -73,12 +74,12 @@ def test_lookup_in_placex(apiobj, frontend, idobj):
|
||||
def test_lookup_in_placex_minimal_info(apiobj, frontend):
|
||||
import_date = dt.datetime(2022, 12, 7, 14, 14, 46, 0)
|
||||
apiobj.add_placex(place_id=332, osm_type='W', osm_id=4,
|
||||
class_='highway', type='residential',
|
||||
admin_level=15,
|
||||
rank_search=27, rank_address=26,
|
||||
centroid=(23, 34),
|
||||
indexed_date=import_date,
|
||||
geometry='LINESTRING(23 34, 23.1 34, 23.1 34.1, 23 34)')
|
||||
class_='highway', type='residential',
|
||||
admin_level=15,
|
||||
rank_search=27, rank_address=26,
|
||||
centroid=(23, 34),
|
||||
indexed_date=import_date,
|
||||
geometry='LINESTRING(23 34, 23.1 34, 23.1 34.1, 23 34)')
|
||||
|
||||
api = frontend(apiobj, options={'details'})
|
||||
result = api.details(napi.PlaceID(332))
|
||||
@@ -131,9 +132,9 @@ def test_lookup_in_placex_with_geometry(apiobj, frontend):
|
||||
|
||||
def test_lookup_placex_with_address_details(apiobj, frontend):
|
||||
apiobj.add_placex(place_id=332, osm_type='W', osm_id=4,
|
||||
class_='highway', type='residential', name='Street',
|
||||
country_code='pl',
|
||||
rank_search=27, rank_address=26)
|
||||
class_='highway', type='residential', name='Street',
|
||||
country_code='pl',
|
||||
rank_search=27, rank_address=26)
|
||||
apiobj.add_address_placex(332, fromarea=False, isaddress=False,
|
||||
distance=0.0034,
|
||||
place_id=1000, osm_type='N', osm_id=3333,
|
||||
@@ -178,9 +179,9 @@ def test_lookup_placex_with_address_details(apiobj, frontend):
|
||||
|
||||
def test_lookup_place_with_linked_places_none_existing(apiobj, frontend):
|
||||
apiobj.add_placex(place_id=332, osm_type='W', osm_id=4,
|
||||
class_='highway', type='residential', name='Street',
|
||||
country_code='pl', linked_place_id=45,
|
||||
rank_search=27, rank_address=26)
|
||||
class_='highway', type='residential', name='Street',
|
||||
country_code='pl', linked_place_id=45,
|
||||
rank_search=27, rank_address=26)
|
||||
|
||||
api = frontend(apiobj, options={'details'})
|
||||
result = api.details(napi.PlaceID(332), linked_places=True)
|
||||
@@ -190,17 +191,17 @@ def test_lookup_place_with_linked_places_none_existing(apiobj, frontend):
|
||||
|
||||
def test_lookup_place_with_linked_places_existing(apiobj, frontend):
|
||||
apiobj.add_placex(place_id=332, osm_type='W', osm_id=4,
|
||||
class_='highway', type='residential', name='Street',
|
||||
country_code='pl', linked_place_id=45,
|
||||
rank_search=27, rank_address=26)
|
||||
class_='highway', type='residential', name='Street',
|
||||
country_code='pl', linked_place_id=45,
|
||||
rank_search=27, rank_address=26)
|
||||
apiobj.add_placex(place_id=1001, osm_type='W', osm_id=5,
|
||||
class_='highway', type='residential', name='Street',
|
||||
country_code='pl', linked_place_id=332,
|
||||
rank_search=27, rank_address=26)
|
||||
class_='highway', type='residential', name='Street',
|
||||
country_code='pl', linked_place_id=332,
|
||||
rank_search=27, rank_address=26)
|
||||
apiobj.add_placex(place_id=1002, osm_type='W', osm_id=6,
|
||||
class_='highway', type='residential', name='Street',
|
||||
country_code='pl', linked_place_id=332,
|
||||
rank_search=27, rank_address=26)
|
||||
class_='highway', type='residential', name='Street',
|
||||
country_code='pl', linked_place_id=332,
|
||||
rank_search=27, rank_address=26)
|
||||
|
||||
api = frontend(apiobj, options={'details'})
|
||||
result = api.details(napi.PlaceID(332), linked_places=True)
|
||||
@@ -221,9 +222,9 @@ def test_lookup_place_with_linked_places_existing(apiobj, frontend):
|
||||
|
||||
def test_lookup_place_with_parented_places_not_existing(apiobj, frontend):
|
||||
apiobj.add_placex(place_id=332, osm_type='W', osm_id=4,
|
||||
class_='highway', type='residential', name='Street',
|
||||
country_code='pl', parent_place_id=45,
|
||||
rank_search=27, rank_address=26)
|
||||
class_='highway', type='residential', name='Street',
|
||||
country_code='pl', parent_place_id=45,
|
||||
rank_search=27, rank_address=26)
|
||||
|
||||
api = frontend(apiobj, options={'details'})
|
||||
result = api.details(napi.PlaceID(332), parented_places=True)
|
||||
@@ -233,17 +234,17 @@ def test_lookup_place_with_parented_places_not_existing(apiobj, frontend):
|
||||
|
||||
def test_lookup_place_with_parented_places_existing(apiobj, frontend):
|
||||
apiobj.add_placex(place_id=332, osm_type='W', osm_id=4,
|
||||
class_='highway', type='residential', name='Street',
|
||||
country_code='pl', parent_place_id=45,
|
||||
rank_search=27, rank_address=26)
|
||||
class_='highway', type='residential', name='Street',
|
||||
country_code='pl', parent_place_id=45,
|
||||
rank_search=27, rank_address=26)
|
||||
apiobj.add_placex(place_id=1001, osm_type='N', osm_id=5,
|
||||
class_='place', type='house', housenumber='23',
|
||||
country_code='pl', parent_place_id=332,
|
||||
rank_search=30, rank_address=30)
|
||||
class_='place', type='house', housenumber='23',
|
||||
country_code='pl', parent_place_id=332,
|
||||
rank_search=30, rank_address=30)
|
||||
apiobj.add_placex(place_id=1002, osm_type='W', osm_id=6,
|
||||
class_='highway', type='residential', name='Street',
|
||||
country_code='pl', parent_place_id=332,
|
||||
rank_search=27, rank_address=26)
|
||||
class_='highway', type='residential', name='Street',
|
||||
country_code='pl', parent_place_id=332,
|
||||
rank_search=27, rank_address=26)
|
||||
|
||||
api = frontend(apiobj, options={'details'})
|
||||
result = api.details(napi.PlaceID(332), parented_places=True)
|
||||
@@ -332,9 +333,9 @@ def test_lookup_osmline_with_address_details(apiobj, frontend):
|
||||
startnumber=2, endnumber=4, step=1,
|
||||
parent_place_id=332)
|
||||
apiobj.add_placex(place_id=332, osm_type='W', osm_id=4,
|
||||
class_='highway', type='residential', name='Street',
|
||||
country_code='pl',
|
||||
rank_search=27, rank_address=26)
|
||||
class_='highway', type='residential', name='Street',
|
||||
country_code='pl',
|
||||
rank_search=27, rank_address=26)
|
||||
apiobj.add_address_placex(332, fromarea=False, isaddress=False,
|
||||
distance=0.0034,
|
||||
place_id=1000, osm_type='N', osm_id=3333,
|
||||
@@ -432,9 +433,9 @@ def test_lookup_tiger_with_address_details(apiobj, frontend):
|
||||
startnumber=2, endnumber=4, step=1,
|
||||
parent_place_id=332)
|
||||
apiobj.add_placex(place_id=332, osm_type='W', osm_id=4,
|
||||
class_='highway', type='residential', name='Street',
|
||||
country_code='us',
|
||||
rank_search=27, rank_address=26)
|
||||
class_='highway', type='residential', name='Street',
|
||||
country_code='us',
|
||||
rank_search=27, rank_address=26)
|
||||
apiobj.add_address_placex(332, fromarea=False, isaddress=False,
|
||||
distance=0.0034,
|
||||
place_id=1000, osm_type='N', osm_id=3333,
|
||||
@@ -571,6 +572,7 @@ def test_lookup_postcode_with_address_details(apiobj, frontend):
|
||||
rank_address=4, distance=0.0)
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize('objid', [napi.PlaceID(1736),
|
||||
napi.OsmID('W', 55),
|
||||
napi.OsmID('N', 55, 'amenity')])
|
||||
@@ -583,8 +585,8 @@ def test_lookup_missing_object(apiobj, frontend, objid):
|
||||
|
||||
|
||||
@pytest.mark.parametrize('gtype', (napi.GeometryFormat.KML,
|
||||
napi.GeometryFormat.SVG,
|
||||
napi.GeometryFormat.TEXT))
|
||||
napi.GeometryFormat.SVG,
|
||||
napi.GeometryFormat.TEXT))
|
||||
def test_lookup_unsupported_geometry(apiobj, frontend, gtype):
|
||||
apiobj.add_placex(place_id=332)
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# This file is part of Nominatim. (https://nominatim.org)
|
||||
#
|
||||
# Copyright (C) 2024 by the Nominatim developer community.
|
||||
# Copyright (C) 2025 by the Nominatim developer community.
|
||||
# For a full list of authors see the git log.
|
||||
"""
|
||||
Tests for lookup API call.
|
||||
@@ -13,6 +13,7 @@ import pytest
|
||||
|
||||
import nominatim_api as napi
|
||||
|
||||
|
||||
def test_lookup_empty_list(apiobj, frontend):
|
||||
api = frontend(apiobj, options={'details'})
|
||||
assert api.lookup([]) == []
|
||||
@@ -28,17 +29,17 @@ def test_lookup_non_existing(apiobj, frontend):
|
||||
napi.OsmID('W', 4, 'highway')))
|
||||
def test_lookup_single_placex(apiobj, frontend, idobj):
|
||||
apiobj.add_placex(place_id=332, osm_type='W', osm_id=4,
|
||||
class_='highway', type='residential',
|
||||
name={'name': 'Road'}, address={'city': 'Barrow'},
|
||||
extratags={'surface': 'paved'},
|
||||
parent_place_id=34, linked_place_id=55,
|
||||
admin_level=15, country_code='gb',
|
||||
housenumber='4',
|
||||
postcode='34425', wikipedia='en:Faa',
|
||||
rank_search=27, rank_address=26,
|
||||
importance=0.01,
|
||||
centroid=(23, 34),
|
||||
geometry='LINESTRING(23 34, 23.1 34, 23.1 34.1, 23 34)')
|
||||
class_='highway', type='residential',
|
||||
name={'name': 'Road'}, address={'city': 'Barrow'},
|
||||
extratags={'surface': 'paved'},
|
||||
parent_place_id=34, linked_place_id=55,
|
||||
admin_level=15, country_code='gb',
|
||||
housenumber='4',
|
||||
postcode='34425', wikipedia='en:Faa',
|
||||
rank_search=27, rank_address=26,
|
||||
importance=0.01,
|
||||
centroid=(23, 34),
|
||||
geometry='LINESTRING(23 34, 23.1 34, 23.1 34.1, 23 34)')
|
||||
|
||||
api = frontend(apiobj, options={'details'})
|
||||
result = api.lookup([idobj])
|
||||
@@ -79,17 +80,17 @@ def test_lookup_single_placex(apiobj, frontend, idobj):
|
||||
|
||||
def test_lookup_multiple_places(apiobj, frontend):
|
||||
apiobj.add_placex(place_id=332, osm_type='W', osm_id=4,
|
||||
class_='highway', type='residential',
|
||||
name={'name': 'Road'}, address={'city': 'Barrow'},
|
||||
extratags={'surface': 'paved'},
|
||||
parent_place_id=34, linked_place_id=55,
|
||||
admin_level=15, country_code='gb',
|
||||
housenumber='4',
|
||||
postcode='34425', wikipedia='en:Faa',
|
||||
rank_search=27, rank_address=26,
|
||||
importance=0.01,
|
||||
centroid=(23, 34),
|
||||
geometry='LINESTRING(23 34, 23.1 34, 23.1 34.1, 23 34)')
|
||||
class_='highway', type='residential',
|
||||
name={'name': 'Road'}, address={'city': 'Barrow'},
|
||||
extratags={'surface': 'paved'},
|
||||
parent_place_id=34, linked_place_id=55,
|
||||
admin_level=15, country_code='gb',
|
||||
housenumber='4',
|
||||
postcode='34425', wikipedia='en:Faa',
|
||||
rank_search=27, rank_address=26,
|
||||
importance=0.01,
|
||||
centroid=(23, 34),
|
||||
geometry='LINESTRING(23 34, 23.1 34, 23.1 34.1, 23 34)')
|
||||
apiobj.add_osmline(place_id=4924, osm_id=9928,
|
||||
parent_place_id=12,
|
||||
startnumber=1, endnumber=4, step=1,
|
||||
@@ -97,7 +98,6 @@ def test_lookup_multiple_places(apiobj, frontend):
|
||||
address={'city': 'Big'},
|
||||
geometry='LINESTRING(23 34, 23 35)')
|
||||
|
||||
|
||||
api = frontend(apiobj, options={'details'})
|
||||
result = api.lookup((napi.OsmID('W', 1),
|
||||
napi.OsmID('W', 4),
|
||||
@@ -111,17 +111,17 @@ def test_lookup_multiple_places(apiobj, frontend):
|
||||
@pytest.mark.parametrize('gtype', list(napi.GeometryFormat))
|
||||
def test_simple_place_with_geometry(apiobj, frontend, gtype):
|
||||
apiobj.add_placex(place_id=332, osm_type='W', osm_id=4,
|
||||
class_='highway', type='residential',
|
||||
name={'name': 'Road'}, address={'city': 'Barrow'},
|
||||
extratags={'surface': 'paved'},
|
||||
parent_place_id=34, linked_place_id=55,
|
||||
admin_level=15, country_code='gb',
|
||||
housenumber='4',
|
||||
postcode='34425', wikipedia='en:Faa',
|
||||
rank_search=27, rank_address=26,
|
||||
importance=0.01,
|
||||
centroid=(23, 34),
|
||||
geometry='POLYGON((23 34, 23.1 34, 23.1 34.1, 23 34))')
|
||||
class_='highway', type='residential',
|
||||
name={'name': 'Road'}, address={'city': 'Barrow'},
|
||||
extratags={'surface': 'paved'},
|
||||
parent_place_id=34, linked_place_id=55,
|
||||
admin_level=15, country_code='gb',
|
||||
housenumber='4',
|
||||
postcode='34425', wikipedia='en:Faa',
|
||||
rank_search=27, rank_address=26,
|
||||
importance=0.01,
|
||||
centroid=(23, 34),
|
||||
geometry='POLYGON((23 34, 23.1 34, 23.1 34.1, 23 34))')
|
||||
|
||||
api = frontend(apiobj, options={'details'})
|
||||
result = api.lookup([napi.OsmID('W', 4)], geometry_output=gtype)
|
||||
@@ -137,17 +137,17 @@ def test_simple_place_with_geometry(apiobj, frontend, gtype):
|
||||
|
||||
def test_simple_place_with_geometry_simplified(apiobj, frontend):
|
||||
apiobj.add_placex(place_id=332, osm_type='W', osm_id=4,
|
||||
class_='highway', type='residential',
|
||||
name={'name': 'Road'}, address={'city': 'Barrow'},
|
||||
extratags={'surface': 'paved'},
|
||||
parent_place_id=34, linked_place_id=55,
|
||||
admin_level=15, country_code='gb',
|
||||
housenumber='4',
|
||||
postcode='34425', wikipedia='en:Faa',
|
||||
rank_search=27, rank_address=26,
|
||||
importance=0.01,
|
||||
centroid=(23, 34),
|
||||
geometry='POLYGON((23 34, 22.999 34, 23.1 34, 23.1 34.1, 23 34))')
|
||||
class_='highway', type='residential',
|
||||
name={'name': 'Road'}, address={'city': 'Barrow'},
|
||||
extratags={'surface': 'paved'},
|
||||
parent_place_id=34, linked_place_id=55,
|
||||
admin_level=15, country_code='gb',
|
||||
housenumber='4',
|
||||
postcode='34425', wikipedia='en:Faa',
|
||||
rank_search=27, rank_address=26,
|
||||
importance=0.01,
|
||||
centroid=(23, 34),
|
||||
geometry='POLYGON((23 34, 22.999 34, 23.1 34, 23.1 34.1, 23 34))')
|
||||
|
||||
api = frontend(apiobj, options={'details'})
|
||||
result = api.lookup([napi.OsmID('W', 4)],
|
||||
@@ -159,5 +159,5 @@ def test_simple_place_with_geometry_simplified(apiobj, frontend):
|
||||
|
||||
geom = json.loads(result[0].geometry['geojson'])
|
||||
|
||||
assert geom['type'] == 'Polygon'
|
||||
assert geom['type'] == 'Polygon'
|
||||
assert geom['coordinates'] == [[[23, 34], [23.1, 34], [23.1, 34.1], [23, 34]]]
|
||||
|
||||
@@ -2,21 +2,21 @@
|
||||
#
|
||||
# This file is part of Nominatim. (https://nominatim.org)
|
||||
#
|
||||
# Copyright (C) 2024 by the Nominatim developer community.
|
||||
# Copyright (C) 2025 by the Nominatim developer community.
|
||||
# For a full list of authors see the git log.
|
||||
"""
|
||||
Tests for the deletable v1 API call.
|
||||
"""
|
||||
import json
|
||||
import datetime as dt
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from fake_adaptor import FakeAdaptor, FakeError, FakeResponse
|
||||
from fake_adaptor import FakeAdaptor
|
||||
|
||||
import nominatim_api.v1.server_glue as glue
|
||||
|
||||
|
||||
class TestPolygonsEndPoint:
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
@@ -35,13 +35,12 @@ class TestPolygonsEndPoint:
|
||||
errormessage text,
|
||||
prevgeometry geometry(Geometry,4326),
|
||||
newgeometry geometry(Geometry,4326)""",
|
||||
content=[(345, 'N', 'boundary', 'administrative',
|
||||
{'name': 'Foo'}, 'xx', self.recent,
|
||||
'some text', None, None),
|
||||
(781, 'R', 'landuse', 'wood',
|
||||
None, 'ds', self.now,
|
||||
'Area reduced by lots', None, None)])
|
||||
|
||||
content=[(345, 'N', 'boundary', 'administrative',
|
||||
{'name': 'Foo'}, 'xx', self.recent,
|
||||
'some text', None, None),
|
||||
(781, 'R', 'landuse', 'wood',
|
||||
None, 'ds', self.now,
|
||||
'Area reduced by lots', None, None)])
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_polygons_simple(self, api):
|
||||
@@ -63,7 +62,6 @@ class TestPolygonsEndPoint:
|
||||
'errormessage': 'Area reduced by lots',
|
||||
'updated': self.now.isoformat(sep=' ', timespec='seconds')}]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_polygons_days(self, api):
|
||||
a = FakeAdaptor()
|
||||
@@ -74,7 +72,6 @@ class TestPolygonsEndPoint:
|
||||
|
||||
assert [r['osm_id'] for r in results] == [781]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_polygons_class(self, api):
|
||||
a = FakeAdaptor()
|
||||
@@ -85,8 +82,6 @@ class TestPolygonsEndPoint:
|
||||
|
||||
assert [r['osm_id'] for r in results] == [781]
|
||||
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_polygons_reduced(self, api):
|
||||
a = FakeAdaptor()
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# This file is part of Nominatim. (https://nominatim.org)
|
||||
#
|
||||
# Copyright (C) 2024 by the Nominatim developer community.
|
||||
# Copyright (C) 2025 by the Nominatim developer community.
|
||||
# For a full list of authors see the git log.
|
||||
"""
|
||||
Tests for reverse API call.
|
||||
@@ -18,6 +18,7 @@ import nominatim_api as napi
|
||||
|
||||
API_OPTIONS = {'reverse'}
|
||||
|
||||
|
||||
def test_reverse_rank_30(apiobj, frontend):
|
||||
apiobj.add_placex(place_id=223, class_='place', type='house',
|
||||
housenumber='1',
|
||||
@@ -35,7 +36,7 @@ def test_reverse_rank_30(apiobj, frontend):
|
||||
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'},
|
||||
name={'name': 'My Street'},
|
||||
centroid=(10.0, 10.0),
|
||||
country_code=country,
|
||||
geometry='LINESTRING(9.995 10, 10.005 10)')
|
||||
@@ -57,16 +58,17 @@ def test_reverse_ignore_unindexed(apiobj, frontend):
|
||||
assert result is None
|
||||
|
||||
|
||||
@pytest.mark.parametrize('y,layer,place_id', [(0.7, napi.DataLayer.ADDRESS, 223),
|
||||
(0.70001, napi.DataLayer.POI, 224),
|
||||
(0.7, napi.DataLayer.ADDRESS | napi.DataLayer.POI, 224),
|
||||
(0.70001, napi.DataLayer.ADDRESS | napi.DataLayer.POI, 223),
|
||||
(0.7, napi.DataLayer.MANMADE, 225),
|
||||
(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),
|
||||
(5, napi.DataLayer.ADDRESS, 229)])
|
||||
@pytest.mark.parametrize('y,layer,place_id',
|
||||
[(0.7, napi.DataLayer.ADDRESS, 223),
|
||||
(0.70001, napi.DataLayer.POI, 224),
|
||||
(0.7, napi.DataLayer.ADDRESS | napi.DataLayer.POI, 224),
|
||||
(0.70001, napi.DataLayer.ADDRESS | napi.DataLayer.POI, 223),
|
||||
(0.7, napi.DataLayer.MANMADE, 225),
|
||||
(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),
|
||||
(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',
|
||||
@@ -108,14 +110,14 @@ def test_reverse_poi_layer_with_no_pois(apiobj, frontend):
|
||||
|
||||
api = frontend(apiobj, options=API_OPTIONS)
|
||||
assert api.reverse((1.3, 0.70001), max_rank=29,
|
||||
layers=napi.DataLayer.POI) is None
|
||||
layers=napi.DataLayer.POI) is None
|
||||
|
||||
|
||||
@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'},
|
||||
name={'name': 'My Street'},
|
||||
centroid=(10.0, 10.0),
|
||||
geometry='LINESTRING(9.995 10, 10.005 10)')
|
||||
apiobj.add_placex(place_id=991, class_='place', type='house',
|
||||
@@ -125,7 +127,7 @@ def test_reverse_housenumber_on_street(apiobj, frontend, with_geom):
|
||||
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'},
|
||||
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',
|
||||
@@ -147,7 +149,7 @@ def test_reverse_housenumber_on_street(apiobj, frontend, with_geom):
|
||||
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'},
|
||||
name={'name': 'My Street'},
|
||||
centroid=(10.0, 10.0),
|
||||
geometry='LINESTRING(9.995 10, 10.005 10)')
|
||||
apiobj.add_placex(place_id=991, class_='place', type='house',
|
||||
@@ -162,7 +164,7 @@ def test_reverse_housenumber_interpolation(apiobj, frontend, with_geom):
|
||||
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'},
|
||||
name={'name': 'Other Street'},
|
||||
centroid=(10.0, 20.0),
|
||||
geometry='LINESTRING(9.995 20, 10.005 20)')
|
||||
apiobj.add_osmline(place_id=1992,
|
||||
@@ -181,7 +183,7 @@ def test_reverse_housenumber_interpolation(apiobj, frontend, with_geom):
|
||||
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'},
|
||||
name={'name': 'My Street'},
|
||||
centroid=(10.0, 10.0),
|
||||
geometry='LINESTRING(9.995 10, 10.005 10)')
|
||||
apiobj.add_osmline(place_id=992,
|
||||
@@ -199,7 +201,7 @@ def test_reverse_housenumber_point_interpolation(apiobj, frontend):
|
||||
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'},
|
||||
name={'name': 'My Street'},
|
||||
centroid=(10.0, 10.0),
|
||||
country_code='us',
|
||||
geometry='LINESTRING(9.995 10, 10.005 10)')
|
||||
@@ -217,7 +219,7 @@ def test_reverse_tiger_number(apiobj, frontend):
|
||||
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'},
|
||||
name={'name': 'My Street'},
|
||||
centroid=(10.0, 10.0),
|
||||
country_code='us',
|
||||
geometry='LINESTRING(9.995 10, 10.005 10)')
|
||||
@@ -393,14 +395,15 @@ def test_reverse_interpolation_geometry(apiobj, frontend):
|
||||
geometry='LINESTRING(9.995 10.00001, 10.005 10.00001)')
|
||||
|
||||
api = frontend(apiobj, options=API_OPTIONS)
|
||||
assert api.reverse((10.0, 10.0), geometry_output=napi.GeometryFormat.TEXT)\
|
||||
.geometry['text'] == 'POINT(10 10.00001)'
|
||||
result = api.reverse((10.0, 10.0), geometry_output=napi.GeometryFormat.TEXT)
|
||||
|
||||
assert result.geometry['text'] == 'POINT(10 10.00001)'
|
||||
|
||||
|
||||
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'},
|
||||
name={'name': 'My Street'},
|
||||
centroid=(10.0, 10.0),
|
||||
country_code='us',
|
||||
geometry='LINESTRING(9.995 10, 10.005 10)')
|
||||
@@ -411,7 +414,7 @@ def test_reverse_tiger_geometry(apiobj, frontend):
|
||||
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'},
|
||||
name={'name': 'My Street'},
|
||||
centroid=(11.0, 11.0),
|
||||
country_code='us',
|
||||
geometry='LINESTRING(10.995 11, 11.005 11)')
|
||||
@@ -426,8 +429,9 @@ def test_reverse_tiger_geometry(apiobj, frontend):
|
||||
params = {'geometry_output': napi.GeometryFormat.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.geometry['geojson']) \
|
||||
== {'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'}
|
||||
|
||||
assert json.loads(output.geometry['geojson']) \
|
||||
== {'coordinates': [11, 11.00001], 'type': 'Point'}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# This file is part of Nominatim. (https://nominatim.org)
|
||||
#
|
||||
# Copyright (C) 2024 by the Nominatim developer community.
|
||||
# Copyright (C) 2025 by the Nominatim developer community.
|
||||
# For a full list of authors see the git log.
|
||||
"""
|
||||
Tests for search API calls.
|
||||
@@ -10,17 +10,13 @@ Tests for search API calls.
|
||||
These tests make sure that all Python code is correct and executable.
|
||||
Functional tests can be found in the BDD test suite.
|
||||
"""
|
||||
import json
|
||||
|
||||
import pytest
|
||||
|
||||
import sqlalchemy as sa
|
||||
|
||||
import nominatim_api as napi
|
||||
import nominatim_api.logging as loglib
|
||||
|
||||
API_OPTIONS = {'search'}
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup_icu_tokenizer(apiobj):
|
||||
""" Setup the properties needed for using the ICU tokenizer.
|
||||
@@ -28,8 +24,9 @@ def setup_icu_tokenizer(apiobj):
|
||||
apiobj.add_data('properties',
|
||||
[{'property': 'tokenizer', 'value': 'icu'},
|
||||
{'property': 'tokenizer_import_normalisation', 'value': ':: lower();'},
|
||||
{'property': 'tokenizer_import_transliteration', 'value': "'1' > '/1/'; 'ä' > 'ä '"},
|
||||
])
|
||||
{'property': 'tokenizer_import_transliteration',
|
||||
'value': "'1' > '/1/'; 'ä' > 'ä '"},
|
||||
])
|
||||
|
||||
|
||||
def test_search_no_content(apiobj, frontend):
|
||||
@@ -64,7 +61,7 @@ def test_search_with_debug(apiobj, frontend, logtype):
|
||||
|
||||
api = frontend(apiobj, options=API_OPTIONS)
|
||||
loglib.set_log_output(logtype)
|
||||
results = api.search('TEST')
|
||||
api.search('TEST')
|
||||
|
||||
assert loglib.get_and_disable()
|
||||
|
||||
|
||||
@@ -2,18 +2,17 @@
|
||||
#
|
||||
# This file is part of Nominatim. (https://nominatim.org)
|
||||
#
|
||||
# Copyright (C) 2024 by the Nominatim developer community.
|
||||
# Copyright (C) 2025 by the Nominatim developer community.
|
||||
# For a full list of authors see the git log.
|
||||
"""
|
||||
Tests for the status API call.
|
||||
"""
|
||||
import datetime as dt
|
||||
import pytest
|
||||
|
||||
from nominatim_db.version import NominatimVersion
|
||||
from nominatim_api.version import NOMINATIM_API_VERSION
|
||||
import nominatim_api as napi
|
||||
|
||||
|
||||
def test_status_no_extra_info(apiobj, frontend):
|
||||
api = frontend(apiobj)
|
||||
result = api.status()
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# This file is part of Nominatim. (https://nominatim.org)
|
||||
#
|
||||
# Copyright (C) 2024 by the Nominatim developer community.
|
||||
# Copyright (C) 2025 by the Nominatim developer community.
|
||||
# For a full list of authors see the git log.
|
||||
"""
|
||||
Tests for loading of parameter dataclasses.
|
||||
@@ -12,6 +12,7 @@ import pytest
|
||||
from nominatim_api.errors import UsageError
|
||||
import nominatim_api.types as typ
|
||||
|
||||
|
||||
def test_no_params_defaults():
|
||||
params = typ.LookupDetails.from_kwargs({})
|
||||
|
||||
@@ -24,7 +25,7 @@ def test_no_params_defaults():
|
||||
('geometry_simplification', 'NaN')])
|
||||
def test_bad_format_reverse(k, v):
|
||||
with pytest.raises(UsageError):
|
||||
params = typ.ReverseDetails.from_kwargs({k: v})
|
||||
typ.ReverseDetails.from_kwargs({k: v})
|
||||
|
||||
|
||||
@pytest.mark.parametrize('rin,rout', [(-23, 0), (0, 0), (1, 1),
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# This file is part of Nominatim. (https://nominatim.org)
|
||||
#
|
||||
# Copyright (C) 2024 by the Nominatim developer community.
|
||||
# Copyright (C) 2025 by the Nominatim developer community.
|
||||
# For a full list of authors see the git log.
|
||||
"""
|
||||
Tests for export CLI function.
|
||||
@@ -11,12 +11,13 @@ import pytest
|
||||
|
||||
import nominatim_db.cli
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def run_export(tmp_path, capsys):
|
||||
def _exec(args):
|
||||
cli_args = ['export', '--project-dir', str(tmp_path)] + args
|
||||
assert 0 == nominatim_db.cli.nominatim(osm2pgsql_path='OSM2PGSQL NOT AVAILABLE',
|
||||
cli_args=['export', '--project-dir', str(tmp_path)]
|
||||
+ args)
|
||||
cli_args=cli_args)
|
||||
return capsys.readouterr().out.split('\r\n')
|
||||
|
||||
return _exec
|
||||
@@ -25,9 +26,9 @@ def run_export(tmp_path, capsys):
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup_database_with_context(apiobj):
|
||||
apiobj.add_placex(place_id=332, osm_type='W', osm_id=4,
|
||||
class_='highway', type='residential', name='Street',
|
||||
country_code='pl', postcode='55674',
|
||||
rank_search=27, rank_address=26)
|
||||
class_='highway', type='residential', name='Street',
|
||||
country_code='pl', postcode='55674',
|
||||
rank_search=27, rank_address=26)
|
||||
apiobj.add_address_placex(332, fromarea=False, isaddress=False,
|
||||
distance=0.0034,
|
||||
place_id=1000, osm_type='N', osm_id=3333,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# This file is part of Nominatim. (https://nominatim.org)
|
||||
#
|
||||
# Copyright (C) 2024 by the Nominatim developer community.
|
||||
# Copyright (C) 2025 by the Nominatim developer community.
|
||||
# For a full list of authors see the git log.
|
||||
"""
|
||||
Tests for the helper functions for v1 API.
|
||||
@@ -11,6 +11,7 @@ import pytest
|
||||
|
||||
import nominatim_api.v1.helpers as helper
|
||||
|
||||
|
||||
@pytest.mark.parametrize('inp', ['',
|
||||
'abc',
|
||||
'12 23',
|
||||
@@ -35,40 +36,42 @@ def test_extract_coords_with_text_before():
|
||||
def test_extract_coords_with_text_after():
|
||||
assert ('abc', 12.456, -78.90) == helper.extract_coords_from_query('-78.90, 12.456 abc')
|
||||
|
||||
|
||||
@pytest.mark.parametrize('inp', [' [12.456,-78.90] ', ' 12.456,-78.90 '])
|
||||
def test_extract_coords_with_spaces(inp):
|
||||
assert ('', -78.90, 12.456) == helper.extract_coords_from_query(inp)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('inp', ['40 26.767 N 79 58.933 W',
|
||||
'40° 26.767′ N 79° 58.933′ W',
|
||||
"40° 26.767' N 79° 58.933' W",
|
||||
"40° 26.767'\n"
|
||||
" N 79° 58.933' W",
|
||||
'N 40 26.767, W 79 58.933',
|
||||
'N 40°26.767′, W 79°58.933′',
|
||||
' N 40°26.767′, W 79°58.933′',
|
||||
"N 40°26.767', W 79°58.933'",
|
||||
|
||||
'40 26 46 N 79 58 56 W',
|
||||
'40° 26′ 46″ N 79° 58′ 56″ W',
|
||||
'40° 26′ 46.00″ N 79° 58′ 56.00″ W',
|
||||
'40°26′46″N 79°58′56″W',
|
||||
'N 40 26 46 W 79 58 56',
|
||||
'N 40° 26′ 46″, W 79° 58′ 56″',
|
||||
'N 40° 26\' 46", W 79° 58\' 56"',
|
||||
'N 40° 26\' 46", W 79° 58\' 56"',
|
||||
|
||||
'40.446 -79.982',
|
||||
'40.446,-79.982',
|
||||
'40.446° N 79.982° W',
|
||||
'N 40.446° W 79.982°',
|
||||
|
||||
'[40.446 -79.982]',
|
||||
'[40.446,-79.982]',
|
||||
' 40.446 , -79.982 ',
|
||||
' 40.446 , -79.982 ',
|
||||
' 40.446 , -79.982 ',
|
||||
' 40.446, -79.982 '])
|
||||
'40° 26.767′ N 79° 58.933′ W',
|
||||
"40° 26.767' N 79° 58.933' W",
|
||||
"40° 26.767'\n"
|
||||
" N 79° 58.933' W",
|
||||
'N 40 26.767, W 79 58.933',
|
||||
'N 40°26.767′, W 79°58.933′',
|
||||
' N 40°26.767′, W 79°58.933′',
|
||||
"N 40°26.767', W 79°58.933'",
|
||||
|
||||
'40 26 46 N 79 58 56 W',
|
||||
'40° 26′ 46″ N 79° 58′ 56″ W',
|
||||
'40° 26′ 46.00″ N 79° 58′ 56.00″ W',
|
||||
'40°26′46″N 79°58′56″W',
|
||||
'N 40 26 46 W 79 58 56',
|
||||
'N 40° 26′ 46″, W 79° 58′ 56″',
|
||||
'N 40° 26\' 46", W 79° 58\' 56"',
|
||||
'N 40° 26\' 46", W 79° 58\' 56"',
|
||||
|
||||
'40.446 -79.982',
|
||||
'40.446,-79.982',
|
||||
'40.446° N 79.982° W',
|
||||
'N 40.446° W 79.982°',
|
||||
|
||||
'[40.446 -79.982]',
|
||||
'[40.446,-79.982]',
|
||||
' 40.446 , -79.982 ',
|
||||
' 40.446 , -79.982 ',
|
||||
' 40.446 , -79.982 ',
|
||||
' 40.446, -79.982 '])
|
||||
def test_extract_coords_formats(inp):
|
||||
query, x, y = helper.extract_coords_from_query(inp)
|
||||
|
||||
@@ -108,9 +111,11 @@ def test_extract_category_good(inp):
|
||||
assert cls == 'shop'
|
||||
assert typ == 'fish'
|
||||
|
||||
|
||||
def test_extract_category_only():
|
||||
assert helper.extract_category_from_query('[shop=market]') == ('', 'shop', 'market')
|
||||
|
||||
|
||||
@pytest.mark.parametrize('inp', ['house []', 'nothing', '[352]'])
|
||||
def test_extract_category_no_match(inp):
|
||||
def test_extract_category_no_match(inp):
|
||||
assert helper.extract_category_from_query(inp) == (inp, None, None)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# This file is part of Nominatim. (https://nominatim.org)
|
||||
#
|
||||
# Copyright (C) 2024 by the Nominatim developer community.
|
||||
# Copyright (C) 2025 by the Nominatim developer community.
|
||||
# For a full list of authors see the git log.
|
||||
"""
|
||||
Test functions for adapting results to the user's locale.
|
||||
@@ -11,34 +11,36 @@ import pytest
|
||||
|
||||
from nominatim_api import Locales
|
||||
|
||||
def test_display_name_empty_names():
|
||||
l = Locales(['en', 'de'])
|
||||
|
||||
assert l.display_name(None) == ''
|
||||
assert l.display_name({}) == ''
|
||||
def test_display_name_empty_names():
|
||||
loc = Locales(['en', 'de'])
|
||||
|
||||
assert loc.display_name(None) == ''
|
||||
assert loc.display_name({}) == ''
|
||||
|
||||
|
||||
def test_display_name_none_localized():
|
||||
l = Locales()
|
||||
loc = Locales()
|
||||
|
||||
assert l.display_name({}) == ''
|
||||
assert l.display_name({'name:de': 'DE', 'name': 'ALL'}) == 'ALL'
|
||||
assert l.display_name({'ref': '34', 'name:de': 'DE'}) == '34'
|
||||
assert loc.display_name({}) == ''
|
||||
assert loc.display_name({'name:de': 'DE', 'name': 'ALL'}) == 'ALL'
|
||||
assert loc.display_name({'ref': '34', 'name:de': 'DE'}) == '34'
|
||||
|
||||
|
||||
def test_display_name_localized():
|
||||
l = Locales(['en', 'de'])
|
||||
loc = Locales(['en', 'de'])
|
||||
|
||||
assert l.display_name({}) == ''
|
||||
assert l.display_name({'name:de': 'DE', 'name': 'ALL'}) == 'DE'
|
||||
assert l.display_name({'ref': '34', 'name:de': 'DE'}) == 'DE'
|
||||
assert loc.display_name({}) == ''
|
||||
assert loc.display_name({'name:de': 'DE', 'name': 'ALL'}) == 'DE'
|
||||
assert loc.display_name({'ref': '34', 'name:de': 'DE'}) == 'DE'
|
||||
|
||||
|
||||
def test_display_name_preference():
|
||||
l = Locales(['en', 'de'])
|
||||
loc = Locales(['en', 'de'])
|
||||
|
||||
assert l.display_name({}) == ''
|
||||
assert l.display_name({'name:de': 'DE', 'name:en': 'EN'}) == 'EN'
|
||||
assert l.display_name({'official_name:en': 'EN', 'name:de': 'DE'}) == 'DE'
|
||||
assert loc.display_name({}) == ''
|
||||
assert loc.display_name({'name:de': 'DE', 'name:en': 'EN'}) == 'EN'
|
||||
assert loc.display_name({'official_name:en': 'EN', 'name:de': 'DE'}) == 'DE'
|
||||
|
||||
|
||||
@pytest.mark.parametrize('langstr,langlist',
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# This file is part of Nominatim. (https://nominatim.org)
|
||||
#
|
||||
# Copyright (C) 2024 by the Nominatim developer community.
|
||||
# Copyright (C) 2025 by the Nominatim developer community.
|
||||
# For a full list of authors see the git log.
|
||||
"""
|
||||
Tests for formatting results for the V1 API.
|
||||
@@ -22,6 +22,7 @@ STATUS_FORMATS = {'text', 'json'}
|
||||
|
||||
# StatusResult
|
||||
|
||||
|
||||
def test_status_format_list():
|
||||
assert set(v1_format.list_formats(napi.StatusResult)) == STATUS_FORMATS
|
||||
|
||||
@@ -36,11 +37,13 @@ def test_status_unsupported():
|
||||
|
||||
|
||||
def test_status_format_text():
|
||||
assert v1_format.format_result(napi.StatusResult(0, 'message here'), 'text', {}) == 'OK'
|
||||
assert v1_format.format_result(napi.StatusResult(0, 'message here'), 'text', {}) \
|
||||
== 'OK'
|
||||
|
||||
|
||||
def test_status_format_text():
|
||||
assert v1_format.format_result(napi.StatusResult(500, 'message here'), 'text', {}) == 'ERROR: message here'
|
||||
def test_status_format_error_text():
|
||||
assert v1_format.format_result(napi.StatusResult(500, 'message here'), 'text', {}) \
|
||||
== 'ERROR: message here'
|
||||
|
||||
|
||||
def test_status_format_json_minimal():
|
||||
@@ -48,8 +51,9 @@ def test_status_format_json_minimal():
|
||||
|
||||
result = v1_format.format_result(status, 'json', {})
|
||||
|
||||
assert result == \
|
||||
f'{{"status":700,"message":"Bad format.","software_version":"{napi.__version__}"}}'
|
||||
assert json.loads(result) == {'status': 700,
|
||||
'message': 'Bad format.',
|
||||
'software_version': napi.__version__}
|
||||
|
||||
|
||||
def test_status_format_json_full():
|
||||
@@ -59,8 +63,11 @@ def test_status_format_json_full():
|
||||
|
||||
result = v1_format.format_result(status, 'json', {})
|
||||
|
||||
assert result == \
|
||||
f'{{"status":0,"message":"OK","data_updated":"2010-02-07T20:20:03+00:00","software_version":"{napi.__version__}","database_version":"5.6"}}'
|
||||
assert json.loads(result) == {'status': 0,
|
||||
'message': 'OK',
|
||||
'data_updated': '2010-02-07T20:20:03+00:00',
|
||||
'software_version': napi.__version__,
|
||||
'database_version': '5.6'}
|
||||
|
||||
|
||||
# DetailedResult
|
||||
@@ -86,7 +93,7 @@ def test_search_details_minimal():
|
||||
'extratags': {},
|
||||
'centroid': {'type': 'Point', 'coordinates': [1.0, 2.0]},
|
||||
'geometry': {'type': 'Point', 'coordinates': [1.0, 2.0]},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def test_search_details_full():
|
||||
@@ -110,7 +117,7 @@ def test_search_details_full():
|
||||
rank_search=28,
|
||||
importance=0.0443,
|
||||
country_code='ll',
|
||||
indexed_date = import_date
|
||||
indexed_date=import_date
|
||||
)
|
||||
search.localize(napi.Locales())
|
||||
|
||||
@@ -140,7 +147,7 @@ def test_search_details_full():
|
||||
'isarea': False,
|
||||
'centroid': {'type': 'Point', 'coordinates': [56.947, -87.44]},
|
||||
'geometry': {'type': 'Point', 'coordinates': [56.947, -87.44]},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.parametrize('gtype,isarea', [('ST_Point', False),
|
||||
@@ -149,9 +156,9 @@ def test_search_details_full():
|
||||
('ST_MultiPolygon', True)])
|
||||
def test_search_details_no_geometry(gtype, isarea):
|
||||
search = napi.DetailedResult(napi.SourceTable.PLACEX,
|
||||
('place', 'thing'),
|
||||
napi.Point(1.0, 2.0),
|
||||
geometry={'type': gtype})
|
||||
('place', 'thing'),
|
||||
napi.Point(1.0, 2.0),
|
||||
geometry={'type': gtype})
|
||||
|
||||
result = v1_format.format_result(search, 'json', {})
|
||||
js = json.loads(result)
|
||||
@@ -161,16 +168,17 @@ def test_search_details_no_geometry(gtype, isarea):
|
||||
|
||||
|
||||
def test_search_details_with_geometry():
|
||||
search = napi.DetailedResult(napi.SourceTable.PLACEX,
|
||||
('place', 'thing'),
|
||||
napi.Point(1.0, 2.0),
|
||||
geometry={'geojson': '{"type":"Point","coordinates":[56.947,-87.44]}'})
|
||||
search = napi.DetailedResult(
|
||||
napi.SourceTable.PLACEX,
|
||||
('place', 'thing'),
|
||||
napi.Point(1.0, 2.0),
|
||||
geometry={'geojson': '{"type":"Point","coordinates":[56.947,-87.44]}'})
|
||||
|
||||
result = v1_format.format_result(search, 'json', {})
|
||||
js = json.loads(result)
|
||||
|
||||
assert js['geometry'] == {'type': 'Point', 'coordinates': [56.947, -87.44]}
|
||||
assert js['isarea'] == False
|
||||
assert js['isarea'] is False
|
||||
|
||||
|
||||
def test_search_details_with_icon_available():
|
||||
@@ -226,7 +234,7 @@ def test_search_details_with_address_minimal():
|
||||
@pytest.mark.parametrize('field,outfield', [('address_rows', 'address'),
|
||||
('linked_rows', 'linked_places'),
|
||||
('parented_rows', 'hierarchy')
|
||||
])
|
||||
])
|
||||
def test_search_details_with_further_infos(field, outfield):
|
||||
search = napi.DetailedResult(napi.SourceTable.PLACEX,
|
||||
('place', 'thing'),
|
||||
@@ -249,50 +257,49 @@ def test_search_details_with_further_infos(field, outfield):
|
||||
js = json.loads(result)
|
||||
|
||||
assert js[outfield] == [{'localname': 'Trespass',
|
||||
'place_id': 3498,
|
||||
'osm_id': 442,
|
||||
'osm_type': 'R',
|
||||
'place_type': 'spec',
|
||||
'class': 'bnd',
|
||||
'type': 'note',
|
||||
'admin_level': 4,
|
||||
'rank_address': 10,
|
||||
'distance': 0.034,
|
||||
'isaddress': True}]
|
||||
'place_id': 3498,
|
||||
'osm_id': 442,
|
||||
'osm_type': 'R',
|
||||
'place_type': 'spec',
|
||||
'class': 'bnd',
|
||||
'type': 'note',
|
||||
'admin_level': 4,
|
||||
'rank_address': 10,
|
||||
'distance': 0.034,
|
||||
'isaddress': True}]
|
||||
|
||||
|
||||
def test_search_details_grouped_hierarchy():
|
||||
search = napi.DetailedResult(napi.SourceTable.PLACEX,
|
||||
('place', 'thing'),
|
||||
napi.Point(1.0, 2.0),
|
||||
parented_rows =
|
||||
[napi.AddressLine(place_id=3498,
|
||||
osm_object=('R', 442),
|
||||
category=('bnd', 'note'),
|
||||
names={'name': 'Trespass'},
|
||||
extratags={'access': 'no',
|
||||
'place_type': 'spec'},
|
||||
admin_level=4,
|
||||
fromarea=True,
|
||||
isaddress=True,
|
||||
rank_address=10,
|
||||
distance=0.034)
|
||||
])
|
||||
parented_rows=[napi.AddressLine(
|
||||
place_id=3498,
|
||||
osm_object=('R', 442),
|
||||
category=('bnd', 'note'),
|
||||
names={'name': 'Trespass'},
|
||||
extratags={'access': 'no',
|
||||
'place_type': 'spec'},
|
||||
admin_level=4,
|
||||
fromarea=True,
|
||||
isaddress=True,
|
||||
rank_address=10,
|
||||
distance=0.034)])
|
||||
|
||||
result = v1_format.format_result(search, 'json', {'group_hierarchy': True})
|
||||
js = json.loads(result)
|
||||
|
||||
assert js['hierarchy'] == {'note': [{'localname': 'Trespass',
|
||||
'place_id': 3498,
|
||||
'osm_id': 442,
|
||||
'osm_type': 'R',
|
||||
'place_type': 'spec',
|
||||
'class': 'bnd',
|
||||
'type': 'note',
|
||||
'admin_level': 4,
|
||||
'rank_address': 10,
|
||||
'distance': 0.034,
|
||||
'isaddress': True}]}
|
||||
'place_id': 3498,
|
||||
'osm_id': 442,
|
||||
'osm_type': 'R',
|
||||
'place_type': 'spec',
|
||||
'class': 'bnd',
|
||||
'type': 'note',
|
||||
'admin_level': 4,
|
||||
'rank_address': 10,
|
||||
'distance': 0.034,
|
||||
'isaddress': True}]}
|
||||
|
||||
|
||||
def test_search_details_keywords_name():
|
||||
@@ -307,7 +314,7 @@ def test_search_details_keywords_name():
|
||||
js = json.loads(result)
|
||||
|
||||
assert js['keywords'] == {'name': [{'id': 23, 'token': 'foo'},
|
||||
{'id': 24, 'token': 'foo'}],
|
||||
{'id': 24, 'token': 'foo'}],
|
||||
'address': []}
|
||||
|
||||
|
||||
@@ -323,6 +330,5 @@ def test_search_details_keywords_address():
|
||||
js = json.loads(result)
|
||||
|
||||
assert js['keywords'] == {'address': [{'id': 23, 'token': 'foo'},
|
||||
{'id': 24, 'token': 'foo'}],
|
||||
{'id': 24, 'token': 'foo'}],
|
||||
'name': []}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# This file is part of Nominatim. (https://nominatim.org)
|
||||
#
|
||||
# Copyright (C) 2024 by the Nominatim developer community.
|
||||
# Copyright (C) 2025 by the Nominatim developer community.
|
||||
# For a full list of authors see the git log.
|
||||
"""
|
||||
Tests for formatting reverse results for the V1 API.
|
||||
@@ -20,6 +20,7 @@ import nominatim_api as napi
|
||||
|
||||
FORMATS = ['json', 'jsonv2', 'geojson', 'geocodejson', 'xml']
|
||||
|
||||
|
||||
@pytest.mark.parametrize('fmt', FORMATS)
|
||||
def test_format_reverse_minimal(fmt):
|
||||
reverse = napi.ReverseResult(napi.SourceTable.PLACEX,
|
||||
@@ -104,8 +105,7 @@ def test_format_reverse_with_address(fmt):
|
||||
reverse.localize(napi.Locales())
|
||||
|
||||
raw = v1_format.format_result(napi.ReverseResults([reverse]), fmt,
|
||||
{'addressdetails': True})
|
||||
|
||||
{'addressdetails': True})
|
||||
|
||||
if fmt == 'xml':
|
||||
root = ET.fromstring(raw)
|
||||
@@ -168,7 +168,7 @@ def test_format_reverse_geocodejson_special_parts():
|
||||
reverse.localize(napi.Locales())
|
||||
|
||||
raw = v1_format.format_result(napi.ReverseResults([reverse]), 'geocodejson',
|
||||
{'addressdetails': True})
|
||||
{'addressdetails': True})
|
||||
|
||||
props = json.loads(raw)['features'][0]['properties']['geocoding']
|
||||
assert props['housenumber'] == '1'
|
||||
@@ -184,8 +184,7 @@ def test_format_reverse_with_address_none(fmt):
|
||||
address_rows=napi.AddressLines())
|
||||
|
||||
raw = v1_format.format_result(napi.ReverseResults([reverse]), fmt,
|
||||
{'addressdetails': True})
|
||||
|
||||
{'addressdetails': True})
|
||||
|
||||
if fmt == 'xml':
|
||||
root = ET.fromstring(raw)
|
||||
@@ -211,10 +210,10 @@ def test_format_reverse_with_extratags(fmt):
|
||||
reverse = napi.ReverseResult(napi.SourceTable.PLACEX,
|
||||
('place', 'thing'),
|
||||
napi.Point(1.0, 2.0),
|
||||
extratags={'one': 'A', 'two':'B'})
|
||||
extratags={'one': 'A', 'two': 'B'})
|
||||
|
||||
raw = v1_format.format_result(napi.ReverseResults([reverse]), fmt,
|
||||
{'extratags': True})
|
||||
{'extratags': True})
|
||||
|
||||
if fmt == 'xml':
|
||||
root = ET.fromstring(raw)
|
||||
@@ -226,7 +225,7 @@ def test_format_reverse_with_extratags(fmt):
|
||||
else:
|
||||
extra = result['extratags']
|
||||
|
||||
assert extra == {'one': 'A', 'two':'B'}
|
||||
assert extra == {'one': 'A', 'two': 'B'}
|
||||
|
||||
|
||||
@pytest.mark.parametrize('fmt', ['json', 'jsonv2', 'geojson', 'xml'])
|
||||
@@ -236,7 +235,7 @@ def test_format_reverse_with_extratags_none(fmt):
|
||||
napi.Point(1.0, 2.0))
|
||||
|
||||
raw = v1_format.format_result(napi.ReverseResults([reverse]), fmt,
|
||||
{'extratags': True})
|
||||
{'extratags': True})
|
||||
|
||||
if fmt == 'xml':
|
||||
root = ET.fromstring(raw)
|
||||
@@ -256,10 +255,10 @@ def test_format_reverse_with_namedetails_with_name(fmt):
|
||||
reverse = napi.ReverseResult(napi.SourceTable.PLACEX,
|
||||
('place', 'thing'),
|
||||
napi.Point(1.0, 2.0),
|
||||
names={'name': 'A', 'ref':'1'})
|
||||
names={'name': 'A', 'ref': '1'})
|
||||
|
||||
raw = v1_format.format_result(napi.ReverseResults([reverse]), fmt,
|
||||
{'namedetails': True})
|
||||
{'namedetails': True})
|
||||
|
||||
if fmt == 'xml':
|
||||
root = ET.fromstring(raw)
|
||||
@@ -271,7 +270,7 @@ def test_format_reverse_with_namedetails_with_name(fmt):
|
||||
else:
|
||||
extra = result['namedetails']
|
||||
|
||||
assert extra == {'name': 'A', 'ref':'1'}
|
||||
assert extra == {'name': 'A', 'ref': '1'}
|
||||
|
||||
|
||||
@pytest.mark.parametrize('fmt', ['json', 'jsonv2', 'geojson', 'xml'])
|
||||
@@ -281,7 +280,7 @@ def test_format_reverse_with_namedetails_without_name(fmt):
|
||||
napi.Point(1.0, 2.0))
|
||||
|
||||
raw = v1_format.format_result(napi.ReverseResults([reverse]), fmt,
|
||||
{'namedetails': True})
|
||||
{'namedetails': True})
|
||||
|
||||
if fmt == 'xml':
|
||||
root = ET.fromstring(raw)
|
||||
@@ -303,7 +302,7 @@ def test_search_details_with_icon_available(fmt):
|
||||
napi.Point(1.0, 2.0))
|
||||
|
||||
result = v1_format.format_result(napi.ReverseResults([reverse]), fmt,
|
||||
{'icon_base_url': 'foo'})
|
||||
{'icon_base_url': 'foo'})
|
||||
|
||||
js = json.loads(result)
|
||||
|
||||
@@ -317,7 +316,6 @@ def test_search_details_with_icon_not_available(fmt):
|
||||
napi.Point(1.0, 2.0))
|
||||
|
||||
result = v1_format.format_result(napi.ReverseResults([reverse]), fmt,
|
||||
{'icon_base_url': 'foo'})
|
||||
{'icon_base_url': 'foo'})
|
||||
|
||||
assert 'icon' not in json.loads(result)
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# This file is part of Nominatim. (https://nominatim.org)
|
||||
#
|
||||
# Copyright (C) 2024 by the Nominatim developer community.
|
||||
# Copyright (C) 2025 by the Nominatim developer community.
|
||||
# For a full list of authors see the git log.
|
||||
"""
|
||||
Tests for result datatype helper functions.
|
||||
@@ -11,16 +11,15 @@ import struct
|
||||
from binascii import hexlify
|
||||
|
||||
import pytest
|
||||
import pytest_asyncio
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
from nominatim_api import SourceTable, DetailedResult, Point
|
||||
import nominatim_api.results as nresults
|
||||
|
||||
|
||||
def mkpoint(x, y):
|
||||
return hexlify(struct.pack("=biidd", 1, 0x20000001, 4326, x, y)).decode('utf-8')
|
||||
|
||||
|
||||
class FakeRow:
|
||||
def __init__(self, **kwargs):
|
||||
if 'parent_place_id' not in kwargs:
|
||||
@@ -39,6 +38,7 @@ def test_minimal_detailed_result():
|
||||
assert res.lat == 0.5
|
||||
assert res.calculated_importance() == pytest.approx(0.00001)
|
||||
|
||||
|
||||
def test_detailed_result_custom_importance():
|
||||
res = DetailedResult(SourceTable.PLACEX,
|
||||
('amenity', 'post_box'),
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# This file is part of Nominatim. (https://nominatim.org)
|
||||
#
|
||||
# Copyright (C) 2024 by the Nominatim developer community.
|
||||
# Copyright (C) 2025 by the Nominatim developer community.
|
||||
# For a full list of authors see the git log.
|
||||
"""
|
||||
Tests for the Python web frameworks adaptor, v1 API.
|
||||
@@ -121,7 +121,6 @@ class TestAdaptorRaiseError:
|
||||
|
||||
return excinfo.value
|
||||
|
||||
|
||||
def test_without_content_set(self):
|
||||
err = self.run_raise_error('TEST', 404)
|
||||
|
||||
@@ -129,7 +128,6 @@ class TestAdaptorRaiseError:
|
||||
assert err.msg == 'ERROR 404: TEST'
|
||||
assert err.status == 404
|
||||
|
||||
|
||||
def test_json(self):
|
||||
self.adaptor.content_type = 'application/json; charset=utf-8'
|
||||
|
||||
@@ -139,7 +137,6 @@ class TestAdaptorRaiseError:
|
||||
assert content['code'] == 501
|
||||
assert content['message'] == 'TEST'
|
||||
|
||||
|
||||
def test_xml(self):
|
||||
self.adaptor.content_type = 'text/xml; charset=utf-8'
|
||||
|
||||
@@ -235,7 +232,6 @@ class TestStatusEndpoint:
|
||||
|
||||
monkeypatch.setattr(napi.NominatimAPIAsync, 'status', _status)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_status_without_params(self):
|
||||
a = FakeAdaptor()
|
||||
@@ -247,7 +243,6 @@ class TestStatusEndpoint:
|
||||
assert resp.status == 200
|
||||
assert resp.content_type == 'text/plain; charset=utf-8'
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_status_with_error(self):
|
||||
a = FakeAdaptor()
|
||||
@@ -259,7 +254,6 @@ class TestStatusEndpoint:
|
||||
assert resp.status == 500
|
||||
assert resp.content_type == 'text/plain; charset=utf-8'
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_status_json_with_error(self):
|
||||
a = FakeAdaptor(params={'format': 'json'})
|
||||
@@ -271,7 +265,6 @@ class TestStatusEndpoint:
|
||||
assert resp.status == 200
|
||||
assert resp.content_type == 'application/json; charset=utf-8'
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_status_bad_format(self):
|
||||
a = FakeAdaptor(params={'format': 'foo'})
|
||||
@@ -298,7 +291,6 @@ class TestDetailsEndpoint:
|
||||
|
||||
monkeypatch.setattr(napi.NominatimAPIAsync, 'details', _lookup)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_details_no_params(self):
|
||||
a = FakeAdaptor()
|
||||
@@ -306,7 +298,6 @@ class TestDetailsEndpoint:
|
||||
with pytest.raises(FakeError, match='^400 -- .*Missing'):
|
||||
await glue.details_endpoint(napi.NominatimAPIAsync(), a)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_details_by_place_id(self):
|
||||
a = FakeAdaptor(params={'place_id': '4573'})
|
||||
@@ -315,7 +306,6 @@ class TestDetailsEndpoint:
|
||||
|
||||
assert self.lookup_args[0].place_id == 4573
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_details_by_osm_id(self):
|
||||
a = FakeAdaptor(params={'osmtype': 'N', 'osmid': '45'})
|
||||
@@ -326,7 +316,6 @@ class TestDetailsEndpoint:
|
||||
assert self.lookup_args[0].osm_id == 45
|
||||
assert self.lookup_args[0].osm_class is None
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_details_with_debugging(self):
|
||||
a = FakeAdaptor(params={'osmtype': 'N', 'osmid': '45', 'debug': '1'})
|
||||
@@ -337,7 +326,6 @@ class TestDetailsEndpoint:
|
||||
assert resp.content_type == 'text/html; charset=utf-8'
|
||||
assert content.tag == 'html'
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_details_no_result(self):
|
||||
a = FakeAdaptor(params={'place_id': '4573'})
|
||||
@@ -353,14 +341,14 @@ class TestReverseEndPoint:
|
||||
@pytest.fixture(autouse=True)
|
||||
def patch_reverse_func(self, monkeypatch):
|
||||
self.result = napi.ReverseResult(napi.SourceTable.PLACEX,
|
||||
('place', 'thing'),
|
||||
napi.Point(1.0, 2.0))
|
||||
('place', 'thing'),
|
||||
napi.Point(1.0, 2.0))
|
||||
|
||||
async def _reverse(*args, **kwargs):
|
||||
return self.result
|
||||
|
||||
monkeypatch.setattr(napi.NominatimAPIAsync, 'reverse', _reverse)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.parametrize('params', [{}, {'lat': '3.4'}, {'lon': '6.7'}])
|
||||
async def test_reverse_no_params(self, params):
|
||||
@@ -371,19 +359,6 @@ class TestReverseEndPoint:
|
||||
with pytest.raises(FakeError, match='^400 -- (?s:.*)missing'):
|
||||
await glue.reverse_endpoint(napi.NominatimAPIAsync(), a)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.parametrize('params', [{'lat': '45.6', 'lon': '4563'}])
|
||||
async def test_reverse_success(self, params):
|
||||
a = FakeAdaptor()
|
||||
a.params = params
|
||||
a.params['format'] = 'json'
|
||||
|
||||
res = await glue.reverse_endpoint(napi.NominatimAPIAsync(), a)
|
||||
|
||||
assert res == ''
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_reverse_success(self):
|
||||
a = FakeAdaptor()
|
||||
@@ -392,7 +367,6 @@ class TestReverseEndPoint:
|
||||
|
||||
assert await glue.reverse_endpoint(napi.NominatimAPIAsync(), a)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_reverse_from_search(self):
|
||||
a = FakeAdaptor()
|
||||
@@ -413,12 +387,12 @@ class TestLookupEndpoint:
|
||||
self.results = [napi.SearchResult(napi.SourceTable.PLACEX,
|
||||
('place', 'thing'),
|
||||
napi.Point(1.0, 2.0))]
|
||||
|
||||
async def _lookup(*args, **kwargs):
|
||||
return napi.SearchResults(self.results)
|
||||
|
||||
monkeypatch.setattr(napi.NominatimAPIAsync, 'lookup', _lookup)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_lookup_no_params(self):
|
||||
a = FakeAdaptor()
|
||||
@@ -428,7 +402,6 @@ class TestLookupEndpoint:
|
||||
|
||||
assert res.output == '[]'
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.parametrize('param', ['w', 'bad', ''])
|
||||
async def test_lookup_bad_params(self, param):
|
||||
@@ -440,7 +413,6 @@ class TestLookupEndpoint:
|
||||
|
||||
assert len(json.loads(res.output)) == 1
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.parametrize('param', ['p234234', '4563'])
|
||||
async def test_lookup_bad_osm_type(self, param):
|
||||
@@ -452,7 +424,6 @@ class TestLookupEndpoint:
|
||||
|
||||
assert len(json.loads(res.output)) == 1
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_lookup_working(self):
|
||||
a = FakeAdaptor()
|
||||
@@ -473,12 +444,12 @@ class TestSearchEndPointSearch:
|
||||
self.results = [napi.SearchResult(napi.SourceTable.PLACEX,
|
||||
('place', 'thing'),
|
||||
napi.Point(1.0, 2.0))]
|
||||
|
||||
async def _search(*args, **kwargs):
|
||||
return napi.SearchResults(self.results)
|
||||
|
||||
monkeypatch.setattr(napi.NominatimAPIAsync, 'search', _search)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_search_free_text(self):
|
||||
a = FakeAdaptor()
|
||||
@@ -488,7 +459,6 @@ class TestSearchEndPointSearch:
|
||||
|
||||
assert len(json.loads(res.output)) == 1
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_search_free_text_xml(self):
|
||||
a = FakeAdaptor()
|
||||
@@ -500,7 +470,6 @@ class TestSearchEndPointSearch:
|
||||
assert res.status == 200
|
||||
assert res.output.index('something') > 0
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_search_free_and_structured(self):
|
||||
a = FakeAdaptor()
|
||||
@@ -508,8 +477,7 @@ class TestSearchEndPointSearch:
|
||||
a.params['city'] = 'ignored'
|
||||
|
||||
with pytest.raises(FakeError, match='^400 -- .*cannot be used together'):
|
||||
res = await glue.search_endpoint(napi.NominatimAPIAsync(), a)
|
||||
|
||||
await glue.search_endpoint(napi.NominatimAPIAsync(), a)
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.parametrize('dedupe,numres', [(True, 1), (False, 2)])
|
||||
@@ -532,12 +500,12 @@ class TestSearchEndPointSearchAddress:
|
||||
self.results = [napi.SearchResult(napi.SourceTable.PLACEX,
|
||||
('place', 'thing'),
|
||||
napi.Point(1.0, 2.0))]
|
||||
|
||||
async def _search(*args, **kwargs):
|
||||
return napi.SearchResults(self.results)
|
||||
|
||||
monkeypatch.setattr(napi.NominatimAPIAsync, 'search_address', _search)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_search_structured(self):
|
||||
a = FakeAdaptor()
|
||||
@@ -555,12 +523,12 @@ class TestSearchEndPointSearchCategory:
|
||||
self.results = [napi.SearchResult(napi.SourceTable.PLACEX,
|
||||
('place', 'thing'),
|
||||
napi.Point(1.0, 2.0))]
|
||||
|
||||
async def _search(*args, **kwargs):
|
||||
return napi.SearchResults(self.results)
|
||||
|
||||
monkeypatch.setattr(napi.NominatimAPIAsync, 'search_category', _search)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_search_category(self):
|
||||
a = FakeAdaptor()
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# This file is part of Nominatim. (https://nominatim.org)
|
||||
#
|
||||
# Copyright (C) 2024 by the Nominatim developer community.
|
||||
# Copyright (C) 2025 by the Nominatim developer community.
|
||||
# For a full list of authors see the git log.
|
||||
"""
|
||||
Tests for warm-up CLI function.
|
||||
@@ -11,6 +11,7 @@ import pytest
|
||||
|
||||
import nominatim_db.cli
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup_database_with_context(apiobj, table_factory):
|
||||
table_factory('word',
|
||||
@@ -21,8 +22,9 @@ def setup_database_with_context(apiobj, table_factory):
|
||||
apiobj.add_data('properties',
|
||||
[{'property': 'tokenizer', 'value': 'icu'},
|
||||
{'property': 'tokenizer_import_normalisation', 'value': ':: lower();'},
|
||||
{'property': 'tokenizer_import_transliteration', 'value': "'1' > '/1/'; 'ä' > 'ä '"},
|
||||
])
|
||||
{'property': 'tokenizer_import_transliteration',
|
||||
'value': "'1' > '/1/'; 'ä' > 'ä '"}
|
||||
])
|
||||
|
||||
|
||||
@pytest.mark.parametrize('args', [['--search-only'], ['--reverse-only']])
|
||||
|
||||
Reference in New Issue
Block a user