Home Ask Login Register

Developers Planet

Your answer is one click away!

Paul Gowder February 2016

python ftplib hangs on upload (STOR) --- and not network latency

I have a very simple utility script using ftplib on python 2.7 to upload web files to my remote host. However, storlines hangs and just sits there for a couple of minutes. Doesn't have the decency to throw any kind of exception.

  • I've verified that the connection works from the REPL. storlines hangs both from the REPL and from the commandline script.

  • my test file is 22 bytes (not KB, bytes), so it seems very unlikely that things are just timing out. Also, at the REPL, after I kill the hung upload via cntrl-c, I can get output from ftp.dir(), so I know I'm not losing the connection at some point.

  • the aforementioned output from ftp.dir() is much larger than my test file, and arrives within a few seconds, so I know the problem isn't network latency.

  • based on this prior SO I've tried adding ftp.set_pasv(False) before the upload function definition, but that does nada.

Does anyone else have any ideas about what could be going wrong here? Here's the code:

import sys
from ftplib import FTP
full = sys.argv[1]
path = 'public_html/' + full[:full.rfind('/') + 1]
filename = full[full.rfind('/') + 1:]

def upload(method, mode, filename):
    with open(filename, mode) as fileobject:
        method('STOR' +filename, fileobject)

if filename.endswith(('.htm','.html','.py','.cgi','.js','.css','.txt','.md', '.svg')):
    upload(ftp.storlines, 'r', filename)
    upload(ftp.storbinary, 'rb', filename)
print 'Done!'

and, seriously, this is the full file I'm trying to upload, with the filename test.md:

this is a test. 


Paul Gowder February 2016

So this is ugly, but I eventually figured out a hack-tastic solution, which just lets the nice existing ftp application that was written by someone who actually knows networking do the work:

import sys
import os
full = sys.argv[1]
path = 'public_html/' + full[:full.rfind('/') + 1]
filename = full[full.rfind('/') + 1:]

def picktype(filename):
    if filename.endswith(('.htm','.html','.py','.cgi','.js','.css','.txt','.md', '.svg')):
        return 'ascii'
    return 'binary'

ftpstring = """
open [SERVER]
cd {0}
put {2}
""".format(path, picktype(filename), filename)

print ftpstring

with open("tempfile.txt", 'w') as tempfile:

os.system('ftp -n < tempfile.txt')

print 'Done!'

I know these days you're supposed to use the subprocess module for this kind of junk, but I can't for the life of me figure out how to make a redirection work.

Post Status

Asked in February 2016
Viewed 2,608 times
Voted 12
Answered 1 times


Leave an answer

Quote of the day: live life