I have a program that uses the win32com library to control iTunes, but have been having some issues getting it to compile into an executable. The problem seems to revolve around using DispatchWithEvents instead of Dispatch. I've created a very simple program to illustrate my problem:
import win32com.client
win32com.client.gencache.is_readonly = False #From py2exe wiki
class ITunesEvents(object):
def __init__(self): self.comEnabled = True
def OnCOMCallsDisabledEvent(self, reason): self.comEnabled = False
def OnCOMCallsEnabledEvent(self): self.comEnabled = True
# The first line works in the exe, the second doesn't.
itunes = win32com.client.Dispatch("iTunes.Application")
#itunes = win32com.client.DispatchWithEvents("iTunes.Application", ITunesEvents)
lib = getattr(itunes, "LibraryPlaylist")
src = getattr(lib, "Source")
playlists = getattr(src, "Playlists")
print "Found %i playlists." % getattr(playlists, "Count")
Using Dispatch, the program compiles and runs correctly. Using DispatchWithEvents, the program runs fine when called from the command line, but produces the following error when running the exe:
Traceback (most recent call last):
File "sandbox.py", line 16, in <module>
itunes = win32com.client.DispatchWithEvents("iTunes.Application", ITunesEvents)
File "win32com\client\__init__.pyc", line 252, in DispatchWithEvents
File "win32com\client\gencache.pyc", line 520, in EnsureModule
File "win32com\client\gencache.pyc", line 287, in MakeModuleForTypelib
File "win32com\client\makepy.pyc", line 259, in GenerateFromTypeLibSpec
File "win32com\client\gencache.pyc", line 141, in GetGeneratePath
IOError: [Errno 2] No such file or directory: '[distDir]\\library.zip\\win32com\\gen_py\\__init__.py'
I've also tried using PyInstaller, which gives a similar error:
File "<string>", line 16, in <module>
File "[outDir]/win32com.client", line 252, in DispatchWithEvents
File "[outDir]/win32com.client.gencache", line 520, in EnsureModule
File "[outDir]/win32com.client.gencache", line 287, in MakeModuleForTypelib
File "[outDir]/win32com.client.makepy", line 286, in GenerateFromTypeLibSpec
File "[outDir]/win32com.client.gencache", line 550, in AddModuleToCache
File "[outDir]/win32com.client.gencache", line 629, in _GetModule
File "[pyinstallerDir]\iu.py", line 455, in importHook
raise ImportError, "No module named %s" % fqname
ImportError: No module named win32com.gen_py.9E93C96F-CF0D-43F6-8BA8-B807A3370712x0x1x13
I know I can manually add the typelib in my setup.py file, but I'd like to run the code on computers with different versions of iTunes without recompiling so I'd prefer to dynamically create it. If there's no way to do this with the setup/spec, maybe there is another way to load the events? Thanks.
Addition:
Thanks to Ryan, I found I could take the generated py file and after a little digging, was able to come up with the following.
Take the generated py file (from makepy.py) and rename it somewhere like cominterface.py. Then you'll need to do the following to actually create the COM object with event handler.
import cominterface
from types import ClassType
from win32com.client import EventsProxy, _event_setattr_
class ItunesEvents:
'''iTunes events class. See cominterface for details.'''
def OnPlayerPlayEvent(self, t):print "Playing..."
def OnPlayerStopEvent(self, t): print "Stopping..."
itunes = cominterface.iTunesApp()
rClass = ClassType("COMEventClass", (itunes.__class__, itunes.default_source, ItunesEvents), {'__setattr__': _event_setattr_})
instance = rClass(itunes._oleobj_)
itunes.default_source.__init__(instance, instance)
#ItunesEvents.__init__(instance) #Uncomment this line if your events class has __init__.
itunes = EventsProxy(instance)
Then you can go about your business.
I was experiencing the exact same error.
This link put me in the right direction -->
http://www.py2exe.org/index.cgi/UsingEnsureDispatch
however it mentions that :
NB You must ensure that the python...\win32com.client.gen_py dir does not exist
to allow creation of the cache in %temp%
Which was a bit confusing.
What solved it for me was renaming "C:\Python26\Lib\site-packages\win32com\gen_py" to "C:\Python26\Lib\site-packages\win32com\gen_pybak" (when running py2exe)
This is the official way to do it.
(Edit: copied verbatim example from that link above)
import win32com.client
if win32com.client.gencache.is_readonly == True:
#allow gencache to create the cached wrapper objects
win32com.client.gencache.is_readonly = False
# under p2exe the call in gencache to __init__() does not happen
# so we use Rebuild() to force the creation of the gen_py folder
win32com.client.gencache.Rebuild()
# NB You must ensure that the python...\win32com.client.gen_py dir does not exist
# to allow creation of the cache in %temp%
# Use SAPI speech through IDispatch
from win32com.client.gencache import EnsureDispatch
from win32com.client import constants
voice = EnsureDispatch("Sapi.SpVoice", bForDemand=0)
voice.Speak( "Hello World.", constants.SVSFlagsAsync )
Instead of depending on the cache, I'd recommend going into the local cache directory, copying the generated file into your local project file, and naming it something like ITunesInterface.py, and calling to that explicitly. This will make py2exe pull it into your compiled app.
Related
I have a simple program that takes input from the user and then does scraping with selenium. Since the user doesn't have Python environment installed I would like to convert it to *.exe. I usually use cx_freeze for that and I have successfully converted .py programs to .exe. At first it was missing some modules (like lxml) but I was able to solve it. Now I think I only have problem with docx package.
This is how I initiate the new document in my program (I guess this is what causes me problems):
doc = Document()
#then I do some stuff to it and add paragraph and in the end...
doc.save('results.docx')
When I run it from python everything works fine but when I convert to exe I get this error:
Traceback (most recent call last):
File "C:\Users\tyszkap\AppData\Local\Continuum\Anaconda3\lib\site-packages\cx_Freeze\initscripts\Console.py", line 27, in <module>
exec(code, m.__dict__)
File "tribunalRio.py", line 30, in <module>
File "C:\Users\tyszkap\AppData\Local\Continuum\Anaconda3\lib\site-packages\docx\api.py", line 25, in Document
document_part = Package.open(docx).main_document_part
File "C:\Users\tyszkap\AppData\Local\Continuum\Anaconda3\lib\site-packages\docx\opc\package.py", line 116, in open
pkg_reader = PackageReader.from_file(pkg_file)
File "C:\Users\tyszkap\AppData\Local\Continuum\Anaconda3\lib\site-packages\docx\opc\pkgreader.py", line 32, in from_file
phys_reader = PhysPkgReader(pkg_file)
File "C:\Users\tyszkap\AppData\Local\Continuum\Anaconda3\lib\site-packages\docx\opc\phys_pkg.py", line 31, in __new__
"Package not found at '%s'" % pkg_file
docx.opc.exceptions.PackageNotFoundError: Package not found at 'C:\Users\tyszkap\Dropbox (Dow Jones)\Python Projects\build\exe.win-a
md64-3.4\library.zip\docx\templates\default.docx'
This is my setup.py program:
from cx_Freeze import setup, Executable
executable = Executable( script = "tribunalRio.py" )
# Add certificate to the build
options = {
"build_exe": {'include_files' : ['default.docx'],
'packages' : ["lxml._elementpath", "inspect", "docx", "selenium"]
}
}
setup(
version = "0",
requires = [],
options = options,
executables = [executable])
I thought that explicitly adding default.docx to the package would solve the problem (I have even tried adding it to the library.zip but it gives me even more errors) but it didn't. I have seen this post but I don't know what they mean by:
copying the docx document.py module inside my function (instead of
using Document()
Any ideas? I know that freezing is not the best solution but I really don't want to build a web interface for such a simple program...
EDIT:
I have just tried this solution :
def find_data_file(filename):
if getattr(sys, 'frozen', False):
# The application is frozen
datadir = os.path.dirname(sys.executable)
else:
# The application is not frozen
# Change this bit to match where you store your data files:
datadir = os.path.dirname(__file__)
return os.path.join(datadir, filename)
doc = Document(find_data_file('default.docx'))
but again receive Traceback error (but the file is in this location...):
Traceback (most recent call last):
File "C:\Users\tyszkap\AppData\Local\Continuum\Anaconda3\lib\site-packages\cx_Freeze\initscripts\Console.py", line 27, in <module>
exec(code, m.__dict__)
File "tribunalRio.py", line 43, in <module>
File "C:\Users\tyszkap\AppData\Local\Continuum\Anaconda3\lib\site-packages\docx\api.py", line 25, in Document
document_part = Package.open(docx).main_document_part
File "C:\Users\tyszkap\AppData\Local\Continuum\Anaconda3\lib\site-packages\docx\opc\package.py", line 116, in open
pkg_reader = PackageReader.from_file(pkg_file)
File "C:\Users\tyszkap\AppData\Local\Continuum\Anaconda3\lib\site-packages\docx\opc\pkgreader.py", line 32, in from_file
phys_reader = PhysPkgReader(pkg_file)
File "C:\Users\tyszkap\AppData\Local\Continuum\Anaconda3\lib\site-packages\docx\opc\phys_pkg.py", line 31, in __new__
"Package not found at '%s'" % pkg_file
docx.opc.exceptions.PackageNotFoundError: Package not found at 'C:\Users\tyszkap\Dropbox (Dow Jones)\Python Projects\build\exe.win-a
md64-3.4\default.docx'
What am I doing wrong?
I expect you'll find the problem has to do with your freezing operation not placing the default Document() template in the expected location. It's stored as package data in the python-docx package as docx/templates/default.docx (see setup.py here: https://github.com/python-openxml/python-docx/blob/master/setup.py#L37)
I don't know how to fix that in your case, but that's where the problem is it looks like.
I had the same problem and managed to get around it by doing the following. First, I located the default.docx file in the site-packages. Then, I copied it in the same directory as my .py file. I also start the .docx file with Document() which has a docx=... flag, to which I assigned the value: os.path.join(os.getcwd(), 'default.docx') and now it looks like doc = Document(docx=os.path.join(os.getcwd(), 'default.docx')). The final step was to include the file in the freezing process. Et voilà! So far I have no problem.
When I run my code from main, it runs perfectly fine, but when I try to build main into an exe using py2exe, it gives this error:
Traceback (most recent call last):
File "main.py", line 118, in <module>
menu.menu.Menu()
File "menu\menu.pyo", line 20, in __init__
File "settingsManager.pyo", line 61, in getSetting
File "settingsManager.pyo", line 148, in __init__
WindowsError: [Error 3] The system cannot find the path specified: 'C:\\Users\\digiholic\\git\\universalSmashSystem\\main.exe\\settings\\rules/*.*'
The line it's referring to is:
for f in os.listdir(os.path.join(os.path.dirname(__file__),'settings','rules')):
It looks like os.listdir is using unix file pathing to find every file, and Windows is having none of that. Is there a way to use listdir in a way that won't blow up everything?
When you're running within the exe you need to check if the module is frozen, the path from __file__ is generally not what you expect when you're within an exe vs the raw python script. You need to access the location with something like this:
import imp, os, sys
def main_is_frozen():
return (hasattr(sys, "frozen") or # new py2exe
hasattr(sys, "importers") # old py2exe
or imp.is_frozen("__main__")) # tools/freeze
def get_main_dir():
if main_is_frozen():
return os.path.dirname(sys.executable)
return os.path.dirname(sys.argv[0])
Source: http://www.py2exe.org/index.cgi/HowToDetermineIfRunningFromExe
You can also check another direction here: http://www.py2exe.org/index.cgi/WhereAmI
Hi I've installed pynsist in order to make my python files into executables but I am having some issues. The project consists of two files that I've written. The main program to be run is Filereader.py and a supplied file called spuriousReq.py which Filereader.py uses a function from. Currently my installer.cfg file looks like this
[Application]
name=WFilereader
version=1.0
entry_point=Filereader
console=true
[Python]
version=3.4.0
[Include]
packages = matplotlib
statistics
bisect
files = spuriousReq.py
I've moved the installer.cfg file and both python files to the C:\Python34\Scripts folder in order to access them from the cmd (Yes I am new at this..). But I get the following error which I dont know how to interpret or solve..
C:\Python34\Scripts>"C:\Python34\python.exe" "C:\Python34\Scripts\\pynsist" inst
aller.cfg
Traceback (most recent call last):
File "C:\Python34\Scripts\\pynsist", line 3, in <module>
main()
File "C:\Python34\lib\site-packages\nsist\__init__.py", line 393, in main
shortcuts = configreader.read_shortcuts_config(cfg)
File "C:\Python34\lib\site-packages\nsist\configreader.py", line 172, in read_
shortcuts_config
appcfg = cfg['Application']
File "C:\Python34\lib\configparser.py", line 937, in __getitem__
raise KeyError(key)
KeyError: 'Application'
As mentioned in the documentation [http://pynsist.readthedocs.io/en/latest/] you need to specify the function from your 'Filereader.py' file which will be starting the execution of your script. For example if you have a 'main' function that will be the entry point or starting point of your script then you need to specify that in your 'installer.cfg' file like below:-
[Application]
name=WFilereader
version=1.0
entry_point=Filereader:main <------ Here mention your entry point function.
console=true
[Python]
version=3.4.0
[Include]
packages = matplotlib
statistics
bisect
files = spuriousReq.py
I'm trying to do this little tutorial http://www.roguebasin.com/index.php?title=Complete_Roguelike_Tutorial,_using_python%2Blibtcod,_part_1
A little ways down the page right before it says moving around it says to test what you have so far. I'm using Pycharm and this is my first time using an outside library or whatever you call it.
This is what I have so far and it is exactly what is in their example:
import libtcodpy as libtcod
#actual size of the window
SCREEN_WIDTH = 80
SCREEN_HEIGHT = 50
LIMIT_FPS = 20 #20 frames-per-second maximum
libtcod.console_set_custom_font('terminal.png', libtcod.FONT_TYPE_GREYSCALE | libtcod.FONT_LAYOUT_TCOD)
libtcod.console_init_root(SCREEN_WIDTH, SCREEN_HEIGHT, 'python/libtcod tutorial', False)
libtcod.sys_set_fps(LIMIT_FPS)
while not libtcod.console_is_window_closed():
libtcod.console_set_default_foreground(0, libtcod.white)
libtcod.console_put_char(0, 1, 1, '#', libtcod.BKGND_NONE)
libtcod.console_flush()
Whenever I run it I get this error.
Traceback (most recent call last):
File "D:\Programming\Project 1\Rogue Like\libtcodpy.py", line 57, in <module>
_lib = ctypes.cdll['./libtcod-mingw.dll']
File "C:\Python34\lib\ctypes\__init__.py", line 426, in __getitem__
return getattr(self, name)
File "C:\Python34\lib\ctypes\__init__.py", line 421, in __getattr__
dll = self._dlltype(name)
File "C:\Python34\lib\ctypes\__init__.py", line 351, in __init__
self._handle = _dlopen(self._name, mode)
OSError: [WinError 126] The specified module could not be found
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "D:/Programming/Project 1/Rogue Like/firstrl.py", line 1, in <module>
import libtcodpy as libtcod
File "D:\Programming\Project 1\Rogue Like\libtcodpy.py", line 60, in <module>
_lib = ctypes.cdll['./libtcod-VS.dll']
File "C:\Python34\lib\ctypes\__init__.py", line 426, in __getitem__
return getattr(self, name)
File "C:\Python34\lib\ctypes\__init__.py", line 421, in __getattr__
dll = self._dlltype(name)
File "C:\Python34\lib\ctypes\__init__.py", line 351, in __init__
self._handle = _dlopen(self._name, mode)
OSError: [WinError 126] The specified module could not be found
Thanks
I'm assuming you also copied libtcod-VS.dll or libtcod-mingw.dll to the project directory, not just libtcodpy.py. And also SDL.dll and a arial10x10.png. If not, go back and look at the Setting it up instructions again.
But if you have, this isn't really your fault, it's theirs.
libtcodpy.py tries to import the libtcod-VS.dll or libtcod-mingw.dll DLL from the current working directory. You can see that from this line:
_lib = ctypes.cdll['./libtcod-mingw.dll']
So, if the current working directory happens to be anything other than the directory that libtcodpy.py is in, it won't find them there.
This is a silly thing to do. If you do what the Choice of code editor section suggests and always run the script from a console (a "DOS prompt"), it will work (as long as you're always running it without an explicit path), but they really shouldn't be relying on that.
Still, that's obviously the simplest fix: Run the program from the console, the way they're expecting you to, instead of from PyCharm.
Alternatively, you can configure PyCharm to run your project with the project directory as your working directory.
There are a few ways to set this, but the one you probably want is the Run/Debug Configurations dialog (which you can find under Edit Configurations… on the Run menu). Open that dialog, open the disclosure triangle to Defaults, click Python, then look for "Working directory:" on the right. Click the … button and pick your project directory (or wherever you put libtcod-VS.dll or libtcod-mingw.dll).
Or you can edit libtcodpy.py to make it look for the DLL alongside of itself, rather than in the current working directory. There are only 4 small changes you should need.
First, in the middle of the import statements near the top, if there's no import os, add it.
Next, right after the import statements, add this:
modpath = os.path.dirname(os.path.abspath(__FILE__))
Now search for the two lines that start with _lib = ctypes.dll (or just look at the line numbers from the tracebacks) and change them as follows:
_lib = ctyles.cdll(os.path.join(modpath, 'libtcod-mingw.dll'))
_lib = ctyles.cdll(os.path.join(modpath, 'libtcod-VS.dll'))
I've just been struggling with the same problem myself, though I'm using Emacs and Python 2.7.
What solved the problem for me was installing a 32-bit python instead of a 64-bit python. The .dlls in libtcod are 32-bit, and 64-bit python on Windows isn't compatible with 32-bit .dlls.
Also, you might want to check if libtcod is compatible with python 3. I've found two places where the subject is discussed, but I can't tell if libtcod-1.5.1 is compatible with the later 3.xs.
I'd also suggest trying to run the samples_py.py in the libtcod folder to test these two problems, as if that runs it's your folder setup or path, rather then your version of python.
I'm trying to run virtual machine set on Computer with Windows 7 (my main laptop) from my netbook (Ubuntu system).
On Ubuntu I've prepared python script:
from vboxapi import VirtualBoxManager
import sys
sys.path.append("/home/myLogin/Downloads/sdk/bindings/webservice/python/lib")
mgr = VirtualBoxManager("WEBSERVICE", {'url':'myIP', 'user':'myServerLogin', 'password':'myPassthere'})
vbox = mgr.vbox
name = "Muszelek"
mach = vbox.findMachine(name)
session = mgr.mgr.getSessionObject(vbox)
progress = mach.launchVMProcess(session, "gui", "")
progress.waitForCompletion(-1)
mgr.closeMachineSession(session)
I'm getting error:
Installation problem: check that appropriate libs in place
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/vboxapi/__init__.py", line 981, in __init__
self.vbox = self.platform.getVirtualBox()
File "/usr/local/lib/python2.7/dist-packages/vboxapi/__init__.py", line 856, in getVirtualBox
return self.connect(self.url, self.user, self.password)
File "/usr/local/lib/python2.7/dist-packages/vboxapi/__init__.py", line 910, in connect
self.vbox = self.wsmgr.logon(self.user, self.password)
File "/home/karolinka/Downloads/sdk/bindings/webservice/python/lib/VirtualBox_wrappers.py", line 11790, in logon
req=IWebsessionManager_logonRequestMsg()
NameError: global name 'IWebsessionManager_logonRequestMsg' is not defined
Traceback (most recent call last):
File "vmmach.py", line 5, in <module>
mgr = VirtualBoxManager("WEBSERVICE", {'url':'myIP', 'user':'myComputerLogin', 'password':'myPass'})
File "/usr/local/lib/python2.7/dist-packages/vboxapi/__init__.py", line 985, in __init__
raise ne
NameError: global name 'IWebsessionManager_logonRequestMsg' is not defined
Any idea how could I solve this issue?
Is it problem with libs on my Windows Machine?
I just had the exact same problem on my Mac. The issue is that VirtualBox_wrappers.py imports VirtualBox_client.py (which defines the global name in question) in a try block and continues (pass) if it can not be imported
try:
from VirtualBox_client import *
except:
pass
the issue is that VirtualBox_client.py depends on ZSI, which was not installed, so the import failed. Once I did
easy_install zsi
everything worked as expected.
It seems that the class is not found! Have you tried to look for the webservice api if they are available?
I had a similar issue, I looked in /usr/lib/virtualbox/sdk/bindings and I didn't find the webservice folder only xpcom was in there, so I just included the webservice folder from the sdk and all worked fine.