1

I have written a wxpython application that uses several different threads all of which need to write to the log window (textctrl box). Because of this I followed this tutorial

http://www.blog.pythonlibrary.org/2010/05/22/wxpython-and-threads/

And used wx.CallAfter and PubSub.

This was my original code

from wx.lib.pubsub import Publisher

Publisher().subscribe(self.messenger, "update")

wx.CallAfter(Publisher().sendMessage, "update", "Thread finished!")

def messenger(self, msg):
    self.logtxtctrl.WriteText(msg.data)

this code worked brilliantly and thought it would be easy to use pyinstaller to create an exe for my code.

How wrong was I!!

So after reading some comments it seems there are two versions of the pubSub API, so using this

http://wiki.wxpython.org/WxLibPubSub

I tweaked my code to the following

from wx.lib.pubsub import setuparg1

from wx.lib.pubsub import pub

pub.subscribe(self.messenger, "update")

wx.CallAfter(pub.sendMessage, "update", data="Program success")

def messenger(self, data):
    self.logtxtctrl.WriteText(data)

This code now works and again I tried to use pyinstaller and still no luck.

So i then read the following articles

How to get pubsub to work with pyinstaller?

http://www.pyinstaller.org/ticket/312

Both of which were very useful and I tried all the different variations of changing the hook files and different spec files, I still cannot get it to work.

These posts are almost 2 years ago and I would have thought adding pubsub would be solved.

Can anyone please explain the process of what hooks I need, what to have in a spec file and other elements I need to do to get it to work?

if there is no solution how else can I do thread safe communications to widgets?

Community
  • 1
  • 1
tjmgis
  • 1,589
  • 4
  • 23
  • 42

1 Answers1

0

Try

from wx.lib.pubsub import setupkwargs
from wx.lib.pubsub import pub

I have a program that does exactly what you're looking for. The relevant pieces of code I use is below. I'd recommend creating a function such as Logger rather than using WriteText, it's saved me some pain down the road as changes come through.

class Frame(wx.Frame):
    def __init__(self, *args, **kwargs):
        super(Frame, self).__init__(*args, **kwargs)
        self.InitUI()
        self.SetSize((380,340))
        self.Show()
        self.count = 0
        self.threads = []
        pub.subscribe(self.__StatusChanged, 'status.changed')

    def __StatusChanged(self, asset, time, status):
        if status:
            msg = 'Online'
        else:
            msg = 'Offline'
        self.Logger('{}: {} - {}\n'.format(time, asset, msg))

    def Logger(self, msg):
        self.txtresults.AppendText(msg)

class PingAssets(threading.Thread):
    def __init__(self, threadNum, asset, window):
        threading.Thread.__init__(self)
        self.threadNum = threadNum
        self.window = window
        self.asset = asset
        self.signal = True
        self.status = None

    def run(self):
        while self.signal:
            logging.debug("Thread {} started run sequence.".format(self.threadNum))
            start_time = datetime.now().strftime(self.fmt)
            try:
                newstatus = onlinecheck.check_status(self.asset)
                if newstatus != self.status or self.verbose:
                    self.status = newstatus
                    pub.sendMessage('status.changed', asset=self.asset,
                                    time=start_time, status=self.status)
pedram
  • 2,931
  • 3
  • 27
  • 43
  • I will give this a go, many thanks. Hopefully it will work with pyinstaller - can you just confirm this? – tjmgis Aug 21 '13 at 08:53
  • I can. I distribute everything using PyInstaller. If it works or is helpful I'd appreciate a +1 / marked as best answer. Sidenote: I've also created a GUI front-end to PyInstaller https://github.com/multiphrenic/GooeyPi. It is currently only compatible with the latest development version of PyInstaller (2.1) and not the stable 2.0. However I'd recommend 2.1 for most use-cases as there are a number of bug-fixes in there. – pedram Aug 21 '13 at 12:49
  • I have just spent the last few hours trying to get this to work and still no luck with my wxpython 2.8 current release. So I removed it and got the development version along with the development version of pyinstaller, used my identical script and used your import statements for pubsub and ran pyinstaller. It found it and now my exe works. Thanks for your help – tjmgis Aug 21 '13 at 22:39
  • By the way i downloaded the zip of gooeypi and opened a new command prompt window in the src folder and did python gooeypi.py and got an error message saying it could not find the .ini file, so I copied the one from the level above into the src folder and tried again. It launched, I gave it the path to the pyinstaller folder and then pointed it to my code. It failed as it could not find -dist. Not sure where I was supposed to set this – tjmgis Aug 21 '13 at 22:41
  • Thanks for checking this out. There was a small error in my code which I've fixed. If you don't mind, try again. If you see an error, maybe you can post an issue on GitHub (might be better suited than here). I'd really appreciate it! – pedram Aug 21 '13 at 23:49