cx_Freeze应用程序将无法在命令提示符下打开并且不打印任何错误

时间:2019-01-07 00:13:17

标签: python-3.x cx-freeze

首先,我在Windows 10上使用python 3.6.5和cx_Freeze 6.0b1。

我有一个使用wxPython构建的程序,想使用cx_Freeze冻结代码。我已经为此工作了好几天,并且已经阅读了关于此问题的每篇文章,但仍然没有取得成功。在命令提示符下运行.exe或双击该应用程序将不会打开。我也曾尝试在baseNoneConsole之间更改Win32GUI,但均未成功。

这时我要放弃了。我很乐意得到一条错误消息来追逐。

setup.py

import os
import sys
from cx_Freeze import setup, Executable

os.environ['TCL_LIBRARY'] = r'C:\Users\Chad\Anaconda3\Library\lib\tcl8.6'
os.environ['TK_LIBRARY'] = r'C:\Users\Chad\Anaconda3\Library\lib\tk8.6'

include_lst = []
package_lst = ['numpy', 'scipy', 'pulp', 'pubsub', 'sqlite3',
               'numpy.core._methods']
exclude_lst = ['matplotlib', 'tkinter', 'PyQt4.QtSql', 'PyQt5',
               'PyQt4.QtNetwork', 'PyQt4.QtScript', 'sqlalchemy']

base = None

setup (
       name='',
       version='',
       author='',
       author_email='',
       options={'build_exe':
                   {'packages': package_lst,
                    'excludes': exclude_lst,
                   'include_files': include_lst,
                   'include_msvcr': True
                   }
                },
       executables=[Executable('main.py',  base=base, icon=None)]
       )

我可以冻结下面的程序而没有任何问题,所以也许这不是cx_Freeze的问题,而是main.py文件中的问题?

 if __name__.endswith('__main__'):
        print('Hello World')

对于准备一个最小的示例,我深表歉意,但是我不确定该怎么做,因为该程序确实使用了sqlite3 db和内部模块中的21个。但是,在尝试时,我认为问题出在连接数据库,因此下面是一个基本示例,但是如果没有db,我怀疑由于db问题您将可以重现。有了这段代码,一旦冻结,就不会在命令上发生任何事情,它只会转到下一行。

main.py

import util
import wx


class MasterPage (wx.Frame):
    def __init__(self, *args, **kwargs):
        wx.Frame.__init__(self, *args, **kwargs)

        self.conn = util.DataBaseManager.DataBaseManager()

        self.createFrame()

    def createFrame(self):
        self.width, self.height = wx.GetDisplaySize()
        self.SetTitle('Test')
        self.SetSize(wx.Size((self.width-50, self.height-50)))
        self.SetMinSize((1080, 720))
        self.W, self.H = self.GetSize()
        self.Bind(wx.EVT_CLOSE, self.onQuit)
        self.Centre()
        self.statusbar = self.CreateStatusBar(2)
        self.statusbar.SetStatusWidths([self.W * 67, self.W * .23])

    def onQuit(self, event):
        """Checks to make sure the user wants to leave the program"""
        dlg = wx.MessageDialog(self,'Do you really want to quit?',
                               'Confirm Exit',
                                wx.ICON_QUESTION|wx.OK|wx.CANCEL )
        result = dlg.ShowModal()
        dlg.Destroy
        if result == wx.ID_OK:
                self.Destroy()

if __name__.endswith('__main__'):
    app = wx.App()
    MasterPage(None).Show()
    app.MainLoop()

util.DataBaseManager.py

import pandas as pd
import sys
import os
import sqlite3


class DataBaseManager(object):

    def __init__(self):
        """Creates a connection to the database requested"""
        try:
            self.db = self.findDataPath('master.db')
            self.conn = sqlite3.connect(self.db)
            self.cursor = self.conn.cursor()
        except sqlite3.Error as e:
            print(e)

    def executePandasQuery(self, sql_statement):
        self.df = pd.read_sql_query(sql_statement, self.conn)
        self.conn.commit()
        return self.df

    def executeCursorQuery(self, sql_statement, values):
        if values == 'na':
            self.cursor.execute(sql_statement)
        else:
            self.cursor.execute(sql_statement, values)
        self.conn.commit()
        return self.cursor

    def __del__(self):
        self.conn.close()

    def findDataPath(self, filename):
        """
        Get the correct path for outside data works with cx_freeze
        :params str filename: the filename looking for
        :returns: the absolute path of the file.
        :rtype: string
        """
        if getattr(sys, 'frozen', False):
            # The application is frozen
            p = os.path.abspath(os.path.dirname(sys.argv[0]))
            p = '{}\{}'.format(p,filename)
        else:
            # The application is not frozen
            p = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
            p = '{}\{}'.format(p,filename)
        return p

编辑#2

我认为这是导入自定义模块util时遇到的问题。如果我在import util中的main.py前面放了一条打印语句,则该打印语句将运行,但应用程序将关闭,命令提示符转到下一行。

1 个答案:

答案 0 :(得分:0)

关于连接数据库的问题:如何在冻结的应用程序中创建数据库文件master.db,该文件位于何处?查看您发布的代码,我了解以下内容:

  • 在非冻结应用程序中,master.db文件位于util软件包目录的父目录(这是主应用程序目录)中

  • 您不会告诉cx_Freezemaster.db文件明确包含在构建目录中。由于此文件位于主应用程序目录中,因此不会自动包含在cx_Freeze中(请查看构建目录以查看是否看到该文件)。

我至少看到了两种解决方案:

  1. master.db文件移动到非冻结应用程序的util软件包目录中。 cx_Freeze应该包括整个util目录,其中包括数据库文件。将您的findDataPath函数更改为:

    def findDataPath(self, filename):
        """
        Get the correct path for outside data works with cx_freeze
        :params str filename: the filename looking for
        :returns: the absolute path of the file.
        :rtype: string
        """
    
        p = os.path.dirname(os.path.abspath(__file__))
        p = os.path.join(p, filename)
        return p
    

    这对于非冻结应用程序和冻结应用程序都应该起作用。 (备注:使用os.path.join以与平台无关的方式连接路径)。

  2. master.db文件保留在非冻结应用程序的主目录中,并告诉cx_Freeze将数据库文件包含到lib的{​​{1}}子目录中目录,它是冻结应用程序中build软件包目录的父目录。您可以通过将元组(utilcx_Freeze)传递到设置脚本中source列表选项的相应条目,来使destination将文件包含到特定位置:

    include_files

    将您的include_lst = [('master.db', os.path.join('lib', 'master.db'))] 函数更改为:

    findDataPath

    这对于非冻结应用程序和冻结应用程序也都适用。