0

I try to try to write some kind of renderer for the command line that should be able to print data from stdin and from another data source using asyncio and blessed, which is an improved version of python-blessings.

Here is what I have so far:

import asyncio
from blessed import Terminal

@asyncio.coroutine
def render(term):
    while True:
        received = yield
        if received:
            print(term.bold + received + term.normal)

async def ping(renderer):
    while True:
        renderer.send('ping')
        await asyncio.sleep(1)

async def input_reader(term, renderer):
    while True:
        with term.cbreak():
            val = term.inkey()
            if val.is_sequence:
               renderer.send("got sequence: {0}.".format((str(val), val.name, val.code)))
            elif val:
               renderer.send("got {0}.".format(val))

async def client():
    term = Terminal()
    renderer = render(term)
    render_task = asyncio.ensure_future(renderer)
    pinger = asyncio.ensure_future(ping(renderer))
    inputter = asyncio.ensure_future(input_reader(term, renderer))
    done, pending = await asyncio.wait(
        [pinger, inputter, renderer],
        return_when=asyncio.FIRST_COMPLETED,
    )
    for task in pending:
        task.cancel()

if __name__ == '__main__':
    asyncio.get_event_loop().run_until_complete(client())
    asyncio.get_event_loop().run_forever()

For learning and testing purposes there is just a dump ping that sends 'ping' each second and another routine, that should grab key inputs and also sends them to my renderer.

But ping only appears once in the command line using this code and the input_reader works as expected. When I replace input_reader with a pong similar to ping everything is fine.

This is how it looks when typing 'pong', although if it takes ten seconds to write 'pong':

$ python async_term.py
ping
got p.
got o.
got n.
got g.
dahrens
  • 3,879
  • 1
  • 20
  • 38

1 Answers1

0

It seems like blessed is not built to work correctly with asyncio: inkey() is a blocking method. This will block any other couroutine.

You can use a loop with kbhit() and await asyncio.sleep() to yield control to other coroutines - but this is not a clean asyncio solution.

Udi
  • 29,222
  • 9
  • 96
  • 129
  • 1
    For `inkey` with `timeout=0` [the docs](https://blessed.readthedocs.io/en/latest/overview.html#inkey) say it is not blocking. But the behavior does not change. Do you have any advice for a clean solution? It must not be blessed that is responsible for reading from stdin - I mostly want to use it for output control. – dahrens Apr 01 '17 at 14:21