Skip to content

PyREPL: Send PS1 as string - #26197

Merged
Eduardo Villalpando Mello (edvilme) merged 1 commit into
mainfrom
pyrepl-str
Oct 5, 2026
Merged

Eduardo Villalpando Mello (edvilme) merged 1 commit into
mainfrom
pyrepl-str

Conversation

@edvilme

@edvilme Eduardo Villalpando Mello (edvilme) commented Oct 5, 2026 •

Copy link
Copy Markdown

Fixes #25467

Improve the integration of prompt handling in the REPL, ensuring that prompts are always passed as strings to _pyrepl.simple_interact.multiline_input

This makes sure that PS1 is converted to string even in python versions without the fix (e.g., 3.15.0r2 - 3.15.0)

Testing

  • Adds a new test test_pyrepl_multiline_input_converts_prompts_to_strings in python_files/tests/test_shell_integration.py to verify that the patched multiline_input function correctly converts prompt arguments to strings before calling the original function.

@edvilme Eduardo Villalpando Mello (edvilme) added the bug Issue identified by VS Code Team member as probable bug label Oct 5, 2026
@rchiodo

Rich Chiodo (rchiodo) commented Oct 5, 2026 •

Copy link
Copy Markdown

🔒 Automated review in progress — Rich Chiodo (@rchiodo) is auto-reviewing this PR.

@rchiodo

Copy link
Copy Markdown

Result: ⚠️ partially-verified

Verification details

Verification: Isolated verification observed failures that were not classified as caused by this PR: Wrapper idempotence and startup-global smoke checks.

Summary: On Python 3.13.16, the targeted shell-integration file reported **11 passed**, including the PR’s new prompt-conversion test. Additional checks confirmed idempotent wrapping, single prompt conversions, and Python 3.11 compatibility. An actual-PS1 smoke check failed because this environment runs under WSL, where pythonrc deliberately suppresses sys.ps1; existing prompt-rendering tests also return early there. Verification is partial, with no observed PR-caused failure.

Test runs: 3 passed, 1 failed

  • ❌ Failed | unrelated to this PR | Wrapper idempotence and startup-global smoke checks | python - <<'PY'
    import importlib
    import sys
    from pathlib import Path
    from unittest.mock import patch
    import _pyrepl.simple_interact as interact
    import pythonrc

calls = []
result = object()
more_lines = object()
def original(more, ps1, ps2):
assert more is more_lines
assert isinstance(ps1, str) and isinstance(ps2, str)
calls.append((ps1, ps2))
return result

class Prompt:
def init(self, text):
self.text = text
self.conversions = 0
def str(self):
self.conversions += 1
return self.text

with patch.object(interact, 'multiline_input', original):
importlib.reload(pythonrc)
wrapped = interact.multiline_input
assert wrapped._vscode_prompts_as_strings is True
importlib.reload(pythonrc)
assert interact.multiline_input is wrapped
primary, secondary = Prompt('primary'), Prompt('secondary')
assert wrapped(more_lines, primary, secondary) is result
assert calls == [('primary', 'secondary')]
assert primary.conversions == secondary.conversions == 1
print('PASS: reload keeps wrapper identity; both prompts converted exactly once; arguments/result preserved')

with patch.object(interact, 'multiline_input', original):
path = Path(pythonrc.file)
namespace = {'name': 'main'}
exec(compile(path.read_text(encoding='utf-8'), str(path), 'exec'), namespace)
namespace.update({'str': 20, 'sys': 1})
assert interact.multiline_input(more_lines, sys.ps1, 123) is result
assert '>>> ' in calls[-1][0] and calls[-1][1] == '123'
print('PASS: actual shell-integration PS1 and non-string PS2 work with shadowed startup globals')
PY

  • ✅ Passed | Shell-integration tests, including new prompt conversion test | python -m pytest tests/test_shell_integration.py -x -q
  • ✅ Passed | Dependency and test-environment discovery | printf 'AUTOMATION_SANDBOX_PROFILE=%s\nPIP_FIND_LINKS=%s\n' "$AUTOMATION_SANDBOX_PROFILE" "$PIP_FIND_LINKS"; command -v python python3 python3.13 python3.14 pytest uv || true; python --version; python -m pytest --version; git diff HEAD^ HEAD --stat; ls -d .venv python_files/.venv 2>/dev/null || true; ls /opt /usr/local/bin/python* /usr/bin/python* 2>/dev/null; find . -maxdepth 2 ( -name uv.lock -o -name pytest.ini -o -name pyproject.toml -o -name setup.cfg ) -print
  • ✅ Passed | Python 3.11 compatibility smoke check | /usr/bin/python3.11 - <<'PY'
    import platform
    import runpy
    import sys
    from unittest.mock import Mock

print('Python:', sys.version.split()[0])
print('Kernel release:', platform.release())
namespace = runpy.run_path('pythonrc.py', run_name='main')
assert '_pyrepl.simple_interact' not in sys.modules
assert '_initialize' not in namespace
assert sys.displayhook.name == 'vscode_displayhook'
assert sys.excepthook.name == 'vscode_excepthook'
hooks = sys.displayhook.self
hooks.original_displayhook = Mock()
hooks.vscode_displayhook('value')
hooks.original_displayhook.assert_called_once_with('value')
print('PASS: Python <3.13 initializes hooks without importing _pyrepl')
print('WSL prompt suppression:', 'microsoft-standard-WSL' in platform.release())
PY

❌ Wrapper idempotence and startup-global smoke checks diagnostic output
PASS: reload keeps wrapper identity; both prompts converted exactly once; arguments/result preserved
Ctrl click to launch VS Code Native REPL (https://aka.ms/python-native-repl)
Traceback (most recent call last):
  File "<stdin>", line 42, in <module>
AttributeError: module 'sys' has no attribute 'ps1'
[container exit=1]
The subsequent compatibility check confirmed WSL, where pythonrc's existing installation condition suppresses sys.ps1.

@rchiodo Rich Chiodo (rchiodo) left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Approved via Review Center.

@rchiodo Rich Chiodo (rchiodo) added the review-auto:approved Automated review: no blocking findings (approval posted). label Oct 5, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🟢 Approval recommended

The reviewed changes include regression coverage and no unresolved issues were identified.

Review effort: Lite
Findings: None

What changed in this PR

Updates PyREPL integration to convert ps1 and ps2 prompts to strings before multiline input handling.

Changes:

  • Wraps _pyrepl.simple_interact.multiline_input with prompt conversion.
  • Adds regression coverage for non-string prompts.
File Description
python_files/​tests/​test_shell_integration.py Tests prompt conversion behavior.
python_files/​pythonrc.py Adds the PyREPL prompt-conversion wrapper.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@edvilme
Eduardo Villalpando Mello (edvilme) merged commit 7cd9ef3 into main Oct 5, 2026
94 of 97 checks passed
Comment thread python_files/pythonrc.py
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Issue identified by VS Code Team member as probable bug review-auto:approved Automated review: no blocking findings (approval posted).

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Shell Integration makes REPL prompt garbled

5 participants