3 The Nominatim search frontend is implemented as a Python library and can as
4 such directly be used in Python scripts and applications. You don't need to
5 set up a web frontend and access it through HTTP calls. The library gives
6 direct access to the Nominatim database through similar search functions as
7 offered by the web API. In addition, it will give you a more complete and
8 detailed view on the search objects stored in the database.
12 The Nominatim library is used for accessing a local Nominatim database.
13 It is not meant to be used against web services of Nominatim like the
14 one on https://nominatim.openstreetmap.org. If you need a Python library
15 to access these web services, have a look at
16 [GeoPy](https://geopy.readthedocs.io). Don't forget to consult the
17 usage policy of the service you want to use before accessing such
22 To use the Nominatim library, you need access to a local Nominatim database.
23 Follow the [installation](../admin/Installation.md) and
24 [import](../admin/Import.md) instructions to set up your database.
26 The Nominatim frontend library is contained in the Python package `nominatim-api`.
27 You can install the latest released version directly from pip:
29 pip install nominatim-api
31 To install the package from the source tree directly, run:
33 pip install packaging/nominatim-api
35 Usually you would want to run this in a virtual environment.
37 ## A simple search example
39 To query the Nominatim database you need to first set up a connection. This
40 is done by creating an Nominatim API object. This object exposes all the
41 search functions of Nominatim that are also known from its web API.
43 This code snippet implements a simple search for the town of 'Brugge':
46 === "NominatimAPIAsync"
50 import nominatim_api as napi
52 async def search(query):
53 async with napi.NominatimAPIAsync() as api:
54 return await api.search(query)
56 results = asyncio.run(search('Brugge'))
58 print('Cannot find Brugge')
60 print(f'Found a place at {results[0].centroid.x},{results[0].centroid.y}')
65 import nominatim_api as napi
67 with napi.NominatimAPI() as api:
68 results = api.search('Brugge')
71 print('Cannot find Brugge')
73 print(f'Found a place at {results[0].centroid.x},{results[0].centroid.y}')
76 The Nominatim library is designed around
77 [asyncio](https://docs.python.org/3/library/asyncio.html). `NominatimAPIAsync`
78 provides you with an interface of coroutines.
79 If you have many requests to make, coroutines can speed up your applications
82 For smaller scripts there is also a synchronous wrapper around the API. By
83 using `NominatimAPI`, you get exactly the same interface using classic functions.
85 The examples in this chapter will always show-case both
86 implementations. The documentation itself will usually refer only to
87 'Nominatim API class' when both flavours are meant. If a functionality is
88 available only for the synchronous or asynchronous version, this will be
91 ## Defining which database to use
93 The [Configuration](../admin/Import.md#configuration-setup-in-env)
94 section explains how Nominatim is configured using the
95 [dotenv](https://github.com/theskumar/python-dotenv) library.
96 The same configuration mechanism is used with the
97 Nominatim API library. You should therefore be sure you are familiar with
100 There are three different ways, how configuration options can be set for
101 a 'Nominatim API class'. When you have set up your Nominatim database, you
102 have normally created a [project directory](../admin/Import.md#creating-the-project-directory)
103 which stores the various configuration and customization files that Nominatim
104 needs. You may pass the location of the project directory to your
105 'Nominatim API class' constructor and it will read the .env file in the
106 directory and set the configuration accordingly. Here is the simple search
107 example, using the configuration from a pre-defined project directory in
108 `/srv/nominatim-project`:
111 === "NominatimAPIAsync"
115 import nominatim_api as napi
117 async def search(query):
118 async with napi.NominatimAPIAsync('/srv/nominatim-project') as api:
119 return await api.search(query)
121 results = asyncio.run(search('Brugge'))
123 print('Cannot find Brugge')
125 print(f'Found a place at {results[0].centroid.x},{results[0].centroid.y}')
130 import nominatim_api as napi
132 with napi.NominatimAPI('/srv/nominatim-project') as api:
133 results = api.search('Brugge')
136 print('Cannot find Brugge')
138 print(f'Found a place at {results[0].centroid.x},{results[0].centroid.y}')
142 You may also configure Nominatim by setting environment variables.
143 Normally Nominatim will check the operating system environment. Lets
144 say you want to look up 'Brugge' in the special database named 'belgium' instead of the
145 standard 'nominatim' database. You can run the example script above like this:
148 NOMINATIM_DATABASE_DSN=pgsql:dbname=belgium python3 example.py
151 The third option to configure the library is to hand in the configuration
152 parameters into the 'Nominatim API class'. Changing the database would look
156 === "NominatimAPIAsync"
159 import nominatim_api as napi
162 'NOMINATIM_DATABASE_DSN': 'pgsql:dbname=belgium'
165 async def search(query):
166 async with napi.NominatimAPIAsync(environ=config_params) as api:
167 return await api.search(query)
169 results = asyncio.run(search('Brugge'))
174 import nominatim_api as napi
177 'NOMINATIM_DATABASE_DSN': 'pgsql:dbname=belgium'
180 with napi.NominatimAPI(environ=config_params) as api:
181 results = api.search('Brugge')
184 When the `environ` parameter is given, then only configuration variables
185 from this dictionary will be used. The operating system's environment
186 variables will be ignored.
188 ## Presenting results to humans
190 All search functions return full result objects from the database. Such a
191 result object contains lots of details: names, address information, OSM tags etc.
192 This gives you lots of flexibility what to do with the results.
194 One of the most common things to get is some kind of human-readable label
195 that describes the result in a compact form. Usually this would be the name
196 of the object and some parts of the address to explain where in the world
197 it is. To create such a label, you need two things:
199 * the address details of the place
200 * all names for the label adapted to the language you wish to use for display
202 Again searching for 'Brugge', this time with a nicely formatted result:
205 === "NominatimAPIAsync"
209 import nominatim_api as napi
211 async def search(query):
212 async with napi.NominatimAPIAsync() as api:
213 return await api.search(query, address_details=True)
215 results = asyncio.run(search('Brugge'))
217 locale = napi.Locales(['fr', 'en'])
218 for i, result in enumerate(results):
219 address_parts = result.address_rows.localize(locale)
220 print(f"{i + 1}. {', '.join(address_parts)}")
225 import nominatim_api as napi
227 with napi.NominatimAPI() as api:
228 results = api.search('Brugge', address_details=True)
230 locale = napi.Locales(['fr', 'en'])
231 for i, result in enumerate(results):
232 address_parts = result.address_rows.localize(locale)
233 print(f"{i + 1}. {', '.join(address_parts)}")
236 To request information about the address of a result, add the optional
237 parameter 'address_details' to your search:
240 >>> results = api.search('Brugge', address_details=True)
243 An additional field `address_rows` will set in results that are returned.
244 It contains a list of all places that make up the address of the place. For
245 simplicity, this includes name and house number of the place itself. With
246 the names in this list it is possible to create a human-readable description
247 of the result. To do that, you first need to decide in which language the
248 results should be presented. As with the names in the result itself, the
249 places in `address_rows` contain all possible name translation for each row.
251 The library has a helper class `Locale` which helps extracting a name of a
252 place in the preferred language. It takes a single parameter with a list
253 of language codes in the order of preference. So
256 locale = napi.Locale(['fr', 'en'])
259 creates a helper class that returns the name preferably in French. If that is
260 not possible, it tries English and eventually falls back to the default `name`
263 The `Locale` object can be applied to a name dictionary to return the best-matching
267 >>> print(locale.display_name(results[0].names))
271 The `address_row` field has a helper function to apply the function to all
272 its members and save the result in the `local_name` field. It also returns
273 all the localized names as a convenient simple list. This list can be used
274 to create a human-readable output:
277 >>> address_parts = results[0].address_rows.localize(locale)
278 >>> print(', '.join(address_parts))
279 Bruges, Flandre-Occidentale, Flandre, Belgique
282 This is a fairly simple way to create a human-readable description. The
283 place information in `address_rows` contains further information about each
284 place. For example, which OSM `admin_level` was used, what category the place
285 belongs to or what rank Nominatim has assigned. Use this to adapt the output
286 to local address formats.
288 For more information on address rows, see
289 [detailed address description](Result-Handling.md#detailed-address-description).