однострочная точка останова условной отладки python для версий до 3.7 PEP 553, которая действует аналогично Perl's $ DB :: single = 1 - PullRequest
15 голосов
/ 14 июня 2019

В версиях Python до утилиты PEP 553 breakpoint(), каков рекомендуемый способ добавления (в идеале однострочного) кода, чтобы иметь точку останова, которую можно игнорировать при условии (например, глобальный флаг отладки или args.debugflag).

В Perl я привык использовать $DB::single=1;1; однострочные, которые, я знаю, я могу безопасно оставить в коде и не повлияет на нормальный запуск perl code.pl, если явно не вызывается perl -d code.pl.Например:

my $a = 1;
$DB::single=1;1; # breakpoint line
my $b = 2;
print "$a $b\n";

Если я выполню этот код как: perl code.pl, он запустится до завершения.Если я выполню этот код с: perl -d code.pl, pdb остановится на строке точки останова (не перед следующей строкой с оператором my $b = 2;), поскольку он содержит оператор 1; после оператора $DB::single=1;;

Точно так же, если я напишу:

my $debug = 1;
my $a = 1;
$DB::single=$debug;1; # first breakpoint line
my $b = 2;
$DB::single=$debug;1; # second breakpoint line
print "$a $b\n";
# [...] Lots more code sprinkled with more of these
$DB::single=$debug;1; # n'th breakpoint line

, я могу затем выполнить perl -d code.pl, который остановится в первой строке точки останова, затем в сеансе pdb, как только я буду рад, чтоего не нужно останавливать где-либо еще, затем выполните: $debug = 0, затем pdb continue c, что не позволит ему остановиться на второй или других аналогичных линиях точки останова в коде.

Как можноЯ достигаю того же, в идеале в однострочных выражениях, в python (2.x и 3.x до PEP 553)?

Я знаю о PEP 553, и кроме того, что приходится явно устанавливать PYTHONBREAKPOINT=0 python3.7 code.py или закомментируйте breakpoint() строки, это решение вопроса здесь.

Я думал о таких вариантах, как:

import pdb; pdb.set_trace()
dummy=None;

Утверждение под pdb.set_trace() таково, чтоЯ могу достичь того же, что и 1; в той же строке после $DB::single=1; в Perl, который должен иметь остановку отладчика, где я разместил точку останова, а не следующий оператор.Это делается для того, чтобы при наличии больших кусков прокомментированного кода или документации между ними отладчик не переходил к следующему оператору вдали от точки останова.

Или с такими условиями, как:

if args.debug or debug:
    import pdb; pdb.set_trace()
    _debug=False; #args.debug=False

Так что, если я закончу отладку для скрипта, я могу установить args.debug=False или debug=False и не должен трогать все эти точки останова вкод.

Ответы [ 2 ]

7 голосов
/ 18 июня 2019

Установка условной точки останова

То же, что и в perl, python можно запустить с помощью -d для установки флага отладки:

$ python --help
[...]
-d     : debug output from parser; also PYTHONDEBUG=x
[...]

Вы можете проверить его состояние во время выполнения с помощью sys.flags:

$ python -d
Python 2.7.15+ (default, Nov 27 2018, 23:36:35) 
[GCC 7.3.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.flags
sys.flags(debug=1, py3k_warning=0, division_warning=0, ...)
#         ^ there it is, right at the front

, что позволяет включить следующую отладку для включения отладки:

import pdb, sys; pdb.set_trace() if sys.flags[0] else None

Отключение условных точек останова от отладчика

Относительно этой части

[...] как только я буду рад, что его не нужно останавливать где-либо еще, тогда выполните [что-то], что не остановит его на второй или других подобных строках точки останова в коде.

все же становится немного сложнее, поскольку python не допускает мутации flags структуры и даже не создает ее экземпляр:

>>> import sys
>>> sys.flags.debug = 0                 # no mutating ...
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: readonly attribute
>>> type(sys.flags)()                   # ... and no instanciating
Traceback (most recent call last):
  File "<input>", line 1, in <module>
TypeError: cannot create 'sys.flags' instances

Но, насколько я тестировал, если вы не запускаете python с другими флагами, следующие действия работают для деактивации последующих трассировок без изменения другого поведения вашей программы:

import sys; sys.flags = [0]*len(sys.flags)  # even fits onto a single line

Для чуть более надежногоэто обезьяна патчВы должны использовать в случае, если первая приводит к странным ошибкам, вам нужно иметь что-то вроде этого:

def untrace():
  """Call this function in the pdb session to skip debug-only set_trace() calls"""
  import re
  import sys
  from collections import namedtuple  # has the same interface as struct sequence
  sys.flags = namedtuple(
    'sys_flags', 
    [m.group() for m in re.finditer(r'\w{2,}', repr(sys.flags)[10:-1])]
  )(0, *sys.flags[1:])

Хотя это утверждение можно поместить в одну строку, этовероятно, слишком много.Вы можете вставить эту функцию в файл .py, в котором вы планируете ее использовать, или иметь какой-то utils.py, из которого вы импортируете ее во время отладки, после чего ac (продолжение) должен снова запустить остальную часть программы:

(Pdb) import utils; utils.untrace()
(Pdb) c
4 голосов
/ 16 июня 2019

Вот простой способ использования файла .pdbrc в текущем каталоге:

t.py

def my_trace():
    global debug
    if debug:
        import pdb; pdb.set_trace()

debug = True
a= 1
my_trace()
b = 2
c = 3
my_trace()
d = 4

.pdbrc

r

Пример сеанса :

$ python t.py
--Return--
> [...]/t.py(12)<module>()
-> b = 2
(Pdb) p a
1
(Pdb) p b
*** NameError: name 'b' is not defined
(Pdb) !debug=False
(Pdb) c
$ 
...