From: Sarah Hoffmann Date: Tue, 19 Sep 2023 09:17:04 +0000 (+0200) Subject: move localization into add_result_details X-Git-Tag: v4.4.0~97^2~3 X-Git-Url: https://git.openstreetmap.org./nominatim.git/commitdiff_plain/5762a5bc80bdb679a23f500aeb428b431f0774f9 move localization into add_result_details This means that the locale now needs to be handed in into the search functions already. At least search needs them for reranking. --- diff --git a/nominatim/api/results.py b/nominatim/api/results.py index 0183f5b9..1b2534e2 100644 --- a/nominatim/api/results.py +++ b/nominatim/api/results.py @@ -292,12 +292,6 @@ class SearchResults(List[SearchResult]): May be empty when no result was found. """ - def localize(self, locales: Locales) -> None: - """ Apply the given locales to all results. - """ - for result in self: - result.localize(locales) - def _filter_geometries(row: SaRow) -> Dict[str, str]: return {k[9:]: v for k, v in row._mapping.items() # pylint: disable=W0212 @@ -459,6 +453,8 @@ async def add_result_details(conn: SearchConnection, results: List[BaseResultT], log().comment('Query keywords') for result in results: await complete_keywords(conn, result) + for result in results: + result.localize(details.locales) def _result_row_to_address_row(row: SaRow) -> AddressLine: diff --git a/nominatim/api/types.py b/nominatim/api/types.py index c96b3f59..3ca023e7 100644 --- a/nominatim/api/types.py +++ b/nominatim/api/types.py @@ -17,6 +17,7 @@ from struct import unpack from binascii import unhexlify from nominatim.errors import UsageError +from nominatim.api.localization import Locales # pylint: disable=no-member,too-many-boolean-expressions,too-many-instance-attributes @@ -386,7 +387,7 @@ TParam = TypeVar('TParam', bound='LookupDetails') # pylint: disable=invalid-name @dataclasses.dataclass class LookupDetails: - """ Collection of parameters that define the amount of details + """ Collection of parameters that define which kind of details are returned with a lookup or details result. """ geometry_output: GeometryFormat = GeometryFormat.NONE @@ -413,6 +414,9 @@ class LookupDetails: 0.0 means the original geometry is kept. The higher the value, the more the geometry gets simplified. """ + locales: Locales = Locales() + """ Prefered languages for localization of results. + """ @classmethod def from_kwargs(cls: Type[TParam], kwargs: Dict[str, Any]) -> TParam: diff --git a/nominatim/api/v1/server_glue.py b/nominatim/api/v1/server_glue.py index 5e8dbf4f..70f7dc40 100644 --- a/nominatim/api/v1/server_glue.py +++ b/nominatim/api/v1/server_glue.py @@ -308,7 +308,8 @@ async def details_endpoint(api: napi.NominatimAPIAsync, params: ASGIAdaptor) -> keywords=params.get_bool('keywords', False), geometry_output = napi.GeometryFormat.GEOJSON if params.get_bool('polygon_geojson', False) - else napi.GeometryFormat.NONE + else napi.GeometryFormat.NONE, + locales=locales ) if debug: @@ -317,8 +318,6 @@ async def details_endpoint(api: napi.NominatimAPIAsync, params: ASGIAdaptor) -> if result is None: params.raise_error('No place with that OSM ID found.', status=404) - result.localize(locales) - output = formatting.format_result(result, fmt, {'locales': locales, 'group_hierarchy': params.get_bool('group_hierarchy', False), @@ -337,6 +336,7 @@ async def reverse_endpoint(api: napi.NominatimAPIAsync, params: ASGIAdaptor) -> details = params.parse_geometry_details(fmt) details['max_rank'] = helpers.zoom_to_rank(params.get_int('zoom', 18)) details['layers'] = params.get_layers() + details['locales'] = napi.Locales.from_accept_languages(params.get_accepted_languages()) result = await api.reverse(coord, **details) @@ -357,9 +357,6 @@ async def reverse_endpoint(api: napi.NominatimAPIAsync, params: ASGIAdaptor) -> 'namedetails': params.get_bool('namedetails', False), 'addressdetails': params.get_bool('addressdetails', True)} - if result: - result.localize(napi.Locales.from_accept_languages(params.get_accepted_languages())) - output = formatting.format_result(napi.ReverseResults([result] if result else []), fmt, fmt_options) @@ -372,6 +369,7 @@ async def lookup_endpoint(api: napi.NominatimAPIAsync, params: ASGIAdaptor) -> A fmt = params.parse_format(napi.SearchResults, 'xml') debug = params.setup_debugging() details = params.parse_geometry_details(fmt) + details['locales'] = napi.Locales.from_accept_languages(params.get_accepted_languages()) places = [] for oid in (params.get('osm_ids') or '').split(','): @@ -394,8 +392,6 @@ async def lookup_endpoint(api: napi.NominatimAPIAsync, params: ASGIAdaptor) -> A 'namedetails': params.get_bool('namedetails', False), 'addressdetails': params.get_bool('addressdetails', True)} - results.localize(napi.Locales.from_accept_languages(params.get_accepted_languages())) - output = formatting.format_result(results, fmt, fmt_options) return params.build_response(output, num_results=len(results)) @@ -456,6 +452,8 @@ async def search_endpoint(api: napi.NominatimAPIAsync, params: ASGIAdaptor) -> A else: details['layers'] = params.get_layers() + details['locales'] = napi.Locales.from_accept_languages(params.get_accepted_languages()) + # unstructured query parameters query = params.get('q', None) # structured query parameters @@ -480,8 +478,6 @@ async def search_endpoint(api: napi.NominatimAPIAsync, params: ASGIAdaptor) -> A except UsageError as err: params.raise_error(str(err)) - results.localize(napi.Locales.from_accept_languages(params.get_accepted_languages())) - if details['dedupe'] and len(results) > 1: results = helpers.deduplicate_results(results, max_results) diff --git a/nominatim/clicmd/api.py b/nominatim/clicmd/api.py index e8f1d233..e8450e6b 100644 --- a/nominatim/clicmd/api.py +++ b/nominatim/clicmd/api.py @@ -109,7 +109,8 @@ class APISearch: 'countries': args.countrycodes, 'excluded': args.exclude_place_ids, 'viewbox': args.viewbox, - 'bounded_viewbox': args.bounded + 'bounded_viewbox': args.bounded, + 'locales': args.get_locales(api.config.DEFAULT_LANGUAGE) } if args.query: @@ -124,9 +125,6 @@ class APISearch: country=args.country, **params) - for result in results: - result.localize(args.get_locales(api.config.DEFAULT_LANGUAGE)) - if args.dedupe and len(results) > 1: results = deduplicate_results(results, args.limit) @@ -187,14 +185,14 @@ class APIReverse: layers=args.get_layers(napi.DataLayer.ADDRESS | napi.DataLayer.POI), address_details=True, # needed for display name geometry_output=args.get_geometry_output(), - geometry_simplification=args.polygon_threshold) + geometry_simplification=args.polygon_threshold, + locales=args.get_locales(api.config.DEFAULT_LANGUAGE)) if args.format == 'debug': print(loglib.get_and_disable()) return 0 if result: - result.localize(args.get_locales(api.config.DEFAULT_LANGUAGE)) output = api_output.format_result( napi.ReverseResults([result]), args.format, @@ -249,10 +247,8 @@ class APILookup: results = api.lookup(places, address_details=True, # needed for display name geometry_output=args.get_geometry_output(), - geometry_simplification=args.polygon_threshold or 0.0) - - for result in results: - result.localize(args.get_locales(api.config.DEFAULT_LANGUAGE)) + geometry_simplification=args.polygon_threshold or 0.0, + locales=args.get_locales(api.config.DEFAULT_LANGUAGE)) output = api_output.format_result( results, @@ -326,6 +322,7 @@ class APIDetails: api = napi.NominatimAPI(args.project_dir) + locales = args.get_locales(api.config.DEFAULT_LANGUAGE) result = api.details(place, address_details=args.addressdetails, linked_places=args.linkedplaces, @@ -333,13 +330,11 @@ class APIDetails: keywords=args.keywords, geometry_output=napi.GeometryFormat.GEOJSON if args.polygon_geojson - else napi.GeometryFormat.NONE) + else napi.GeometryFormat.NONE, + locales=locales) if result: - locales = args.get_locales(api.config.DEFAULT_LANGUAGE) - result.localize(locales) - output = api_output.format_result( result, 'json', diff --git a/test/python/api/test_api_details.py b/test/python/api/test_api_details.py index 101dfd13..05a7aa7f 100644 --- a/test/python/api/test_api_details.py +++ b/test/python/api/test_api_details.py @@ -150,17 +150,20 @@ def test_lookup_placex_with_address_details(apiobj): category=('highway', 'residential'), names={'name': 'Street'}, extratags={}, admin_level=15, fromarea=True, isaddress=True, - rank_address=26, distance=0.0), + rank_address=26, distance=0.0, + local_name='Street'), napi.AddressLine(place_id=1000, osm_object=('N', 3333), category=('place', 'suburb'), names={'name': 'Smallplace'}, extratags={}, admin_level=13, fromarea=False, isaddress=True, - rank_address=23, distance=0.0034), + rank_address=23, distance=0.0034, + local_name='Smallplace'), napi.AddressLine(place_id=1001, osm_object=('N', 3334), category=('place', 'city'), names={'name': 'Bigplace'}, extratags={}, admin_level=15, fromarea=True, isaddress=True, - rank_address=16, distance=0.0), + rank_address=16, distance=0.0, + local_name='Bigplace'), napi.AddressLine(place_id=None, osm_object=None, category=('place', 'country_code'), names={'ref': 'pl'}, extratags={}, @@ -341,22 +344,26 @@ def test_lookup_osmline_with_address_details(apiobj): category=('place', 'house_number'), names={'ref': '2'}, extratags={}, admin_level=None, fromarea=True, isaddress=True, - rank_address=28, distance=0.0), + rank_address=28, distance=0.0, + local_name='2'), napi.AddressLine(place_id=332, osm_object=('W', 4), category=('highway', 'residential'), names={'name': 'Street'}, extratags={}, admin_level=15, fromarea=True, isaddress=True, - rank_address=26, distance=0.0), + rank_address=26, distance=0.0, + local_name='Street'), napi.AddressLine(place_id=1000, osm_object=('N', 3333), category=('place', 'suburb'), names={'name': 'Smallplace'}, extratags={}, admin_level=13, fromarea=False, isaddress=True, - rank_address=23, distance=0.0034), + rank_address=23, distance=0.0034, + local_name='Smallplace'), napi.AddressLine(place_id=1001, osm_object=('N', 3334), category=('place', 'city'), names={'name': 'Bigplace'}, extratags={}, admin_level=15, fromarea=True, isaddress=True, - rank_address=16, distance=0.0), + rank_address=16, distance=0.0, + local_name='Bigplace'), napi.AddressLine(place_id=None, osm_object=None, category=('place', 'country_code'), names={'ref': 'pl'}, extratags={}, @@ -441,22 +448,26 @@ def test_lookup_tiger_with_address_details(apiobj): category=('place', 'house_number'), names={'ref': '2'}, extratags={}, admin_level=None, fromarea=True, isaddress=True, - rank_address=28, distance=0.0), + rank_address=28, distance=0.0, + local_name='2'), napi.AddressLine(place_id=332, osm_object=('W', 4), category=('highway', 'residential'), names={'name': 'Street'}, extratags={}, admin_level=15, fromarea=True, isaddress=True, - rank_address=26, distance=0.0), + rank_address=26, distance=0.0, + local_name='Street'), napi.AddressLine(place_id=1000, osm_object=('N', 3333), category=('place', 'suburb'), names={'name': 'Smallplace'}, extratags={}, admin_level=13, fromarea=False, isaddress=True, - rank_address=23, distance=0.0034), + rank_address=23, distance=0.0034, + local_name='Smallplace'), napi.AddressLine(place_id=1001, osm_object=('N', 3334), category=('place', 'city'), names={'name': 'Bigplace'}, extratags={}, admin_level=15, fromarea=True, isaddress=True, - rank_address=16, distance=0.0), + rank_address=16, distance=0.0, + local_name='Bigplace'), napi.AddressLine(place_id=None, osm_object=None, category=('place', 'country_code'), names={'ref': 'us'}, extratags={}, @@ -536,17 +547,20 @@ def test_lookup_postcode_with_address_details(apiobj): category=('place', 'suburb'), names={'name': 'Smallplace'}, extratags={}, admin_level=13, fromarea=True, isaddress=True, - rank_address=23, distance=0.0), + rank_address=23, distance=0.0, + local_name='Smallplace'), napi.AddressLine(place_id=1001, osm_object=('N', 3334), category=('place', 'city'), names={'name': 'Bigplace'}, extratags={}, admin_level=15, fromarea=True, isaddress=True, - rank_address=16, distance=0.0), + rank_address=16, distance=0.0, + local_name='Bigplace'), napi.AddressLine(place_id=None, osm_object=None, category=('place', 'postcode'), names={'ref': '34 425'}, extratags={}, admin_level=None, fromarea=False, isaddress=True, - rank_address=5, distance=0.0), + rank_address=5, distance=0.0, + local_name='34 425'), napi.AddressLine(place_id=None, osm_object=None, category=('place', 'country_code'), names={'ref': 'gb'}, extratags={}, diff --git a/test/python/cli/test_cmd_api.py b/test/python/cli/test_cmd_api.py index 05e3c4f0..ca160a35 100644 --- a/test/python/cli/test_cmd_api.py +++ b/test/python/cli/test_cmd_api.py @@ -67,7 +67,9 @@ class TestCliReverseCall: result = napi.ReverseResult(napi.SourceTable.PLACEX, ('place', 'thing'), napi.Point(1.0, -3.0), names={'name':'Name', 'name:fr': 'Nom'}, - extratags={'extra':'Extra'}) + extratags={'extra':'Extra'}, + locale_name='Name', + display_name='Name') monkeypatch.setattr(napi.NominatimAPI, 'reverse', lambda *args, **kwargs: result) @@ -109,16 +111,6 @@ class TestCliReverseCall: assert out['type'] == 'FeatureCollection' - def test_reverse_language(self, cli_call, tmp_path, capsys): - result = cli_call('reverse', '--project-dir', str(tmp_path), - '--lat', '34', '--lon', '34', '--lang', 'fr') - - assert result == 0 - - out = json.loads(capsys.readouterr().out) - assert out['name'] == 'Nom' - - class TestCliLookupCall: @pytest.fixture(autouse=True) @@ -126,7 +118,9 @@ class TestCliLookupCall: result = napi.SearchResult(napi.SourceTable.PLACEX, ('place', 'thing'), napi.Point(1.0, -3.0), names={'name':'Name', 'name:fr': 'Nom'}, - extratags={'extra':'Extra'}) + extratags={'extra':'Extra'}, + locale_name='Name', + display_name='Name') monkeypatch.setattr(napi.NominatimAPI, 'lookup', lambda *args, **kwargs: napi.SearchResults([result])) @@ -150,9 +144,11 @@ class TestCliLookupCall: ]) def test_search(cli_call, tmp_path, capsys, monkeypatch, endpoint, params): result = napi.SearchResult(napi.SourceTable.PLACEX, ('place', 'thing'), - napi.Point(1.0, -3.0), - names={'name':'Name', 'name:fr': 'Nom'}, - extratags={'extra':'Extra'}) + napi.Point(1.0, -3.0), + names={'name':'Name', 'name:fr': 'Nom'}, + extratags={'extra':'Extra'}, + locale_name='Name', + display_name='Name') monkeypatch.setattr(napi.NominatimAPI, endpoint, lambda *args, **kwargs: napi.SearchResults([result]))