py2exe and numpy not getting along - python

I am trying to use py2exe-0.6.9.win32 to wrap up an application that I have written in Python2.6.5 using the following object libraries with associated download file names:
matplotlib-0.99.3.win32
numpy-1.4.1-win32
scipy-0.8.0b1-win32
wxPython2.8-win32-unicode-2.8.11.0
I am getting error messages when I try to launch the resulting .exe file. At the moment, the error message is related to numpy, though before that I was getting something related to matplot lib data files not loading and thus blocking the launch of my exe file.
Rather than post a mile of code and all the error messages, I am posting a more general question: Can anyone show me some instructions for making all of these object libraries and versions play well together using py2exe to create a working exe file?
I have been reading things that come up with google searches on the topic, but it seems like a wild goose chase in that everyone is using different versions of different things. I can change some of the versions of some of these object libraries if that makes a difference, but I have already written 5,000 lines of code in this signal processing application, and I would prefer not to have to re-write all of it, if possible.
EDIT:
Here is a simplified version of my code in a file called GUIdiagnostics.py that I made to test the ability of my py2exe script to import all the libraries that I need in my real application:
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()
Here is the code for setup.py, which is the file containing my py2exe code:
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
)
I run this code by typing the following line into the command line interface of windows (cmd.exe) as per the following link:
setup.py py2exe
Py2exe then runs, but when I try to launch the resulting exe file, it creates a log file containing the following message:
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'
Can anyone show me how to edit setup.py so that py2exe can create a usable executable running numpy, scipy, matplotlib, etc.?
SECOND EDIT:
OK. I tried RC's advice again today now that I have a fresh mind for this, and I got the same errorr, but I am including it below. Here is the code for a file called cxsetup.py that I created following the template at: 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")])
Unfortunately, running it in the command line ( cmd.exe ) with the command:
python cxsetup.py build
generates the following error in the command line:
ImportError: No module named cx_Freeze
The directory in the command line is the directory for my application, which is in a subfolder of the desktop. That is different than the directory for the python application, but I assume cmd.exe can figure that out because python can figure it out. Am I wrong? As a test, I added the following line of code to the first line of cxsetup.py :
import matplotlib
But that generated the almost identical error:
ImportError: No module named matplotlib
I have tried to keep this thread focused and short, but it is getting kind of long. Can anyone help me with this? I would hate to do all the work of switching to cx_freeze only to find that it cannot work with numpy, matplotlib, scipy, etc.

Seems like the problem mentioned on the bottom of this: http://www.py2exe.org/index.cgi/MatPlotLib
Looks like you need to make a few small changes to mlab.py:
psd.__doc__ = psd.__doc__ % kwdocd
to
if psd.__doc__ is not None:
psd.__doc__ = psd.__doc__ % kwdocd
else:
psd.__doc__ = ""
If you haven't seen this page already this is how I got there: http://www.py2exe.org/index.cgi/WorkingWithVariousPackagesAndModules

As others have mentioned, py2exe seems to require ugly, random fixes on a case-by-case basis... there appears to be no way around it. Also, some errors refuse to go away, and do not impact the program, but do cause the program to inform the user that an errors log was created after exit. To avoid that, I use this code:
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

This might just me being stupid, but why dont you try to update your scipy from 0.8.0b1 to 0.8.0 and do the same with matplotlib? Numpy 1.4.1 should still be fine.

Related

servable panel app ModuleNotFoundError on included local module

I'm having issues deploying my Panel app to be served up as HTML.
Following instructions at https://panel.holoviz.org/user_guide/Running_in_Webassembly.html, with script.py as
import panel as pn
from mymodule import MyObj
pn.extension('terminal', 'tabulator', sizing_mode="stretch_width")
gspec = pn.GridSpec(sizing_mode='stretch_width', max_height=100, ncols=3)
PI = MyObj()
gspec[0, 0:1] = PI.tabs
gspec[0, 2] = PI.view
pn.Column(
"Text Text Text"
, gspec
).servable()
and mymodule/__init__.py:
__version__ = '0.1.0'
from .my_obj import MyObj
and mymodule/my_obj.py:
from .param_classes import ClassA
from .param_classes import ClassB
# etc
from .compute_obj import ComputeObj
class MyObj(object):
# all the details of the panel build, calling in turn
# param classes detailed in another file, and also calling another module
# to handle all the computation behind the panel
panel serve script.py --autoreload works perfectly, but
$ panel convert script.py --to pyodide-worker --out pyodide
$ python3 -m http.server
does not work. I get a big display at http://localhost:8000/pyodide/script.html: ModuleNotFoundError: no module named 'mymodule', and an infinite loop spinning graphic, and in the Developer Tools Console output:
pyodide.asm.js:10 Uncaught (in promise) PythonError: Traceback (most recent call last):
File "/lib/python3.10/asyncio/futures.py", line 201, in result
raise self._exception
File "/lib/python3.10/asyncio/tasks.py", line 232, in __step
result = coro.send(None)
File "/lib/python3.10/site-packages/_pyodide/_base.py", line 506, in eval_code_async
await CodeRunner(
File "/lib/python3.10/site-packages/_pyodide/_base.py", line 359, in run_async
await coroutine
File "<exec>", line 11, in <module>
ModuleNotFoundError: No module named 'mymodule'
at new_error (pyodide.asm.js:10:218123)
at pyodide.asm.wasm:0xdef7c
at pyodide.asm.wasm:0xe37ae
at method_call_trampoline (pyodide.asm.js:10:218037)
at pyodide.asm.wasm:0x126317
at pyodide.asm.wasm:0x1f6f2e
at pyodide.asm.wasm:0x161a32
at pyodide.asm.wasm:0x126827
at pyodide.asm.wasm:0x126921
at pyodide.asm.wasm:0x1269c4
at pyodide.asm.wasm:0x1e0697
at pyodide.asm.wasm:0x1da6a5
at pyodide.asm.wasm:0x126a07
at pyodide.asm.wasm:0x1e248c
at pyodide.asm.wasm:0x1e00d9
at pyodide.asm.wasm:0x1da6a5
at pyodide.asm.wasm:0x126a07
at pyodide.asm.wasm:0xe347a
at Module.callPyObjectKwargs (pyodide.asm.js:10:119064)
at Module.callPyObject (pyodide.asm.js:10:119442)
at wrapper (pyodide.asm.js:10:183746)
I should add that I'm using poetry to manage packages and build the venv, and I'm operating all the above from within the activated .venv (via poetry shell)
I've tried all the tips and tricks around append the local path to sys.path. Looking at the .js file that the convert utility generates, I gather it would work if all the code were in one file, but forcing bad coding practice doesn't sound right.
I imagine there could be some kind of C++ build-style --include argument to panel convert, but there are no man pages, and the closest I can get with online documentation is --requirements ./mymodule, but no joy.
Could anybody please advise?

How to store the results of a command to a variable?

I'm trying to build a context menu that will show a tree structure of all my packages and their resources. Something like this terrible MS Paint rendering I drew:
I have PackageResourceViewer installed. It offers commands that show in a window. But I would like to use them to populate these sub-context menues:
get_packages_list that I think will populate the first sub-menu (packages)
list_package_files that should populate each subsequent sub-menu
However, I'm not sure how to get the output of these into a context menu. I've been looking at python (writing a sublime plugin for this).
How do I get the output of these commands into a variable?
My Code
import sublime
import sublime_plugin
class ExampleCommand(sublime_plugin.TextCommand):
def run(self, edit):
self.view.insert(edit, 0, package_resource_viewer)
But it gives me this error:
>>> view.window().run_command("example")
Traceback (most recent call last):
File "C:\Program Files\Sublime Text 3\sublime_plugin.py", line 818, in run_
return self.run(edit)
File "C:\Users\heete\AppData\Roaming\Sublime Text 3\Packages\User\hello_world.py", line 7, in run
self.view.insert(edit, 0, package_resource_viewer)
NameError: global name 'package_resource_viewer' is not defined
Obviously I haven't gotten far, but I can't even get the output of this to show in the buffer.
You can import and access those commands. I made a minimal example, which prints the packages to the current view.
However output the to a context/sidebar menu seems to be harder, because they are usually static and you cannot just create one dynamically. (You may try to create a static menu file via a command.)
import sublime_plugin
from PackageResourceViewer.package_resources import (
get_packages_list, list_package_files
)
class ExampleListPackagesCommand(sublime_plugin.TextCommand):
def run(self, edit):
packages = get_packages_list()
insert_sb = []
insert_sb.append("Installed Packages:")
insert_sb.extend(packages)
for package in packages:
insert_sb.append("")
insert_sb.append(package)
package_files = list_package_files(package)
insert_sb.extend("\t" + pf for pf in package_files)
self.view.insert(edit, 0, "\n".join(insert_sb))

keyring module is not included while packaging with py2exe

I am making an app using python 2.7 on windows and keyring-3.2.1 . In my python code on eclipse, I used
import keyring
keyring.set_password("service","jsonkey",json_res)
json_res= keyring.get_password("service","jsonkey")
is working fine as I am storing json response in keyring. But, when I converted python code into exe by using py2exe, it shows import error keyring while making dist. Please suggest how to include keyring in py2exe.
Traceback (most recent call last):
File "APP.py", line 8, in <module>
File "keyring\__init__.pyc", line 12, in <module>
File "keyring\core.pyc", line 15, in <module>
File "keyring\util\platform_.pyc", line 4, in <module>
File "keyring\util\platform.pyc", line 29, in <module>
AttributeError: 'module' object has no attribute 'system'
platform_.py code is :
from __future__ import absolute_import
import os
import platform
def _data_root_Windows():
try:
root = os.environ['LOCALAPPDATA']
except KeyError:
# Windows XP
root = os.path.join(os.environ['USERPROFILE'], 'Local Settings')
return os.path.join(root, 'Python Keyring')
def _data_root_Linux():
"""
Use freedesktop.org Base Dir Specfication to determine storage
location.
"""
fallback = os.path.expanduser('~/.local/share')
root = os.environ.get('XDG_DATA_HOME', None) or fallback
return os.path.join(root, 'python_keyring')
# by default, use Unix convention
data_root = globals().get('_data_root_' + platform.system(), _data_root_Linux)
platform.py code is:
import os
import sys
# While we support Python 2.4, use a convoluted technique to import
# platform from the stdlib.
# With Python 2.5 or later, just do "from __future__ import absolute_import"
# and "import platform"
exec('__import__("platform", globals=dict())')
platform = sys.modules['platform']
def _data_root_Windows():
try:
root = os.environ['LOCALAPPDATA']
except KeyError:
# Windows XP
root = os.path.join(os.environ['USERPROFILE'], 'Local Settings')
return os.path.join(root, 'Python Keyring')
def _data_root_Linux():
"""
Use freedesktop.org Base Dir Specfication to determine storage
location.
"""
fallback = os.path.expanduser('~/.local/share')
root = os.environ.get('XDG_DATA_HOME', None) or fallback
return os.path.join(root, 'python_keyring')
# by default, use Unix convention
data_root = globals().get('_data_root_' + platform.system(), _data_root_Linux)
The issue you're reporting is due to an environment that contains invalid modules, perhaps from an improper installation of one version of keyring over another. You will want to ensure that you've removed remnants of the older version of keyring. In particular, make sure there's no file called keyring\util\platform.* in your site-packages.
After doing that, however, you'll encounter another problem. Keyring loads its backend modules programmatically, so py2exe won't detect them.
To work around that, you'll want to add a 'packages' declaration to your py2exe options to specifically include the keyring.backends package. I invoked the following setup.py script with Python 2.7 to convert 'app.py' (which imports keyring) to an exe:
from distutils.core import setup
import py2exe
setup(
console=['app.py'],
options=dict(py2exe=dict(
packages='keyring.backends',
)),
)
The resulting app.exe will import and invoke keyring.

Create and use settings module in Python

I am new to Python so bear with me. I use the pyDev plugin fore eclipse. There are three files:
tool.py:
from gui import Tool_Window
import wx
import settings
if __name__ == '__main__':
window = wx.App()
Tool_Window(None, settings.WindowHeader)
window.MainLoop()
Tool_Window.py:
from Tool import settings
import wx
class Tool_Window(wx.Frame):
def __init__(self, parent, title):
super(Tool_Window,self).__init__(parent, title = title)
self.SetDimensions(settings.WindowOpenX,
settings.WindowOpenY,
settings.WindowWidth,
settings.WindowHeight)
settings.py:
WindowHeader = 'The SuperAwesome Tool'
WindowOpenX = 500
WindowOpenY = 100
WindowWidth = 200
WindowHeight = 400
The "tool.py" file is in a package called "Tool", as is the "settings.py" file, and "Tool_Window" is in the package "gui".
I am getting error messages from a previous file I had in the project, now renamed to the "settings.py". I have tried cleaning the project in Eclipse, but nothing happens. The error message looks like:
Traceback (most recent call last):
File "/home/oystein/workspaces/python/awesome.tool/src/Tool/tool.py", line 8, in <module>
Tool_Window(None, settings.WindowHeader)
File "/home/oystein/workspaces/python/awesome.tool/src/gui/__init__.py", line 12, in __init__
# ;-)
AttributeError: class GeneralParameters has no attribute 'WindowParameters'
Previously I had a class named GeneralParameters with a sub-class WindowParameters, as I wanted to access static variables for settings. I relaized Python couldn't do it like that and changed it to the "settings.py" file.
I run the program from "tool.py"
Can anyone see what's wrong here?
You are running stale byte-code, remove the .pyc files and rerun your code.
The traceback reads the source from the .py file but is built from the bytecode, and the fact that is shows that the error is on a line that only consists of a comment is a hint that things are no longer in sync.
Normally, Python will clean up the .pyc file when stale, but only if the .py modification time is newer.

Using psyco with py2exe?

In my main script, lets call this MyScript.py, I have it like this:
import psyco
psyco.full()
And then my setup.py looks like this:
from distutils.core import setup
import py2exe, sys, os, glob
sys.argv.append('py2exe')
import psyco #speed up compilation
psyco.full()
def find_data_files(source,target,patterns):
"""Locates the specified data-files and returns the matches
in a data_files compatible format.
source is the root of the source data tree.
Use '' or '.' for current directory.
target is the root of the target data tree.
Use '' or '.' for the distribution directory.
patterns is a sequence of glob-patterns for the
files you want to copy.
"""
if glob.has_magic(source) or glob.has_magic(target):
raise ValueError("Magic not allowed in src, target")
ret = {}
for pattern in patterns:
pattern = os.path.join(source,pattern)
for filename in glob.glob(pattern):
if os.path.isfile(filename):
targetpath = os.path.join(target,os.path.relpath(filename,source))
path = os.path.dirname(targetpath)
ret.setdefault(path,[]).append(filename)
return sorted(ret.items())
setup(
name="MyScript",
version="1.0",
description="a script that does something",
author="Keelx",
data_files=find_data_files('.','',[
'gfx/*',
'data/*',
]),
options={'py2exe': {'bundle_files': 1,'optimize': 2}},
windows=[{'script': "MyScript.py"}],
zipfile=None,
)
It creates a 'dist' folder, with the executable, a win9x executable, and the gfx and data folders next to the executable. However, when I run it it points me to a log which reads:
Traceback (most recent call last):
File "MyScript.py", line 16, in
File "zipextimporter.pyo", line 82, in load_module
File "psyco__init__.pyo", line 64, in
WindowsError: [Error 3] The system cannot find the path specified: 'C:\Documents and Settings\Keelx\Desktop\MyScriptFolder\dist\MyScript.exe\psyco\_psyco.pyd'
It would seem that the psyco module is not being put into the executable. I've been searching, and I haven't found a working solution to get py2exe to copy psyco over.
And please refrain from posting solutions along the lines of 'don't use py2exe'.
Thank you in advance whomever can help me out here.
Hunting down py2exe errors appears to be an art to me.
That said, I will at least offer something to try.
I py2exe'ed a psyco enabled python script and tossed it in the includes part of the setup.
Thats the only part that looks different between your setup and my old one.
options = {'py2exe': {'packages': [ 'IPython'],
'includes': ["psyco"],
}
}
Also I was never able to enable optimize. It always caused random errors. Best to leave that one off in my experience. I think it was matplotlib that caused those errors.
Hope this helps,
Cheers,

Categories