From f0d475e3b5d4f226d24837256efc697271b1c611 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 4 May 2024 19:36:10 +0200 Subject: Adding upstream version 3.0.22. Signed-off-by: Daniel Baumann --- examples/asyncio-python-embed.py | 56 +++++++ examples/asyncio-ssh-python-embed.py | 62 ++++++++ examples/ptpython_config/config.py | 203 ++++++++++++++++++++++++ examples/python-embed-with-custom-prompt.py | 38 +++++ examples/python-embed.py | 12 ++ examples/python-input.py | 15 ++ examples/ssh-and-telnet-embed.py | 49 ++++++ examples/test-cases/ptpython-in-other-thread.py | 24 +++ 8 files changed, 459 insertions(+) create mode 100755 examples/asyncio-python-embed.py create mode 100755 examples/asyncio-ssh-python-embed.py create mode 100644 examples/ptpython_config/config.py create mode 100755 examples/python-embed-with-custom-prompt.py create mode 100755 examples/python-embed.py create mode 100755 examples/python-input.py create mode 100755 examples/ssh-and-telnet-embed.py create mode 100644 examples/test-cases/ptpython-in-other-thread.py (limited to 'examples') diff --git a/examples/asyncio-python-embed.py b/examples/asyncio-python-embed.py new file mode 100755 index 0000000..05f52f1 --- /dev/null +++ b/examples/asyncio-python-embed.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python +""" +(Python >3.3) + +This is an example of how we can embed a Python REPL into an asyncio +application. In this example, we have one coroutine that runs in the +background, prints some output and alters a global state. The REPL, which runs +inside another coroutine can access and change this global state, interacting +with the running asyncio application. +The ``patch_stdout`` option makes sure that when another coroutine is writing +to stdout, it won't break the input line, but instead writes nicely above the +prompt. +""" +import asyncio + +from ptpython.repl import embed + +loop = asyncio.get_event_loop() +counter = [0] + + +async def print_counter(): + """ + Coroutine that prints counters and saves it in a global variable. + """ + while True: + print("Counter: %i" % counter[0]) + counter[0] += 1 + await asyncio.sleep(3) + + +async def interactive_shell(): + """ + Coroutine that starts a Python REPL from which we can access the global + counter variable. + """ + print( + 'You should be able to read and update the "counter[0]" variable from this shell.' + ) + try: + await embed(globals=globals(), return_asyncio_coroutine=True, patch_stdout=True) + except EOFError: + # Stop the loop when quitting the repl. (Ctrl-D press.) + loop.stop() + + +def main(): + asyncio.ensure_future(print_counter()) + asyncio.ensure_future(interactive_shell()) + + loop.run_forever() + loop.close() + + +if __name__ == "__main__": + main() diff --git a/examples/asyncio-ssh-python-embed.py b/examples/asyncio-ssh-python-embed.py new file mode 100755 index 0000000..86b5607 --- /dev/null +++ b/examples/asyncio-ssh-python-embed.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python +""" +Example of running the Python REPL through an SSH connection in an asyncio process. +This requires Python 3, asyncio and asyncssh. + +Run this example and then SSH to localhost, port 8222. +""" +import asyncio +import logging + +import asyncssh + +from ptpython.contrib.asyncssh_repl import ReplSSHServerSession + +logging.basicConfig() +logging.getLogger().setLevel(logging.INFO) + + +class MySSHServer(asyncssh.SSHServer): + """ + Server without authentication, running `ReplSSHServerSession`. + """ + + def __init__(self, get_namespace): + self.get_namespace = get_namespace + + def begin_auth(self, username): + # No authentication. + return False + + def session_requested(self): + return ReplSSHServerSession(self.get_namespace) + + +def main(port=8222): + """ + Example that starts the REPL through an SSH server. + """ + loop = asyncio.get_event_loop() + + # Namespace exposed in the REPL. + environ = {"hello": "world"} + + # Start SSH server. + def create_server(): + return MySSHServer(lambda: environ) + + print("Listening on :%i" % port) + print('To connect, do "ssh localhost -p %i"' % port) + + loop.run_until_complete( + asyncssh.create_server( + create_server, "", port, server_host_keys=["/etc/ssh/ssh_host_dsa_key"] + ) + ) + + # Run eventloop. + loop.run_forever() + + +if __name__ == "__main__": + main() diff --git a/examples/ptpython_config/config.py b/examples/ptpython_config/config.py new file mode 100644 index 0000000..bf9d05f --- /dev/null +++ b/examples/ptpython_config/config.py @@ -0,0 +1,203 @@ +""" +Configuration example for ``ptpython``. + +Copy this file to $XDG_CONFIG_HOME/ptpython/config.py +On Linux, this is: ~/.config/ptpython/config.py +""" +from prompt_toolkit.filters import ViInsertMode +from prompt_toolkit.key_binding.key_processor import KeyPress +from prompt_toolkit.keys import Keys +from prompt_toolkit.styles import Style + +from ptpython.layout import CompletionVisualisation + +__all__ = ["configure"] + + +def configure(repl): + """ + Configuration method. This is called during the start-up of ptpython. + + :param repl: `PythonRepl` instance. + """ + # Show function signature (bool). + repl.show_signature = True + + # Show docstring (bool). + repl.show_docstring = False + + # Show the "[Meta+Enter] Execute" message when pressing [Enter] only + # inserts a newline instead of executing the code. + repl.show_meta_enter_message = True + + # Show completions. (NONE, POP_UP, MULTI_COLUMN or TOOLBAR) + repl.completion_visualisation = CompletionVisualisation.POP_UP + + # When CompletionVisualisation.POP_UP has been chosen, use this + # scroll_offset in the completion menu. + repl.completion_menu_scroll_offset = 0 + + # Show line numbers (when the input contains multiple lines.) + repl.show_line_numbers = False + + # Show status bar. + repl.show_status_bar = True + + # When the sidebar is visible, also show the help text. + repl.show_sidebar_help = True + + # Swap light/dark colors on or off + repl.swap_light_and_dark = False + + # Highlight matching parethesis. + repl.highlight_matching_parenthesis = True + + # Line wrapping. (Instead of horizontal scrolling.) + repl.wrap_lines = True + + # Mouse support. + repl.enable_mouse_support = True + + # Complete while typing. (Don't require tab before the + # completion menu is shown.) + repl.complete_while_typing = True + + # Fuzzy and dictionary completion. + repl.enable_fuzzy_completion = False + repl.enable_dictionary_completion = False + + # Vi mode. + repl.vi_mode = False + + # Paste mode. (When True, don't insert whitespace after new line.) + repl.paste_mode = False + + # Use the classic prompt. (Display '>>>' instead of 'In [1]'.) + repl.prompt_style = "classic" # 'classic' or 'ipython' + + # Don't insert a blank line after the output. + repl.insert_blank_line_after_output = False + + # History Search. + # When True, going back in history will filter the history on the records + # starting with the current input. (Like readline.) + # Note: When enable, please disable the `complete_while_typing` option. + # otherwise, when there is a completion available, the arrows will + # browse through the available completions instead of the history. + repl.enable_history_search = False + + # Enable auto suggestions. (Pressing right arrow will complete the input, + # based on the history.) + repl.enable_auto_suggest = False + + # Enable open-in-editor. Pressing C-x C-e in emacs mode or 'v' in + # Vi navigation mode will open the input in the current editor. + repl.enable_open_in_editor = True + + # Enable system prompt. Pressing meta-! will display the system prompt. + # Also enables Control-Z suspend. + repl.enable_system_bindings = True + + # Ask for confirmation on exit. + repl.confirm_exit = True + + # Enable input validation. (Don't try to execute when the input contains + # syntax errors.) + repl.enable_input_validation = True + + # Use this colorscheme for the code. + # Ptpython uses Pygments for code styling, so you can choose from Pygments' + # color schemes. See: + # https://pygments.org/docs/styles/ + # https://pygments.org/demo/ + repl.use_code_colorscheme("default") + # A colorscheme that looks good on dark backgrounds is 'native': + # repl.use_code_colorscheme("native") + + # Set color depth (keep in mind that not all terminals support true color). + + # repl.color_depth = "DEPTH_1_BIT" # Monochrome. + # repl.color_depth = "DEPTH_4_BIT" # ANSI colors only. + repl.color_depth = "DEPTH_8_BIT" # The default, 256 colors. + # repl.color_depth = "DEPTH_24_BIT" # True color. + + # Min/max brightness + repl.min_brightness = 0.0 # Increase for dark terminal backgrounds. + repl.max_brightness = 1.0 # Decrease for light terminal backgrounds. + + # Syntax. + repl.enable_syntax_highlighting = True + + # Get into Vi navigation mode at startup + repl.vi_start_in_navigation_mode = False + + # Preserve last used Vi input mode between main loop iterations + repl.vi_keep_last_used_mode = False + + # Install custom colorscheme named 'my-colorscheme' and use it. + """ + repl.install_ui_colorscheme("my-colorscheme", Style.from_dict(_custom_ui_colorscheme)) + repl.use_ui_colorscheme("my-colorscheme") + """ + + # Add custom key binding for PDB. + """ + @repl.add_key_binding("c-b") + def _(event): + " Pressing Control-B will insert "pdb.set_trace()" " + event.cli.current_buffer.insert_text("\nimport pdb; pdb.set_trace()\n") + """ + + # Typing ControlE twice should also execute the current command. + # (Alternative for Meta-Enter.) + """ + @repl.add_key_binding("c-e", "c-e") + def _(event): + event.current_buffer.validate_and_handle() + """ + + # Typing 'jj' in Vi Insert mode, should send escape. (Go back to navigation + # mode.) + """ + @repl.add_key_binding("j", "j", filter=ViInsertMode()) + def _(event): + " Map 'jj' to Escape. " + event.cli.key_processor.feed(KeyPress(Keys("escape"))) + """ + + # Custom key binding for some simple autocorrection while typing. + """ + corrections = { + "impotr": "import", + "pritn": "print", + } + + @repl.add_key_binding(" ") + def _(event): + " When a space is pressed. Check & correct word before cursor. " + b = event.cli.current_buffer + w = b.document.get_word_before_cursor() + + if w is not None: + if w in corrections: + b.delete_before_cursor(count=len(w)) + b.insert_text(corrections[w]) + + b.insert_text(" ") + """ + + # Add a custom title to the status bar. This is useful when ptpython is + # embedded in other applications. + """ + repl.title = "My custom prompt." + """ + + +# Custom colorscheme for the UI. See `ptpython/layout.py` and +# `ptpython/style.py` for all possible tokens. +_custom_ui_colorscheme = { + # Blue prompt. + "prompt": "bg:#eeeeff #000000 bold", + # Make the status toolbar red. + "status-toolbar": "bg:#ff0000 #000000", +} diff --git a/examples/python-embed-with-custom-prompt.py b/examples/python-embed-with-custom-prompt.py new file mode 100755 index 0000000..968aedc --- /dev/null +++ b/examples/python-embed-with-custom-prompt.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python +""" +Example of embedding a Python REPL, and setting a custom prompt. +""" +from prompt_toolkit.formatted_text import HTML + +from ptpython.prompt_style import PromptStyle +from ptpython.repl import embed + + +def configure(repl): + # Probably, the best is to add a new PromptStyle to `all_prompt_styles` and + # activate it. This way, the other styles are still selectable from the + # menu. + class CustomPrompt(PromptStyle): + def in_prompt(self): + return HTML("Input[%s]: ") % ( + repl.current_statement_index, + ) + + def in2_prompt(self, width): + return "...: ".rjust(width) + + def out_prompt(self): + return HTML("Result[%s]: ") % ( + repl.current_statement_index, + ) + + repl.all_prompt_styles["custom"] = CustomPrompt() + repl.prompt_style = "custom" + + +def main(): + embed(globals(), locals(), configure=configure) + + +if __name__ == "__main__": + main() diff --git a/examples/python-embed.py b/examples/python-embed.py new file mode 100755 index 0000000..ac2cd06 --- /dev/null +++ b/examples/python-embed.py @@ -0,0 +1,12 @@ +#!/usr/bin/env python +""" +""" +from ptpython.repl import embed + + +def main(): + embed(globals(), locals(), vi_mode=False) + + +if __name__ == "__main__": + main() diff --git a/examples/python-input.py b/examples/python-input.py new file mode 100755 index 0000000..567c2ee --- /dev/null +++ b/examples/python-input.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python +""" +""" +from ptpython.python_input import PythonInput + + +def main(): + prompt = PythonInput() + + text = prompt.app.run() + print("You said: " + text) + + +if __name__ == "__main__": + main() diff --git a/examples/ssh-and-telnet-embed.py b/examples/ssh-and-telnet-embed.py new file mode 100755 index 0000000..378784c --- /dev/null +++ b/examples/ssh-and-telnet-embed.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python +""" +Serve a ptpython console using both telnet and ssh. + +Thanks to Vincent Michel for this! +https://gist.github.com/vxgmichel/7685685b3e5ead04ada4a3ba75a48eef +""" + +import asyncio +import pathlib + +import asyncssh +from prompt_toolkit import print_formatted_text +from prompt_toolkit.contrib.ssh.server import PromptToolkitSSHServer +from prompt_toolkit.contrib.telnet.server import TelnetServer + +from ptpython.repl import embed + + +def ensure_key(filename="ssh_host_key"): + path = pathlib.Path(filename) + if not path.exists(): + rsa_key = asyncssh.generate_private_key("ssh-rsa") + path.write_bytes(rsa_key.export_private_key()) + return str(path) + + +async def interact(connection=None): + global_dict = {**globals(), "print": print_formatted_text} + await embed(return_asyncio_coroutine=True, globals=global_dict) + + +async def main(ssh_port=8022, telnet_port=8023): + ssh_server = PromptToolkitSSHServer(interact=interact) + await asyncssh.create_server( + lambda: ssh_server, "", ssh_port, server_host_keys=[ensure_key()] + ) + print(f"Running ssh server on port {ssh_port}...") + + telnet_server = TelnetServer(interact=interact, port=telnet_port) + telnet_server.start() + print(f"Running telnet server on port {telnet_port}...") + + while True: + await asyncio.sleep(60) + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/examples/test-cases/ptpython-in-other-thread.py b/examples/test-cases/ptpython-in-other-thread.py new file mode 100644 index 0000000..7c78846 --- /dev/null +++ b/examples/test-cases/ptpython-in-other-thread.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python +""" +Example of running ptpython in another thread. + +(For testing whether it's working fine if it's not embedded in the main +thread.) +""" +import threading + +from ptpython.repl import embed + + +def in_thread(): + embed(globals(), locals(), vi_mode=False) + + +def main(): + th = threading.Thread(target=in_thread) + th.start() + th.join() + + +if __name__ == "__main__": + main() -- cgit v1.2.3