如何调试采用stdin的python CLI?

whe*_*den 20 python stdin command-line-interface command-line-tool pdb

我正在尝试调试我编写的Python CLI,它可以从stdin获取其参数.一个简单的测试用例将具有输出

echo "test" | python mytool.py
Run Code Online (Sandbox Code Playgroud)

相当于.的输出

python mytool.py test
Run Code Online (Sandbox Code Playgroud)

我想用这个工具调试一些问题,所以我试着运行它:

echo "test" | pdb mytool.py
Run Code Online (Sandbox Code Playgroud)

但我得到这个输出,然后pdb退出:

> /path/to/mytool.py(5)<module>()
-> '''
(Pdb) *** NameError: name 'test' is not defined
(Pdb)
Run Code Online (Sandbox Code Playgroud)

当我添加-m python到shebang时,如果我pdb.set_trace()在脚本中运行,则会发生同样的事情.

这里发生了什么?

dmo*_*eno 13

另一种选择是创建自己的Pdb对象,并在那里设置stdin和stdout.我的概念证明涉及2个终端,但肯定有些工作可以合并某种非常不安全的网络服务器.

  1. 创建两个fifos: mkfifo fifo_stdin mkfifo fifo_stdout

  2. 在一个终端中,在后台打开stdout,并写入stdin: cat fifo_stdout & cat > fifo_stdin

  3. 在你的python代码/控制台中创建pdb对象,并使用它: import pdb mypdb=pdb.Pdb(stdin=open('fifo_stdin','r'), stdout=open('fifo_stdout','w')) ... mypdb.set_trace() ...
  4. 利润!

您应该能够在第一个控制台上使用pdb.

唯一的缺点是必须使用你的自定义pdb,但在init(PYTHONSTARTUP或类似的)一些猴子修补可以帮助:

import pdb mypdb=pdb.Pdb(stdin=open('fifo_stdin','r'), stdout=open('fifo_stdout','w')) pdb.set_trace=mydbp.set_trace


pil*_*ona 6

你的控制 TTY 仍然是一个终端,对吗?使用这个代替pdb.set_trace.

def tty_pdb():
    from contextlib import (_RedirectStream,
                            redirect_stdout, redirect_stderr)
    class redirect_stdin(_RedirectStream):
        _stream = 'stdin'
    with open('/dev/tty', 'r') as new_stdin, \
         open('/dev/tty', 'w') as new_stdout, \
         open('/dev/tty', 'w') as new_stderr, \
         redirect_stdin(new_stdin), \
         redirect_stdout(new_stdout), redirect_stderr(new_stderr):
        __import__('pdb').set_trace()
Run Code Online (Sandbox Code Playgroud)

在这种情况下还没有自动完成 readline 。向上箭头或任何其他阅读行细节都不起作用。


dmo*_*eno 5

您可以使用其他文件描述符.使用bash,您可以创建一个新的文件描述符:

exec 3<> test.txt
Run Code Online (Sandbox Code Playgroud)

然后你的python文件有类似的东西:

#!/usr/bin/python

# Use fd 3 as another stdin file.
import os
stdin=os.fdopen(3)

while True:
    s=stdin.readline()
    import pdb; pdb.set_trace()
    print len(s)
Run Code Online (Sandbox Code Playgroud)

只运行您的脚本将使用该test.txt作为输入,您可以在stdin上使用stdin.如果需要,它也可以用于管道.

  • 我更喜欢不需要修改工具代码的解决方案. (4认同)

小智 2

当您使用 pdb(或任何其他 python 调试器)时,它会获取stdin调试命令,这就是为什么您会得到 NameError: name 'test' is not defined.

例如,此命令将在运行时退出调试器,并且一次运行不会出现此错误(也不会出现交互式调试):

(回声继续;回声“测试”)| python -m pdb mytool.py

  • 虽然这解释了发生了什么,但它没有提供答案。 (2认同)
  • @whereswalden 事实上,“答案”是 pdb 因从 stdin 获取输入而损坏且愚蠢。:/ (2认同)