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 compute the display name for each Address Line
 
 272 component based on its `local_name` field. This is then utilized by the overall `result` object,
 
 273 which has a helper function to apply the function to all its ‘address_row’ members and saves
 
 274 the result in the `locale_name` field. 
 
 276 However, in order to set this `local_name` field in a preferred language, you must use the `Locale`
 
 277 object which contains the function `localize_results`, which explicitly sets each `local_name field`.
 
 280 >>> Locales().localize_results(results)
 
 281 >>> address_parts = results[0].address_rows
 
 282 >>> print(', '.join(address_parts))
 
 283 Bruges, Flandre-Occidentale, Flandre, Belgique
 
 286 This is a fairly simple way to create a human-readable description. The
 
 287 place information in `address_rows` contains further information about each
 
 288 place. For example, which OSM `admin_level` was used, what category the place
 
 289 belongs to or what rank Nominatim has assigned. Use this to adapt the output
 
 290 to local address formats.
 
 292 For more information on address rows, see
 
 293 [detailed address description](Result-Handling.md#detailed-address-description).