diff options
218 files changed, 513 insertions, 322 deletions
@@ -1,6 +1,33 @@ CHANGELOG ========= +3.0.46: 2024-06-04 +------------------ + +Fixes: +- Fix pytest capsys fixture compatibility. + + +3.0.45: 2024-05-28 +------------------ + +Fixes: +- Improve performance of `GrammarCompleter` (faster deduplication of completions). + + +3.0.44: 2024-05-27 +------------------ + +New features: +- Accept `os.PathLike` in `FileHistory` (typing fix). + +Fixes: +- Fix memory leak in filters. +- Improve performance of progress bar formatters. +- Fix compatibility when a SIGINT handler is installed by non-Python (Rust, C). +- Limit number of completions in buffer to 10k by default (for performance). + + 3.0.43: 2023-12-13 ------------------ diff --git a/PROJECTS.rst b/PROJECTS.rst index 863c727..eabfe13 100644 --- a/PROJECTS.rst +++ b/PROJECTS.rst @@ -39,6 +39,7 @@ Shells: - `kafka-shell <https://github.com/devshawn/kafka-shell>`_: A supercharged shell for Apache Kafka. - `starterTree <https://github.com/thomas10-10/starterTree>`_: A command launcher organized in a tree structure with fuzzy autocompletion - `git-delete-merged-branches <https://github.com/hartwork/git-delete-merged-branches>`_: Command-line tool to delete merged Git branches +- `radian <https://github.com/randy3k/radian>`_: A 21 century R console Full screen applications: @@ -51,6 +52,7 @@ Full screen applications: - `sanctuary-zero <https://github.com/t0xic0der/sanctuary-zero>`_: A secure chatroom with zero logging and total transience. - `Hummingbot <https://github.com/CoinAlpha/hummingbot>`_: A Cryptocurrency Algorithmic Trading Platform - `git-bbb <https://github.com/MrMino/git-bbb>`_: A `git blame` browser. +- `ass <https://github.com/mlang/ass`_: An OpenAI Assistants API client. Libraries: @@ -80,8 +80,6 @@ It's worth noting that the implementation is a "best effort of what is possible". Both Unix and Windows terminals have their limitations. But in general, the Unix experience will still be a little better. -For Windows, it's recommended to use either `cmder -<http://cmder.net/>`_ or `conemu <https://conemu.github.io/>`_. Getting started *************** diff --git a/docs/conf.py b/docs/conf.py index abf6db3..dbbcecc 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -41,16 +41,16 @@ master_doc = "index" # General information about the project. project = "prompt_toolkit" -copyright = "2014-2023, Jonathan Slenders" +copyright = "2014-2024, Jonathan Slenders" # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. -version = "3.0.43" +version = "3.0.46" # The full version, including alpha/beta/rc tags. -release = "3.0.43" +release = "3.0.46" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/docs/pages/advanced_topics/unit_testing.rst b/docs/pages/advanced_topics/unit_testing.rst index 2224bfc..02ca82d 100644 --- a/docs/pages/advanced_topics/unit_testing.rst +++ b/docs/pages/advanced_topics/unit_testing.rst @@ -116,6 +116,21 @@ single fixture that does it for every test. Something like this: with create_app_session(input=pipe_input, output=DummyOutput()): yield pipe_input +For compatibility with pytest's ``capsys`` fixture, we have to create a new +:class:`~prompt_toolkit.application.current.AppSession` for every test. This +can be done in an autouse fixture. Pytest replaces ``sys.stdout`` with a new +object in every test that uses ``capsys`` and the following will ensure that +the new :class:`~prompt_toolkit.application.current.AppSession` will each time +refer to the latest output. + +.. code:: python + + from prompt_toolkit.application import create_app_session + + @fixture(autouse=True, scope="function") + def _pt_app_session() + with create_app_session(): + yield Type checking ------------- diff --git a/docs/pages/full_screen_apps.rst b/docs/pages/full_screen_apps.rst index 805c8c7..9123c20 100644 --- a/docs/pages/full_screen_apps.rst +++ b/docs/pages/full_screen_apps.rst @@ -358,7 +358,7 @@ As said earlier, a :class:`~prompt_toolkit.layout.Window` is a .. note:: - Basically, windows are the leafs in the tree structure that represent the UI. + Basically, windows are the leaves in the tree structure that represent the UI. A :class:`~prompt_toolkit.layout.Window` provides a "view" on the :class:`~prompt_toolkit.layout.UIControl`, which provides lines of content. The @@ -391,7 +391,7 @@ A :class:`~prompt_toolkit.layout.processors.Processor` operates on individual lines. Basically, it takes a (formatted) line and produces a new (formatted) line. -Some build-in processors: +Some built-in processors: +----------------------------------------------------------------------------+-----------------------------------------------------------+ | Processor | Usage: | diff --git a/docs/pages/progress_bars.rst b/docs/pages/progress_bars.rst index 54a8ee1..5248f98 100644 --- a/docs/pages/progress_bars.rst +++ b/docs/pages/progress_bars.rst @@ -237,7 +237,7 @@ printing text possible while the progress bar is displayed. This ensures that printing happens above the progress bar. Further, when "x" is pressed, we set a cancel flag, which stops the progress. -It would also be possible to send `SIGINT` to the mean thread, but that's not +It would also be possible to send `SIGINT` to the main thread, but that's not always considered a clean way of cancelling something. In the example above, we also display a toolbar at the bottom which shows the diff --git a/examples/dialogs/button_dialog.py b/examples/dialogs/button_dialog.py index 7a99b9a..24e1a47 100755 --- a/examples/dialogs/button_dialog.py +++ b/examples/dialogs/button_dialog.py @@ -2,6 +2,7 @@ """ Example of button dialog window. """ + from prompt_toolkit.shortcuts import button_dialog diff --git a/examples/dialogs/checkbox_dialog.py b/examples/dialogs/checkbox_dialog.py index 90be263..70df166 100755 --- a/examples/dialogs/checkbox_dialog.py +++ b/examples/dialogs/checkbox_dialog.py @@ -2,6 +2,7 @@ """ Example of a checkbox-list-based dialog. """ + from prompt_toolkit.formatted_text import HTML from prompt_toolkit.shortcuts import checkboxlist_dialog, message_dialog from prompt_toolkit.styles import Style @@ -30,7 +31,7 @@ results = checkboxlist_dialog( if results: message_dialog( title="Room service", - text="You selected: %s\nGreat choice sir !" % ",".join(results), + text="You selected: {}\nGreat choice sir !".format(",".join(results)), ).run() else: message_dialog("*starves*").run() diff --git a/examples/dialogs/input_dialog.py b/examples/dialogs/input_dialog.py index 6235265..057bc37 100755 --- a/examples/dialogs/input_dialog.py +++ b/examples/dialogs/input_dialog.py @@ -2,6 +2,7 @@ """ Example of an input box dialog. """ + from prompt_toolkit.shortcuts import input_dialog diff --git a/examples/dialogs/messagebox.py b/examples/dialogs/messagebox.py index 4642b84..7b11580 100755 --- a/examples/dialogs/messagebox.py +++ b/examples/dialogs/messagebox.py @@ -2,6 +2,7 @@ """ Example of a message box window. """ + from prompt_toolkit.shortcuts import message_dialog diff --git a/examples/dialogs/password_dialog.py b/examples/dialogs/password_dialog.py index 39d7b9c..d3752ba 100755 --- a/examples/dialogs/password_dialog.py +++ b/examples/dialogs/password_dialog.py @@ -2,6 +2,7 @@ """ Example of an password input dialog. """ + from prompt_toolkit.shortcuts import input_dialog diff --git a/examples/dialogs/progress_dialog.py b/examples/dialogs/progress_dialog.py index 1fd3ffb..7a29f1b 100755 --- a/examples/dialogs/progress_dialog.py +++ b/examples/dialogs/progress_dialog.py @@ -2,6 +2,7 @@ """ Example of a progress bar dialog. """ + import os import time diff --git a/examples/dialogs/radio_dialog.py b/examples/dialogs/radio_dialog.py index 94d80e2..aed9d66 100755 --- a/examples/dialogs/radio_dialog.py +++ b/examples/dialogs/radio_dialog.py @@ -2,6 +2,7 @@ """ Example of a radio list box dialog. """ + from prompt_toolkit.formatted_text import HTML from prompt_toolkit.shortcuts import radiolist_dialog diff --git a/examples/dialogs/styled_messagebox.py b/examples/dialogs/styled_messagebox.py index 3f6fc53..5ca197f 100755 --- a/examples/dialogs/styled_messagebox.py +++ b/examples/dialogs/styled_messagebox.py @@ -7,6 +7,7 @@ styling. This also demonstrates that the `title` argument can be any kind of formatted text. """ + from prompt_toolkit.formatted_text import HTML from prompt_toolkit.shortcuts import message_dialog from prompt_toolkit.styles import Style diff --git a/examples/dialogs/yes_no_dialog.py b/examples/dialogs/yes_no_dialog.py index 4b08dd6..6463a38 100755 --- a/examples/dialogs/yes_no_dialog.py +++ b/examples/dialogs/yes_no_dialog.py @@ -2,6 +2,7 @@ """ Example of confirmation (yes/no) dialog window. """ + from prompt_toolkit.shortcuts import yes_no_dialog diff --git a/examples/full-screen/buttons.py b/examples/full-screen/buttons.py index 540194d..f741b26 100755 --- a/examples/full-screen/buttons.py +++ b/examples/full-screen/buttons.py @@ -2,6 +2,7 @@ """ A simple example of a few buttons and click handlers. """ + from prompt_toolkit.application import Application from prompt_toolkit.application.current import get_app from prompt_toolkit.key_binding import KeyBindings diff --git a/examples/full-screen/calculator.py b/examples/full-screen/calculator.py index 1cb513f..1f2b329 100755 --- a/examples/full-screen/calculator.py +++ b/examples/full-screen/calculator.py @@ -3,6 +3,7 @@ A simple example of a calculator program. This could be used as inspiration for a REPL. """ + from prompt_toolkit.application import Application from prompt_toolkit.document import Document from prompt_toolkit.key_binding import KeyBindings diff --git a/examples/full-screen/dummy-app.py b/examples/full-screen/dummy-app.py index 7ea7506..b9e246b 100755 --- a/examples/full-screen/dummy-app.py +++ b/examples/full-screen/dummy-app.py @@ -2,6 +2,7 @@ """ This is the most simple example possible. """ + from prompt_toolkit import Application app = Application(full_screen=False) diff --git a/examples/full-screen/full-screen-demo.py b/examples/full-screen/full-screen-demo.py index de7379a..af3ef5f 100755 --- a/examples/full-screen/full-screen-demo.py +++ b/examples/full-screen/full-screen-demo.py @@ -1,6 +1,6 @@ #!/usr/bin/env python -""" -""" +""" """ + from pygments.lexers.html import HtmlLexer from prompt_toolkit.application import Application @@ -218,7 +218,7 @@ application = Application( def run(): result = application.run() - print("You said: %r" % result) + print(f"You said: {result!r}") if __name__ == "__main__": diff --git a/examples/full-screen/hello-world.py b/examples/full-screen/hello-world.py index b818018..86102d6 100755 --- a/examples/full-screen/hello-world.py +++ b/examples/full-screen/hello-world.py @@ -2,6 +2,7 @@ """ A simple example of a a text area displaying "Hello World!". """ + from prompt_toolkit.application import Application from prompt_toolkit.key_binding import KeyBindings from prompt_toolkit.layout import Layout diff --git a/examples/full-screen/no-layout.py b/examples/full-screen/no-layout.py index be5c6f8..a9961c0 100644 --- a/examples/full-screen/no-layout.py +++ b/examples/full-screen/no-layout.py @@ -2,6 +2,7 @@ """ An empty full screen application without layout. """ + from prompt_toolkit import Application Application(full_screen=True).run() diff --git a/examples/full-screen/pager.py b/examples/full-screen/pager.py index 799c834..61336a5 100755 --- a/examples/full-screen/pager.py +++ b/examples/full-screen/pager.py @@ -2,6 +2,7 @@ """ A simple application that shows a Pager application. """ + from pygments.lexers.python import PythonLexer from prompt_toolkit.application import Application @@ -28,10 +29,7 @@ def get_statusbar_text(): ("class:status", _pager_py_path + " - "), ( "class:status.position", - "{}:{}".format( - text_area.document.cursor_position_row + 1, - text_area.document.cursor_position_col + 1, - ), + f"{text_area.document.cursor_position_row + 1}:{text_area.document.cursor_position_col + 1}", ), ("class:status", " - Press "), ("class:status.key", "Ctrl-C"), diff --git a/examples/full-screen/scrollable-panes/simple-example.py b/examples/full-screen/scrollable-panes/simple-example.py index a94274f..cdf2674 100644 --- a/examples/full-screen/scrollable-panes/simple-example.py +++ b/examples/full-screen/scrollable-panes/simple-example.py @@ -2,6 +2,7 @@ """ A simple example of a scrollable pane. """ + from prompt_toolkit.application import Application from prompt_toolkit.application.current import get_app from prompt_toolkit.key_binding import KeyBindings diff --git a/examples/full-screen/scrollable-panes/with-completion-menu.py b/examples/full-screen/scrollable-panes/with-completion-menu.py index fba8d17..e08609d 100644 --- a/examples/full-screen/scrollable-panes/with-completion-menu.py +++ b/examples/full-screen/scrollable-panes/with-completion-menu.py @@ -2,6 +2,7 @@ """ A simple example of a scrollable pane. """ + from prompt_toolkit.application import Application from prompt_toolkit.application.current import get_app from prompt_toolkit.completion import WordCompleter diff --git a/examples/full-screen/simple-demos/alignment.py b/examples/full-screen/simple-demos/alignment.py index b20b43d..10a8044 100755 --- a/examples/full-screen/simple-demos/alignment.py +++ b/examples/full-screen/simple-demos/alignment.py @@ -2,6 +2,7 @@ """ Demo of the different Window alignment options. """ + from prompt_toolkit.application import Application from prompt_toolkit.key_binding import KeyBindings from prompt_toolkit.layout.containers import HSplit, Window, WindowAlign diff --git a/examples/full-screen/simple-demos/autocompletion.py b/examples/full-screen/simple-demos/autocompletion.py index bcbb594..f041637 100755 --- a/examples/full-screen/simple-demos/autocompletion.py +++ b/examples/full-screen/simple-demos/autocompletion.py @@ -6,6 +6,7 @@ completion. Important is to make sure that there is a `CompletionsMenu` in the layout, otherwise the completions won't be visible. """ + from prompt_toolkit.application import Application from prompt_toolkit.buffer import Buffer from prompt_toolkit.completion import WordCompleter diff --git a/examples/full-screen/simple-demos/colorcolumn.py b/examples/full-screen/simple-demos/colorcolumn.py index 054aa44..184b997 100755 --- a/examples/full-screen/simple-demos/colorcolumn.py +++ b/examples/full-screen/simple-demos/colorcolumn.py @@ -2,6 +2,7 @@ """ Colorcolumn example. """ + from prompt_toolkit.application import Application from prompt_toolkit.buffer import Buffer from prompt_toolkit.key_binding import KeyBindings diff --git a/examples/full-screen/simple-demos/cursorcolumn-cursorline.py b/examples/full-screen/simple-demos/cursorcolumn-cursorline.py index 505b3ee..a6eb5e6 100755 --- a/examples/full-screen/simple-demos/cursorcolumn-cursorline.py +++ b/examples/full-screen/simple-demos/cursorcolumn-cursorline.py @@ -2,6 +2,7 @@ """ Cursorcolumn / cursorline example. """ + from prompt_toolkit.application import Application from prompt_toolkit.buffer import Buffer from prompt_toolkit.key_binding import KeyBindings diff --git a/examples/full-screen/simple-demos/float-transparency.py b/examples/full-screen/simple-demos/float-transparency.py index 4dc38fc..a7a88c2 100755 --- a/examples/full-screen/simple-demos/float-transparency.py +++ b/examples/full-screen/simple-demos/float-transparency.py @@ -2,6 +2,7 @@ """ Example of the 'transparency' attribute of `Window' when used in a Float. """ + from prompt_toolkit.application import Application from prompt_toolkit.formatted_text import HTML from prompt_toolkit.key_binding import KeyBindings diff --git a/examples/full-screen/simple-demos/floats.py b/examples/full-screen/simple-demos/floats.py index 0d45be9..4d79c2b 100755 --- a/examples/full-screen/simple-demos/floats.py +++ b/examples/full-screen/simple-demos/floats.py @@ -2,6 +2,7 @@ """ Horizontal split example. """ + from prompt_toolkit.application import Application from prompt_toolkit.key_binding import KeyBindings from prompt_toolkit.layout.containers import Float, FloatContainer, Window diff --git a/examples/full-screen/simple-demos/focus.py b/examples/full-screen/simple-demos/focus.py index 9fe9b8f..fbf965e 100755 --- a/examples/full-screen/simple-demos/focus.py +++ b/examples/full-screen/simple-demos/focus.py @@ -2,6 +2,7 @@ """ Demonstration of how to programmatically focus a certain widget. """ + from prompt_toolkit.application import Application from prompt_toolkit.buffer import Buffer from prompt_toolkit.document import Document diff --git a/examples/full-screen/simple-demos/horizontal-align.py b/examples/full-screen/simple-demos/horizontal-align.py index bb0de12..038823a 100755 --- a/examples/full-screen/simple-demos/horizontal-align.py +++ b/examples/full-screen/simple-demos/horizontal-align.py @@ -2,6 +2,7 @@ """ Horizontal align demo with HSplit. """ + from prompt_toolkit.application import Application from prompt_toolkit.formatted_text import HTML from prompt_toolkit.key_binding import KeyBindings diff --git a/examples/full-screen/simple-demos/horizontal-split.py b/examples/full-screen/simple-demos/horizontal-split.py index 0427e67..660cd57 100755 --- a/examples/full-screen/simple-demos/horizontal-split.py +++ b/examples/full-screen/simple-demos/horizontal-split.py @@ -2,6 +2,7 @@ """ Horizontal split example. """ + from prompt_toolkit.application import Application from prompt_toolkit.key_binding import KeyBindings from prompt_toolkit.layout.containers import HSplit, Window diff --git a/examples/full-screen/simple-demos/line-prefixes.py b/examples/full-screen/simple-demos/line-prefixes.py index b52cb48..687d436 100755 --- a/examples/full-screen/simple-demos/line-prefixes.py +++ b/examples/full-screen/simple-demos/line-prefixes.py @@ -6,6 +6,7 @@ completion. Important is to make sure that there is a `CompletionsMenu` in the layout, otherwise the completions won't be visible. """ + from prompt_toolkit.application import Application from prompt_toolkit.buffer import Buffer from prompt_toolkit.filters import Condition diff --git a/examples/full-screen/simple-demos/margins.py b/examples/full-screen/simple-demos/margins.py index 467492d..b60ce0c 100755 --- a/examples/full-screen/simple-demos/margins.py +++ b/examples/full-screen/simple-demos/margins.py @@ -5,6 +5,7 @@ Example of Window margins. This is mainly used for displaying line numbers and scroll bars, but it could be used to display any other kind of information as well. """ + from prompt_toolkit.application import Application from prompt_toolkit.buffer import Buffer from prompt_toolkit.key_binding import KeyBindings diff --git a/examples/full-screen/simple-demos/vertical-align.py b/examples/full-screen/simple-demos/vertical-align.py index 1475d71..13b8504 100755 --- a/examples/full-screen/simple-demos/vertical-align.py +++ b/examples/full-screen/simple-demos/vertical-align.py @@ -2,6 +2,7 @@ """ Vertical align demo with VSplit. """ + from prompt_toolkit.application import Application from prompt_toolkit.formatted_text import HTML from prompt_toolkit.key_binding import KeyBindings diff --git a/examples/full-screen/simple-demos/vertical-split.py b/examples/full-screen/simple-demos/vertical-split.py index b48d106..2f4b66f 100755 --- a/examples/full-screen/simple-demos/vertical-split.py +++ b/examples/full-screen/simple-demos/vertical-split.py @@ -2,6 +2,7 @@ """ Vertical split example. """ + from prompt_toolkit.application import Application from prompt_toolkit.key_binding import KeyBindings from prompt_toolkit.layout.containers import VSplit, Window diff --git a/examples/full-screen/split-screen.py b/examples/full-screen/split-screen.py index af5403e..17e69c9 100755 --- a/examples/full-screen/split-screen.py +++ b/examples/full-screen/split-screen.py @@ -5,6 +5,7 @@ Simple example of a full screen application with a vertical split. This will show a window on the left for user input. When the user types, the reversed input is shown on the right. Pressing Ctrl-Q will quit the application. """ + from prompt_toolkit.application import Application from prompt_toolkit.buffer import Buffer from prompt_toolkit.key_binding import KeyBindings diff --git a/examples/full-screen/text-editor.py b/examples/full-screen/text-editor.py index 9c0a414..7fb6b0b 100755 --- a/examples/full-screen/text-editor.py +++ b/examples/full-screen/text-editor.py @@ -2,6 +2,7 @@ """ A simple example of a Notepad-like text editor. """ + import datetime from asyncio import Future, ensure_future @@ -53,10 +54,7 @@ def get_statusbar_text(): def get_statusbar_right_text(): - return " {}:{} ".format( - text_field.document.cursor_position_row + 1, - text_field.document.cursor_position_col + 1, - ) + return f" {text_field.document.cursor_position_row + 1}:{text_field.document.cursor_position_col + 1} " search_toolbar = SearchToolbar() diff --git a/examples/gevent-get-input.py b/examples/gevent-get-input.py index ecb89b4..0a0f016 100755 --- a/examples/gevent-get-input.py +++ b/examples/gevent-get-input.py @@ -3,6 +3,7 @@ For testing: test to make sure that everything still works when gevent monkey patches are applied. """ + from gevent.monkey import patch_all from prompt_toolkit.eventloop.defaults import create_event_loop @@ -21,4 +22,4 @@ if __name__ == "__main__": # Ask for input. session = PromptSession("Give me some input: ", loop=eventloop) answer = session.prompt() - print("You said: %s" % answer) + print(f"You said: {answer}") diff --git a/examples/print-text/ansi-colors.py b/examples/print-text/ansi-colors.py index 7bd3831..9e223a5 100755 --- a/examples/print-text/ansi-colors.py +++ b/examples/print-text/ansi-colors.py @@ -2,6 +2,7 @@ """ Demonstration of all the ANSI colors. """ + from prompt_toolkit import print_formatted_text from prompt_toolkit.formatted_text import HTML, FormattedText diff --git a/examples/print-text/ansi.py b/examples/print-text/ansi.py index 618775c..e7a20e4 100755 --- a/examples/print-text/ansi.py +++ b/examples/print-text/ansi.py @@ -5,6 +5,7 @@ Demonstration of how to print using ANSI escape sequences. The advantage here is that this is cross platform. The escape sequences will be parsed and turned into appropriate Win32 API calls on Windows. """ + from prompt_toolkit import print_formatted_text from prompt_toolkit.formatted_text import ANSI, HTML diff --git a/examples/print-text/html.py b/examples/print-text/html.py index 5276fe3..4edb74d 100755 --- a/examples/print-text/html.py +++ b/examples/print-text/html.py @@ -2,6 +2,7 @@ """ Demonstration of how to print using the HTML class. """ + from prompt_toolkit import HTML, print_formatted_text print = print_formatted_text diff --git a/examples/print-text/named-colors.py b/examples/print-text/named-colors.py index ea3f0ba..632b3e4 100755 --- a/examples/print-text/named-colors.py +++ b/examples/print-text/named-colors.py @@ -2,6 +2,7 @@ """ Demonstration of all the ANSI colors. """ + from prompt_toolkit import HTML, print_formatted_text from prompt_toolkit.formatted_text import FormattedText from prompt_toolkit.output import ColorDepth diff --git a/examples/print-text/print-formatted-text.py b/examples/print-text/print-formatted-text.py index 4b09ae2..e2efca9 100755 --- a/examples/print-text/print-formatted-text.py +++ b/examples/print-text/print-formatted-text.py @@ -2,6 +2,7 @@ """ Example of printing colored text to the output. """ + from prompt_toolkit import print_formatted_text from prompt_toolkit.formatted_text import ANSI, HTML, FormattedText from prompt_toolkit.styles import Style diff --git a/examples/print-text/print-frame.py b/examples/print-text/print-frame.py index fb703c5..8dec82b 100755 --- a/examples/print-text/print-frame.py +++ b/examples/print-text/print-frame.py @@ -3,6 +3,7 @@ Example usage of 'print_container', a tool to print any layout in a non-interactive way. """ + from prompt_toolkit.shortcuts import print_container from prompt_toolkit.widgets import Frame, TextArea diff --git a/examples/print-text/prompt-toolkit-logo-ansi-art.py b/examples/print-text/prompt-toolkit-logo-ansi-art.py index 617a506..e34fb03 100755 --- a/examples/print-text/prompt-toolkit-logo-ansi-art.py +++ b/examples/print-text/prompt-toolkit-logo-ansi-art.py @@ -4,6 +4,7 @@ This prints the prompt_toolkit logo at the terminal. The ANSI output was generated using "pngtoansi": https://github.com/crgimenes/pngtoansi (ESC still had to be replaced with \x1b """ + from prompt_toolkit import print_formatted_text from prompt_toolkit.formatted_text import ANSI diff --git a/examples/print-text/pygments-tokens.py b/examples/print-text/pygments-tokens.py index 3470e8e..a79788a 100755 --- a/examples/print-text/pygments-tokens.py +++ b/examples/print-text/pygments-tokens.py @@ -3,6 +3,7 @@ Printing a list of Pygments (Token, text) tuples, or an output of a Pygments lexer. """ + import pygments from pygments.lexers.python import PythonLexer from pygments.token import Token diff --git a/examples/print-text/true-color-demo.py b/examples/print-text/true-color-demo.py index a241006..4debd27 100755 --- a/examples/print-text/true-color-demo.py +++ b/examples/print-text/true-color-demo.py @@ -2,6 +2,7 @@ """ Demonstration of all the ANSI colors. """ + from prompt_toolkit import print_formatted_text from prompt_toolkit.formatted_text import HTML, FormattedText from prompt_toolkit.output import ColorDepth diff --git a/examples/progress-bar/a-lot-of-parallel-tasks.py b/examples/progress-bar/a-lot-of-parallel-tasks.py index 31110ac..a209827 100755 --- a/examples/progress-bar/a-lot-of-parallel-tasks.py +++ b/examples/progress-bar/a-lot-of-parallel-tasks.py @@ -2,6 +2,7 @@ """ More complex demonstration of what's possible with the progress bar. """ + import random import threading import time diff --git a/examples/progress-bar/colored-title-and-label.py b/examples/progress-bar/colored-title-and-label.py index 0b5e73a..bdea5b9 100755 --- a/examples/progress-bar/colored-title-and-label.py +++ b/examples/progress-bar/colored-title-and-label.py @@ -3,6 +3,7 @@ A progress bar that displays a formatted title above the progress bar and has a colored label. """ + import time from prompt_toolkit.formatted_text import HTML diff --git a/examples/progress-bar/custom-key-bindings.py b/examples/progress-bar/custom-key-bindings.py index f700811..f276a1e 100755 --- a/examples/progress-bar/custom-key-bindings.py +++ b/examples/progress-bar/custom-key-bindings.py @@ -3,6 +3,7 @@ A very simple progress bar which keep track of the progress as we consume an iterator. """ + import os import signal import time diff --git a/examples/progress-bar/many-parallel-tasks.py b/examples/progress-bar/many-parallel-tasks.py index dc34ef2..f3af4fe 100755 --- a/examples/progress-bar/many-parallel-tasks.py +++ b/examples/progress-bar/many-parallel-tasks.py @@ -2,6 +2,7 @@ """ More complex demonstration of what's possible with the progress bar. """ + import threading import time diff --git a/examples/progress-bar/nested-progress-bars.py b/examples/progress-bar/nested-progress-bars.py index 1a1e706..cfbf5f2 100755 --- a/examples/progress-bar/nested-progress-bars.py +++ b/examples/progress-bar/nested-progress-bars.py @@ -2,6 +2,7 @@ """ Example of nested progress bars. """ + import time from prompt_toolkit import HTML diff --git a/examples/progress-bar/scrolling-task-name.py b/examples/progress-bar/scrolling-task-name.py index bce155f..5531ace 100755 --- a/examples/progress-bar/scrolling-task-name.py +++ b/examples/progress-bar/scrolling-task-name.py @@ -3,6 +3,7 @@ A very simple progress bar where the name of the task scrolls, because it's too long. iterator. """ + import time from prompt_toolkit.shortcuts import ProgressBar diff --git a/examples/progress-bar/simple-progress-bar.py b/examples/progress-bar/simple-progress-bar.py index c8776e5..672e103 100755 --- a/examples/progress-bar/simple-progress-bar.py +++ b/examples/progress-bar/simple-progress-bar.py @@ -3,6 +3,7 @@ A very simple progress bar which keep track of the progress as we consume an iterator. """ + import time from prompt_toolkit.shortcuts import ProgressBar diff --git a/examples/progress-bar/styled-1.py b/examples/progress-bar/styled-1.py index d972e55..1f395cf 100755 --- a/examples/progress-bar/styled-1.py +++ b/examples/progress-bar/styled-1.py @@ -3,6 +3,7 @@ A very simple progress bar which keep track of the progress as we consume an iterator. """ + import time from prompt_toolkit.shortcuts import ProgressBar diff --git a/examples/progress-bar/styled-2.py b/examples/progress-bar/styled-2.py index 15c57d4..f5979b9 100755 --- a/examples/progress-bar/styled-2.py +++ b/examples/progress-bar/styled-2.py @@ -3,6 +3,7 @@ A very simple progress bar which keep track of the progress as we consume an iterator. """ + import time from prompt_toolkit.formatted_text import HTML diff --git a/examples/progress-bar/styled-apt-get-install.py b/examples/progress-bar/styled-apt-get-install.py index bafe70b..50b6935 100755 --- a/examples/progress-bar/styled-apt-get-install.py +++ b/examples/progress-bar/styled-apt-get-install.py @@ -2,6 +2,7 @@ """ Styled just like an apt-get installation. """ + import time from prompt_toolkit.shortcuts import ProgressBar diff --git a/examples/progress-bar/styled-rainbow.py b/examples/progress-bar/styled-rainbow.py index b46e949..e14e2f0 100755 --- a/examples/progress-bar/styled-rainbow.py +++ b/examples/progress-bar/styled-rainbow.py @@ -2,6 +2,7 @@ """ A simple progress bar, visualized with rainbow colors (for fun). """ + import time from prompt_toolkit.output import ColorDepth diff --git a/examples/progress-bar/styled-tqdm-1.py b/examples/progress-bar/styled-tqdm-1.py index 9484ac0..a24f887 100755 --- a/examples/progress-bar/styled-tqdm-1.py +++ b/examples/progress-bar/styled-tqdm-1.py @@ -4,6 +4,7 @@ Styled similar to tqdm, another progress bar implementation in Python. See: https://github.com/noamraph/tqdm """ + import time from prompt_toolkit.shortcuts import ProgressBar diff --git a/examples/progress-bar/styled-tqdm-2.py b/examples/progress-bar/styled-tqdm-2.py index 0e66e90..bcdac67 100755 --- a/examples/progress-bar/styled-tqdm-2.py +++ b/examples/progress-bar/styled-tqdm-2.py @@ -4,6 +4,7 @@ Styled similar to tqdm, another progress bar implementation in Python. See: https://github.com/noamraph/tqdm """ + import time from prompt_toolkit.shortcuts import ProgressBar diff --git a/examples/progress-bar/two-tasks.py b/examples/progress-bar/two-tasks.py index c78604e..36bdf6a 100755 --- a/examples/progress-bar/two-tasks.py +++ b/examples/progress-bar/two-tasks.py @@ -2,6 +2,7 @@ """ Two progress bars that run in parallel. """ + import threading import time diff --git a/examples/progress-bar/unknown-length.py b/examples/progress-bar/unknown-length.py index e39ac39..5d2d06f 100755 --- a/examples/progress-bar/unknown-length.py +++ b/examples/progress-bar/unknown-length.py @@ -3,6 +3,7 @@ A very simple progress bar which keep track of the progress as we consume an iterator. """ + import time from prompt_toolkit.shortcuts import ProgressBar diff --git a/examples/prompts/accept-default.py b/examples/prompts/accept-default.py index 311ef46..0ef45d9 100644 --- a/examples/prompts/accept-default.py +++ b/examples/prompts/accept-default.py @@ -6,6 +6,7 @@ user typed without allowing him/her to edit it. This should display the prompt with all the formatting like usual, but not allow any editing. """ + from prompt_toolkit import HTML, prompt if __name__ == "__main__": @@ -13,4 +14,4 @@ if __name__ == "__main__": HTML("<b>Type <u>some input</u>: </b>"), accept_default=True, default="test" ) - print("You said: %s" % answer) + print(f"You said: {answer}") diff --git a/examples/prompts/auto-completion/autocomplete-with-control-space.py b/examples/prompts/auto-completion/autocomplete-with-control-space.py index 61160a3..238f908 100755 --- a/examples/prompts/auto-completion/autocomplete-with-control-space.py +++ b/examples/prompts/auto-completion/autocomplete-with-control-space.py @@ -2,6 +2,7 @@ """ Example of using the control-space key binding for auto completion. """ + from prompt_toolkit import prompt from prompt_toolkit.completion import WordCompleter from prompt_toolkit.key_binding import KeyBindings @@ -68,7 +69,7 @@ def main(): complete_while_typing=False, key_bindings=kb, ) - print("You said: %s" % text) + print(f"You said: {text}") if __name__ == "__main__": diff --git a/examples/prompts/auto-completion/autocompletion-like-readline.py b/examples/prompts/auto-completion/autocompletion-like-readline.py index 613d3e7..eac0edd 100755 --- a/examples/prompts/auto-completion/autocompletion-like-readline.py +++ b/examples/prompts/auto-completion/autocompletion-like-readline.py @@ -3,6 +3,7 @@ Autocompletion example that displays the autocompletions like readline does by binding a custom handler to the Tab key. """ + from prompt_toolkit.completion import WordCompleter from prompt_toolkit.shortcuts import CompleteStyle, prompt @@ -51,7 +52,7 @@ def main(): completer=animal_completer, complete_style=CompleteStyle.READLINE_LIKE, ) - print("You said: %s" % text) + print(f"You said: {text}") if __name__ == "__main__": diff --git a/examples/prompts/auto-completion/autocompletion.py b/examples/prompts/auto-completion/autocompletion.py index fc9dda0..ea5727f 100755 --- a/examples/prompts/auto-completion/autocompletion.py +++ b/examples/prompts/auto-completion/autocompletion.py @@ -7,6 +7,7 @@ Press [Tab] to complete the current word. and shows all the completions. (In the menu) - Any following tab press cycles through all the possible completions. """ + from prompt_toolkit import prompt from prompt_toolkit.completion import WordCompleter @@ -53,7 +54,7 @@ def main(): text = prompt( "Give some animals: ", completer=animal_completer, complete_while_typing=False ) - print("You said: %s" % text) + print(f"You said: {text}") if __name__ == "__main__": diff --git a/examples/prompts/auto-completion/colored-completions-with-formatted-text.py b/examples/prompts/auto-completion/colored-completions-with-formatted-text.py index 8a89c7a..eeff259 100755 --- a/examples/prompts/auto-completion/colored-completions-with-formatted-text.py +++ b/examples/prompts/auto-completion/colored-completions-with-formatted-text.py @@ -4,6 +4,7 @@ Demonstration of a custom completer class and the possibility of styling completions independently by passing formatted text objects to the "display" and "display_meta" arguments of "Completion". """ + from prompt_toolkit.completion import Completer, Completion from prompt_toolkit.formatted_text import HTML from prompt_toolkit.shortcuts import CompleteStyle, prompt diff --git a/examples/prompts/auto-completion/colored-completions.py b/examples/prompts/auto-completion/colored-completions.py index 9c5cba3..1295e7d 100755 --- a/examples/prompts/auto-completion/colored-completions.py +++ b/examples/prompts/auto-completion/colored-completions.py @@ -3,6 +3,7 @@ Demonstration of a custom completer class and the possibility of styling completions independently. """ + from prompt_toolkit.completion import Completer, Completion from prompt_toolkit.output.color_depth import ColorDepth from prompt_toolkit.shortcuts import CompleteStyle, prompt diff --git a/examples/prompts/auto-completion/combine-multiple-completers.py b/examples/prompts/auto-completion/combine-multiple-completers.py index 511988b..7c21078 100755 --- a/examples/prompts/auto-completion/combine-multiple-completers.py +++ b/examples/prompts/auto-completion/combine-multiple-completers.py @@ -2,6 +2,7 @@ """ Example of multiple individual completers that are combined into one. """ + from prompt_toolkit import prompt from prompt_toolkit.completion import WordCompleter, merge_completers @@ -69,7 +70,7 @@ def main(): text = prompt( "Give some animals: ", completer=completer, complete_while_typing=False ) - print("You said: %s" % text) + print(f"You said: {text}") if __name__ == "__main__": diff --git a/examples/prompts/auto-completion/fuzzy-custom-completer.py b/examples/prompts/auto-completion/fuzzy-custom-completer.py index fd9a7d7..ca763c7 100755 --- a/examples/prompts/auto-completion/fuzzy-custom-completer.py +++ b/examples/prompts/auto-completion/fuzzy-custom-completer.py @@ -3,6 +3,7 @@ Demonstration of a custom completer wrapped in a `FuzzyCompleter` for fuzzy matching. """ + from prompt_toolkit.completion import Completer, Completion, FuzzyCompleter from prompt_toolkit.shortcuts import CompleteStyle, prompt diff --git a/examples/prompts/auto-completion/fuzzy-word-completer.py b/examples/prompts/auto-completion/fuzzy-word-completer.py index 329c0c1..0ea059e 100755 --- a/examples/prompts/auto-completion/fuzzy-word-completer.py +++ b/examples/prompts/auto-completion/fuzzy-word-completer.py @@ -7,6 +7,7 @@ Press [Tab] to complete the current word. and shows all the completions. (In the menu) - Any following tab press cycles through all the possible completions. """ + from prompt_toolkit.completion import FuzzyWordCompleter from prompt_toolkit.shortcuts import prompt @@ -52,7 +53,7 @@ def main(): text = prompt( "Give some animals: ", completer=animal_completer, complete_while_typing=True ) - print("You said: %s" % text) + print(f"You said: {text}") if __name__ == "__main__": diff --git a/examples/prompts/auto-completion/multi-column-autocompletion-with-meta.py b/examples/prompts/auto-completion/multi-column-autocompletion-with-meta.py index 5ba3ab5..c748837 100755 --- a/examples/prompts/auto-completion/multi-column-autocompletion-with-meta.py +++ b/examples/prompts/auto-completion/multi-column-autocompletion-with-meta.py @@ -2,6 +2,7 @@ """ Autocompletion example that shows meta-information alongside the completions. """ + from prompt_toolkit.completion import WordCompleter from prompt_toolkit.shortcuts import CompleteStyle, prompt @@ -43,7 +44,7 @@ def main(): completer=animal_completer, complete_style=CompleteStyle.MULTI_COLUMN, ) - print("You said: %s" % text) + print(f"You said: {text}") if __name__ == "__main__": diff --git a/examples/prompts/auto-completion/multi-column-autocompletion.py b/examples/prompts/auto-completion/multi-column-autocompletion.py index 7fcfc52..9b24622 100755 --- a/examples/prompts/auto-completion/multi-column-autocompletion.py +++ b/examples/prompts/auto-completion/multi-column-autocompletion.py @@ -2,6 +2,7 @@ """ Similar to the autocompletion example. But display all the completions in multiple columns. """ + from prompt_toolkit.completion import WordCompleter from prompt_toolkit.shortcuts import CompleteStyle, prompt @@ -50,7 +51,7 @@ def main(): completer=animal_completer, complete_style=CompleteStyle.MULTI_COLUMN, ) - print("You said: %s" % text) + print(f"You said: {text}") if __name__ == "__main__": diff --git a/examples/prompts/auto-completion/nested-autocompletion.py b/examples/prompts/auto-completion/nested-autocompletion.py index cd85b8c..e56e82e 100755 --- a/examples/prompts/auto-completion/nested-autocompletion.py +++ b/examples/prompts/auto-completion/nested-autocompletion.py @@ -2,6 +2,7 @@ """ Example of nested autocompletion. """ + from prompt_toolkit import prompt from prompt_toolkit.completion import NestedCompleter @@ -15,7 +16,7 @@ completer = NestedCompleter.from_nested_dict( def main(): text = prompt("Type a command: ", completer=completer) - print("You said: %s" % text) + print(f"You said: {text}") if __name__ == "__main__": diff --git a/examples/prompts/auto-completion/slow-completions.py b/examples/prompts/auto-completion/slow-completions.py index cce9d59..0c9cc11 100755 --- a/examples/prompts/auto-completion/slow-completions.py +++ b/examples/prompts/auto-completion/slow-completions.py @@ -12,6 +12,7 @@ An example of how to deal with slow auto completion code. - We also set a `loading` boolean in the completer function to keep track of when the completer is running, and display this in the toolbar. """ + import time from prompt_toolkit.completion import Completer, Completion @@ -96,7 +97,7 @@ def main(): bottom_toolbar=bottom_toolbar, complete_style=CompleteStyle.MULTI_COLUMN, ) - print("You said: %s" % text) + print(f"You said: {text}") if __name__ == "__main__": diff --git a/examples/prompts/auto-suggestion.py b/examples/prompts/auto-suggestion.py index 6660777..56a9dc6 100755 --- a/examples/prompts/auto-suggestion.py +++ b/examples/prompts/auto-suggestion.py @@ -7,6 +7,7 @@ entry of the history starts with the given input, then it will show the remaining part as a suggestion. Pressing the right arrow will insert this suggestion. """ + from prompt_toolkit import PromptSession from prompt_toolkit.auto_suggest import AutoSuggestFromHistory from prompt_toolkit.history import InMemoryHistory @@ -41,7 +42,7 @@ def main(): else: break - print("You said: %s" % text) + print(f"You said: {text}") if __name__ == "__main__": diff --git a/examples/prompts/autocorrection.py b/examples/prompts/autocorrection.py index 6378132..2699554 100755 --- a/examples/prompts/autocorrection.py +++ b/examples/prompts/autocorrection.py @@ -4,6 +4,7 @@ Example of implementing auto correction while typing. The word "impotr" will be corrected when the user types a space afterwards. """ + from prompt_toolkit import prompt from prompt_toolkit.key_binding import KeyBindings @@ -37,7 +38,7 @@ def main(): # Read input. text = prompt("Say something: ", key_bindings=bindings) - print("You said: %s" % text) + print(f"You said: {text}") if __name__ == "__main__": diff --git a/examples/prompts/bottom-toolbar.py b/examples/prompts/bottom-toolbar.py index 4980e5b..937a961 100755 --- a/examples/prompts/bottom-toolbar.py +++ b/examples/prompts/bottom-toolbar.py @@ -10,6 +10,7 @@ The bottom toolbar will always receive the style 'bottom-toolbar', and the text inside will get 'bottom-toolbar.text'. These can be used to change the default style. """ + import time from prompt_toolkit import prompt @@ -20,14 +21,14 @@ from prompt_toolkit.styles import Style def main(): # Example 1: fixed text. text = prompt("Say something: ", bottom_toolbar="This is a toolbar") - print("You said: %s" % text) + print(f"You said: {text}") # Example 2: fixed text from a callable: def get_toolbar(): - return "Bottom toolbar: time=%r" % time.time() + return f"Bottom toolbar: time={time.time()!r}" text = prompt("Say something: ", bottom_toolbar=get_toolbar, refresh_interval=0.5) - print("You said: %s" % text) + print(f"You said: {text}") # Example 3: Using HTML: text = prompt( @@ -36,7 +37,7 @@ def main(): '(html) <b>This</b> <u>is</u> a <style bg="ansired">toolbar</style>' ), ) - print("You said: %s" % text) + print(f"You said: {text}") # Example 4: Using ANSI: text = prompt( @@ -45,7 +46,7 @@ def main(): "(ansi): \x1b[1mThis\x1b[0m \x1b[4mis\x1b[0m a \x1b[91mtoolbar" ), ) - print("You said: %s" % text) + print(f"You said: {text}") # Example 5: styling differently. style = Style.from_dict( @@ -56,7 +57,7 @@ def main(): ) text = prompt("Say something: ", bottom_toolbar="This is a toolbar", style=style) - print("You said: %s" % text) + print(f"You said: {text}") # Example 6: Using a list of tokens. def get_bottom_toolbar(): @@ -69,11 +70,11 @@ def main(): ] text = prompt("Say something: ", bottom_toolbar=get_bottom_toolbar) - print("You said: %s" % text) + print(f"You said: {text}") # Example 7: multiline fixed text. text = prompt("Say something: ", bottom_toolbar="This is\na multiline toolbar") - print("You said: %s" % text) + print(f"You said: {text}") if __name__ == "__main__": diff --git a/examples/prompts/clock-input.py b/examples/prompts/clock-input.py index e43abd8..80bfa51 100755 --- a/examples/prompts/clock-input.py +++ b/examples/prompts/clock-input.py @@ -2,6 +2,7 @@ """ Example of a 'dynamic' prompt. On that shows the current time in the prompt. """ + import datetime from prompt_toolkit.shortcuts import prompt @@ -18,7 +19,7 @@ def get_prompt(): def main(): result = prompt(get_prompt, refresh_interval=0.5) - print("You said: %s" % result) + print(f"You said: {result}") if __name__ == "__main__": diff --git a/examples/prompts/colored-prompt.py b/examples/prompts/colored-prompt.py index 1e63e29..428ff1d 100755 --- a/examples/prompts/colored-prompt.py +++ b/examples/prompts/colored-prompt.py @@ -2,6 +2,7 @@ """ Example of a colored prompt. """ + from prompt_toolkit import prompt from prompt_toolkit.formatted_text import ANSI, HTML from prompt_toolkit.styles import Style @@ -40,7 +41,7 @@ def example_1(): ] answer = prompt(prompt_fragments, style=style) - print("You said: %s" % answer) + print(f"You said: {answer}") def example_2(): @@ -57,7 +58,7 @@ def example_2(): ), style=style, ) - print("You said: %s" % answer) + print(f"You said: {answer}") def example_3(): @@ -72,7 +73,7 @@ def example_3(): "# " ) ) - print("You said: %s" % answer) + print(f"You said: {answer}") if __name__ == "__main__": diff --git a/examples/prompts/confirmation-prompt.py b/examples/prompts/confirmation-prompt.py index bd52b9e..18687fe 100755 --- a/examples/prompts/confirmation-prompt.py +++ b/examples/prompts/confirmation-prompt.py @@ -2,8 +2,9 @@ """ Example of a confirmation prompt. """ + from prompt_toolkit.shortcuts import confirm if __name__ == "__main__": answer = confirm("Should we do that?") - print("You said: %s" % answer) + print(f"You said: {answer}") diff --git a/examples/prompts/cursor-shapes.py b/examples/prompts/cursor-shapes.py index e668243..62b2d95 100755 --- a/examples/prompts/cursor-shapes.py +++ b/examples/prompts/cursor-shapes.py @@ -2,6 +2,7 @@ """ Example of cursor shape configurations. """ + from prompt_toolkit import prompt from prompt_toolkit.cursor_shapes import CursorShape, ModalCursorShapeConfig diff --git a/examples/prompts/custom-key-binding.py b/examples/prompts/custom-key-binding.py index 32d889e..b918ab3 100755 --- a/examples/prompts/custom-key-binding.py +++ b/examples/prompts/custom-key-binding.py @@ -2,6 +2,7 @@ """ Example of adding a custom key binding to a prompt. """ + import asyncio from prompt_toolkit import prompt @@ -70,7 +71,7 @@ def main(): # Read input. print('Press F4 to insert "hello world", type "xy" to insert "z":') text = prompt("> ", key_bindings=bindings) - print("You said: %s" % text) + print(f"You said: {text}") if __name__ == "__main__": diff --git a/examples/prompts/custom-lexer.py b/examples/prompts/custom-lexer.py index c4c9fbe..75ad2d3 100755 --- a/examples/prompts/custom-lexer.py +++ b/examples/prompts/custom-lexer.py @@ -2,6 +2,7 @@ """ An example of a custom lexer that prints the input text in random colors. """ + from prompt_toolkit.lexers import Lexer from prompt_toolkit.shortcuts import prompt from prompt_toolkit.styles.named_colors import NAMED_COLORS @@ -22,7 +23,7 @@ class RainbowLexer(Lexer): def main(): answer = prompt("Give me some input: ", lexer=RainbowLexer()) - print("You said: %s" % answer) + print(f"You said: {answer}") if __name__ == "__main__": diff --git a/examples/prompts/custom-vi-operator-and-text-object.py b/examples/prompts/custom-vi-operator-and-text-object.py index 7478afc..74bac23 100755 --- a/examples/prompts/custom-vi-operator-and-text-object.py +++ b/examples/prompts/custom-vi-operator-and-text-object.py @@ -3,6 +3,7 @@ Example of adding a custom Vi operator and text object. (Note that this API is not guaranteed to remain stable.) """ + from prompt_toolkit import prompt from prompt_toolkit.enums import EditingMode from prompt_toolkit.key_binding import KeyBindings @@ -63,7 +64,7 @@ def main(): text = prompt( "> ", default="hello world", key_bindings=bindings, editing_mode=EditingMode.VI ) - print("You said: %s" % text) + print(f"You said: {text}") if __name__ == "__main__": diff --git a/examples/prompts/enforce-tty-input-output.py b/examples/prompts/enforce-tty-input-output.py index 93b43ee..08bb762 100755 --- a/examples/prompts/enforce-tty-input-output.py +++ b/examples/prompts/enforce-tty-input-output.py @@ -6,6 +6,7 @@ output, even if sys.stdin/stdout are connected to pipes. For testing, run as: cat /dev/null | python ./enforce-tty-input-output.py > /dev/null """ + from prompt_toolkit.application import create_app_session_from_tty from prompt_toolkit.shortcuts import prompt diff --git a/examples/prompts/fancy-zsh-prompt.py b/examples/prompts/fancy-zsh-prompt.py index 4761c08..cc31c1f 100755 --- a/examples/prompts/fancy-zsh-prompt.py +++ b/examples/prompts/fancy-zsh-prompt.py @@ -9,6 +9,7 @@ See: - https://github.com/xonsh/xonsh/issues/3356 - https://github.com/prompt-toolkit/python-prompt-toolkit/issues/1111 """ + import datetime from prompt_toolkit import prompt @@ -72,7 +73,7 @@ def get_prompt() -> HTML: def main() -> None: while True: answer = prompt(get_prompt, style=style, refresh_interval=1) - print("You said: %s" % answer) + print(f"You said: {answer}") if __name__ == "__main__": diff --git a/examples/prompts/finalterm-shell-integration.py b/examples/prompts/finalterm-shell-integration.py index 30c7a7f..254d226 100755 --- a/examples/prompts/finalterm-shell-integration.py +++ b/examples/prompts/finalterm-shell-integration.py @@ -3,6 +3,7 @@ Mark the start and end of the prompt with Final term (iterm2) escape sequences. See: https://iterm2.com/finalterm.html """ + import sys from prompt_toolkit import prompt @@ -39,5 +40,5 @@ if __name__ == "__main__": # Output. sys.stdout.write(BEFORE_OUTPUT) - print("You said: %s" % answer) + print(f"You said: {answer}") sys.stdout.write(AFTER_OUTPUT.format(command_status=0)) diff --git a/examples/prompts/get-input-vi-mode.py b/examples/prompts/get-input-vi-mode.py index 566ffd5..4073bcd 100755 --- a/examples/prompts/get-input-vi-mode.py +++ b/examples/prompts/get-input-vi-mode.py @@ -4,4 +4,4 @@ from prompt_toolkit import prompt if __name__ == "__main__": print("You have Vi keybindings here. Press [Esc] to go to navigation mode.") answer = prompt("Give me some input: ", multiline=False, vi_mode=True) - print("You said: %s" % answer) + print(f"You said: {answer}") diff --git a/examples/prompts/get-input-with-default.py b/examples/prompts/get-input-with-default.py index 67446d5..974888f 100755 --- a/examples/prompts/get-input-with-default.py +++ b/examples/prompts/get-input-with-default.py @@ -3,10 +3,11 @@ Example of a call to `prompt` with a default value. The input is pre-filled, but the user can still edit the default. """ + import getpass from prompt_toolkit import prompt if __name__ == "__main__": - answer = prompt("What is your name: ", default="%s" % getpass.getuser()) - print("You said: %s" % answer) + answer = prompt("What is your name: ", default=f"{getpass.getuser()}") + print(f"You said: {answer}") diff --git a/examples/prompts/get-input.py b/examples/prompts/get-input.py index 5529bbb..6db7e2c 100755 --- a/examples/prompts/get-input.py +++ b/examples/prompts/get-input.py @@ -2,8 +2,9 @@ """ The most simple prompt example. """ + from prompt_toolkit import prompt if __name__ == "__main__": answer = prompt("Give me some input: ") - print("You said: %s" % answer) + print(f"You said: {answer}") diff --git a/examples/prompts/get-multiline-input.py b/examples/prompts/get-multiline-input.py index eda35be..cda6fa5 100755 --- a/examples/prompts/get-multiline-input.py +++ b/examples/prompts/get-multiline-input.py @@ -26,4 +26,4 @@ if __name__ == "__main__": answer = prompt( "Multiline input: ", multiline=True, prompt_continuation=prompt_continuation ) - print("You said: %s" % answer) + print(f"You said: {answer}") diff --git a/examples/prompts/get-password-with-toggle-display-shortcut.py b/examples/prompts/get-password-with-toggle-display-shortcut.py index b89cb41..a233e5e 100755 --- a/examples/prompts/get-password-with-toggle-display-shortcut.py +++ b/examples/prompts/get-password-with-toggle-display-shortcut.py @@ -3,6 +3,7 @@ get_password function that displays asterisks instead of the actual characters. With the addition of a ControlT shortcut to hide/show the input. """ + from prompt_toolkit import prompt from prompt_toolkit.filters import Condition from prompt_toolkit.key_binding import KeyBindings @@ -21,7 +22,7 @@ def main(): password = prompt( "Password: ", is_password=Condition(lambda: hidden[0]), key_bindings=bindings ) - print("You said: %s" % password) + print(f"You said: {password}") if __name__ == "__main__": diff --git a/examples/prompts/get-password.py b/examples/prompts/get-password.py index 1c9517c..a9c0c27 100755 --- a/examples/prompts/get-password.py +++ b/examples/prompts/get-password.py @@ -3,4 +3,4 @@ from prompt_toolkit import prompt if __name__ == "__main__": password = prompt("Password: ", is_password=True) - print("You said: %s" % password) + print(f"You said: {password}") diff --git a/examples/prompts/history/persistent-history.py b/examples/prompts/history/persistent-history.py index 2bdb758..6299bdc 100755 --- a/examples/prompts/history/persistent-history.py +++ b/examples/prompts/history/persistent-history.py @@ -4,6 +4,7 @@ Simple example of a CLI that keeps a persistent history of all the entered strings in a file. When you run this script for a second time, pressing arrow-up will go back in history. """ + from prompt_toolkit import PromptSession from prompt_toolkit.history import FileHistory @@ -18,7 +19,7 @@ def main(): while True: text = session.prompt("Say something: ") - print("You said: %s" % text) + print(f"You said: {text}") if __name__ == "__main__": diff --git a/examples/prompts/history/slow-history.py b/examples/prompts/history/slow-history.py index 5b6a7a2..10e4592 100755 --- a/examples/prompts/history/slow-history.py +++ b/examples/prompts/history/slow-history.py @@ -5,6 +5,7 @@ Simple example of a custom, very slow history, that is loaded asynchronously. By wrapping it in `ThreadedHistory`, the history will load in the background without blocking any user interaction. """ + import time from prompt_toolkit import PromptSession @@ -41,7 +42,7 @@ def main(): while True: text = session.prompt("Say something: ") - print("You said: %s" % text) + print(f"You said: {text}") if __name__ == "__main__": diff --git a/examples/prompts/html-input.py b/examples/prompts/html-input.py index 4c51737..e8ecc00 100755 --- a/examples/prompts/html-input.py +++ b/examples/prompts/html-input.py @@ -3,6 +3,7 @@ Simple example of a syntax-highlighted HTML input line. (This requires Pygments to be installed.) """ + from pygments.lexers.html import HtmlLexer from prompt_toolkit import prompt @@ -11,7 +12,7 @@ from prompt_toolkit.lexers import PygmentsLexer def main(): text = prompt("Enter HTML: ", lexer=PygmentsLexer(HtmlLexer)) - print("You said: %s" % text) + print(f"You said: {text}") if __name__ == "__main__": diff --git a/examples/prompts/input-validation.py b/examples/prompts/input-validation.py index d8bd3ee..2151671 100755 --- a/examples/prompts/input-validation.py +++ b/examples/prompts/input-validation.py @@ -2,6 +2,7 @@ """ Simple example of input validation. """ + from prompt_toolkit import prompt from prompt_toolkit.validation import Validator @@ -22,13 +23,13 @@ def main(): text = prompt( "Enter e-mail address: ", validator=validator, validate_while_typing=False ) - print("You said: %s" % text) + print(f"You said: {text}") # While typing text = prompt( "Enter e-mail address: ", validator=validator, validate_while_typing=True ) - print("You said: %s" % text) + print(f"You said: {text}") if __name__ == "__main__": diff --git a/examples/prompts/inputhook.py b/examples/prompts/inputhook.py index 7cbfe18..a776246 100755 --- a/examples/prompts/inputhook.py +++ b/examples/prompts/inputhook.py @@ -11,6 +11,7 @@ There are two ways to know when input is ready. One way is to poll `InputHookContext.input_is_ready()`. Another way is to check for `InputHookContext.fileno()` to be ready. In this example we do the latter. """ + import gobject import gtk from pygments.lexers.python import PythonLexer @@ -76,7 +77,7 @@ def main(): "Python >>> ", inputhook=inputhook, lexer=PygmentsLexer(PythonLexer) ) result = session.prompt() - print("You said: %s" % result) + print(f"You said: {result}") if __name__ == "__main__": diff --git a/examples/prompts/mouse-support.py b/examples/prompts/mouse-support.py index 1e4ee76..b1b4bb7 100755 --- a/examples/prompts/mouse-support.py +++ b/examples/prompts/mouse-support.py @@ -7,4 +7,4 @@ if __name__ == "__main__": ) print("You can click with the mouse in order to select text.") answer = prompt("Multiline input: ", multiline=True, mouse_support=True) - print("You said: %s" % answer) + print(f"You said: {answer}") diff --git a/examples/prompts/multiline-prompt.py b/examples/prompts/multiline-prompt.py index d6a7698..f2e70ef 100755 --- a/examples/prompts/multiline-prompt.py +++ b/examples/prompts/multiline-prompt.py @@ -2,10 +2,11 @@ """ Demonstration of how the input can be indented. """ + from prompt_toolkit import prompt if __name__ == "__main__": answer = prompt( "Give me some input: (ESCAPE followed by ENTER to accept)\n > ", multiline=True ) - print("You said: %s" % answer) + print(f"You said: {answer}") diff --git a/examples/prompts/no-wrapping.py b/examples/prompts/no-wrapping.py index 371486e..170e7d5 100755 --- a/examples/prompts/no-wrapping.py +++ b/examples/prompts/no-wrapping.py @@ -3,4 +3,4 @@ from prompt_toolkit import prompt if __name__ == "__main__": answer = prompt("Give me some input: ", wrap_lines=False, multiline=True) - print("You said: %s" % answer) + print(f"You said: {answer}") diff --git a/examples/prompts/operate-and-get-next.py b/examples/prompts/operate-and-get-next.py index 6ea4d79..0bc70ba 100755 --- a/examples/prompts/operate-and-get-next.py +++ b/examples/prompts/operate-and-get-next.py @@ -5,6 +5,7 @@ Demo of "operate-and-get-next". (Actually, this creates one prompt application, and keeps running the same app over and over again. -- For now, this is the only way to get this working.) """ + from prompt_toolkit.shortcuts import PromptSession diff --git a/examples/prompts/patch-stdout.py b/examples/prompts/patch-stdout.py index 1c83524..3a89f36 100755 --- a/examples/prompts/patch-stdout.py +++ b/examples/prompts/patch-stdout.py @@ -5,6 +5,7 @@ An example that demonstrates how `patch_stdout` works. This makes sure that output from other threads doesn't disturb the rendering of the prompt, but instead is printed nicely above the prompt. """ + import threading import time @@ -31,7 +32,7 @@ def main(): # should not disturb anything. with patch_stdout(): result = prompt("Say something: ") - print("You said: %s" % result) + print(f"You said: {result}") # Stop thread. running = False diff --git a/examples/prompts/placeholder-text.py b/examples/prompts/placeholder-text.py index 35e1c6c..65d77a1 100755 --- a/examples/prompts/placeholder-text.py +++ b/examples/prompts/placeholder-text.py @@ -2,6 +2,7 @@ """ Example of a placeholder that's displayed as long as no input is given. """ + from prompt_toolkit import prompt from prompt_toolkit.formatted_text import HTML @@ -10,4 +11,4 @@ if __name__ == "__main__": "Give me some input: ", placeholder=HTML('<style color="#888888">(please type something)</style>'), ) - print("You said: %s" % answer) + print(f"You said: {answer}") diff --git a/examples/prompts/regular-language.py b/examples/prompts/regular-language.py index cbe7256..12cf257 100755 --- a/examples/prompts/regular-language.py +++ b/examples/prompts/regular-language.py @@ -12,6 +12,7 @@ Type for instance:: This example shows how you can define the grammar of a regular language and how to use variables in this grammar with completers and tokens attached. """ + import math from prompt_toolkit import prompt @@ -99,7 +100,7 @@ if __name__ == "__main__": }[vars.get("operator1") or vars.get("operator2")] # Execute and print the result. - print("Result: %s\n" % (operator(var1, var2))) + print(f"Result: {operator(var1, var2)}\n") elif vars.get("operator2"): print("Operator 2") diff --git a/examples/prompts/rprompt.py b/examples/prompts/rprompt.py index f7656b7..fd4fe1b 100755 --- a/examples/prompts/rprompt.py +++ b/examples/prompts/rprompt.py @@ -6,6 +6,7 @@ is long enough to cover the right side of the terminal. This is similar to RPROMPT is Zsh. """ + from prompt_toolkit import prompt from prompt_toolkit.formatted_text import ANSI, HTML from prompt_toolkit.styles import Style @@ -30,23 +31,23 @@ def get_rprompt_text(): def main(): # Option 1: pass a string to 'rprompt': answer = prompt("> ", rprompt=" <rprompt> ", style=example_style) - print("You said: %s" % answer) + print(f"You said: {answer}") # Option 2: pass HTML: answer = prompt("> ", rprompt=HTML(" <u><rprompt></u> "), style=example_style) - print("You said: %s" % answer) + print(f"You said: {answer}") # Option 3: pass ANSI: answer = prompt( "> ", rprompt=ANSI(" \x1b[4m<rprompt>\x1b[0m "), style=example_style ) - print("You said: %s" % answer) + print(f"You said: {answer}") # Option 4: Pass a callable. (This callable can either return plain text, # an HTML object, an ANSI object or a list of (style, text) # tuples. answer = prompt("> ", rprompt=get_rprompt_text, style=example_style) - print("You said: %s" % answer) + print(f"You said: {answer}") if __name__ == "__main__": diff --git a/examples/prompts/swap-light-and-dark-colors.py b/examples/prompts/swap-light-and-dark-colors.py index e602449..4237d73 100755 --- a/examples/prompts/swap-light-and-dark-colors.py +++ b/examples/prompts/swap-light-and-dark-colors.py @@ -7,6 +7,7 @@ Notice that this doesn't swap foreground and background like "reverse" does. It turns light green into dark green and the other way around. Foreground and background are independent of each other. """ + from pygments.lexers.html import HtmlLexer from prompt_toolkit import prompt @@ -71,7 +72,7 @@ def main(): lexer=PygmentsLexer(HtmlLexer), swap_light_and_dark_colors=Condition(lambda: swapped[0]), ) - print("You said: %s" % text) + print(f"You said: {text}") if __name__ == "__main__": diff --git a/examples/prompts/switch-between-vi-emacs.py b/examples/prompts/switch-between-vi-emacs.py index 249c7ef..a69b140 100755 --- a/examples/prompts/switch-between-vi-emacs.py +++ b/examples/prompts/switch-between-vi-emacs.py @@ -3,6 +3,7 @@ Example that displays how to switch between Emacs and Vi input mode. """ + from prompt_toolkit import prompt from prompt_toolkit.application.current import get_app from prompt_toolkit.enums import EditingMode diff --git a/examples/prompts/system-clipboard-integration.py b/examples/prompts/system-clipboard-integration.py index f605921..0b9136b 100755 --- a/examples/prompts/system-clipboard-integration.py +++ b/examples/prompts/system-clipboard-integration.py @@ -3,6 +3,7 @@ Demonstration of a custom clipboard class. This requires the 'pyperclip' library to be installed. """ + from prompt_toolkit import prompt from prompt_toolkit.clipboard.pyperclip import PyperclipClipboard @@ -14,4 +15,4 @@ if __name__ == "__main__": print("") answer = prompt("Give me some input: ", clipboard=PyperclipClipboard()) - print("You said: %s" % answer) + print(f"You said: {answer}") diff --git a/examples/prompts/system-prompt.py b/examples/prompts/system-prompt.py index 47aa2a5..e9ff460 100755 --- a/examples/prompts/system-prompt.py +++ b/examples/prompts/system-prompt.py @@ -7,14 +7,14 @@ if __name__ == "__main__": "(1/3) If you press meta-! or esc-! at the following prompt, you can enter system commands." ) answer = prompt("Give me some input: ", enable_system_prompt=True) - print("You said: %s" % answer) + print(f"You said: {answer}") # Enable suspend. print("(2/3) If you press Control-Z, the application will suspend.") answer = prompt("Give me some input: ", enable_suspend=True) - print("You said: %s" % answer) + print(f"You said: {answer}") # Enable open_in_editor print("(3/3) If you press Control-X Control-E, the prompt will open in $EDITOR.") answer = prompt("Give me some input: ", enable_open_in_editor=True) - print("You said: %s" % answer) + print(f"You said: {answer}") diff --git a/examples/prompts/terminal-title.py b/examples/prompts/terminal-title.py index 14f9459..dc49c26 100755 --- a/examples/prompts/terminal-title.py +++ b/examples/prompts/terminal-title.py @@ -7,4 +7,4 @@ if __name__ == "__main__": answer = prompt("Give me some input: ") set_title("") - print("You said: %s" % answer) + print(f"You said: {answer}") diff --git a/examples/prompts/up-arrow-partial-string-matching.py b/examples/prompts/up-arrow-partial-string-matching.py index 742a12e..999b1f9 100755 --- a/examples/prompts/up-arrow-partial-string-matching.py +++ b/examples/prompts/up-arrow-partial-string-matching.py @@ -5,6 +5,7 @@ Simple example of a CLI that demonstrates up-arrow partial string matching. When you type some input, it's possible to use the up arrow to filter the history on the items starting with the given input text. """ + from prompt_toolkit import PromptSession from prompt_toolkit.history import InMemoryHistory @@ -34,7 +35,7 @@ def main(): else: break - print("You said: %s" % text) + print(f"You said: {text}") if __name__ == "__main__": diff --git a/examples/ssh/asyncssh-server.py b/examples/ssh/asyncssh-server.py index 27d0dd2..0b09f2b 100755 --- a/examples/ssh/asyncssh-server.py +++ b/examples/ssh/asyncssh-server.py @@ -2,6 +2,7 @@ """ Example of running a prompt_toolkit application in an asyncssh server. """ + import asyncio import logging diff --git a/examples/telnet/chat-app.py b/examples/telnet/chat-app.py index 2e3508d..8f4cb2c 100755 --- a/examples/telnet/chat-app.py +++ b/examples/telnet/chat-app.py @@ -4,6 +4,7 @@ A simple chat application over telnet. Everyone that connects is asked for his name, and then people can chat with each other. """ + import logging import random from asyncio import Future, run @@ -84,9 +85,9 @@ def _send_to_everyone(sender_connection, name, message, color): if c != sender_connection: c.send_above_prompt( [ - ("fg:" + color, "[%s]" % name), + ("fg:" + color, f"[{name}]"), ("", " "), - ("fg:" + color, "%s\n" % message), + ("fg:" + color, f"{message}\n"), ] ) diff --git a/examples/telnet/dialog.py b/examples/telnet/dialog.py index c674a9d..1044fb0 100755 --- a/examples/telnet/dialog.py +++ b/examples/telnet/dialog.py @@ -2,6 +2,7 @@ """ Example of a telnet application that displays a dialog window. """ + import logging from asyncio import Future, run diff --git a/examples/telnet/hello-world.py b/examples/telnet/hello-world.py index c19c60c..f7bbda1 100755 --- a/examples/telnet/hello-world.py +++ b/examples/telnet/hello-world.py @@ -6,6 +6,7 @@ The interaction function is a prompt_toolkit coroutine. Also see the `hello-world-asyncio.py` example which uses an asyncio coroutine. That is probably the preferred way if you only need Python 3 support. """ + import logging from asyncio import run diff --git a/examples/telnet/toolbar.py b/examples/telnet/toolbar.py index d6ae886..6e31c9f 100755 --- a/examples/telnet/toolbar.py +++ b/examples/telnet/toolbar.py @@ -3,6 +3,7 @@ Example of a telnet application that displays a bottom toolbar and completions in the prompt. """ + import logging from asyncio import run diff --git a/pyproject.toml b/pyproject.toml index 7b5a835..1bff4ba 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.ruff] target-version = "py37" -select = [ +lint.select = [ "E", # pycodestyle errors "W", # pycodestyle warnings "F", # pyflakes @@ -12,7 +12,7 @@ select = [ "RUF100", # unused-noqa "Q", # quotes ] -ignore = [ +lint.ignore = [ "E501", # Line too long, handled by black "C901", # Too complex "E731", # Assign lambda. @@ -21,7 +21,7 @@ ignore = [ ] -[tool.ruff.per-file-ignores] +[tool.ruff.lint.per-file-ignores] "examples/*" = ["T201"] # Print allowed in examples. "src/prompt_toolkit/application/application.py" = ["T100", "T201", "F821"] # pdb and print allowed. "src/prompt_toolkit/contrib/telnet/server.py" = ["T201"] # Print allowed. @@ -31,9 +31,10 @@ ignore = [ "src/prompt_toolkit/filters/__init__.py" = ["F403", "F405"] # Possibly undefined due to star import. "src/prompt_toolkit/filters/cli.py" = ["F403", "F405"] # Possibly undefined due to star import. "src/prompt_toolkit/shortcuts/progress_bar/formatters.py" = ["UP031"] # %-style formatting. +"src/*" = ["UP032"] # f-strings instead of format calls. -[tool.ruff.isort] +[tool.ruff.lint.isort] known-first-party = ["prompt_toolkit"] known-third-party = ["pygments", "asyncssh"] diff --git a/src/prompt_toolkit/__init__.py b/src/prompt_toolkit/__init__.py index 82324cb..9f194f1 100644 --- a/src/prompt_toolkit/__init__.py +++ b/src/prompt_toolkit/__init__.py @@ -13,6 +13,7 @@ See the examples directory to learn about the usage. Probably, to get started, you might also want to have a look at `prompt_toolkit.shortcuts.prompt`. """ + from __future__ import annotations import re @@ -27,7 +28,7 @@ from .formatted_text import ANSI, HTML from .shortcuts import PromptSession, print_formatted_text, prompt # Don't forget to update in `docs/conf.py`! -__version__ = "3.0.43" +__version__ = "3.0.46" assert pep440.match(__version__) diff --git a/src/prompt_toolkit/application/application.py b/src/prompt_toolkit/application/application.py index d463781..d93c243 100644 --- a/src/prompt_toolkit/application/application.py +++ b/src/prompt_toolkit/application/application.py @@ -1621,5 +1621,6 @@ def _restore_sigint_from_ctypes() -> Generator[None, None, None]: try: yield finally: - signal.signal(signal.SIGINT, sigint) + if sigint is not None: + signal.signal(signal.SIGINT, sigint) pythonapi.PyOS_setsig(signal.SIGINT, sigint_os) diff --git a/src/prompt_toolkit/application/current.py b/src/prompt_toolkit/application/current.py index 908141a..7e2cf48 100644 --- a/src/prompt_toolkit/application/current.py +++ b/src/prompt_toolkit/application/current.py @@ -147,11 +147,17 @@ def create_app_session( Like in the case of an Telnet/SSH server. """ # If no input/output is specified, fall back to the current input/output, - # whatever that is. + # if there was one that was set/created for the current session. + # (Note that we check `_input`/`_output` and not `input`/`output`. This is + # because we don't want to accidently create a new input/output objects + # here and store it in the "parent" `AppSession`. Especially, when + # combining pytest's `capsys` fixture and `create_app_session`, sys.stdin + # and sys.stderr are patched for every test, so we don't want to leak + # those outputs object across `AppSession`s.) if input is None: - input = get_app_session().input + input = get_app_session()._input if output is None: - output = get_app_session().output + output = get_app_session()._output # Create new `AppSession` and activate. session = AppSession(input=input, output=output) diff --git a/src/prompt_toolkit/application/run_in_terminal.py b/src/prompt_toolkit/application/run_in_terminal.py index 1e4da2d..18a3dad 100644 --- a/src/prompt_toolkit/application/run_in_terminal.py +++ b/src/prompt_toolkit/application/run_in_terminal.py @@ -1,6 +1,7 @@ """ Tools for running functions on the terminal above the current application or prompt. """ + from __future__ import annotations from asyncio import Future, ensure_future diff --git a/src/prompt_toolkit/auto_suggest.py b/src/prompt_toolkit/auto_suggest.py index 98cb4dd..73213ba 100644 --- a/src/prompt_toolkit/auto_suggest.py +++ b/src/prompt_toolkit/auto_suggest.py @@ -11,6 +11,7 @@ because they take too much time, and could potentially block the event loop, then wrap the :class:`.AutoSuggest` instance into a :class:`.ThreadedAutoSuggest`. """ + from __future__ import annotations from abc import ABCMeta, abstractmethod @@ -46,7 +47,7 @@ class Suggestion: self.text = text def __repr__(self) -> str: - return "Suggestion(%s)" % self.text + return f"Suggestion({self.text})" class AutoSuggest(metaclass=ABCMeta): diff --git a/src/prompt_toolkit/buffer.py b/src/prompt_toolkit/buffer.py index 100ca78..f5847d4 100644 --- a/src/prompt_toolkit/buffer.py +++ b/src/prompt_toolkit/buffer.py @@ -2,6 +2,7 @@ Data structures for the Buffer. It holds the text, cursor position, history, etc... """ + from __future__ import annotations import asyncio @@ -85,12 +86,7 @@ class CompletionState: self.complete_index = complete_index # Position in the `_completions` array. def __repr__(self) -> str: - return "{}({!r}, <{!r}> completions, index={!r})".format( - self.__class__.__name__, - self.original_document, - len(self.completions), - self.complete_index, - ) + return f"{self.__class__.__name__}({self.original_document!r}, <{len(self.completions)!r}> completions, index={self.complete_index!r})" def go_to_index(self, index: int | None) -> None: """ @@ -149,12 +145,7 @@ class YankNthArgState: self.n = n def __repr__(self) -> str: - return "{}(history_position={!r}, n={!r}, previous_inserted_word={!r})".format( - self.__class__.__name__, - self.history_position, - self.n, - self.previous_inserted_word, - ) + return f"{self.__class__.__name__}(history_position={self.history_position!r}, n={self.n!r}, previous_inserted_word={self.previous_inserted_word!r})" BufferEventHandler = Callable[["Buffer"], None] @@ -188,6 +179,9 @@ class Buffer: In case of a `PromptSession` for instance, we want to keep the text, because we will exit the application, and only reset it during the next run. + :param max_number_of_completions: Never display more than this number of + completions, even when the completer can produce more (limited by + default to 10k for performance). Events: @@ -234,12 +228,13 @@ class Buffer: accept_handler: BufferAcceptHandler | None = None, read_only: FilterOrBool = False, multiline: FilterOrBool = True, + max_number_of_completions: int = 10000, on_text_changed: BufferEventHandler | None = None, on_text_insert: BufferEventHandler | None = None, on_cursor_position_changed: BufferEventHandler | None = None, on_completions_changed: BufferEventHandler | None = None, on_suggestion_set: BufferEventHandler | None = None, - ): + ) -> None: # Accept both filters and booleans as input. enable_history_search = to_filter(enable_history_search) complete_while_typing = to_filter(complete_while_typing) @@ -261,6 +256,7 @@ class Buffer: self.enable_history_search = enable_history_search self.read_only = read_only self.multiline = multiline + self.max_number_of_completions = max_number_of_completions # Text width. (For wrapping, used by the Vi 'gq' operator.) self.text_width = 0 @@ -1748,6 +1744,13 @@ class Buffer: # If the input text changes, abort. if not proceed(): break + + # Always stop at 10k completions. + if ( + len(complete_state.completions) + >= self.max_number_of_completions + ): + break finally: refresh_task.cancel() diff --git a/src/prompt_toolkit/clipboard/base.py b/src/prompt_toolkit/clipboard/base.py index b05275b..28cfdcd 100644 --- a/src/prompt_toolkit/clipboard/base.py +++ b/src/prompt_toolkit/clipboard/base.py @@ -1,6 +1,7 @@ """ Clipboard for command line interface. """ + from __future__ import annotations from abc import ABCMeta, abstractmethod diff --git a/src/prompt_toolkit/completion/base.py b/src/prompt_toolkit/completion/base.py index 04a712d..3846ef7 100644 --- a/src/prompt_toolkit/completion/base.py +++ b/src/prompt_toolkit/completion/base.py @@ -1,5 +1,5 @@ -""" -""" +""" """ + from __future__ import annotations from abc import ABCMeta, abstractmethod @@ -66,18 +66,9 @@ class Completion: def __repr__(self) -> str: if isinstance(self.display, str) and self.display == self.text: - return "{}(text={!r}, start_position={!r})".format( - self.__class__.__name__, - self.text, - self.start_position, - ) + return f"{self.__class__.__name__}(text={self.text!r}, start_position={self.start_position!r})" else: - return "{}(text={!r}, start_position={!r}, display={!r})".format( - self.__class__.__name__, - self.text, - self.start_position, - self.display, - ) + return f"{self.__class__.__name__}(text={self.text!r}, start_position={self.start_position!r}, display={self.display!r})" def __eq__(self, other: object) -> bool: if not isinstance(other, Completion): @@ -156,11 +147,7 @@ class CompleteEvent: self.completion_requested = completion_requested def __repr__(self) -> str: - return "{}(text_inserted={!r}, completion_requested={!r})".format( - self.__class__.__name__, - self.text_inserted, - self.completion_requested, - ) + return f"{self.__class__.__name__}(text_inserted={self.text_inserted!r}, completion_requested={self.completion_requested!r})" class Completer(metaclass=ABCMeta): diff --git a/src/prompt_toolkit/completion/nested.py b/src/prompt_toolkit/completion/nested.py index a1d211a..8569bd2 100644 --- a/src/prompt_toolkit/completion/nested.py +++ b/src/prompt_toolkit/completion/nested.py @@ -1,6 +1,7 @@ """ Nestedcompleter for completion of hierarchical data structures. """ + from __future__ import annotations from typing import Any, Iterable, Mapping, Set, Union diff --git a/src/prompt_toolkit/contrib/regular_languages/__init__.py b/src/prompt_toolkit/contrib/regular_languages/__init__.py index c947fd5..38b027c 100644 --- a/src/prompt_toolkit/contrib/regular_languages/__init__.py +++ b/src/prompt_toolkit/contrib/regular_languages/__init__.py @@ -72,6 +72,7 @@ TODO: some examples of: - How to create an autocompleter from this grammar. - How to create a parser from this grammar. """ + from __future__ import annotations from .compiler import compile diff --git a/src/prompt_toolkit/contrib/regular_languages/compiler.py b/src/prompt_toolkit/contrib/regular_languages/compiler.py index 474f6cf..dd558a6 100644 --- a/src/prompt_toolkit/contrib/regular_languages/compiler.py +++ b/src/prompt_toolkit/contrib/regular_languages/compiler.py @@ -38,6 +38,7 @@ Partial matches are possible:: m.variables().get('operator2') # Returns "add" """ + from __future__ import annotations import re @@ -96,13 +97,13 @@ class _CompiledGrammar: counter = [0] def create_group_func(node: Variable) -> str: - name = "n%s" % counter[0] + name = f"n{counter[0]}" self._group_names_to_nodes[name] = node.varname counter[0] += 1 return name # Compile regex strings. - self._re_pattern = "^%s$" % self._transform(root_node, create_group_func) + self._re_pattern = f"^{self._transform(root_node, create_group_func)}$" self._re_prefix_patterns = list( self._transform_prefix(root_node, create_group_func) ) @@ -153,7 +154,7 @@ class _CompiledGrammar: def transform(node: Node) -> str: # Turn `AnyNode` into an OR. if isinstance(node, AnyNode): - return "(?:%s)" % "|".join(transform(c) for c in node.children) + return "(?:{})".format("|".join(transform(c) for c in node.children)) # Concatenate a `NodeSequence` elif isinstance(node, NodeSequence): @@ -311,11 +312,11 @@ class _CompiledGrammar: yield "".join(result) elif isinstance(node, Regex): - yield "(?:%s)?" % node.regex + yield f"(?:{node.regex})?" elif isinstance(node, Lookahead): if node.negative: - yield "(?!%s)" % cls._transform(node.childnode, create_group_func) + yield f"(?!{cls._transform(node.childnode, create_group_func)})" else: # Not sure what the correct semantics are in this case. # (Probably it's not worth implementing this.) @@ -349,10 +350,10 @@ class _CompiledGrammar: ) else: - raise TypeError("Got %r" % node) + raise TypeError(f"Got {node!r}") for r in transform(root_node): - yield "^(?:%s)$" % r + yield f"^(?:{r})$" def match(self, string: str) -> Match | None: """ diff --git a/src/prompt_toolkit/contrib/regular_languages/completion.py b/src/prompt_toolkit/contrib/regular_languages/completion.py index 2e353e8..19ebaad 100644 --- a/src/prompt_toolkit/contrib/regular_languages/completion.py +++ b/src/prompt_toolkit/contrib/regular_languages/completion.py @@ -1,6 +1,7 @@ """ Completer for a regular grammar. """ + from __future__ import annotations from typing import Iterable @@ -37,12 +38,10 @@ class GrammarCompleter(Completer): m = self.compiled_grammar.match_prefix(document.text_before_cursor) if m: - completions = self._remove_duplicates( + yield from self._remove_duplicates( self._get_completions_for_match(m, complete_event) ) - yield from completions - def _get_completions_for_match( self, match: Match, complete_event: CompleteEvent ) -> Iterable[Completion]: @@ -81,14 +80,21 @@ class GrammarCompleter(Completer): display_meta=completion.display_meta, ) - def _remove_duplicates(self, items: Iterable[Completion]) -> list[Completion]: + def _remove_duplicates(self, items: Iterable[Completion]) -> Iterable[Completion]: """ Remove duplicates, while keeping the order. (Sometimes we have duplicates, because the there several matches of the same grammar, each yielding similar completions.) """ - result: list[Completion] = [] - for i in items: - if i not in result: - result.append(i) - return result + + def hash_completion(completion: Completion) -> tuple[str, int]: + return completion.text, completion.start_position + + yielded_so_far: set[tuple[str, int]] = set() + + for completion in items: + hash_value = hash_completion(completion) + + if hash_value not in yielded_so_far: + yielded_so_far.add(hash_value) + yield completion diff --git a/src/prompt_toolkit/contrib/regular_languages/lexer.py b/src/prompt_toolkit/contrib/regular_languages/lexer.py index b0a4deb..c5434cf 100644 --- a/src/prompt_toolkit/contrib/regular_languages/lexer.py +++ b/src/prompt_toolkit/contrib/regular_languages/lexer.py @@ -2,6 +2,7 @@ `GrammarLexer` is compatible with other lexers and can be used to highlight the input using a regular grammar with annotations. """ + from __future__ import annotations from typing import Callable diff --git a/src/prompt_toolkit/contrib/regular_languages/regex_parser.py b/src/prompt_toolkit/contrib/regular_languages/regex_parser.py index a365ba8..353e54f 100644 --- a/src/prompt_toolkit/contrib/regular_languages/regex_parser.py +++ b/src/prompt_toolkit/contrib/regular_languages/regex_parser.py @@ -14,6 +14,7 @@ Remarks: Limitations: - Lookahead is not supported. """ + from __future__ import annotations import re @@ -115,11 +116,7 @@ class Variable(Node): self.varname = varname def __repr__(self) -> str: - return "{}(childnode={!r}, varname={!r})".format( - self.__class__.__name__, - self.childnode, - self.varname, - ) + return f"{self.__class__.__name__}(childnode={self.childnode!r}, varname={self.varname!r})" class Repeat(Node): @@ -265,7 +262,7 @@ def parse_regex(regex_tokens: list[str]) -> Node: raise Exception(f"{t}-style repetition not yet supported") elif t.startswith("(?"): - raise Exception("%r not supported" % t) + raise Exception(f"{t!r} not supported") elif t.isspace(): pass diff --git a/src/prompt_toolkit/contrib/regular_languages/validation.py b/src/prompt_toolkit/contrib/regular_languages/validation.py index 8e56e05..e6cfd74 100644 --- a/src/prompt_toolkit/contrib/regular_languages/validation.py +++ b/src/prompt_toolkit/contrib/regular_languages/validation.py @@ -1,6 +1,7 @@ """ Validator for a regular language. """ + from __future__ import annotations from prompt_toolkit.document import Document diff --git a/src/prompt_toolkit/contrib/ssh/server.py b/src/prompt_toolkit/contrib/ssh/server.py index 9a5d402..4badc6c 100644 --- a/src/prompt_toolkit/contrib/ssh/server.py +++ b/src/prompt_toolkit/contrib/ssh/server.py @@ -1,6 +1,7 @@ """ Utility for running a prompt_toolkit application in an asyncssh server. """ + from __future__ import annotations import asyncio diff --git a/src/prompt_toolkit/contrib/telnet/log.py b/src/prompt_toolkit/contrib/telnet/log.py index 0fe8433..476dffc 100644 --- a/src/prompt_toolkit/contrib/telnet/log.py +++ b/src/prompt_toolkit/contrib/telnet/log.py @@ -1,6 +1,7 @@ """ Python logger for the telnet server. """ + from __future__ import annotations import logging diff --git a/src/prompt_toolkit/contrib/telnet/protocol.py b/src/prompt_toolkit/contrib/telnet/protocol.py index 4b90e98..58286e2 100644 --- a/src/prompt_toolkit/contrib/telnet/protocol.py +++ b/src/prompt_toolkit/contrib/telnet/protocol.py @@ -4,6 +4,7 @@ specification, but sufficient for a command line interface.) Inspired by `Twisted.conch.telnet`. """ + from __future__ import annotations import struct diff --git a/src/prompt_toolkit/contrib/telnet/server.py b/src/prompt_toolkit/contrib/telnet/server.py index 9ebe66c..69e9a88 100644 --- a/src/prompt_toolkit/contrib/telnet/server.py +++ b/src/prompt_toolkit/contrib/telnet/server.py @@ -1,6 +1,7 @@ """ Telnet server. """ + from __future__ import annotations import asyncio @@ -99,7 +100,7 @@ class _ConnectionStdout: if not self._closed: self._connection.send(b"".join(self._buffer)) except OSError as e: - logger.warning("Couldn't send data over socket: %s" % e) + logger.warning(f"Couldn't send data over socket: {e}") self._buffer = [] @@ -416,7 +417,7 @@ class TelnetServer: # Unhandled control-c propagated by a prompt. logger.info("Unhandled KeyboardInterrupt in telnet application.") except BaseException as e: - print("Got %s" % type(e).__name__, e) + print(f"Got {type(e).__name__}", e) import traceback traceback.print_exc() diff --git a/src/prompt_toolkit/document.py b/src/prompt_toolkit/document.py index 74f4c13..df5293e 100644 --- a/src/prompt_toolkit/document.py +++ b/src/prompt_toolkit/document.py @@ -1,6 +1,7 @@ """ The `Document` that implements all the text operations/querying. """ + from __future__ import annotations import bisect diff --git a/src/prompt_toolkit/eventloop/async_generator.py b/src/prompt_toolkit/eventloop/async_generator.py index 5aee50a..32e5f88 100644 --- a/src/prompt_toolkit/eventloop/async_generator.py +++ b/src/prompt_toolkit/eventloop/async_generator.py @@ -1,6 +1,7 @@ """ Implementation for async generators. """ + from __future__ import annotations from asyncio import get_running_loop diff --git a/src/prompt_toolkit/eventloop/inputhook.py b/src/prompt_toolkit/eventloop/inputhook.py index a4c0eee..40016e8 100644 --- a/src/prompt_toolkit/eventloop/inputhook.py +++ b/src/prompt_toolkit/eventloop/inputhook.py @@ -22,6 +22,7 @@ stuff to do. There are two ways to detect when to return: asynchronous autocompletion. When the completion for instance is ready, we also want prompt-toolkit to gain control again in order to display that. """ + from __future__ import annotations import asyncio diff --git a/src/prompt_toolkit/filters/__init__.py b/src/prompt_toolkit/filters/__init__.py index 277f428..556ed88 100644 --- a/src/prompt_toolkit/filters/__init__.py +++ b/src/prompt_toolkit/filters/__init__.py @@ -16,6 +16,7 @@ Filters can be chained using ``&`` and ``|`` operations, and inverted using the filter = has_focus('default') & ~ has_selection """ + from __future__ import annotations from .app import * diff --git a/src/prompt_toolkit/filters/app.py b/src/prompt_toolkit/filters/app.py index aacb228..b1b7c1b 100644 --- a/src/prompt_toolkit/filters/app.py +++ b/src/prompt_toolkit/filters/app.py @@ -1,6 +1,7 @@ """ Filters that accept a `Application` as argument. """ + from __future__ import annotations from typing import TYPE_CHECKING, cast diff --git a/src/prompt_toolkit/filters/base.py b/src/prompt_toolkit/filters/base.py index afce6dc..410749d 100644 --- a/src/prompt_toolkit/filters/base.py +++ b/src/prompt_toolkit/filters/base.py @@ -30,7 +30,7 @@ class Filter(metaclass=ABCMeta): """ Chaining of filters using the & operator. """ - assert isinstance(other, Filter), "Expecting filter, got %r" % other + assert isinstance(other, Filter), f"Expecting filter, got {other!r}" if isinstance(other, Always): return self @@ -48,7 +48,7 @@ class Filter(metaclass=ABCMeta): """ Chaining of filters using the | operator. """ - assert isinstance(other, Filter), "Expecting filter, got %r" % other + assert isinstance(other, Filter), f"Expecting filter, got {other!r}" if isinstance(other, Always): return other @@ -193,7 +193,7 @@ class _Invert(Filter): return not self.filter() def __repr__(self) -> str: - return "~%r" % self.filter + return f"~{self.filter!r}" class Always(Filter): @@ -207,6 +207,9 @@ class Always(Filter): def __or__(self, other: Filter) -> Filter: return self + def __and__(self, other: Filter) -> Filter: + return other + def __invert__(self) -> Never: return Never() @@ -222,6 +225,9 @@ class Never(Filter): def __and__(self, other: Filter) -> Filter: return self + def __or__(self, other: Filter) -> Filter: + return other + def __invert__(self) -> Always: return Always() @@ -248,7 +254,7 @@ class Condition(Filter): return self.func() def __repr__(self) -> str: - return "Condition(%r)" % self.func + return f"Condition({self.func!r})" # Often used as type annotation. diff --git a/src/prompt_toolkit/filters/cli.py b/src/prompt_toolkit/filters/cli.py index c95080a..902fbaa 100644 --- a/src/prompt_toolkit/filters/cli.py +++ b/src/prompt_toolkit/filters/cli.py @@ -2,6 +2,7 @@ For backwards-compatibility. keep this file. (Many people are going to have key bindings that rely on this file.) """ + from __future__ import annotations from .app import * diff --git a/src/prompt_toolkit/filters/utils.py b/src/prompt_toolkit/filters/utils.py index bac85ba..20e00ee 100644 --- a/src/prompt_toolkit/filters/utils.py +++ b/src/prompt_toolkit/filters/utils.py @@ -29,7 +29,7 @@ def to_filter(bool_or_filter: FilterOrBool) -> Filter: if isinstance(bool_or_filter, Filter): return bool_or_filter - raise TypeError("Expecting a bool or a Filter instance. Got %r" % bool_or_filter) + raise TypeError(f"Expecting a bool or a Filter instance. Got {bool_or_filter!r}") def is_true(value: FilterOrBool) -> bool: diff --git a/src/prompt_toolkit/formatted_text/__init__.py b/src/prompt_toolkit/formatted_text/__init__.py index db44ab9..0590c81 100644 --- a/src/prompt_toolkit/formatted_text/__init__.py +++ b/src/prompt_toolkit/formatted_text/__init__.py @@ -10,6 +10,7 @@ an :class:`.HTML` object, an :class:`.ANSI` object or a sequence of `(style_string, text)` tuples. The :func:`.to_formatted_text` conversion function takes any of these and turns all of them into such a tuple sequence. """ + from __future__ import annotations from .ansi import ANSI diff --git a/src/prompt_toolkit/formatted_text/ansi.py b/src/prompt_toolkit/formatted_text/ansi.py index 08ec0b3..4761982 100644 --- a/src/prompt_toolkit/formatted_text/ansi.py +++ b/src/prompt_toolkit/formatted_text/ansi.py @@ -210,10 +210,8 @@ class ANSI: # True colors. if n == 2 and len(attrs) >= 3: try: - color_str = "#{:02x}{:02x}{:02x}".format( - attrs.pop(), - attrs.pop(), - attrs.pop(), + color_str = ( + f"#{attrs.pop():02x}{attrs.pop():02x}{attrs.pop():02x}" ) except IndexError: pass diff --git a/src/prompt_toolkit/formatted_text/base.py b/src/prompt_toolkit/formatted_text/base.py index 92de353..5fee1f8 100644 --- a/src/prompt_toolkit/formatted_text/base.py +++ b/src/prompt_toolkit/formatted_text/base.py @@ -38,8 +38,7 @@ if TYPE_CHECKING: text. """ - def __pt_formatted_text__(self) -> StyleAndTextTuples: - ... + def __pt_formatted_text__(self) -> StyleAndTextTuples: ... AnyFormattedText = Union[ @@ -132,7 +131,7 @@ class FormattedText(StyleAndTextTuples): return self def __repr__(self) -> str: - return "FormattedText(%s)" % super().__repr__() + return f"FormattedText({super().__repr__()})" class Template: diff --git a/src/prompt_toolkit/formatted_text/utils.py b/src/prompt_toolkit/formatted_text/utils.py index c8c37e0..43228c3 100644 --- a/src/prompt_toolkit/formatted_text/utils.py +++ b/src/prompt_toolkit/formatted_text/utils.py @@ -4,6 +4,7 @@ Utilities for manipulating formatted text. When ``to_formatted_text`` has been called, we get a list of ``(style, text)`` tuples. This file contains functions for manipulating such a list. """ + from __future__ import annotations from typing import Iterable, cast diff --git a/src/prompt_toolkit/history.py b/src/prompt_toolkit/history.py index 553918e..2d497a0 100644 --- a/src/prompt_toolkit/history.py +++ b/src/prompt_toolkit/history.py @@ -7,6 +7,7 @@ NOTE: There is no `DynamicHistory`: loading can be done asynchronously and making the history swappable would probably break this. """ + from __future__ import annotations import datetime @@ -14,7 +15,7 @@ import os import threading from abc import ABCMeta, abstractmethod from asyncio import get_running_loop -from typing import AsyncGenerator, Iterable, Sequence +from typing import AsyncGenerator, Iterable, Sequence, Union __all__ = [ "History", @@ -254,12 +255,15 @@ class DummyHistory(History): pass +_StrOrBytesPath = Union[str, bytes, "os.PathLike[str]", "os.PathLike[bytes]"] + + class FileHistory(History): """ :class:`.History` class that stores all strings in a file. """ - def __init__(self, filename: str) -> None: + def __init__(self, filename: _StrOrBytesPath) -> None: self.filename = filename super().__init__() @@ -297,6 +301,6 @@ class FileHistory(History): def write(t: str) -> None: f.write(t.encode("utf-8")) - write("\n# %s\n" % datetime.datetime.now()) + write(f"\n# {datetime.datetime.now()}\n") for line in string.split("\n"): - write("+%s\n" % line) + write(f"+{line}\n") diff --git a/src/prompt_toolkit/input/ansi_escape_sequences.py b/src/prompt_toolkit/input/ansi_escape_sequences.py index 5648c66..1fba418 100644 --- a/src/prompt_toolkit/input/ansi_escape_sequences.py +++ b/src/prompt_toolkit/input/ansi_escape_sequences.py @@ -10,6 +10,7 @@ mostly Xterm compatible. Some useful docs: - Mintty: https://github.com/mintty/mintty/blob/master/wiki/Keycodes.md """ + from __future__ import annotations from ..keys import Keys diff --git a/src/prompt_toolkit/input/base.py b/src/prompt_toolkit/input/base.py index fd1429d..3dcb994 100644 --- a/src/prompt_toolkit/input/base.py +++ b/src/prompt_toolkit/input/base.py @@ -1,6 +1,7 @@ """ Abstraction of CLI Input. """ + from __future__ import annotations from abc import ABCMeta, abstractmethod, abstractproperty @@ -116,7 +117,7 @@ class DummyInput(Input): raise NotImplementedError def typeahead_hash(self) -> str: - return "dummy-%s" % id(self) + return f"dummy-{id(self)}" def read_keys(self) -> list[KeyPress]: return [] diff --git a/src/prompt_toolkit/input/typeahead.py b/src/prompt_toolkit/input/typeahead.py index a45e7cf..f8faa93 100644 --- a/src/prompt_toolkit/input/typeahead.py +++ b/src/prompt_toolkit/input/typeahead.py @@ -31,6 +31,7 @@ To support type ahead, this module will store all the key strokes that were read too early, so that they can be feed into to the next `prompt()` call or to the next prompt_toolkit `Application`. """ + from __future__ import annotations from collections import defaultdict diff --git a/src/prompt_toolkit/input/vt100_parser.py b/src/prompt_toolkit/input/vt100_parser.py index 99e2d99..73dbce3 100644 --- a/src/prompt_toolkit/input/vt100_parser.py +++ b/src/prompt_toolkit/input/vt100_parser.py @@ -1,6 +1,7 @@ """ Parser for VT100 input stream. """ + from __future__ import annotations import re diff --git a/src/prompt_toolkit/input/win32.py b/src/prompt_toolkit/input/win32.py index 35e8948..322d7c0 100644 --- a/src/prompt_toolkit/input/win32.py +++ b/src/prompt_toolkit/input/win32.py @@ -329,8 +329,8 @@ class ConsoleInputReader: buffered_high_surrogate = None for key in key_presses: is_text = not isinstance(key.key, Keys) - is_high_surrogate = is_text and "\uD800" <= key.key <= "\uDBFF" - is_low_surrogate = is_text and "\uDC00" <= key.key <= "\uDFFF" + is_high_surrogate = is_text and "\ud800" <= key.key <= "\udbff" + is_low_surrogate = is_text and "\udc00" <= key.key <= "\udfff" if buffered_high_surrogate: if is_low_surrogate: diff --git a/src/prompt_toolkit/key_binding/bindings/auto_suggest.py b/src/prompt_toolkit/key_binding/bindings/auto_suggest.py index 3d8a843..b487f14 100644 --- a/src/prompt_toolkit/key_binding/bindings/auto_suggest.py +++ b/src/prompt_toolkit/key_binding/bindings/auto_suggest.py @@ -1,6 +1,7 @@ """ Key bindings for auto suggestion (for fish-style auto suggestion). """ + from __future__ import annotations import re diff --git a/src/prompt_toolkit/key_binding/bindings/basic.py b/src/prompt_toolkit/key_binding/bindings/basic.py index 084548d..ad18df9 100644 --- a/src/prompt_toolkit/key_binding/bindings/basic.py +++ b/src/prompt_toolkit/key_binding/bindings/basic.py @@ -29,6 +29,16 @@ def if_no_repeat(event: E) -> bool: return not event.is_repeat +@Condition +def has_text_before_cursor() -> bool: + return bool(get_app().current_buffer.text) + + +@Condition +def in_quoted_insert() -> bool: + return get_app().quoted_insert + + def load_basic_bindings() -> KeyBindings: key_bindings = KeyBindings() insert_mode = vi_insert_mode | emacs_insert_mode @@ -171,10 +181,6 @@ def load_basic_bindings() -> KeyBindings: # CTRL keys. - @Condition - def has_text_before_cursor() -> bool: - return bool(get_app().current_buffer.text) - handle("c-d", filter=has_text_before_cursor & insert_mode)( get_by_name("delete-char") ) @@ -240,10 +246,6 @@ def load_basic_bindings() -> KeyBindings: event.current_buffer.insert_text(data) - @Condition - def in_quoted_insert() -> bool: - return get_app().quoted_insert - @handle(Keys.Any, filter=in_quoted_insert, eager=True) def _insert_text(event: E) -> None: """ diff --git a/src/prompt_toolkit/key_binding/bindings/completion.py b/src/prompt_toolkit/key_binding/bindings/completion.py index 016821f..8c5e005 100644 --- a/src/prompt_toolkit/key_binding/bindings/completion.py +++ b/src/prompt_toolkit/key_binding/bindings/completion.py @@ -1,6 +1,7 @@ """ Key binding handlers for displaying completions. """ + from __future__ import annotations import asyncio diff --git a/src/prompt_toolkit/key_binding/bindings/emacs.py b/src/prompt_toolkit/key_binding/bindings/emacs.py index 80a66fd..207afba 100644 --- a/src/prompt_toolkit/key_binding/bindings/emacs.py +++ b/src/prompt_toolkit/key_binding/bindings/emacs.py @@ -33,6 +33,16 @@ __all__ = [ E = KeyPressEvent +@Condition +def is_returnable() -> bool: + return get_app().current_buffer.is_returnable + + +@Condition +def is_arg() -> bool: + return get_app().key_processor.arg == "-" + + def load_emacs_bindings() -> KeyBindingsBase: """ Some e-macs extensions. @@ -134,7 +144,7 @@ def load_emacs_bindings() -> KeyBindingsBase: if event._arg is None: event.append_to_arg_count("-") - @handle("-", filter=Condition(lambda: get_app().key_processor.arg == "-")) + @handle("-", filter=is_arg) def _dash(event: E) -> None: """ When '-' is typed again, after exactly '-' has been given as an @@ -142,10 +152,6 @@ def load_emacs_bindings() -> KeyBindingsBase: """ event.app.key_processor.arg = "-" - @Condition - def is_returnable() -> bool: - return get_app().current_buffer.is_returnable - # Meta + Enter: always accept input. handle("escape", "enter", filter=insert_mode & is_returnable)( get_by_name("accept-line") diff --git a/src/prompt_toolkit/key_binding/bindings/named_commands.py b/src/prompt_toolkit/key_binding/bindings/named_commands.py index d836116..8ea8dd0 100644 --- a/src/prompt_toolkit/key_binding/bindings/named_commands.py +++ b/src/prompt_toolkit/key_binding/bindings/named_commands.py @@ -3,6 +3,7 @@ Key bindings which are also known by GNU Readline by the given names. See: http://www.delorie.com/gnu/docs/readline/rlman_13.html """ + from __future__ import annotations from typing import Callable, TypeVar, Union, cast @@ -58,7 +59,7 @@ def get_by_name(name: str) -> Binding: try: return _readline_commands[name] except KeyError as e: - raise KeyError("Unknown Readline command: %r" % name) from e + raise KeyError(f"Unknown Readline command: {name!r}") from e # diff --git a/src/prompt_toolkit/key_binding/bindings/open_in_editor.py b/src/prompt_toolkit/key_binding/bindings/open_in_editor.py index d156424..26b8685 100644 --- a/src/prompt_toolkit/key_binding/bindings/open_in_editor.py +++ b/src/prompt_toolkit/key_binding/bindings/open_in_editor.py @@ -1,6 +1,7 @@ """ Open in editor key bindings. """ + from __future__ import annotations from prompt_toolkit.filters import emacs_mode, has_selection, vi_navigation_mode diff --git a/src/prompt_toolkit/key_binding/bindings/page_navigation.py b/src/prompt_toolkit/key_binding/bindings/page_navigation.py index 3918e14..c490425 100644 --- a/src/prompt_toolkit/key_binding/bindings/page_navigation.py +++ b/src/prompt_toolkit/key_binding/bindings/page_navigation.py @@ -2,6 +2,7 @@ Key bindings for extra page navigation: bindings for up/down scrolling through long pages, like in Emacs or Vi. """ + from __future__ import annotations from prompt_toolkit.filters import buffer_has_focus, emacs_mode, vi_mode diff --git a/src/prompt_toolkit/key_binding/bindings/scroll.py b/src/prompt_toolkit/key_binding/bindings/scroll.py index 83a4be1..13e44ed 100644 --- a/src/prompt_toolkit/key_binding/bindings/scroll.py +++ b/src/prompt_toolkit/key_binding/bindings/scroll.py @@ -5,6 +5,7 @@ This are separate bindings, because GNU readline doesn't have them, but they are very useful for navigating through long multiline buffers, like in Vi, Emacs, etc... """ + from __future__ import annotations from prompt_toolkit.key_binding.key_processor import KeyPressEvent diff --git a/src/prompt_toolkit/key_binding/bindings/search.py b/src/prompt_toolkit/key_binding/bindings/search.py index ba5e117..a57c52e 100644 --- a/src/prompt_toolkit/key_binding/bindings/search.py +++ b/src/prompt_toolkit/key_binding/bindings/search.py @@ -1,6 +1,7 @@ """ Search related key bindings. """ + from __future__ import annotations from prompt_toolkit import search diff --git a/src/prompt_toolkit/key_binding/bindings/vi.py b/src/prompt_toolkit/key_binding/bindings/vi.py index 5cc74b4..d68a31f 100644 --- a/src/prompt_toolkit/key_binding/bindings/vi.py +++ b/src/prompt_toolkit/key_binding/bindings/vi.py @@ -371,6 +371,35 @@ def create_operator_decorator( return operator_decorator +@Condition +def is_returnable() -> bool: + return get_app().current_buffer.is_returnable + + +@Condition +def in_block_selection() -> bool: + buff = get_app().current_buffer + return bool( + buff.selection_state and buff.selection_state.type == SelectionType.BLOCK + ) + + +@Condition +def digraph_symbol_1_given() -> bool: + return get_app().vi_state.digraph_symbol1 is not None + + +@Condition +def search_buffer_is_empty() -> bool: + "Returns True when the search buffer is empty." + return get_app().current_buffer.text == "" + + +@Condition +def tilde_operator() -> bool: + return get_app().vi_state.tilde_operator + + def load_vi_bindings() -> KeyBindingsBase: """ Vi extensions. @@ -410,7 +439,7 @@ def load_vi_bindings() -> KeyBindingsBase: (("g", "~"), Always(), lambda string: string.swapcase()), ( ("~",), - Condition(lambda: get_app().vi_state.tilde_operator), + tilde_operator, lambda string: string.swapcase(), ), ] @@ -528,10 +557,6 @@ def load_vi_bindings() -> KeyBindingsBase: """ event.current_buffer.cancel_completion() - @Condition - def is_returnable() -> bool: - return get_app().current_buffer.is_returnable - # In navigation mode, pressing enter will always return the input. handle("enter", filter=vi_navigation_mode & is_returnable)( get_by_name("accept-line") @@ -681,13 +706,6 @@ def load_vi_bindings() -> KeyBindingsBase: ) ) - @Condition - def in_block_selection() -> bool: - buff = get_app().current_buffer - return bool( - buff.selection_state and buff.selection_state.type == SelectionType.BLOCK - ) - @handle("I", filter=in_block_selection & ~is_read_only) def insert_in_block_selection(event: E, after: bool = False) -> None: """ @@ -2071,10 +2089,6 @@ def load_vi_bindings() -> KeyBindingsBase: """ event.app.vi_state.waiting_for_digraph = True - @Condition - def digraph_symbol_1_given() -> bool: - return get_app().vi_state.digraph_symbol1 is not None - @handle(Keys.Any, filter=vi_digraph_mode & ~digraph_symbol_1_given) def _digraph1(event: E) -> None: """ @@ -2180,11 +2194,6 @@ def load_vi_search_bindings() -> KeyBindingsBase: handle = key_bindings.add from . import search - @Condition - def search_buffer_is_empty() -> bool: - "Returns True when the search buffer is empty." - return get_app().current_buffer.text == "" - # Vi-style forward search. handle( "/", diff --git a/src/prompt_toolkit/key_binding/defaults.py b/src/prompt_toolkit/key_binding/defaults.py index 166da8d..6c26571 100644 --- a/src/prompt_toolkit/key_binding/defaults.py +++ b/src/prompt_toolkit/key_binding/defaults.py @@ -4,6 +4,7 @@ Default key bindings.:: key_bindings = load_key_bindings() app = Application(key_bindings=key_bindings) """ + from __future__ import annotations from prompt_toolkit.filters import buffer_has_focus diff --git a/src/prompt_toolkit/key_binding/digraphs.py b/src/prompt_toolkit/key_binding/digraphs.py index 1e8a432..f0152dc 100644 --- a/src/prompt_toolkit/key_binding/digraphs.py +++ b/src/prompt_toolkit/key_binding/digraphs.py @@ -6,6 +6,7 @@ pressing Control-K followed by to normal characters. Taken from Neovim and translated to Python: https://raw.githubusercontent.com/neovim/neovim/master/src/nvim/digraph.c """ + from __future__ import annotations __all__ = [ diff --git a/src/prompt_toolkit/key_binding/key_bindings.py b/src/prompt_toolkit/key_binding/key_bindings.py index 62530f2..854da80 100644 --- a/src/prompt_toolkit/key_binding/key_bindings.py +++ b/src/prompt_toolkit/key_binding/key_bindings.py @@ -34,6 +34,7 @@ been assigned, through the `key_binding` decorator.:: # Later, add it to the key bindings. kb.add(Keys.A, my_key_binding) """ + from __future__ import annotations from abc import ABCMeta, abstractmethod, abstractproperty @@ -140,10 +141,8 @@ class Binding: event.app.invalidate() def __repr__(self) -> str: - return "{}(keys={!r}, handler={!r})".format( - self.__class__.__name__, - self.keys, - self.handler, + return ( + f"{self.__class__.__name__}(keys={self.keys!r}, handler={self.handler!r})" ) @@ -226,9 +225,9 @@ class KeyBindings(KeyBindingsBase): def __init__(self) -> None: self._bindings: list[Binding] = [] - self._get_bindings_for_keys_cache: SimpleCache[ - KeysTuple, list[Binding] - ] = SimpleCache(maxsize=10000) + self._get_bindings_for_keys_cache: SimpleCache[KeysTuple, list[Binding]] = ( + SimpleCache(maxsize=10000) + ) self._get_bindings_starting_with_keys_cache: SimpleCache[ KeysTuple, list[Binding] ] = SimpleCache(maxsize=1000) diff --git a/src/prompt_toolkit/key_binding/key_processor.py b/src/prompt_toolkit/key_binding/key_processor.py index 4c4f0d1..e2070a1 100644 --- a/src/prompt_toolkit/key_binding/key_processor.py +++ b/src/prompt_toolkit/key_binding/key_processor.py @@ -5,6 +5,7 @@ the input in the :class:`~prompt_toolkit.inputstream.InputStream` instance. The `KeyProcessor` will according to the implemented keybindings call the correct callbacks when new key presses are feed through `feed`. """ + from __future__ import annotations import weakref @@ -450,11 +451,7 @@ class KeyPressEvent: self._app = get_app() def __repr__(self) -> str: - return "KeyPressEvent(arg={!r}, key_sequence={!r}, is_repeat={!r})".format( - self.arg, - self.key_sequence, - self.is_repeat, - ) + return f"KeyPressEvent(arg={self.arg!r}, key_sequence={self.key_sequence!r}, is_repeat={self.is_repeat!r})" @property def data(self) -> str: diff --git a/src/prompt_toolkit/layout/__init__.py b/src/prompt_toolkit/layout/__init__.py index c5fce46..7cd0c77 100644 --- a/src/prompt_toolkit/layout/__init__.py +++ b/src/prompt_toolkit/layout/__init__.py @@ -44,6 +44,7 @@ And one prepared menu: - CompletionsMenu """ + from __future__ import annotations from .containers import ( diff --git a/src/prompt_toolkit/layout/containers.py b/src/prompt_toolkit/layout/containers.py index 100d4aa..99b4534 100644 --- a/src/prompt_toolkit/layout/containers.py +++ b/src/prompt_toolkit/layout/containers.py @@ -2,6 +2,7 @@ Container for the layout. (Containers can contain other containers or user interface controls.) """ + from __future__ import annotations from abc import ABCMeta, abstractmethod @@ -156,8 +157,7 @@ if TYPE_CHECKING: Any object that implements ``__pt_container__`` represents a container. """ - def __pt_container__(self) -> AnyContainer: - ... + def __pt_container__(self) -> AnyContainer: ... AnyContainer = Union[Container, "MagicContainer"] @@ -296,9 +296,9 @@ class HSplit(_Split): self.align = align - self._children_cache: SimpleCache[ - tuple[Container, ...], list[Container] - ] = SimpleCache(maxsize=1) + self._children_cache: SimpleCache[tuple[Container, ...], list[Container]] = ( + SimpleCache(maxsize=1) + ) self._remaining_space_window = Window() # Dummy window. def preferred_width(self, max_available_width: int) -> Dimension: @@ -533,9 +533,9 @@ class VSplit(_Split): self.align = align - self._children_cache: SimpleCache[ - tuple[Container, ...], list[Container] - ] = SimpleCache(maxsize=1) + self._children_cache: SimpleCache[tuple[Container, ...], list[Container]] = ( + SimpleCache(maxsize=1) + ) self._remaining_space_window = Window() # Dummy window. def preferred_width(self, max_available_width: int) -> Dimension: @@ -1093,7 +1093,7 @@ class Float: return self.height def __repr__(self) -> str: - return "Float(content=%r)" % self.content + return f"Float(content={self.content!r})" class WindowRenderInfo: @@ -1352,12 +1352,7 @@ class ScrollOffsets: return to_int(self._right) def __repr__(self) -> str: - return "ScrollOffsets(top={!r}, bottom={!r}, left={!r}, right={!r})".format( - self._top, - self._bottom, - self._left, - self._right, - ) + return f"ScrollOffsets(top={self._top!r}, bottom={self._bottom!r}, left={self._left!r}, right={self._right!r})" class ColorColumn: @@ -1504,9 +1499,9 @@ class Window(Container): self.z_index = z_index # Cache for the screens generated by the margin. - self._ui_content_cache: SimpleCache[ - tuple[int, int, int], UIContent - ] = SimpleCache(maxsize=8) + self._ui_content_cache: SimpleCache[tuple[int, int, int], UIContent] = ( + SimpleCache(maxsize=8) + ) self._margin_width_cache: SimpleCache[tuple[Margin, int], int] = SimpleCache( maxsize=1 ) @@ -1514,7 +1509,7 @@ class Window(Container): self.reset() def __repr__(self) -> str: - return "Window(content=%r)" % self.content + return f"Window(content={self.content!r})" def reset(self) -> None: self.content.reset() diff --git a/src/prompt_toolkit/layout/controls.py b/src/prompt_toolkit/layout/controls.py index c30c0ef..222e471 100644 --- a/src/prompt_toolkit/layout/controls.py +++ b/src/prompt_toolkit/layout/controls.py @@ -1,6 +1,7 @@ """ User interface Controls for the layout. """ + from __future__ import annotations import time diff --git a/src/prompt_toolkit/layout/dimension.py b/src/prompt_toolkit/layout/dimension.py index c1f05f9..2e6f5dd 100644 --- a/src/prompt_toolkit/layout/dimension.py +++ b/src/prompt_toolkit/layout/dimension.py @@ -2,6 +2,7 @@ Layout dimensions are used to give the minimum, maximum and preferred dimensions for containers and controls. """ + from __future__ import annotations from typing import TYPE_CHECKING, Any, Callable, Union @@ -105,15 +106,15 @@ class Dimension: def __repr__(self) -> str: fields = [] if self.min_specified: - fields.append("min=%r" % self.min) + fields.append(f"min={self.min!r}") if self.max_specified: - fields.append("max=%r" % self.max) + fields.append(f"max={self.max!r}") if self.preferred_specified: - fields.append("preferred=%r" % self.preferred) + fields.append(f"preferred={self.preferred!r}") if self.weight_specified: - fields.append("weight=%r" % self.weight) + fields.append(f"weight={self.weight!r}") - return "Dimension(%s)" % ", ".join(fields) + return "Dimension({})".format(", ".join(fields)) def sum_layout_dimensions(dimensions: list[Dimension]) -> Dimension: diff --git a/src/prompt_toolkit/layout/dummy.py b/src/prompt_toolkit/layout/dummy.py index 139f311..1ee3e6c 100644 --- a/src/prompt_toolkit/layout/dummy.py +++ b/src/prompt_toolkit/layout/dummy.py @@ -2,6 +2,7 @@ Dummy layout. Used when somebody creates an `Application` without specifying a `Layout`. """ + from __future__ import annotations from prompt_toolkit.formatted_text import HTML diff --git a/src/prompt_toolkit/layout/layout.py b/src/prompt_toolkit/layout/layout.py index a5e7a80..f9b7110 100644 --- a/src/prompt_toolkit/layout/layout.py +++ b/src/prompt_toolkit/layout/layout.py @@ -1,6 +1,7 @@ """ Wrapper for the layout. """ + from __future__ import annotations from typing import Generator, Iterable, Union diff --git a/src/prompt_toolkit/layout/margins.py b/src/prompt_toolkit/layout/margins.py index cc9dd96..737a74d 100644 --- a/src/prompt_toolkit/layout/margins.py +++ b/src/prompt_toolkit/layout/margins.py @@ -1,6 +1,7 @@ """ Margin implementations for a :class:`~prompt_toolkit.layout.containers.Window`. """ + from __future__ import annotations from abc import ABCMeta, abstractmethod @@ -83,7 +84,7 @@ class NumberedMargin(Margin): def get_width(self, get_ui_content: Callable[[], UIContent]) -> int: line_count = get_ui_content().line_count - return max(3, len("%s" % line_count) + 1) + return max(3, len(f"{line_count}") + 1) def create_margin( self, window_render_info: WindowRenderInfo, width: int, height: int diff --git a/src/prompt_toolkit/layout/menus.py b/src/prompt_toolkit/layout/menus.py index 2c2ccb6..612e8ab 100644 --- a/src/prompt_toolkit/layout/menus.py +++ b/src/prompt_toolkit/layout/menus.py @@ -212,10 +212,7 @@ def _get_menu_item_fragments( width. """ if is_current_completion: - style_str = "class:completion-menu.completion.current {} {}".format( - completion.style, - completion.selected_style, - ) + style_str = f"class:completion-menu.completion.current {completion.style} {completion.selected_style}" else: style_str = "class:completion-menu.completion " + completion.style diff --git a/src/prompt_toolkit/layout/mouse_handlers.py b/src/prompt_toolkit/layout/mouse_handlers.py index 56a4edd..52deac1 100644 --- a/src/prompt_toolkit/layout/mouse_handlers.py +++ b/src/prompt_toolkit/layout/mouse_handlers.py @@ -34,9 +34,9 @@ class MouseHandlers: # over the mouse handlers of the visible region in the scrollable pane. # Map y (row) to x (column) to handlers. - self.mouse_handlers: defaultdict[ - int, defaultdict[int, MouseHandler] - ] = defaultdict(lambda: defaultdict(lambda: dummy_callback)) + self.mouse_handlers: defaultdict[int, defaultdict[int, MouseHandler]] = ( + defaultdict(lambda: defaultdict(lambda: dummy_callback)) + ) def set_mouse_handler_for_range( self, diff --git a/src/prompt_toolkit/layout/processors.py b/src/prompt_toolkit/layout/processors.py index b737611..b10ecf7 100644 --- a/src/prompt_toolkit/layout/processors.py +++ b/src/prompt_toolkit/layout/processors.py @@ -5,6 +5,7 @@ from a buffer before the BufferControl will render it to the screen. They can insert fragments before or after, or highlight fragments by replacing the fragment types. """ + from __future__ import annotations import re @@ -343,9 +344,9 @@ class HighlightMatchingBracketProcessor(Processor): self.chars = chars self.max_cursor_distance = max_cursor_distance - self._positions_cache: SimpleCache[ - Hashable, list[tuple[int, int]] - ] = SimpleCache(maxsize=8) + self._positions_cache: SimpleCache[Hashable, list[tuple[int, int]]] = ( + SimpleCache(maxsize=8) + ) def _get_positions_to_highlight(self, document: Document) -> list[tuple[int, int]]: """ @@ -924,11 +925,7 @@ class ConditionalProcessor(Processor): return Transformation(transformation_input.fragments) def __repr__(self) -> str: - return "{}(processor={!r}, filter={!r})".format( - self.__class__.__name__, - self.processor, - self.filter, - ) + return f"{self.__class__.__name__}(processor={self.processor!r}, filter={self.filter!r})" class DynamicProcessor(Processor): diff --git a/src/prompt_toolkit/layout/screen.py b/src/prompt_toolkit/layout/screen.py index 49aebbd..0f19f52 100644 --- a/src/prompt_toolkit/layout/screen.py +++ b/src/prompt_toolkit/layout/screen.py @@ -320,10 +320,4 @@ class WritePosition: self.height = height def __repr__(self) -> str: - return "{}(x={!r}, y={!r}, width={!r}, height={!r})".format( - self.__class__.__name__, - self.xpos, - self.ypos, - self.width, - self.height, - ) + return f"{self.__class__.__name__}(x={self.xpos!r}, y={self.ypos!r}, width={self.width!r}, height={self.height!r})" diff --git a/src/prompt_toolkit/layout/utils.py b/src/prompt_toolkit/layout/utils.py index 0f78f37..373fe52 100644 --- a/src/prompt_toolkit/layout/utils.py +++ b/src/prompt_toolkit/layout/utils.py @@ -36,12 +36,10 @@ class _ExplodedList(List[_T]): # TODO: When creating a copy() or [:], return also an _ExplodedList. @overload - def __setitem__(self, index: SupportsIndex, value: _T) -> None: - ... + def __setitem__(self, index: SupportsIndex, value: _T) -> None: ... @overload - def __setitem__(self, index: slice, value: Iterable[_T]) -> None: - ... + def __setitem__(self, index: slice, value: Iterable[_T]) -> None: ... def __setitem__( self, index: SupportsIndex | slice, value: _T | Iterable[_T] diff --git a/src/prompt_toolkit/lexers/__init__.py b/src/prompt_toolkit/lexers/__init__.py index 9bdc599..8f72d07 100644 --- a/src/prompt_toolkit/lexers/__init__.py +++ b/src/prompt_toolkit/lexers/__init__.py @@ -2,6 +2,7 @@ Lexer interface and implementations. Used for syntax highlighting. """ + from __future__ import annotations from .base import DynamicLexer, Lexer, SimpleLexer diff --git a/src/prompt_toolkit/lexers/base.py b/src/prompt_toolkit/lexers/base.py index 3f65f8e..c61e2b9 100644 --- a/src/prompt_toolkit/lexers/base.py +++ b/src/prompt_toolkit/lexers/base.py @@ -1,6 +1,7 @@ """ Base classes for prompt_toolkit lexers. """ + from __future__ import annotations from abc import ABCMeta, abstractmethod diff --git a/src/prompt_toolkit/lexers/pygments.py b/src/prompt_toolkit/lexers/pygments.py index 4721d73..d5a39c4 100644 --- a/src/prompt_toolkit/lexers/pygments.py +++ b/src/prompt_toolkit/lexers/pygments.py @@ -4,6 +4,7 @@ Adaptor classes for using Pygments lexers within prompt_toolkit. This includes syntax synchronization code, so that we don't have to start lexing at the beginning of a document, when displaying a very large text. """ + from __future__ import annotations import re diff --git a/src/prompt_toolkit/log.py b/src/prompt_toolkit/log.py index adb5172..2853579 100644 --- a/src/prompt_toolkit/log.py +++ b/src/prompt_toolkit/log.py @@ -1,6 +1,7 @@ """ Logging configuration. """ + from __future__ import annotations import logging diff --git a/src/prompt_toolkit/mouse_events.py b/src/prompt_toolkit/mouse_events.py index 743773b..f244f8e 100644 --- a/src/prompt_toolkit/mouse_events.py +++ b/src/prompt_toolkit/mouse_events.py @@ -15,6 +15,7 @@ through the `Window` class where the coordinates are translated from absolute coordinates to coordinates relative to the user control, and there `UIControl.mouse_handler` is called. """ + from __future__ import annotations from enum import Enum @@ -81,9 +82,4 @@ class MouseEvent: self.modifiers = modifiers def __repr__(self) -> str: - return "MouseEvent({!r},{!r},{!r},{!r})".format( - self.position, - self.event_type, - self.button, - self.modifiers, - ) + return f"MouseEvent({self.position!r},{self.event_type!r},{self.button!r},{self.modifiers!r})" diff --git a/src/prompt_toolkit/output/base.py b/src/prompt_toolkit/output/base.py index 3c38cec..6ba09fd 100644 --- a/src/prompt_toolkit/output/base.py +++ b/src/prompt_toolkit/output/base.py @@ -1,6 +1,7 @@ """ Interface for an output. """ + from __future__ import annotations from abc import ABCMeta, abstractmethod diff --git a/src/prompt_toolkit/output/vt100.py b/src/prompt_toolkit/output/vt100.py index 142deab..069636b 100644 --- a/src/prompt_toolkit/output/vt100.py +++ b/src/prompt_toolkit/output/vt100.py @@ -6,6 +6,7 @@ A lot of thanks, regarding outputting of colors, goes to the Pygments project: everything has been highly optimized.) http://pygments.org/ """ + from __future__ import annotations import io @@ -521,7 +522,7 @@ class Vt100_Output(Output): "eterm-color", ): # Not supported by the Linux console. self.write_raw( - "\x1b]2;%s\x07" % title.replace("\x1b", "").replace("\x07", "") + "\x1b]2;{}\x07".format(title.replace("\x1b", "").replace("\x07", "")) ) def clear_title(self) -> None: diff --git a/src/prompt_toolkit/output/win32.py b/src/prompt_toolkit/output/win32.py index edeca09..83ccea4 100644 --- a/src/prompt_toolkit/output/win32.py +++ b/src/prompt_toolkit/output/win32.py @@ -73,11 +73,11 @@ class NoConsoleScreenBufferError(Exception): if xterm: message = ( - "Found %s, while expecting a Windows console. " + "Found {}, while expecting a Windows console. " 'Maybe try to run this program using "winpty" ' "or run it in cmd.exe instead. Or otherwise, " "in case of Cygwin, use the Python executable " - "that is compiled for Cygwin." % os.environ["TERM"] + "that is compiled for Cygwin.".format(os.environ["TERM"]) ) else: message = "No Windows console found. Are you running cmd.exe?" @@ -163,13 +163,13 @@ class Win32Output(Output): self.flush() if _DEBUG_RENDER_OUTPUT: - self.LOG.write(("%r" % func.__name__).encode("utf-8") + b"\n") + self.LOG.write((f"{func.__name__!r}").encode() + b"\n") self.LOG.write( - b" " + ", ".join(["%r" % i for i in a]).encode("utf-8") + b"\n" + b" " + ", ".join([f"{i!r}" for i in a]).encode("utf-8") + b"\n" ) self.LOG.write( b" " - + ", ".join(["%r" % type(i) for i in a]).encode("utf-8") + + ", ".join([f"{type(i)!r}" for i in a]).encode("utf-8") + b"\n" ) self.LOG.flush() @@ -370,7 +370,7 @@ class Win32Output(Output): data = "".join(self._buffer) if _DEBUG_RENDER_OUTPUT: - self.LOG.write(("%r" % data).encode("utf-8") + b"\n") + self.LOG.write((f"{data!r}").encode() + b"\n") self.LOG.flush() # Print characters one by one. This appears to be the best solution diff --git a/src/prompt_toolkit/patch_stdout.py b/src/prompt_toolkit/patch_stdout.py index 528bec7..4958e9d 100644 --- a/src/prompt_toolkit/patch_stdout.py +++ b/src/prompt_toolkit/patch_stdout.py @@ -17,6 +17,7 @@ Usage:: Multiple applications can run in the body of the context manager, one after the other. """ + from __future__ import annotations import asyncio diff --git a/src/prompt_toolkit/renderer.py b/src/prompt_toolkit/renderer.py index 5ad1dd6..3f92303 100644 --- a/src/prompt_toolkit/renderer.py +++ b/src/prompt_toolkit/renderer.py @@ -2,6 +2,7 @@ Renders the command line on the console. (Redraws parts of the input line that were changed.) """ + from __future__ import annotations from asyncio import FIRST_COMPLETED, Future, ensure_future, sleep, wait diff --git a/src/prompt_toolkit/search.py b/src/prompt_toolkit/search.py index fd90a04..d1cf7ac 100644 --- a/src/prompt_toolkit/search.py +++ b/src/prompt_toolkit/search.py @@ -5,6 +5,7 @@ For the key bindings implementation with attached filters, check `prompt_toolkit.key_binding.bindings.search`. (Use these for new key bindings instead of calling these function directly.) """ + from __future__ import annotations from enum import Enum @@ -59,12 +60,7 @@ class SearchState: self.ignore_case = to_filter(ignore_case) def __repr__(self) -> str: - return "{}({!r}, direction={!r}, ignore_case={!r})".format( - self.__class__.__name__, - self.text, - self.direction, - self.ignore_case, - ) + return f"{self.__class__.__name__}({self.text!r}, direction={self.direction!r}, ignore_case={self.ignore_case!r})" def __invert__(self) -> SearchState: """ diff --git a/src/prompt_toolkit/selection.py b/src/prompt_toolkit/selection.py index 2158fa9..ff88535 100644 --- a/src/prompt_toolkit/selection.py +++ b/src/prompt_toolkit/selection.py @@ -1,6 +1,7 @@ """ Data structures for the selection. """ + from __future__ import annotations from enum import Enum @@ -54,8 +55,4 @@ class SelectionState: self.shift_mode = True def __repr__(self) -> str: - return "{}(original_cursor_position={!r}, type={!r})".format( - self.__class__.__name__, - self.original_cursor_position, - self.type, - ) + return f"{self.__class__.__name__}(original_cursor_position={self.original_cursor_position!r}, type={self.type!r})" diff --git a/src/prompt_toolkit/shortcuts/progress_bar/base.py b/src/prompt_toolkit/shortcuts/progress_bar/base.py index 21aa1be..a7c2a52 100644 --- a/src/prompt_toolkit/shortcuts/progress_bar/base.py +++ b/src/prompt_toolkit/shortcuts/progress_bar/base.py @@ -7,6 +7,7 @@ Progress bar implementation on top of prompt_toolkit. for item in pb(data): ... """ + from __future__ import annotations import contextvars diff --git a/src/prompt_toolkit/shortcuts/progress_bar/formatters.py b/src/prompt_toolkit/shortcuts/progress_bar/formatters.py index dd0339c..202949c 100644 --- a/src/prompt_toolkit/shortcuts/progress_bar/formatters.py +++ b/src/prompt_toolkit/shortcuts/progress_bar/formatters.py @@ -2,6 +2,7 @@ Formatter classes for the progress bar. Each progress bar consists of a list of these formatters. """ + from __future__ import annotations import datetime @@ -130,7 +131,7 @@ class Percentage(Formatter): Display the progress as a percentage. """ - template = "<percentage>{percentage:>5}%</percentage>" + template = HTML("<percentage>{percentage:>5}%</percentage>") def format( self, @@ -138,7 +139,7 @@ class Percentage(Formatter): progress: ProgressBarCounter[object], width: int, ) -> AnyFormattedText: - return HTML(self.template).format(percentage=round(progress.percentage, 1)) + return self.template.format(percentage=round(progress.percentage, 1)) def get_width(self, progress_bar: ProgressBar) -> AnyDimension: return D.exact(6) @@ -149,7 +150,9 @@ class Bar(Formatter): Display the progress bar itself. """ - template = "<bar>{start}<bar-a>{bar_a}</bar-a><bar-b>{bar_b}</bar-b><bar-c>{bar_c}</bar-c>{end}</bar>" + template = HTML( + "<bar>{start}<bar-a>{bar_a}</bar-a><bar-b>{bar_b}</bar-b><bar-c>{bar_c}</bar-c>{end}</bar>" + ) def __init__( self, @@ -202,7 +205,7 @@ class Bar(Formatter): bar_b = sym_b bar_c = sym_c * (width - pb_a) - return HTML(self.template).format( + return self.template.format( start=self.start, end=self.end, bar_a=bar_a, bar_b=bar_b, bar_c=bar_c ) @@ -215,7 +218,7 @@ class Progress(Formatter): Display the progress as text. E.g. "8/20" """ - template = "<current>{current:>3}</current>/<total>{total:>3}</total>" + template = HTML("<current>{current:>3}</current>/<total>{total:>3}</total>") def format( self, @@ -223,7 +226,7 @@ class Progress(Formatter): progress: ProgressBarCounter[object], width: int, ) -> AnyFormattedText: - return HTML(self.template).format( + return self.template.format( current=progress.items_completed, total=progress.total or "?" ) @@ -250,6 +253,8 @@ class TimeElapsed(Formatter): Display the elapsed time. """ + template = HTML("<time-elapsed>{time_elapsed}</time-elapsed>") + def format( self, progress_bar: ProgressBar, @@ -257,9 +262,7 @@ class TimeElapsed(Formatter): width: int, ) -> AnyFormattedText: text = _format_timedelta(progress.time_elapsed).rjust(width) - return HTML("<time-elapsed>{time_elapsed}</time-elapsed>").format( - time_elapsed=text - ) + return self.template.format(time_elapsed=text) def get_width(self, progress_bar: ProgressBar) -> AnyDimension: all_values = [ @@ -275,7 +278,7 @@ class TimeLeft(Formatter): Display the time left. """ - template = "<time-left>{time_left}</time-left>" + template = HTML("<time-left>{time_left}</time-left>") unknown = "?:??:??" def format( @@ -290,7 +293,7 @@ class TimeLeft(Formatter): else: formatted_time_left = self.unknown - return HTML(self.template).format(time_left=formatted_time_left.rjust(width)) + return self.template.format(time_left=formatted_time_left.rjust(width)) def get_width(self, progress_bar: ProgressBar) -> AnyDimension: all_values = [ @@ -307,7 +310,7 @@ class IterationsPerSecond(Formatter): Display the iterations per second. """ - template = ( + template = HTML( "<iterations-per-second>{iterations_per_second:.2f}</iterations-per-second>" ) @@ -318,7 +321,7 @@ class IterationsPerSecond(Formatter): width: int, ) -> AnyFormattedText: value = progress.items_completed / progress.time_elapsed.total_seconds() - return HTML(self.template.format(iterations_per_second=value)) + return self.template.format(iterations_per_second=value) def get_width(self, progress_bar: ProgressBar) -> AnyDimension: all_values = [ @@ -335,6 +338,7 @@ class SpinningWheel(Formatter): Display a spinning wheel. """ + template = HTML("<spinning-wheel>{0}</spinning-wheel>") characters = r"/-\|" def format( @@ -344,9 +348,7 @@ class SpinningWheel(Formatter): width: int, ) -> AnyFormattedText: index = int(time.time() * 3) % len(self.characters) - return HTML("<spinning-wheel>{0}</spinning-wheel>").format( - self.characters[index] - ) + return self.template.format(self.characters[index]) def get_width(self, progress_bar: ProgressBar) -> AnyDimension: return D.exact(1) diff --git a/src/prompt_toolkit/shortcuts/prompt.py b/src/prompt_toolkit/shortcuts/prompt.py index 7274b5f..115d890 100644 --- a/src/prompt_toolkit/shortcuts/prompt.py +++ b/src/prompt_toolkit/shortcuts/prompt.py @@ -24,6 +24,7 @@ Example:: s = PromptSession() result = s.prompt('Say something: ') """ + from __future__ import annotations from asyncio import get_running_loop diff --git a/src/prompt_toolkit/styles/__init__.py b/src/prompt_toolkit/styles/__init__.py index 23f61bb..39e97ca 100644 --- a/src/prompt_toolkit/styles/__init__.py +++ b/src/prompt_toolkit/styles/__init__.py @@ -1,6 +1,7 @@ """ Styling for prompt_toolkit applications. """ + from __future__ import annotations from .base import ( diff --git a/src/prompt_toolkit/styles/base.py b/src/prompt_toolkit/styles/base.py index b50f3b0..0657221 100644 --- a/src/prompt_toolkit/styles/base.py +++ b/src/prompt_toolkit/styles/base.py @@ -1,6 +1,7 @@ """ The base classes for the styling. """ + from __future__ import annotations from abc import ABCMeta, abstractmethod, abstractproperty diff --git a/src/prompt_toolkit/styles/defaults.py b/src/prompt_toolkit/styles/defaults.py index 75b8dd2..2faba94 100644 --- a/src/prompt_toolkit/styles/defaults.py +++ b/src/prompt_toolkit/styles/defaults.py @@ -1,6 +1,7 @@ """ The default styling. """ + from __future__ import annotations from prompt_toolkit.cache import memoized diff --git a/src/prompt_toolkit/styles/named_colors.py b/src/prompt_toolkit/styles/named_colors.py index 0395c8b..b6290a4 100644 --- a/src/prompt_toolkit/styles/named_colors.py +++ b/src/prompt_toolkit/styles/named_colors.py @@ -2,6 +2,7 @@ All modern web browsers support these 140 color names. Taken from: https://www.w3schools.com/colors/colors_names.asp """ + from __future__ import annotations __all__ = [ diff --git a/src/prompt_toolkit/styles/pygments.py b/src/prompt_toolkit/styles/pygments.py index 3e101f1..c0f6031 100644 --- a/src/prompt_toolkit/styles/pygments.py +++ b/src/prompt_toolkit/styles/pygments.py @@ -6,6 +6,7 @@ Usage:: from pygments.styles.tango import TangoStyle style = style_from_pygments_cls(pygments_style_cls=TangoStyle) """ + from __future__ import annotations from typing import TYPE_CHECKING diff --git a/src/prompt_toolkit/styles/style.py b/src/prompt_toolkit/styles/style.py index 1abee0f..fc8b31b 100644 --- a/src/prompt_toolkit/styles/style.py +++ b/src/prompt_toolkit/styles/style.py @@ -1,6 +1,7 @@ """ Tool for creating styles from a dictionary. """ + from __future__ import annotations import itertools @@ -72,7 +73,7 @@ def parse_color(text: str) -> str: elif text in ("", "default"): return text - raise ValueError("Wrong color format %r" % text) + raise ValueError(f"Wrong color format {text!r}") # Attributes, when they are not filled in by a style. None means that we take diff --git a/src/prompt_toolkit/styles/style_transformation.py b/src/prompt_toolkit/styles/style_transformation.py index fbb5a63..e8d5b0a 100644 --- a/src/prompt_toolkit/styles/style_transformation.py +++ b/src/prompt_toolkit/styles/style_transformation.py @@ -9,6 +9,7 @@ When the UI is rendered, these transformations can be applied right after the style strings are turned into `Attrs` objects that represent the actual formatting. """ + from __future__ import annotations from abc import ABCMeta, abstractmethod diff --git a/src/prompt_toolkit/token.py b/src/prompt_toolkit/token.py index a2c80e5..e97893d 100644 --- a/src/prompt_toolkit/token.py +++ b/src/prompt_toolkit/token.py @@ -1,5 +1,4 @@ -""" -""" +""" """ from __future__ import annotations diff --git a/src/prompt_toolkit/validation.py b/src/prompt_toolkit/validation.py index 127445e..2b35d1f 100644 --- a/src/prompt_toolkit/validation.py +++ b/src/prompt_toolkit/validation.py @@ -2,6 +2,7 @@ Input validation for a `Buffer`. (Validators will be called before accepting input.) """ + from __future__ import annotations from abc import ABCMeta, abstractmethod @@ -36,11 +37,7 @@ class ValidationError(Exception): self.message = message def __repr__(self) -> str: - return "{}(cursor_position={!r}, message={!r})".format( - self.__class__.__name__, - self.cursor_position, - self.message, - ) + return f"{self.__class__.__name__}(cursor_position={self.cursor_position!r}, message={self.message!r})" class Validator(metaclass=ABCMeta): diff --git a/src/prompt_toolkit/widgets/__init__.py b/src/prompt_toolkit/widgets/__init__.py index 9d1d4e3..53cc3e1 100644 --- a/src/prompt_toolkit/widgets/__init__.py +++ b/src/prompt_toolkit/widgets/__init__.py @@ -6,6 +6,7 @@ module. Most of these widgets implement the ``__pt_container__`` method, which makes it possible to embed these in the layout like any other container. """ + from __future__ import annotations from .base import ( diff --git a/src/prompt_toolkit/widgets/base.py b/src/prompt_toolkit/widgets/base.py index f36a545..709b7a9 100644 --- a/src/prompt_toolkit/widgets/base.py +++ b/src/prompt_toolkit/widgets/base.py @@ -12,6 +12,7 @@ container object. guarantees are made yet). The public API in `prompt_toolkit.shortcuts.dialogs` on the other hand is considered stable. """ + from __future__ import annotations from functools import partial diff --git a/src/prompt_toolkit/widgets/dialogs.py b/src/prompt_toolkit/widgets/dialogs.py index c47c15b..5f5f170 100644 --- a/src/prompt_toolkit/widgets/dialogs.py +++ b/src/prompt_toolkit/widgets/dialogs.py @@ -1,6 +1,7 @@ """ Collection of reusable components for building full screen applications. """ + from __future__ import annotations from typing import Sequence diff --git a/src/prompt_toolkit/widgets/toolbars.py b/src/prompt_toolkit/widgets/toolbars.py index deddf15..c5deffc 100644 --- a/src/prompt_toolkit/widgets/toolbars.py +++ b/src/prompt_toolkit/widgets/toolbars.py @@ -352,11 +352,7 @@ class ValidationToolbar: ) if show_position: - text = "{} (line={} column={})".format( - buff.validation_error.message, - row + 1, - column + 1, - ) + text = f"{buff.validation_error.message} (line={row + 1} column={column + 1})" else: text = buff.validation_error.message diff --git a/tests/test_cli.py b/tests/test_cli.py index 3a16e9f..c155325 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -2,6 +2,7 @@ These are almost end-to-end tests. They create a Prompt, feed it with some input and check the result. """ + from __future__ import annotations from functools import partial diff --git a/tests/test_print_formatted_text.py b/tests/test_print_formatted_text.py index 26c7265..7d0e99a 100644 --- a/tests/test_print_formatted_text.py +++ b/tests/test_print_formatted_text.py @@ -1,6 +1,7 @@ """ Test the `print` function. """ + from __future__ import annotations import pytest diff --git a/tests/test_regular_languages.py b/tests/test_regular_languages.py index deef6b8..3d55dbc 100644 --- a/tests/test_regular_languages.py +++ b/tests/test_regular_languages.py @@ -78,13 +78,13 @@ def test_prefix(): def test_completer(): class completer1(Completer): def get_completions(self, document, complete_event): - yield Completion("before-%s-after" % document.text, -len(document.text)) - yield Completion("before-%s-after-B" % document.text, -len(document.text)) + yield Completion(f"before-{document.text}-after", -len(document.text)) + yield Completion(f"before-{document.text}-after-B", -len(document.text)) class completer2(Completer): def get_completions(self, document, complete_event): - yield Completion("before2-%s-after2" % document.text, -len(document.text)) - yield Completion("before2-%s-after2-B" % document.text, -len(document.text)) + yield Completion(f"before2-{document.text}-after2", -len(document.text)) + yield Completion(f"before2-{document.text}-after2-B", -len(document.text)) # Create grammar. "var1" + "whitespace" + "var2" g = compile(r"(?P<var1>[a-z]*) \s+ (?P<var2>[a-z]*)") diff --git a/tools/debug_input_cross_platform.py b/tools/debug_input_cross_platform.py index 55f6190..d87cfcc 100755 --- a/tools/debug_input_cross_platform.py +++ b/tools/debug_input_cross_platform.py @@ -5,6 +5,7 @@ For testing terminal input. Works on both Windows and Posix. """ + import asyncio from prompt_toolkit.input import create_input diff --git a/tools/debug_vt100_input.py b/tools/debug_vt100_input.py index d3660b9..b74c06f 100755 --- a/tools/debug_vt100_input.py +++ b/tools/debug_vt100_input.py @@ -5,6 +5,7 @@ For testing terminal input. (This does not use the `Input` implementation, but only the `Vt100Parser`.) """ + import sys from prompt_toolkit.input.vt100 import raw_mode |