Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 38cfa92

Browse filesBrowse files
[3.13] gh-118908: Use __main__ for the default PyREPL namespace (GH-121054) (#121059)
1 parent 64c4139 commit 38cfa92
Copy full SHA for 38cfa92

File tree

Expand file treeCollapse file tree

4 files changed

+75
-67
lines changed
Filter options
Expand file treeCollapse file tree

4 files changed

+75
-67
lines changed

‎Lib/_pyrepl/__main__.py

Copy file name to clipboard
+2-50Lines changed: 2 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,3 @@
1-
import os
2-
import sys
3-
4-
CAN_USE_PYREPL: bool
5-
if sys.platform != "win32":
6-
CAN_USE_PYREPL = True
7-
else:
8-
CAN_USE_PYREPL = sys.getwindowsversion().build >= 10586 # Windows 10 TH2
9-
10-
11-
def interactive_console(mainmodule=None, quiet=False, pythonstartup=False):
12-
global CAN_USE_PYREPL
13-
if not CAN_USE_PYREPL:
14-
return sys._baserepl()
15-
16-
startup_path = os.getenv("PYTHONSTARTUP")
17-
if pythonstartup and startup_path:
18-
import tokenize
19-
with tokenize.open(startup_path) as f:
20-
startup_code = compile(f.read(), startup_path, "exec")
21-
exec(startup_code)
22-
23-
# set sys.{ps1,ps2} just before invoking the interactive interpreter. This
24-
# mimics what CPython does in pythonrun.c
25-
if not hasattr(sys, "ps1"):
26-
sys.ps1 = ">>> "
27-
if not hasattr(sys, "ps2"):
28-
sys.ps2 = "... "
29-
30-
run_interactive = None
31-
try:
32-
import errno
33-
if not os.isatty(sys.stdin.fileno()):
34-
raise OSError(errno.ENOTTY, "tty required", "stdin")
35-
from .simple_interact import check
36-
if err := check():
37-
raise RuntimeError(err)
38-
from .simple_interact import run_multiline_interactive_console
39-
run_interactive = run_multiline_interactive_console
40-
except Exception as e:
41-
from .trace import trace
42-
msg = f"warning: can't use pyrepl: {e}"
43-
trace(msg)
44-
print(msg, file=sys.stderr)
45-
CAN_USE_PYREPL = False
46-
if run_interactive is None:
47-
return sys._baserepl()
48-
return run_interactive(mainmodule)
49-
501
if __name__ == "__main__":
51-
interactive_console()
2+
from .main import interactive_console as __pyrepl_interactive_console
3+
__pyrepl_interactive_console()

‎Lib/_pyrepl/main.py

Copy file name to clipboard
+55Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import os
2+
import sys
3+
4+
CAN_USE_PYREPL: bool
5+
if sys.platform != "win32":
6+
CAN_USE_PYREPL = True
7+
else:
8+
CAN_USE_PYREPL = sys.getwindowsversion().build >= 10586 # Windows 10 TH2
9+
10+
11+
def interactive_console(mainmodule=None, quiet=False, pythonstartup=False):
12+
global CAN_USE_PYREPL
13+
if not CAN_USE_PYREPL:
14+
return sys._baserepl()
15+
16+
if mainmodule:
17+
namespace = mainmodule.__dict__
18+
else:
19+
import __main__
20+
namespace = __main__.__dict__
21+
namespace.pop("__pyrepl_interactive_console", None)
22+
23+
startup_path = os.getenv("PYTHONSTARTUP")
24+
if pythonstartup and startup_path:
25+
import tokenize
26+
with tokenize.open(startup_path) as f:
27+
startup_code = compile(f.read(), startup_path, "exec")
28+
exec(startup_code, namespace)
29+
30+
# set sys.{ps1,ps2} just before invoking the interactive interpreter. This
31+
# mimics what CPython does in pythonrun.c
32+
if not hasattr(sys, "ps1"):
33+
sys.ps1 = ">>> "
34+
if not hasattr(sys, "ps2"):
35+
sys.ps2 = "... "
36+
37+
run_interactive = None
38+
try:
39+
import errno
40+
if not os.isatty(sys.stdin.fileno()):
41+
raise OSError(errno.ENOTTY, "tty required", "stdin")
42+
from .simple_interact import check
43+
if err := check():
44+
raise RuntimeError(err)
45+
from .simple_interact import run_multiline_interactive_console
46+
run_interactive = run_multiline_interactive_console
47+
except Exception as e:
48+
from .trace import trace
49+
msg = f"warning: can't use pyrepl: {e}"
50+
trace(msg)
51+
print(msg, file=sys.stderr)
52+
CAN_USE_PYREPL = False
53+
if run_interactive is None:
54+
return sys._baserepl()
55+
run_interactive(namespace)

‎Lib/_pyrepl/simple_interact.py

Copy file name to clipboardExpand all lines: Lib/_pyrepl/simple_interact.py
+1-11Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -80,23 +80,13 @@ def _clear_screen():
8080
"clear": _clear_screen,
8181
}
8282

83-
DEFAULT_NAMESPACE: dict[str, Any] = {
84-
'__name__': '__main__',
85-
'__doc__': None,
86-
'__package__': None,
87-
'__loader__': None,
88-
'__spec__': None,
89-
'__annotations__': {},
90-
'__builtins__': builtins,
91-
}
9283

9384
def run_multiline_interactive_console(
94-
mainmodule: ModuleType | None = None,
85+
namespace: dict[str, Any],
9586
future_flags: int = 0,
9687
console: code.InteractiveConsole | None = None,
9788
) -> None:
9889
from .readline import _setup
99-
namespace = mainmodule.__dict__ if mainmodule else DEFAULT_NAMESPACE
10090
_setup(namespace)
10191

10292
if console is None:

‎Lib/test/test_pyrepl/test_pyrepl.py

Copy file name to clipboardExpand all lines: Lib/test/test_pyrepl/test_pyrepl.py
+17-6Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -843,15 +843,26 @@ def test_bracketed_paste_single_line(self):
843843
class TestMain(TestCase):
844844
@force_not_colorized
845845
def test_exposed_globals_in_repl(self):
846-
expected_output = (
847-
"[\'__annotations__\', \'__builtins__\', \'__doc__\', \'__loader__\', "
848-
"\'__name__\', \'__package__\', \'__spec__\']"
849-
)
846+
pre = "['__annotations__', '__builtins__'"
847+
post = "'__loader__', '__name__', '__package__', '__spec__']"
850848
output, exit_code = self.run_repl(["sorted(dir())", "exit"])
851-
if "can\'t use pyrepl" in output:
849+
if "can't use pyrepl" in output:
852850
self.skipTest("pyrepl not available")
853851
self.assertEqual(exit_code, 0)
854-
self.assertIn(expected_output, output)
852+
853+
# if `__main__` is not a file (impossible with pyrepl)
854+
case1 = f"{pre}, '__doc__', {post}" in output
855+
856+
# if `__main__` is an uncached .py file (no .pyc)
857+
case2 = f"{pre}, '__doc__', '__file__', {post}" in output
858+
859+
# if `__main__` is a cached .pyc file and the .py source exists
860+
case3 = f"{pre}, '__cached__', '__doc__', '__file__', {post}" in output
861+
862+
# if `__main__` is a cached .pyc file but there's no .py source file
863+
case4 = f"{pre}, '__cached__', '__doc__', {post}" in output
864+
865+
self.assertTrue(case1 or case2 or case3 or case4, output)
855866

856867
def test_dumb_terminal_exits_cleanly(self):
857868
env = os.environ.copy()

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.