Possibility to specify port in __init__ of ftplib.FTP

If there is possible to connect and login to ftp server within __init__, I think it would make sense to add parameter port in ftplib.FTP. It could look like this:

    def __init__(self, host='', port=0, user='', passwd='', acct='',
                 timeout=_GLOBAL_DEFAULT_TIMEOUT, source_address=None, *,
				 encoding='utf-8'):
		self.encoding = encoding
        self.source_address = source_address
        self.timeout = timeout
        if host:
            self.connect(host, port)
            if user:
                self.login(user, passwd, acct)

Currently if I need to specify port, I have to do it like this:

with FTP() as ftp:
	ftp.connect(host, port)
	ftp.login(user, password)
	# my actions

If the port parameter would be added, I could use it like this:

with FTP(host, port, user, password) as ftp:
	# my actions

In all my cases, all I need is to connect to ftp server and work with it. If there is some trouble with connection or login, the code still can’t continue working with ftp…
Do you rather use connect() and login() explicitly or just let it connect and login within __init__ implicitly? What do you think about it?

Thanks.

Hi Marty,

I just want to give you a heads up that the python-ideas email list usually gets more attention and discussion than this discourse forum, so you might try to bring this conversation over there:

https://mail.python.org/mailman3/lists/python-ideas.python.org/

Another thing to consider is that ftplib.FTP already has a bunch of optional positional arguments in its __init__:

(host='', user='', passwd='', acct='', keyfile=None,
 certfile=None, context=None, timeout=None, source_address=None,
 *, encoding='utf-8')

So, then, port would need to either be a keyword argument, or be at the end of the list of optional keyword arguments to not break existing code. Now you get a strange API where you need to do this:

with FTP('ftp.domain.com', 'myuseristhis', pw, port=21) as ftp:
    ...

Now, the user must name the port parameter, but not the others. Kind of quirky.

Personally, I think that this small change is easy enough to achieve with subclassing if you want to create an adapter layer to have the API that you want:

class MyFTP(FTP):

    def __init__(self, host, port, user, password):
        super().__init__(self, host, user, password)
        self.port = port
        ...

    def __enter__(self):
        super().__enter__()
        self.connect(self.host, self.port)

    def __exit__(self, exception_type, exception, exception_msg):
        # bonus: you can handle any exceptions however you think
        # is the right way to do it
        ...
1 Like

Thanks for your answer. I’ll create a topic there. :slight_smile:

Not sure I buy this argument. The FTP class arguments are not positional-only, so you can do

with FTP('ftp.domain.com', port=21, user='myuseristhis', passwd=pw) as ftp:
    ...

which is probably a good idea in general anyway. BUt yeah, python-ideas is a better forum to discuss this due to popularity.

1 Like