Skip to content

Commit

Permalink
cli: Add support for Python 3.13 enhanced REPL
Browse files Browse the repository at this point in the history
Signed-off-by: Stephen Brennan <[email protected]>
  • Loading branch information
brenns10 authored and osandov committed Oct 18, 2024
1 parent a43ae0b commit 1102a7c
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 4 deletions.
7 changes: 7 additions & 0 deletions docs/advanced_usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,13 @@ Some of drgn's behavior can be modified through environment variables:
Whether drgn should use libkdumpfile for ELF vmcores (0 or 1). The default
is 0. This functionality will be removed in the future.

``DRGN_USE_PYREPL``
Whether drgn should attempt to use the improved REPL (pyrepl) from Python
3.13. This provides colored output and multiline editing, among other
features. The default is 1. Unfortunately, Python has no public API to use
these features, so drgn must rely on internal implementation details. Set
this to 0 to disable this feature.

``DRGN_USE_SYS_MODULE``
Whether drgn should use ``/sys/module`` to find information about loaded
kernel modules for the running kernel instead of getting them from the core
Expand Down
5 changes: 2 additions & 3 deletions drgn/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,18 @@

import argparse
import builtins
import code
import importlib
import logging
import os
import os.path
import pkgutil
import readline
import runpy
import shutil
import sys
from typing import Any, Callable, Dict, Optional

import drgn
from drgn.internal.repl import interact, readline
from drgn.internal.rlcompleter import Completer
from drgn.internal.sudohelper import open_via_sudo

Expand Down Expand Up @@ -435,7 +434,7 @@ def run_interactive(
drgn.set_default_prog(prog)

try:
code.interact(banner=banner, exitmsg="", local=init_globals)
interact(init_globals, banner)
finally:
try:
readline.write_history_file(histfile)
Expand Down
47 changes: 47 additions & 0 deletions drgn/internal/repl.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Copyright (c) 2024, Oracle and/or its affiliates.
# SPDX-License-Identifier: LGPL-2.1-or-later

"""Compatibility shim between drgn and the pyrepl/code modules"""

import os
import sys
from typing import Any, Dict

__all__ = ("interact", "readline")

# Python 3.13 introduces a new REPL implemented by the "_pyrepl" internal
# module. It includes features such as colored output and multiline editing.
# Unfortunately, there is no public API exposing these abilities to users, even
# in the "code" module. We'd like to give the best experience possible, so we'll
# detect _pyrepl and try to use it where possible.
try:
# Since this mucks with internals, add a knob that can be used to disable it
# and use the traditional REPL.
if os.environ.get("DRGN_USE_PYREPL") in ("0", "n", "N", "false", "False"):
raise ModuleNotFoundError()

# Unfortunately, the typeshed library behind mypy explicitly removed type
# stubs for these modules. This makes sense as they are private APIs, but it
# means we need to disable mypy checks.
from _pyrepl import readline # type: ignore
from _pyrepl.console import InteractiveColoredConsole # type: ignore
from _pyrepl.simple_interact import ( # type: ignore
run_multiline_interactive_console,
)

# This _setup() function clobbers the readline completer, but it is
# protected so it only runs once. Call it early so that our overridden
# completer doesn't get clobbered.
readline._setup({})

def interact(local: Dict[str, Any], banner: str) -> None:
console = InteractiveColoredConsole(local)
print(banner, file=sys.stderr)
run_multiline_interactive_console(console)

except (ModuleNotFoundError, ImportError):
import code
import readline

def interact(local: Dict[str, Any], banner: str) -> None:
code.interact(banner=banner, exitmsg="", local=local)
3 changes: 2 additions & 1 deletion drgn/internal/rlcompleter.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@
import builtins
import keyword
import re
import readline
from typing import Any, Dict, List, Optional

from drgn.internal.repl import readline

_EXPR_RE = re.compile(
r"""
(
Expand Down

0 comments on commit 1102a7c

Please sign in to comment.