Как отлаживать CLI python, который принимает stdin? - программирование
Подтвердить что ты не робот

Как отлаживать CLI python, который принимает stdin?

Я пытаюсь отлаживать Python CLI, который я написал, который может принимать свои аргументы от stdin. Простой тестовый пример будет иметь выход

echo "test" | python mytool.py

эквивалентно выходу

python mytool.py test

Я хотел бы отладить некоторые проблемы с этим инструментом, поэтому я попытался запустить это:

echo "test" | pdb mytool.py

Но я получаю этот вывод, затем выходы pdb:

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

То же самое происходит, когда я добавляю -m python к shebang, и если я запускаю pdb.set_trace() внутри script.

Что здесь происходит?

4b9b3361

Ответ 1

Другой вариант - создать свой собственный объект Pdb и установить там stdin и stdout. Мое доказательство концепции включает в себя 2 терминала, но наверняка некоторые работы могут быть объединены с каким-то очень незащищенным сетевым сервером.

  • Создайте два фифа: mkfifo stdin mkfifo stdout

  • В одном терминале откройте stdout на фоне и напишите в stdin: cat stdout & cat > stdin

  • В вашем коде/консоли python создайте объект pdb и используйте его: import pdb mypdb=pdb.Pdb(stdin=open('stdin','r'), stdout=open('stdout','w')) ... mypdb.set_trace() ...
  • Profit!

Вы должны иметь возможность использовать pdb на первой консоли.

Единственным недостатком является использование вашего пользовательского pdb, но некоторые исправления обезьян в init (PYTHONSTARTUP или аналогичные) могут помочь:

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

Ответ 2

Вы можете использовать другой файловый дескриптор. С помощью bash вы можете создать новый файловый дескриптор с помощью:

exec 3<> test.txt

И тогда в вашем файле 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)

Просто запуск вашего script будет использовать этот test.txt в качестве входных данных, и вы можете использовать stdin на stdin. Его также можно использовать с трубами, если вам нужно.

Ответ 3

Когда вы используете pdb (или любой другой отладчик python), он получает stdin для команд отладки, поэтому вы получаете NameError: name 'test' is not defined.

Например, эта команда закроет отладчик при запуске среды выполнения, и вы не получите эту ошибку (или интерактивную отладку) для одного запуска:

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

Ответ 4

Управляющий 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()

Не получили readline для автозаполнения в этих условиях. Стрелка вверх тоже не будет работать, или любые другие тонкости readline.