python打包exe 转表工具 高版本twisted zope.interface pyinstaller
注意事项:1.最好用pyinstaller1.5或者3.2.1【注意3.2.1不能像1.5那样在文件夹中使用,需要安装】, ancondapython和原生态python都没有问题,win7下测试;
2.报错找不到包,import xx.包名即可,如果这样都找不到,检测包层级关系里面有没有__init__.py文件,或者__init__.py文件里面的代码有没有问题,空白的最好
3.注意代码里面的方法getpwd()的使用,里面有各种pyinstaller获取本地路径的方法
4.注意代码头里面的des描述
5. 高版本的无法找到module,那么pyinstaller --onefile --hiddern-import=zope.interface theano_test.py
# coding=utf-8 u""" win7和win10都能打包成功 python2.7.5 64位--Anaconda的python也可以 twisted13.10, 如果是高版本的twisted>14 我用的17.1,会报tls找不到,这是因为twisted\protocols\__init__.py里面做了警告,将__init__.py的里面的代码注释掉即可打包 这个和zope.interface找不到是一个原因 wxpython2.9 pycrypto2.6.1 如果要想用pyinstaller1.5打包exe成功-----easy_install zope.interface==3.6, 默认是最高版本,但是不能打包exe pip install twisted 注意:1.pyinstall缺啥module就import啥,有的module没有__init__.py要加上 2.pyinstall1.5 按照上面的步骤没有问题 3.pyinstall3.2.1 也没有问题,但是需要注释掉twisted.internet.main.installReactor的这两句 ####################### if 'twisted.internet.reactor' in sys.modules: raise error.ReactorAlreadyInstalledError("reactor already installed") ######################## """ import zope.interface # 打包exe需要添加这句---用debug模式,找到site-package下面的zope,加入__init__.py文件,这个很重要 #高版本twited #end--高版本twisted import wx, time, xlrd, os, re, copy, json, sys import wx.lib.filebrowsebutton as filebrowse from twisted.internet import wxreactor wxreactor.install() from twisted.internet import reactor, protocol from twisted.protocols import basic import sys, os, traceback, base64 import wx.lib.dialogs,Crypto import Crypto.Cipher from Crypto.Cipher import DES import httplib import time import os dk = b'iupdqxy2' block_key = "fds84kjfdllaaf47e" class Et(Exception): """ @author: yuanxiao @date: 2010-6-10 @des: 自定义事物中的错误 """ def __init__(self, state, v, *args, **kwas): """ """ super(Et, self).__init__(*args, **kwas) self._msg = v self.state = state @property def msg(self): return self._msg def get_webservertime(host): conn=httplib.HTTPConnection(host) conn.request("GET", "/") r=conn.getresponse() #r.getheaders() #获取所有的http头 ts= r.getheader('date') #获取http头date部分 #将GMT时间转换成北京时间 ltime= time.strptime(ts[5:25], "%d %b %Y %H:%M:%S") # print(ltime) ttime=time.localtime(time.mktime(ltime)+8*60*60) # print(ttime) dat="date %u-%02u-%02u"%(ttime.tm_year,ttime.tm_mon,ttime.tm_mday) tm="time %02u:%02u:%02u"%(ttime.tm_hour,ttime.tm_min,ttime.tm_sec) # print (dat,tm) os.system(dat) os.system(tm) return ttime import datetime import time def gettimestamp(): tmm = get_webservertime('www.baidu.com') t = datetime.datetime(tmm.tm_year,tmm.tm_mon,tmm.tm_mday, tmm.tm_hour, tmm.tm_min,tmm.tm_sec) timestamp = time.mktime(t.timetuple()) return timestamp class SqChFrame(wx.Frame): def __init__(self, parent, id): wx.Frame.__init__(self, parent, id, title=u'数据转换', size=(600, 300)) self.SetMaxSize((600, 300)) # 不允许拖动和放大 self.SetMinSize((600, 300)) # 不允许拖动和放大 panel = MyPanel(self) class MyPanel(wx.Panel): def __init__(self, parent, id=-1): self.yx_debugs = [] # 记录bug信息 wx.Panel.__init__(self, parent, id) # 目标 self.dirBrowser = filebrowse.DirBrowseButton(self, -1, size=(300, 40), pos=(212, 10), labelText=u'需要转换: ', buttonText=u"选择") # end 目标 # 主界面 self.cc1 = wx.CheckBox(self, -1, u"cpp", size=(50, 40), name=u"c1") self.cc1.SetValue(True) # 设置复选框选框默认值 self.cc1_fb = wx.RadioBox(self, -1, u"", size=(100, 40), choices=[u"前台", u"后台"], name=u"c1_fb") self.cc1_fb.SetSelection(0) # 设置单选框默认值 # print self.cc1_fb.GetItemLabel(self.cc1_fb.GetSelection()) #获取单选框选择的值 self.newTxtBox1 = filebrowse.DirBrowseButton(self, -1, size=(300, 40), labelText=u' 输出到: ', buttonText=u"选择") self.cc2 = wx.CheckBox(self, -1, u"py", size=(50, 40), name=u"c2") self.cc2.SetValue(True) self.cc2_fb = wx.RadioBox(self, -1, u"", size=(100, 40), choices=[u"前台", u"后台"], name=u"c2_fb") self.cc2_fb.SetSelection(1) self.newTxtBox2 = filebrowse.DirBrowseButton(self, -1, size=(300, 40), labelText=u' 输出到: ', buttonText=u"选择") self.cc3 = wx.CheckBox(self, -1, u"as", size=(50, 40), name=u"c3") self.cc3_fb = wx.RadioBox(self, -1, u"", size=(100, 40), choices=[u"前台", u"后台"], name=u"c3_fb") self.cc3_fb.SetSelection(0) self.newTxtBox3 = filebrowse.DirBrowseButton(self, -1, size=(300, 40), labelText=u' 输出到: ', buttonText=u"选择") mySizer = wx.FlexGridSizer(cols=3, hgap=6, vgap=6) mySizer.AddMany([self.cc1, self.cc1_fb, self.newTxtBox1, self.cc2, self.cc2_fb, self.newTxtBox2, self.cc3, self.cc3_fb, self.newTxtBox3, ]) border = wx.BoxSizer(wx.VERTICAL) border.Add(mySizer, 0, wx.ALL, 50) # 控制mySizer的位置--50用来控制 self.SetSizer(border) self.SetAutoLayout(True) # end 主界面 # 按钮 self.ok = wx.wx.Button(self, -1, u"确定", pos=(410, 200), size=(100, 40), name=u"ok") self.Bind(wx.EVT_BUTTON, self.makeData, self.ok) # end 按钮 self.Bind(wx.EVT_CLOSE, self.OnCloseWindow) def makeData(self, event): """ 用非阻塞方式调用---防止连点 """ reactor.callInThread(self._makeData) def _makeData(self): try: errorMeg = '' self.ok.Disable() self.yx_version = str(time.time()) # 在这里进行版本号生成,保证每次makedata的版本号都不一样 #self.yx_version = str(gettimestamp()) print 'version',self.yx_version road = self.dirBrowser.GetValue() # road = "D:\yx\workspace\makedata" datas = self.listFolder(road) if self.cc1.Value: fb = self.cc1_fb.GetItemLabel(self.cc1_fb.GetSelection()) self.makeCppData(datas, fb) if self.cc2.Value: fb = self.cc2_fb.GetItemLabel(self.cc2_fb.GetSelection()) self.makePythonData(datas, fb) if self.cc3.Value: fb = self.cc3_fb.GetItemLabel(self.cc3_fb.GetSelection()) self.makeAsData(datas, fb) self.ok.Enable() # 消息提示 dlg = wx.MessageDialog(self, u'转换成功', u'消息', wx.OK | wx.ICON_INFORMATION ) dlg.ShowModal() dlg.Destroy() # end---消息提示 except Et, e: errorMeg += e.msg except Exception, e: errorMeg += 'error' finally: if errorMeg: # 消息提示 try: for file, lineno, function, text in traceback.extract_tb(sys.exc_info()[2]): errorMeg += '%s\n%s, in %s\n%s: %s!' % (str(e), file, function, lineno, text) try: errorMeg += "\n****************\n%s" % sys.exc_info()[1].text except Exception, e: pass errorMeg += "\n****************\n%s:%s" % (self.yx_debugs[-1].get('excelName', 'nofile'), self.yx_debugs[-1]) errorMeg = errorMeg.encode('utf-8') except Exception, e1: pass reactor.callFromThread(self.msg, u'消息', u"转换失败:%s" % errorMeg.decode("utf8")) # end---消息提示 self.ok.Enable() def msg(self, title, content, size=(500, 300)): """ @des: 关键,这种滚动对话框必须放在callFromThread执行,否则会在缩放的时候卡死 """ dlg = wx.lib.dialogs.ScrolledMessageDialog(self, content, title, style=wx.OK | wx.ICON_INFORMATION, size=size # wx.YES_NO | wx.NO_DEFAULT | wx.CANCEL | wx.ICON_INFORMATION ) dlg.ShowModal() dlg.Destroy() def makePublicData(self, datas, fb): mydatas = { 'Version':{ "1":{"c_value":self.yx_version} } } # 版本号 for data in datas: mydata = {} for className, alls in data.items(): if 0: if className.strip()=="": print self.yx_debugs[-1].get('excelName', 'no name') mydata[className] = {} for row in alls: mydata_row = {} for item in row: if 0:#寻找excelName if className=='NewYearActivity1_Extra': print item['excelName'] self.yx_debugs.append(item) # 记录出bug的位置 if (fb == u"前台" and item['ztype'] in ['all', 'front']) or \ (fb == u"后台" and item['ztype'] in ['all', 'back']): iv = item['value'] ty = item['type'] try: length = int(item['length']) except Exception, e: length = 2 if ty == 'int': iv = int(iv) elif ty == 'float': fs = '%%.%sf' % length iv = float(fs % iv) elif ty == 'list': if iv.strip() == '': iv = "[]" iv = iv.replace(u",", u",") iv = eval(iv) elif ty == 'dict': if iv.strip() == '': iv = "{}" iv = iv.replace(u",", u",") iv = eval(iv) elif ty == 'string': iv = "%s" % iv # if len(iv) > length + 2: # raise u"字符串长度太长" # mydata_row.append({item['var']:iv}) # 如果编码有问题,修改这里--原来是unicode mydata_row[item['var']] = iv else: continue if mydata_row.has_key('c_id'):#这里不用判断c_id是否有重复,因为listforder已经判断过了 sc_id = str(mydata_row['c_id']) mydata[className][sc_id] = mydata_row if not mydatas.has_key(className):#判断className是否为空 mydatas.update(mydata) elif className=='des': pass else: raise Et, (2, "%s is exists"%className) #精简 u""" @des: mydatas结构 { 'ClassName':{ '1':{'c_v':5000, 'c_s':1000} } } 变为 { 'ClassName':{ 'sts':['c_v', 'c_s'], 'sds':{ '1':[5000,1000], } } } """ realdatas = {} for classname,olddata in mydatas.items(): _stss = [] #判断结构是否一致 #判断属性值是否一致 for c_id, values in olddata.items(): _sts = values.keys() _sts.sort() _sts = json.dumps(_sts) _stss.append(_sts) _stss = list(set(_stss)) if len(_stss)>1: raise Et, (3, u"%s struct not sample %s"%(classname,_stss)) if len(_stss)==0: continue #end--判断属性值是否一致 #拼接数据 sts = json.loads(_stss[0]) #获取真正的结构 realdatas[classname] = {'sts':sts, 'sds':{}} sds = realdatas[classname]['sds'] for c_id, values in olddata.items(): sds[c_id] = [] #这里不用判断c_id是否有重复,因为listforder已经判断过了 for i,st in enumerate(sts): sds[c_id].append(values[st]) #end--拼接数据 #end--精简 #return mydatas return realdatas def getpwd(self): """ @des:获取程序运行的路径 """ if os.getcwd() == sys.path[0]: # 说明是直接运行py,没有用pyinstaller1.5打包成exe return os.getcwd() else: if len(sys.path)>1:# 说明是pyinstaller1.5打包成exe的文件在运行 return sys.path[1] else:# 说明是pyinstaller3.2.1打包成exe的文件在运行 return os.getcwd() def _transterPlainText(self, plainText): """ @DES:转换 """ plaintext = u'%s' % plainText plaintext = plaintext.encode('utf8') striplen = (len(plaintext) % 8) if striplen == 0: striplen = 8 plaintext = '%s%s' % (plaintext, ' ' * (8 - striplen)) return plaintext def encrypt(self, plainText): """ @DES:加密 """ plainText = self._transterPlainText(plainText) # do encrypt _encrypt = DES.new(dk, DES.MODE_ECB).encrypt return _encrypt(plainText) def decrypt(self, cipherText): """ @des:解密 """ _decrypt = DES.new(dk, DES.MODE_ECB).decrypt return _decrypt(cipherText).strip() def makeCppData(self, datas, fb): mydatas = self.makePublicData(datas, fb) p = self.newTxtBox1.GetValue() #保存到文件 if p: f = open(os.path.join(p, "cpp_config.json"), 'w') else: ps = self.getpwd() f = open(os.path.join(ps, "cpp_config.json"), 'w') f.write(json.dumps(mydatas,separators=(',',':'))) f.close() # end--保存到文件 #modify by yx # 保存加密文件 if 1: filename = "cpp_config.block.encrypt.json" if p: f = open(os.path.join(p, filename), 'wb') #todo------win上用wb,不知道linux上是否wb能通过 else: ps = self.getpwd() f = open(os.path.join(ps, filename), 'wb')#todo------win上用wb,不知道linux上是否wb能通过 #加密 if 0:#当数据特别大的时候用这个 if p: cpp_config_f = open(os.path.join(p, "cpp_config.json"), 'r') else: ps = self.getpwd() cpp_config_f = open(os.path.join(ps, "cpp_config.json"), 'r') data = cpp_config_f.read(10 * 1024) while data: f.write(self.encrypt(data)) data = cpp_config_f.read(10 * 1024) cpp_config_f.close() if 1: for classname in mydatas.keys(): block = {} block[classname] = mydatas[classname] f.write(self.encrypt(json.dumps(block,separators=(',',':')))) f.write(self.encrypt("%s"%block_key)) # edata = self.encrypt(json.dumps(mydatas,separators=(',',':'))) # f.write(edata) #print self.decrypt(edata) #end--加密 f.close() #end--保存加密文件 if 0: #保存到普通文件 filename = "cpp_config.no_json_%s.json"%self.yx_version if p: f = open(os.path.join(p, filename), 'w') else: ps = self.getpwd() f = open(os.path.join(ps, filename), 'w') f.write(json.dumps(mydatas,separators=(',',':'))) f.close() #end--保存到普通文件 if 1:#保存到分段文件-不加密 filename = "cpp_config.block.json" if p: f = open(os.path.join(p, filename), 'w') else: ps = self.getpwd() f = open(os.path.join(ps, filename), 'w') for classname in mydatas.keys(): block = {} block[classname] = mydatas[classname] f.write(json.dumps(block,separators=(',',':'))) f.write("%s"%block_key) f.close() #end--保存到分段文件-不加密 #end--modify by yx def makePythonData(self, datas, fb): mydatas = self.makePublicData(datas, fb) p = self.newTxtBox2.GetValue() if p: f = open(os.path.join(p, "py_config.py"), 'w') else: ps = self.getpwd() f = open(os.path.join(ps, "py_config.py"), 'w') f.write(json.dumps(mydatas, separators=(',',':'))) f.close() # end--保存到文件 def makeAsData(self, datas, fb): mydatas = self.makePublicData(datas, fb) p = self.newTxtBox3.GetValue() if p: f = open(os.path.join(p, "as_config.json"), 'w') else: ps = self.getpwd() f = open(os.path.join(ps, "as_config.json"), 'w') f.write(json.dumps(mydatas,separators=(',',':'))) f.close() def listFolder(self, road): """ 遍历文件夹---分析excel """ # 寻找所有的excel文件 alls = [] datas = [] # [{'City':[[{"k":'id_1',"v":1,"type":"int"},],]}] find_file = re.compile(r"\.xls[x]{0,1}$") # 正则表达式来寻找以**结尾的文件 for root , dirs, files in os.walk(road): for file in files: if find_file.search(file) and file.find("~$") == -1: # 防止打开文件 alls.append("%s " % (root + '\\' + file)) # end--寻找所有的excel文件 # 遍历excel数据 for ex in alls: data = xlrd.open_workbook(ex) debug_file_name = os.path.basename(ex) # 输出debug信息 for sheet_name in data.sheet_names(): self.yx_debugs.append({'excelName':"%s-%s" % (debug_file_name, sheet_name)}) # 记录debug信息 mydata = {} # 获取sheet名称,留为生成表的主键 table = data.sheet_by_name(sheet_name) # end--获取sheet名称,留为生成lua表的主键 # 总行数和总列数 row_count = table.nrows col_count = table.ncols # end--总行数和总列数 # 有效行数 valid_row_count = len(table.col_values(0)) # end--有效行数 # 有效列数,判断依据:标题行如果有一个单元格内容为空,则视为结束 valid_col_count = 0 for item in table.row_values(0): if item.strip(): valid_col_count = valid_col_count + 1 else: break # end--有效列数,判断依据:标题行如果有一个单元格内容为空,则视为结束 # 获取数据 head = table.row_values(0)[0] className = head.split(",")[0] className = className.strip() mydata[className] = [] cids = [] # cid重复校验 for rowindex in range(2, valid_row_count): row = table.row_values(rowindex) if row and [ri for ri in row if ri]: # 判断空行,空行不处理 rdata = [] for colindex in range(0, valid_col_count): chead = table.row_values(0)[colindex] ddc = {} var = chead.split(",")[1] type = chead.split(",")[2] length = chead.split(",")[3] ztype = chead.split(",")[4] # 平台类型,all---前后台都有,front--前台,end---后台 ddc['var'] = "%s" % (var) ddc['type'] = type ddc['length'] = length ddc['ztype'] = ztype ddc['value'] = row[colindex] ddc['excelName'] = "%s-%s" % (debug_file_name, sheet_name) # 记录debug位置信息 rdata.append(ddc) # cid重复校验 if var == 'c_id': cids.append(row[colindex]) # end--#cid重复校验 mydata[className].append(rdata) # cid校验 repeats = [cid for cid in cids if cids.count(cid) != 1] if repeats: self.yx_debugs.append({'excelName':"%s-%s-%s" % (debug_file_name, sheet_name, 'c_id repeat %s' % set(repeats))}) # 记录debug信息 raise # end--cid校验 # end--获取数据 datas.append(mydata) # #end---遍历excel数据 # import pprint # pprint.pprint(datas) return datas def OnCloseWindow(self, event): reactor.stop() self.Destroy() if __name__ == '__main__': # app = wx.PySimpleApp() # frame = SqChFrame(parent=None, id=-1) # frame.Show() # app.MainLoop() app = wx.App(False) frame = SqChFrame(parent=None, id=-1) frame.Show() reactor.registerWxApp(app) reactor.run()