Содержание страницы
29.5. warnings – Управление предупреждениями¶warnings – Warning control
Исходный код: Lib/warnings.py
Предупреждения обычно выводятся в ситуациях, когда полезно предупредить пользователя о некотором условии в программе, когда это условие (обычно) не требует возбуждения исключения и завершения программы. Например, может потребоваться выдать предупреждение, если программа использует устаревший модуль.
Разработчики на Python выводят предупреждения, вызывая функцию warn(), определённую
в этом модуле. (Разработчики на C используют PyErr_WarnEx(); см.
Обработка исключений для подробностей).
Предупреждения обычно выводятся в sys.stderr, но их поведение
можно гибко изменять – от полного игнорирования до превращения в
исключения. Поведение предупреждений может зависеть от категории предупреждения
(см. ниже), текста сообщения и местоположения источника, из которого оно
выдаётся. Повторные предупреждения из одного и того же источника обычно
подавляются.
Управление предупреждениями состоит из двух этапов: сначала каждый раз при выдаче предупреждения определяется, должно ли сообщение быть выдано; затем, если сообщение должно быть выдано, оно форматируется и выводится с помощью настраиваемого пользователем перехватчика.
Решение о выдаче предупреждения управляется
фильтром предупреждений – последовательностью правил сопоставления и действий. Правила можно
добавлять в фильтр вызовом filterwarnings() и сбрасывать в состояние по умолчанию
вызовом resetwarnings().
Вывод предупреждающих сообщений выполняется вызовом showwarning(), который
может быть переопределён; реализация по умолчанию этой функции форматирует
сообщение вызовом formatwarning(), который также доступен для использования в
пользовательских реализациях.
См. также
logging.captureWarnings() позволяет обрабатывать все предупреждения с помощью
стандартной инфраструктуры журналирования.
29.5.1. Категории предупреждений¶Warning Categories
Существует ряд встроенных исключений, представляющих категории предупреждений. Такая категоризация полезна для фильтрации групп предупреждений. В настоящее время определены следующие классы категорий предупреждений:
Класс |
Описание |
|---|---|
Это базовый класс всех классов
категорий предупреждений. Он является подклассом
|
|
Категория по умолчанию для |
|
Базовая категория для предупреждений об устаревших возможностях (по умолчанию игнорируется). |
|
Базовый тип для предупреждений о сомнительных синтаксических особенностях. |
|
Базовая категория для предупреждений о сомнительных возможностях времени выполнения. |
|
Базовая категория для предупреждений о конструкциях, которые в будущем изменят свою семантику. |
|
Базовая категория для предупреждений о возможностях, которые будут объявлены устаревшими в будущем (игнорируется по умолчанию). |
|
Базовая категория для предупреждений, возникающих в процессе импорта модуля (игнорируется по умолчанию). |
|
Базовая категория для предупреждений, связанных с Юникодом. |
|
Базовая категория для предупреждений, связанных с
|
|
Базовый класс для предупреждений, связанных с использованием ресурсов. |
Хотя технически это встроенные исключения, они документируются здесь, поскольку концептуально относятся к механизму предупреждений.
Пользовательский код может определять дополнительные категории предупреждений, создавая подкласс одной из
стандартных категорий предупреждений. Категория предупреждения всегда должна быть подклассом
класса Warning.
29.5.2. Фильтр предупреждений¶The Warnings Filter
Фильтр предупреждений управляет тем, игнорируются ли предупреждения, выводятся на экран или превращаются в ошибки (вызывают исключение).
Концептуально фильтр предупреждений поддерживает упорядоченный список спецификаций фильтра; каждое конкретное предупреждение последовательно сопоставляется с каждой спецификацией фильтра в списке, пока не будет найдено совпадение; совпадение определяет дальнейшие действия. Каждая запись представляет собой кортеж вида (action, message, category, module, lineno), где:
Действие – одна из следующих строк:
Значение
Действие
"error"превращать подходящие предупреждения в исключения
"ignore"никогда не выводить подходящие предупреждения
"always"всегда выводить подходящие предупреждения
"default"выводит первое появление соответствующих предупреждений для каждого места, где было выдано предупреждение
"module"выводит первое появление соответствующих предупреждений для каждого модуля, где было выдано предупреждение
"once"выводить только первое вхождение подходящих предупреждений, независимо от местоположения
message – это строка с регулярным выражением, которому должно соответствовать начало предупреждающего сообщения. Выражение компилируется с игнорированием регистра.
category – это класс (подкласс
Warning), подклассом которого должна быть категория предупреждения для совпадения.module – это строка с регулярным выражением, которому должно соответствовать имя модуля. Выражение компилируется с учётом регистра.
lineno – это целое число, которому должен соответствовать номер строки, где произошло предупреждение, или
0для соответствия всем номерам строк.
Поскольку класс Warning является наследником встроенного класса Exception, чтобы превратить предупреждение в ошибку, мы просто возбуждаем category(message).
Фильтр предупреждений инициализируется параметрами -W, переданными командной строке
интерпретатора Python. Интерпретатор сохраняет аргументы для всех
параметров -W без интерпретации в sys.warnoptions; модуль
warnings разбирает их при первом импорте (недопустимые параметры
игнорируются после вывода сообщения в sys.stderr).
29.5.2.1. Фильтры предупреждений по умолчанию¶Default Warning Filters
По умолчанию Python устанавливает несколько фильтров предупреждений, которые можно переопределить
с помощью параметров командной строки, переданных -W, и вызовов
filterwarnings().
DeprecationWarning,PendingDeprecationWarningиImportWarningигнорируются.BytesWarningигнорируется, если только параметр-bне указан один или два раза; в этом случае данное предупреждение либо выводится (-b), либо превращается в исключение (-bb).ResourceWarningигнорируется, если только Python не был собран в режиме отладки.
Изменено в версии 3.2: DeprecationWarning теперь по умолчанию игнорируется в дополнение к PendingDeprecationWarning.
29.5.3. Временное подавление предупреждений¶Temporarily Suppressing Warnings
Если используется код, который, как известно, вызовет предупреждение (например, устаревшая функция), но видеть его не требуется, то можно подавить предупреждение с помощью контекстного менеджера catch_warnings:
import warnings
def fxn():
warnings.warn("deprecated", DeprecationWarning)
with warnings.catch_warnings():
warnings.simplefilter("ignore")
fxn()
Пока менеджер контекста активен, все предупреждения просто игнорируются.
Это позволяет использовать заведомо устаревший код, не видя предупреждения, при этом не подавляя предупреждения для другого кода, который может не знать об использовании устаревших функций.
Примечание: это гарантируется только в однопоточном приложении. Если два или более потока одновременно используют менеджер контекста catch_warnings, поведение не определено.
29.5.4. Тестирование предупреждений¶Testing Warnings
Для тестирования предупреждений, вызываемых кодом, используйте контекстный менеджер catch_warnings. С его помощью можно временно изменить фильтр предупреждений, чтобы упростить тестирование. Например, сделайте следующее, чтобы перехватить все возникающие предупреждения для проверки:
import warnings
def fxn():
warnings.warn("deprecated", DeprecationWarning)
with warnings.catch_warnings(record=True) as w:
# Привести к тому, что все предупреждения всегда будут срабатывать.
warnings.simplefilter("always")
# Вызвать предупреждение.
fxn()
# Проверить некоторые вещи
assert len(w) == 1
assert issubclass(w[-1].category, DeprecationWarning)
assert "deprecated" in str(w[-1].message)
Также можно сделать все предупреждения исключениями, используя error вместо always. Следует учитывать, что если предупреждение уже было вызвано из-за правила once/default, то, независимо от установленных фильтров, оно не будет показано снова, пока не будет очищен реестр предупреждений, связанный с этим предупреждением.
После выхода из менеджера контекста фильтр предупреждений восстанавливается до состояния на момент входа.
Это предотвращает непреднамеренное изменение фильтра предупреждений между тестами и получение неопределённых результатов.
Функция showwarning() в модуле также восстанавливается до исходного значения.
Примечание: это гарантируется только в однопоточном приложении. Если два или более потока одновременно используют менеджер контекста catch_warnings, поведение не определено.
При тестировании нескольких операций, вызывающих один и тот же тип предупреждения, важно тестировать их так, чтобы подтвердить, что каждая операция вызывает новое предупреждение (например, настроить предупреждения как исключения и проверить, что операции вызывают исключения, проверить, что длина списка предупреждений увеличивается после каждой операции, или удалять предыдущие записи из списка предупреждений перед каждой новой операцией).
29.5.5. Обновление кода для новых версий Python¶Updating Code For New Versions of Python
Предупреждения, которые представляют интерес только для разработчика, по умолчанию игнорируются. Поэтому следует проверить свой код, сделав видимыми обычно игнорируемые предупреждения. Это можно сделать из командной строки, передав интерпретатору -Wd (сокращение для -W default). Это включает обработку по умолчанию для всех предупреждений, включая те, что игнорируются по умолчанию. Чтобы изменить действие для встреченных предупреждений, достаточно изменить аргумент, передаваемый в -W, например -W error. См. флаг -W для получения более подробной информации о возможностях.
Чтобы программно сделать то же самое, что и -Wd, используйте:
warnings.simplefilter('default')
Убедитесь, что этот код выполняется как можно раньше. Это предотвратит неожиданное влияние регистрации возникших предупреждений на то, как будут обрабатываться будущие предупреждения.
Игнорирование некоторых предупреждений по умолчанию делается для того, чтобы пользователь не видел предупреждения, представляющие интерес только для разработчика. Поскольку разработчик не обязательно контролирует, какой интерпретатор использует пользователь для запуска своего кода, возможно, что между циклами выпуска будет выпущена новая версия Python. Новый выпуск интерпретатора может вызвать новые предупреждения в коде, которых не было в старом интерпретаторе, например DeprecationWarning для используемого модуля. Хотя разработчик хочет получать уведомления о том, что его код использует устаревший модуль, для пользователя эта информация, по сути, является шумом и не приносит пользы.
Модуль unittest также был обновлён для использования фильтра 'default' при выполнении тестов.
29.5.6. Доступные функции¶Available Functions
-
warnings.warn(message, category=None, stacklevel=1, source=None)¶ Выдаёт предупреждение, либо игнорирует его, либо возбуждает исключение. Аргумент category, если задан, должен быть классом категории предупреждения (см. выше); по умолчанию он равен
UserWarning. В качестве альтернативы message может быть экземпляромWarning, и в этом случае category игнорируется, а используетсяmessage.__class__. В этом случае текст сообщения будетstr(message). Эта функция возбуждает исключение, если конкретное выданное предупреждение преобразуется в ошибку фильтром предупреждений (см. выше). Аргумент stacklevel может использоваться функциями-обёртками, написанными на Python, например:def deprecation(message): warnings.warn(message, DeprecationWarning, stacklevel=2)
Благодаря этому предупреждение указывает на вызывающий код
deprecation(), а не на источник самогоdeprecation()(поскольку иначе терялся бы смысл сообщения предупреждения).Если указан, source – это уничтоженный объект, который породил
ResourceWarning.Изменено в версии 3.6: Добавлен параметр source.
-
warnings.warn_explicit(message, category, filename, lineno, module=None, registry=None, module_globals=None, source=None)¶ Это низкоуровневый интерфейс к функциональности
warn(), который принимает явно сообщение, категорию, имя файла и номер строки, а также опционально имя модуля и реестр (который должен быть словарём__warningregistry__модуля). Имя модуля по умолчанию равно имени файла с удалённым.py; если реестр не передан, предупреждение никогда не подавляется. сообщение должно быть строкой, а категория – подклассомWarning, или сообщение может быть экземпляромWarning, и в этом случае категория будет проигнорирован.module_globals, если указан, должно быть глобальным пространством имён, используемым кодом, для которого выдаётся предупреждение. (Этот аргумент используется для поддержки отображения исходного кода для модулей, найденных в zip-файлах или других источниках импорта, не основанных на файловой системе).
Если указан, source – это уничтоженный объект, который породил
ResourceWarning.Изменено в версии 3.6: Добавлен параметр source.
-
warnings.showwarning(message, category, filename, lineno, file=None, line=None)¶ Записывает предупреждение в файл. Реализация по умолчанию вызывает
formatwarning(message, category, filename, lineno, line)и записывает результирующую строку в file, который по умолчанию равенsys.stderr. Эту функцию можно заменить любой вызываемой, присвоив еёwarnings.showwarning. line – это строка исходного кода, которая должна быть включена в сообщение предупреждения; если line не указана,showwarning()попытается прочитать строку, заданную filename и lineno.
-
warnings.formatwarning(message, category, filename, lineno, line=None)¶ Форматирует предупреждение стандартным способом. Возвращает строку, которая может содержать встроенные символы новой строки и заканчивается символом новой строки. line – это строка исходного кода, которая должна быть включена в сообщение предупреждения; если line не указана,
formatwarning()попытается прочитать строку, заданную filename и lineno.
-
warnings.filterwarnings(action, message='', category=Warning, module='', lineno=0, append=False)¶ Вставляет запись в список спецификаций фильтра предупреждений. По умолчанию запись вставляется в начало; если append равен истине, она вставляется в конец. Эта функция проверяет типы аргументов, компилирует регулярные выражения message и module и вставляет их в виде кортежа в список фильтров предупреждений. Записи, находящиеся ближе к началу списка, имеют приоритет над записями, находящимися ближе к концу, если обе соответствуют конкретному предупреждению. Опущенные аргументы по умолчанию принимают значение, которое соответствует всему.
-
warnings.simplefilter(action, category=Warning, lineno=0, append=False)¶ Вставляет простую запись в список спецификаций фильтра предупреждений. Смысл параметров функции такой же, как у
filterwarnings(), но регулярные выражения не нужны, так как вставленный фильтр всегда соответствует любому сообщению в любом модуле, если совпадают категория и номер строки.
-
warnings.resetwarnings()¶ Сбрасывает фильтр предупреждений. Это отменяет действие всех предыдущих вызовов
filterwarnings(), включая вызовы, сделанные с помощью параметров командной строки-Wи вызовыsimplefilter().
29.5.7. Доступные контекстные менеджеры¶Available Context Managers
-
class
warnings.catch_warnings(*, record=False, module=None)¶ Менеджер контекста, который копирует и при выходе восстанавливает фильтр предупреждений и функцию
showwarning(). Если аргумент record равенFalse(по умолчанию), менеджер контекста возвращаетNoneпри входе. Если record равенTrue, возвращается список, который постепенно заполняется объектами, как их видит пользовательская функцияshowwarning()(которая также подавляет вывод вsys.stdout). Каждый объект в списке имеет атрибуты с теми же именами, что и аргументыshowwarning().Аргумент module принимает модуль, который будет использоваться вместо модуля, возвращаемого при импорте
warnings, фильтр которого будет защищён. Этот аргумент существует в основном для тестирования самого модуляwarnings.Примечание
Менеджер
catch_warningsработает путём замены, а затем восстановления функцииshowwarning()модуля и внутреннего списка спецификаций фильтров. Это означает, что менеджер контекста изменяет глобальное состояние и поэтому не является потокобезопасным.