diff --git a/Lib/ftplib.py b/Lib/ftplib.py index 9dce22b35b6..22aff51acba 100644 --- a/Lib/ftplib.py +++ b/Lib/ftplib.py @@ -76,9 +76,15 @@ class FTP: '''An FTP client class. - To create a connection, call the class using these argument: - host, user, passwd, acct - These are all strings, and have default value ''. + To create a connection, call the class using these arguments: + host, user, passwd, acct, timeout + + The first four arguments are all strings, and have default value ''. + timeout must be numeric and defaults to None if not passed, + meaning that no timeout will be set on any ftp socket(s) + If a timeout is passed, then this is now the default timeout for all ftp + socket operations for this instance. + Then use self.connect() with optional host and port argument. To download a file, use ftp.retrlines('RETR ' + filename), @@ -102,32 +108,24 @@ class FTP: # Initialize host to localhost, port to standard ftp port # Optional arguments are host (for connect()), # and user, passwd, acct (for login()) - def __init__(self, host='', user='', passwd='', acct=''): + def __init__(self, host='', user='', passwd='', acct='', timeout=None): + self.timeout = timeout if host: self.connect(host) - if user: self.login(user, passwd, acct) + if user: + self.login(user, passwd, acct) - def connect(self, host = '', port = 0): + def connect(self, host='', port=0): '''Connect to host. Arguments are: - - host: hostname to connect to (string, default previous host) - - port: port to connect to (integer, default previous port)''' - if host: self.host = host - if port: self.port = port - msg = "getaddrinfo returns an empty list" - for res in socket.getaddrinfo(self.host, self.port, 0, socket.SOCK_STREAM): - af, socktype, proto, canonname, sa = res - try: - self.sock = socket.socket(af, socktype, proto) - self.sock.connect(sa) - except socket.error, msg: - if self.sock: - self.sock.close() - self.sock = None - continue - break - if not self.sock: - raise socket.error, msg - self.af = af + - host: hostname to connect to (string, default previous host) + - port: port to connect to (integer, default previous port) + ''' + if host != '': + self.host = host + if port > 0: + self.port = port + self.sock = socket.create_connection((self.host, self.port), self.timeout) + self.af = self.sock.family self.file = self.sock.makefile('rb') self.welcome = self.getresp() return self.welcome diff --git a/Lib/test/test_ftplib.py b/Lib/test/test_ftplib.py new file mode 100644 index 00000000000..8cf78868664 --- /dev/null +++ b/Lib/test/test_ftplib.py @@ -0,0 +1,68 @@ +import socket +import threading +import ftplib +import time + +from unittest import TestCase +from test import test_support + +def server(evt): + serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + serv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + serv.bind(("", 9091)) + serv.listen(5) + conn, addr = serv.accept() + conn.send("1 Hola mundo\n") + conn.close() + serv.close() + evt.set() + +class GeneralTests(TestCase): + + def setUp(self): + ftplib.FTP.port = 9091 + self.evt = threading.Event() + threading.Thread(target=server, args=(self.evt,)).start() + time.sleep(.1) + + def tearDown(self): + self.evt.wait() + + def testBasic(self): + # do nothing + ftplib.FTP() + + # connects + ftp = ftplib.FTP("localhost") + ftp.sock.close() + + def testTimeoutDefault(self): + # default + ftp = ftplib.FTP("localhost") + self.assertTrue(ftp.sock.gettimeout() is None) + ftp.sock.close() + + def testTimeoutValue(self): + # a value + ftp = ftplib.FTP("localhost", timeout=30) + self.assertEqual(ftp.sock.gettimeout(), 30) + ftp.sock.close() + + def testTimeoutNone(self): + # None, having other default + previous = socket.getdefaulttimeout() + socket.setdefaulttimeout(30) + try: + ftp = ftplib.FTP("localhost", timeout=None) + finally: + socket.setdefaulttimeout(previous) + self.assertEqual(ftp.sock.gettimeout(), 30) + ftp.close() + + + +def test_main(verbose=None): + test_support.run_unittest(GeneralTests) + +if __name__ == '__main__': + test_main()