简体   繁体   English

如何调试采用标准输入的 python CLI?

[英]How to debug python CLI that takes stdin?

I'm trying to debug a Python CLI I wrote that can take its arguments from stdin.我正在尝试调试我编写的可以从 stdin 获取参数的 Python CLI。 A simple test case would have the output of一个简单的测试用例将有输出

echo "test" | python mytool.py

be equivalent to the output of等价于输出

python mytool.py test

I'd like to debug some issues with this tool, so I tried to run this:我想用这个工具调试一些问题,所以我试着运行这个:

echo "test" | pdb mytool.py

But I get this output, then pdb exits:但我得到这个输出,然后 pdb 退出:

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

The same thing occurs when I add -m python to the shebang, and if I run pdb.set_trace() inside the script.当我将-m python添加到shebang时,如果我在脚本中运行pdb.set_trace() ,也会发生同样的事情。

What's going on here?这里发生了什么?

Another option is to create you own Pdb object, and set there the stdin and stdout.另一种选择是创建您自己的 Pdb 对象,并在其中设置 stdin 和 stdout。 My proof of concept involves 2 terminals, but for sure some work can be merged some kind of very unsecure network server.我的概念证明涉及 2 个终端,但可以肯定的是,某些工作可以合并到某种非常不安全的网络服务器上。

  1. Create two fifos:创建两个fifo:

     mkfifo fifo_stdin mkfifo fifo_stdout
  2. In one terminal, open stdout on background, and write to stdin:在一个终端中,在后台打开标准输出,并写入标准输入:

     cat fifo_stdout & cat > fifo_stdin
  3. In your python code/console create the pdb object, and use it:在您的 python 代码/控制台中创建 pdb 对象,并使用它:

     import pdb mypdb=pdb.Pdb(stdin=open('fifo_stdin','r'), stdout=open('fifo_stdout','w')) ... mypdb.set_trace() ...
  4. Profit!利润!

You should be able to use pdb on the first console.您应该能够在第一个控制台上使用 pdb。

The only drawback is having to use your custom pdb, but some monkey patching at init (PYTHONSTARTUP or similar) can help:唯一的缺点是必须使用您的自定义 pdb,但是在 init(PYTHONSTARTUP 或类似的)中进行一些猴子修补可以提供帮助:

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

You can use another file descriptor.您可以使用另一个文件描述符。 With bash you can create a new file descriptor with:使用 bash,您可以创建一个新的文件描述符:

exec 3<> test.txt

And then on your python file have something like:然后在你的 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)

Just runing your script will use that test.txt as input, and you can use stdin on stdin.只要运行你的脚本就会使用 test.txt 作为输入,你可以在 stdin 上使用 stdin。 It can be used as well with pipes if you need.如果需要,它也可以与管道一起使用。

Your controlling TTY is still a terminal, right?你的控制 TTY 仍然是一个终端,对吧? Use this instead of pdb.set_trace .使用它而不是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()

Haven't gotten readline to autocomplete under these circumstances.在这种情况下,还没有让 readline 自动完成。 Up arrow won't work either, or any other of the readline niceties.向上箭头或任何其他 readline 细节也不起作用。

When you use pdb(or any other python debugger) it acquires stdin for debug commands, that's why you get NameError: name 'test' is not defined .当您使用 pdb(或任何其他 python 调试器)时,它会获取用于调试命令的stdin ,这就是您得到NameError: name 'test' is not defined

For example this command will quit debugger at the begging of a runtime and you wont get this error(nor interactive debugging) for one run:例如,此命令将在运行时退出调试器,并且一次运行不会出现此错误(也不会出现交互式调试):

(echo cont;echo "test") | (echo cont;echo "test") | python -m pdb mytool.py python -m pdb mytool.py

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM