This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author christianmlong
Recipients
Date 2003-06-10.06:51:09
SpamBayes Score
Marked as misclassified
Message-id
In-reply-to
Content
Subject: ftplib.retrbinary() fails when called from
inside retrlines() callback function

I'm using ftplib to backup files from a Linux server to
a Windows 2000 worksation. 


Client:  
Windows 2000 Pro
ActivePython 2.2.2 Build 224 (ActiveState Corp.) based on
Python 2.2.2 (#37, Nov 26 2002, 10:24:37) [MSC 32 bit
(Intel)] on win32
Komodo IDE

Server:
ProFTP server (ProFTPd version 1.25) 
Mandrake Linux 9.0


Summary:

When I use it like this it works fine.

# Build a list of files that are on the remote server
f.retrlines('NLST', makeListOfFiles)

--then--
# Iterate over the list, retrieving each file
for remoteFileName in listOfFiles:
    --snip--
    f.retrbinary('RETR %s' % remoteFileName,
localFile.write)
    --snip--


But it fails if I try to do the retrieve directly in my
callback function.

def transferFile(listLine):
    --snip--
    f.retrbinary('RETR %s' % remoteFileName,
localFile.write)  <--fails here on first time through
    --snip--

# get list of files from server, adn transfer each file
as it gets listed
f.retrlines('LIST', transferFile)

--snip--
  File "D:\My Documents\Computer World\Python
Resources\My Utilities\backup_remote_files.py", line
45, in ?
    f.retrlines('LIST', transferFile)
  File "C:\Python22\lib\ftplib.py", line 413, in retrlines
    callback(line)
  File "D:\My Documents\Computer World\Python
Resources\My Utilities\backup_remote_files.py", line
36, in transferFile
    f.retrbinary('RETR mra.py', localFile.write)
--snip--
  File "C:\Python22\lib\ftplib.py", line 300, in makepasv
    host, port = parse227(self.sendcmd('PASV'))
  File "C:\Python22\lib\ftplib.py", line 572, in parse227
    raise error_reply, resp
error_reply: 200 Type set to I.


It looks like the server is returning a 200 instead of
a 227 when retrbinary() is called inside a callback
function for retrlines().



Files:

2 Files are included:  a broken version and a version
that works

This One Is Broken -  retrbinary() called from inside a
callback function for retrlines().
===================================================
import ftplib
import os
import time

REMOTE_DIR = "/home/mydir"
LOCAL_DIR = "C:\My Documents"
TIME_FORMAT = "%y%m%d"    # YYMMDD, like 030522

def transferFile(listLine):
    # Strips the file name from a line of a
    # directory listing, and gets it from the
    # server.  Depends on filenames
    # with no embedded spaces or extra dots.
    if listLine.endswith('.py'):
        #Split file name on the dot
        splitFileName=remoteFileName.split('.')
        # Add a timestamp
        localFileName="%s_%s.%s" % (splitFileName[0],
                                   
time.strftime(TIME_FORMAT),
                                    splitFileName[1])
        # Open a local file for (over)writing, in
binary mode.
        # print os.path.join(LOCAL_DIR,localFileName)
       
localFile=file(os.path.join(LOCAL_DIR,localFileName), 'wb')
        print remoteFileName
        print localFile
        # Execute the FTP retrieve command, calling
        # the write() function of the local file
        # for each block retrieved from the FTP server
        # BUG: This should work, but I get the
following traceback
        f.retrbinary('RETR %s' % remoteFileName,
localFile.write)    #<--- Fails
                                                      
              #     Here

#        mra.py
#<open file 'D:\My
Documents\Work\IA\Miller\MRA\Dev\Backup of remote
files\mra_030610.py', mode 'wb' at 0x00886B70>
#Traceback (most recent call last):
#  File "C:\Program Files\ActiveState Komodo
2.3\callkomodo\kdb.py", line 430, in _do_start
#    self.kdb.run(code_ob, locals, locals)
#  File "C:\Python22\lib\bdb.py", line 349, in run
#    exec cmd in globals, locals
#  File "D:\My Documents\Computer World\Python
Resources\My Utilities\backup_remote_files.py", line
45, in ?
#    f.retrlines('LIST', transferFile)
#  File "C:\Python22\lib\ftplib.py", line 413, in retrlines
#    callback(line)
#  File "D:\My Documents\Computer World\Python
Resources\My Utilities\backup_remote_files.py", line
36, in transferFile
#    f.retrbinary('RETR mra.py', localFile.write)
#  File "C:\Python22\lib\ftplib.py", line 385, in
retrbinary
#    conn = self.transfercmd(cmd, rest)
#  File "C:\Python22\lib\ftplib.py", line 346, in
transfercmd
#    return self.ntransfercmd(cmd, rest)[0]
#  File "C:\Python22\lib\ftplib.py", line 322, in
ntransfercmd
#    host, port = self.makepasv()
#  File "C:\Python22\lib\ftplib.py", line 300, in makepasv
#    host, port = parse227(self.sendcmd('PASV'))
#  File "C:\Python22\lib\ftplib.py", line 572, in parse227
#    raise error_reply, resp
#error_reply: 200 Type set to I.

# The problem is that the self.sendcmd('PASV') call is
not getting a 227
# reply from the server.  Rather, it is getting a 200
reply, confirming
# that the type was set to I (Image).


        localFile.flush()
        localFile.close()

f=ftplib.FTP('server', 'user', 'password')
f.cwd(REMOTE_DIR)
# List directory contents, and call the transferFile
# function on each line in the listing
f.retrlines('LIST', transferFile)

f.close()




===================================================



This One Works - retlines() builds a list, and then
files are transferred by iterating over
that list and calling retrbinary() for each.
===================================================
import ftplib
import os
import time

REMOTE_DIR = "/home/mydir"
LOCAL_DIR = "C:\My Documents"
TIME_FORMAT = "%y%m%d"    # YYMMDD, like 030522

listOfFiles = []

def makeListOfFiles(remoteFileName):
    # Strips the file name from a line of a
    # directory listing, and gets file from the
    # server.  Depends on filenames
    # with no embedded spaces or extra dots.
    if remoteFileName.endswith('.py'):
        listOfFiles.append(remoteFileName)

f=ftplib.FTP('server', 'user', 'password')
f.cwd(REMOTE_DIR)
# List directory contents, and call the transferFile
# function on each line in the listing
f.retrlines('NLST', makeListOfFiles)
print listOfFiles

for remoteFileName in listOfFiles:
    #Split file name on the dot
    splitFileName=remoteFileName.split('.')
    # Add a timestamp
    localFileName="%s_%s.%s" % (splitFileName[0],
                                time.strftime(TIME_FORMAT),
                                splitFileName[1])
    # Open a local file for (over)writing, in binary mode.
    # print os.path.join(LOCAL_DIR,localFileName)
   
localFile=file(os.path.join(LOCAL_DIR,localFileName), 'wb')

    # Execute the FTP retrieve command, calling
    # the write() function of the local file
    # for each block retrieved from the FTP server
    f.retrbinary('RETR %s' % remoteFileName,
localFile.write)
    localFile.flush()
    localFile.close()

f.close()





===================================================
History
Date User Action Args
2007-08-23 14:13:48adminlinkissue751758 messages
2007-08-23 14:13:48admincreate