Question

J'ai un programme qui utilise la bibliothèque iTunes win32com de contrôle, mais ont eu quelques problèmes pour trouver à compiler dans un fichier exécutable. Le problème semble tourner autour de l'utilisation DispatchWithEvents au lieu de Dispatch. J'ai créé un programme très simple pour illustrer mon problème:

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

En utilisant Dispatch, les compiles du programme et fonctionne correctement. En utilisant DispatchWithEvents, le programme fonctionne très bien lorsqu'il est appelé à partir de la ligne de commande, mais produit l'erreur suivante lors de l'exécution du 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'

J'ai aussi essayé d'utiliser PyInstaller, ce qui donne une erreur semblable:

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

Je sais que je peux ajouter manuellement le typelib dans mon fichier setup.py, mais je voudrais exécuter le code sur les ordinateurs avec différentes versions d'iTunes sans recompilation donc je préfère créer dynamiquement. S'il n'y a aucun moyen de le faire avec la configuration / spécification, peut-être il y a une autre façon de charger les événements? Merci.


Addition:

Merci à Ryan, je trouve que je pouvais prendre le fichier py généré et après un peu de creuser, a pu trouver ce qui suit.

Prenez le fichier généré py (à partir makepy.py) et renommez quelque part comme cominterface.py. Ensuite, vous devrez effectuer les opérations suivantes pour créer effectivement l'objet COM avec gestionnaire d'événements.

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)

Ensuite, vous pouvez vaquer à vos occupations.

Était-ce utile?

La solution

Au lieu de dépendre du cache, je vous conseille d'aller dans le répertoire de cache local, la copie du fichier généré dans votre fichier de projet local, et en le nommant quelque chose comme ITunesInterface.py, et appelant à explicitement. Cela fera tirer py2exe dans votre application compilée.

Autres conseils

Je connaissait exactement la même erreur. Ce lien m'a mis dans la bonne direction -> http://www.py2exe.org/index.cgi/UsingEnsureDispatch mais il mentionne que: NB Vous devez vous assurer que le python ... \ dir win32com.client.gen_py n'existe pas pour permettre la création du cache en% temp% Ce qui était un peu déroutant. Que résolu pour moi a été rebaptiser "C: \ Python26 \ Lib \ site-packages \ win32com \ gen_py" à "C: \ Python26 \ Lib \ site-packages \ win32com \ gen_pybak" (quand py2exe en cours d'exécution)

Cette est la façon officielle de le faire.

(Edit: par exemple copié mot à mot de ce lien ci-dessus)

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 )
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top