[Python-bugs-list] [ python-Bugs-751758 ] ftplib.retrbinary fails when called from retrlines callback
SourceForge.net
noreply@sourceforge.net
Sat, 14 Jun 2003 17:45:14 -0700
Bugs item #751758, was opened at 2003-06-10 01:51
Message generated for change (Comment added) made by sjones
You can respond by visiting:
https://sourceforge.net/tracker/?func=detail&atid=105470&aid=751758&group_id=5470
Category: Python Library
Group: Python 2.2.2
Status: Open
Resolution: None
Priority: 5
Submitted By: Christian Long (christianmlong)
Assigned to: Nobody/Anonymous (nobody)
Summary: ftplib.retrbinary fails when called from retrlines callback
Initial Comment:
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()
===================================================
----------------------------------------------------------------------
Comment By: Shannon Jones (sjones)
Date: 2003-06-14 19:45
Message:
Logged In: YES
user_id=589306
The problem seems to happen when you use a callback within a
function that was called as a callback. Here is a much
simpler case that demonstrates the problem:
-----------------------------
import ftplib
def transferFile(listLine):
filename = listLine.split()[-1]
if filename == 'README':
# Note that retrlines uses a default
# callback that just prints the file
f.retrlines('RETR README') # <-- Fails
f=ftplib.FTP('ftp.python.org', 'ftp', 'anon@')
f.cwd('/pub/python')
f.retrlines('LIST', transferFile)
f.close()
-----------------------------
This fails with the following:
Traceback (most recent call last):
File "ftptest.py", line 10, in ?
f.retrlines('LIST', transferFile)
File "/home/sjones/src/python/dist/src/Lib/ftplib.py",
line 407, in retrlines
callback(line)
File "ftptest.py", line 6, in transferFile
f.retrlines('RETR README') # <-- Fails
File "/home/sjones/src/python/dist/src/Lib/ftplib.py",
line 396, in retrlines
conn = self.transfercmd(cmd)
File "/home/sjones/src/python/dist/src/Lib/ftplib.py",
line 345, in transfercmd
return self.ntransfercmd(cmd, rest)[0]
File "/home/sjones/src/python/dist/src/Lib/ftplib.py",
line 321, in ntransfercmd
host, port = self.makepasv()
File "/home/sjones/src/python/dist/src/Lib/ftplib.py",
line 299, in makepasv
host, port = parse227(self.sendcmd('PASV'))
File "/home/sjones/src/python/dist/src/Lib/ftplib.py",
line 566, in parse227
raise error_reply, resp
ftplib.error_reply: 200 Type set to A.
Note this is with the current CVS version on Redhat 9.
----------------------------------------------------------------------
You can respond by visiting:
https://sourceforge.net/tracker/?func=detail&atid=105470&aid=751758&group_id=5470