Как программно выйти из pdb, запущенного в eval () или exec (), не показывая вывод - PullRequest
3 голосов
/ 18 октября 2010

В моем коде Python у меня есть эта строка:

try:
    result = eval(command, self.globals, self.locals)
except SyntaxError:
    exec(command, self.globals, self.locals)

Переменная command может быть любой строкой.Следовательно, отладчик Python pdb может быть запущен в eval / exec и оставаться активным, когда возвращается eval / exec.Что я хочу сделать, это убедиться, что нормальное выполнение программы возобновляется при возврате из eval / exec.Чтобы просто дать вам представление, это примерно то поведение, которое я хочу:

try:
    result = eval(command, self.globals, self.locals)
    try: self.globals['pdb'].run('continue')
    except: pass
except SyntaxError:
    exec(command, self.globals, self.locals)
    try: self.globals['pdb'].run('continue')
    except: pass

Однако строка try отображается в отладчике перед его выполнением, но я не хочу, чтобы отладчик показывал мойкод вообще.Кроме того, это на самом деле не работает ... Причина, по которой я повторяю код, состоит в том, чтобы минимизировать отладку в моем коде, иначе я мог бы просто сделать это после блока except.

Так, как я могу сделатьthis?

В качестве идентификатора:

Если вы попытаетесь ввести следующие строки в интерпретаторы IPython или bpython, вы увидите, что у них та же проблема, и выспособны войти в их код.

import pdb
pdb.set_trace()
next

Однако, если вы сделаете это в стандартном интерпретаторе cpython, вы вернетесь в приглашение python.Причина этого, очевидно, в том, что два первых реализованы на python, а последний - нет.Но я хочу, чтобы поведение было таким же, даже когда весь код написан на Python.

1 Ответ

3 голосов
/ 06 декабря 2010

Хотя я несколько обеспокоен тем, что вы проверяете / исполняете строку, которую вы не контролируете, я предполагаю, что вы все продумали.

Я думаю, что самой простой вещью было бы убедить pdb проверить кадр стека на каждом шаге и автоматически возобновить работу, когда вы вернетесь к желаемому уровню. Вы можете сделать это с помощью простого исправления. В приведенном ниже коде я упростил его до простого eval, поскольку все, что вы действительно просите, - это автоматически возобновлять pdb при возврате к определенной функции. Вызовите Pdb (). Resume_here () в функции, которую вы не хотите отслеживать. Нотабене возобновление является глобальным, и есть только одна точка возобновления, но я уверен, что вы можете изменить это, если хотите.

Если вы запустите код, то вы введете отладчик в функцию foo() и затем сможете выполнить один шаг, но как только вернетесь к bar(), код продолжится автоматически.

, например

import sys
from pdb import Pdb

def trace_dispatch(self, frame, event, arg):
    if frame is self._resume_frame:
        self.set_continue()
        return
    return self._original_trace_dispatch(frame, event, arg)

def resume_here(self):
    Pdb._resume_frame = sys._getframe().f_back

# hotfix Pdb
Pdb._original_trace_dispatch = Pdb.trace_dispatch
Pdb.trace_dispatch = trace_dispatch
Pdb.resume_here = resume_here
Pdb._resume_frame = None

def foo():
    import pdb
    pdb.set_trace()
    print("tracing...")
    for i in range(3):
        print(i)

def bar():
    Pdb().resume_here()
    exec("foo();print('done')")
    print("returning")

bar()
...