Upgrading to prompt_toolkit 3.0

There are two major changes in 3.0 to be aware of:

  • First, prompt_toolkit uses the asyncio event loop natively, rather then using its own implementations of event loops. This means that all coroutines are now asyncio coroutines, and all Futures are asyncio futures. Asynchronous generators became real asynchronous generators as well.
  • Prompt_toolkit uses type annotations (almost) everywhere. This should not break any code, but its very helpful in many ways.

There are some minor breaking changes:

  • The dialogs API had to change (see below).

Detecting the prompt_toolkit version

Detecting whether version 3 is being used can be done as follows:

from prompt_toolkit import __version__ as ptk_version

PTK3 = ptk_version.startswith('3.')

Fixing calls to get_event_loop

Every usage of get_event_loop has to be fixed. An easy way to do this is by changing the imports like this:

if PTK3:
    from asyncio import get_event_loop
else:
    from prompt_toolkit.eventloop import get_event_loop

Notice that for prompt_toolkit 2.0, get_event_loop returns a prompt_toolkit EventLoop object. This is not an asyncio eventloop, but the API is similar.

There are some changes to the eventloop API:

version 2.0 version 3.0 (asyncio)
loop.run_in_executor(callback) loop.run_in_executor(None, callback)
loop.call_from_executor(callback) loop.call_soon_threadsafe(callback)

Running on top of asyncio

For 2.0, you had tell prompt_toolkit to run on top of the asyncio event loop. Now it’s the default. So, you can simply remove the following two lines:

from prompt_toolkit.eventloop.defaults import use_asyncio_event_loop
use_asyncio_event_loop()

There is a few little breaking changes though. The following:

# For 2.0
result = await PromptSession().prompt('Say something: ', async_=True)

has to be changed into:

# For 3.0
result = await PromptSession().prompt_async('Say something: ')

Further, it’s impossible to call the prompt() function within an asyncio application (within a coroutine), because it will try to run the event loop again. In that case, always use prompt_async().

Changes to the dialog functions

The original way of using dialog boxes looked like this:

from prompt_toolkit.shortcuts import input_dialog

result = input_dialog(title='...', text='...')

Now, the dialog functions return a prompt_toolkit Application object. You have to call either its run or run_async method to display the dialog. The async_ parameter has been removed everywhere.

if PTK3:
    result = input_dialog(title='...', text='...').run()
else:
    result = input_dialog(title='...', text='...')

# Or

if PTK3:
    result = await input_dialog(title='...', text='...').run_async()
else:
    result = await input_dialog(title='...', text='...', async_=True)