From 14fc9b36ed5e6681e2efd6d0ae6fc9fa93ebf4c6 Mon Sep 17 00:00:00 2001
From: Felix Delattre <fd@gfz-potsdam.de>
Date: Thu, 23 Sep 2021 14:43:47 +0000
Subject: [PATCH] Introduced configuration management

---
 .gitignore                                    |  4 +-
 setup.py                                      |  2 +-
 spearhead/__init__.py                         |  4 +-
 spearhead/configure.py                        | 44 ++++++++++++++++
 .../{osm_analyzer.py => diff_analyzer.py}     | 34 +++++++------
 spearhead/spearhead.py                        | 50 +++++++++++++------
 6 files changed, 106 insertions(+), 32 deletions(-)
 create mode 100644 spearhead/configure.py
 rename spearhead/{osm_analyzer.py => diff_analyzer.py} (72%)

diff --git a/.gitignore b/.gitignore
index dc767ab..31b5a99 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,7 +4,6 @@
 *.egg-info
 Pipfile
 Pipfile.lock
-.idea
 
 __pycache__
 .cache
@@ -13,4 +12,7 @@ build
 dist
 env
 
+config.yml
+
+.idea
 .vscode
diff --git a/setup.py b/setup.py
index c404e07..5b50343 100644
--- a/setup.py
+++ b/setup.py
@@ -27,7 +27,7 @@ setup(
     description="Trigger calculations on the Rabotnik Message Bus based on \
         OpenStreetMap's augmented diffs",
     license="AGPLv3+",
-    install_requires=["osmdiff>=0.1.9"],
+    install_requires=["aiofiles", "osmdiff>=0.1.9"],
     extras_require={
         "tests": tests_require,
         "linters": linters_require,
diff --git a/spearhead/__init__.py b/spearhead/__init__.py
index 8b2b9df..a1a76c7 100644
--- a/spearhead/__init__.py
+++ b/spearhead/__init__.py
@@ -17,7 +17,7 @@
 # along with this program. If not, see http://www.gnu.org/licenses/.
 
 
-from .osm_analyzer import OSMAnalyzer
+from .diff_analyzer import DiffAnalyzer
 
 
-__all__ = ["OSMAnalyzer"]
+__all__ = ["DiffAnalyzer"]
diff --git a/spearhead/configure.py b/spearhead/configure.py
new file mode 100644
index 0000000..96f3a4b
--- /dev/null
+++ b/spearhead/configure.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python3
+
+# Copyright (c) 2020-2021:
+#   Helmholtz-Zentrum Potsdam Deutsches GeoForschungsZentrum GFZ
+#
+# This program is free software: you can redistribute it and/or modify it
+# under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or (at
+# your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero
+# General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see http://www.gnu.org/licenses/.
+
+import logging
+import sys
+import yaml
+
+
+logger = logging.getLogger(__name__)
+logger.addHandler(logging.StreamHandler(sys.stdout))
+
+
+class Configuration:
+    """Configuration.
+
+    Holds configuration data.
+    """
+
+    def __init__(self, config_file: str = "config.yml") -> None:
+
+        if config_file:
+            with open(config_file) as f:
+                config = yaml.load(f.read(), Loader=yaml.FullLoader)
+
+        try:
+            self.overpass_base_url = config["overpass_base_url"]
+        except KeyError as e:
+            logger.info("Error: The variable %s hasn't been set in the config file." % str(e))
+            sys.exit(1)
diff --git a/spearhead/osm_analyzer.py b/spearhead/diff_analyzer.py
similarity index 72%
rename from spearhead/osm_analyzer.py
rename to spearhead/diff_analyzer.py
index 369295a..6cb6608 100644
--- a/spearhead/osm_analyzer.py
+++ b/spearhead/diff_analyzer.py
@@ -17,38 +17,44 @@
 # along with this program. If not, see http://www.gnu.org/licenses/.
 
 import logging
-
+import sys
 import osmdiff
 
+from spearhead.configure import Configuration
+
 logger = logging.getLogger(__name__)
+logger.addHandler(logging.StreamHandler(sys.stdout))
 
 
-class OSMAnalyzer:
-    """OSM analyzer.
+class DiffAnalyzer:
+    """DiffAnalyzer.
 
     This class contains the logic for obtaining and interpreting the OpenStreetMap's
     "augmented diffs".
     """
 
-    async def get_augmented_diff(self, provider: osmdiff.AugmentedDiff):
+    def __init__(self, diff_provider: osmdiff.AugmentedDiff, config: Configuration):
+        self.diff_provider = diff_provider
+
+    async def get_augmented_diff(self) -> osmdiff.AugmentedDiff:
         """Obtain an augmented diff from Overpass API
 
         Args:
-            provider: connection to database
+            diff_provider: connection to database
         Returns:
-            provider (AugmentedDiff):
+            diff_provider (AugmentedDiff):
                 An object containing all information of an augmented diff.
         """
+        logger.info("Downloading augmented diff: " + str(self.diff_provider.sequence_number))
+        self.diff_provider.retrieve()
+        return self.diff_provider
 
-        provider.get_state()
-        provider.retrieve()
-
-        return provider
-
-    async def get_buildings(self, augmented_diff):
+    async def get_buildings(self, augmented_diff) -> None:
         """Collect the building IDs of building objects that have changed in a given
         augmented diff.
         """
+        logger.info(" " + str(augmented_diff))
+
         building_count = 0
 
         # Check on newly created objects
@@ -71,9 +77,9 @@ class OSMAnalyzer:
             if self._is_way_or_relation(n):
                 building_count += 1
 
-        print("building_count: " + str(building_count))
+        logger.info(" building_count: " + str(building_count))
 
-    def _is_way_or_relation(self, element):
+    def _is_way_or_relation(self, element) -> bool:
         """Check if element is of type `osm.Way` or `osm.Relation`"""
         return isinstance(element, osmdiff.osm.osm.Way) or isinstance(
             element, osmdiff.osm.osm.Relation
diff --git a/spearhead/spearhead.py b/spearhead/spearhead.py
index bdabe7a..29e6e46 100644
--- a/spearhead/spearhead.py
+++ b/spearhead/spearhead.py
@@ -21,10 +21,12 @@ import logging
 import sys
 
 import osmdiff
-from spearhead import OSMAnalyzer
+
+from spearhead.configure import Configuration
+from spearhead import DiffAnalyzer
 
 logger = logging.getLogger(__name__)
-logger.setLevel(logging.DEBUG)
+logging.basicConfig(level=logging.DEBUG)
 logger.addHandler(logging.StreamHandler(sys.stdout))
 
 
@@ -34,22 +36,42 @@ def main():
 
 async def async_main():
 
-    logger.info("spearhead started")
+    logger.info("spearhead started - it can be stopped with CTRL+c")
+
+    config = Configuration("config.yml")
+
+    await Spearhead().get_changed_buildings(config)
+
+
+class Spearhead:
+    """Spearhead.
+
+    This class contains the main entry point for this program.
+    """
+
+    async def get_changed_buildings(self, config: Configuration):
+        """Obtain a list of buiildings that have changed since last check."""
 
-    await get_changed_buildings()
+        diff_provider = osmdiff.AugmentedDiff()
+        diff_provider.base_url = config.overpass_base_url
+        diff_provider.get_state()
+        logger.info("Using Overpass API: " + diff_provider.base_url)
 
-    # Leave the program
-    sys.exit()
+        diff_analyzer = DiffAnalyzer(diff_provider, config)
 
+        while True:
+            try:
 
-async def get_changed_buildings():
+                # Obtain and read augmented diff from Overpass API
+                diff = await diff_analyzer.get_augmented_diff()
 
-    analyzer = OSMAnalyzer()
+                # Get identifiers of all buildings that have changed
+                await diff_analyzer.get_buildings(diff)
 
-    diff_provider = osmdiff.AugmentedDiff()
-    diff_provider.base_url = "https://overpass.openbuildingmap.org/api"
+                # Wait until requesting more data
+                await asyncio.sleep(60)
 
-    while True:
-        diff = await analyzer.get_augmented_diff(diff_provider)
-        await analyzer.get_buildings(diff)
-        await asyncio.sleep(60)
+            except KeyboardInterrupt:
+                # Leave the program
+                logger.info("spearhead stopped")
+                sys.exit()
-- 
GitLab