]> git.openstreetmap.org Git - nominatim.git/blobdiff - src/nominatim_db/clicmd/api.py
add new format 'raw' for CLI commands
[nominatim.git] / src / nominatim_db / clicmd / api.py
index ddc10ff96d729a826126c7052f60b9cd70efe61c..000a603296d5f7c6e95e21e288d34a62ec3639c6 100644 (file)
@@ -12,6 +12,7 @@ import argparse
 import logging
 import json
 import sys
+import pprint
 from functools import reduce
 
 import nominatim_api as napi
@@ -113,24 +114,29 @@ def _list_formats(formatter: napi.FormatDispatcher, rtype: Type[Any]) -> int:
     for fmt in formatter.list_formats(rtype):
         print(fmt)
     print('debug')
+    print('raw')
 
     return 0
 
 
 def _print_output(formatter: napi.FormatDispatcher, result: Any,
                   fmt: str, options: Mapping[str, Any]) -> None:
-    output = formatter.format_result(result, fmt, options)
-    if formatter.get_content_type(fmt) == CONTENT_JSON:
-        # reformat the result, so it is pretty-printed
-        try:
-            json.dump(json.loads(output), sys.stdout, indent=4, ensure_ascii=False)
-        except json.decoder.JSONDecodeError as err:
-            # Catch the error here, so that data can be debugged,
-            # when people are developping custom result formatters.
-            LOG.fatal("Parsing json failed: %s\nUnformatted output:\n%s", err, output)
+
+    if fmt == 'raw':
+        pprint.pprint(result)
     else:
-        sys.stdout.write(output)
-    sys.stdout.write('\n')
+        output = formatter.format_result(result, fmt, options)
+        if formatter.get_content_type(fmt) == CONTENT_JSON:
+            # reformat the result, so it is pretty-printed
+            try:
+                json.dump(json.loads(output), sys.stdout, indent=4, ensure_ascii=False)
+            except json.decoder.JSONDecodeError as err:
+                # Catch the error here, so that data can be debugged,
+                # when people are developping custom result formatters.
+                LOG.fatal("Parsing json failed: %s\nUnformatted output:\n%s", err, output)
+        else:
+            sys.stdout.write(output)
+        sys.stdout.write('\n')
 
 
 class APISearch:
@@ -174,35 +180,38 @@ class APISearch:
         if args.list_formats:
             return _list_formats(formatter, napi.SearchResults)
 
-        if args.format == 'debug':
+        if args.format in ('debug', 'raw'):
             loglib.set_log_output('text')
         elif not formatter.supports_format(napi.SearchResults, args.format):
             raise UsageError(f"Unsupported format '{args.format}'. "
                              'Use --list-formats to see supported formats.')
 
-        api = napi.NominatimAPI(args.project_dir)
-        params: Dict[str, Any] = {'max_results': args.limit + min(args.limit, 10),
-                                  'address_details': True, # needed for display name
-                                  'geometry_output': _get_geometry_output(args),
-                                  'geometry_simplification': args.polygon_threshold,
-                                  'countries': args.countrycodes,
-                                  'excluded': args.exclude_place_ids,
-                                  'viewbox': args.viewbox,
-                                  'bounded_viewbox': args.bounded,
-                                  'locales': _get_locales(args, api.config.DEFAULT_LANGUAGE)
-                                 }
-
-        if args.query:
-            results = api.search(args.query, **params)
-        else:
-            results = api.search_address(amenity=args.amenity,
-                                         street=args.street,
-                                         city=args.city,
-                                         county=args.county,
-                                         state=args.state,
-                                         postalcode=args.postalcode,
-                                         country=args.country,
-                                         **params)
+        try:
+            with napi.NominatimAPI(args.project_dir) as api:
+                params: Dict[str, Any] = {'max_results': args.limit + min(args.limit, 10),
+                                          'address_details': True, # needed for display name
+                                          'geometry_output': _get_geometry_output(args),
+                                          'geometry_simplification': args.polygon_threshold,
+                                          'countries': args.countrycodes,
+                                          'excluded': args.exclude_place_ids,
+                                          'viewbox': args.viewbox,
+                                          'bounded_viewbox': args.bounded,
+                                          'locales': _get_locales(args, api.config.DEFAULT_LANGUAGE)
+                                         }
+
+                if args.query:
+                    results = api.search(args.query, **params)
+                else:
+                    results = api.search_address(amenity=args.amenity,
+                                                 street=args.street,
+                                                 city=args.city,
+                                                 county=args.county,
+                                                 state=args.state,
+                                                 postalcode=args.postalcode,
+                                                 country=args.country,
+                                                 **params)
+        except napi.UsageError as ex:
+            raise UsageError(ex) from ex
 
         if args.dedupe and len(results) > 1:
             results = deduplicate_results(results, args.limit)
@@ -251,7 +260,7 @@ class APIReverse:
         if args.list_formats:
             return _list_formats(formatter, napi.ReverseResults)
 
-        if args.format == 'debug':
+        if args.format in ('debug', 'raw'):
             loglib.set_log_output('text')
         elif not formatter.supports_format(napi.ReverseResults, args.format):
             raise UsageError(f"Unsupported format '{args.format}'. "
@@ -260,14 +269,19 @@ class APIReverse:
         if args.lat is None or args.lon is None:
             raise UsageError("lat' and 'lon' parameters are required.")
 
-        api = napi.NominatimAPI(args.project_dir)
-        result = api.reverse(napi.Point(args.lon, args.lat),
-                             max_rank=zoom_to_rank(args.zoom or 18),
-                             layers=_get_layers(args, napi.DataLayer.ADDRESS | napi.DataLayer.POI),
-                             address_details=True, # needed for display name
-                             geometry_output=_get_geometry_output(args),
-                             geometry_simplification=args.polygon_threshold,
-                             locales=_get_locales(args, api.config.DEFAULT_LANGUAGE))
+        layers = _get_layers(args, napi.DataLayer.ADDRESS | napi.DataLayer.POI)
+
+        try:
+            with napi.NominatimAPI(args.project_dir) as api:
+                result = api.reverse(napi.Point(args.lon, args.lat),
+                                     max_rank=zoom_to_rank(args.zoom or 18),
+                                     layers=layers,
+                                     address_details=True, # needed for display name
+                                     geometry_output=_get_geometry_output(args),
+                                     geometry_simplification=args.polygon_threshold,
+                                     locales=_get_locales(args, api.config.DEFAULT_LANGUAGE))
+        except napi.UsageError as ex:
+            raise UsageError(ex) from ex
 
         if args.format == 'debug':
             print(loglib.get_and_disable())
@@ -312,7 +326,7 @@ class APILookup:
         if args.list_formats:
             return _list_formats(formatter, napi.ReverseResults)
 
-        if args.format == 'debug':
+        if args.format in ('debug', 'raw'):
             loglib.set_log_output('text')
         elif not formatter.supports_format(napi.ReverseResults, args.format):
             raise UsageError(f"Unsupported format '{args.format}'. "
@@ -323,12 +337,15 @@ class APILookup:
 
         places = [napi.OsmID(o[0], int(o[1:])) for o in args.ids]
 
-        api = napi.NominatimAPI(args.project_dir)
-        results = api.lookup(places,
-                             address_details=True, # needed for display name
-                             geometry_output=_get_geometry_output(args),
-                             geometry_simplification=args.polygon_threshold or 0.0,
-                             locales=_get_locales(args, api.config.DEFAULT_LANGUAGE))
+        try:
+            with napi.NominatimAPI(args.project_dir) as api:
+                results = api.lookup(places,
+                                     address_details=True, # needed for display name
+                                     geometry_output=_get_geometry_output(args),
+                                     geometry_simplification=args.polygon_threshold or 0.0,
+                                     locales=_get_locales(args, api.config.DEFAULT_LANGUAGE))
+        except napi.UsageError as ex:
+            raise UsageError(ex) from ex
 
         if args.format == 'debug':
             print(loglib.get_and_disable())
@@ -391,7 +408,7 @@ class APIDetails:
         if args.list_formats:
             return _list_formats(formatter, napi.DetailedResult)
 
-        if args.format == 'debug':
+        if args.format in ('debug', 'raw'):
             loglib.set_log_output('text')
         elif not formatter.supports_format(napi.DetailedResult, args.format):
             raise UsageError(f"Unsupported format '{args.format}'. "
@@ -410,17 +427,20 @@ class APIDetails:
             raise UsageError('One of the arguments --node/-n --way/-w '
                              '--relation/-r --place_id/-p is required/')
 
-        api = napi.NominatimAPI(args.project_dir)
-        locales = _get_locales(args, api.config.DEFAULT_LANGUAGE)
-        result = api.details(place,
-                             address_details=args.addressdetails,
-                             linked_places=args.linkedplaces,
-                             parented_places=args.hierarchy,
-                             keywords=args.keywords,
-                             geometry_output=napi.GeometryFormat.GEOJSON
-                                             if args.polygon_geojson
-                                             else napi.GeometryFormat.NONE,
-                            locales=locales)
+        try:
+            with napi.NominatimAPI(args.project_dir) as api:
+                locales = _get_locales(args, api.config.DEFAULT_LANGUAGE)
+                result = api.details(place,
+                                     address_details=args.addressdetails,
+                                     linked_places=args.linkedplaces,
+                                     parented_places=args.hierarchy,
+                                     keywords=args.keywords,
+                                     geometry_output=napi.GeometryFormat.GEOJSON
+                                                     if args.polygon_geojson
+                                                     else napi.GeometryFormat.NONE,
+                                    locales=locales)
+        except napi.UsageError as ex:
+            raise UsageError(ex) from ex
 
         if args.format == 'debug':
             print(loglib.get_and_disable())
@@ -459,13 +479,17 @@ class APIStatus:
         if args.list_formats:
             return _list_formats(formatter, napi.StatusResult)
 
-        if args.format == 'debug':
+        if args.format in ('debug', 'raw'):
             loglib.set_log_output('text')
         elif not formatter.supports_format(napi.StatusResult, args.format):
             raise UsageError(f"Unsupported format '{args.format}'. "
                              'Use --list-formats to see supported formats.')
 
-        status = napi.NominatimAPI(args.project_dir).status()
+        try:
+            with napi.NominatimAPI(args.project_dir) as api:
+                status = api.status()
+        except napi.UsageError as ex:
+            raise UsageError(ex) from ex
 
         if args.format == 'debug':
             print(loglib.get_and_disable())