py2exe и numpy не ладят
Я пытаюсь использовать py2exe-0.6.9.win32, чтобы обернуть приложение, которое я написал в Python2.6.5, используя следующие библиотеки объектов со связанными именами загружаемых файлов:
Matplotlib-0.99.3.win32
SciPy-0.8.0b1-win32
wxPython2.8-win32-юникод-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 ответа
Похоже, проблема упоминается в нижней части этого: 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
Это может быть просто глупость, но почему бы вам не попробовать обновить ваш scipy с 0.8.0b1 до 0.8.0 и сделать то же самое с matplotlib? Numpy 1.4.1 все еще должен быть в порядке.
Как уже упоминали другие, 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