question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

prompt with async_ doesn't clean up if cancelled

See original GitHub issue

I’m having some trouble with porting a REPL app (ntsh to prompt-toolkit 2.0. Mostly the new API is making things much simpler (thanks!), and instead of using an Application I’m now trying to use just PromptSession plus asyncio. Sometimes I want to terminate the app in response to a network event rather than user input. However, it seems that if the prompt future is cancelled, it doesn’t restore normal terminal settings, and after exit characters aren’t echoed.

Here’s a minimal example case (tested with Ubuntu 18.04, Python 3.6, prompt-toolkit 2.0.7; also requires async_timeout). Just run it and wait 5 seconds for it to exit on its own, then observe that terminal echo is off.

#!/usr/bin/env python

import asyncio

import async_timeout
from prompt_toolkit.eventloop import use_asyncio_event_loop
from prompt_toolkit.shortcuts import prompt

async def main():
    try:
        with async_timeout.timeout(5):
            text = await prompt('> ', async_=True)
        print('You entered:', text)
    except asyncio.TimeoutError:
        print('Timed out')

use_asyncio_event_loop()
asyncio.get_event_loop().run_until_complete(main())

Issue Analytics

  • State:open
  • Created 5 years ago
  • Comments:5 (3 by maintainers)

github_iconTop GitHub Comments

2reactions
derekbrokeitcommented, Mar 7, 2019

I should note that the only way I could get a complete fix on my machine required the following:

async def main():
    layout = Layout(Window(content=BufferControl(buffer=Buffer())))
    app = Application(layout=layout, full_screen=True)

    # temporary patch
    import termios, sys
    old_attrs = termios.tcgetattr(sys.stdin)

    try:
        # timeout the application after 2 seconds
        await asyncio.wait_for(app.run_async().to_asyncio_future(), 2)
    finally:
        app.exit()
        termios.tcsetattr(sys.stdin, termios.TCSANOW, old_attrs)
0reactions
derekbrokeitcommented, Mar 7, 2019

I had a similar behavior as described by @bmerry. I attempted to force the application to exit as a fix, but this did not seem to work around the issues that I observed. The following test application demonstrates what I saw in a posix shell:

import asyncio
from prompt_toolkit import Application
from prompt_toolkit.buffer import Buffer
from prompt_toolkit.layout.containers import Window
from prompt_toolkit.layout.controls import BufferControl, FormattedTextControl
from prompt_toolkit.layout.layout import Layout
from prompt_toolkit.eventloop import use_asyncio_event_loop

# set up event loop
use_asyncio_event_loop()

async def main():
    layout = Layout(Window(content=BufferControl(buffer=Buffer())))
    app = Application(layout=layout, full_screen=True)

    try:
        # timeout the application after 2 seconds
        await asyncio.wait_for(app.run_async().to_asyncio_future(), 2)
    finally:
        app.exit()

loop = asyncio.get_event_loop()
loop.run_until_complete(main())

The difference before and after included the following changes: ICRNL --> -ICRNL, ISIG --> -ISIG, and IEXTEN --> -IEXTEN. Right now, I have to run stty sane to fix the terminal after running an application. It would be better if the application set up an atexit or acted as a context manager for resetting sane terminal interface settings.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Async.StartAsTask behavior in cancellation scenarios. #3219
Today I stumbled on some unexpected behavior when cancelling a asynchronous workflow which interacts with Tasks. When StartAsTask is used it ...
Read more >
c# - Can't specify the 'async' modifier on the 'Main' method of a ...
I've just tried it out, and it seems like the cancellation request is being processed at the deepest level, even when the Wait()...
Read more >
Async/Await Prompt UI - Beginner JavaScript - Wes Bos
We are going to see how we can re-implement this with promises and async/await. We will be working out of the /exercises/72 -...
Read more >
Async Dialogs - Bluebird JS
Write a function that takes a Dialog instance and a default value. Have it return a promise that resolves to the default value...
Read more >
Cleaning up Async Functions in React's useEffect Hook ...
There is no doubt that you may have once used an async function inside the useEffect hook. If you haven't you are eventually...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found