source: lliurex-abies2pmb/trunk/fuentes/lliurex-abies2pmb.install/usr/share/lliurex-abies2pmb/abies2pmb.py @ 4245

Last change on this file since 4245 was 4245, checked in by jrpelegrina, 2 years ago

add suppot to default values

  • Property svn:executable set to *
File size: 18.4 KB
Line 
1#!/usr/bin/python3
2import os
3import datetime
4import subprocess
5import sys
6import tempfile
7# -*- coding: utf-8 -*-
8class abies2Pmb():
9        def __init__(self):
10                self.dbg=0
11               
12                #Dict with relations between pmb and abies
13                self.pmb_abies={}
14                self.pmb_abies["empr_categ"]=["TiposLector"]
15                self.pmb_abies["docs_location"]=["Ubicaciones"]
16                self.pmb_abies["authors"]=["Autores"]
17                self.pmb_abies["exemplaires"]=["Ejemplares"]
18                self.pmb_abies["notices"]=["Fondos"]
19                self.pmb_abies["collections"]=["Series"]
20                self.pmb_abies["notices_langues"]=["Fondos_Idiomas"]
21                self.pmb_abies["publishers"]=["Editoriales"]
22                self.pmb_abies["groupe"]=["Cursos"]
23                self.pmb_abies["indexint"]=["CDUs"]
24                self.pmb_abies["notices_tmp"]=["Fondos_all"]
25
26                #Dict with forced column data type
27                self.formatPmbColumns={}
28                self.formatPmbColumns['indexint']={1:'string'}
29                self.formatPmbColumns['indexint'].update({3:'string'})
30
31                #Dict with default values to column
32                self.defaultPmbValues={}
33                self.defaultPmbValues['docs_location']={5:'1'}
34                self.defaultPmbValues['indexint']={4:'1'}
35                self.defaultPmbValues['notices']={29:'"m"'}
36                self.defaultPmbValues['notices'].update({38:'1'})
37
38                #Blacklist pmb_abies tables.
39                self.blacklist=['notices_tmp']
40
41                #Dict with abies source fields for pmb
42                #Numbers are the indexes of the source data table
43                self.pmb_tables={}
44                self.pmb_tables["docs_location"]=[0,1,'','','','','','','','','','','','','','','','','','','','','','','']
45                self.pmb_tables["empr_categ"]=[0,1,'','','','']
46                self.pmb_tables["authors"]=[0,1,2,'','','','','','','','','','','','']
47                self.pmb_tables["publishers"]=[0,1,'','','','','','','','']
48                self.pmb_tables["groupe"]=[0,1,'','','','']
49                self.pmb_tables["exemplaires"]=[0,4,1,'','',13,'','',6,'','','','','','','','',9,'','','','','','','','','']
50                self.pmb_tables["collections"]=[0,1,'','','','','','']
51                self.pmb_tables["indexint"]=[0,1,'',1,'']
52                self.pmb_tables["notices_tmp"]=[0,1,2]
53                self.pmb_tables["notices"]=[0,1,14,15,16,13,'','',19,'',24,'',20,17,25,11,21,22,23,'','','','','','','',26,'','','','','','','','','','','','','',6,'','','','','','','','','','','','','']
54                self.pmb_tables["notices_langues"]=[0,'',1,'']
55                #dict with needed virtual tables
56                #Only load one column using a 'get', any other column must be charged with formatTables or formatFields
57                self.virtual_tables={}
58                self.virtual_tables["CDUs"]={}
59                self.virtual_tables["CDUs"].update({'index 0':''})
60                self.virtual_tables["CDUs"].update({'index 1':'get Fondos_CDUs.1'})
61                self.virtual_tables['Series']={}
62                self.virtual_tables['Series'].update({'index 0':''})
63                self.virtual_tables['Series'].update({'index 1':'get Fondos.24'})
64                self.virtual_tables['Fondos_all']={'index 0':'get Fondos.0'}
65                self.virtual_tables['Fondos_all'].update({'index 1':''})
66                self.virtual_tables['Fondos_all'].update({'index 2':''})
67                self.virtual_tables['Fondos_Idiomas']={}
68                self.virtual_tables['Fondos_Idiomas']={'index 0':'get Fondos.0'}
69                self.virtual_tables['Fondos_Idiomas'].update({'index 1':''})
70
71                #Dict whith field transformations
72                self.formatFields={}
73                self.formatFields['TiposLector']={'index 0':'add index 0 7'}
74                self.formatFields['Autores']={'index 1':'value 100=70,value 110=71,value 120=72,value 700=70'}
75                self.formatFields['Ejemplares']={'index 13':'concat 13,14,15'}
76                self.formatFields['Ejemplares'].update({'index 9':'date %m/%d/%y %H:%M:%S %Y-%m-%d %H:%M:%S'})
77                self.formatFields['CDUs']={'index 0':'inc 1 1000'}
78                self.formatFields['Series']={'index 0':'inc 1 1000'}
79                self.formatFields['Fondos']={'index 1':'value 1="a",value 2="g",value 3="m",value4="j",value 5="k",value 6="a",value 7="l"'}
80                self.formatFields['Fondos'].update({'index 13':'from Autores.2 on 13=0'})
81                self.formatFields['Fondos'].update({'index 24':'from Series.0 on 24=0'})
82                self.formatFields['Fondos'].update({'index 26':'from Fondos_all.2 on 0=1'})
83                self.formatFields['Fondos_all']={'index 2':'from CDUs.0 on 0=1'}
84                self.formatFields['Fondos_Idiomas']={'index 1':'from Fondos.9 on 0=0'}
85
86                #Dict whith special columns
87                self.formatTables={}
88                self.formatTables['CDUs']={'index 1':'uniq'}
89                self.formatTables['Series']={'index 1':'uniq'}
90                self.formatTables['Fondos_all']={'index 1':'from Fondos_CDUs.1 on 0=0'}
91
92
93                #Dict with errors
94                self.error={}
95                #self.error['status']=True
96
97                #Array with process order (including virtual tables)
98                self.executionOrder=['Ubicaciones','TiposLector','Autores','Editoriales','Cursos','Ejemplares','Series','CDUs','Fondos_all','Fondos','Fondos_Idiomas']
99                #Tmp variables
100                self.workDir='/tmp/.abiesToPmb/'
101                self.tableValuesDict={}
102                self.tmpInc=0
103
104                #Work files
105                self.mdb=''
106                self.sql=''
107                self.sqlFiles=[]
108        #def _init
109
110        def _debug(self,msg):
111                if self.dbg:
112                        print('Migrator: '+str(msg))
113        #def _debug
114
115        def _error(self,code,index=None):
116                #Error Codes
117                #10 -> Table not found
118                #11 -> Error ocurred while importing mdb file
119                #12 -> Error exporting mdb to csv
120                #13 -> Error generating sql file
121                #14 -> Error concatenating sql files
122                #15 -> No source table for virtual table
123                #16 -> Couldn't fetch data from table
124                self.error['status']=False
125                self.error['code']=code
126#               if index:
127#                       if index in self.error.keys():
128#                               self.error[index].append(e)
129#                       else:
130#                               self.error[index]=e
131#               else:
132#                       if 'ERR' in self.error.keys():
133#                               self.error['ERR'].append(e)
134#                       else:
135#                               self.error['ERR']=e
136        #def _error
137
138        ###
139        #Process array executionOrder
140        ###
141        def beginMigration(self,mdbFile,sqlFile):
142
143                self.error['status']=True
144                self.error['code']=""
145                self.mdb=mdbFile
146                self.sql=sqlFile
147                if self.exportMdb():
148                        self.sqlFiles=[]
149                        for abiesTable in self.executionOrder:
150                                self.tmpInc=0
151                                self._debug("Processing "+abiesTable)
152                                self._loadTable(abiesTable)
153                                if not self.error['status']:
154                                        break
155                                pmbTable=self._getTableEquivalence(abiesTable)
156                                if not self.error['status']:
157                                        break
158                                self._generateSql(pmbTable,abiesTable)
159                                if not self.error['status']:
160                                        break
161                        if self.error['status']:
162                                self._debug("Concatenating sql files in an unique file")
163                                self._concatFiles()
164                        else:
165                                self._debug("Errors ocurred")
166                                self._debug(self.error)
167                        self._debug("Files generated for tables "+str(self.executionOrder))
168                else:
169                        self._error(11)
170
171                self._debug("ErrorDict:")
172                self._debug(self.error)
173                return self.error
174        #def beginMigration
175
176        def exportMdb(self):
177                returnValue=None
178                self._debug(self.mdb)
179                if os.path.exists(self.mdb):
180                        try:
181                                cmdOut=subprocess.check_output(['mdb-tables',self.mdb],universal_newlines=True)
182                                if cmdOut:
183                                        self.workDir=tempfile.mkdtemp()+"/"
184                                        tables=cmdOut.strip("\n")
185                                        listTables=tables.split(' ')
186                                        for table in listTables:
187                                                if table!='':
188                                                        cmdOut=subprocess.check_output(['mdb-export','-H','-d|||',self.mdb,table],universal_newlines=True)
189                                                        if cmdOut:
190                                                                f=open (self.workDir+table+".csv",'w')
191                                                                f.writelines(cmdOut)
192                                                                f.close()
193                                        returnValue=True
194                        except Exception as e:
195                                self._error(12)
196                                returnValue=False
197                return returnValue
198        #def exportMdb
199
200        ###
201        #Generates the sql
202        #Input: pmb tableName
203        #Output: Array of sql sentences
204        ###
205        def _generateSql(self,destTable,abiesTable):
206                transformDict=self._checkTransformField(abiesTable)
207                origData=self.tableValuesDict[abiesTable]
208                sqlFile=self.workDir+destTable+".sql"
209                fileName=destTable+".sql"
210                try:
211                        if destTable not in self.blacklist:
212                                f=open (sqlFile,'w')
213                        for line in origData:
214                                pmbColumn=0
215                                strInsertValues=''
216                                for index in self.pmb_tables[destTable]:
217                                        if index!='':
218                                                if transformDict:
219                                                        if index in transformDict.keys():
220                                                                strTransform=transformDict[index]
221        #                                                       self._debug("Transforming value "+str(line[index])+" index "+str(index)+" with "+strTransform)
222                                                                line[index]=eval(strTransform)
223                                                tmp=str(line[index]).strip("\n")
224                                                #Clean tmp field
225                                                tmp=tmp.replace('"',' ')
226                                                chkFormat=True
227                                                if (destTable in self.formatPmbColumns):
228                                                        if index in self.formatPmbColumns[destTable]:
229                                                                chkFormat=False
230                                                                if self.formatPmbColumns[destTable][index]=='string':
231                                                                        tmp=str(tmp)
232                                                                        tmp=tmp.lstrip(' ')
233                                                                        tmp=tmp.rstrip(' ')
234                                                                        tmp='"'+tmp+'"'
235                                                                elif self.formatPmbColumns[destTable][index]=='int':
236                                                                        tmp=int(tmp)
237
238                                                if chkFormat:
239                                                        try:
240                                                                int(tmp)
241                                                        except:
242                                                                tmp=tmp.lstrip(' ')
243                                                                tmp=tmp.rstrip(' ')
244                                                                tmp='"'+tmp+'"'
245                                                                pass
246                                        else:
247                                                if (destTable in self.defaultPmbValues):
248                                                        if pmbColumn in self.defaultPmbValues[destTable]:
249                                                                tmp=self.defaultPmbValues[destTable][pmbColumn]
250                                                               
251                                                        else:
252                                                                tmp='""'       
253                                                else:
254                                                        tmp='""'
255                                               
256                                        strInsertValues=strInsertValues+tmp+','
257                                        pmbColumn=pmbColumn+1
258                                strInsertValues=strInsertValues[:-1]
259                                if destTable not in self.blacklist:
260                                        f.write("Insert into "+destTable+" values ("+strInsertValues+");\n")
261                        if destTable not in self.blacklist:
262                                f.close()
263                                self.sqlFiles.append(sqlFile)
264                except Exception as e:
265                        self._error(13)
266
267        #def _generateSql
268
269        ###
270        #Concats all the generated files
271        ###
272        def _concatFiles(self):
273                self._debug("Generating "+self.sql)
274                self._debug("Files list:")
275                self._debug(self.sqlFiles)
276                try:
277                        f=open(self.sql,'w')
278                        f.write("DELETE from docs_location;\n")
279                        f.write("DELETE from indexint;\n")
280                        for sqlFile in self.sqlFiles:
281                                self._debug("Opening "+sqlFile)
282                                a=open(sqlFile,'r')
283                                aContent=a.readlines()
284                                a.close()
285                                f.writelines(aContent)
286                        f.close()
287                except Exception as e:
288                        self._error(14)
289                       
290        #def _concatFile
291
292
293        ###
294        #Loads a table from a file or a virtual table from a bunch of tables
295        #Input: Table name
296        ###
297        def _loadTable(self,tableName):
298                returnValue=False
299                fileName=self.workDir+tableName+'.csv'
300                data=[]
301                if os.path.exists(fileName):
302                        try:
303                                f=open(fileName,'r')
304                                lines=f.readlines()
305                                f.close()
306                                for line in lines:
307                                        array=line.split('|||')
308                                        data.append(array)
309                                returnValue=True
310                        except Exception as e:
311                                self._error(10)
312                else: #Check in virtual dict
313                        if tableName in self.virtual_tables.keys():
314                                data=self._loadVirtualTable(tableName)
315                                returnValue=True
316                        else:
317                                self._error(10)
318
319                self.tableValuesDict[tableName]=data
320                if tableName in self.formatTables.keys():
321                        self.tableValuesDict[tableName]=self._checkTransformTables(tableName)
322                return (returnValue)
323        #def _loadTable
324
325        ###
326        #Loads a virtual table as described by virtual tables dict
327        #Input: Table name
328        #Output: Dataset (array of arrays with the virtual table)
329        ###
330        def _loadVirtualTable(self,tableName):
331                self._debug("Loading virtual table "+tableName)
332                data=[]
333                dataDict={}
334                if tableName in self.virtual_tables.keys():
335                        proceed=False
336                        for key,line in self.virtual_tables[tableName].items():
337#                               print (s)ourceData)
338#                               for key,line in sourceData.items():
339                                        if line.startswith('get'):
340                                                proceed=True
341                                                sourceIndex=key.split(' ')[1]
342                                                getFrom=line.split(' ')[1]
343                                                sourceIndex=getFrom.split('.')[1]
344                                                sourceTable=getFrom.split('.')[0]
345                                                dataDict[key]=self._funcGetValueFromTable(sourceTable,sourceIndex)
346                        if proceed:
347                                #Data is charged on the dataDict, time to populate data array
348                                maxLen=0
349                                for key in dataDict.keys():
350                                        columnLen=len(dataDict[key])
351                                        if columnLen>maxLen:
352                                                maxLen=columnLen
353                                index=0
354                                while index<maxLen:
355                                        dataLine=[]
356                                        for key in self.virtual_tables[tableName].keys():
357                                                arrayIndex=int(key.split(' ')[-1])
358                                                if key in dataDict.keys():
359                                                        dataLine.insert(arrayIndex,dataDict[key][index])
360                                                else:
361                                                        dataLine.insert(arrayIndex,'')
362                                        data.append(dataLine)
363                                        index=index+1
364                else:
365                        self._error(15)
366                return(data)
367
368        ###
369        #Finds the pmb table related with an abies table
370        #Input: Table name in abies
371        #Output: pmb table name
372        ###
373        def _getTableEquivalence(self,tableName):
374                pmbTable=None
375                for key in self.pmb_abies.keys():
376                        if tableName in self.pmb_abies[key]:
377                                pmbTable=key
378                                break
379                return pmbTable
380        #def _getTableEquivalence
381
382        ###
383        #Check if there's any transformation to apply to the fields of a table
384        #Input: Abies table name
385        #Output: Dict with field indexes as keys and transformations to apply as values
386        def     _checkTransformField(self,abiesTable):
387                transformDict={}
388                if abiesTable in self.formatFields.keys():
389                        transform=self.formatFields[abiesTable]
390                        self._debug("Transforming fields "+str(transform)+" in "+abiesTable)
391                        for key,line in transform.items():
392                                index=int(key.split(' ')[-1])
393                                if line.startswith('add'):
394                                        transformDict[index]=self._transformAdd(line,index)
395                                elif line.startswith('value'):
396                                        transformDict[index]=self._transformValue(line,index)
397                                elif line.startswith('concat'):
398                                        transformDict[index]=self._transformConcat(line,index)
399                                elif line.startswith('date'):
400                                        transformDict[index]=self._transformDate(line,index)
401                                elif line.startswith('inc'):
402                                        transformDict[index]=self._transformInc(line,index)
403                                elif line.startswith('get'):
404                                        transformDict[index]=self._transformGet(line,index)
405                                elif line.startswith('from'):
406                                        transformDict[index]=self._transformQuery(line,index,abiesTable)
407
408                self._debug("TransformDict: "+str(transformDict))
409                return transformDict
410        #def _checkTransformField
411
412        ###
413        #Transform routines, self-explaining
414        ###
415        def _transformAdd(self,line,index):
416                sourceIndex=line.split(' ')[1]
417                increment=line.split(' ')[-1]
418                returnValue='int(line['+sourceIndex+'])+'+increment
419                return(returnValue)
420
421        def _transformValue(self,line,index):
422                values=line.split(',')
423                tmpStr=''
424                for value in values:
425                        relation=value.split('=')
426                        sourceValue=relation[0].split(' ')[-1]
427                        destValue=relation[-1]
428                        tmpStr=tmpStr+str(destValue)+' if line['+str(index)+']=="'+str(sourceValue)+'" else '
429                try:
430                        int(destValue)
431                        returnValue='('+tmpStr+ '"'+str(destValue)+'")'
432                except:
433                        returnValue='('+tmpStr+ ''+str(destValue)+')'
434                return(returnValue)
435
436        def _transformConcat(self,line,index):
437                concat=line.split(' ')[-1]
438                concatArray=concat.split(',')
439                tmpStr=''
440                for concatField in concatArray:
441                        tmpStr=tmpStr+'line['+str(concatField)+']+'
442                returnValue=tmpStr[:-1]
443                return(returnValue)
444
445        def _transformDate(self,line,index):
446                dates=line.split(' ')
447                sourceFormat=dates[1]+' '+dates[2]
448                destFormat=dates[3]+' '+dates[4]
449                returnValue='self._funcDateTransform(line['+str(index)+'],"'+sourceFormat+'","'+destFormat+'")'
450                return(returnValue)
451
452        def _funcDateTransform(self,date,origFormat,destFormat):
453                date=date.replace('"','')
454                destFormat=destFormat.replace('"','')
455                returnValue=(datetime.datetime.strptime(date, origFormat).strftime(destFormat))
456                return(returnValue)
457               
458        def _transformInc(self,line,index):
459                increment=line.split(' ')
460                inc=increment[1]
461                base=0
462                if len(increment)==3:
463                        base=int(increment[2])
464                if self.tmpInc<base:
465                        self.tmpInc=base
466                returnValue='self._funcIncrementField('+inc+')'
467                return(returnValue)
468        ###
469        #Some values need a special transformation that requires a helper function.
470        #Those helper functions are the _func...
471        ###
472        def _funcIncrementField(self,inc):
473                self.tmpInc=self.tmpInc+int(inc)
474                returnValue=self.tmpInc
475                return(returnValue)
476
477        def _transformGet(self,line,index):
478                getFrom=line.split(' ')[-1]
479                getFromTable=getFrom.split('.')[0]
480                getFromIndex=getFrom.split('.')[-1]
481                returnValue='self._funcGetValueFromTable('+getFromTable+','+getFromIndex+')'
482                return(returnValue)
483
484        def _funcGetValueFromTable(self,table,index):
485                fileName=self.workDir+table+'.csv'
486                data=[]
487                index=int(index)
488                if os.path.exists(fileName):
489                        try:
490                                f=open(fileName,'r')
491                                lines=f.readlines()
492                                f.close()
493                                for line in lines:
494                                        array=line.split('|||')
495                                        data.append(array[index])
496                        except Exception as e:
497                                self._error(16)
498                else:
499                        self._error(16)
500                return(data)
501
502        def _transformQuery(self,line,index,tableName):
503                self._debug("Join field "+line)
504                transformDict=[]
505                arrayLine=line.split(' ')
506                sourceTableField=arrayLine[1]
507                joinFromTo=arrayLine[-1]
508                sourceTable=sourceTableField.split('.')[0]
509                sourceField=int(sourceTableField.split('.')[1])
510                joinFrom=joinFromTo.split('=')[0]
511                joinTo=joinFromTo.split('=')[1]
512                returnValue='self._funcGetValueFromQuery("'+tableName+'","'+sourceTable+'",line['+str(joinFrom)+'],'+str(joinTo)+','+str(sourceField)+')'
513                return(returnValue)
514
515        def _funcGetValueFromQuery(self,abiesTable,sourceTable,valueFrom,fieldTo,reqFieldIndex):
516                returnValue=''
517                valueFrom=valueFrom.strip("\n")
518                if sourceTable not in self.tableValuesDict:
519                        self._loadTable(sourceTable)
520                for row in self.tableValuesDict[sourceTable]:
521                                #                       print ("Comparing "+str(valueFrom)+" with "+str(row[fieldTo]))
522                        if valueFrom==str(row[fieldTo]).strip("\n"):
523                                returnValue=row[reqFieldIndex]
524                                break
525                return returnValue
526        #Transform fields functions
527
528        ###
529        #Check if there's any Transform to apply to a whole table
530        #Input: abies table
531        #Output: Dataset with the table
532        ###
533        def _checkTransformTables(self,tableName):
534                transformDict={}
535                if tableName in self.formatTables.keys():
536                        transform=self.formatTables[tableName]
537                        for key,line in transform.items():
538                                index=int(key.split(' ')[-1])
539                                if line.startswith('uniq'):
540                                        transformDict=self._transformTableUniq(tableName,index)
541                                if line.startswith('from'):
542                                        transformDict=self._transformTableJoin(tableName,index,line)
543                return transformDict
544        #def _checkTransformTamble
545
546        ###
547        #Function helpers for table transformation. Self-explaining
548        ###
549        def _transformTableUniq(self,tableName,index):
550                self._debug("Uniq items from index "+str(index))
551                transformDict=[]
552                for item in self.tableValuesDict[tableName]:
553                        if item not in transformDict:
554                                transformDict.append(item)
555                return transformDict
556
557        def _transformTableJoin(self,tableName,index,line):
558                self._debug("Join "+line)
559                transformDict=[]
560                arrayLine=line.split(' ')
561                sourceTableField=arrayLine[1]
562                joinFromTo=arrayLine[-1]
563                sourceTable=sourceTableField.split('.')[0]
564                sourceField=int(sourceTableField.split('.')[1])
565                joinFrom=joinFromTo.split('=')[0]
566                joinTo=joinFromTo.split('=')[1]
567                if sourceTable not in self.tableValuesDict:
568                        self._loadTable(sourceTable)
569                #Generate a dict with joinTo as index and required field as value
570                tmpDict={}
571                tmpIndex=int(joinTo)
572                for row in self.tableValuesDict[sourceTable]:
573                        rowIndex=row[tmpIndex]
574                        rowValue=row[sourceField]
575                        tmpDict.update({rowIndex:rowValue})
576
577                #Walk through origin table and insert values from sourceTableDict
578                tmpIndex=int(joinFrom)
579                for row in self.tableValuesDict[tableName]:
580                        rowIndex=row[tmpIndex]
581                        if rowIndex in tmpDict:
582                                row.insert(tmpIndex,tmpDict[rowIndex])
583                        else:
584                                row.insert(tmpIndex,'')
585                        transformDict.append(row)
586                return transformDict
587        #Table transformation function helpers
588
589### MAIN PROGRAM ###
590
591#migration=abies2Pmb()
592#result=migration.beginMigration(sys.argv[1],sys.argv[2])
593#print(result)
Note: See TracBrowser for help on using the repository browser.