TypeError: prepare() got an unexpected keyword argument 'ConnectTimeout'

246 views
Skip to first unread message

Scott Willis

unread,
Oct 28, 2021, 10:06:26 PM10/28/21
to asyncssh-users
Attempting to set a shorter login timeout by adding `kwargs['ConnectTimeout'] = 5` to kwargs for the asyncssh.create_connection() call, getting an exception:
    "TypeError: prepare() got an unexpected keyword argument 'ConnectTimeout'.

In misc.py, starting line 254, the code I see:
```
class Options:
    """Container for configuration options"""

    def __init__(self, options=None, **kwargs):
        if options:
            if not isinstance(options, type(self)):
                raise TypeError('Invalid %s, got %s' %
                                (type(self).__name__, type(options).__name__))

            self.kwargs = options.kwargs.copy()
        else:
            self.kwargs = {}

        self.kwargs.update(kwargs)
        self.prepare(**self.kwargs)

    def prepare(self):
        """Pre-process configuration options"""
```
It appears that lines:  `self.kwargs = {}`, `self.kwargs.update(kwargs)` and `self.prepare(**self.kwargs)` are executing.  Then it calls `prepare(self)` and raises the exception, because `prepare` has no parameters other than (self).

Is `prepare(self)` missing `,**kwargs` or am I misusing the library?

If I want to set a shorter connection timeout, how should I do that?

Call stack:
```
Traceback (most recent call last):
<my code here>  which sets parameters host, port, **kwargs.
  File "/home/swillis/.local/lib/python3.7/site-packages/asyncssh/connection.py", line 7161, in create_connection
    conn = await connect(host, port, client_factory=client_factory, **kwargs)
  File "/home/swillis/.local/lib/python3.7/site-packages/asyncssh/connection.py", line 6853, in connect
    **kwargs)
  File "/home/swillis/.local/lib/python3.7/site-packages/asyncssh/connection.py", line 5596, in __init__
    super().__init__(options=options, last_config=last_config, **kwargs)
  File "/home/swillis/.local/lib/python3.7/site-packages/asyncssh/misc.py", line 268, in __init__
    self.prepare(**self.kwargs)
TypeError: prepare() got an unexpected keyword argument 'ConnectTimeout'```

Ron Frederick

unread,
Oct 29, 2021, 12:54:22 AM10/29/21
to Scott Willis, asyncssh-users
Hi Scott,

There are a few points here.

First, “ConnectTimeout” is a config file option, not an optional keyword argument. The equivalent keyword argument right now is named “login_timeout”, and you can set it by just adding it as an argument to create_connection(). In other words, add “login_timeout=5” as another one of the arguments in your create_connection() call. See the documentation at https://asyncssh.readthedocs.io/en/latest/api.html#sshclientconnectionoptions for all the available keyword options you can use on the various connect calls.

The way this works is that SSHClientConnectionOptions is a subclass of the Options class you found, and its prepare() call has all of the individual options listed as arguments, each with a default value. Any additional keyword arguments passed to create_connection() will be pass to connect(), which creates an SSHClientConnectionOptions instance using these parameters. These keyword arguments are stored in “self.kwargs” in the Options constructor as shown in the code you listed below, and that is passed to prepare() as keyword arguments that will vary depending on the subclass being instantiated. The prepare() method is a no-op in  this parent class. it is meant to only be implemented by the child classes (though in some cases there are also intermediate subclasses that handle arguments common across connect() and listen() calls).

That said, the login_timeout only applies after the TCP connection succeeds right now. If making the TCP connection is the source of the delay, using login_timeout won’t work. You’ll need to use asyncio.wait_for() on your connect call. See https://github.com/ronf/asyncssh/discussions/409 for more details about how to do this.

I’ve gotten multiple questions about this recently, so I’m going to look into adding a new connect_timeout keyword argument and see if I can make it apply even during the TCP connect. If I do this, I’ll also switch the config file option “ConnectTimeout” over to using that, which would be more consistent with how I think this option works in OpenSSH.
-- 
Ron Frederick
ro...@timeheart.net



Ron Frederick

unread,
Oct 30, 2021, 4:00:56 PM10/30/21
to Scott Willis, asyncssh-users
Hi Scott,

Following up on this, I’ve gotten enough questions recently about this timeout issue that I decided to add a new “connect_timeout” connection option which basically acts as a shorthand for using asyncio.await_for(). See https://github.com/ronf/asyncssh/issues/415 for more details about this new option. This change is only in the “develop” branch of AsyncSSH for now, but I will be including it in my next release. In the meantime, you can use the asyncio.wait_for() syntax discussed there against the released versions of AsyncSSH.
Reply all
Reply to author
Forward
0 new messages