Skip to content

Commit 255180b

Browse files
committed
Use 3.13+ _pyrepl if that is available
1 parent cbe650c commit 255180b

1 file changed

Lines changed: 80 additions & 22 deletions

File tree

trepan/processor/command/python.py

Lines changed: 80 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# -*- coding: utf-8 -*-
22
#
3-
# Copyright (C) 2009-2010, 2013, 2015, 2017, 2020, 2023-2025
3+
# Copyright (C) 2009-2010, 2013, 2015, 2017, 2020, 2023-2026
44
# Rocky Bernstein
55
#
66
# This program is free software: you can redistribute it and/or modify
@@ -17,18 +17,40 @@
1717
# along with this program. If not, see <http://www.gnu.org/licenses/>.
1818
import code
1919
import sys
20+
from typing import Callable
2021

2122
from trepan.interfaces.server import ServerInterface
2223

2324
# Our local modules
2425
from trepan.processor.command.base_cmd import DebuggerCommand
2526

27+
use_pyrepl = False
28+
try:
29+
from _pyrepl.console import InteractiveColoredConsole
30+
from _pyrepl.unix_console import InvalidTerminal
31+
from _pyrepl.simple_interact import run_multiline_interactive_console
32+
33+
import os
34+
35+
if os.name == "nt":
36+
from _pyrepl.windows_console import WindowsConsole as Console
37+
else:
38+
from _pyrepl.unix_console import UnixConsole as Console
39+
use_pyrepl = True
40+
41+
except ImportError:
42+
use_pyrepl = False
43+
44+
2645

2746
class PythonCommand(DebuggerCommand):
2847
"""**python** [**-d**]
2948
3049
Run Python as a command subshell. The *sys.ps1* prompt will be set to
31-
`trepan3 >>> `.
50+
`trepan3k >>> `.
51+
52+
If running Python 3.13 or it is possible to use pyrepl, this will be used,
53+
providing its colorization and language completion facilities.
3254
3355
If *-d* is passed, you can access debugger state via local variable *debugger*.
3456
@@ -72,7 +94,7 @@ def run(self, args):
7294
pass
7395
pass
7496

75-
banner_tmpl = """trepan3 python shell%s
97+
banner_tmpl = """trepan3k python shell%s
7698
Use dbgr(*string*) to issue debugger command: *string*"""
7799

78100
debug = len(args) > 1 and args[1] == "-d"
@@ -109,12 +131,14 @@ def run(self, args):
109131
sys.excepthook = None
110132
if len(my_locals):
111133
interact(
134+
msg_func=self.msg,
135+
errmsg_func=self.errmsg,
112136
banner=(banner_tmpl % " with locals"),
113137
my_locals=my_locals,
114138
my_globals=my_globals,
115139
)
116140
else:
117-
interact(banner=(banner_tmpl % ""))
141+
interact(errmsg_func=self.errmsg, banner=banner_tmpl % "")
118142
pass
119143
finally:
120144
sys.excepthook = old_sys_excepthook
@@ -124,6 +148,7 @@ def run(self, args):
124148
if hasattr(interface, "complete") and interface.complete is not None:
125149
try:
126150
from readline import parse_and_bind, set_completer
151+
127152
parse_and_bind("tab: complete")
128153
set_completer(proc.intf[-1].complete)
129154
except ImportError:
@@ -138,11 +163,20 @@ def run(self, args):
138163
pass
139164

140165

141-
# Monkey-patched from code.py
142-
# FIXME: get changes into Python.
143-
def interact(banner=None, readfunc=None, my_locals=None, my_globals=None):
144-
"""Almost a copy of ``code.interact``.
145-
Closely emulate the interactive Python interpreter.
166+
pyrepl_console = None
167+
168+
169+
# Modified from code.py
170+
def interact(
171+
msg_func: Callable,
172+
errmsg_func: Callable,
173+
banner=None,
174+
readfunc=None,
175+
my_locals=None,
176+
my_globals=None,
177+
):
178+
"""
179+
Emulate the interactive Python interpreter. This is Similar to ``code.interact``.
146180
147181
This is a backwards compatible interface to the InteractiveConsole
148182
class. When readfunc is not specified, it attempts to import the
@@ -157,19 +191,44 @@ def interact(banner=None, readfunc=None, my_locals=None, my_globals=None):
157191
"""
158192

159193
def console_runcode(code_obj):
160-
runcode(console, code_obj)
161-
162-
console = code.InteractiveConsole(my_locals, filename="<trepan>")
163-
console.runcode = console_runcode
164-
setattr(console, "globals", my_globals)
165-
if readfunc is not None:
166-
console.raw_input = readfunc
167-
console.interact(banner)
168-
pass
194+
runcode(pyrepl_console, code_obj)
195+
196+
global pyrepl_console
197+
global use_pyrepl
198+
199+
if use_pyrepl:
200+
if not pyrepl_console:
201+
pyrepl_console = InteractiveColoredConsole(my_locals, filename="<trepan>")
169202

203+
pyrepl_console.runcode = console_runcode
204+
setattr(pyrepl_console, "globals", my_globals)
205+
if readfunc is not None:
206+
pyrepl_console.raw_input = readfunc
170207

171-
# Also monkey-patched from code.py
172-
# FIXME: get changes into Python.
208+
209+
try:
210+
Console(sys.stdin, sys.stdout)
211+
except InvalidTerminal:
212+
use_pyrepl = None
213+
errmsg_func(
214+
"Colored PyREPL can't be used here; using standard Python shell"
215+
)
216+
217+
msg_func(banner)
218+
run_multiline_interactive_console(pyrepl_console)
219+
220+
# Fancy color pyrepl console can't be used, so use InteractiveConsole.
221+
if not pyrepl_console:
222+
pyrepl_console = code.InteractiveConsole(my_locals, filename="<trepan>")
223+
pyrepl_console.runcode = console_runcode
224+
setattr(pyrepl_console, "globals", my_globals)
225+
if readfunc is not None:
226+
pyrepl_console.raw_input = readfunc
227+
228+
pyrepl_console.interact(banner)
229+
return
230+
231+
# Monkey-patched from code.py
173232
def runcode(obj, code_obj):
174233
"""Execute a code object.
175234
@@ -190,8 +249,7 @@ def runcode(obj, code_obj):
190249
except SystemExit:
191250
raise
192251
except Exception:
193-
info = sys.exc_info()
194-
print(f"{info[0]}; {info[1]}")
252+
obj.showtraceback()
195253
else:
196254
pass
197255
return

0 commit comments

Comments
 (0)