From ef1b52eee517d826c7c0e664f9a539b8ceffaaf6 Mon Sep 17 00:00:00 2001 From: Sarah Hoffmann Date: Sun, 27 Aug 2023 14:42:04 +0200 Subject: [PATCH] add getting started section for library docs --- docs/extra.css | 5 + docs/library/Getting-Started.md | 222 +++++++++++++++++++++++++++----- docs/library/NominatimAPI.md | 2 - docs/mkdocs.yml | 1 + 4 files changed, 199 insertions(+), 31 deletions(-) diff --git a/docs/extra.css b/docs/extra.css index 2151b066..155fa1aa 100644 --- a/docs/extra.css +++ b/docs/extra.css @@ -29,3 +29,8 @@ th { .doc-children .doc-contents { margin-left: 3em; +} + +.md-footer__inner { + display: none; +} diff --git a/docs/library/Getting-Started.md b/docs/library/Getting-Started.md index a013f40c..77724e67 100644 --- a/docs/library/Getting-Started.md +++ b/docs/library/Getting-Started.md @@ -34,52 +34,216 @@ You can also point the PYTHONPATH to the Nominatim source code. To query the Nominatim database you need to first set up a connection. This is done by creating an Nominatim API object. This object exposes all the -search functions of Nominatim that are also knwon from its web API. +search functions of Nominatim that are also known from its web API. This code snippet implements a simple search for the town if 'Brugge': -=== "NominatimAPIAsync" - ``` - from pathlib import Path - import asyncio +!!! example + === "NominatimAPIAsync" + ``` python + from pathlib import Path + import asyncio - import nominatim.api as napi + import nominatim.api as napi - async def search(query): - api = napi.NominatimAPIAsync(Path('.')) + async def search(query): + api = napi.NominatimAPIAsync(Path('.')) - return await api.search(query) + return await api.search(query) - results = asyncio.run(search('Brugge')) - if not results: - print('Cannot find Brugge') - else: - print(f'Found a place at {results[0].centroid.x},{results[1].centroid.y}') - ``` + results = asyncio.run(search('Brugge')) + if not results: + print('Cannot find Brugge') + else: + print(f'Found a place at {results[0].centroid.x},{results[1].centroid.y}') + ``` -=== "NominatimAPI" - ``` - from pathlib import Path + === "NominatimAPI" + ``` python + from pathlib import Path - import nominatim.api as napi + import nominatim.api as napi - api = napi.NominatimAPI(Path('.')) + api = napi.NominatimAPI(Path('.')) - results = api.search('Brugge') + results = api.search('Brugge') - if not results: - print('Cannot find Brugge') - else: - print(f'Found a place at {results[0].centroid.x},{results[1].centroid.y}') - ``` + if not results: + print('Cannot find Brugge') + else: + print(f'Found a place at {results[0].centroid.x},{results[1].centroid.y}') + ``` -The Nonminatim API comes in two flavours: synchronous and asynchronous. -The complete Nominatim library is written so that it can work asynchronously. +The Nominatim library is designed around +[asyncio](https://docs.python.org/3/library/asyncio.html). `NominatimAPIAsync` +provides you with an interface of coroutines. If you have many requests to make, coroutines can speed up your applications significantly. -For smaller scripts there is also a sychronous wrapper around the API. +For smaller scripts there is also a synchronous wrapper around the API. By +using `NominatimAPI`, you get exactly the same interface using classic functions. + +The examples in this chapter will always show how work with both of the +implementations. The documentation itself will refer usually only to +'Nominatim API class' when both flavours are meant. If a functionality is +available only for the synchronous or asynchronous version, this will be +explicitly mentioned. ### Defining which database to use +The [Configuration](../admin/Import.md#configuration-setup-in-env) +section explains how Nominatim is configured using the +[dotenv](https://github.com/theskumar/python-dotenv) library. +The same configuration mechanism is used with the +Nominatim API library. You should therefore be sure you are familiar with +the section. + +The constructor of the 'Nominatim API class' takes one mandatory parameter: +the path to the [project directory](../admin/Import.md#creating-the-project-directory). +You should have set up this directory as part of the Nominatim import. +Any configuration found in the `.env` file in this directory will automatically +used. + +The second way to configure your Nominatim setup is through environment variables. +Normally, Nominatim will check the operating system environment. This can be +overwritten by giving the constructor a dictionary of configuration parameters. + +Let us look up 'Brugge' in the special database named 'belgium' instead of the +standard 'nominatim' database: + +!!! example + === "NominatimAPIAsync" + ``` python + from pathlib import Path + import asyncio + + import nominatim.api as napi + + config_params = { + 'NOMINATIM_DATABASE_DSN': 'pgsql:dbname=belgium' + } + + async def search(query): + api = napi.NominatimAPIAsync(Path('.'), environ=config_params) + + return await api.search(query) + + results = asyncio.run(search('Brugge')) + ``` + + === "NominatimAPI" + ``` python + from pathlib import Path + + import nominatim.api as napi + + config_params = { + 'NOMINATIM_DATABASE_DSN': 'pgsql:dbname=belgium' + } + + api = napi.NominatimAPI(Path('.'), environ=config_params) + + results = api.search('Brugge') + ``` + +### Presenting results to humans + +All search functions return the raw results from the database. There is no +full human-readable label. To create such a label, you need two things: + +* the address details of the place +* adapt the result to the language you wish to use for display + +Again searching for 'Brugge', this time with a nicely formatted result: + +!!! example + === "NominatimAPIAsync" + ``` python + from pathlib import Path + import asyncio + + import nominatim.api as napi + + async def search(query): + api = napi.NominatimAPIAsync(Path('.')) + + return await api.search(query, address_details=True) + + results = asyncio.run(search('Brugge')) + + locale = napi.Locales(['fr', 'en']) + for i, result in enumerate(results): + address_parts = result.address_rows.localize(locale) + print(f"{i + 1}. {', '.join(address_parts)}") + ``` + + === "NominatimAPI" + ``` python + from pathlib import Path + + import nominatim.api as napi + + api = napi.NominatimAPI(Path('.')) + + results = api.search('Brugge', address_details=True) + + locale = napi.Locales(['fr', 'en']) + for i, result in enumerate(results): + address_parts = result.address_rows.localize(locale) + print(f"{i + 1}. {', '.join(address_parts)}") + ``` + +To request information about the address of a result, add the optional +parameter 'address_details' to your search: + +``` python +>>> results = api.search('Brugge', address_details=True) +``` + +An additional field `address_rows` will set in results that are returned. +It contains a list of all places that make up the address of the place. For +simplicity, this includes name and house number of the place itself. With +the names in this list it is possible to create a human-readable description +of the result. To do that, you first need to decide in which language the +results should be presented. As with the names in the result itself, the +places in `address_rows` contain all possible name translation for each row. + +The library has a helper class `Locale` which helps extracting a name of a +place in the preferred language. It gets a list of language code in the +order of preference. So + +``` python +locale = napi.Locale(['fr', 'en']) +``` + +creates a helper class that returns the name preferably in French. If that is +not possible, it tries English and eventually falls back to the default `name` +or `ref`. + +The Locale object can be applied to a name dictionary to return the best-matching +name out of it: + +``` python +>>> print(locale.display_name(results[0].names)) +'Brugges' +``` + +The `address_row` field has a helper function to apply the function to all +its members and save the result in the `local_name` field. It also returns +all the localized names as a convenient simple list. This list can be used +to create a human-readable output: + +``` python +>>> address_parts = results[0].address_rows.localize(locale) +>>> print(', '.join(address_parts)) +Bruges, Flandre-Occidentale, Flandre, Belgique +``` + +This is a fairly simple way to create a human-readable description. The +place information in `address_rows` contains further information about each +place. For example, which OSM `adlin_level` was used, what category the place +belongs to or what rank Nominatim has assigned. Use this to adapt the output +to local address formats. +For more information on address rows, see +[detailed address description](Result-Handling.md#detailed-address-description). diff --git a/docs/library/NominatimAPI.md b/docs/library/NominatimAPI.md index a5481a19..0fa9d659 100644 --- a/docs/library/NominatimAPI.md +++ b/docs/library/NominatimAPI.md @@ -21,7 +21,6 @@ to instantiate a separate instance for each thread. - search_category heading_level: 6 group_by_category: False - show_signature_annotations: True ### NominatimAPIAsync @@ -35,4 +34,3 @@ to instantiate a separate instance for each thread. - begin heading_level: 6 group_by_category: False - show_signature_annotations: True diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index 8a9d6e7d..df68cda8 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -3,6 +3,7 @@ theme: name: material features: - navigation.tabs +copyright: Copyright © 2023 Nominatim developer community docs_dir: ${CMAKE_CURRENT_BINARY_DIR} site_url: https://nominatim.org repo_url: https://github.com/openstreetmap/Nominatim -- 2.39.5