Skip to content

gh-157612: Strip prompts and output from pasted REPL sessions - #157615

Open
johnslavik wants to merge 4 commits into
python:mainfrom
johnslavik:gh-157612-strip-repl-prompts
Open

johnslavik wants to merge 4 commits into
python:mainfrom
johnslavik:gh-157612-strip-repl-prompts

Conversation

@johnslavik

@johnslavik johnslavik commented Sep 16, 2026 •

Copy link
Copy Markdown
Member

Copy a REPL example from a web page and paste it straight into the new REPL:

>>> def double(value):
...     return value * 2
...
>>> result = double(3)
>>> print(result)
6

At an empty >>> prompt, the REPL removes the copied prompts and output, leaving this code ready to edit:

def double(value):
    return value * 2

result = double(3)
print(result)

Indentation stays intact. Nothing runs on paste, so you can change double(3) to double(5) before running it.

This also makes it easier to send students examples or copy code between two REPLs to compare different parameters. You no longer need to delete prompts and output by hand.

The terminal must support bracketed paste, which tells the REPL where a paste starts and ends. The input must be empty, and the paste must start with a standard >>> prompt. Pasting into existing code, a string, or an input() prompt keeps the text unchanged.

Rough edges

As discussed in the issue, this only recognizes >>> and ..., since those are the prompts most web examples use. Output that looks like a prompted code line will also be kept as code.

The pasted code runs as one block, so it can behave differently from entering each command separately. The issue notes differences involving sys.displayhook and builtins._.

Tests cover prompt and output removal, different line endings, pastes that should stay unchanged, and editing before running.

@read-the-docs-community

read-the-docs-community Bot commented Sep 16, 2026 •

Copy link
Copy Markdown

@edvilme edvilme left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should also consider cases in which the prompts have been changed. I think these would be few but still ?

E.g., (not endorsing changing the prompt, but something that could happen, especially in other tools modifying the REPL)

>>> import sys
>>> sys.ps1 = "py> "
py> # This is code I want to copy and paste later
py> class A(object):
...     def __new__(self):
...         raise TypeError("i do not exist")
...
py> class B(A):
...     __new__ = object.__new__
...     def __init__(self, x):
...         self.x = x
...
py> B(1)

Comment thread Lib/_pyrepl/commands.py Outdated
Comment thread Lib/_pyrepl/commands.py Outdated
@johnslavik

johnslavik commented Sep 16, 2026 •

Copy link
Copy Markdown
Member Author

We could, but I find that limiting this to >>> and ... only makes this feature simpler and easier to predict.

Do you personally customize your PS1 and would need that in this feature?

@edvilme

edvilme commented Sep 16, 2026 •

Copy link
Copy Markdown
Contributor

Not explicitly but it is documented behavior on the tutorial.
However, I was thinking more of tools/IDEs modifying PYTHONSTARTUP to alter the behavior of the REPL (VSCode does it -- although mostly to insert ANSI characters; but there could be other tools that do change it completely)

@johnslavik

johnslavik commented Sep 16, 2026 •

Copy link
Copy Markdown
Member Author

However, I was thinking more of tools/IDEs modifying PYTHONSTARTUP to alter the behavior of the REPL (VSCode does it -- although mostly to insert ANSI characters; but there could be other tools that do change it completely)

  1. VS Code uses >>>. We already match >>>. Seems to me that matching against sys.ps1 doesn't solve anything here.

  2. Your second suggestion would raise a TypeError under the VS Code terminal with patched sys.ps11, since VS Code sets sys.ps1 to a non-str object, which by the way floods the terminal, preventing the 3.15.rc2+ REPL from starting in the first place:

    Screen.Recording.2026-09-16.at.23.28.48.mov

    Consequently, your first suggestion would never match under the VS Code terminal with patched sys.ps1.

although mostly to insert ANSI characters

Would a user paste something that contains ANSI sequences?

I was thinking more of tools/IDEs modifying PYTHONSTARTUP to alter the behavior of the REPL

What tools or IDEs modify sys.ps1 to something other than >>>? How would following their specific behaviors benefit this feature in CPython?

Footnotes

  1. Assuming the bug that follows (that prevents the REPL from starting in the first place) is fixed. ↩

@johnslavik

johnslavik commented Sep 16, 2026 •

Copy link
Copy Markdown
Member Author

Please also note that sys.ps1 can have leading lines which would make it more complicated to match. I'd really stick only with >>> and ... for now.

@edvilme

edvilme commented Sep 16, 2026

Copy link
Copy Markdown
Contributor

Oh you are right, didn't consider the case for it not being a string :)

Comment thread Lib/test/test_pyrepl/test_pyrepl.py Outdated
Comment thread Lib/_pyrepl/commands.py Outdated
@bedevere-app bedevere-app Bot added the type-feature A feature request or enhancement label Oct 19, 2026
@github-project-automation github-project-automation Bot moved this to Todo in Sprint Oct 20, 2026
@ambv

ambv commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

There's a few edge cases here that I don't like around how the thing that actually executes is not the thing that the person pasting the snippet expects:

  1. Copying between two new REPLs (the PR's stated use case) can silently change code. When an input line is wider than the terminal, pyrepl draws a \ in the last column and continues on a new row with no prompt. Raw pty bytes plus a real terminal emulator (WezTerm) confirm that terminals copy that row as a separate line. The PR drops the row, and the leftover \ joins the line onto the next statement. Most wrapped pastes end in a visible SyntaxError instead. The silent cases are mainly long list or string literals, which is arguably worse.

  2. Lines abandoned with Ctrl-C get run. Both REPLs leave an abandoned line on screen with its prompt, followed by KeyboardInterrupt. The PR keeps the line and drops the KeyboardInterrupt as output, so code the user chose not to run now runs.

>>> x = 1
>>> x = 2
KeyboardInterrupt
>>> x
1
  1. Replay stops at the first exception, and the traceback hides it. On Enter, pyrepl runs the whole buffer as one input and stops at the first statement that raises (Lib/_pyrepl/console.py). Many docs and tutorial sessions deliberately show an error and then continue. The printed traceback is the one the session already shows, so the skipped statements go unnoticed.

    • The PR's own test case (1 / 0, then print('hello')) never prints hello. The tests only
      check the edit buffer, never what runs.
    • In the tutorial dict session (datastructures.rst:576), the 8 statements after the KeyError are skipped and tel ends up wrong.
    • About 59 doc blocks have this shape.
  2. The strip also runs at the (Pdb) prompt (a regression and outside the documented scope). PdbPyReplInput also sets more_lines, so the PR's more_lines is not None check doesn't exclude pdb. There's some plausible conflicts with the Pdb command grammar here:

    • q = …, quit = … or exit = … as the first statement quits pdb and ends the program. Under python -m pdb the process just exits with no confirmation.
    • run = … / restart = … restart the program with sys.argv set to ['=', …].
    • A one-line paste of >>> c continues the program.
    • Baseline gives a harmless *** SyntaxError.
    • pdb's command dispatch is old behaviour; the PR just makes a pasted session reach it.

There's more cases that are less concerning, but the state above makes me think that maybe this convenience is not worth it by default.

A plausible way out would be to discover the paste of a console session, and attach more info to the SyntaxError raised that would tell the user "To use Paste Mode (F3) to automatically strip >>> and ...". We would also need to address the backslash-wrapped lines handling, and at least document the exception handling difference.

@johnslavik
johnslavik force-pushed the gh-157612-strip-repl-prompts branch from 132cd49 to 68f0d6a Compare October 21, 2026 00:26
@johnslavik

Copy link
Copy Markdown
Member Author

1 - fixed, 2 - KeyboardInterrupt prompts are stripped out, 3 - implemented the new flow with error overlays, 4 - feature no longer works in pdb.

@ambv ambv left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the current PR, generic commands know about ReadlineAlikeReader.paste_repl_sessions and can_strip_repl_prompts, and that reader imports Python-session parsing helpers from commands.py. The responsibility is split across both layers. I’d use the existing command registry to install reader-specific paste commands. ReadlineAlikeReader.post_init() already does this for maybe_accept and backspace_dedent.

Keep bracketed-paste collection generic. Then, specialise it in readline.py (specialise the F3 command there too). Finally, register both specializations in ReadlineAlikeReader.post_init().

@github-project-automation github-project-automation Bot moved this from Todo to In Progress in Sprint Oct 21, 2026
@bedevere-app

bedevere-app Bot commented Oct 21, 2026

Copy link
Copy Markdown

A Python core developer has requested some changes be made to your pull request before we can consider merging it. If you could please address their requests along with any other requests in other reviews from core developers that would be appreciated.

Once you have made the requested changes, please leave a comment on this pull request containing the phrase I have made the requested changes; please review again. I will then notify any core developers who have left a review that you're ready for them to take another look at this pull request.

@johnslavik

Copy link
Copy Markdown
Member Author

✨ I have made the requested changes; please review again ✨

@bedevere-app

bedevere-app Bot commented Oct 21, 2026

Copy link
Copy Markdown

Thanks for making the requested changes!

@ambv: please review the changes made to this pull request.

@bedevere-app
bedevere-app Bot requested a review from ambv October 21, 2026 22:13
@johnslavik
johnslavik force-pushed the gh-157612-strip-repl-prompts branch 2 times, most recently from d9f9dc6 to 1b51aea Compare October 21, 2026 22:23
@johnslavik

Copy link
Copy Markdown
Member Author

Merging main to fix a flake.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

awaiting change review sprint type-feature A feature request or enhancement

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

5 participants