Question

I'm using ftplib to create a simple script to push out a file to multiple IP addresses, all set up as FTP servers. I wanted to display progress in the file upload process, but I'm having an issue. I use the callback argument of FTP.storbinary() and it works with something like this:

count = 0
def update(block):
   count2 = str(count + 1)
   print count2

However, if I try to do any arithmetic outside of a str() call, the program hangs. So the following doesn't work:

count = 0
def update(block):
   count += 1
   print count

Even wrapping count in a str() call doesn't work. It just hangs on the first call.

Was it helpful?

Solution

If you just try calling update yourself, instead of passing it to FTP.storbinary, you'll see the problem immediately:

>>> update('')
UnboundLocalError: local variable 'count' referenced before assignment

If you want to update a global variable, you have to mark it global explicitly:

def update(block):
   global count
   count += 1
   print count

See the FAQ entry Why am I getting an UnboundLocalError when the variable has a value? and the following question What are the rules for local and global variables in Python?, and the docs on global, for more details.


A better way to solve this would be to write a class:

class FtpHandler(object):
    def __init__(self):
        self.count = 0
    def update(self, block):
        self.count += 1
        print self.count

Then, to use it, you construct an instance of the class, and pass a bound method instead of a plain function to the FTP code. For example, instead of this:

ftp = ftplib.FTP(...)
# ...
ftp.storbinary(spam, eggs, callback=update)

… do this:

myhandler = FtpHandler()
ftp = ftplib.FTP(...)
# ...
ftp.storbinary(spam, eggs, callback=myhandler.update)

OTHER TIPS

It doesn't just hang, it produces an Exception (specifically an UnboundLocalError). You're trying to modify a global variable inside of a function; to do this the variable must be declared global:

count = 0
def update(block):
   global count
   count += 1
   print count

This is almost always a sign of bad design, in your case it would probably be better to use a class with an attribute:

class MyCallbackHandler(object):
    def __init__(self):
        self.count = 0

    def update(self, block):
        self.count += 1
        #... etc.
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top