]> git.openstreetmap.org Git - nominatim.git/blob - nominatim/clicmd/api.py
Merge remote-tracking branch 'upstream/master'
[nominatim.git] / nominatim / clicmd / api.py
1 """
2 Subcommand definitions for API calls from the command line.
3 """
4 import logging
5
6 from ..tools.exec_utils import run_api_script
7
8 # Do not repeat documentation of subcommand classes.
9 # pylint: disable=C0111
10
11 LOG = logging.getLogger()
12
13 STRUCTURED_QUERY = (
14     ('street', 'housenumber and street'),
15     ('city', 'city, town or village'),
16     ('county', 'county'),
17     ('state', 'state'),
18     ('country', 'country'),
19     ('postalcode', 'postcode')
20 )
21
22 EXTRADATA_PARAMS = (
23     ('addressdetails', 'Include a breakdown of the address into elements.'),
24     ('extratags', ("Include additional information if available "
25                    "(e.g. wikipedia link, opening hours).")),
26     ('namedetails', 'Include a list of alternative names.')
27 )
28
29 DETAILS_SWITCHES = (
30     ('addressdetails', 'Include a breakdown of the address into elements.'),
31     ('keywords', 'Include a list of name keywords and address keywords.'),
32     ('linkedplaces', 'Include a details of places that are linked with this one.'),
33     ('hierarchy', 'Include details of places lower in the address hierarchy.'),
34     ('group_hierarchy', 'Group the places by type.'),
35     ('polygon_geojson', 'Include geometry of result.')
36 )
37
38 def _add_api_output_arguments(parser):
39     group = parser.add_argument_group('Output arguments')
40     group.add_argument('--format', default='jsonv2',
41                        choices=['xml', 'json', 'jsonv2', 'geojson', 'geocodejson'],
42                        help='Format of result')
43     for name, desc in EXTRADATA_PARAMS:
44         group.add_argument('--' + name, action='store_true', help=desc)
45
46     group.add_argument('--lang', '--accept-language', metavar='LANGS',
47                        help='Preferred language order for presenting search results')
48     group.add_argument('--polygon-output',
49                        choices=['geojson', 'kml', 'svg', 'text'],
50                        help='Output geometry of results as a GeoJSON, KML, SVG or WKT.')
51     group.add_argument('--polygon-threshold', type=float, metavar='TOLERANCE',
52                        help=("Simplify output geometry."
53                              "Parameter is difference tolerance in degrees."))
54
55
56 class APISearch:
57     """\
58     Execute API search query.
59     """
60
61     @staticmethod
62     def add_args(parser):
63         group = parser.add_argument_group('Query arguments')
64         group.add_argument('--query',
65                            help='Free-form query string')
66         for name, desc in STRUCTURED_QUERY:
67             group.add_argument('--' + name, help='Structured query: ' + desc)
68
69         _add_api_output_arguments(parser)
70
71         group = parser.add_argument_group('Result limitation')
72         group.add_argument('--countrycodes', metavar='CC,..',
73                            help='Limit search results to one or more countries.')
74         group.add_argument('--exclude_place_ids', metavar='ID,..',
75                            help='List of search object to be excluded')
76         group.add_argument('--limit', type=int,
77                            help='Limit the number of returned results')
78         group.add_argument('--viewbox', metavar='X1,Y1,X2,Y2',
79                            help='Preferred area to find search results')
80         group.add_argument('--bounded', action='store_true',
81                            help='Strictly restrict results to viewbox area')
82
83         group = parser.add_argument_group('Other arguments')
84         group.add_argument('--no-dedupe', action='store_false', dest='dedupe',
85                            help='Do not remove duplicates from the result list')
86
87
88     @staticmethod
89     def run(args):
90         if args.query:
91             params = dict(q=args.query)
92         else:
93             params = {k : getattr(args, k) for k, _ in STRUCTURED_QUERY if getattr(args, k)}
94
95         for param, _ in EXTRADATA_PARAMS:
96             if getattr(args, param):
97                 params[param] = '1'
98         for param in ('format', 'countrycodes', 'exclude_place_ids', 'limit', 'viewbox'):
99             if getattr(args, param):
100                 params[param] = getattr(args, param)
101         if args.lang:
102             params['accept-language'] = args.lang
103         if args.polygon_output:
104             params['polygon_' + args.polygon_output] = '1'
105         if args.polygon_threshold:
106             params['polygon_threshold'] = args.polygon_threshold
107         if args.bounded:
108             params['bounded'] = '1'
109         if not args.dedupe:
110             params['dedupe'] = '0'
111
112         return run_api_script('search', args.project_dir,
113                               phpcgi_bin=args.phpcgi_path, params=params)
114
115 class APIReverse:
116     """\
117     Execute API reverse query.
118     """
119
120     @staticmethod
121     def add_args(parser):
122         group = parser.add_argument_group('Query arguments')
123         group.add_argument('--lat', type=float, required=True,
124                            help='Latitude of coordinate to look up (in WGS84)')
125         group.add_argument('--lon', type=float, required=True,
126                            help='Longitude of coordinate to look up (in WGS84)')
127         group.add_argument('--zoom', type=int,
128                            help='Level of detail required for the address')
129
130         _add_api_output_arguments(parser)
131
132
133     @staticmethod
134     def run(args):
135         params = dict(lat=args.lat, lon=args.lon)
136         if args.zoom is not None:
137             params['zoom'] = args.zoom
138
139         for param, _ in EXTRADATA_PARAMS:
140             if getattr(args, param):
141                 params[param] = '1'
142         if args.format:
143             params['format'] = args.format
144         if args.lang:
145             params['accept-language'] = args.lang
146         if args.polygon_output:
147             params['polygon_' + args.polygon_output] = '1'
148         if args.polygon_threshold:
149             params['polygon_threshold'] = args.polygon_threshold
150
151         return run_api_script('reverse', args.project_dir,
152                               phpcgi_bin=args.phpcgi_path, params=params)
153
154
155 class APILookup:
156     """\
157     Execute API lookup query.
158     """
159
160     @staticmethod
161     def add_args(parser):
162         group = parser.add_argument_group('Query arguments')
163         group.add_argument('--id', metavar='OSMID',
164                            action='append', required=True, dest='ids',
165                            help='OSM id to lookup in format <NRW><id> (may be repeated)')
166
167         _add_api_output_arguments(parser)
168
169
170     @staticmethod
171     def run(args):
172         params = dict(osm_ids=','.join(args.ids))
173
174         for param, _ in EXTRADATA_PARAMS:
175             if getattr(args, param):
176                 params[param] = '1'
177         if args.format:
178             params['format'] = args.format
179         if args.lang:
180             params['accept-language'] = args.lang
181         if args.polygon_output:
182             params['polygon_' + args.polygon_output] = '1'
183         if args.polygon_threshold:
184             params['polygon_threshold'] = args.polygon_threshold
185
186         return run_api_script('lookup', args.project_dir,
187                               phpcgi_bin=args.phpcgi_path, params=params)
188
189
190 class APIDetails:
191     """\
192     Execute API details query.
193     """
194
195     @staticmethod
196     def add_args(parser):
197         group = parser.add_argument_group('Query arguments')
198         objs = group.add_mutually_exclusive_group(required=True)
199         objs.add_argument('--node', '-n', type=int,
200                           help="Look up the OSM node with the given ID.")
201         objs.add_argument('--way', '-w', type=int,
202                           help="Look up the OSM way with the given ID.")
203         objs.add_argument('--relation', '-r', type=int,
204                           help="Look up the OSM relation with the given ID.")
205         objs.add_argument('--place_id', '-p', type=int,
206                           help='Database internal identifier of the OSM object to look up.')
207         group.add_argument('--class', dest='object_class',
208                            help=("Class type to disambiguated multiple entries "
209                                  "of the same object."))
210
211         group = parser.add_argument_group('Output arguments')
212         for name, desc in DETAILS_SWITCHES:
213             group.add_argument('--' + name, action='store_true', help=desc)
214         group.add_argument('--lang', '--accept-language', metavar='LANGS',
215                            help='Preferred language order for presenting search results')
216
217     @staticmethod
218     def run(args):
219         if args.node:
220             params = dict(osmtype='N', osmid=args.node)
221         elif args.way:
222             params = dict(osmtype='W', osmid=args.node)
223         elif args.relation:
224             params = dict(osmtype='R', osmid=args.node)
225         else:
226             params = dict(place_id=args.place_id)
227         if args.object_class:
228             params['class'] = args.object_class
229         for name, _ in DETAILS_SWITCHES:
230             params[name] = '1' if getattr(args, name) else '0'
231
232         return run_api_script('details', args.project_dir,
233                               phpcgi_bin=args.phpcgi_path, params=params)
234
235
236 class APIStatus:
237     """\
238     Execute API status query.
239     """
240
241     @staticmethod
242     def add_args(parser):
243         group = parser.add_argument_group('API parameters')
244         group.add_argument('--format', default='text', choices=['text', 'json'],
245                            help='Format of result')
246
247     @staticmethod
248     def run(args):
249         return run_api_script('status', args.project_dir,
250                               phpcgi_bin=args.phpcgi_path,
251                               params=dict(format=args.format))