I'm new to threads and having some trouble getting my worker function to update the GUI. I have two variables 'bytes_so_far' and 'size' that I'm trying to pass to back to the GUI instance but when I run it I get a 'ValueError: too many values to unpack'.
import time
import os, sys, wx
from ftplib import FTP_TLS
from threading import Thread
from wx.lib.pubsub import Publisher
########################################################################
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.
HOST = '127.0.0.1'
USERID = 'User'
PASSWD = 'Passwd'
FILE = r'C:\Myfile.zip'
BLOCKSIZE = 57344
try:
ftp = FTP_TLS(HOST)
ftp.login(USERID, PASSWD)
ftp.prot_p()
ftp.voidcmd("TYPE I")
f = open(FILE, 'rb')
datasock, esize = ftp.ntransfercmd(
'STOR %s' % os.path.basename(FILE))
size = os.stat(FILE)[6]
bytes_so_far = 0
while 1:
buf = f.read(BLOCKSIZE)
if not buf:
break
datasock.sendall(buf)
bytes_so_far += len(buf)
msg = [bytes_so_far, size]
Publisher().sendMessage("update", msg)
except: raise
finally:
try:
datasock.close()
f.close()
ftp.voidresp()
ftp.quit()
print 'Complete...'
except: pass
wx.CallAfter(Publisher().sendMessage, "update", "Thread finished!")
########################################################################
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")
self.gauge = wx.Gauge(panel, -1, 100, size=(370, 24))
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)
sizer.Add(self.gauge, 0, wx.ALL|wx.CENTER, 5)
panel.SetSizer(sizer)
# create a pubsub receiver
Publisher().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, msg):
"""
Receives data from thread and updates the display
"""
print msg.data
bytes_so_far, size = msg.data
k = 100 * bytes_so_far / size
self.displayLbl.SetLabel("\rSent %d of %d bytes %.1f%%\r" % (bytes_so_far, size, 100 * bytes_so_far / size))
self.gauge.SetValue(k)
self.btn.Enable()
#----------------------------------------------------------------------
# Run the program
if __name__ == "__main__":
app = wx.PySimpleApp()
frame = MyForm().Show()
app.MainLoop()
The error is as follows:
Traceback (most recent call last):
File "C:\Python27\lib\site-packages\wx-2.8-msw-unicode\wx\_core.py", line 14640, in <lambda>
lambda event: event.callable(*event.args, **event.kw) )
File "C:\Python27\lib\site-packages\wx-2.8-msw-unicode\wx\lib\pubsub\pubsub1\pub.py", line 750, in sendMessage
self.__topicTree.sendMessage(aTopic, message, onTopicNeverCreated)
File "C:\Python27\lib\site-packages\wx-2.8-msw-unicode\wx\lib\pubsub\pubsub1\pub.py", line 423, in sendMessage
deliveryCount += node.sendMessage(message)
File "C:\Python27\lib\site-packages\wx-2.8-msw-unicode\wx\lib\pubsub\pubsub1\pub.py", line 261, in sendMessage
listener(message)
File "F:\Programming\Tests\wxThread_FTP_Funtion.py", line 98, in updateDisplay
bytes_so_far, size = msg.data
ValueError: too many values to unpack
The message
indicates that the error is occurring when the variable
list
is assigned to variablesbytes_so_far, size
. Thetoo many values to unpack
error indicates thatlist
has more than 2 elements in it.But your code does not seem to match that error, since there is no line
bytes_so_far, size = list
in your sample, so it seems there is some other version of the code out there somewhere that might make the reason for the error more clear.EDIT:
Thanks for the update. The error should be due to this call:
When updateDisplay runs this line of code,
msg.data
contains the string"Thread finished!"
, python attempts to unpack the string into its individual characters in order to pass those into each of the assigned variables bytes_so_far and size, which leads to thetoo many values to unpack
message even though on the face of it there is only one value to assign (the string) and you might expect aneed more than x values to unpack
message.