Return the error code from most commands, rather than swallowing it.

Adapted the example (lying slightly about the string printed by
login()).
This commit is contained in:
Guido van Rossum 1997-10-07 14:49:56 +00:00
parent ae590db3ce
commit 2f3941d743

View file

@ -12,6 +12,7 @@ Example:
>>> from ftplib import FTP >>> from ftplib import FTP
>>> ftp = FTP('ftp.python.org') # connect to host, default port >>> ftp = FTP('ftp.python.org') # connect to host, default port
>>> ftp.login() # default, i.e.: user anonymous, passwd user@hostname >>> ftp.login() # default, i.e.: user anonymous, passwd user@hostname
'230 Guest login ok, access restrictions apply.'
>>> ftp.retrlines('LIST') # list directory contents >>> ftp.retrlines('LIST') # list directory contents
total 9 total 9
drwxr-xr-x 8 root wheel 1024 Jan 3 1994 . drwxr-xr-x 8 root wheel 1024 Jan 3 1994 .
@ -23,7 +24,9 @@ drwxr-xr-x 2 root wheel 1024 Nov 17 1993 lib
drwxr-xr-x 6 1094 wheel 1024 Sep 13 19:07 pub drwxr-xr-x 6 1094 wheel 1024 Sep 13 19:07 pub
drwxr-xr-x 3 root wheel 1024 Jan 3 1994 usr drwxr-xr-x 3 root wheel 1024 Jan 3 1994 usr
-rw-r--r-- 1 root root 312 Aug 1 1994 welcome.msg -rw-r--r-- 1 root root 312 Aug 1 1994 welcome.msg
'226 Transfer complete.'
>>> ftp.quit() >>> ftp.quit()
'221 Goodbye.'
>>> >>>
A nice test that reveals some of the network dialogue would be: A nice test that reveals some of the network dialogue would be:
@ -98,9 +101,11 @@ class FTP:
self.sock = None self.sock = None
self.file = None self.file = None
self.welcome = None self.welcome = None
resp = None
if host: if host:
self.connect(host) resp = self.connect(host)
if user: self.login(user, passwd, acct) if user: resp = self.login(user, passwd, acct)
return resp
def connect(self, host = '', port = 0): def connect(self, host = '', port = 0):
'''Connect to host. Arguments are: '''Connect to host. Arguments are:
@ -113,6 +118,7 @@ class FTP:
self.sock.connect(self.host, self.port) self.sock.connect(self.host, self.port)
self.file = self.sock.makefile('rb') self.file = self.sock.makefile('rb')
self.welcome = self.getresp() self.welcome = self.getresp()
return self.welcome
def getwelcome(self): def getwelcome(self):
'''Get the welcome message from the server. '''Get the welcome message from the server.
@ -203,6 +209,7 @@ class FTP:
resp = self.getresp() resp = self.getresp()
if resp[0] <> '2': if resp[0] <> '2':
raise error_reply, resp raise error_reply, resp
return resp
def abort(self): def abort(self):
'''Abort a file transfer. Uses out-of-band data. '''Abort a file transfer. Uses out-of-band data.
@ -224,7 +231,7 @@ class FTP:
def voidcmd(self, cmd): def voidcmd(self, cmd):
"""Send a command and expect a response beginning with '2'.""" """Send a command and expect a response beginning with '2'."""
self.putcmd(cmd) self.putcmd(cmd)
self.voidresp() return self.voidresp()
def sendport(self, host, port): def sendport(self, host, port):
'''Send a PORT command with the current host and the given port number.''' '''Send a PORT command with the current host and the given port number.'''
@ -232,7 +239,7 @@ class FTP:
pbytes = [`port/256`, `port%256`] pbytes = [`port/256`, `port%256`]
bytes = hbytes + pbytes bytes = hbytes + pbytes
cmd = 'PORT ' + string.joinfields(bytes, ',') cmd = 'PORT ' + string.joinfields(bytes, ',')
self.voidcmd(cmd) return self.voidcmd(cmd)
def makeport(self): def makeport(self):
'''Create a new socket and send a PORT command for it.''' '''Create a new socket and send a PORT command for it.'''
@ -309,6 +316,7 @@ class FTP:
if resp[0] == '3': resp = self.sendcmd('ACCT ' + acct) if resp[0] == '3': resp = self.sendcmd('ACCT ' + acct)
if resp[0] <> '2': if resp[0] <> '2':
raise error_reply, resp raise error_reply, resp
return resp
def retrbinary(self, cmd, callback, blocksize): def retrbinary(self, cmd, callback, blocksize):
'''Retrieve data in binary mode. '''Retrieve data in binary mode.
@ -323,7 +331,7 @@ class FTP:
break break
callback(data) callback(data)
conn.close() conn.close()
self.voidresp() return self.voidresp()
def retrlines(self, cmd, callback = None): def retrlines(self, cmd, callback = None):
'''Retrieve data in line mode. '''Retrieve data in line mode.
@ -347,7 +355,7 @@ class FTP:
callback(line) callback(line)
fp.close() fp.close()
conn.close() conn.close()
self.voidresp() return self.voidresp()
def storbinary(self, cmd, fp, blocksize): def storbinary(self, cmd, fp, blocksize):
'''Store a file in binary mode.''' '''Store a file in binary mode.'''
@ -358,7 +366,7 @@ class FTP:
if not buf: break if not buf: break
conn.send(buf) conn.send(buf)
conn.close() conn.close()
self.voidresp() return self.voidresp()
def storlines(self, cmd, fp): def storlines(self, cmd, fp):
'''Store a file in line mode.''' '''Store a file in line mode.'''
@ -372,12 +380,12 @@ class FTP:
buf = buf + CRLF buf = buf + CRLF
conn.send(buf) conn.send(buf)
conn.close() conn.close()
self.voidresp() return self.voidresp()
def acct(self, password): def acct(self, password):
'''Send new account name.''' '''Send new account name.'''
cmd = 'ACCT ' + password cmd = 'ACCT ' + password
self.voidcmd(cmd) return self.voidcmd(cmd)
def nlst(self, *args): def nlst(self, *args):
'''Return a list of files in a given directory (default the current).''' '''Return a list of files in a given directory (default the current).'''
@ -408,13 +416,13 @@ class FTP:
resp = self.sendcmd('RNFR ' + fromname) resp = self.sendcmd('RNFR ' + fromname)
if resp[0] <> '3': if resp[0] <> '3':
raise error_reply, resp raise error_reply, resp
self.voidcmd('RNTO ' + toname) return self.voidcmd('RNTO ' + toname)
def delete(self, filename): def delete(self, filename):
'''Delete a file.''' '''Delete a file.'''
resp = self.sendcmd('DELE ' + filename) resp = self.sendcmd('DELE ' + filename)
if resp[:3] == '250': if resp[:3] == '250':
return return resp
elif resp[:1] == '5': elif resp[:1] == '5':
raise error_perm, resp raise error_perm, resp
else: else:
@ -424,13 +432,12 @@ class FTP:
'''Change to a directory.''' '''Change to a directory.'''
if dirname == '..': if dirname == '..':
try: try:
self.voidcmd('CDUP') return self.voidcmd('CDUP')
return
except error_perm, msg: except error_perm, msg:
if msg[:3] != '500': if msg[:3] != '500':
raise error_perm, msg raise error_perm, msg
cmd = 'CWD ' + dirname cmd = 'CWD ' + dirname
self.voidcmd(cmd) return self.voidcmd(cmd)
def size(self, filename): def size(self, filename):
'''Retrieve the size of a file.''' '''Retrieve the size of a file.'''
@ -451,8 +458,9 @@ class FTP:
def quit(self): def quit(self):
'''Quit, and close the connection.''' '''Quit, and close the connection.'''
self.voidcmd('QUIT') resp = self.voidcmd('QUIT')
self.close() self.close()
return resp
def close(self): def close(self):
'''Close the connection without assuming anything about it.''' '''Close the connection without assuming anything about it.'''
@ -495,7 +503,6 @@ def parse227(resp):
host = string.join(numbers[:4], '.') host = string.join(numbers[:4], '.')
port = (string.atoi(numbers[4]) << 8) + string.atoi(numbers[5]) port = (string.atoi(numbers[4]) << 8) + string.atoi(numbers[5])
return host, port return host, port
# end parse227
def parse257(resp): def parse257(resp):
@ -520,10 +527,12 @@ def parse257(resp):
dirname = dirname + c dirname = dirname + c
return dirname return dirname
def print_line(line): def print_line(line):
'''Default retrlines callback to print a line.''' '''Default retrlines callback to print a line.'''
print line print line
def ftpcp(source, sourcename, target, targetname = '', type = 'I'): def ftpcp(source, sourcename, target, targetname = '', type = 'I'):
'''Copy file from one FTP-instance to another.''' '''Copy file from one FTP-instance to another.'''
if not targetname: targetname = sourcename if not targetname: targetname = sourcename