[컴][파이썬] py2exe 관련 pub.Publisher import error 해결책


사용한 module version

  • wxpython version : wxpython 2.8.12.1
  • python version : python 2.7

wxpython 에 있는 pubsub와 py2exe 를 같이 사용할 때 문제점.

Publisher 를 사용하는 데에 py2exe 로 변환후에 error 가 발생했다.
from wx.lib.pubsub import Publisher
py2exe 를 이용해서 exe 를 만든후에 실행을 하면, 이 부분에서 Publisher 를 찾을 수 없다는 에러가 뜬다.
결론부터 이야기 하면 kwargs 를 사용하는 pub 로 converting 했다.

from wx.lib.pubsub import setuparg1

이것은 wxpython 2.8.10.1 에서는 발생하지 않지만, 이후 버전에서 kwargs 가 추가 되고 문제가 발생한다고 한다.
from wx.lib.pubsub import setuparg1
를 추가 하면 된다고 해서 기존코드에 추가해서 다시 py2exe 를 해서 실행했다. 일단 Publisher 를 찾기는 하지만 args1 을 사용하는 Publisher 가 import 되지 않는다. 그래서 subscribe 을 한 listener 를 부르지 않는등의 이상한 현상이 보였다.

'pubsub.*', 'pubsub.core.*', 'pubsub.core.arg1.*'

setup.py 에서 'pubsub.*', 'pubsub.core.*', 'pubsub.core.arg1.*' 를 넣으면 된다고 해서 넣고는 py2exe 를 실행했지만, 여전히 안됐다.

from distutils.core import setup
import py2exe

setup(
    windows=[{"script": "getMangaW.py"}],
    options={
        "py2exe": 
        {
            'packages':['wx.lib.pubsub'],
            "includes": ["lxml.etree", "lxml._elementpath","wx.lib.pubsub.*",
                    "wx.lib.pubsub.core.*", "wx.lib.pubsub.core.args1.*" ],
            "excludes":["mswsock.dll", "powrprof.dll", "uxTheme.dll", "MSVCP90.dll"],
            "bundle_files": 3, # the less, the more zip
            "optimize":2
        }
    },
    zipfile = "lib/library.zip"
)


kwargs 로 변환

ref. 2 에서 pubsub 해결책에 대해 많이 논하고 있다. 일단 arg1 을 이용한 방법을 최대한 찾아보았으나, 결론적으로 실패했다.

결국 arg1 을 사용하던 것은 kwargs 로 변환하였다. 그것이 차라리 간단하고 빠를 듯 하다. kwargs 의 예제는 ref. 3, ref. 4, ref. 5 을 참조하자.


Example

ref. 6 의 args1 을 사용한 source code 를 kwargs 로 변환했다.

import time
import wx
 
from threading import Thread


from wx.lib.pubsub import setupkwargs
from wx.lib.pubsub import pub
 
########################################################################
class TestThread(Thread):
    """Test Worker Thread Class."""
 
    #----------------------------------------------------------------------
    def __init__(self):
        """Init Worker Thread Class."""
        Thread.__init__(self)
        self.start()    # start the thread
 
    #----------------------------------------------------------------------
    def run(self):
        """Run Worker Thread."""
        # This is the code executing in the new thread.
        for i in range(6):
            time.sleep(10)
            wx.CallAfter(self.postTime, i)
        time.sleep(5)
        wx.CallAfter(pub.sendMessage, "update", data = "Thread finished!")
 
    #----------------------------------------------------------------------
    def postTime(self, amt):
        """
        Send time to GUI
        """
        amtOfTime = (amt + 1) * 10
        pub.sendMessage("update", data = amtOfTime)
 
########################################################################
class MyForm(wx.Frame):
 
    #----------------------------------------------------------------------
    def __init__(self):
        wx.Frame.__init__(self, None, wx.ID_ANY, "Tutorial")
 
        # Add a panel so it looks the correct on all platforms
        panel = wx.Panel(self, wx.ID_ANY)
        self.displayLbl = wx.StaticText(panel, label="Amount of time since thread started goes here")
        self.btn = btn = wx.Button(panel, label="Start Thread")
 
        btn.Bind(wx.EVT_BUTTON, self.onButton)
 
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.displayLbl, 0, wx.ALL|wx.CENTER, 5)
        sizer.Add(btn, 0, wx.ALL|wx.CENTER, 5)
        panel.SetSizer(sizer)
 
        # create a pubsub receiver
        pub.subscribe(self.updateDisplay, "update")
 
    #----------------------------------------------------------------------
    def onButton(self, event):
        """
        Runs the thread
        """
        TestThread()
        self.displayLbl.SetLabel("Thread started!")
        btn = event.GetEventObject()
        btn.Disable()
 
    #----------------------------------------------------------------------
    def updateDisplay(self, data):
        """
        Receives data from thread and updates the display
        """
        t = data # t = msg.data
        if isinstance(t, int):
            self.displayLbl.SetLabel("Time since thread started: %s seconds" % t)
        else:
            self.displayLbl.SetLabel("%s" % t)
            self.btn.Enable()
 
#----------------------------------------------------------------------
# Run the program
if __name__ == "__main__":
    app = wx.PySimpleApp()
    frame = MyForm().Show()
    app.MainLoop()


References

  1. Working with Various Packages and Modules >> pubsub
  2. wxPython 2.8.11.0 Pubsub not found by py2exe
  3. kwargs example sources
  4. convert arg1 to kwargs
  5. Example_using_API_version_1
  6. http://www.blog.pythonlibrary.org/2010/05/22/wxpython-and-threads/

댓글 없음:

댓글 쓰기