diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 17:35:20 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 17:35:20 +0000 |
commit | e106bf94eff07d9a59771d9ccc4406421e18ab64 (patch) | |
tree | edb6545500e39df9c67aa918a6125bffc8ec1aee /docs/pages/upgrading | |
parent | Initial commit. (diff) | |
download | prompt-toolkit-e106bf94eff07d9a59771d9ccc4406421e18ab64.tar.xz prompt-toolkit-e106bf94eff07d9a59771d9ccc4406421e18ab64.zip |
Adding upstream version 3.0.36.upstream/3.0.36upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | docs/pages/upgrading/2.0.rst | 221 | ||||
-rw-r--r-- | docs/pages/upgrading/3.0.rst | 118 | ||||
-rw-r--r-- | docs/pages/upgrading/index.rst | 11 |
3 files changed, 350 insertions, 0 deletions
diff --git a/docs/pages/upgrading/2.0.rst b/docs/pages/upgrading/2.0.rst new file mode 100644 index 0000000..a580ff3 --- /dev/null +++ b/docs/pages/upgrading/2.0.rst @@ -0,0 +1,221 @@ +.. _upgrading_2_0: + +Upgrading to prompt_toolkit 2.0 +=============================== + +Prompt_toolkit 2.0 is not compatible with 1.0, however you probably want to +upgrade your applications. This page explains why we have these differences and +how to upgrade. + +If you experience some difficulties or you feel that some information is +missing from this page, don't hesitate to open a GitHub issue for help. + + +Why all these breaking changes? +------------------------------- + +After more and more custom prompt_toolkit applications were developed, it +became clear that prompt_toolkit 1.0 was not flexible enough for certain use +cases. Mostly, the development of full screen applications was not really +natural. All the important components, like the rendering, key bindings, input +and output handling were present, but the API was in the first place designed +for simple command line prompts. This was mostly notably in the following two +places: + +- First, there was the focus which was always pointing to a + :class:`~prompt_toolkit.buffer.Buffer` (or text input widget), but in full + screen applications there are other widgets, like menus and buttons which + can be focused. +- And secondly, it was impossible to make reusable UI components. All the key + bindings for the entire applications were stored together in one + ``KeyBindings`` object, and similar, all + :class:`~prompt_toolkit.buffer.Buffer` objects were stored together in one + dictionary. This didn't work well. You want reusable components to define + their own key bindings and everything. It's the idea of encapsulation. + +For simple prompts, the changes wouldn't be that invasive, but given that there +would be some, I took the opportunity to fix a couple of other things. For +instance: + +- In prompt_toolkit 1.0, we translated `\\r` into `\\n` during the input + processing. This was not a good idea, because some people wanted to handle + these keys individually. This makes sense if you keep in mind that they + correspond to `Control-M` and `Control-J`. However, we couldn't fix this + without breaking everyone's enter key, which happens to be the most important + key in prompts. + +Given that we were going to break compatibility anyway, we changed a couple of +other important things that effect both simple prompt applications and +full screen applications. These are the most important: + +- We no longer depend on Pygments for styling. While we like Pygments, it was + not flexible enough to provide all the styling options that we need, and the + Pygments tokens were not ideal for styling anything besides tokenized text. + + Instead we created something similar to CSS. All UI components can attach + classnames to themselves, as well as define an inline style. The final style is + then computed by combining the inline styles, the classnames and the style + sheet. + + There are still adaptors available for using Pygments lexers as well as for + Pygments styles. + +- The way that key bindings were defined was too complex. + ``KeyBindingsManager`` was too complex and no longer exists. Every set of key + bindings is now a + :class:`~prompt_toolkit.key_binding.KeyBindings` object and multiple of these + can be merged together at any time. The runtime performance remains the same, + but it's now easier for users. + +- The separation between the ``CommandLineInterface`` and + :class:`~prompt_toolkit.application.Application` class was confusing and in + the end, didn't really had an advantage. These two are now merged together in + one :class:`~prompt_toolkit.application.Application` class. + +- We no longer pass around the active ``CommandLineInterface``. This was one of + the most annoying things. Key bindings need it in order to change anything + and filters need it in order to evaluate their state. It was pretty annoying, + especially because there was usually only one application active at a time. + So, :class:`~prompt_toolkit.application.Application` became a ``TaskLocal``. + That is like a global variable, but scoped in the current coroutine or + context. The way this works is still not 100% correct, but good enough for + the projects that need it (like Pymux), and hopefully Python will get support + for this in the future thanks to PEP521, PEP550 or PEP555. + +All of these changes have been tested for many months, and I can say with +confidence that prompt_toolkit 2.0 is a better prompt_toolkit. + + +Some new features +----------------- + +Apart from the breaking changes above, there are also some exciting new +features. + +- We now support vt100 escape codes for Windows consoles on Windows 10. This + means much faster rendering, and full color support. + +- We have a concept of formatted text. This is an object that evaluates to + styled text. Every input that expects some text, like the message in a + prompt, or the text in a toolbar, can take any kind of formatted text as input. + This means you can pass in a plain string, but also a list of `(style, + text)` tuples (similar to a Pygments tokenized string), or an + :class:`~prompt_toolkit.formatted_text.HTML` object. This simplifies many + APIs. + +- New utilities were added. We now have function for printing formatted text + and an experimental module for displaying progress bars. + +- Autocompletion, input validation, and auto suggestion can now either be + asynchronous or synchronous. By default they are synchronous, but by wrapping + them in :class:`~prompt_toolkit.completion.ThreadedCompleter`, + :class:`~prompt_toolkit.validation.ThreadedValidator` or + :class:`~prompt_toolkit.auto_suggest.ThreadedAutoSuggest`, they will become + asynchronous by running in a background thread. + + Further, if the autocompletion code runs in a background thread, we will show + the completions as soon as they arrive. This means that the autocompletion + algorithm could for instance first yield the most trivial completions and then + take time to produce the completions that take more time. + + +Upgrading +--------- + +More guidelines on how to upgrade will follow. + + +`AbortAction` has been removed +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Prompt_toolkit 1.0 had an argument ``abort_action`` for both the +``Application`` class as well as for the ``prompt`` function. This has been +removed. The recommended way to handle this now is by capturing +``KeyboardInterrupt`` and ``EOFError`` manually. + + +Calling `create_eventloop` usually not required anymore +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Prompt_toolkit 2.0 will automatically create the appropriate event loop when +it's needed for the first time. There is no need to create one and pass it +around. If you want to run an application on top of asyncio (without using an +executor), it still needs to be activated by calling +:func:`~prompt_toolkit.eventloop.use_asyncio_event_loop` at the beginning. + + +Pygments styles and tokens +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +prompt_toolkit 2.0 no longer depends on `Pygments <http://pygments.org/>`_, but +that definitely doesn't mean that you can't use any Pygments functionality +anymore. The only difference is that Pygments stuff needs to be wrapped in an +adaptor to make it compatible with the native prompt_toolkit objects. + +- For instance, if you have a list of ``(pygments.Token, text)`` tuples for + formatting, then this needs to be wrapped in a + :class:`~prompt_toolkit.formatted_text.PygmentsTokens` object. This is an + adaptor that turns it into prompt_toolkit "formatted text". Feel free to keep + using this. + +- Pygments lexers need to be wrapped in a + :class:`~prompt_toolkit.lexers.PygmentsLexer`. This will convert the list of + Pygments tokens into prompt_toolkit formatted text. + +- If you have a Pygments style, then this needs to be converted as well. A + Pygments style class can be converted in a prompt_toolkit + :class:`~prompt_toolkit.styles.Style` with the + :func:`~prompt_toolkit.styles.pygments.style_from_pygments_cls` function + (which used to be called ``style_from_pygments``). A Pygments style + dictionary can be converted using + :func:`~prompt_toolkit.styles.pygments.style_from_pygments_dict`. + + Multiple styles can be merged together using + :func:`~prompt_toolkit.styles.merge_styles`. + + +Wordcompleter +^^^^^^^^^^^^^ + +`WordCompleter` was moved from +:class:`prompt_toolkit.contrib.completers.base.WordCompleter` to +:class:`prompt_toolkit.completion.word_completer.WordCompleter`. + + +Asynchronous autocompletion +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +By default, prompt_toolkit 2.0 completion is now synchronous. If you still want +asynchronous auto completion (which is often good thing), then you have to wrap +the completer in a :class:`~prompt_toolkit.completion.ThreadedCompleter`. + + +Filters +^^^^^^^ + +We don't distiguish anymore between `CLIFilter` and `SimpleFilter`, because the +application object is no longer passed around. This means that all filters are +a `Filter` from now on. + +All filters have been turned into functions. For instance, `IsDone` became +`is_done` and `HasCompletions` became `has_completions`. + +This was done because almost all classes were called without any arguments in +the `__init__` causing additional braces everywhere. This means that +`HasCompletions()` has to be replaced by `has_completions` (without +parenthesis). + +The few filters that took arguments as input, became functions, but still have +to be called with the given arguments. + +For new filters, it is recommended to use the `@Condition` decorator, +rather then inheriting from `Filter`. For instance: + +.. code:: python + + from prompt_toolkit.filters import Condition + + @Condition + def my_filter(); + return True # Or False + diff --git a/docs/pages/upgrading/3.0.rst b/docs/pages/upgrading/3.0.rst new file mode 100644 index 0000000..7a867c5 --- /dev/null +++ b/docs/pages/upgrading/3.0.rst @@ -0,0 +1,118 @@ +.. _upgrading_3_0: + +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: + +.. code:: python + + 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: + +.. code:: python + + 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: + +.. code:: + + from prompt_toolkit.eventloop.defaults import use_asyncio_event_loop + use_asyncio_event_loop() + +There is a few little breaking changes though. The following: + +.. code:: + + # For 2.0 + result = await PromptSession().prompt('Say something: ', async_=True) + +has to be changed into: + +.. code:: + + # 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: + +.. code:: python + + 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. + +.. code:: python + + 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) diff --git a/docs/pages/upgrading/index.rst b/docs/pages/upgrading/index.rst new file mode 100644 index 0000000..b790a64 --- /dev/null +++ b/docs/pages/upgrading/index.rst @@ -0,0 +1,11 @@ +.. _upgrading: + +Upgrading +========= + +.. toctree:: + :caption: Contents: + :maxdepth: 1 + + 2.0 + 3.0 |