如何在 gdb 中使用 IPython 交互式 shell?||如何让制表符完成在 gdb 的 Python 交互式 (pi) shell 中工作? [英] How can I use IPython interactive shell in gdb? || How can I get tab-completion to work in gdb's Python-interactive (pi) shell?

查看:24
本文介绍了如何在 gdb 中使用 IPython 交互式 shell?||如何让制表符完成在 gdb 的 Python 交互式 (pi) shell 中工作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

通常,在 Python shell 中,我可以按两次 Tab 键来获取提示列表.

Normally, in Python shells I can press Tab twice to get a list of prompts.

另一方面,在 gdb 的 Python shell(pipython-interactive 命令)中,只有 gdb 样式的补全.

On the other hand, in gdb's Python shell (pi or python-interactive command), there's only gdb-style completion.

示例会话:

$ gdb -q
(gdb) pi
>>> gdb
<module 'gdb' from '/usr/share/gdb/python/gdb/__init__.py'>
>>> gdb.TabTab
... nothing ...
>>> show TabTab
Display all 148 possibilities? (y or n)
ada                              exec-direction                   record
agent                            exec-done-display                remote
annotate                         exec-file-mismatch               remoteaddresssize
[...]

Python 自动补全应该至少是这样的.

Python auto complete should be at least like this.

$ python
Python 3.X.Y ...
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.TabTab
sys.abiflags                              sys.hash_info
sys.addaudithook(                         sys.hexversion
sys.api_version                           sys.implementation
[...]

如何在 gdb 中获得相同/相似的东西?特别是带有制表符完成的 IPython shell 很好.

How can I get the same/similar thing in gdb? in particular IPython shell with tab completion is fine.

尝试失败:

import readline
import rlcompleter
readline.parse_and_bind("tab: complete")

当在 sys. 或类似之后按下 Tab 时,使 shell 输出一个文字选项卡.

makes the shell output a literal tab when Tab is pressed after sys. or similar.

至少它确实适用于标识符选项卡完成(aTabTab)确实列出了一些条目)

At least it does work for identifier tab completion (aTabTab) does list some entries)

看起来这是因为与 gdb 的一些交互——get_completer_delims 每次都会重置为某个值,如果运行上面的代码,则 tab 补全 outsidegdb 切换到Python 模式";也是.

Looks like this is because of some interaction with gdb -- get_completer_delims get reset to some value every time, and if the code above is run then the tab completion outside gdb switches to "Python mode" as well.

使用background_zmq_ipython会导致分段错误,因为某些gdb API(如gdb.Value)无法从主线程外读取.

Use background_zmq_ipython causes segmentation fault, because some gdb API (such as gdb.Value) cannot be read from outside the main thread.

使用 IPython.embed() 还可以使 Tab 输出文字制表符.

Use IPython.embed() also make Tab output a literal tab character.

gdb 官方文档 https://sourceware.org/gdb/current/onlinedocs/gdb/Completion.html 没有提到任何关于 Python 的内容.

The official gdb documentation https://sourceware.org/gdb/current/onlinedocs/gdb/Completion.html doesn't mention anything about Python.

推荐答案

我想出了几种方法.

我想不出任何使用内置 readline 库的方法.有关详细信息,请参阅问题中的失败尝试.

I can't figure out any way to use the built-in readline library. See the failed attempts in the question for more details.

  1. 在调用 IPython.embed 之前重置 stdout 和 stderr.

  1. Reset stdout and stderr before calling IPython.embed.

import sys
sys.stdout=sys.__stdout__
sys.stderr=sys.__stderr__

import IPython
IPython.embed(colors="neutral")

记得在之后重置 stdout 和 stderr 以避免可能出现的问题.

Remember to reset stdout and stderr afterwards to avoid possible issues.

参考:

所有 stdin、stdout 和 stderr 都是 tty 设备时,IPython 只会使用制表符补全和颜色.默认情况下 gdb sys.stdout 和 sys.stderr 是 gdb 包装器(因此 gdb 可以按 Enter 继续")超过分页限制时)

IPython will only use tab-completion and color when all of stdin, stdout and stderr are tty devices. By default gdb sys.stdout and sys.stderr are gdb wrappers (so that gdb can do "press enter to continue" when pagination limit is exceeded)

启动内核,单独启动控制台.

Start a kernel, and start a console separately.

import IPython
IPython.embed_kernel()

阅读控制台输出,了解如何连接,以及如何从远程控制台退出终端.

Read the console output on how to connect, and how to exit the terminal from the remote console.

使用我的其他答案也可以通过编程方式远程退出终端.

Using my other answer it's also possible to exit the terminal remotely programmatically.

启动内核(复杂方式)

阅读IPython的源码,了解如何手动启动内核,并在过程中获取连接文件路径.

Read the source code of IPython to figure out how to start a kernel manually, and get the connection file path in the process.

import threading
import subprocess
import IPython
from ipykernel.kernelapp import IPKernelApp
import sys

app = IPKernelApp.instance()
app.initialize([])
app.kernel.user_module = sys.modules[__name__]
app.kernel.user_ns = locals()
app.shell.set_completer_frame()

def console_thread_run():
    subprocess.run(["jupyter-console", "--no-confirm-exit", "--existing", 
        app.abs_connection_file
        ])
    app.kernel.do_shutdown(restart=False)
console_thread=threading.Thread(target=console_thread_run)
console_thread.start()

app.start()

  • 使用 background_zmq_ipython 启动内核(访问内部属性,随时可能中断).

  • Start a kernel using background_zmq_ipython (accesses internal property, might break at any time).

    主要区别在于sys.stdinsys.stdout等不受影响.见 background_zmq_ipython文档和 ipython - 为 Python 脚本提供远程 shell - 堆栈内存溢出了解更多详细信息.

    The main difference is that sys.stdin, sys.stdout etc. are not affected. See background_zmq_ipython documentation and ipython - Provide remote shell for Python script - Stack Overflow for more details.

    import subprocess
    import logging
    import threading
    
    from background_zmq_ipython import IPythonBackgroundKernelWrapper
    
    kernel_wrapper = IPythonBackgroundKernelWrapper(
            banner="", # default value is "Hello from background-zmq-ipython."
            user_ns=globals(),
            logger=logging.Logger("IPython", level=logging.INFO)
            # no handler
            # otherwise it will print "To connect another client to this IPython kernel" ...
            )
    kernel_wrapper.thread=threading.main_thread()  # workaround for assertions
    
    subprocess.Popen(["python", "-c",
        (
        "from jupyter_console.app import ZMQTerminalIPythonApp;"
        "app = ZMQTerminalIPythonApp();"
        "app.initialize();"
        "app.shell.own_kernel=True;"
        "app.start();"
        ),
        "--no-confirm-exit",
        "--existing", kernel_wrapper.connection_filename
        ])
    
    kernel_wrapper._thread_loop()
    

    还展示了如何更改消息保持内核活动";到关闭内核".

    Also show how to change the message "keeping kernel alive" to "Shutting down kernel".

    这篇关于如何在 gdb 中使用 IPython 交互式 shell?||如何让制表符完成在 gdb 的 Python 交互式 (pi) shell 中工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆