Skip to content

Commit 7ea2321

Browse files
CNSeniorious000eleanorjboydedvilmeCopilot
authored
Fix mismatched traceback in pythonrc.py injection (#25480)
Since vscode-python injects `PYTHONSTARTUP` into `pythonrc.py` to show the "Ctrl click to launch VS Code Native REPL" message, traceback always shows lines inside `pythonrc.py` in the interactive console. Example: <img width="1199" height="732" alt="image" src="https://github.com/user-attachments/assets/7c68a20b-7b3c-4f32-bc76-3e73a61282e5" /> That's because python sets `__main__` to the `pythonrc.py` module, which has a `__loader__` attribute. The `__loader__` object is then exposed in the global namespace of the interactive console. However, [linecache uses `__loader__` to get the source code](https://github.com/python/cpython/blob/a756a4b95341cda63298fb5628b56c32f43f4f1e/Lib/linecache.py#L231), causing the mismatch. After this PR, the traceback points to the right source now: <img width="1223" height="488" alt="image" src="https://github.com/user-attachments/assets/b4d1635b-9137-463d-91ab-34b7d178e98d" /> In the [`_pyrepl.__main__` module](https://github.com/python/cpython/blob/main/Lib/_pyrepl/__main__.py), there was some comment mentioning this behavior and they set `__loader__ = None` to avoid this. See python/cpython#129098 for more information --------- Co-authored-by: Eleanor Boyd <26030610+eleanorjboyd@users.noreply.github.com> Co-authored-by: Eduardo Villalpando Mello <eduardovil@microsoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent bbd2d7d commit 7ea2321

2 files changed

Lines changed: 26 additions & 0 deletions

File tree

‎python_files/pythonrc.py‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
# PYTHONSTARTUP runs in __main__; clear its metadata at module scope so linecache
2+
# cannot use this file's loader for later interactive tracebacks.
3+
# CPython issue: https://github.com/python/cpython/issues/129098
4+
# CPython fix: https://github.com/python/cpython/pull/130721
5+
__spec__ = __loader__ = None
6+
7+
18
def _initialize():
29
import platform
310
import sys

‎python_files/tests/test_shell_integration.py‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import importlib
2+
import linecache
23
import platform
34
import sys
5+
from importlib.machinery import ModuleSpec, SourceFileLoader
46
from pathlib import Path
57
from typing import Any, Protocol, cast
68
from unittest.mock import Mock
@@ -81,6 +83,23 @@ def test_does_not_pollute_namespace():
8183
assert not [name for name in vars(pythonrc) if not name.startswith("__")]
8284

8385

86+
def test_pythonstartup_clears_loader_metadata_for_tracebacks(monkeypatch, tmp_path):
87+
source = PYTHONRC_PATH.read_text(encoding="utf-8")
88+
loader = SourceFileLoader("__main__", str(PYTHONRC_PATH))
89+
namespace: dict[str, Any] = {
90+
"__name__": "__main__",
91+
"__loader__": loader,
92+
"__spec__": ModuleSpec("__main__", loader),
93+
}
94+
monkeypatch.setattr(linecache, "cache", {})
95+
96+
exec(compile(source, str(PYTHONRC_PATH), "exec"), namespace)
97+
98+
assert linecache.getline(str(tmp_path / "missing.py"), 1, namespace) == ""
99+
assert namespace["__loader__"] is None
100+
assert namespace["__spec__"] is None
101+
102+
84103
def test_replacement_regex_removes_bel_terminated_osc():
85104
if sys.version_info < (3, 13):
86105
return

0 commit comments

Comments
 (0)