288 lines
5.9 KiB
Python
288 lines
5.9 KiB
Python
|
import os
|
||
|
import sys
|
||
|
from openpyxl import load_workbook
|
||
|
from appPublic.myjson import loadf,dumpf,dumps
|
||
|
from appPublic.dictObject import DictObject
|
||
|
|
||
|
class TypeConvert:
|
||
|
def conv(self,typ,v):
|
||
|
if typ is None:
|
||
|
return v
|
||
|
f = getattr(self,'to_'+typ,None)
|
||
|
if f is None:
|
||
|
return v
|
||
|
return f(v)
|
||
|
|
||
|
def to_int(self,v):
|
||
|
try:
|
||
|
return int(v)
|
||
|
except:
|
||
|
return 0
|
||
|
|
||
|
def to_float(self,v):
|
||
|
try:
|
||
|
return float(v)
|
||
|
except:
|
||
|
return 0.0
|
||
|
|
||
|
def to_str(self,v):
|
||
|
try:
|
||
|
return str(v)
|
||
|
except:
|
||
|
return ''
|
||
|
def to_json(self,v):
|
||
|
if v == '':
|
||
|
return v
|
||
|
try:
|
||
|
return loads(v)
|
||
|
except:
|
||
|
return v
|
||
|
|
||
|
def to_date(self,v):
|
||
|
return v
|
||
|
|
||
|
def to_time(self,v):
|
||
|
return v
|
||
|
|
||
|
def to_timestamp(self,v):
|
||
|
return v
|
||
|
|
||
|
def to_cruddata(self,v):
|
||
|
vs = v.split('"',3)
|
||
|
if vs < 3:
|
||
|
return v
|
||
|
fn = vs[1]
|
||
|
d = CRUDData(fn)
|
||
|
try:
|
||
|
data = d.read()
|
||
|
except Exception as e:
|
||
|
return v
|
||
|
if vs[2] is None:
|
||
|
return data
|
||
|
cmd = "d%s" % vs[2]
|
||
|
ret=eval(cmd,{'d':data})
|
||
|
return ret
|
||
|
|
||
|
def to_xlsxdata(self,v):
|
||
|
vs = v.split('"',3)
|
||
|
if vs < 3:
|
||
|
return v
|
||
|
fn = vs[1]
|
||
|
d = XLSXData(fn)
|
||
|
try:
|
||
|
data = d.read()
|
||
|
except Exception as e:
|
||
|
return v
|
||
|
if vs[2] is None:
|
||
|
return data
|
||
|
cmd = "d%s" % vs[2]
|
||
|
ret=eval(cmd,{'d':data})
|
||
|
return ret
|
||
|
|
||
|
class CRUDException(Exception):
|
||
|
def __init__(self,xlsfile,errmsg,*args,**argv):
|
||
|
Exception.__init__(self,*args,**argv)
|
||
|
self.xlsfile = xlsfile
|
||
|
self.errmsg = errmsg
|
||
|
|
||
|
def __str__(self):
|
||
|
return 'filename:' + self.xlsfile+' error:' + self.errmsg
|
||
|
|
||
|
class XLSXData(object):
|
||
|
def __init__(self,xlsxfile):
|
||
|
atype = type(xlsxfile)
|
||
|
if atype == type('') or atype == type(u''):
|
||
|
self.xlsxfile = xlsxfile
|
||
|
self.book = load_workbook(filename=xlsxfile)
|
||
|
else:
|
||
|
self.book = xlsxfile # is from Factory
|
||
|
|
||
|
def readRecords(self,name,sheet):
|
||
|
i = 1
|
||
|
recs = []
|
||
|
fields = []
|
||
|
tc = TypeConvert()
|
||
|
|
||
|
for i,row in enumerate(sheet.values):
|
||
|
if i==0:
|
||
|
fields = self.getFieldNames(row)
|
||
|
continue
|
||
|
rec = {}
|
||
|
for j, a in enumerate(row):
|
||
|
if a is None:
|
||
|
continue
|
||
|
k = fields[j][0]
|
||
|
v = tc.conv(fields[j][1],a)
|
||
|
rec[k] = v
|
||
|
if rec == {}:
|
||
|
continue
|
||
|
o = DictObject(**rec)
|
||
|
recs.append(o)
|
||
|
return {name:recs}
|
||
|
|
||
|
def read(self):
|
||
|
ret = {}
|
||
|
for i,s in enumerate(self.book.worksheets):
|
||
|
ret.update(self.readRecords(self.book.sheetnames[i], s))
|
||
|
return DictObject(**ret)
|
||
|
|
||
|
def getFieldNames(self,row):
|
||
|
fs = []
|
||
|
for i,f in enumerate(row):
|
||
|
if f is None:
|
||
|
f = 'F_' + str(i)
|
||
|
else:
|
||
|
if type(f) != type(u""):
|
||
|
f = 'F_' + str(f)
|
||
|
"""
|
||
|
else:
|
||
|
f = f.encode('utf-8')
|
||
|
"""
|
||
|
b=f.split(':')
|
||
|
if len(b) < 2:
|
||
|
b.append(None)
|
||
|
fs.append(b)
|
||
|
i+= 1
|
||
|
return fs
|
||
|
|
||
|
class CRUDData(XLSXData):
|
||
|
@classmethod
|
||
|
def isMe(self,book):
|
||
|
names = book.sheetnames
|
||
|
if 'summary' not in names:
|
||
|
return False
|
||
|
if 'fields' not in names:
|
||
|
return False
|
||
|
if 'validation' not in names:
|
||
|
return False
|
||
|
return True
|
||
|
|
||
|
def read(self):
|
||
|
d = XLSXData.read(self)
|
||
|
if not 'summary' in d.keys():
|
||
|
raise CRUDException(self.xlsxfile,'summary sheet missing')
|
||
|
if not 'fields' in d.keys():
|
||
|
raise CRUDException(self.xlsxfile,'fields sheet missing')
|
||
|
if not 'validation' in d.keys():
|
||
|
raise CRUDException(self.xlsxfile,'validation sheet missing')
|
||
|
|
||
|
v = d['summary'][0]['primary']
|
||
|
v = v.split(',')
|
||
|
d['summary'][0]['primary'] = v
|
||
|
d = self.convForeignkey(d)
|
||
|
d = self.convIndex(d)
|
||
|
return d
|
||
|
|
||
|
def convForeignkey(self,data):
|
||
|
vs = data['validation']
|
||
|
nvs = []
|
||
|
for v in vs:
|
||
|
if v['oper'] == 'fk':
|
||
|
m = v['value']
|
||
|
des= m.split(':')
|
||
|
if len(des) != 3:
|
||
|
raise CRUDException(self.xlsxfile,'fk value error:%s' % m)
|
||
|
v['value'] = {'table':des[0],'value':des[1],'title':des[2]}
|
||
|
nvs.append(v)
|
||
|
data['validation'] = nvs
|
||
|
return data
|
||
|
|
||
|
def getFieldByNmae(self,fields,name):
|
||
|
for f in fields:
|
||
|
if f['name'] == name:
|
||
|
return f
|
||
|
|
||
|
def getFKs(self,validation):
|
||
|
fks = []
|
||
|
for v in validation:
|
||
|
if v['oepr'] == 'fk':
|
||
|
fks.append(v)
|
||
|
return fks
|
||
|
|
||
|
def getIDXs(self,validation):
|
||
|
idxs = []
|
||
|
for v in validation:
|
||
|
if v['oper'] == 'idx':
|
||
|
idxs.append(v)
|
||
|
return idxs
|
||
|
|
||
|
def isFieldExist(self,fields,name):
|
||
|
for f in fields:
|
||
|
if f['name'] == name:
|
||
|
return True
|
||
|
return False
|
||
|
|
||
|
def convIndex(self,data):
|
||
|
vs = data['validation']
|
||
|
nvs = []
|
||
|
for v in vs:
|
||
|
if v['oper'] == 'idx':
|
||
|
idx = {}
|
||
|
idx['name'] = v['name']
|
||
|
m = v['value']
|
||
|
des= m.split(':')
|
||
|
if len(des) != 2:
|
||
|
raise CRUDException(self.xlsxfile,'idx value format:idx_type:keylist:%s' % m)
|
||
|
idx['idxtype'] = des[0]
|
||
|
idx['idxfields'] = des[1].split(',')
|
||
|
nvs.append(idx)
|
||
|
data['indexes'] = nvs
|
||
|
return data
|
||
|
|
||
|
def xlsxFactory(xlsxfilename):
|
||
|
def findSubclass(name,klass):
|
||
|
for k in klass.__subclasses__():
|
||
|
if k.isMe(name):
|
||
|
return k
|
||
|
k1 = findSubclass(name,k)
|
||
|
if k1 is not None:
|
||
|
return k1
|
||
|
return None
|
||
|
try:
|
||
|
book = load_workbook(filename=xlsxfilename)
|
||
|
k = findSubclass(book,XLSXData)
|
||
|
if k is not None:
|
||
|
xlsx = k(book)
|
||
|
xlsx.xlsxfile = xlsxfilename
|
||
|
return xlsx
|
||
|
return XLSXData(book)
|
||
|
|
||
|
except Exception as e:
|
||
|
# print(xlsxfilename, 'load failed\n%s' % str(e))
|
||
|
return None
|
||
|
|
||
|
def ValueConvert(s):
|
||
|
if s[:9] == 'xlsfile::':
|
||
|
d = xlsxFactory(s[9:])
|
||
|
return d.read()
|
||
|
if s[:10] == 'jsonfile::':
|
||
|
return loadf(s[10:])
|
||
|
return s
|
||
|
|
||
|
def paramentHandle(ns):
|
||
|
for k,v in ns.items():
|
||
|
ns[k] = ValueConvert(v)
|
||
|
return ns
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
retData = {}
|
||
|
ns = {}
|
||
|
datafiles = []
|
||
|
for a in sys.argv[1:]:
|
||
|
m = a.split('=',1)
|
||
|
if len(m)>1:
|
||
|
ns[m[0]] = m[1]
|
||
|
else:
|
||
|
datafiles.append(a)
|
||
|
|
||
|
ns = paramentHandle(ns)
|
||
|
for f in datafiles:
|
||
|
ext = os.path.splitext(f)[-1]
|
||
|
if ext in ['.xlsx','.xls' ]:
|
||
|
d = xlsxFactory(f)
|
||
|
data = d.read()
|
||
|
retData.update(data)
|
||
|
retData.update(ns)
|
||
|
print( dumps(retData))
|
||
|
|