verifier.py 3 KB
Newer Older
Jgiannelos's avatar
Jgiannelos committed
1
import json
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import osmium
import psycopg2
import yaml


class InconsistentChangeException(Exception):
    pass


class ElementHandler:
    def __init__(self, conn, tables, failfast):
        self.conn = conn
        self.tables = tables
        self.failfast = failfast
        self.inconsistencies = []

18
19
20
21
22
23
24
25
26
27
28
29
    def serialize(self, change):
        tags = {}
        for tag in change.tags:
            tags[tag.k] = tag.v

        return {
            "id": change.id,
            "changeset": change.changeset,
            "version": change.version,
            "tags": tags,
        }

30
31
32
33
34
35
36
37
38
39
40
41
42
    def exists(self, table, osm_id):
        query = f"SELECT * FROM {table} WHERE osm_id = {osm_id}"
        cursor = self.conn.cursor()
        cursor.execute(query)
        return cursor.fetchone() is not None

    def verify_deleted(self, change):
        for table in self.tables:
            if self.exists(table, change.id):
                if self.failfast:
                    raise InconsistentChangeException(
                        f"Element with id:{change.id} shouldn't exist"
                    )
Jgiannelos's avatar
Jgiannelos committed
43
                self.inconsistencies.append(
44
                    {"type": "should be deleted", "element": self.serialize(change)}
Jgiannelos's avatar
Jgiannelos committed
45
46
                )
                break
47
48

    def verify_existing(self, change):
Jgiannelos's avatar
Jgiannelos committed
49
        at_least_once = False
50
        for table in self.tables:
Jgiannelos's avatar
Jgiannelos committed
51
52
53
54
55
56
57
58
59
            if self.exists(table, change.id):
                at_least_once = True
                break

        if not at_least_once:
            if self.failfast:
                raise InconsistentChangeException(
                    f"Element with id:{change.id} should exist"
                )
60
61
62
            self.inconsistencies.append(
                {"type": "should exist", "element": self.serialize(change)}
            )
63
64
65

    def log_inconsistencies(self):
        for elem in self.inconsistencies:
Jgiannelos's avatar
Jgiannelos committed
66
            print(f"{json.dumps(elem)}")
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99

    def __call__(self, change):
        if change.deleted:
            self.verify_deleted(change)
        else:
            self.verify_existing(change)


class Verifier:
    def __init__(self, changesetPath, mappingPath, pgURL, failfast=True):
        self.changesetPath = changesetPath
        self.mappingPath = mappingPath
        self.pgURL = pgURL
        self.tables = self.get_tables()
        self.conn = psycopg2.connect(self.pgURL)
        self.conn.set_session(readonly=True)
        self.failfast = failfast

    def get_tables(self):
        with open(self.mappingPath, "r") as f:
            mapping = yaml.safe_load(f)
            return mapping["tables"].keys()

    def verify(self):
        node = ElementHandler(self.conn, self.tables, self.failfast)
        way = ElementHandler(self.conn, self.tables, self.failfast)
        relation = ElementHandler(self.conn, self.tables, self.failfast)
        handler = osmium.make_simple_handler(node=node, way=way, relation=relation)
        handler.apply_file(self.changesetPath)

        node.log_inconsistencies()
        way.log_inconsistencies()
        relation.log_inconsistencies()