как написать отладчик / редактор Python - PullRequest
0 голосов
/ 12 июля 2010

Извините за общий вопрос.Подробнее о том, что я хочу:

Я хочу, чтобы пользователь мог написать некоторый код Python и выполнить его.Как только возникает исключение, которое не обрабатывается, я хочу, чтобы отладчик приостановил выполнение, показал информацию о текущем состоянии / среде / стеке / исключении и позволил редактировать код .

Я хочу, чтобы специальный блок кода редактировался только там, где произошло исключение, и больше ничего (пока).Т.е., если это произошло внутри цикла for, я хочу, чтобы блок кода только внутри цикла for редактировался.Это должен быть последний / самый последний блок кода, который находится в области действия редактора пользователя (а не внутри некоторых других библиотек или библиотек Python).В этих условиях всегда ясно, какой блок кода нужно редактировать.


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

Pythontraceback не дает мне непосредственно блок кода, только функцию и строку кода.Я мог бы рассчитать это обратно, но мне это кажется немного хакерским.Лучше (и более естественным) было бы, если бы я мог как-то получить ссылку на блок кода в AST кода.

Чтобы получить AST (и работать с ним, т.е. манипулировать / редактировать), я, вероятно,будет использовать compiler (что устарело?) и / или модуль parser.Или модуль ast.Не уверен, хотя, как я мог бы перекомпилировать специальные узлы / блоки кода в AST.Или если я только могу перекомпилировать целые функции.

Ответы [ 3 ]

2 голосов
/ 12 июля 2010

Играя с ast и compile (встроенными), кажется, что вы можете использовать NodeTransformer для изменения некоторых узлов ... Вы также можете редактировать их вручную, если знаете, что ищетеfor.

test.py

print 'Dumb Guy'
x = 4 + 4
print x * 3

change.py

import ast
with open('test.py') as f:
    expr = f.read()

e = ast.parse(expr)
e.body[0].values[0].s = 'Cool Guy'       # Replace the string
e.body[1].targets[0].id = 'herring'      # Change x to herring
e.body[2].values[0].left.id = 'herring'  # Change reference to x to reference to herring
c = compile(e, '<string>', 'exec')
exec(c)

Выход change.py:

Крутой парень24

Вы также можете добавить код в тело следующим образом (или заменить элементы обычным способом замены элементов списка):

p = ast.parse('print "Sweet!"', mode='single')
e.body.extend(p)

, а затем просто перекомпилировать и выполнить exec:

c = compile(e, '<string>', 'exec')
exec(c)

Таким способом можно заменить определения функций или отдельные строки.Определение функции будет иметь свое собственное тело, поэтому, если вы добавите некоторую функцию (или цикл), вы сможете получить к ней доступ с помощью

e.body[N].body  # Replace N with the index of the FunctionDef object

Однако единственный известный мне способ выполнить один объект ast (_ast.Print или _ast.Assign или что-то еще), чтобы сделать что-то вроде этого:

e2 = ast.parse('', mode='exec')
e2.body.append(e.body[0])
exec(compile(e2, '<string>', 'exec'))

, что мне кажется немного хакерским.Что касается строк - каждый объект в AST имеет атрибут lineno, поэтому, если вы можете извлечь номер строки из исключения, вы можете довольно легко определить, какой оператор вызвал исключение.

Конечно, это на самом деле не решает проблему перемотки стека в состояние предисключения, как вы действительно хотите, похоже.Тем не менее, это может быть возможно сделать через pdb .

0 голосов
/ 17 августа 2010

Из того, что я выяснил за это время, это невозможно.По крайней мере, не блочно.Можно перекомпилировать код для каждой функции, но не для каждого кодового блока, поскольку Python генерирует объекты кода для каждой функции.

Поэтому единственный способ - написать собственный компилятор Python.

0 голосов
/ 12 июля 2010

Интересно, может ли вам помочь HAP Remote Debugger для Python ?Я не думаю, что у них есть живое редактирование, но некоторые аспекты отладки могут быть полезны.

...