mirror of
https://github.com/osm-search/Nominatim.git
synced 2024-11-22 21:28:10 +03:00
convert version to named tuple
Also return the new NominatimVersion rather than a string in the status result.
This commit is contained in:
parent
93b9288c30
commit
0c47558729
@ -23,10 +23,9 @@ class StatusResult:
|
|||||||
def __init__(self, status: int, msg: str):
|
def __init__(self, status: int, msg: str):
|
||||||
self.status = status
|
self.status = status
|
||||||
self.message = msg
|
self.message = msg
|
||||||
# XXX versions really should stay tuples here
|
self.software_version = version.NOMINATIM_VERSION
|
||||||
self.software_version = version.version_str()
|
|
||||||
self.data_updated: Optional[dt.datetime] = None
|
self.data_updated: Optional[dt.datetime] = None
|
||||||
self.database_version: Optional[str] = None
|
self.database_version: Optional[version.NominatimVersion] = None
|
||||||
|
|
||||||
|
|
||||||
async def _get_database_date(conn: AsyncConnection) -> Optional[dt.datetime]:
|
async def _get_database_date(conn: AsyncConnection) -> Optional[dt.datetime]:
|
||||||
@ -41,13 +40,13 @@ async def _get_database_date(conn: AsyncConnection) -> Optional[dt.datetime]:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
async def _get_database_version(conn: AsyncConnection) -> Optional[str]:
|
async def _get_database_version(conn: AsyncConnection) -> Optional[version.NominatimVersion]:
|
||||||
sql = sqla.text("""SELECT value FROM nominatim_properties
|
sql = sqla.text("""SELECT value FROM nominatim_properties
|
||||||
WHERE property = 'database_version'""")
|
WHERE property = 'database_version'""")
|
||||||
result = await conn.execute(sql)
|
result = await conn.execute(sql)
|
||||||
|
|
||||||
for row in result:
|
for row in result:
|
||||||
return cast(str, row[0])
|
return version.parse_version(cast(str, row[0]))
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ class CommandlineParser:
|
|||||||
def nominatim_version_text(self) -> str:
|
def nominatim_version_text(self) -> str:
|
||||||
""" Program name and version number as string
|
""" Program name and version number as string
|
||||||
"""
|
"""
|
||||||
text = f'Nominatim version {version.version_str()}'
|
text = f'Nominatim version {version.NOMINATIM_VERSION!s}'
|
||||||
if version.GIT_COMMIT_HASH is not None:
|
if version.GIT_COMMIT_HASH is not None:
|
||||||
text += f' ({version.GIT_COMMIT_HASH})'
|
text += f' ({version.GIT_COMMIT_HASH})'
|
||||||
return text
|
return text
|
||||||
|
@ -18,7 +18,7 @@ from nominatim.config import Configuration
|
|||||||
from nominatim.db.connection import connect
|
from nominatim.db.connection import connect
|
||||||
from nominatim.db import status, properties
|
from nominatim.db import status, properties
|
||||||
from nominatim.tokenizer.base import AbstractTokenizer
|
from nominatim.tokenizer.base import AbstractTokenizer
|
||||||
from nominatim.version import version_str
|
from nominatim.version import NOMINATIM_VERSION
|
||||||
from nominatim.clicmd.args import NominatimArgs
|
from nominatim.clicmd.args import NominatimArgs
|
||||||
from nominatim.errors import UsageError
|
from nominatim.errors import UsageError
|
||||||
|
|
||||||
@ -205,4 +205,4 @@ class SetupAll:
|
|||||||
except Exception as exc: # pylint: disable=broad-except
|
except Exception as exc: # pylint: disable=broad-except
|
||||||
LOG.error('Cannot determine date of database: %s', exc)
|
LOG.error('Cannot determine date of database: %s', exc)
|
||||||
|
|
||||||
properties.set_property(conn, 'database_version', version_str())
|
properties.set_property(conn, 'database_version', str(NOMINATIM_VERSION))
|
||||||
|
@ -26,14 +26,13 @@ def _format_status_text(result: StatusResult) -> str:
|
|||||||
|
|
||||||
@create.format_func(StatusResult, 'json')
|
@create.format_func(StatusResult, 'json')
|
||||||
def _format_status_json(result: StatusResult) -> str:
|
def _format_status_json(result: StatusResult) -> str:
|
||||||
# XXX write a simple JSON serializer
|
|
||||||
out: Dict[str, Any] = OrderedDict()
|
out: Dict[str, Any] = OrderedDict()
|
||||||
out['status'] = result.status
|
out['status'] = result.status
|
||||||
out['message'] = result.message
|
out['message'] = result.message
|
||||||
if result.data_updated is not None:
|
if result.data_updated is not None:
|
||||||
out['data_updated'] = result.data_updated.isoformat()
|
out['data_updated'] = result.data_updated.isoformat()
|
||||||
out['software_version'] = result.software_version
|
out['software_version'] = str(result.software_version)
|
||||||
if result.database_version is not None:
|
if result.database_version is not None:
|
||||||
out['database_version'] = result.database_version
|
out['database_version'] = str(result.database_version)
|
||||||
|
|
||||||
return json.dumps(out)
|
return json.dumps(out)
|
||||||
|
@ -20,7 +20,7 @@ from psycopg2.extensions import make_dsn, parse_dsn
|
|||||||
from nominatim.config import Configuration
|
from nominatim.config import Configuration
|
||||||
from nominatim.db.connection import connect
|
from nominatim.db.connection import connect
|
||||||
from nominatim.typing import DictCursorResults
|
from nominatim.typing import DictCursorResults
|
||||||
from nominatim.version import version_str
|
from nominatim.version import NOMINATIM_VERSION
|
||||||
|
|
||||||
|
|
||||||
def convert_version(ver_tup: Tuple[int, int]) -> str:
|
def convert_version(ver_tup: Tuple[int, int]) -> str:
|
||||||
@ -135,8 +135,8 @@ def report_system_information(config: Configuration) -> None:
|
|||||||
|
|
||||||
**Software Environment:**
|
**Software Environment:**
|
||||||
- Python version: {sys.version}
|
- Python version: {sys.version}
|
||||||
- Nominatim version: {version_str()}
|
- Nominatim version: {NOMINATIM_VERSION!s}
|
||||||
- PostgreSQL version: {postgresql_ver}
|
- PostgreSQL version: {postgresql_ver}
|
||||||
- PostGIS version: {postgis_ver}
|
- PostGIS version: {postgis_ver}
|
||||||
- OS: {os_name_info()}
|
- OS: {os_name_info()}
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ from urllib.parse import urlencode
|
|||||||
|
|
||||||
from nominatim.config import Configuration
|
from nominatim.config import Configuration
|
||||||
from nominatim.typing import StrPath
|
from nominatim.typing import StrPath
|
||||||
from nominatim.version import version_str
|
from nominatim.version import NOMINATIM_VERSION
|
||||||
from nominatim.db.connection import get_pg_env
|
from nominatim.db.connection import get_pg_env
|
||||||
|
|
||||||
LOG = logging.getLogger()
|
LOG = logging.getLogger()
|
||||||
@ -162,7 +162,7 @@ def run_osm2pgsql(options: Mapping[str, Any]) -> None:
|
|||||||
def get_url(url: str) -> str:
|
def get_url(url: str) -> str:
|
||||||
""" Get the contents from the given URL and return it as a UTF-8 string.
|
""" Get the contents from the given URL and return it as a UTF-8 string.
|
||||||
"""
|
"""
|
||||||
headers = {"User-Agent": f"Nominatim/{version_str()}"}
|
headers = {"User-Agent": f"Nominatim/{NOMINATIM_VERSION!s}"}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
request = urlrequest.Request(url, headers=headers)
|
request = urlrequest.Request(url, headers=headers)
|
||||||
|
@ -15,16 +15,14 @@ from psycopg2 import sql as pysql
|
|||||||
from nominatim.config import Configuration
|
from nominatim.config import Configuration
|
||||||
from nominatim.db import properties
|
from nominatim.db import properties
|
||||||
from nominatim.db.connection import connect, Connection
|
from nominatim.db.connection import connect, Connection
|
||||||
from nominatim.version import NOMINATIM_VERSION, version_str
|
from nominatim.version import NominatimVersion, NOMINATIM_VERSION, parse_version
|
||||||
from nominatim.tools import refresh
|
from nominatim.tools import refresh
|
||||||
from nominatim.tokenizer import factory as tokenizer_factory
|
from nominatim.tokenizer import factory as tokenizer_factory
|
||||||
from nominatim.errors import UsageError
|
from nominatim.errors import UsageError
|
||||||
|
|
||||||
LOG = logging.getLogger()
|
LOG = logging.getLogger()
|
||||||
|
|
||||||
VersionTuple = Tuple[int, int, int, int]
|
_MIGRATION_FUNCTIONS : List[Tuple[NominatimVersion, Callable[..., None]]] = []
|
||||||
|
|
||||||
_MIGRATION_FUNCTIONS : List[Tuple[VersionTuple, Callable[..., None]]] = []
|
|
||||||
|
|
||||||
def migrate(config: Configuration, paths: Any) -> int:
|
def migrate(config: Configuration, paths: Any) -> int:
|
||||||
""" Check for the current database version and execute migrations,
|
""" Check for the current database version and execute migrations,
|
||||||
@ -37,8 +35,7 @@ def migrate(config: Configuration, paths: Any) -> int:
|
|||||||
db_version_str = None
|
db_version_str = None
|
||||||
|
|
||||||
if db_version_str is not None:
|
if db_version_str is not None:
|
||||||
parts = db_version_str.split('.')
|
db_version = parse_version(db_version_str)
|
||||||
db_version = tuple(int(x) for x in parts[:2] + parts[2].split('-'))
|
|
||||||
|
|
||||||
if db_version == NOMINATIM_VERSION:
|
if db_version == NOMINATIM_VERSION:
|
||||||
LOG.warning("Database already at latest version (%s)", db_version_str)
|
LOG.warning("Database already at latest version (%s)", db_version_str)
|
||||||
@ -53,8 +50,7 @@ def migrate(config: Configuration, paths: Any) -> int:
|
|||||||
for version, func in _MIGRATION_FUNCTIONS:
|
for version, func in _MIGRATION_FUNCTIONS:
|
||||||
if db_version <= version:
|
if db_version <= version:
|
||||||
title = func.__doc__ or ''
|
title = func.__doc__ or ''
|
||||||
LOG.warning("Running: %s (%s)", title.split('\n', 1)[0],
|
LOG.warning("Running: %s (%s)", title.split('\n', 1)[0], version)
|
||||||
version_str(version))
|
|
||||||
kwargs = dict(conn=conn, config=config, paths=paths)
|
kwargs = dict(conn=conn, config=config, paths=paths)
|
||||||
func(**kwargs)
|
func(**kwargs)
|
||||||
conn.commit()
|
conn.commit()
|
||||||
@ -66,14 +62,14 @@ def migrate(config: Configuration, paths: Any) -> int:
|
|||||||
tokenizer = tokenizer_factory.get_tokenizer_for_db(config)
|
tokenizer = tokenizer_factory.get_tokenizer_for_db(config)
|
||||||
tokenizer.update_sql_functions(config)
|
tokenizer.update_sql_functions(config)
|
||||||
|
|
||||||
properties.set_property(conn, 'database_version', version_str())
|
properties.set_property(conn, 'database_version', str(NOMINATIM_VERSION))
|
||||||
|
|
||||||
conn.commit()
|
conn.commit()
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
def _guess_version(conn: Connection) -> VersionTuple:
|
def _guess_version(conn: Connection) -> NominatimVersion:
|
||||||
""" Guess a database version when there is no property table yet.
|
""" Guess a database version when there is no property table yet.
|
||||||
Only migrations for 3.6 and later are supported, so bail out
|
Only migrations for 3.6 and later are supported, so bail out
|
||||||
when the version seems older.
|
when the version seems older.
|
||||||
@ -89,7 +85,7 @@ def _guess_version(conn: Connection) -> VersionTuple:
|
|||||||
'prior to 3.6.0. Automatic migration not possible.')
|
'prior to 3.6.0. Automatic migration not possible.')
|
||||||
raise UsageError('Migration not possible.')
|
raise UsageError('Migration not possible.')
|
||||||
|
|
||||||
return (3, 5, 0, 99)
|
return NominatimVersion(3, 5, 0, 99)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -108,7 +104,8 @@ def _migration(major: int, minor: int, patch: int = 0,
|
|||||||
there.
|
there.
|
||||||
"""
|
"""
|
||||||
def decorator(func: Callable[..., None]) -> Callable[..., None]:
|
def decorator(func: Callable[..., None]) -> Callable[..., None]:
|
||||||
_MIGRATION_FUNCTIONS.append(((major, minor, patch, dbpatch), func))
|
version = (NominatimVersion(major, minor, patch, dbpatch))
|
||||||
|
_MIGRATION_FUNCTIONS.append((version, func))
|
||||||
return func
|
return func
|
||||||
|
|
||||||
return decorator
|
return decorator
|
||||||
|
@ -18,7 +18,7 @@ from nominatim.config import Configuration
|
|||||||
from nominatim.db.connection import Connection, connect
|
from nominatim.db.connection import Connection, connect
|
||||||
from nominatim.db.utils import execute_file
|
from nominatim.db.utils import execute_file
|
||||||
from nominatim.db.sql_preprocessor import SQLPreprocessor
|
from nominatim.db.sql_preprocessor import SQLPreprocessor
|
||||||
from nominatim.version import version_str
|
from nominatim.version import NOMINATIM_VERSION
|
||||||
|
|
||||||
LOG = logging.getLogger()
|
LOG = logging.getLogger()
|
||||||
|
|
||||||
@ -223,7 +223,7 @@ def setup_website(basedir: Path, config: Configuration, conn: Connection) -> Non
|
|||||||
@define('CONST_Debug', $_GET['debug'] ?? false);
|
@define('CONST_Debug', $_GET['debug'] ?? false);
|
||||||
@define('CONST_LibDir', '{config.lib_dir.php}');
|
@define('CONST_LibDir', '{config.lib_dir.php}');
|
||||||
@define('CONST_TokenizerDir', '{config.project_dir / 'tokenizer'}');
|
@define('CONST_TokenizerDir', '{config.project_dir / 'tokenizer'}');
|
||||||
@define('CONST_NominatimVersion', '{version_str()}');
|
@define('CONST_NominatimVersion', '{NOMINATIM_VERSION!s}');
|
||||||
|
|
||||||
""")
|
""")
|
||||||
|
|
||||||
|
@ -7,25 +7,34 @@
|
|||||||
"""
|
"""
|
||||||
Version information for Nominatim.
|
Version information for Nominatim.
|
||||||
"""
|
"""
|
||||||
from typing import Optional, Tuple
|
from typing import Optional, NamedTuple
|
||||||
|
|
||||||
# Version information: major, minor, patch level, database patch level
|
class NominatimVersion(NamedTuple):
|
||||||
#
|
""" Version information for Nominatim. We follow semantic versioning.
|
||||||
# The first three numbers refer to the last released version.
|
|
||||||
#
|
Major, minor and patch_level refer to the last released version.
|
||||||
# The database patch level tracks important changes between releases
|
The database patch level tracks important changes between releases
|
||||||
# and must always be increased when there is a change to the database or code
|
and must always be increased when there is a change to the database or code
|
||||||
# that requires a migration.
|
that requires a migration.
|
||||||
#
|
|
||||||
# When adding a migration on the development branch, raise the patch level
|
When adding a migration on the development branch, raise the patch level
|
||||||
# to 99 to make sure that the migration is applied when updating from a
|
to 99 to make sure that the migration is applied when updating from a
|
||||||
# patch release to the next minor version. Patch releases usually shouldn't
|
patch release to the next minor version. Patch releases usually shouldn't
|
||||||
# have migrations in them. When they are needed, then make sure that the
|
have migrations in them. When they are needed, then make sure that the
|
||||||
# migration can be reapplied and set the migration version to the appropriate
|
migration can be reapplied and set the migration version to the appropriate
|
||||||
# patch level when cherry-picking the commit with the migration.
|
patch level when cherry-picking the commit with the migration.
|
||||||
#
|
"""
|
||||||
# Released versions always have a database patch level of 0.
|
|
||||||
NOMINATIM_VERSION = (4, 2, 99, 0)
|
major: int
|
||||||
|
minor: int
|
||||||
|
patch_level: int
|
||||||
|
db_patch_level: int
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
return f"{self.major}.{self.minor}.{self.patch_level}-{self.db_patch_level}"
|
||||||
|
|
||||||
|
|
||||||
|
NOMINATIM_VERSION = NominatimVersion(4, 2, 99, 0)
|
||||||
|
|
||||||
POSTGRESQL_REQUIRED_VERSION = (9, 6)
|
POSTGRESQL_REQUIRED_VERSION = (9, 6)
|
||||||
POSTGIS_REQUIRED_VERSION = (2, 2)
|
POSTGIS_REQUIRED_VERSION = (2, 2)
|
||||||
@ -37,9 +46,11 @@ POSTGIS_REQUIRED_VERSION = (2, 2)
|
|||||||
GIT_COMMIT_HASH : Optional[str] = None
|
GIT_COMMIT_HASH : Optional[str] = None
|
||||||
|
|
||||||
|
|
||||||
# pylint: disable=consider-using-f-string
|
def parse_version(version: str) -> NominatimVersion:
|
||||||
def version_str(version:Tuple[int, int, int, int] = NOMINATIM_VERSION) -> str:
|
""" Parse a version string into a version consisting of a tuple of
|
||||||
|
four ints: major, minor, patch level, database patch level
|
||||||
|
|
||||||
|
This is the reverse operation of `version_str()`.
|
||||||
"""
|
"""
|
||||||
Return a human-readable string of the version.
|
parts = version.split('.')
|
||||||
"""
|
return NominatimVersion(*[int(x) for x in parts[:2] + parts[2].split('-')])
|
||||||
return '{}.{}.{}-{}'.format(*version)
|
|
||||||
|
@ -11,7 +11,7 @@ from pathlib import Path
|
|||||||
import datetime as dt
|
import datetime as dt
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from nominatim.version import version_str
|
from nominatim.version import NOMINATIM_VERSION, NominatimVersion
|
||||||
from nominatim.api import NominatimAPI
|
from nominatim.api import NominatimAPI
|
||||||
|
|
||||||
def test_status_no_extra_info(apiobj, table_factory):
|
def test_status_no_extra_info(apiobj, table_factory):
|
||||||
@ -24,7 +24,7 @@ def test_status_no_extra_info(apiobj, table_factory):
|
|||||||
|
|
||||||
assert result.status == 0
|
assert result.status == 0
|
||||||
assert result.message == 'OK'
|
assert result.message == 'OK'
|
||||||
assert result.software_version == version_str()
|
assert result.software_version == NOMINATIM_VERSION
|
||||||
assert result.database_version is None
|
assert result.database_version is None
|
||||||
assert result.data_updated is None
|
assert result.data_updated is None
|
||||||
|
|
||||||
@ -41,8 +41,8 @@ def test_status_full(apiobj, table_factory):
|
|||||||
|
|
||||||
assert result.status == 0
|
assert result.status == 0
|
||||||
assert result.message == 'OK'
|
assert result.message == 'OK'
|
||||||
assert result.software_version == version_str()
|
assert result.software_version == NOMINATIM_VERSION
|
||||||
assert result.database_version == '99.5.4-2'
|
assert result.database_version == NominatimVersion(99, 5, 4, 2)
|
||||||
assert result.data_updated == dt.datetime(2022, 12, 7, 14, 14, 46, 0, tzinfo=dt.timezone.utc)
|
assert result.data_updated == dt.datetime(2022, 12, 7, 14, 14, 46, 0, tzinfo=dt.timezone.utc)
|
||||||
|
|
||||||
|
|
||||||
@ -55,6 +55,6 @@ def test_status_database_not_found(monkeypatch):
|
|||||||
|
|
||||||
assert result.status == 700
|
assert result.status == 700
|
||||||
assert result.message == 'Database connection failed'
|
assert result.message == 'Database connection failed'
|
||||||
assert result.software_version == version_str()
|
assert result.software_version == NOMINATIM_VERSION
|
||||||
assert result.database_version is None
|
assert result.database_version is None
|
||||||
assert result.data_updated is None
|
assert result.data_updated is None
|
||||||
|
@ -12,7 +12,7 @@ import pytest
|
|||||||
|
|
||||||
import nominatim.result_formatter.v1 as format_module
|
import nominatim.result_formatter.v1 as format_module
|
||||||
from nominatim.apicmd.status import StatusResult
|
from nominatim.apicmd.status import StatusResult
|
||||||
from nominatim.version import version_str
|
from nominatim.version import NOMINATIM_VERSION
|
||||||
|
|
||||||
STATUS_FORMATS = {'text', 'json'}
|
STATUS_FORMATS = {'text', 'json'}
|
||||||
|
|
||||||
@ -50,7 +50,7 @@ class TestStatusResultFormat:
|
|||||||
|
|
||||||
result = self.formatter.format(status, 'json')
|
result = self.formatter.format(status, 'json')
|
||||||
|
|
||||||
assert result == '{"status": 700, "message": "Bad format.", "software_version": "%s"}' % (version_str())
|
assert result == '{"status": 700, "message": "Bad format.", "software_version": "%s"}' % (NOMINATIM_VERSION, )
|
||||||
|
|
||||||
|
|
||||||
def test_format_json_full(self):
|
def test_format_json_full(self):
|
||||||
@ -60,4 +60,4 @@ class TestStatusResultFormat:
|
|||||||
|
|
||||||
result = self.formatter.format(status, 'json')
|
result = self.formatter.format(status, 'json')
|
||||||
|
|
||||||
assert result == '{"status": 0, "message": "OK", "data_updated": "2010-02-07T20:20:03+00:00", "software_version": "%s", "database_version": "5.6"}' % (version_str())
|
assert result == '{"status": 0, "message": "OK", "data_updated": "2010-02-07T20:20:03+00:00", "software_version": "%s", "database_version": "5.6"}' % (NOMINATIM_VERSION, )
|
||||||
|
Loading…
Reference in New Issue
Block a user