osandov / drgn

Programmable debugger
Other
1.75k stars 163 forks source link

Investigate using enhanced REPL in Python 3.13 #446

Open brenns10 opened 1 week ago

brenns10 commented 1 week ago

Python 3.13 introduces a new REPL mode which has several useful items that can be seen in the docs. But the big item in my mind is the multiline editing! It allows you to easily write multiline expressions in a way that would have been quite tedious before.

I'm obviously an enhanced REPL fan so I looked into using the enhanced 3.13 REPL, and unfortunately I don't see any changes to the code standard module API to allow using it. I was able to hack something together that works on 3.13 (see the diff below). The issue is that it muddles all around in private modules, which may change in the next release.

I'll take a look into the Python bug tracker tomorrow and see whether there are any bug/enhancement requests to add some sort of public interface to the newer features -- really the multiline editing is what I want to see.

diff --git a/drgn/cli.py b/drgn/cli.py
index ac66745d..5d2c9f45 100644
--- a/drgn/cli.py
+++ b/drgn/cli.py
@@ -6,7 +6,6 @@

 import argparse
 import builtins
-import code
 import importlib
 import logging
 import os
@@ -22,6 +21,18 @@ import drgn
 from drgn.internal.rlcompleter import Completer
 from drgn.internal.sudohelper import open_via_sudo

+try:
+    from _pyrepl.console import InteractiveColoredConsole
+    from _pyrepl.simple_interact import run_multiline_interactive_console
+
+    def interact(banner: str = "", exitmsg: str = "", local={}):
+        console = InteractiveColoredConsole(local)
+        print(banner)
+        run_multiline_interactive_console(console)
+
+except ModuleNotFoundError:
+    from code import interact
+
 __all__ = ("run_interactive", "version_header")

 logger = logging.getLogger("drgn")
@@ -484,7 +495,7 @@ For help, type help(drgn).
         drgn.set_default_prog(prog)

         try:
-            code.interact(banner=banner, exitmsg="", local=init_globals)
+            interact(banner=banner, exitmsg="", local=init_globals)
         finally:
             try:
                 readline.write_history_file(histfile)
osandov commented 1 week ago

I've been meaning to look into this, so thank you! Obviously it'd be great to get a public API, but the new REPL is alluring enough that I'd probably be willing to go for a hack like this in the meantime.

brenns10 commented 1 week ago

Sounds good! I can work to make the hack as innocent as possible. I started late in the day so I didn't have much time to experiment. In particular I don't know if the readline completer or history got applied with this hack.

In parallel we can see if there's any chance of a public API so we can have a better option in the future.

brenns10 commented 6 days ago

I did a search through the cpython issues to get an idea if there are already open feature requests. It looks like this is the feature request we're looking for:

python/cpython#119512

I think it would be fair to say that this may not be enough for our purposes. In addition to using the code interactive interpreter, we use readline to load our own history file, and we set a custom completer that gets used by the code module. Presumably a PyREPL-based code module would not pick up those customizations, so we'd need something more. I'll ask on that issue if those considerations would be in-scope for that change, if it were to be implemented.