-1

I am trying to use telnetlib3 with python 3.8.10 to open a connection, write data to it and try to read the reply. This is the code I am using:

reader,writer = asyncio.run(telnetlib3.open_connection(host, port))
writer.write("$SYS,INFO")
reply = asyncio.run(reader.read())

However, I get the following error for which I have no idea what it means, and for which I do not really find anything useful with google:

RuntimeError: Task <Task pending name='Task-3' coro=<TelnetReaderUnicode.read() running at /home/alex/.local/lib/python3.8/site-packages/telnetlib3/stream_reader.py:206> cb=[_run_until_complete_cb() at /usr/lib/python3.8/asyncio/base_events.py:184]> got Future <Future pending> attached to a different loop

Can this be fixed? How to use telnetlib3 properly?

Alex
  • 41,580
  • 88
  • 260
  • 469

1 Answers1

1

Each call to asyncio.run() is spawning a different event loop. You need to put all your code into the same loop:

import asyncio
import telnetlib3

async def main():
    reader, writer = await telnetlib3.open_connection('localhost', 2300)
    writer.write("$SYS,INFO")
    reply = await reader.read()
    print('reply:', reply)


asyncio.run(main())

Note that read() is a blocking method; if the connection isn't closed after the reply is sent, it may end up blocking indefinitely. You can read character-by-character instead, if there is a specific delimiter that marks the end of the reply. E.g., if we expect the reply to be terminated with an EOL character:

import asyncio
import telnetlib3

async def main():
    reader, writer = await telnetlib3.open_connection('localhost', 2300)
    writer.write("$SYS,INFO")

    reply = []
    while True:
        c = await reader.read(1)
        if not c:
            break

        if c in ['\r', '\n']:
            break

        reply.append(c)

    print('reply:', ''.join(reply))


asyncio.run(main())

As for "how do I create a class out of it?", I'm not sure how to answer that. The example above could be written like:

import asyncio
import telnetlib3

class Communicator:
    def __init__(self, host, port):
        self.host = host
        self.port = port

    async def connect(self):
        self.reader, self.writer = await telnetlib3.open_connection(self.host, self.port)

    async def get_info(self):
        self.writer.write("$SYS,INFO")

        reply = []
        while True:
            c = await self.reader.read(1)
            if not c:
                break

            if c in ['\r', '\n']:
                break

            reply.append(c)

        return ''.join(reply)

async def main():
    conn = Communicator('localhost', 2300)
    await conn.connect()
    print('info:', await conn.get_info())


asyncio.run(main())

That's not necessarily a great example, but it works. There are additional examples in the telnetlib3 documentation that may also be of interest.

larsks
  • 277,717
  • 41
  • 399
  • 399
  • Thanks for the hint, but not sure if it works. I do not get any reply and the code seems to be stuck. Also, how do I create a class of it? I mean a module that creates the connection and then can have different write/read sessions? Is there some other telnetlib that actually can be used maybe? – Alex Jun 06 '23 at 13:38
  • i mean you have __init__ to create the connection, and another method to write and read . but that seems not to be possible to be done – Alex Jun 06 '23 at 13:46
  • Is there no way to use telnetlib3 without asyncio? I want/need to use this as part of a test script using py.test and with always calling this with "asyncio.run" I still have no idea how to do that ... – Alex Jun 07 '23 at 05:44
  • Beside the example does not seem to work. I get the message `Terminal emulator detected (unknown), switching to interactive shell` – Alex Jun 07 '23 at 05:49
  • `telnetlib3` requires asyncio. – larsks Jun 07 '23 at 11:49