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()
    

分享到: 微信 更多