Library for building powerful interactive command line applications in Python

Overview

Python Prompt Toolkit

Build Status AppVeyor Latest Version RTD License Codecov

https://github.com/prompt-toolkit/python-prompt-toolkit/raw/master/docs/images/logo_400px.png

prompt_toolkit is a library for building powerful interactive command line applications in Python.

Read the documentation on readthedocs.

NOTICE: prompt_toolkit 3.0

Please notice that this branch is the prompt_toolkit 3.0 branch. For most users, it should be compatible with prompt_toolkit 2.0, but it requires at least Python 3.6. On the plus side, prompt_toolkit 3.0 is completely type annotated and uses asyncio natively.

Gallery

ptpython is an interactive Python Shell, build on top of prompt_toolkit.

https://github.com/prompt-toolkit/python-prompt-toolkit/raw/master/docs/images/ptpython.png

More examples

prompt_toolkit features

prompt_toolkit could be a replacement for GNU readline, but it can be much more than that.

Some features:

  • Pure Python.
  • Syntax highlighting of the input while typing. (For instance, with a Pygments lexer.)
  • Multi-line input editing.
  • Advanced code completion.
  • Both Emacs and Vi key bindings. (Similar to readline.)
  • Even some advanced Vi functionality, like named registers and digraphs.
  • Reverse and forward incremental search.
  • Works well with Unicode double width characters. (Chinese input.)
  • Selecting text for copy/paste. (Both Emacs and Vi style.)
  • Support for bracketed paste.
  • Mouse support for cursor positioning and scrolling.
  • Auto suggestions. (Like fish shell.)
  • Multiple input buffers.
  • No global state.
  • Lightweight, the only dependencies are Pygments and wcwidth.
  • Runs on Linux, OS X, FreeBSD, OpenBSD and Windows systems.
  • And much more...

Feel free to create tickets for bugs and feature requests, and create pull requests if you have nice patches that you would like to share with others.

Installation

pip install prompt_toolkit

For Conda, do:

conda install -c https://conda.anaconda.org/conda-forge prompt_toolkit

About Windows support

prompt_toolkit is cross platform, and everything that you build on top should run fine on both Unix and Windows systems. Windows support is best on recent Windows 10 builds, for which the command line window supports vt100 escape sequences. (If not supported, we fall back to using Win32 APIs for color and cursor movements).

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 or conemu.

Getting started

The most simple example of the library would look like this:

from prompt_toolkit import prompt

if __name__ == '__main__':
    answer = prompt('Give me some input: ')
    print('You said: %s' % answer)

For more complex examples, have a look in the examples directory. All examples are chosen to demonstrate only one thing. Also, don't be afraid to look at the source code. The implementation of the prompt function could be a good start.

Philosophy

The source code of prompt_toolkit should be readable, concise and efficient. We prefer short functions focusing each on one task and for which the input and output types are clearly specified. We mostly prefer composition over inheritance, because inheritance can result in too much functionality in the same object. We prefer immutable objects where possible (objects don't change after initialization). Reusability is important. We absolutely refrain from having a changing global state, it should be possible to have multiple independent instances of the same code in the same process. The architecture should be layered: the lower levels operate on primitive operations and data structures giving -- when correctly combined -- all the possible flexibility; while at the higher level, there should be a simpler API, ready-to-use and sufficient for most use cases. Thinking about algorithms and efficiency is important, but avoid premature optimization.

Projects using prompt_toolkit

Special thanks to

  • Pygments: Syntax highlighter.
  • wcwidth: Determine columns needed for a wide characters.
Comments
  • Question: rename prompt_toolkit to prompt_toolkit2 or not?  (during a transition period).

    Question: rename prompt_toolkit to prompt_toolkit2 or not? (during a transition period).

    Hi everyone,

    I'm opening this issue to discuss whether or not we should rename prompt_toolkit to prompt_toolkit2.

    The problem that we are facing right now is that we want to release version 2.0, but it's backwards incompatible with 1.0. This would normally not be an issue, because the best practices tell you to install Python applications in a virtualenv. However, most prompt_toolkit applications are system tools, which are often installed with the system wide Python installation, and very often these are distributed through other channels like the repositories of Linux distributions. We don't want to break those.

    As I understand it, setuptools can install multiple versions of a package alongside each other. There is a __requires__ variable that is inspected by pkg_resources to make sure the right version of the package is loaded. (See, e.g.: https://stackoverflow.com/questions/13720065/what-does-requires-mean-in-python ). However, I'm not sure how well this works in practice.

    While I don't like it, if renaming this library to prompt_toolkit2 during a transition period is the only way to solve certain issues, then I'm in favor of doing it. The intend is to rename it back to prompt_toolkit when most applications are transitioned. (At that point, prompt_toolkit2 could remain an alias for prompt_toolkit.)

    I don't have much personal experience with issues like this, so all feedback is welcome.

    question 
    opened by jonathanslenders 30
  • customize amount of reserved space

    customize amount of reserved space

    Hi! It seems like using prompt-toolkit with xonsh reserves 8 lines at the bottom minimum. See https://github.com/jonathanslenders/python-prompt-toolkit/blob/9e96e1bf815b07edb5c266bf2ba9ae1d6e350746/prompt_toolkit/shortcuts.py#L232-L238 This is far too large to be usable for me. Is there any way that this could be customizable in some way? I'd really appreciate it...

    See the xonsh list for more discussion: https://groups.google.com/d/topic/xonsh/Y3L9GAcFwGM/discussion

    enhancement 
    opened by scopatz 17
  • Patched stdout does not allow ANSI escape codes

    Patched stdout does not allow ANSI escape codes

    Due to this line, ANSI escape codes are mangled and cannot be used by an application that also uses the patched stdout functionality. I was going to colorize messages from logging in my program with a formatter, but because of this it's not possible. I'm not even sure what the intent was here?

    https://github.com/jonathanslenders/python-prompt-toolkit/blame/master/prompt_toolkit/terminal/vt100_output.py#L184

    To not sound like a total downer, this module is super amazing and is really damn useful.

    bug 
    opened by trap15 17
  • Adding support for selecting text with shift + movement

    Adding support for selecting text with shift + movement

    This is a proposal for an implementation of text selection using shift + cursor movement as is customary in many GUI. This refers to issue #979.

    The implementation is based on defining a new boolean flag shift_mode in the SelectionState class. shift_mode is initialized to False by the class constructor and set to True by a call to SelectionState. enter_shift_mode() whenever a shift+movement binding is called to start selecting text in this fashion. There is an associated new shift_selection_mode filter. The advantage of proceeding this way are that

    1. the shift_mode flag is automatically destroyed when selection is exited by any means through any other bindings (because the SelectionState instance is destroyed). In that way, we are sure that the shift_mode flag will not persist to True by accident.
    2. it enables the shift-selection mode to co-exist for example with the Emacs marking mode (entered with ctrl-space). In principle, it could also co-exist with the vi-mode, but I haven't tested that as I am really not familiar with vi - so at the moment the corresponding binding definitions are only defined alongside the Emacs bindings, though they could in principle be defined with the basics bindings with some extra testing and tweaks.

    Behavior:

    • Shift + any cursor motion starts or extend the selection, accompanied by the corresponding cursor movement.
    • A cursor movement without shift will exit the selection (and moves the cursor).
    • The selection is replaced by any text that is typed (including enter, if multiline; backspace, which deletes the selection; and pasting/yanking - note: more tests might be needed here especially with regard to multiline paste).

    Cursor movements above refers to left, right, up, down, home & end (beginning & end of line), ctrl-left/right (word-by-word), ctrl-home/end (beginning/end of buffer). All missing shift- combinations of these keys have been added to keys.py (and set by default to do nothing in bindings/basic.py). Ctrl-home/end have also been added, with the corresponding commands implemented as new readline-style commands in named_commands.py. For completeness, ctrl/shift-insert keys have also been added as these are sometimes used for copy/paste. All these new key combinations are correctly converted to key-presses in input/win32.py.

    I have tested this implementation stand-alone as well as in IPython 7.6.1 (through applying the same changes to prompt_toolkit 2.0.9 - apart from removing the type hints). Everything seems to work well, without any changes required to the IPython source code itself.

    Happy to get some feedback at this stage, of what could be improved or done differently. I will continue to do more testing with multiline pasting in the meantime.

    opened by scoennz 16
  • Integration of finalterm/iterm2 escape sequences for shell integration.

    Integration of finalterm/iterm2 escape sequences for shell integration.

    Have a look at following escape sequences: before_prompt, after_prompt, before_output, after_output:

    https://groups.google.com/forum/#!msg/iterm2-discuss/URKCBtS0228/rs5Ive4PCAAJ https://iterm2.com/shell_integration.html https://github.com/asmeurer/iterm2-tools/blob/master/iterm2_tools/shell_integration.py

    See: https://github.com/ipython/ipython/issues/8724

    enhancement 
    opened by jonathanslenders 15
  • Actually use IPython input transformer to get correct syntax

    Actually use IPython input transformer to get correct syntax

    This uses IPython input transformer to detect if the syntax is correct IPython.

    Things that are invalid IPython do not go through : 1 ! 1 do not validate; a =! ls still does. ?,??do validate; not ???. And so on and so forth.

    opened by Carreau 15
  • ThreadedHistory: invoke history load callback on event loop

    ThreadedHistory: invoke history load callback on event loop

    Successor to #1159, but with a nice, compact commit history. Here is the original description:

    Fixes issue #1158, and seems to work in Xonsh as well.

    Depends on ThreadedHistory and Application being able to rendezvous on same event loop. While this may not be possible for history in general, I think it is an acceptable restriction on ThreadedHistory.

    bug 
    opened by bobhy 14
  • win32 console debug

    win32 console debug

    Debugging applications on windows under a debugger/ide can be difficult because the IDE may use its own 'console' which Prompt Toolkit is unable to use productively. This PR makes it possible to set an environment variable which allows Prompt Toolkit to create a console window and attach the appropriate handles to allow the program to use the console productively.

    enhancement 
    opened by stephenrauch 14
  • Allow ansi color name in Pygments style.

    Allow ansi color name in Pygments style.

    Hey,

    I know that currently you can use vt100 to get GREN/BLUE ... etc, though if you create your own style that should work with pygments, it wont be accepted as these string won't be detected as correct colors.

    Pygments recently added the ability to do that, except the names are slightly different, so this (once finished) should allow to have themes that works correctly with both Pygments 2.2+ and Prompt Toolkit and get the correct ansi escape sequences.

    opened by Carreau 14
  • Terminal windows exits on Windows 10 build 17692

    Terminal windows exits on Windows 10 build 17692

    I am having problems with prompt-toolkit 1 after getting the newest update to Windows (Insiders slow ring build 17692).

    Both xonsh (#2703) and ptpython with ptk1 causes the terminal window to exit when I start the programs. No error messages or anything. The conhost terminal window just disappears.

    I haven't tried to debug this yet, to see when it happens. But I will try it this weekend.

    I would really love to see if this is a problem with PTK 2 as well. Is there any application I could try to test that?

    test

    opened by melund 13
  • Copy/pasting: multiline in a single line prompt

    Copy/pasting: multiline in a single line prompt

    Could we have an option so that prompt only accepts a single line, even when pasting some text ?

    Currently, even when multiline is set to False, you can paste multi-line text in it.

    Code: Here's the code i am using:

    PROMPT_TOOLKIT_HISTORY = prompt_toolkit.history.FileHistory(conf.histfile)
    # ScapyCompleter is a quite basic completer, returning all matching content as a shell would do
    _completer = ScapyCompleter()
    from prompt_toolkit.token import Token
    prompts_style = prompt_toolkit.styles.style_from_dict({
        Token.Prompt: "#2E64FE",
    })
    def readLineScapy(prompt):
        result = ""
        end = False
        while not end :
            if not end and result != "":
                line = prompt_toolkit.prompt(u"... ", completer=_completer, history=PROMPT_TOOLKIT_HISTORY)
            else:
                line = prompt_toolkit.prompt(u">>> ", completer=_completer, style=prompts_style, history=PROMPT_TOOLKIT_HISTORY)
            if line.strip()[-1:] in [":", "(", ",", "\\"]:
                end = False
            elif result == "":
                end = True
            if line.strip() == "":
                end = True
            result = result + "\n" + line
        result = result.replace("\\\n", "")
        return str(result)
    # Run console with python_toolkit
    code.interact(banner="hello, this is a great shell", readfunc=readLineScapy)
    

    The goal of this code is to emulate a shell. In that way, we need to print "..." or ">>>" on each line. readlinescapy is using prompt_toolkit.prompt to get the same input as in a shell...

    When one copy multi-line, the prompt function takes all the lines, so ... is not printed.

    opened by gpotter2 11
  • filedescriptor still out of range in select

    filedescriptor still out of range in select

    Hi, I'm still having some problems with select.select raising an exception "ValueError: filedescriptor out of range in select()" in src/prompt_toolkit/input/posix_utils.py", line 72 if the file descriptor number is too large (>1023). This happens when passing in a pipe instead of stdin during testing. It seems to be similar to problems that were already discussed in #354.

    What makes this especially problematic is that the exception occurs inside the prompt loop which results in the prompt (and pytest) hanging indefinitely. A simple test to reproduce the problem:

    import os
    from typing import NamedTuple
    
    import pytest
    
    from prompt_toolkit import PromptSession
    from prompt_toolkit.input import create_pipe_input
    from prompt_toolkit.input.base import PipeInput
    from prompt_toolkit.output import DummyOutput
    
    
    @pytest.fixture
    def prompt():
        file_descriptors = []
        try:  # if an "OSError: Too many open files" is thrown, you may need to adjust the fp limit (`ulimit -n`)
            for _ in range(512):  # this should be enough to create a file descriptor > 1023
                read_fd, write_fd = os.pipe()
                file_descriptors.extend([read_fd, write_fd])
            with create_pipe_input() as input_:
                session = PromptSession(input=input_, output=DummyOutput())
                yield Prompt(session, input_)
        finally:
            for fd in file_descriptors:
                os.close(fd)
    
    
    class Prompt(NamedTuple):
        session: PromptSession
        input: PipeInput
    
    
    def test_too_many_open_files(prompt):
        prompt.input.send_text(f"foobar\n")
        # the prompt will hang if `select.select` is used because it causes an exception "filedescriptor out of range"
        prompt.session.prompt("foobar")
    

    As discussed in #354, it is possible to easily fix this by replacing select.select with select.poll. I have added a patch which seemingly fixes this: select_poll_patch.txt

    opened by jstucke 0
  • Allow nested scrolling of Windows

    Allow nested scrolling of Windows

    These changes mean that Windows will return NotImplemented when attempting to scroll beyond their scrollable limits.

    This means mouse scroll events can bubble up to a scrollable parent container when a window has finished scrolling.

    In the following screen recording, you can see that when the TextArea is moves under the mouse while scrolling the parent pane, it begins scrolling, and when the TextArea has scrolled all the way to the bottom, the parent pane resumes scrolling:

    nested-scrolling.webm

    I've also changed the reported line-count of the DummyControl to 1 rather than 100*100 for this to work. Without this, Windows without content believe their DummyControl is always scrollable and accept all scroll events. I can't find any issues with doing this - why was the DummyControl's content's line count set to 100*100?

    opened by joouha 0
  • Typo in -> is

    Typo in -> is

    Hey man, i found a typo in one of the library files

    file has "is_windows", "is_windows_vt100_supported", "is_conemu_ansi" and "in_main_thread" i believe that this should be "is_main_thread".

    version: 3.0.36 file: utils.py line: 214

    opened by isecvirus 0
  • Pass current prompt value to bottom toolbar callback

    Pass current prompt value to bottom toolbar callback

    I'd like to display the result of parsing a date to the user in real time as they type it. It would be nice to be able to do this using the bottom_toolbar parameter to prompt, but as far as I can tell the callable specified in bottom_toolbar is not passed the current value. Is it possible to pass the current value entered into the prompt to some sort of callback that can update the screen?

    opened by SeanDS 0
  • Why does my prompt-toolkit Dialog flicker on terminal output with asyncio and patch_stout?

    Why does my prompt-toolkit Dialog flicker on terminal output with asyncio and patch_stout?

    When running a prompt-toolkit Dialog it will flicker if there is terminal output from a different asyncio task.

    I am using the context with patch_stdout() within a task as mentioned in the doc, at least as far as I understand it. I read somewhere that starting with prompt-toolkit 3.0 it uses the default asyncio event loop and does not create one itself.

    And since asyncio.run always creates a new event loop and closes it at the end and the context manager is within that, I have no clue what could be the reason for the flickering. What am I missing?

    (Python 3.9, prompt-toolkit 3.0.36)

    This is a MCVE:

    import asyncio
    from prompt_toolkit.patch_stdout import patch_stdout
    from prompt_toolkit.shortcuts.dialogs import _create_app, _return_none
    from prompt_toolkit.widgets import Button, Dialog, Label
    
    dialog_align = Dialog(
        title='Please align',
        body=Label(text="init", dont_extend_height=True),
        buttons=[Button(text='Start measurement', width=21, handler=_return_none)],
        with_background=True,
    )
    
    async def prompt_align():
    
        return await _create_app(dialog_align, style=None).run_async()
    
    
    async def main_datasource():
    
        while True:
            await asyncio.sleep(0.5)
            print("test")
    
    
    async def main():
    
        with patch_stdout():
    
            task1 = asyncio.create_task(prompt_align())
            task2 = asyncio.create_task(main_datasource())
    
            await asyncio.gather(task1, task2)
    
    
    if __name__ == "__main__":
    
        try:
            from asyncio import run
        except ImportError:
            asyncio.run_until_complete(main())
        else:
            
            asyncio.run(main())
    
    opened by harrandt 0
  • Fix currentThread() deprecation warning

    Fix currentThread() deprecation warning

    DeprecationWarning: currentThread() is deprecated, use current_thread() instead

    No change in functionality, just noticed the warning while testing a third-party package.

    opened by smuth4 0
Owner
prompt-toolkit
Tools for building command line applications in Python
prompt-toolkit
Python Fire is a library for automatically generating command line interfaces (CLIs) from absolutely any Python object.

Python Fire Python Fire is a library for automatically generating command line interfaces (CLIs) from absolutely any Python object. Python Fire is a s

Google 23.6k Dec 31, 2022
Python composable command line interface toolkit

$ click_ Click is a Python package for creating beautiful command line interfaces in a composable way with as little code as necessary. It's the "Comm

The Pallets Projects 13.3k Dec 31, 2022
Python Command-line Application Tools

Clint: Python Command-line Interface Tools Clint is a module filled with a set of awesome tools for developing commandline applications. C ommand L in

Kenneth Reitz Archive 82 Dec 28, 2022
Corgy allows you to create a command line interface in Python, without worrying about boilerplate code

corgy Elegant command line parsing for Python. Corgy allows you to create a command line interface in Python, without worrying about boilerplate code.

Jayanth Koushik 7 Nov 17, 2022
Command line animations based on the state of the system

shell-emotions Command line animations based on the state of the system for Linux or Windows 10 The ascii animations were created using a modified ver

Simon Malave 63 Nov 12, 2022
Cleo allows you to create beautiful and testable command-line interfaces.

Cleo Create beautiful and testable command-line interfaces. Cleo is mostly a higher level wrapper for CliKit, so a lot of the components and utilities

Sébastien Eustace 984 Jan 2, 2023
Color text streams with a polished command line interface

colout(1) -- Color Up Arbitrary Command Output Synopsis colout [-h] [-r RESOURCE] colout [-g] [-c] [-l min,max] [-a] [-t] [-T DIR] [-P DIR] [-d COLORM

nojhan 1.1k Dec 21, 2022
Pythonic command line arguments parser, that will make you smile

docopt creates beautiful command-line interfaces Video introduction to docopt: PyCon UK 2012: Create *beautiful* command-line interfaces with Python N

null 7.7k Dec 30, 2022
A CLI tool to build beautiful command-line interfaces with type validation.

Piou A CLI tool to build beautiful command-line interfaces with type validation. It is as simple as from piou import Cli, Option cli = Cli(descriptio

Julien Brayere 310 Dec 7, 2022
A minimal and ridiculously good looking command-line-interface toolkit

Proper CLI Proper CLI is a Python package for creating beautiful, composable, and ridiculously good looking command-line-user-interfaces without havin

Juan-Pablo Scaletti 2 Dec 22, 2022
Clint is a module filled with a set of awesome tools for developing commandline applications.

Clint: Python Command-line Interface Tools Clint is a module filled with a set of awesome tools for developing commandline applications. C ommand L in

Kenneth Reitz Archive 82 Dec 28, 2022
sane is a command runner made simple.

sane is a command runner made simple.

Miguel M. 22 Jan 3, 2023
Rich is a Python library for rich text and beautiful formatting in the terminal.

Rich 中文 readme • lengua española readme • Läs på svenska Rich is a Python library for rich text and beautiful formatting in the terminal. The Rich API

Will McGugan 41.4k Jan 2, 2023
Python library that measures the width of unicode strings rendered to a terminal

Introduction This library is mainly for CLI programs that carefully produce output for Terminals, or make pretend to be an emulator. Problem Statement

Jeff Quast 305 Dec 25, 2022
Terminalcmd - a Python library which can help you to make your own terminal program with high-intellegence instruments

Terminalcmd - a Python library which can help you to make your own terminal program with high-intellegence instruments, that will make your code clear and readable.

Dallas 0 Jun 19, 2022
A simple terminal Christmas tree made with Python

Python Christmas Tree A simple CLI Christmas tree made with Python Installation Just clone the repository and run $ python terminal_tree.py More opti

Francisco B. 64 Dec 27, 2022
Simple cross-platform colored terminal text in Python

Colorama Makes ANSI escape character sequences (for producing colored terminal text and cursor positioning) work under MS Windows. PyPI for releases |

Jonathan Hartley 3k Jan 1, 2023
emoji terminal output for Python

Emoji Emoji for Python. This project was inspired by kyokomi. Example The entire set of Emoji codes as defined by the unicode consortium is supported

Taehoon Kim 1.6k Jan 2, 2023
Python and tab completion, better together.

argcomplete - Bash tab completion for argparse Tab complete all the things! Argcomplete provides easy, extensible command line tab completion of argum

Andrey Kislyuk 1.1k Jan 8, 2023