ValueError в функции обратного вызова Thread - пытается обновить прогресс FTP - PullRequest
0 голосов
/ 13 января 2012

Я новичок в потоках и у меня возникли проблемы с получением моей рабочей функции для обновления графического интерфейса. У меня есть две переменные 'bytes_so_far' и 'size', которые я пытаюсь передать обратно в экземпляр GUI, но когда я запускаю его, я получаю 'ValueError: слишком много значений для распаковки'.

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

Ошибка выглядит следующим образом:

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 Ответ

1 голос
/ 13 января 2012

Сообщение

  File "G:\Programming\Tests\wxThread_FTP_Funtion.py", line 126, in updateDisplay
    bytes_so_far, size = list

указывает, что ошибка возникает, когда переменная list назначена переменным bytes_so_far, size.Ошибка too many values to unpack указывает на то, что list содержит более 2 элементов.

Но ваш код, по-видимому, не соответствует этой ошибке, поскольку в вашем примере нет строки bytes_so_far, size = list, так что, похоже, существует какая-то другая версия кода, которая может послужить причиной дляошибка более понятна.

РЕДАКТИРОВАТЬ:

Спасибо за обновление.Ошибка должна быть вызвана этим вызовом:

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

Когда updateDisplay запускает эту строку кода,

bytes_so_far, size = msg.data

msg.data содержит строку "Thread finished!", python пытается распаковатьстрока в свои отдельные символы, чтобы передать их в каждую из назначенных переменных bytes_so_far и size, что приводит к сообщению too many values to unpack, хотя на первый взгляд это только одно значение для присваивания (строка), и вы можете ожидатьneed more than x values to unpack сообщение.

...