py2exe и numpy не ладят - PullRequest
       14

py2exe и numpy не ладят

7 голосов
/ 04 февраля 2011

Я пытаюсь использовать py2exe-0.6.9.win32, чтобы обернуть приложение, которое я написал в Python2.6.5, используя следующие библиотеки объектов со связанными именами загружаемых файлов:

matplotlib-0.99.3.win32

numpy-1.4.1-win32

scipy-0.8.0b1-win32

wxPython2.8-win32-unicode-2.8.11.0

Я получаю сообщения об ошибках при попытке запустить полученный файл .exe.На данный момент сообщение об ошибке связано с numpy, хотя до этого я получал что-то, связанное с тем, что файлы данных matplot lib не загружались и таким образом блокировали запуск моего exe-файла.

Вместо того, чтобы публиковать милю кода и всех сообщений об ошибках, я задаю более общий вопрос: Может кто-нибудь показать мне некоторые инструкции по совместному использованию всех этих библиотек объектов и версий с помощью py2exe?создать рабочий exe-файл?

Я читал вещи, которые придумали поиски в Google по этой теме, но это похоже на дикую погоню за тем, что все используют разные версии разных вещей.Я могу изменить некоторые версии некоторых из этих библиотек объектов, если это имеет значение, но я уже написал 5000 строк кода в этом приложении для обработки сигналов, и я бы предпочел не переписывать все это, есливозможно.


РЕДАКТИРОВАТЬ:

Вот упрощенная версия моего кода в файле с именем GUIdiagnostics.py, который я сделал, чтобы проверить способность моего py2exeскрипт для импорта всех библиотек, которые мне нужны в моем реальном приложении:

import time
import wxversion
import wx
import csv
import os
import pylab as p
from scipy import stats
import math
from matplotlib import *
from numpy import *
from pylab import *
import scipy.signal as signal
import scipy.optimize
import Tkinter

ID_EXIT = 130

class MainWindow(wx.Frame):
    def __init__(self, parent,id,title):
        wx.Frame.__init__(self,parent,wx.ID_ANY,title, size = (500,500), style =     wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE)

        # A button
        self.button =wx.Button(self, label="Click Here", pos=(160, 120))
        self.Bind(wx.EVT_BUTTON,self.OnClick,self.button)

        # the combobox Control
        self.sampleList = ['first','second','third']
        self.lblhear = wx.StaticText(self, label="Choose TestID to filter:", pos=(20, 75))
        self.edithear = wx.ComboBox(self, pos=(160, 75), size=(95, -1),     choices=self.sampleList, style=wx.CB_DROPDOWN)

        # the progress bar
        self.progressMax = 3
        self.count = 0
        self.newStep='step '+str(self.count)
        self.dialog = None

        #-------Setting up the menu.
        # create a new instance of the wx.Menu() object
        filemenu = wx.Menu()

        # enables user to exit the program gracefully
        filemenu.Append(ID_EXIT, "E&xit", "Terminate the program")

        #------- Creating the menu.
        # create a new instance of the wx.MenuBar() object
        menubar = wx.MenuBar()
        # add our filemenu as the first thing on this menu bar
        menubar.Append(filemenu,"&File")
        # set the menubar we just created as the MenuBar for this frame
        self.SetMenuBar(menubar)
        #----- Setting menu event handler
        wx.EVT_MENU(self,ID_EXIT,self.OnExit)

        self.Show(True)

    def OnExit(self,event):
        self.Close(True)

    def OnClick(self,event):
        try:
            if not self.dialog:
                self.dialog = wx.ProgressDialog("Progress in processing your data.", self.newStep,
                                            self.progressMax,
                                            style=wx.PD_CAN_ABORT
                                            | wx.PD_APP_MODAL
                                            | wx.PD_SMOOTH)
            self.count += 1
            self.newStep='Start'
            (keepGoing, skip) = self.dialog.Update(self.count,self.newStep)
            TestID = self.edithear.GetValue()

            self.count += 1
            self.newStep='Continue.'
            (keepGoing, skip) = self.dialog.Update(self.count,self.newStep)
            myObject=myClass(TestID)
            print myObject.description

            self.count += 1
            self.newStep='Finished.'
            (keepGoing, skip) = self.dialog.Update(self.count,self.newStep)

            self.count = 0

            self.dialog.Destroy()

        except:
            self.dialog.Destroy()
            import sys, traceback
            xc = traceback.format_exception(*sys.exc_info())
            d = wx.MessageDialog( self, ''.join(xc),"Error",wx.OK)
            d.ShowModal() # Show it
            d.Destroy() #finally destroy it when finished

class myClass():
    def __init__(self,TestID):
        self.description = 'The variable name is:  '+str(TestID)+'. '

app = wx.PySimpleApp()
frame = MainWindow(None,-1,"My GUI")
app.MainLoop()

Вот код для setup.py, который является файлом, содержащим мой код py2exe:

from distutils.core import setup
import py2exe

# Remove the build folder, a bit slower but ensures that build contains the latest
import shutil
shutil.rmtree("build", ignore_errors=True)

# my setup.py is based on one generated with gui2exe, so data_files is done a bit differently
data_files = []
includes = []
excludes = ['_gtkagg', '_tkagg', 'bsddb', 'curses', 'pywin.debugger',
        'pywin.debugger.dbgcon', 'pywin.dialogs', 'tcl',
        'Tkconstants', 'Tkinter', 'pydoc', 'doctest', 'test', 'sqlite3'
        ]
packages = ['pytz']
dll_excludes = ['libgdk-win32-2.0-0.dll', 'libgobject-2.0-0.dll', 'tcl84.dll',
            'tk84.dll']
icon_resources = []
bitmap_resources = []
other_resources = []

# add the mpl mpl-data folder and rc file
import matplotlib as mpl
data_files += mpl.get_py2exe_datafiles()

setup(
    windows=['GUIdiagnostics.py'],
                      # compressed and optimize reduce the size
    options = {"py2exe": {"compressed": 2, 
                      "optimize": 2,
                      "includes": includes,
                      "excludes": excludes,
                      "packages": packages,
                      "dll_excludes": dll_excludes,
                      # using 2 to reduce number of files in dist folder
                      # using 1 is not recommended as it often does not work
                      "bundle_files": 2,
                      "dist_dir": 'dist',
                      "xref": False,
                      "skip_archive": False,
                      "ascii": False,
                      "custom_boot_script": '',
                     }
          },

    # using zipfile to reduce number of files in dist
    zipfile = r'lib\library.zip',

    data_files=data_files
)

Я запускаю этот код, введя следующую строку в интерфейс командной строки Windows (cmd.exe) по следующей ссылке:

setup.py py2exe

Затем запускается Py2exe, но когда я пытаюсь запустить полученный exe-файл, он создает файл журнала, содержащий следующее сообщение:

Traceback (most recent call last):
  File "setup.py", line 6, in <module>
  File "zipextimporter.pyo", line 82, in load_module
  File "pylab.pyo", line 1, in <module>
  File "zipextimporter.pyo", line 82, in load_module
  File "matplotlib\pylab.pyo", line 206, in <module>
  File "zipextimporter.pyo", line 82, in load_module
  File "matplotlib\mpl.pyo", line 3, in <module>
  File "zipextimporter.pyo", line 82, in load_module
  File "matplotlib\axes.pyo", line 14, in <module>
  File "zipextimporter.pyo", line 82, in load_module
  File "matplotlib\collections.pyo", line 21, in <module>
  File "zipextimporter.pyo", line 82, in load_module
  File "matplotlib\backend_bases.pyo", line 32, in <module>
  File "zipextimporter.pyo", line 82, in load_module
  File "matplotlib\widgets.pyo", line 12, in <module>
  File "zipextimporter.pyo", line 82, in load_module
  File "matplotlib\mlab.pyo", line 388, in <module>
TypeError: unsupported operand type(s) for %: 'NoneType' and 'dict'

Может кто-нибудь показать мне, как отредактировать setup.py, чтобы py2exe мог создать пригодный для использования исполняемый файл, запущенный numpy, scipy, matplotlib и т. д .?


ВТОРОЕ РЕДАКТИРОВАНИЕ:

ОК.Сегодня я снова попробовал совет RC, так как у меня есть свежий взгляд на это, и я получил ту же ошибку, но я включаю ее ниже.Вот код для файла cxsetup.py, который я создал по шаблону: http://cx -freeze.sourceforge.net / cx_Freeze.html .

from cx_Freeze import setup, Executable

setup(
        name = "Potark",
        version = "0.1",
        description = "My application.",
        executables = [Executable("Potark-ICG.py")])

К сожалению,запуск его в командной строке (cmd.exe) с помощью команды:

python cxsetup.py build

приводит к следующей ошибке в командной строке:

ImportError: No module named cx_Freeze

Каталог в командной строке являетсякаталог для моего приложения, который находится в подпапке рабочего стола.Это отличается от каталога для приложения python, но я полагаю, что cmd.exe может понять это, потому что python может понять это. Я не прав? В качестве теста я добавил следующую строку кода в первую строку cxsetup.py:

import matplotlib

Но это привело к почти идентичной ошибке:

ImportError: No module named matplotlib

Я пытался держать эту тему сфокусированной и короткой, но она становится довольно длинной. Может ли кто-нибудь помочь мне с этим? Я бы не хотел делать всю работу по переключению на cx_freeze только для того, чтобы обнаружить, что он не может работать с numpy, matplotlib, scipy и т. Д.

Ответы [ 3 ]

2 голосов
/ 07 февраля 2011

Похоже, проблема, упомянутая внизу: http://www.py2exe.org/index.cgi/MatPlotLib

Похоже, вам нужно внести несколько небольших изменений в mlab.py:

psd.__doc__ = psd.__doc__ % kwdocd

в

if psd.__doc__ is not None:
    psd.__doc__ = psd.__doc__ % kwdocd
else:
    psd.__doc__ = ""

Если вы еще не видели эту страницу, вот как я туда попал: http://www.py2exe.org/index.cgi/WorkingWithVariousPackagesAndModules

0 голосов
/ 19 марта 2011

Это может быть просто глупость, но почему бы вам не попробовать обновить ваш scipy с 0.8.0b1 до 0.8.0 и сделать то же самое с matplotlib? Numpy 1.4.1 все еще должен быть в порядке.

0 голосов
/ 10 февраля 2011

Как уже упоминали другие, py2exe требует некрасивых, случайных исправлений в каждом конкретном случае ... кажется, что нет никакого способа обойти это. Кроме того, некоторые ошибки отказываются исчезать и не влияют на программу, но заставляют программу сообщать пользователю, что журнал ошибок был создан после выхода. Чтобы избежать этого, я использую этот код:

import sys
IS_USING_PY2EXE = hasattr(sys, "frozen")

# Redirect output to a file if this program is compiled.     
if IS_USING_PY2EXE:
    # Redirect log to a file.
    LOG_FILENAME = os.path.join(logDir, "myfile.log")
    print('Redirecting Stderr... to %s' % LOG_FILENAME)
    logFile = open(os.path.join(LOG_FILENAME),"w") # a --> append, "w" --> write

    sys.stderr = logFile
    sys.stdout = logFile
...