Python-сообщество
- Начало
- » Python для новичков
- » Прерывание скрипта и повторный запуск
#1 Дек. 13, 2022 02:56:43
robisho Зарегистрирован: 2020-10-19 Сообщения: 60 Репутация: 2 Профиль Отправить e-mail
Прерывание скрипта и повторный запуск
Добрый день. Задача такая: при работе скрипта нужно его остановить, а затем продолжить выполнение с того же места остановки. Например, при парсинге или массовой отправки сообщений smtp. Т.е. структура, я думаю, будет одна: из списка берется url или email и обрабатывается в функции парсинга/smtp. Нужно при остановке скрипта дать функции парсинга/smtp завершиться и остановиться на выдаче очередного url/email, а при повторном запуске начать с точки останова. Подскажите, пожалуйста, как это можно осуществить? Интересуют все возможные теории/названия/библиотеки. Спасибо.
#2 Дек. 13, 2022 04:23:02
py.user.next От: Зарегистрирован: 2010-04-29 Сообщения: 9629 Репутация: 839 Профиль Отправить e-mail
Прерывание скрипта и повторный запуск
robisho
Подскажите, пожалуйста, как это можно осуществить?
Можно сделать по принципу, который есть у браузеров и программ для закачки. Когда она закачивает, она регистрирует все закачанные части. При её остановке остаются эти файлы, в которых записано то последнее, что закачалось. При новом запуске она ищет эти файлы, в которых записано, что там было до этого запуска, и по ним действует дальше, так же их меняя.
robisho
Нужно при остановке скрипта дать функции парсинга/smtp завершиться и остановиться на выдаче очередного url/email
При сигнале остановки программа должна доделать задачу и выйти из-за того, что был получен этот сигнал остановки. Ну, ты получаешь сигнал, устанавливаешь флажок, что был получен сигнал, а в конце цикла этот флажок проверяется.
Я такой закачник делал, я очень много накачал им в итоге. У него в текстовый файл можно было занести сотню ссылок и он помечал каждую (закачивалась она или не закачивалась), всегда можно было залезть в этот файл и пометить какую-нибудь закачанную ссылку, что она не закачана, и она тогда по новой качалась. При этом при закачке эти недокачанные файлы сохранялись под специальными именами на основе md5-хешей, чтобы они все были уникальными, а после закачки этих файлов, которая могла быть продолжена через несколько дней, через неделю, через месяц, эти хеши срезались просто и в конечных именах их не было уже. То есть они ставились автоматически только на то время, пока файл скачался не полностью, а потом так же автоматически убирались, когда он был докачан полностью. Интересно это всё было, и оно работало как часы. Действительно, можно было десятки фильмов тяжёлых качать одновременно, сериалы там всякие с кучей серий в хорошем качестве, и они не перемешивались вообще никак, а качать я там мог их целую неделю или даже больше. Вот эти хеши давали возможность не беспокоиться за совпадающие имена, которые там иногда появлялись у разных фильмов и серий.
Отредактировано py.user.next (Дек. 13, 2022 04:25:18)
#3 Дек. 13, 2022 05:57:46
robisho Зарегистрирован: 2020-10-19 Сообщения: 60 Репутация: 2 Профиль Отправить e-mail
Прерывание скрипта и повторный запуск
py.user.next
спасибо за идеи) ну у меня не такая глобальная задача будет, нужно будет просто ставить скрипт на паузу в течении одной сессии терминала или стопить. сохранять состояния, думаю не надо.
а каким образом можно реализовать получение сигнала остановки?
например,
цикл for - выдает ссылки: проверка нажатия клавиши P проверка нажатия клавиши S тело функции проверка нажатия клавиши P проверка нажатия клавиши S
а по поводу сохранения ссылок думаю так: индекс ссылки, выданной из for, сохраняется в global temp, и после паузы список редактируется на
[temp+1:]
Отредактировано robisho (Дек. 13, 2022 06:06:53)
Запуск python-скрипта в Windows по расписанию
Как настроить запуск python-скрипта в Windows по расписанию?
admin Админ. ответил 2 года назад
Прежде всего необходимо создать файл с расширением bat.
В этом файле написать следующий код:
C:\Users\user\PycharmProjects\venv\Scripts\python.exe C:\Users\user\PycharmProjects\avtozapusk\citaty.py pause
Где мы сначала указываем путь, где находится python, далее путь к скрипту, который хотим запускать.
Следующая строка — это команда pause — остановка командной строки.
После этого идем в Планировщик заданий, в который можно попасть через Пуск.
В Планировщике заданий наводим мышкой на Библиотеку планировщика и кликаем правой кнопкой мыши, чтобы появилось меню. Там выбираем пункт: Создать простую задачу…

В появившемся окне зададим имя скрипту, а также, если есть желание, описание. После чего кликаем на кнопку Далее.

В следующем окне выберем как часто хотим запускать наш скрипт, в нашем случае выберем ежедневно. И вновь жамкаем на кнопку Далее.

На следующем шаге укажем время, в которое хотим запускать наш python-скрипт.

Выберем какую задачу хотим выполнить, в нашем примере — это Запустить программу.

В следующем окне укажем, расположение созданного нами файл с расширением .bat.

И в последнем окне кликаем на кнопку «Готово!»

На этом все. Если возникнуть сложности или остались вопросы — пишите в комментариях.
pdb — Отладчик Python¶
Модуль pdb определяет интерактивный источник отладчик код для программ Python. Она поддерживает установку (условных) точек останова и одиночное пошаговое выполнение на уровне исходной строки, проверку кадров стека, перечисление исходного кода и оценку произвольного Python код в контекст любого стека фрейм. Он также поддерживает отладку после крущения и может вызываться под управлением программы.
Отладчик является расширяемым и фактически определяется как класс Pdb . Это в настоящее время не имеет документов, но легко понять, прочитав источник. Интерфейс расширения использует модули bdb и cmd .
Приглашение отладчика (Pdb) . Типичное использование для запуска программы под управлением отладчика::
>>> import pdb >>> import mymodule >>> pdb.run('mymodule.test()') > (0)?() (Pdb) continue > (1)?() (Pdb) continue NameError: 'spam' > (1)?() (Pdb)
Изменено в версии 3.3: Tab-завершение (Tab-completion) через модуль readline доступен для команд и аргументов команд, например, текущие глобальные и локальная имена предлагаются в качестве аргументов команды p .
pdb.py также может быть вызван как сценарий для отладки других сценариев. Например:
python3 -m pdb myscript.py
При вызове в качестве сценария pdb автоматически вводит послепоторную отладку, если отлаживаемая программа выходит из ненормального режима. После посмертной отладки (или после нормального выхода из программы) pdb перезапустит программу. Автоматический перезапуск сохраняет состояние pdb (например, точки останова) и в большинстве случаев более полезен, чем выход из отладчика при выходе программы.
Добавлено в версии 3.2: pdb.py теперь принимает параметр -c , который выполняет команды, как если бы они были заданы в файле .pdbrc , см. раздел Команды отладчика .
Добавлено в версии 3.7: Теперь pdb.py принимает опцию -m , которая выполняет модули аналогично тому, как это делает python3 -m . Как и в случае со сценарием, отладчик приостановит выполнение непосредственно перед первой строкой модуля.
Типичное использование для прерывания отладчика из запущенной программы — вставка:
import pdb; pdb.set_trace()
в том месте, где вы хотите прервать отладчик. Вы можете тогда ступить через код после этого инструкция и продолжить бежать без отладчика, используя команду continue .
Добавлено в версии 3.7: Встроенный breakpoint() , когда его называют с дефолтами, может быть используемый вместо import pdb; pdb.set_trace() .
Типичное использование для проверки поврежденной программы::
>>> import pdb >>> import mymodule >>> mymodule.test() Traceback (most recent call last): File "", line 1, in File "./mymodule.py", line 4, in test test2() File "./mymodule.py", line 3, in test2 print(spam) NameError: spam >>> pdb.pm() > ./mymodule.py(3)test2() -> print(spam) (Pdb)
Модуль определяет следующие функции: каждый входит в отладчик несколько по- другому:
pdb. run ( statement, globals=None, locals=None ) ¶
Выполнить команду statement (заданную как строка или код объект) под управлением отладчика. Перед выполнением любого код появляется приглашение отладчика; можно установить точки останова и ввести continue , либо перейти через инструкция с помощью step или next (все эти команды описаны ниже). Необязательные аргументы globals и locals определяют среду, в которой выполняется код; по умолчанию словарь модуля __main__ является используемый. (См. описание встроенных функций exec() или eval() .
pdb. runeval ( expression, globals=None, locals=None ) ¶
Вычислите expression (заданный как строка или код объект) под управлением отладчика. Когда runeval() возвращает, это возвращает значение выражения. В противном случае эта функция аналогична функции run() .
Вызовите function (функцию или объект метода, а не строка) с заданными аргументами. Когда runcall() возвращает, это возвращает то, что функция называет возвращенный. Запрос отладчика появляется сразу после ввода функции.
Введите отладчик в вызывающем стеке фрейм. Это полезно для трудно-код контрольной точки в данной точке в программе, даже если код иначе не отлаживается (например, когда утверждение терпит неудачу). Если задано, header печатается на консоли непосредственно перед началом отладки.
Изменено в версии 3.7: Только ключевой аргумент header.
pdb. post_mortem ( traceback=None ) ¶
Введите посмертную отладку данного объекта traceback. Если traceback не задан, используется одно из обрабатываемых в настоящее время исключений (если по умолчанию используется используемый).
Введите посмертную отладку трейсбэк, найденных в sys.last_traceback .
Функции run* и set_trace() являются псевдонимами для создания экземпляра класса Pdb и вызова метода с тем же именем. Если вы хотите получить доступ к другим функциям, вы должны сделать это самостоятельно:
class pdb. Pdb ( completekey=’tab’, stdin=None, stdout=None, skip=None, nosigint=False, readrc=True ) ¶
Аргументы completekey, stdin и stdout передаются базовому классу cmd.Cmd ; см. описание.
Аргументом skip, если дали, должны быть повторяемые из шаблонов имени модуля glob-style. Отладчик не будет переходить к кадрам, созданным в модуле, соответствующем одному из этих шаблонов. [1]
По умолчанию Pdb устанавливает обработчик для сигнала SIGINT (который посылается при нажатии пользователем кнопки Ctrl-C на консоли) при выполнении команды continue . Это позволяет снова прервать отладчик нажатием клавиши Ctrl-C . Если вы хотите, чтобы Pdb не тронул SIGINT обработчик, установите nosigint в истинный.
Аргумент readrc по умолчанию имеет значение true и определяет, будет ли PDB загружать файлы .pdbrc из файловой системы.
Пример вызова для включения трассировки с помощью skip:
import pdb; pdb.Pdb(skip=['django.*']).set_trace()
Raises an auditing event pdb.Pdb with no arguments.
Добавлено в версии 3.1: Аргумент skip.
Добавлено в версии 3.2: Аргумент nosigint. Ранее, SIGINT обработчик никогда не устанавливался Pdb.
Изменено в версии 3.6: Аргумент readrc.
run ( statement, globals=None, locals=None ) ¶ runeval ( expression, globals=None, locals=None ) ¶ runcall ( function, *args, **kwds ) ¶ set_trace ( ) ¶
См. документацию по функциям, описанным выше.
Команды отладчика¶
Ниже перечислены команды, распознаваемые отладчиком. Большинство команд может быть сокращено до одной или двух букв, как указано; например, h(elp) означает, что или h или help могут быть используемый, чтобы войти в команду помощи (но не he или hel , ни H или Help или HELP ). Аргументы команд должны разделяться пробелами (пробелами или табуляциями). Необязательные аргументы заключены в квадратные скобки ( [] ) в синтаксисе команды; не следует вводить квадратные скобки. Альтернативные варианты в синтаксисе команд разделены вертикальной полосой ( | ).
Ввод пустой строки повторяет последнюю введенную команду. Исключение: если последней командой была команда list , перечисляются следующие 11 строк.
Команды, которые отладчик не распознает, считаются Python инструкции и выполняются в контекст отлаживаемой программы. Python инструкции также может иметь префикс восклицательного знака ( ! ). Это мощный способ проверки отлаживаемой программы; можно даже изменить переменную или вызвать функцию. Когда в такой инструкция возникает исключение, имя исключения печатается, но состояние отладчика не изменяется.
Отладчик поддерживает алиасы . Псевдонимы могут иметь параметры, обеспечивающие определенный уровень адаптируемости к исследуемому контекст.
Несколько команд могут быть введены в одной строке, разделенной ;; . (Единственный ; не используемый, как это — сепаратор для нескольких команд в линии, которая передана к Python парсер.) для разделения команд не применяется интеллект; вход разделен в первой паре ;; , даже если это посреди указанной строки.
Если файл .pdbrc существует в домашнем каталоге пользователя или в текущем каталоге, он считывается и выполняется, как если бы он был введен в ответ на запрос отладчика. Это особенно полезно для псевдонимов. При наличии обоих файлов сначала считывается файл в домашнем каталоге, а определенные псевдонимы могут быть переопределены файлом локальная.
Изменено в версии 3.2: Теперь .pdbrc может содержать команды, которые продолжают отладку, например continue или next . Ранее эти команды не имели эффекта.
h (elp) [команда] ¶
Без аргументов распечатайте список доступных команд. С аргументом command как напечатайте справку об этой команде. На help pdb отображается полная документация (докстринг модуля pdb ). Поскольку аргумент command должен быть идентификатором, необходимо ввести help exec , чтобы получить справку по команде ! .
Печать трассировки стека с самыми последними фрейм внизу. Стрелка указывает текущую фрейм, которая определяет контекст большинства команд.
Переместите текущие уровни фрейм count (по умолчанию) вниз в трассировке стека (на более новый фрейм).
Переместите текущий уровень фрейм count (по умолчанию) вверх в трассировке стека (на более старый фрейм).
b (reak) [([имя файла:] lineno | функция) [, условие]] ¶
С помощью аргумента lineno установите разрыв в текущем файле. С аргументом function, набор разрыв в первом выполнимом инструкция в той функции. Номер строки может иметь префикс с именем файла и двоеточием для указания точки останова в другом файле (возможно, еще не загруженном). Файл — найденный на sys.path . Следует отметить, что каждой точке останова присваивается номер, на который ссылаются все остальные команды точки останова.
Если присутствует второй аргумент, он является выражением, которое должно быть вычислено как true, прежде чем точка останова будет учтена.
Без аргументов перечислите все разрывы, в том числе для каждой точки останова, количество попаданий в эту точку останова, текущее число игнорирования и связанное условие, если оно имеется.
tbreak [([имя файла:] lineno | функция) [, условие]] ¶
Временная точка останова, которая удаляется автоматически при первом попадании. Аргументы те же, что и для break .
cl (ear) [имя файла: lineno | bpnumber [bpnumber. ]] ¶
С помощью аргумента filename:lineno очистите все точки останова в этой строке. С помощью списка номеров точек останова, разделенных пробелами, очистите эти точки останова. Без аргументов очистите все разрывы (но сначала спросите подтверждение).
disable [bpnumber [bpnumber. ]] ¶
Отключить точки останова, заданные в виде разделенного пробелом списка номеров точек останова. Отключение точки останова означает, что она не может привести к остановке выполнения программы, но в отличие от очистки точки останова, она остается в списке точек останова и может быть (повторно) включена.
enable [bpnumber [bpnumber. ]] ¶
Включить указанные точки останова.
ignore bpnumber [count] ¶
Установите счетчик игнорирования для данного номера точки останова. Если значение счетчика опущено, значение счетчика игнорирования равно 0. Точка останова становится активной, когда счетчик игнорирования равен нулю. При ненулевом значении счетчик уменьшается каждый раз, когда достигается точка останова, и точка останова не отключается, и любое связанное условие вычисляется как true.
condition bpnumber [condition] ¶
Установить new condition для точки останова, выражение, которое должно вычислять значение true перед тем, как точка останова будет обработана. Если condition отсутствует, любое существующее условие снимается; то есть точка останова делается безусловной.
Укажите список команд для номера точки останова bpnumber. Сами команды отображаются в следующих строках. Введите строку, содержащую только end , чтобы завершить команды. Пример:
(Pdb) commands 1 (com) p some_variable (com) end (Pdb)
Чтобы удалить все команды из точки останова, введите commands и немедленно следуйте ей вместе с end ; то есть не давать команд.
Без аргумента bpnumber commands относится к последнему набору контрольной точки.
Для повторного запуска программы можно использовать команды точки останова. Просто используйте команду continue , или step , или любую другую команду, которая возобновляет выполнение.
Определение любого выполнения возобновления команды (в настоящее время continue , step , next , return , jump , quit и их сокращения) заканчивает список команды (как будто та команда немедленно сопровождалась к концу). Это связано с тем, что при каждом возобновлении выполнения (даже при простом следующем или шаге) может возникнуть другая точка останова, которая может иметь свой собственный список команд, что приведет к двусмысленностям относительно того, какой список выполнять.
При использовании команды «silent» в списке команд обычное сообщение об остановке в точке останова не печатается. Это может быть желательно для точек останова, которые должны распечатать конкретное сообщение и затем продолжить. Если ни одна из других команд ничего не напечатает, вы не увидите признаков достижения точки останова.
Выполнить текущую строку, остановитесь в первом возможном случае (либо в функции, которая вызывается, либо в следующей строке текущей функции).
Продолжите выполнение, пока следующая строка в текущей функции не будет достигнута или оно возвращает. (Разница между next и step заключается в том, что step останавливается внутри вызываемой функции, в то время как next выполняет вызываемые функции на (почти) полной скорости, останавливаясь только на следующей строке в текущей функции.
Без аргументов продолжайте выполнение до тех пор, пока не будет достигнута строка с числом, превышающим текущее.
С номером строки продолжайте выполнение до тех пор, пока не будет достигнута строка с числом, большим или равным этому. В обоих случаях также остановитесь, когда текущая фрейм возвращает.
Изменено в версии 3.2: Разрешить указание явного номера строки.
Продолжайте выполнение до текущей функции возвращает.
Продолжение выполнения, остановка только при обнаружении точки останова.
Установите следующую строку, которая будет выполнена. Доступно только в самом нижнем фрейм. Это позволяет перейти назад и выполнить код снова, или перейти вперед, чтобы пропустить код, которые вы не хотите запускать.
Следует отметить, что не все прыжки разрешены – для сущность невозможно прыгнуть в середину петли for или из finally клаузула.
l(ist) [first[, last]] ¶
Список исходного кода для текущего файла. Без аргументов перечислите 11 строк вокруг текущей строки или продолжите предыдущее объявление. С аргументом . в качестве аргумента перечислите 11 строк вокруг текущей строки. С одним аргументом перечислите 11 строк вокруг этой строки. С двумя аргументами перечислите заданный диапазон; если второй аргумент меньше первого, он интерпретируется как счетчик.
Текущая строка в текущем фрейм обозначается символом -> . Если происходит отладка исключения, строка, в которой это исключение было первоначально вызвано или распространено, обозначается как >> , если оно отличается от текущей строки.
Добавлено в версии 3.2: Маркер >> .
ll | longlist ¶
Перечислите все исходные код для текущей функции или фрейм. Интересные строки отмечены как для list .
Добавлено в версии 3.2.
Печать списка аргументов текущей функции.
Оцените expression в текущем контекст и распечатайте его значение.
print() также может быть используемый, но не является командой отладчика — это выполняет функцию Python print() .
pp expression ¶
Как команда p , кроме значение выражения довольно напечатан, используя модуль pprint .
Печать типа expression.
Попытайтесь получить источник код для данного объекта и показать его.
Добавлено в версии 3.2.
display [expression] ¶
Покажите значение выражения, если это изменилось, каждый раз остановки выполнения в текущем фрейм.
Без выражения, список все выражения дисплея для текущего фрейма.
Добавлено в версии 3.2.
undisplay [expression] ¶
Больше не отображать выражение в текущем фрейм. Без выражения, четкого все выражения дисплея для текущего фрейм.
Добавлено в версии 3.2.
Запустите интерактивное интерпретатор (с помощью модуля code ), глобальное пространство имен которого содержит все (глобальные и локальная) имена, найденные в текущем область видимости.
Добавлено в версии 3.2.
alias [name [command]] ¶
Создайте алиас с именем name, который выполняет command. Команда не должна быть приложенной в кавычках. Заменяемые параметры могут обозначаться буквами %1 , %2 и так далее, в то время как %* заменяется всеми параметрами. Если команда не задана, отображается текущее значение алиас для name. Если аргументы не заданы, перечисляются все псевдонимы.
Псевдонимы могут быть вложенными и содержать все, что можно легально ввести в ответ на запрос pdb. Обратите внимание, что внутренний pdb приказывает, чтобы can были отвергнуты псевдонимами. Такая команда тогда скрыта, пока алиас не удален. Псевдоним рекурсивно применяется к первому слову командной строки; все остальные слова в строке остаются в покое.
В качестве примера можно привести два полезных псевдонима (особенно при размещении в файле .pdbrc ):
# Распечатать переменную экземпляра (использование "pi classInst") alias pi for k in %1.__dict__.keys(): print("%1.",k,"=",%1.__dict__[k]) # Напечатать переменные экземпляра в self alias ps pi self
unalias name ¶
Удаление указанного алиаса.
Выполнить (однострочный) statement в контексте текущего стека фрейма. Восклицательный знак может быть опущен, если первое слово инструкция не напоминает команду отладчику. Чтобы установить глобальную переменную, Вы можете снабдить префиксом команду назначения global инструкции на той же строке, например.:
(Pdb) global list_options; list_options = ['-l'] (Pdb)
run [args . ] ¶ restart [args . ] ¶
Перезапустить отлаженную программу Python. Если аргумент указан, он разделяется на shlex , и результат является используемый в качестве нового sys.argv . История, точки останова, действия и параметры отладчика сохраняются. restart является алиас для run .
Выход из отладчика. Выполняемая программа прерывается.
Введите рекурсивный отладчик, проходящий через аргумент код (который является произвольным выражением или инструкция, выполняемым в текущей среде).
Печать возвращаемого значения для последнего возвращения функции.
| [1] | Считается ли фрейм источником в определенном модуле, определяется __name__ в фрейме глобалов (globals). |
Использование и вызов¶
Тестирование можно запустить из командной строки интерпретатора Python , используя команду:
python -m pytest [. ]
В отличие от запуска напрямую командой pytest [. ] , запуск через Python добавит текущий каталог в sys.path .
Статусы завершения¶
Выполнение pytest может генерировать один из следующих статусов завершения:
Все тесты были собраны и успешно прошли
Тесты были собраны и запущены, но некоторые из них упали
Выполнение тестов было прервано пользователем
Во время выполнения тестов произошла внутренняя ошибка
Ошибка запуска pytest из командной строки
Не удалось собрать тесты (тесты не найдены)
Коллекция статусов представлена перечислением _pytest.config.ExitCode. Статусы завершения являются частью публичного API, их можно импортировать и использовать непосредственно:
from pytest import ExitCode
Для настройки кода завершения сценария, особенно когда тесты не удалось собрать, можно использовать плагин pytest-custom_exit_code.
Получение помощи по версии, параметрам, переменным окружения¶
pytest --version # показывает версию и место, откуда импортирован ``pytest`` pytest --fixtures # показывает доступные встроенные функции pytest -h | --help # показывает помощь по командной строке и параметры конфигруационного файла
Остановка после первых N падений¶
Чтобы остановить процесс тестирования после первых N падений, используются параметры:
pytest -x # остановка после первого упавшего теста pytest --maxfail=2 # остановка после первых двух упавших тестов
Выбор выполняемых тестов¶
pytest поддерживает несколько способов выбора и запуска тестов из командной строки.
Запуск тестов модуля
pytest test_mod.py
Запуск тестов из директории
pytest testing/
Запуск тестов, удовлетворяющих ключевому выражению
pytest -k "MyClass and not method"
Эта команда запустит тесты, имена которых удовлетворяют заданному строковому выражению (без учета регистра). Строковые выражения могут включать операторы Python , которые используют имена файлов, классов и функций в качестве переменных. В приведенном выше примере будет запущен тест MyClass.test_something , но не будет запущен тест TestMyClass.test_method_simple .
Запуск тестов по идентификаторам узлов
Каждому собранному тесту присваивается уникальный идентификатор nodeid , который состоит из имени файла модуля, за которым следуют спецификаторы, такие как имена классов, имена функций и параметры из параметризации, разделенные символами :: :
Чтобы запустить конкретный тест из модуля, выполните:
pytest test_mod.py::test_func
Еще один пример спецификации тестового метода в командной строке:
pytest test_mod.py::TestClass::test_method
Запуск маркированных тестов
pytest -m slow
Будут запущены тесты, помеченные декоратором @pytest.mark.slow .
Запуск тестов из пакетов
pytest --pyargs pkg.testing
Будет импортирован пакет pkg.testing , и его расположение в файловой системе будет использовано для поиска и запуска тестов.
Изменение вывода сообщений трассировки¶
pytest --showlocals # показывать локальные переменные в сообщениях pytest -l # показывать локальные переменные в сообщениях (краткий вариант) pytest --tb=auto # (по умолчанию) "расширенный" вывод для первого и # последнего сообщений, и "короткий" для остальных pytest --tb=long # исчерпывающий, подробный формат сообщений pytest --tb=short # сокращенный формат сообщений pytest --tb=line # только одна строка на падение pytest --tb=native # стандартный формат библиотеки Python pytest --tb=no # никаких сообщений
Использование —full-trace приводит к тому, что при ошибке печатаются очень длинные трассировки (длиннее, чем при —tb=long ). Параметр также гарантирует, что сообщения трассировки будут напечатаны при прерывании выполнения c клавиатуры с помощью Ctrl+C. Это очень полезно, если тесты занимают слишком много времени, и вы прерываете их с клавиатуры с помощью Ctrl+C, чтобы узнать, где они зависли. По умолчанию при прерывании вывод не будет показан (поскольку исключение KeyboardInterrupt будет поймано pytest ). Используя этот параметр, вы можете быть уверены, что увидите трассировку.
Детализация сводного отчета¶
Флаг -r можно использовать для отображения «краткой сводной информации по тестированию» в конце тестового сеанса, что упрощает получение четкой картины всех сбоев, пропусков, xfails и т. д.
По умолчанию для списка сбоев и ошибок используется добавочная комбинация fE .
# content of test_example.py import pytest @pytest.fixture def error_fixture(): assert 0 def test_ok(): print("ok") def test_fail(): assert 0 def test_error(error_fixture): pass def test_skip(): pytest.skip("skipping this test") def test_xfail(): pytest.xfail("xfailing this test") @pytest.mark.xfail(reason="always xfail") def test_xpass(): pass
$ pytest -ra =========================== test session starts ============================ platform linux -- Python 3.x.y, pytest-5.x.y, py-1.x.y, pluggy-0.x.y cachedir: $PYTHON_PREFIX/.pytest_cache rootdir: $REGENDOC_TMPDIR collected 6 items test_example.py .FEsxX [100%] ================================== ERRORS ================================== _______________________ ERROR at setup of test_error _______________________ @pytest.fixture def error_fixture(): > assert 0 E assert 0 test_example.py:6: AssertionError ================================= FAILURES ================================= ________________________________ test_fail _________________________________ def test_fail(): > assert 0 E assert 0 test_example.py:14: AssertionError ========================= short test summary info ========================== SKIPPED [1] $REGENDOC_TMPDIR/test_example.py:22: skipping this test XFAIL test_example.py::test_xfail reason: xfailing this test XPASS test_example.py::test_xpass always xfail ERROR test_example.py::test_error - assert 0 FAILED test_example.py::test_fail - assert 0 == 1 failed, 1 passed, 1 skipped, 1 xfailed, 1 xpassed, 1 error in 0.12s ===
Параметр -r принимает ряд символов после себя. Использованный выше символ а означает “все, кроме успешных».
Вот полный список доступных символов, которые можно использовать:
- f — упавшие (добавляет раздел FAILED)
- E — ошибки (добавляет раздел ERROR)
- s — пропущенные (добавляет раздел SKIPPED)
- x — тесты XFAIL (добавляет раздел XFAIL)
- X — тесты XPASS (добавляет раздел XPASS)
- p — успешные (passed)
- P — успешные (passed) с выводом
Есть и специальные символы для пропуска отдельных групп:
- a — выводить все, кроме pP
- A — выводить все
- N — ничего не выводить (может быть полезным, поскольку по умолчанию используется комбинация fE ).
Можно использовать более одного символа. Например, для того, чтобы увидеть только упавшие и пропущенные тесты, можно выполнить:
$ pytest -rfs =========================== test session starts ============================ platform linux -- Python 3.x.y, pytest-5.x.y, py-1.x.y, pluggy-0.x.y cachedir: $PYTHON_PREFIX/.pytest_cache rootdir: $REGENDOC_TMPDIR collected 6 items test_example.py .FEsxX [100%] ================================== ERRORS ================================== _______________________ ERROR at setup of test_error _______________________ @pytest.fixture def error_fixture(): > assert 0 E assert 0 test_example.py:6: AssertionError ================================= FAILURES ================================= ________________________________ test_fail _________________________________ def test_fail(): > assert 0 E assert 0 test_example.py:14: AssertionError ========================= short test summary info ========================== FAILED test_example.py::test_fail - assert 0 SKIPPED [1] $REGENDOC_TMPDIR/test_example.py:22: skipping this test == 1 failed, 1 passed, 1 skipped, 1 xfailed, 1 xpassed, 1 error in 0.12s ===
Использование p добавляет в сводный отчет успешные тесты, а P добавляет дополнительный раздел «пройдены” (PASSED) для тестов, которые прошли, но перехватили вывод:
$ pytest -rpP =========================== test session starts ============================ platform linux -- Python 3.x.y, pytest-5.x.y, py-1.x.y, pluggy-0.x.y cachedir: $PYTHON_PREFIX/.pytest_cache rootdir: $REGENDOC_TMPDIR collected 6 items test_example.py .FEsxX [100%] ================================== ERRORS ================================== _______________________ ERROR at setup of test_error _______________________ @pytest.fixture def error_fixture(): > assert 0 E assert 0 test_example.py:6: AssertionError ================================= FAILURES ================================= ________________________________ test_fail _________________________________ def test_fail(): > assert 0 E assert 0 test_example.py:14: AssertionError ================================== PASSES ================================== _________________________________ test_ok __________________________________ --------------------------- Captured stdout call --------------------------- ok ========================= short test summary info ========================== PASSED test_example.py::test_ok == 1 failed, 1 passed, 1 skipped, 1 xfailed, 1 xpassed, 1 error in 0.12s ===
Запуск отладчика PDB (Python Debugger) при падении тестов¶
python содержит встроенный отладчик PDB (Python Debugger). pytest позволяет запустить отладчик с помощью параметра командной строки:
pytest --pdb
Использование параметра позволяет запускать отладчик при каждом падении теста (или прерывании его с клавиатуры). Часто хочется сделать это для первого же упавшего теста, чтобы понять причину его падения:
pytest -x --pdb # вызывает отладчик при первом падении и завершает тестовую сессию pytest --pdb --maxfail=3 # вызывает отладчик для первых трех падений
Обратите внимание, что при любом падении информация об исключении сохраняется в sys.last_value , sys.last_type и sys.last_traceback . При интерактивном использовании это позволяет перейти к отладке после падения с помощью любого инструмента отладки. Можно также вручную получить доступ к информации об исключениях, например:
>>> import sys >>> sys.last_traceback.tb_lineno 42 >>> sys.last_value AssertionError('assert result == "ok"',)
Запуск отладчика PDB (Python Debugger) в начале теста¶
pytest позволяет запустить отладчик сразу же при старте каждого теста. Для этого нужно передать следующий параметр:
pytest --trace
В этом случае отладчик будет вызываться при запуске каждого теста.
Установка точек останова¶
Чтобы установить точку останова, вызовите в коде import pdb;pdb.set_trace() , и pytest автоматически отключит перехват вывода для этого теста, при этом:
- на перехват вывода в других тестах это не повлияет;
- весь перехваченный ранее вывод будет обработан как есть;
- перехват вывода возобновится после завершения отладочной сессии (с помощью команды continue ).
Использование встроенной функции breakpoint¶
Python 3.7 содержит встроенную функцию breakpoint() . pytest поддерживает использование breakpoint() следующим образом:
- если вызывается breakpoint() , и при этом переменная PYTHONBREAKPOINT установлена в значение по умолчанию, pytest использует расширяемый отладчик PDB вместо системного;
- когда тестирование будет завершено, система снова будет использовать отладчик Pdb по умолчанию;
- если pytest вызывается с опцией —pdb то расширяемый отладчик PDB используется как для функции breakpoint() , так и для упавших тестов/необработанных исключений;
- для определения пользовательского класса отладчика можно использовать —pdbcls .
Профилирование продолжительности выполнения теста¶
Чтобы получить список 10 самых медленных тестов, выполните:
pytest --durations=10
По умолчанию, pytest не покажет тесты со слишком маленькой (менее одной сотой секунды) длительностью выполнения, если в командной строке не будет передан параметр -vv .
Модуль faulthandler ¶
Стандартный модуль faulthandler можно использовать для сброса трассировок Python при ошибке или по истечении времени ожидания.
При запуске pytest модуль автоматически подключается, если только в командной строке не используется опция -p no:faulthandler .
Кроме того, для сброса трассировок всех потоков в случае, когда тест длится более X секунд, можно использовать опцию faulthandler_timeout=X (для Windows неприменима).
Эта функциональность была интегрирована из внешнего плагина pytest-faulthandler с двумя небольшими изменениями:
- чтобы ее отключить, используйте -p no:faulthandler вместо —no-faulthandler ;
- опция командной строки —faulthandler-timeout превратилась в конфигурационную опцию faulthandler_timeout. Ее по-прежнему можно настроить из команндной строки, используя -o faulthandler_timeout=X .
Создание файлов формата JUnit¶
Чтобы создать результирующие файлы в формате, понятном Jenkins или другому серверу непрерывной интеграции, используйте вызов:
pytest --junitxml=path
Команда создает xml-файл по указанному пути.
Чтобы задать имя корневого xml-элемента для набора тестов, можно настроить параметр junit_suite_name в конфигурационном файле:
[pytest] junit_suite_name = my_suite
Спецификация JUnit XML, по-видимому, указывает, что атрибут «time» должен сообщать об общем времени выполнения теста, включая выполнение setup- и teardown- методов (1, 2). Это поведение pytest по умолчанию. Чтобы вместо этого сообщать только о длительности вызовов, настройте параметр junit_duration_report следующим образом:
[pytest] junit_duration_report = call
record_property¶
Чтобы записать дополнительную информацию для теста, используйте фикстуру record_property :
def test_function(record_property): record_property("example_key", 1) assert True
Такая запись добавит дополнительное свойство example_key=»1″ к сгенерированному тегу testcase :
classname="test_function" file="test_function.py" line="0" name="test_function" time="0.0009"> name="example_key" value="1" />
Эту функциональность также можно использовать совместно с пользовательскими маркерами:
# content of conftest.py def pytest_collection_modifyitems(session, config, items): for item in items: for marker in item.iter_markers(name="test_id"): test_id = marker.args[0] item.user_properties.append(("test_id", test_id))
# content of test_function.py import pytest @pytest.mark.test_id(1501) def test_function(): assert True
В файле получим:
classname="test_function" file="test_function.py" line="0" name="test_function" time="0.0009"> name="test_id" value="1501" />
Пожалуйста, обратите внимание, что использование этой возможности приведет к записи некорректного с точки зрения JUnitXML-схем последних версий файла и может вызывать проблемы при работе с некоторыми серверами непрерывной интеграции.
record_xml_attribute¶
Чтобы добавить дополнительный атрибут в элемент testcase , можно использовать фикстуру record_xml_attribute . Ее также можно использовать для переопределения существующих значений:
def test_function(record_xml_attribute): record_xml_attribute("assertions", "REQ-1234") record_xml_attribute("classname", "custom_classname") print("hello world") assert True
В отличие от record_property , дочерний элемент в данном случае не добавляется. Вместо этого в элемент testcase будет добавлен атрибут assertions=»REQ-1234″ , а значение атрибута classname по умолчанию будет заменено на «classname=custom_classname» :
classname="custom_classname" file="test_function.py" line="0" name="test_function" time="0.003" assertions="REQ-1234"> hello world
record_xml_attribute пока используется в режиме эксперимента, и в будущем может быть заменен чем-то более мощным и/или общим. Однако сама функциональность как таковая будет сохранена.
Использование record_xml_attribute поверх record_xml_property может быть полезным при парсинге xml-отчетов средствами непрерывной интеграции. Однако некоторые парсеры допускают не любые элементы и атрибуты. Многие инструменты (как в примере ниже), используют xsd-схему для валидации входящих xml. Поэтому убедитесь, что имена атрибутов, которые вы используете, являются допустимыми для вашего парсера.
Ниже представлена схема, которую использует Jenkins для валидации xml-отчетов:
name="testcase"> ref="skipped" minOccurs="0" maxOccurs="1"/> ref="error" minOccurs="0" maxOccurs="unbounded"/> ref="failure" minOccurs="0" maxOccurs="unbounded"/> ref="system-out" minOccurs="0" maxOccurs="unbounded"/> ref="system-err" minOccurs="0" maxOccurs="unbounded"/> name="name" type="xs:string" use="required"/> name="assertions" type="xs:string" use="optional"/> name="time" type="xs:string" use="optional"/> name="classname" type="xs:string" use="optional"/> name="status" type="xs:string" use="optional"/>
Пожалуйста, обратите внимание, что использование этой возможности приведет к записи некорректного с точки зрения JUnitXML-схем последних версий файла и может вызывать проблемы при работе с некоторыми серверами непрерывной интеграции.
Чтобы добавить свойства каждому тесту из набора, можно использовать фикстуру record_testsuite_property с параметром scope=»session» (в этом случае она будет применяться ко всем тестам тестовой сессии).
import pytest @pytest.fixture(scope="session", autouse=True) def log_global_env_facts(record_testsuite_property): record_testsuite_property("ARCH", "PPC") record_testsuite_property("STORAGE_TYPE", "CEPH") class TestMe: def test_foo(self): assert True
Этой фикстуре передаются имя ( name ) и значение ( value ) тэга , который добавляется на уровне тестового набора для генерируемого xml-файла:
errors="0" failures="0" name="pytest" skipped="0" tests="1" time="0.006"> name="ARCH" value="PPC"/> name="STORAGE_TYPE" value="CEPH"/> classname="test_me.TestMe" file="test_me.py" line="16" name="test_foo" time="0.000243663787842"/>
name должно быть строкой, а value будет преобразовано в строку и корректно экранировано.
В отличие от случаев использования record_property и record_xml_attribute созданный xml-файл будет совместим с последним стандартом xunit .
Создание файлов в формате resultlog¶
Для создания машиночитаемых логов в формате plain-text можно выполнить
pytest --resultlog=path
и просмотреть содержимое по указанному пути path . Эти файлы также используются ресурсом PyPy-test для отображения результатов тестов после ревизий.
Поскольку эта возможность редко используется, она запланирована к удалению в pytest 6.0 .
Если вы пользуетесь ею, рассмотрите возможность использования нового плагина pytest-reportlog .
Отправка отчетов на сервис pastebin¶
Создание ссылки для каждого упавшего теста:
pytest --pastebin=failed
Эта команда отправит информацию о прохождении теста на удаленный сервис регистрации и сгенерирует ссылку для каждого падения. Тесты можно отбирать как обычно, или, например, добавить -x , если вы хотите отправить данные по конкретному упавшему тесту.
Создание ссылки для лога тестовой сессии:
pytest --pastebin=all
В настоящее время реализовна регистрация только в сервисе http://bpaste.net.
Изменено в вресии 5.2
Если по каким-то причинам не удалось создать ссылку, вместо падения всего тестового набора генерируется предупреждение.
Подключение плагинов¶
В командной строке можно явно подгрузить какой-либо внутренний или внешний плагин, используя опцию -p :
pytest -p mypluginmodule
Опция принимает параметр name , который может быть:
- Полным именем модуля, записанным через точку, например myproject.plugins . Имя должно быть импортируемым.
- «Входным» именем плагина, которое передается в setuptools при регистрации плагина. К примеру, чтобы подгрузить pytest-cov , нужно использовать:
pytest -p pytest_cov
Отключение плагинов¶
Чтобы отключить загрузку определенных плагинов во время вызова, используйте опцию -p с префиксом no: .
Пример: чтобы отключить загрузку плагина doctest , который отвечает за выполнение тестов из строк «docstring», вызовите pytest следующим образом:
pytest -p no:doctest
Вызов pytest из кода Python¶
pytest можно вызвать прямо в коде Python:
pytest.main()
Такой способ эквивалентен вызову «pytest» из командной строки. В этом случае вместо исключения SystemExit возвращается статус завершения. Можно также передавать параметры и опции:
pytest.main(["-x", "mytestdir"])
Дополнительные плагины можно указать в pytest.main :
# content of myinvoke.py import pytest class MyPlugin: def pytest_sessionfinish(self): print("*** test run reporting finishing") pytest.main(["-qq"], plugins=[MyPlugin()])
Выполнив этот код, увидим, что MyPlugin был загружен и применен:
$ python myinvoke.py .FEsxX. [100%]*** test run reporting finishing ================================== ERRORS ================================== _______________________ ERROR at setup of test_error _______________________ @pytest.fixture def error_fixture(): > assert 0 E assert 0 test_example.py:6: AssertionError ================================= FAILURES ================================= ________________________________ test_fail _________________________________ def test_fail(): > assert 0 E assert 0 test_example.py:14: AssertionError
Вызов pytest.main() приводит к тому, что импортируются не только тесты, но и все модули, которые они используют. Из-за механизма кэширования импорта Python последующие вызовы pytest.main() из того же процесса не будут учитывать изменения в файлах, внесенные между вызовами. Поэтому не рекомендуется многократное использование pytest.main() в одном и том же процессе (например, при перезапуске тестов).
pytest
- Что такое pytest
- Установка
- Содержание
- Примеры
- Конфигурирование
- Лицензия
- Использование и вызов
- Вызов pytest с помощью python -m pytest
- Статусы завершения
- Получение помощи по версии, параметрам, переменным окружения
- Остановка после первых N падений
- Выбор выполняемых тестов
- Изменение вывода сообщений трассировки
- Детализация сводного отчета
- Запуск отладчика PDB (Python Debugger) при падении тестов
- Запуск отладчика PDB (Python Debugger) в начале теста
- Установка точек останова
- Использование встроенной функции breakpoint
- Профилирование продолжительности выполнения теста
- Модуль faulthandler
- Создание файлов формата JUnit
- record_property
- record_xml_attribute
Навигация:
- Оглавление
- Предыдущий раздел: Установка и запуск
- Следующий раздел: Использование pytest с существующими наборами тестов
Полезные ссылки
- pytest @ PyPI
- pytest @ GitHub
- 3rd party plugins
- Issue Tracker
- PDF Documentation
©2015–2020, holger krekel and pytest-dev team. | Powered by Sphinx 2.1.0 & Alabaster 0.7.12 | Page source
