Search code examples
pythonftpprogress-barftplib

Python progressbar for FTP downloads not working


I'm trying to use progressbar to display the FTP file download progress (ftplib) but the progress does not update correctly. The speed starts out high then gradually decreases (down to bytes). The download ends up completing after a few seconds while the progress bar is still at 0%. It appears I am not updating the progress correctly and am not sure how to correct this.

I tried the solution I found here Show FTP download progress in Python (ProgressBar) using pbar += len(data) but this gave me the following error:

Traceback (most recent call last):                                                             ] ETA:  --:--:--   0.00  B/s
  File "ftp.py", line 38, in <module>
    ftp.retrbinary('RETR ' + file, file_write)
  File "/usr/lib/python3.5/ftplib.py", line 446, in retrbinary
    callback(data)
  File "ftp.py", line 29, in file_write
    pbar += len(data)
TypeError: unsupported operand type(s) for +=: 'ProgressBar' and 'int'

So I tweaked it by adding pbar.update(len(data)) to my file_write() function and got it working without the error, but as I said the speed is totally incorrect, keeps dropping (till it hits 0 probably) and then just suddenly completes.

Here is my entire script:

from ftplib import FTP_TLS
import time

from progressbar import AnimatedMarker, Bar, BouncingBar, Counter, ETA, \
    AdaptiveETA, FileTransferSpeed, FormatLabel, Percentage, \
    ProgressBar, ReverseBar, RotatingMarker, \
    SimpleProgress, Timer, UnknownLength

ftp_host = 'domain.com'
ftp_port = 21
ftp_user = 'user'
ftp_pass = 'pass'

ftp = FTP_TLS()

ftp.connect(ftp_host, ftp_port)
ftp.login(ftp_user, ftp_pass)
ftp.cwd('/videos')

files = ftp.nlst()

widgets = ['Downloading: ', Percentage(), ' ', Bar(marker='#', \
            left='[',right=']'), ' ', ETA(), ' ', FileTransferSpeed()]

def file_write(data):
    localfile.write(data)
    global pbar
    pbar.update(len(data))
    #pbar += len(data)

for file in files:
    size = ftp.size(file)
    pbar = ProgressBar(widgets = widgets, maxval = size)
    pbar.start()

    localfile = open('/local/videos/' + file, 'wb')

    ftp.retrbinary('RETR ' + file, file_write)

    pbar.finish() 
    localfile.close()

ftp.quit()

Any help would be much appreciated to get this code working like it should.

UPDATE:

I made the following additions/changes and got the right speed/progress bar movement:

i = 0
def file_write(data):
    localfile.write(data)
    global pbar, i
    pbar.update(i * 1024 * 10)
    i+=1
    #pbar += len(data)

but just as it is about to finish I get this error:

Traceback (most recent call last):################################################## ] ETA:  0:00:00  45.62 MB/s
  File "ftp.py", line 42, in <module>
    ftp.retrbinary('RETR ' + file, file_write)
  File "/usr/lib/python3.5/ftplib.py", line 446, in retrbinary
    callback(data)
  File "ftp.py", line 30, in file_write
    pbar.update(o * 1024 * 10)
  File "/usr/local/lib/python3.5/dist-packages/progressbar/progressbar.py", line 250, in update
    raise ValueError('Value out of range')
ValueError: Value out of range

I'm using progressbar 2.5 (latest) and Python 3.5.


Solution

  • The code is actually for progressbar2 library.

    Its ProgressBar class implements __iadd__.