]> git.openstreetmap.org Git - nominatim.git/blobdiff - nominatim/config.py
Vagrant and CI tests for Ubuntu 22.04
[nominatim.git] / nominatim / config.py
index 3ac8e33fc65ffe5e3c3250c71c29a11feabb5686..b3934b491fa9a36a690526d1b1c55be4b524804d 100644 (file)
@@ -1,3 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# This file is part of Nominatim. (https://nominatim.org)
+#
+# Copyright (C) 2022 by the Nominatim developer community.
+# For a full list of authors see the git log.
 """
 Nominatim configuration accessor.
 """
 """
 Nominatim configuration accessor.
 """
@@ -12,7 +18,7 @@ from dotenv import dotenv_values
 from nominatim.errors import UsageError
 
 LOG = logging.getLogger()
 from nominatim.errors import UsageError
 
 LOG = logging.getLogger()
-
+CONFIG_CACHE = {}
 
 def flatten_config_list(content, section=''):
     """ Flatten YAML configuration lists that contain include sections
 
 def flatten_config_list(content, section=''):
     """ Flatten YAML configuration lists that contain include sections
@@ -56,12 +62,6 @@ class Configuration:
         if project_dir is not None and (project_dir / '.env').is_file():
             self._config.update(dotenv_values(str((project_dir / '.env').resolve())))
 
         if project_dir is not None and (project_dir / '.env').is_file():
             self._config.update(dotenv_values(str((project_dir / '.env').resolve())))
 
-        # Add defaults for variables that are left empty to set the default.
-        # They may still be overwritten by environment variables.
-        if not self._config['NOMINATIM_ADDRESS_LEVEL_CONFIG']:
-            self._config['NOMINATIM_ADDRESS_LEVEL_CONFIG'] = \
-                str(config_dir / 'address-levels.json')
-
         class _LibDirs:
             pass
 
         class _LibDirs:
             pass
 
@@ -86,19 +86,47 @@ class Configuration:
             Values of '1', 'yes' and 'true' are accepted as truthy values,
             everything else is interpreted as false.
         """
             Values of '1', 'yes' and 'true' are accepted as truthy values,
             everything else is interpreted as false.
         """
-        return self.__getattr__(name).lower() in ('1', 'yes', 'true')
+        return getattr(self, name).lower() in ('1', 'yes', 'true')
 
 
     def get_int(self, name):
         """ Return the given configuration parameter as an int.
         """
         try:
 
 
     def get_int(self, name):
         """ Return the given configuration parameter as an int.
         """
         try:
-            return int(self.__getattr__(name))
+            return int(getattr(self, name))
         except ValueError as exp:
             LOG.fatal("Invalid setting NOMINATIM_%s. Needs to be a number.", name)
             raise UsageError("Configuration error.") from exp
 
 
         except ValueError as exp:
             LOG.fatal("Invalid setting NOMINATIM_%s. Needs to be a number.", name)
             raise UsageError("Configuration error.") from exp
 
 
+    def get_str_list(self, name):
+        """ Return the given configuration parameter as a list of strings.
+            The values are assumed to be given as a comma-sparated list and
+            will be stripped before returning them. On empty values None
+            is returned.
+        """
+        raw = getattr(self, name)
+
+        return [v.strip() for v in raw.split(',')] if raw else None
+
+
+    def get_path(self, name):
+        """ Return the given configuration parameter as a Path.
+            If a relative path is configured, then the function converts this
+            into an absolute path with the project directory as root path.
+            If the configuration is unset, a falsy value is returned.
+        """
+        value = getattr(self, name)
+        if value:
+            value = Path(value)
+
+            if not value.is_absolute():
+                value = self.project_dir / value
+
+            value = value.resolve()
+
+        return value
+
     def get_libpq_dsn(self):
         """ Get configured database DSN converted into the key/value format
             understood by libpq and psycopg.
     def get_libpq_dsn(self):
         """ Get configured database DSN converted into the key/value format
             understood by libpq and psycopg.
@@ -124,12 +152,12 @@ class Configuration:
             name of the standard styles automatically into a file in the
             config style.
         """
             name of the standard styles automatically into a file in the
             config style.
         """
-        style = self.__getattr__('IMPORT_STYLE')
+        style = getattr(self, 'IMPORT_STYLE')
 
         if style in ('admin', 'street', 'address', 'full', 'extratags'):
 
         if style in ('admin', 'street', 'address', 'full', 'extratags'):
-            return self.config_dir / 'import-{}.style'.format(style)
+            return self.config_dir / f'import-{style}.style'
 
 
-        return Path(style)
+        return self.find_config_file('', 'IMPORT_STYLE')
 
 
     def get_os_env(self):
 
 
     def get_os_env(self):
@@ -164,14 +192,19 @@ class Configuration:
         """
         configfile = self.find_config_file(filename, config)
 
         """
         configfile = self.find_config_file(filename, config)
 
-        if configfile.suffix in ('.yaml', '.yml'):
-            return self._load_from_yaml(configfile)
+        if str(configfile) in CONFIG_CACHE:
+            return CONFIG_CACHE[str(configfile)]
 
 
-        if configfile.suffix == '.json':
-            with configfile.open('r') as cfg:
-                return json.load(cfg)
+        if configfile.suffix in ('.yaml', '.yml'):
+            result = self._load_from_yaml(configfile)
+        elif configfile.suffix == '.json':
+            with configfile.open('r', encoding='utf-8') as cfg:
+                result = json.load(cfg)
+        else:
+            raise UsageError(f"Config file '{configfile}' has unknown format.")
 
 
-        raise UsageError(f"Config file '{configfile}' has unknown format.")
+        CONFIG_CACHE[str(configfile)] = result
+        return result
 
 
     def find_config_file(self, filename, config=None):
 
 
     def find_config_file(self, filename, config=None):
@@ -181,7 +214,7 @@ class Configuration:
             a regular file.
         """
         if config is not None:
             a regular file.
         """
         if config is not None:
-            cfg_filename = self.__getattr__(config)
+            cfg_filename = getattr(self, config)
             if cfg_filename:
                 cfg_filename = Path(cfg_filename)
 
             if cfg_filename:
                 cfg_filename = Path(cfg_filename)