问题
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
回答1:
The message
File "G:\Programming\Tests\wxThread_FTP_Funtion.py", line 126, in updateDisplay
bytes_so_far, size = list
indicates that the error is occurring when the variable list
is assigned to variables bytes_so_far, size
. The too many values to unpack
error indicates that list
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:
wx.CallAfter(Publisher().sendMessage, "update", "Thread finished!")
When updateDisplay runs this line of code,
bytes_so_far, size = msg.data
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 the too 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 a need more than x values to unpack
message.
来源:https://stackoverflow.com/questions/8844608/valueerror-in-thread-callback-function-trying-to-update-ftp-progress