py2exe / pyinstaller y DispatchWithEvents

Tengo un progtwig que usa la biblioteca win32com para controlar iTunes, pero he tenido algunos problemas para comstackrlo en un ejecutable. El problema parece girar en torno al uso de DispatchWithEvents lugar de Dispatch . He creado un progtwig muy simple para ilustrar mi problema:

 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") 

Usando Dispatch , el progtwig comstack y ejecuta correctamente. Usando DispatchWithEvents , el progtwig se ejecuta bien cuando se llama desde la línea de comandos, pero produce el siguiente error al ejecutar el exe:

 Traceback (most recent call last): File "sandbox.py", line 16, in  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' 

También he intentado usar PyInstaller, que da un error similar:

 File "", line 16, in  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 

Sé que puedo agregar manualmente el typelib en mi archivo setup.py , pero me gustaría ejecutar el código en computadoras con diferentes versiones de iTunes sin comstackr, así que prefiero crearlo dinámicamente. Si no hay manera de hacer esto con la configuración / especificación, ¿tal vez hay otra forma de cargar los eventos? Gracias.


Adición:

Gracias a Ryan, descubrí que podía tomar el archivo py generado y, después de una pequeña investigación, pude encontrar lo siguiente.

Tome el archivo py generado (de makepy.py ) y makepy.py nombre a algún lugar como cominterface.py . Luego deberá hacer lo siguiente para crear realmente el objeto COM con el controlador de eventos.

 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) 

Entonces usted puede ir a su negocio.

En lugar de depender de la memoria caché, recomiendo ir al directorio de la memoria caché local, copiar el archivo generado en su archivo de proyecto local, y nombrarlo como ITunesInterface.py, y llamar a eso explícitamente. Esto hará que py2exe lo arrastre a tu aplicación comstackda.

Estaba experimentando el mismo error exacto. Este enlace me puso en la dirección correcta -> http://www.py2exe.org/index.cgi/UsingEnsureDispatch sin embargo, menciona que: NB Debe asegurarse de que el directorio python … \ win32com.client.gen_py no lo haga existe para permitir la creación de la memoria caché en% temp%, lo que fue un poco confuso. Lo que lo resolvió para mí fue cambiar el nombre de “C: \ Python26 \ Lib \ site-packages \ win32com \ gen_py” a “C: \ Python26 \ Lib \ site-packages \ win32com \ gen_pybak” (cuando se ejecuta py2exe)

Esta es la forma oficial de hacerlo.

(Edición: ejemplo textual copiado de ese enlace arriba)

 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 )