]> git.openstreetmap.org Git - nominatim.git/commitdiff
Merge pull request #2277 from lonvia/update-osm2pgsql
authorSarah Hoffmann <lonvia@denofr.de>
Fri, 16 Apr 2021 15:40:43 +0000 (17:40 +0200)
committerGitHub <noreply@github.com>
Fri, 16 Apr 2021 15:40:43 +0000 (17:40 +0200)
Update osm2pgsql to current master

27 files changed:
nominatim/cli.py
nominatim/clicmd/__init__.py
nominatim/clicmd/admin.py
nominatim/clicmd/api.py
nominatim/clicmd/freeze.py
nominatim/clicmd/index.py
nominatim/clicmd/refresh.py
nominatim/clicmd/replication.py
nominatim/clicmd/setup.py
nominatim/clicmd/transition.py
nominatim/config.py
nominatim/db/connection.py
nominatim/db/status.py
nominatim/db/utils.py
nominatim/indexer/indexer.py
nominatim/tools/admin.py
nominatim/tools/check_database.py
nominatim/tools/database_import.py
nominatim/tools/exec_utils.py
nominatim/tools/migration.py
nominatim/tools/postcodes.py [new file with mode: 0644]
nominatim/tools/refresh.py
nominatim/tools/replication.py
nominatim/tools/tiger_data.py
test/python/conftest.py
test/python/test_cli.py
test/python/test_tools_postcodes.py [new file with mode: 0644]

index e162d1a65e23a280d11719375a42b93fd421a05e..9235055b3fc1c3918de3c129e159d30225f8c290 100644 (file)
@@ -8,12 +8,12 @@ import sys
 import argparse
 from pathlib import Path
 
-from .config import Configuration
-from .tools.exec_utils import run_legacy_script, run_php_server
-from .errors import UsageError
-from . import clicmd
-from .clicmd.args import NominatimArgs
-from .tools import tiger_data
+from nominatim.config import Configuration
+from nominatim.tools.exec_utils import run_legacy_script, run_php_server
+from nominatim.errors import UsageError
+from nominatim import clicmd
+from nominatim.clicmd.args import NominatimArgs
+from nominatim.tools import tiger_data
 
 LOG = logging.getLogger()
 
index ca64f3635031a449f5f9112a0906ccb70de882ce..9856ad68c70d8745b5ebf351297ac20769be6394 100644 (file)
@@ -2,12 +2,12 @@
 Subcommand definitions for the command-line tool.
 """
 
-from .setup import SetupAll
-from .replication import UpdateReplication
-from .api import APISearch, APIReverse, APILookup, APIDetails, APIStatus
-from .index import UpdateIndex
-from .refresh import UpdateRefresh
-from .admin import AdminFuncs
-from .freeze import SetupFreeze
-from .transition import AdminTransition
-from .special_phrases import ImportSpecialPhrases
+from nominatim.clicmd.setup import SetupAll
+from nominatim.clicmd.replication import UpdateReplication
+from nominatim.clicmd.api import APISearch, APIReverse, APILookup, APIDetails, APIStatus
+from nominatim.clicmd.index import UpdateIndex
+from nominatim.clicmd.refresh import UpdateRefresh
+from nominatim.clicmd.admin import AdminFuncs
+from nominatim.clicmd.freeze import SetupFreeze
+from nominatim.clicmd.transition import AdminTransition
+from nominatim.clicmd.special_phrases import ImportSpecialPhrases
index 03d7ca8a73e8c55a63f9571dca302f2a4bceff0c..e99807727095257a6ad2d538e0b7d087659d11b9 100644 (file)
@@ -3,8 +3,8 @@ Implementation of the 'admin' subcommand.
 """
 import logging
 
-from ..tools.exec_utils import run_legacy_script
-from ..db.connection import connect
+from nominatim.tools.exec_utils import run_legacy_script
+from nominatim.db.connection import connect
 
 # Do not repeat documentation of subcommand classes.
 # pylint: disable=C0111
index c3e869b8aa60441af9b62c7f074f66a885e14ed9..a555695224403fd3b647f9601f5888f78b506bfb 100644 (file)
@@ -3,7 +3,7 @@ Subcommand definitions for API calls from the command line.
 """
 import logging
 
-from ..tools.exec_utils import run_api_script
+from nominatim.tools.exec_utils import run_api_script
 
 # Do not repeat documentation of subcommand classes.
 # pylint: disable=C0111
index 1b311e97f2f7ee1081c4d1706501b9591c08704c..8a6c928e7f3ade5ec8e5c06cfcc089853358d578 100644 (file)
@@ -2,7 +2,7 @@
 Implementation of the 'freeze' subcommand.
 """
 
-from ..db.connection import connect
+from nominatim.db.connection import connect
 
 # Do not repeat documentation of subcommand classes.
 # pylint: disable=C0111
index 0225c5ed41561b35ca257eb622f6804204ac56f6..8fd4f6011251f480a3d37ff2572d979c7b971cb5 100644 (file)
@@ -3,8 +3,8 @@ Implementation of the 'index' subcommand.
 """
 import psutil
 
-from ..db import status
-from ..db.connection import connect
+from nominatim.db import status
+from nominatim.db.connection import connect
 
 # Do not repeat documentation of subcommand classes.
 # pylint: disable=C0111
index 9dca4e42e073db9317ba5d02578a93a9340261b9..6a20834427f3abe7de973b986ff292e7ed3b5ad0 100644 (file)
@@ -4,7 +4,7 @@ Implementation of 'refresh' subcommand.
 import logging
 from pathlib import Path
 
-from ..db.connection import connect
+from nominatim.db.connection import connect
 
 # Do not repeat documentation of subcommand classes.
 # pylint: disable=C0111
index f9c5561a5c53edd099bb0855e9a58562335e3514..f8417bd10faf21cdc9f4ef1cc2f3efc29cd720b3 100644 (file)
@@ -6,9 +6,9 @@ import logging
 import socket
 import time
 
-from ..db import status
-from ..db.connection import connect
-from ..errors import UsageError
+from nominatim.db import status
+from nominatim.db.connection import connect
+from nominatim.errors import UsageError
 
 LOG = logging.getLogger()
 
index 92d0694359e62ab48a58a255143b4733dfd316f6..fe7c8dc18de4ee650e7bbb42824c813f4e2d9753 100644 (file)
@@ -6,11 +6,10 @@ from pathlib import Path
 
 import psutil
 
-from ..tools.exec_utils import run_legacy_script
-from ..db.connection import connect
-from ..db import status, properties
-from ..version import NOMINATIM_VERSION
-from ..errors import UsageError
+from nominatim.db.connection import connect
+from nominatim.db import status, properties
+from nominatim.version import NOMINATIM_VERSION
+from nominatim.errors import UsageError
 
 # Do not repeat documentation of subcommand classes.
 # pylint: disable=C0111
@@ -56,6 +55,7 @@ class SetupAll:
         from ..tools import database_import
         from ..tools import refresh
         from ..indexer.indexer import Indexer
+        from ..tools import postcodes
 
         if args.osm_file and not Path(args.osm_file).is_file():
             LOG.fatal("OSM file '%s' does not exist.", args.osm_file)
@@ -116,8 +116,7 @@ class SetupAll:
                                       args.threads or psutil.cpu_count() or 1)
 
             LOG.warning('Calculate postcodes')
-            run_legacy_script('setup.php', '--calculate-postcodes',
-                              nominatim_env=args, throw_on_fail=not args.ignore_errors)
+            postcodes.import_postcodes(args.config.get_libpq_dsn(), args.project_dir)
 
         if args.continue_at is None or args.continue_at in ('load-data', 'indexing'):
             LOG.warning('Indexing places')
index c9341f496d57efac9fd3527fdfffe3ba73618be1..f4df992c060e2bf760577dfe86d070cbf3891728 100644 (file)
@@ -8,9 +8,9 @@ This module will be removed as soon as the transition phase is over.
 import logging
 from pathlib import Path
 
-from ..db.connection import connect
-from ..db import status
-from ..errors import UsageError
+from nominatim.db.connection import connect
+from nominatim.db import status
+from nominatim.errors import UsageError
 
 # Do not repeat documentation of subcommand classes.
 # pylint: disable=C0111
index a22f90ab247b7b63b11b15068845623afa3aa778..d4645b93b89b08ee0eecab7818f0bc94ce652210 100644 (file)
@@ -7,7 +7,7 @@ from pathlib import Path
 
 from dotenv import dotenv_values
 
-from .errors import UsageError
+from nominatim.errors import UsageError
 
 LOG = logging.getLogger()
 
index 5aa05ced1ceb22cfb0c7e5ab218281ade9d0d18f..ac8d7c858090a725142fc9a3bf8546baf6caac8b 100644 (file)
@@ -9,7 +9,7 @@ import psycopg2
 import psycopg2.extensions
 import psycopg2.extras
 
-from ..errors import UsageError
+from nominatim.errors import UsageError
 
 LOG = logging.getLogger()
 
index 225638f4bef3979f4f0b1fec501b90c120b57bfe..e63a40f9ba67a6ec81ec43003c4ce1984ab6d9e1 100644 (file)
@@ -5,8 +5,8 @@ import datetime as dt
 import logging
 import re
 
-from ..tools.exec_utils import get_url
-from ..errors import UsageError
+from nominatim.tools.exec_utils import get_url
+from nominatim.errors import UsageError
 
 LOG = logging.getLogger()
 
index 0a2e2c067cb1b291a57cd655f9a5cc86f0f71efc..b376940d804af364c049864a07649c897b515f0f 100644 (file)
@@ -5,8 +5,8 @@ import subprocess
 import logging
 import gzip
 
-from .connection import get_pg_env
-from ..errors import UsageError
+from nominatim.db.connection import get_pg_env
+from nominatim.errors import UsageError
 
 LOG = logging.getLogger()
 
index 06c05e1d5a49e32a7e2c44290339d19c1344b548..4f4de2189e57dfde2c5cce5e7ec4274170f4d5b2 100644 (file)
@@ -7,8 +7,8 @@ import select
 
 import psycopg2
 
-from .progress import ProgressLogger
-from ..db.async_connection import DBConnection
+from nominatim.indexer.progress import ProgressLogger
+from nominatim.db.async_connection import DBConnection
 
 LOG = logging.getLogger()
 
index 119adf37170c38d0e9f9f043e7c1ffadc91d12bf..2e18cb6f854b2c06698d225f377bcbbc5982e241 100644 (file)
@@ -3,7 +3,7 @@ Functions for database analysis and maintenance.
 """
 import logging
 
-from ..errors import UsageError
+from nominatim.errors import UsageError
 
 LOG = logging.getLogger()
 
index 5b39085d76f72bc52c31677fa191f8f6b0ace673..265f8666adf65e24657c68760ced7888d289e5af 100644 (file)
@@ -6,8 +6,8 @@ from textwrap import dedent
 
 import psycopg2
 
-from ..db.connection import connect
-from ..errors import UsageError
+from nominatim.db.connection import connect
+from nominatim.errors import UsageError
 
 CHECKLIST = []
 
index 433cd8afaca30372ab58698821fee06092748b1a..964bc7026cff88dcab26b006331ef3515b2621d4 100644 (file)
@@ -11,13 +11,13 @@ from pathlib import Path
 import psutil
 import psycopg2
 
-from ..db.connection import connect, get_pg_env
-from ..db import utils as db_utils
-from ..db.async_connection import DBConnection
-from ..db.sql_preprocessor import SQLPreprocessor
-from .exec_utils import run_osm2pgsql
-from ..errors import UsageError
-from ..version import POSTGRESQL_REQUIRED_VERSION, POSTGIS_REQUIRED_VERSION
+from nominatim.db.connection import connect, get_pg_env
+from nominatim.db import utils as db_utils
+from nominatim.db.async_connection import DBConnection
+from nominatim.db.sql_preprocessor import SQLPreprocessor
+from nominatim.tools.exec_utils import run_osm2pgsql
+from nominatim.errors import UsageError
+from nominatim.version import POSTGRESQL_REQUIRED_VERSION, POSTGIS_REQUIRED_VERSION
 
 LOG = logging.getLogger()
 
index e6b9d8d4d15f032cfc1bdf3312f764546b6960f7..96679d279472fd49d568b7ce41fdfeeebde1a206 100644 (file)
@@ -6,8 +6,8 @@ import subprocess
 import urllib.request as urlrequest
 from urllib.parse import urlencode
 
-from ..version import NOMINATIM_VERSION
-from ..db.connection import get_pg_env
+from nominatim.version import NOMINATIM_VERSION
+from nominatim.db.connection import get_pg_env
 
 LOG = logging.getLogger()
 
index 5484834182d876f540eb919b605abff458bbabc0..07fd2ec509d0c552a04789ecfe9a31e01bd39d64 100644 (file)
@@ -3,11 +3,11 @@ Functions for database migration to newer software versions.
 """
 import logging
 
-from ..db import properties
-from ..db.connection import connect
-from ..version import NOMINATIM_VERSION
-from . import refresh, database_import
-from ..errors import UsageError
+from nominatim.db import properties
+from nominatim.db.connection import connect
+from nominatim.version import NOMINATIM_VERSION
+from nominatim.tools import refresh, database_import
+from nominatim.errors import UsageError
 
 LOG = logging.getLogger()
 
diff --git a/nominatim/tools/postcodes.py b/nominatim/tools/postcodes.py
new file mode 100644 (file)
index 0000000..0a568cb
--- /dev/null
@@ -0,0 +1,80 @@
+"""
+Functions for importing, updating and otherwise maintaining the table
+of artificial postcode centroids.
+"""
+
+from nominatim.db.utils import execute_file
+from nominatim.db.connection import connect
+
+def import_postcodes(dsn, project_dir):
+    """ Set up the initial list of postcodes.
+    """
+
+    with connect(dsn) as conn:
+        conn.drop_table('gb_postcode')
+        conn.drop_table('us_postcode')
+
+        with conn.cursor() as cur:
+            cur.execute("""CREATE TABLE gb_postcode (
+                            id integer,
+                            postcode character varying(9),
+                            geometry GEOMETRY(Point, 4326))""")
+
+        with conn.cursor() as cur:
+            cur.execute("""CREATE TABLE us_postcode (
+                            postcode text,
+                            x double precision,
+                            y double precision)""")
+        conn.commit()
+
+        gb_postcodes = project_dir / 'gb_postcode_data.sql.gz'
+        if gb_postcodes.is_file():
+            execute_file(dsn, gb_postcodes)
+
+        us_postcodes = project_dir / 'us_postcode_data.sql.gz'
+        if us_postcodes.is_file():
+            execute_file(dsn, us_postcodes)
+
+        with conn.cursor() as cur:
+            cur.execute("TRUNCATE location_postcode")
+            cur.execute("""
+                INSERT INTO location_postcode
+                 (place_id, indexed_status, country_code, postcode, geometry)
+                SELECT nextval('seq_place'), 1, country_code,
+                       upper(trim (both ' ' from address->'postcode')) as pc,
+                       ST_Centroid(ST_Collect(ST_Centroid(geometry)))
+                  FROM placex
+                 WHERE address ? 'postcode' AND address->'postcode' NOT SIMILAR TO '%(,|;)%'
+                       AND geometry IS NOT null
+                 GROUP BY country_code, pc
+            """)
+
+            cur.execute("""
+                INSERT INTO location_postcode
+                 (place_id, indexed_status, country_code, postcode, geometry)
+                SELECT nextval('seq_place'), 1, 'us', postcode,
+                       ST_SetSRID(ST_Point(x,y),4326)
+                  FROM us_postcode WHERE postcode NOT IN
+                        (SELECT postcode FROM location_postcode
+                          WHERE country_code = 'us')
+            """)
+
+            cur.execute("""
+                INSERT INTO location_postcode
+                 (place_id, indexed_status, country_code, postcode, geometry)
+                SELECT nextval('seq_place'), 1, 'gb', postcode, geometry
+                  FROM gb_postcode WHERE postcode NOT IN
+                           (SELECT postcode FROM location_postcode
+                             WHERE country_code = 'gb')
+            """)
+
+            cur.execute("""
+                    DELETE FROM word WHERE class='place' and type='postcode'
+                    and word NOT IN (SELECT postcode FROM location_postcode)
+            """)
+
+            cur.execute("""
+                SELECT count(getorcreate_postcode_id(v)) FROM
+                (SELECT distinct(postcode) as v FROM location_postcode) p
+            """)
+        conn.commit()
index 581c69e8a110875406dfc76cf4a0f245ef0e3d9a..77eecf0457119c5d338af71c160659beca9f9a44 100644 (file)
@@ -7,9 +7,9 @@ from textwrap import dedent
 
 from psycopg2.extras import execute_values
 
-from ..db.utils import execute_file
-from ..db.sql_preprocessor import SQLPreprocessor
-from ..version import NOMINATIM_VERSION
+from nominatim.db.utils import execute_file
+from nominatim.db.sql_preprocessor import SQLPreprocessor
+from nominatim.version import NOMINATIM_VERSION
 
 LOG = logging.getLogger()
 
index a0a741e8ff4ae87155ff38853784d1af41b66ce3..d6e8089161bc96cc71f1119b8252e3046af654b3 100644 (file)
@@ -6,9 +6,9 @@ from enum import Enum
 import logging
 import time
 
-from ..db import status
-from .exec_utils import run_osm2pgsql
-from ..errors import UsageError
+from nominatim.db import status
+from nominatim.tools.exec_utils import run_osm2pgsql
+from nominatim.errors import UsageError
 
 try:
     from osmium.replication.server import ReplicationServer
index c655f91d73bf096f0af4fcf7cbc7ce75c4415bd0..c1de3615f7f953a65984b2bf0d644552b4d30cf0 100644 (file)
@@ -6,9 +6,9 @@ import os
 import tarfile
 import selectors
 
-from ..db.connection import connect
-from ..db.async_connection import DBConnection
-from ..db.sql_preprocessor import SQLPreprocessor
+from nominatim.db.connection import connect
+from nominatim.db.async_connection import DBConnection
+from nominatim.db.sql_preprocessor import SQLPreprocessor
 
 
 LOG = logging.getLogger()
index 871365d90214f0515365179644d6ffe69e8a0100..0d1cd2f37168f8446182d030d2e26e4427922ead 100644 (file)
@@ -33,8 +33,6 @@ class _TestingCursor(psycopg2.extras.DictCursor):
         """ Execute a query and return the result as a set of tuples.
         """
         self.execute(sql, params)
-        if self.rowcount == 1:
-            return set(tuple(self.fetchone()))
 
         return set((tuple(row) for row in self))
 
index eb0ee58487b5917112824ad4b0ce2940d5d21f3a..38bbaefee82688bbad8194ee5623884222af6b03 100644 (file)
@@ -21,6 +21,7 @@ import nominatim.tools.check_database
 import nominatim.tools.database_import
 import nominatim.tools.freeze
 import nominatim.tools.refresh
+import nominatim.tools.postcodes
 
 from mocks import MockParamCapture
 
@@ -96,13 +97,13 @@ def test_import_full(temp_db, mock_func_factory):
         mock_func_factory(nominatim.tools.database_import, 'create_search_indices'),
         mock_func_factory(nominatim.tools.database_import, 'create_country_names'),
         mock_func_factory(nominatim.tools.refresh, 'load_address_levels_from_file'),
+        mock_func_factory(nominatim.tools.postcodes, 'import_postcodes'),
         mock_func_factory(nominatim.indexer.indexer.Indexer, 'index_full'),
         mock_func_factory(nominatim.tools.refresh, 'setup_website'),
         mock_func_factory(nominatim.db.properties, 'set_property')
     ]
 
     cf_mock = mock_func_factory(nominatim.tools.refresh, 'create_functions')
-    mock_func_factory(nominatim.clicmd.setup, 'run_legacy_script')
 
     assert 0 == call_nominatim('import', '--osm-file', __file__)
 
diff --git a/test/python/test_tools_postcodes.py b/test/python/test_tools_postcodes.py
new file mode 100644 (file)
index 0000000..1fc060b
--- /dev/null
@@ -0,0 +1,50 @@
+"""
+Tests for functions to maintain the artificial postcode table.
+"""
+
+import pytest
+
+from nominatim.tools import postcodes
+
+@pytest.fixture
+def postcode_table(temp_db_with_extensions, temp_db_cursor, table_factory,
+                   placex_table, word_table):
+    table_factory('location_postcode',
+                  """ place_id BIGINT,
+                      parent_place_id BIGINT,
+                      rank_search SMALLINT,
+                      rank_address SMALLINT,
+                      indexed_status SMALLINT,
+                      indexed_date TIMESTAMP,
+                      country_code varchar(2),
+                      postcode TEXT,
+                      geometry GEOMETRY(Geometry, 4326)""")
+    temp_db_cursor.execute('CREATE SEQUENCE seq_place')
+    temp_db_cursor.execute("""CREATE OR REPLACE FUNCTION getorcreate_postcode_id(postcode TEXT)
+                              RETURNS INTEGER AS $$ BEGIN RETURN 1; END; $$ LANGUAGE plpgsql;
+                           """)
+
+
+def test_import_postcodes_empty(dsn, temp_db_cursor, postcode_table, tmp_path):
+    postcodes.import_postcodes(dsn, tmp_path)
+
+    assert temp_db_cursor.table_exists('gb_postcode')
+    assert temp_db_cursor.table_exists('us_postcode')
+    assert temp_db_cursor.table_rows('location_postcode') == 0
+
+
+def test_import_postcodes_from_placex(dsn, temp_db_cursor, postcode_table, tmp_path):
+    temp_db_cursor.execute("""
+        INSERT INTO placex (place_id, country_code, address, geometry)
+          VALUES (1, 'xx', '"postcode"=>"9486"', 'SRID=4326;POINT(10 12)')
+    """)
+
+    postcodes.import_postcodes(dsn, tmp_path)
+
+    rows = temp_db_cursor.row_set(""" SELECT postcode, country_code,
+                                      ST_X(geometry), ST_Y(geometry)
+                                      FROM location_postcode""")
+    print(rows)
+    assert len(rows) == 1
+    assert rows == set((('9486', 'xx', 10, 12), ))
+