Search code examples
python-3.xasync-awaitsftppython-asynciosanic

AsyncSSH Create SFTP Client Error- too many values to unpack


I am using the asyncssh library in a Sanic application (running the Asyncio Event loop) to create an SFTP client connection. In my code I am doing this:

class MyClass:
    async def connect(self, host, username, password, port):
        return await asyncssh.connect(host=host, port=port, username=username, password=password, known_hosts=None)

    async def establish_sftp_client(self, conn):
        return await conn.start_sftp_client()

    # This is my invoker:
    async def create_connection(self, <some args>):
        conn = await self.connect()
        sftp_client = await self.establish_sftp_client(conn)
        ...
        return conn, sftp_client

I am getting this error when I try to do this:

Traceback (most recent call last):
File "/tmp/pycharm_projects/<MY SANIC APP>/requests/helpers.py", line 378, in establish_sftp_client
    return await conn.start_sftp_client()
  File "<MY SANIC APP>/venv/lib/python3.6/site-packages/asyncssh/misc.py", line 182, in __await__
    return (yield from self._coro)
  File "<MY SANIC APP>/venv/lib/python3.6/site-packages/asyncssh/connection.py", line 3503, in start_sftp_client
    encoding=None)
ValueError: too many values to unpack (expected 3)

When I debug this, and log out what that start_sftp_client() is actually returning, I get this:

(asyncssh.stream.SSHWriter object at 0x7f51bbb29dd8, asyncssh.stream.SSHReader object at 0x7f51bbb29da0, asyncssh.stream.SSHReader object at 0x7f51b99b7978, asyncssh.stream.SSHClientStreamSession object at 0x7f51bbb29f98)

So it actually is returning 4 values...and when I look at the source code for asyncSSH, at what start_sftp_client() actually does, it is looking for only three:

writer, reader, _ = yield from self.open_session(subsystem='sftp', encoding=None)

So it makes sense that this error is thrown...but why?

When I run this method from the python console -- it works just fine. an SFTP client is created properly from this script:

import asyncssh, asyncio

async def x():
    conn = await asyncssh.connect(host='<host'>, username='some name', password='some pass', port=22, known_hosts=None)
    sftp = await conn.start_sftp_client()
    print("sftp {}".format(sftp)) # This works!

asyncio.get_event_loop().run_until_complete(x())

Solution

  • Found the underlying cause of this issue finally, after putting log statements everywhere in the code base. These lines were hidden in some obscure files:

    @asyncio.coroutine
    def open_session(self, *args, **kwargs):            
        chan, session = yield from self.create_session(CoreSSHClientStreamSession,
                                                       *args, **kwargs)
    
        return (asyncssh.stream.SSHWriter(session, chan), asyncssh.stream.SSHReader(session, chan),
                asyncssh.stream.SSHReader(session, chan, asyncssh.constants.EXTENDED_DATA_STDERR))
    
    
    asyncssh.SSHClientConnection.open_session = open_session
    

    That last line overwrites the open_session method from asyncssh!