-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathcsvScriptBuilder.py
More file actions
284 lines (216 loc) · 9.33 KB
/
csvScriptBuilder.py
File metadata and controls
284 lines (216 loc) · 9.33 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
import requests
import codecs
import os
import json
import uuid
import re
import csv
class csvScriptBuilder:
MAX_PROPERTY_NUMBER = 4000
CSV_FILE_NAME = "constraints.csv"
CONSTRAINT_BEGIN_STRING = "{{Constraint:"
def __init__(self):
self.parameters = {}
self.constraint_name = ""
def find_next_seperator(self, constraint_parameters, equal_sign):
next_equal_sign = constraint_parameters.find('=', equal_sign + 1)
if next_equal_sign == -1:
next_seperator = len(constraint_parameters)
else:
next_seperator = constraint_parameters.rfind('|', equal_sign, next_equal_sign)
if next_seperator == -1:
next_seperator = len(constraint_parameters)
else:
next_seperator = next_seperator + 1
return next_seperator
def to_comma_seperated_string(self, values):
return values.replace("{", "").replace("}", "").replace("|", "").replace(" ", "").replace("[", "").replace("]", "").strip()
def add_property(self, values):
self.parameters['property'] = values.strip()
def add_classes(self, values):
self.parameters['class'] = self.to_comma_seperated_string(values)
def add_exceptions(self, values):
self.parameters['known_exception'] = self.to_comma_seperated_string(values).replace(";", ",")
def add_group_by(self, values):
self.parameters['group_by'] = values.strip()
def add_items(self, values):
itemString = ""
snakString = ""
for element in self.to_comma_seperated_string(values).split(","):
if element.startswith("Q"):
itemString = itemString + element + ","
elif element.lower() == "somevalue" or element.lower() == "novalue":
snakString = snakString + element + ","
if itemString != "":
self.parameters['item'] = itemString.rstrip(",")
if snakString != "":
self.parameters['snak'] = snakString.rstrip(",")
def add_list(self, values):
if self.constraint_name == "Qualifiers" or self.constraint_name == "Mandatory qualifiers":
self.parameters['property'] = self.to_comma_seperated_string(values)
else:
self.list_parameter = self.to_comma_seperated_string(values)
def set_constraint_name(self, values):
if values == 'true':
self.constraint_name = 'Mandatory qualifiers'
def add_status(self, values):
self.parameters['constraint_status'] = 'mandatory'
def add_max(self, values):
self.parameters['maximum_quantity'] = values.strip()
def add_min(self, values):
self.parameters['minimum_quantity'] = values.strip()
def add_namespace(self, values):
self.parameters['namespace'] = values.strip()
def add_pattern(self, values):
self.parameters['pattern'] = values.strip()
def add_relation(self, values):
self.parameters['relation'] = values.strip()
def write_one_line(self, property_number, constraint_name):
self.write_element_into_csv(property_number, constraint_name)
self.reset_parameter()
def write_multiple_lines(self, property_number, constraint_name):
for line in self.list_parameter.split(';'):
self.split_list_parameter(line)
self.write_element_into_csv(property_number, constraint_name)
self.parameters.pop('item', None)
self.reset_parameter()
def write_into_csv_file(self, property_number, constraint_name):
if self.list_parameter != 'NULL':
self.write_multiple_lines(property_number, constraint_name)
else:
self.write_one_line(property_number, constraint_name)
def write_element_into_csv(self, property_number, constraint_name):
json_blob_string = json.dumps(self.parameters).replace("<nowiki>","").replace("</nowiki>","").replace("&lt;nowiki&lt;","").replace("&lt;/nowiki&gt;","").replace("<nowiki>","").replace("</nowiki>","")
self.csv_writer.writerow((str(uuid.uuid4()), str(property_number), constraint_name.strip(), json_blob_string))
def split_list_parameter(self, line):
if ':' in line:
self.parameters['item'] = line[line.index(':')+1:]
self.parameters['property'] = line[:line.index(':')]
else:
self.parameters['property'] = line
def reset_parameter(self):
self.parameters = {}
self.list_parameter = 'NULL'
def get_constraint_part(self, property_talk_page):
start = property_talk_page.find("{{Constraint:")
end = property_talk_page.find("==", start)
if end != -1:
property_talk_page = property_talk_page[start:end]
else:
property_talk_page = property_talk_page[start:]
#delete <!-- --> comments from site
open_index = property_talk_page.find("<!--")
while open_index != -1:
close_index = property_talk_page.find("-->", open_index)
if close_index == -1:
break
property_talk_page = property_talk_page[:open_index] + property_talk_page[close_index+3:]
open_index = property_talk_page.find("<!--")
return property_talk_page
def progress_print(self, number, maxNumber):
if number % 10 == 0:
print(str(number) + "/" + str(maxNumber))
def property_exists(self, propertyTalkPage):
# return not (propertyTalkPage.find("Creating Property talk") != -1 or
# propertyTalkPage == "")
regex = re.compile('<title>(.*)</title>')
match = regex.search(propertyTalkPage)
if match:
return not "Creating Property talk" in match.group(0)
else:
return False
def get_constraint_end_index(self, constraintPart):
#match brackets to find end of constraint
count = 2
for i, c in enumerate(constraintPart):
if c == '{':
count += 1
elif c == '}':
count -= 1
if count == 0:
return (i - 1)
def split_constraint_block(self, constraint_part):
start_index = constraint_part.find(self.CONSTRAINT_BEGIN_STRING)
if start_index != -1:
start_index += len(self.CONSTRAINT_BEGIN_STRING)
constraint_part = constraint_part[start_index:]
end_index = self.get_constraint_end_index(constraint_part)
constraint_string = constraint_part[:end_index]
remaining_constraint = constraint_part[end_index:]
return constraint_string, remaining_constraint
else:
return "", ""
call_method = {
'base_property' : add_property,
'class' : add_classes,
'classes' : add_classes,
'exceptions' : add_exceptions,
'group by' : add_group_by,
'group property' : add_group_by,
'item' : add_items,
'items' : add_items,
'list' : add_list,
'mandatory' : add_status,
'max' : add_max,
'min' : add_min,
'namespace' : add_namespace,
'pattern' : add_pattern,
'property' : add_property,
'relation' : add_relation,
'required' : set_constraint_name,
'value' : add_items,
'values' : add_items
}
def split_parameters(self, constraint_parameters):
equal_sign_pos = constraint_parameters.find('=')
next_seperator = self.find_next_seperator(constraint_parameters, equal_sign_pos)
value_end_pos = max(-1, next_seperator - 1)
parameter_name = constraint_parameters[:equal_sign_pos].strip()
parameter_value = constraint_parameters[equal_sign_pos + 1 : value_end_pos]
remaining_constraint_parameters = constraint_parameters[next_seperator:]
return parameter_name, parameter_value, remaining_constraint_parameters
def add_all_parameters(self, constraint_parameters):
while constraint_parameters != None and constraint_parameters.find('=') != -1:
p_name, p_value, constraint_parameters = self.split_parameters(constraint_parameters)
try:
self.call_method[p_name](self, p_value)
except KeyError, e: # other Exceptions will be raised
pass
def process_constraint_part(self, constraint_part, property_number):
constraint_string, remaining_constraint = self.split_constraint_block(constraint_part)
while constraint_string != "":
self.constraint_name = None
self.list_parameter = 'NULL'
delimiter_index = constraint_string.find('|')
if delimiter_index == -1:
self.constraint_name = constraint_string
else:
self.constraint_name = constraint_string[:delimiter_index]
constraint_parameters = constraint_string[delimiter_index+1:]
self.add_all_parameters(constraint_parameters)
self.write_into_csv_file(property_number, self.constraint_name)
constraint_string, remaining_constraint = self.split_constraint_block(remaining_constraint)
def get_property_talk_page(self, property_number):
url = "http://www.wikidata.org/w/index.php?title=Property_talk:P" + \
str(property_number) + "&action=edit"
property_talk_page = requests.get(url).text
return property_talk_page
def process_property_talk_page(self, property_number):
property_talk_page = self.get_property_talk_page(property_number)
if self.property_exists(property_talk_page):
constraintPart = self.get_constraint_part(property_talk_page)
self.process_constraint_part(constraintPart, property_number)
# only purpose: Build csv-Statement to fill table with constraints
# fetches constraints from property talk pages
# nonetheless: use table layout that will suit the new way of storing
# constraints as statements on properties
def run(self):
with open(self.CSV_FILE_NAME, 'wb') as csv_file:
self.csv_writer = csv.writer(csv_file)
for property_number in range(1, self.MAX_PROPERTY_NUMBER+1):
self.progress_print(property_number, self.MAX_PROPERTY_NUMBER)
self.process_property_talk_page(property_number)
def main():
builder = csvScriptBuilder()
builder.run()
if __name__ == "__main__": main()