-
Notifications
You must be signed in to change notification settings - Fork 7
/
main.py
368 lines (293 loc) · 13.1 KB
/
main.py
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
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
#-*-coding:utf-8-*
import pywikibot
import functionsmain.APIfunction
import collections
from lxml import etree
import re
import sys
"""
This Bot was made to automaticaly import lexicograficals data to the wikidata database.
This Bot takes the datas from a xml file and uses the wikidata's framework pywikibot.
To identifie itself to the wikidata API, the Bot needs a valid wikidata account.
To run the bot use this command :
cat <file.xml> | python3 <user_name> <password> (<lexeme_only>)
The lexeme_only parameter is facultative.
To find more informations please read the documentation.
You will find in the doc file the details of the functions used by the bot, an example of xml file, the detail of the utility of the lexeme_only parameter and a "known issues" section.
"""
# I set the user name and the password of the bots account
try:
functionsmain.APIfunction.setCo(sys.argv[1], sys.argv[2])
except:
print('Erreur : il vous faut renseigner le nom et le mot de passe du compte utilisateur du bot en paramètre')
sys.exit()
# I look if the mode 'lexeme_only' is on
try:
if sys.argv[3] == 'lexeme_only':
lexeme_only = True
# print('lexeme_only = True')# trace
else:
lexeme_only = False
# print('lexeme_only = False')# trace
except:
lexeme_only = False
# print('lexeme_only = False') # trace
try:
parser = etree.XMLParser(remove_blank_text=True, encoding="utf-8")
tree = etree.parse(sys.stdin, parser)
except:
print('Erreur : fichier XML vide ou illisible')
sys.exit()
# I create the log.txt file which will contains the errors messages
fLog = open('log.txt','w')
fInputs = open('inputs.csv','w')
err = 0
compteur = 0
comptForm = 0
# I get to the root of the xml file
tei = tree.getroot()
# for each lexeme
for lexeme in tei.xpath('.//form[@type="lemma"]'):
compteur += 1
# I get the id of the lexeme for the errors
if lexeme.get("{http://www.w3.org/XML/1998/namespace}id"):
idlexxml=lexeme.get("{http://www.w3.org/XML/1998/namespace}id")
else:
idlexxml=""
# I get the infos of the language
langs=lexeme.xpath('lang')
# if there is no language tag, I send an error and jump to the next lexeme
if len(langs)==0:
fLog.write('erreur fichier source lexème "'+idlexxml+'" : il doit y avoir une balise <lang> sous les <form type="lemma">\n')
err += 1
continue
else:
lang=langs[0]
libLg=lang.get('norm')
codeLg=lang.text
# if the language tag has no code or Q-id, I send an error and jump to the next lexeme
if libLg==None or codeLg==None or codeLg=="":
fLog.write('erreur fichier source lexème "'+idlexxml+'" : la balise <lang> ne peut être vide et elle doit avoir un attribut "norm"\n')
err += 1
continue
# if the Q-id is not valid, I send an error and jump to the next lexeme
if not re.search(r'^Q([0-9]+)$', codeLg):
fLog.write('erreur fichier source lexème "'+idlexxml+'" : Qid de langue "'+codeLg+'" invalide\n')
err += 1
continue
lg={ 'libLg':libLg , 'codeLg':codeLg }
# i get the spelling
orths=lexeme.xpath('orth')
# if there is no spelling tag, I send an error and jump to the next lexeme
if len(orths)==0:
fLog.write('erreur fichier source lexème "'+idlexxml+'" : il doit y avoir une balise <orth> sous les <form type="lemma">\n')
err += 1
continue
else:
orth=orths[0]
lemme=orth.text
# if the spelling tag is empty, I send an error and jump to the next lexeme
if lemme==None or lemme=="":
fLog.write('erreur fichier source lexème "'+idlexxml+'" : la balise <orth> ne peut être vide\n')
err += 1
continue
# I get the nature (cats)
cats=lexeme.xpath('pos')
# if there is no nature tag, I send an error and jump to the next lexeme
if len(cats)==0:
fLog.write('erreur fichier source lexème "'+idlexxml+'" : il doit y avoir une balise <pos> sous les <form type="lemma">\n')
err += 1
continue
else:
cat=cats[0]
catLex=cat.text
# if the pos tag is empty, I send an error and jump to the next lexeme
if catLex==None or catLex=="":
fLog.write('erreur fichier source lexème "'+idlexxml+'" : la balise <pos> ne peut être vide\n')
err += 1
continue
# if the Q-id is not valid, I send an error and jump to the next lexeme
if not re.search(r'^Q([0-9]+)$', catLex):
fLog.write('erreur fichier source lexème "'+idlexxml+'" : Qid de nature "'+catLex+'" invalide\n')
err += 1
continue
# I get the claims if its needed
declaLex = {}
for relation in lexeme.xpath('listRelation/relation'):
prop=relation.get('name')
concept=relation.get('passive')
if prop==None or concept==None:
fLog.write('erreur fichier source lexème "'+idlexxml+'" : la balise <relation> doit avoir un attribut "name" et un attribut "passive"\n')
err += 1
continue
# if the Q-id is not valid, I send an error and jump to the next lexeme
if concept!=None and not re.search(r'^Q([0-9]+)$', concept):
fLog.write('erreur fichier source lexème "'+idlexxml+'" : Qid "'+concept+'" invalide\n')
err += 1
continue
# if the P-id is not valid, I send an error and jump to the next lexeme
if prop!=None and not re.search(r'^P([0-9]+)$', prop):
fLog.write('erreur fichier source lexème "'+idlexxml+'" : Pid "'+prop+'" invalide\n')
err += 1
continue
if prop not in declaLex:
declaLex[prop]=set()
declaLex[prop].add(concept)
print('\ntraitement du lexeme numéro', compteur, ':', lemme) # trace
# I get the L-id of the lexeme (if the lexeme don't exists, i create it) and then i get the data of the lexeme
idLex, chercheLerr = functionsmain.APIfunction.chercheLex(lemme, lg, catLex, declaLex)
# if there were an error when researching the lexeme, I send an error and jump to the next lexeme
if chercheLerr==1:
fLog.write('erreur lexème "'+idlexxml+'" : erreur lors de la recherche du lexeme\n')
err += 1
continue
# if there were an error while creating, I send an error and jump to the next lexeme
elif chercheLerr==2:
fLog.write('erreur lexème "'+idlexxml+'" : erreur lors de la creation du lexeme\n')
err += 1
continue
# if there were an error in the function getQidCat, I send an error and jump to the next lexeme
elif chercheLerr==3:
fLog.write('erreur lexème "'+idlexxml+'" : erreur dans la fontion getQidCat lors de la creation du lexeme\n')
err += 1
continue
# if there were an error while adding a claim, I send an error and jump to the next lexeme
elif chercheLerr==4:
fLog.write('erreur lexème "'+idlexxml+'" : erreur dans la fontion setClaim lors de la creation du lexeme\n')
err += 1
continue
fInputs.write(idlexxml+"§"+idLex+"\n")
infoLex = functionsmain.APIfunction.getLex(idLex)
# if there were an error while getting the lexeme's features, I send an error and jump to the next lexeme
if infoLex==1:
fLog.write('erreur lexème "'+idlexxml+'" : erreur lors de la récupération des infos du lexeme\n')
err += 1
continue
# if lexeme_only is not on, I add the forms
if not lexeme_only:
# print('paramètre lexeme_only renseigné, j\'ajoute les formes') # trace
for flexion in lexeme.xpath('form[@type="inflected"]'):
comptForm += 1
# I get the id of the form for the errors
if flexion.get("{http://www.w3.org/XML/1998/namespace}id"):
idformxml=flexion.get("{http://www.w3.org/XML/1998/namespace}id")
else:
idformxml=""
# I get the spelling
orthfs=flexion.xpath('orth')
# if there is no spelling tag (orth), I send an error and jump to the next form
if len(orthfs)==0:
fLog.write('erreur fichier source lexème "'+idlexxml+'" forme "'+idformxml+'" : il doit y avoir une balise <orth> sous les <form type="inflected">\n')
err += 1
continue
else:
orthf=orthfs[0]
form=orthf.text
# if the orth tag is empty, I send an error and jump to the next form
if form==None or form=="":
fLog.write('erreur fichier source lexème "'+idlexxml+'" forme "'+idformxml+'" : la balise <orth> ne peut être vide\n')
err += 1
continue
# I get the grammaticals features
infosGram = []
for gram in flexion.xpath('gramGrp/gram'):
infoGram=gram.text
# if the gram tag id empty, I send an error and jump to the next form
if infoGram==None or infoGram=="":
fLog.write('erreur fichier source lexème "'+idlexxml+'" forme "'+idformxml+'" : la balise <gram> ne peut être vide\n')
err += 1
continue
# if the Q-id is not valid, I send an error and jump to the next form
if infoGram!=None and not re.search(r'^Q([0-9]+)$', infoGram):
fLog.write('erreur fichier source lexème "'+idlexxml+'" forme "'+idformxml+'" : Qid d\'information grammaticale "'+infoGram+'" invalide\n')
err += 1
continue
infosGram.append(infoGram)
# if get the claims if its needed
declaForm = {}
for relation in flexion.xpath('listRelation/relation'):
prop=relation.get('name')
concept=relation.get('passive')
if prop==None or concept==None:
fLog.write('erreur fichier source lexème "'+idlexxml+'" forme "'+idformxml+'" : la balise <relation> doit avoir un attribut "name" et un attribut "passive"\n')
err += 1
continue
# if the Q-id is not valid, I send an error and jump to the next form
if concept!=None and not re.search(r'^Q([0-9]+)$', concept):
fLog.write('erreur fichier source lexème "'+idlexxml+'" forme "'+idformxml+'" : Qid "'+concept+'" invalide\n')
err += 1
continue
# if the P-id is not valid, I send an error and jump to the next form
if prop!=None and not re.search(r'^P([0-9]+)$', prop):
fLog.write('erreur fichier source lexème "'+idlexxml+'" forme "'+idformxml+'" : Pid "'+prop+'" invalide\n')
err += 1
continue
if prop not in declaForm:
declaForm[prop]=set()
declaForm[prop].add(concept)
print('--traitement de la forme numéro', comptForm, ':', form) # trace
# I check if the form exists
formExists = False
formeMatch = []
# if the form exists I check the grammaticals features
for formes in infoLex['formes']:
if form == formes['representation']:
formExists = True
formeMatch += [formes]
# if the grammaticals features are the same
if formExists == True:
# print('main : la forme existe') # trace
memeCat = False
for forme in formeMatch:
if collections.Counter(infosGram) == collections.Counter(forme['catGram']):
memeCat = True
formeMatch = forme
continue
# if the grammaticals features are the same (the form may be in an other dialect)
if memeCat == True:
# print('main : les catégories sont les mêmes') # trace
# I check the claims and add the missing ones if its needed
for cle, valeurs in declaForm.items():
for valeur in valeurs:
if cle not in formeMatch['declaration'].keys() or valeur not in formeMatch['declaration'][cle]:
# print('j\'ajoute une declaration') # trace
functionsmain.APIfunction.setClaim(formeMatch['idForm'], cle, valeur)
else:
# I create the form
# print('main : les catégories sont différentes, je crée une nouvelle forme') # trace
idForm = functionsmain.APIfunction.createForm(idLex, form, infosGram, lg, declaForm)
# if there is an error while creating the form, I send an error and jump to the next form
if idForm==1:
fLog.write('erreur lexème "'+idlexxml+'" forme "'+idformxml+'" : erreur lors de la création de la forme\n')
err += 1
continue
# if there is an error in setClaim creating the form, I send an error and jump to the next form
if idForm==2:
fLog.write('erreur lexème "'+idlexxml+'" forme "'+idformxml+'" : erreur dans la fonction setClaim lors de la création de la forme\n')
err += 1
continue
fInputs.write(idformxml+"§"+idForm+"\n")
# I create the form
else:
# print('main : la forme n\'existe pas je la crée') # trace
idForm = functionsmain.APIfunction.createForm(idLex, form, infosGram, lg, declaForm)
# if there is an error while creating the form, I send an error and jump to the next form
if idForm==1:
fLog.write('erreur lexème "'+idlexxml+'" forme "'+idformxml+'" : erreur lors de la création de la forme\n')
err += 1
continue
# if there is an error in setClaim creating the form, I send an error and jump to the next form
if idForm==2:
fLog.write('erreur lexème "'+idlexxml+'" forme "'+idformxml+'" : erreur dans la fonction setClaim lors de la création de la forme\n')
err += 1
continue
fInputs.write(idformxml+","+idForm+"\n")
print('--forme ', form, 'traitée\n') # trace
print('\nlexeme numéro', compteur, ':', lemme, 'traité') # trace
fLog.close()
fInputs.close()
msg = 'Programme terminé'
if err>0:
err = str(err)
msg += '\nIl y a eu '+err+' erreurs, consultez le fichier log.txt pour plus de détails'
print(msg)