Mercurial > dive4elements > river
comparison flys-backend/contrib/import-kms.py @ 3344:cb376f48dd37 2.8
merged flys-backend/2.8
author | Thomas Arendsen Hein <thomas@intevation.de> |
---|---|
date | Fri, 28 Sep 2012 12:14:36 +0200 |
parents | 80669241956c |
children |
comparison
equal
deleted
inserted
replaced
3318:dbe2f85bf160 | 3344:cb376f48dd37 |
---|---|
1 #!/usr/bin/env python | |
2 | |
3 import sys | |
4 import logging | |
5 import re | |
6 import os | |
7 | |
8 import sqlite3 as db | |
9 import locale | |
10 import codecs | |
11 | |
12 from optparse import OptionParser | |
13 | |
14 log = logging.getLogger(__name__) | |
15 log.setLevel(logging.WARNING) | |
16 log.addHandler(logging.StreamHandler(sys.stderr)) | |
17 | |
18 RANGE = re.compile("([^#]*)#(.*)") | |
19 DEFAULT_DATABASE = "flys.db" | |
20 | |
21 SQL_NEXT_ID = "SELECT coalesce(max(id), -1) + 1 FROM %s" | |
22 SQL_SELECT_ID = "SELECT id FROM %s WHERE %s = ?" | |
23 SQL_INSERT_ID = "INSERT INTO %s (id, %s) VALUES (?, ?)" | |
24 | |
25 SQL_SELECT_RANGE_ID = """ | |
26 SELECT id FROM ranges WHERE river_id = ? AND a = ? AND b = ? | |
27 """ | |
28 SQL_INSERT_RANGE_ID = """ | |
29 INSERT INTO ranges (id, river_id, a, b) VALUES (?, ?, ?, ?) | |
30 """ | |
31 SQL_SELECT_ANNOTATION_ID = """ | |
32 SELECT id FROM annotations | |
33 WHERE range_id = ? AND attribute_id = ? AND position_id = ? | |
34 """ | |
35 SQL_INSERT_ANNOTATION_ID = """ | |
36 INSERT INTO annotations (id, range_id, attribute_id, position_id) | |
37 VALUES (?, ?, ?, ?) | |
38 """ | |
39 | |
40 def encode(s): | |
41 try: | |
42 return unicode(s, "latin-1") | |
43 except UnicodeDecodeError: | |
44 return unicode.encode(s, locale.getpreferredencoding()) | |
45 | |
46 class hashabledict(dict): | |
47 def __key(self): | |
48 return tuple((k, self[k]) for k in sorted(self)) | |
49 def __hash__(self): | |
50 return hash(self.__key()) | |
51 def __eq__(self, other): | |
52 return self.__key() == other.__key() | |
53 | |
54 def cache(f): | |
55 def func(*args, **kw): | |
56 key = (args, hashabledict(kw)) | |
57 try: | |
58 return f.__cache__[key] | |
59 except KeyError: | |
60 value = f(*args, **kw) | |
61 f.__cache__[key] = value | |
62 return value | |
63 f.__cache__ = {} | |
64 return func | |
65 | |
66 NEXT_IDS = {} | |
67 def next_id(cur, relation): | |
68 idx = NEXT_IDS.get(relation) | |
69 if idx is None: | |
70 cur.execute(SQL_NEXT_ID % relation) | |
71 idx = cur.fetchone()[0] | |
72 NEXT_IDS[relation] = idx + 1 | |
73 return idx | |
74 | |
75 def get_id(cur, relation, attribute, value): | |
76 select_stmt = SQL_SELECT_ID % (relation, attribute) | |
77 #log.debug(select_stmt) | |
78 cur.execute(select_stmt, (value,)) | |
79 row = cur.fetchone() | |
80 if row: return row[0] | |
81 idx = next_id(cur, relation) | |
82 insert_stmnt = SQL_INSERT_ID % (relation, attribute) | |
83 #log.debug(insert_stmnt) | |
84 cur.execute(insert_stmnt, (idx, value)) | |
85 cur.connection.commit() | |
86 log.debug("insert %s '%s' id: '%d'" % (relation, value, idx)) | |
87 return idx | |
88 | |
89 #@cache | |
90 def get_river_id(cur, name): | |
91 return get_id(cur, "rivers", "name", name) | |
92 | |
93 #@cache | |
94 def get_attribute_id(cur, value): | |
95 return get_id(cur, "attributes", "value", value) | |
96 | |
97 #@cache | |
98 def get_position_id(cur, value): | |
99 return get_id(cur, "positions", "value", value) | |
100 | |
101 #@cache | |
102 def get_range_id(cur, river_id, a, b): | |
103 cur.execute(SQL_SELECT_RANGE_ID, (river_id, a, b)) | |
104 row = cur.fetchone() | |
105 if row: return row[0] | |
106 idx = next_id(cur, "ranges") | |
107 cur.execute(SQL_INSERT_RANGE_ID, (idx, river_id, a, b)) | |
108 cur.connection.commit() | |
109 return idx | |
110 | |
111 #@cache | |
112 def get_annotation_id(cur, range_id, attribute_id, position_id): | |
113 cur.execute(SQL_SELECT_ANNOTATION_ID, ( | |
114 range_id, attribute_id, position_id)) | |
115 row = cur.fetchone() | |
116 if row: return row[0] | |
117 idx = next_id(cur, "annotations") | |
118 cur.execute(SQL_INSERT_ANNOTATION_ID, ( | |
119 idx, range_id, attribute_id, position_id)) | |
120 cur.connection.commit() | |
121 return idx | |
122 | |
123 def files(root, accept=lambda x: True): | |
124 if os.path.isfile(root): | |
125 if accept(root): yield root | |
126 elif os.path.isdir(root): | |
127 stack = [ root ] | |
128 while stack: | |
129 cur = stack.pop() | |
130 for f in os.listdir(cur): | |
131 p = os.path.join(cur, f) | |
132 if os.path.isdir(p): | |
133 stack.append(p) | |
134 elif os.path.isfile(p) and accept(p): | |
135 yield p | |
136 | |
137 def feed_km(cur, river_id, km_file): | |
138 | |
139 log.info("processing: %s" % km_file) | |
140 | |
141 for line in codecs.open(km_file, "r", "latin-1"): | |
142 line = line.strip() | |
143 if not line or line.startswith('*'): | |
144 continue | |
145 parts = [x.strip() for x in line.split(';')] | |
146 if len(parts) < 3: | |
147 log.error("cannot process: '%s'" % line) | |
148 continue | |
149 m = RANGE.match(parts[2]) | |
150 try: | |
151 if m: | |
152 x = [float(x.replace(",", ".")) for x in m.groups()] | |
153 a, b = min(x), max(x) | |
154 if a == b: b = None | |
155 else: | |
156 a, b = float(parts[2].replace(",", ".")), None | |
157 except ValueError: | |
158 log.error("cannot process: '%s'" % line) | |
159 continue | |
160 | |
161 attribute = parts[0] | |
162 position = parts[1] | |
163 attribute_id = get_attribute_id(cur, attribute) if attribute else None | |
164 position_id = get_position_id(cur, position) if position else None | |
165 | |
166 range_id = get_range_id(cur, river_id, a, b) | |
167 | |
168 get_annotation_id(cur, range_id, attribute_id, position_id) | |
169 | |
170 def main(): | |
171 | |
172 usage = "usage: %prog [options] river km-file ..." | |
173 parser = OptionParser(usage=usage) | |
174 parser.add_option( | |
175 "-v", "--verbose", action="store_true", | |
176 dest="verbose", | |
177 help="verbose output") | |
178 parser.add_option( | |
179 "-r", "--recursive", action="store_true", | |
180 dest="recursive", default=False, | |
181 help="recursive") | |
182 parser.add_option( | |
183 "-d", "--database", action="store", | |
184 dest="database", | |
185 help="database to connect with", | |
186 default=DEFAULT_DATABASE) | |
187 | |
188 options, args = parser.parse_args() | |
189 | |
190 if options.verbose: | |
191 log.setLevel(logging.INFO) | |
192 | |
193 if len(args) < 1: | |
194 log.error("missing river argument") | |
195 sys.exit(1) | |
196 | |
197 river = unicode(args[0], locale.getpreferredencoding()) | |
198 | |
199 with db.connect(options.database) as con: | |
200 cur = con.cursor() | |
201 river_id = get_river_id(cur, river) | |
202 | |
203 for arg in args[1:]: | |
204 if options.recursive: | |
205 for km_file in files( | |
206 arg, lambda x: x.lower().endswith(".km")): | |
207 feed_km(cur, river_id, km_file) | |
208 else: | |
209 feed_km(cur, river_id, arg) | |
210 | |
211 | |
212 if __name__ == '__main__': | |
213 main() |