Содержание страницы
warnings – Управление предупреждениями¶warnings – Warning control
Исходный код: Lib/warnings.py
Предупреждения обычно выводятся в ситуациях, когда полезно предупредить пользователя о некотором условии в программе, когда это условие (обычно) не требует возбуждения исключения и завершения программы. Например, может потребоваться выдать предупреждение, если программа использует устаревший модуль.
Разработчики на Python выводят предупреждения, вызывая функцию warn(), определённую
в этом модуле. (Разработчики на C используют PyErr_WarnEx(); см.
Обработка исключений для подробностей).
Предупреждения обычно записываются в sys.stderr, но их обработку
можно гибко изменять: от игнорирования всех предупреждений до превращения их в
исключения. Обработка предупреждений может зависеть от категории предупреждения, текста предупреждающего сообщения и места в исходном коде, где оно
выдается. Повторные предупреждения для одного и того же места в исходном коде
обычно подавляются.
Управление предупреждениями состоит из двух этапов: сначала каждый раз при выдаче предупреждения определяется, должно ли сообщение быть выдано; затем, если сообщение должно быть выдано, оно форматируется и выводится с помощью настраиваемого пользователем перехватчика.
Решение о том, выдавать ли предупреждающее сообщение, управляется
фильтром предупреждений, который представляет собой последовательность правил сопоставления и действий. Правила можно
добавлять в фильтр, вызывая filterwarnings(), и сбрасывать в состояние по умолчанию,
вызывая resetwarnings().
Вывод предупреждающих сообщений выполняется вызовом showwarning(), который
может быть переопределён; реализация по умолчанию этой функции форматирует
сообщение вызовом formatwarning(), который также доступен для использования в
пользовательских реализациях.
См. также
logging.captureWarnings() позволяет обрабатывать все предупреждения с помощью
стандартной инфраструктуры журналирования.
Категории предупреждений¶Warning Categories
Существует ряд встроенных исключений, представляющих категории предупреждений. Такая категоризация полезна для фильтрации групп предупреждений.
Хотя технически это встроенные исключения, они documented here, потому что концептуально относятся к механизму предупреждений.
Пользовательский код может определять дополнительные категории предупреждений, создавая подкласс одной из
стандартных категорий предупреждений. Категория предупреждения всегда должна быть подклассом
класса Warning.
В настоящее время определены следующие классы категорий предупреждений:
Класс |
Описание |
|---|---|
Это базовый класс всех классов
категорий предупреждений. Он является подклассом
|
|
Категория по умолчанию для |
|
Базовая категория для предупреждений об устаревших
возможностях, если эти предупреждения предназначены для
других разработчиков Python (игнорируется по умолчанию,
если не вызвано кодом в |
|
Базовый тип для предупреждений о сомнительных синтаксических особенностях. |
|
Базовая категория для предупреждений о сомнительных возможностях времени выполнения. |
|
Базовая категория для предупреждений об устаревших возможностях, если эти предупреждения предназначены для конечных пользователей приложений, написанных на Python. |
|
Базовая категория для предупреждений о возможностях, которые будут объявлены устаревшими в будущем (игнорируется по умолчанию). |
|
Базовая категория для предупреждений, возникающих в процессе импорта модуля (игнорируется по умолчанию). |
|
Базовая категория для предупреждений, связанных с Юникодом. |
|
Базовая категория для предупреждений, связанных с
|
|
Базовая категория для предупреждений, связанных с использованием ресурсов (игнорируется по умолчанию). |
Изменено в версии 3.7: Ранее DeprecationWarning и FutureWarning
различались по тому, удалялась ли возможность полностью или
меняла своё поведение. Теперь они различаются по
целевой аудитории и способу обработки фильтрами предупреждений
по умолчанию.
Фильтр предупреждений¶The Warnings Filter
Фильтр предупреждений управляет тем, игнорируются ли предупреждения, выводятся на экран или превращаются в ошибки (вызывают исключение).
Концептуально фильтр предупреждений поддерживает упорядоченный список спецификаций фильтра; любое конкретное предупреждение последовательно сопоставляется с каждой спецификацией фильтра из списка, пока не будет найдено совпадение; фильтр определяет обработку совпадения. Каждая запись представляет собой кортеж вида (действие, сообщение, категория, модуль, номер_строки), где:
Действие – одна из следующих строк:
Значение
Действие
"default"выводить первое вхождение подходящих предупреждений для каждого местоположения (модуль + номер строки), где выдано предупреждение
"error"превращать подходящие предупреждения в исключения
"ignore"никогда не выводить подходящие предупреждения
"always"всегда выводить подходящие предупреждения
"module"выводить первое вхождение подходящих предупреждений для каждого модуля, где выдано предупреждение (независимо от номера строки)
"once"выводить только первое вхождение подходящих предупреждений, независимо от местоположения
message – это строка, содержащая регулярное выражение, которому должно соответствовать начало сообщения предупреждения (без учёта регистра). В
-WиPYTHONWARNINGSпараметр message – это литеральная строка, которую должно содержать начало сообщения предупреждения (без учёта регистра), при этом игнорируются любые пробельные символы в начале и конце message.category – это класс (подкласс
Warning), подклассом которого должна быть категория предупреждения для совпадения.module – это строка, содержащая регулярное выражение, которому должно соответствовать начало полного имени модуля (с учётом регистра). В
-WиPYTHONWARNINGSпараметр module – это литеральная строка, которой должно быть равно полное имя модуля (с учётом регистра), при этом игнорируются любые пробельные символы в начале и конце module.lineno – это целое число, которому должен соответствовать номер строки, где произошло предупреждение, или
0для соответствия всем номерам строк.
Поскольку класс Warning является наследником встроенного класса Exception, чтобы превратить предупреждение в ошибку, мы просто возбуждаем category(message).
Если предупреждение зарегистрировано и не соответствует ни одному из установленных фильтров, то применяется действие «default» (отсюда и его название).
Критерии подавления повторяющихся предупреждений¶Repeated Warning Suppression Criteria
Фильтры, подавляющие повторяющиеся предупреждения, используют следующие критерии для определения, считается ли предупреждение повторным:
"default": предупреждение считается повторным только в том случае, если все значения (message, category, module, lineno) одинаковы."module": предупреждение считается повторным, если (message, category, module) одинаковы, независимо от номера строки."once": предупреждение считается повторным, если (message, category) одинаковы, независимо от модуля и номера строки.
Описание фильтров предупреждений¶Describing Warning Filters
Фильтр предупреждений инициализируется опциями -W, переданными в командной строке интерпретатора Python, и переменной окружения PYTHONWARNINGS. Интерпретатор сохраняет аргументы для всех предоставленных записей без интерпретации в sys.warnoptions; модуль warnings анализирует их при первом импорте (недопустимые опции игнорируются после вывода сообщения в sys.stderr).
Отдельные фильтры предупреждений задаются в виде последовательности полей, разделённых двоеточиями:
action:message:category:module:line
Значение каждого из этих полей описано в разделе Фильтр предупреждений. При перечислении нескольких фильтров в одной строке (как для PYTHONWARNINGS) отдельные фильтры разделяются запятыми, и фильтры, указанные позже, имеют приоритет над теми, что указаны раньше (поскольку они применяются слева направо, и последние применённые фильтры имеют преимущество перед более ранними).
Обычно используемые фильтры предупреждений применяются либо ко всем предупреждениям, либо к предупреждениям определённой категории, либо к предупреждениям, вызванным определёнными модулями или пакетами. Несколько примеров:
default # Показывать все предупреждения (даже те, что игнорируются по умолчанию)
ignore # Игнорировать все предупреждения
error # Преобразовать все предупреждения в ошибки
error::ResourceWarning # Обрабатывать сообщения ResourceWarning как ошибки
default::DeprecationWarning # Показывать сообщения DeprecationWarning
ignore,default:::mymodule # Сообщать только о предупреждениях, вызванных "mymodule"
error:::mymodule # Преобразовывать предупреждения в ошибки в "mymodule"
Фильтр предупреждений по умолчанию¶Default Warning Filter
По умолчанию Python устанавливает несколько фильтров предупреждений, которые можно переопределить с помощью параметра командной строки -W, переменной окружения PYTHONWARNINGS и вызовов filterwarnings().
В обычных сборках релиза фильтр предупреждений по умолчанию имеет следующие записи (в порядке приоритета):
default::DeprecationWarning:__main__
ignore::DeprecationWarning
ignore::PendingDeprecationWarning
ignore::ImportWarning
ignore::ResourceWarning
В отладочной сборке список фильтров предупреждений по умолчанию пуст.
Изменено в версии 3.2: DeprecationWarning теперь по умолчанию игнорируется в дополнение к PendingDeprecationWarning.
Изменено в версии 3.7: DeprecationWarning снова отображается по умолчанию при непосредственном вызове кодом в __main__.
Изменено в версии 3.7: BytesWarning больше не появляется в списке фильтров по умолчанию и вместо этого настраивается через sys.warnoptions, когда -b указан дважды.
Переопределение фильтра по умолчанию¶Overriding the default filter
Разработчики приложений на Python могут захотеть скрыть все предупреждения уровня Python
от пользователей по умолчанию и показывать их только во время тестирования
или другой работы над приложением. Атрибут sys.warnoptions,
используемый для передачи конфигураций фильтра интерпретатору, может служить маркером,
указывающим, следует ли отключить предупреждения:
import sys
if not sys.warnoptions:
import warnings
warnings.simplefilter("ignore")
Разработчикам средств запуска тестов для кода Python рекомендуется вместо этого обеспечить, чтобы все предупреждения отображались по умолчанию для тестируемого кода, используя код наподобие:
import sys
if not sys.warnoptions:
import os, warnings
warnings.simplefilter("default") # Изменить фильтр в этом процессе
os.environ["PYTHONWARNINGS"] = "default" # Также действовать на подпроцессы
Наконец, разработчикам интерактивных оболочек, выполняющих пользовательский код в пространстве имён, отличном от __main__, рекомендуется обеспечить, чтобы сообщения DeprecationWarning были видны по умолчанию, используя код наподобие следующего (где user_ns – это модуль, используемый для выполнения вводимого интерактивно кода):
import warnings
warnings.filterwarnings("default", category=DeprecationWarning,
module=user_ns.get("__name__"))
Временное подавление предупреждений¶Temporarily Suppressing Warnings
Если вы используете код, который, как известно, вызовет предупреждение (например, устаревшую функцию), но не хотите видеть это предупреждение (даже если предупреждения были явно настроены через командную строку), то предупреждение можно подавить с помощью контекстного менеджера catch_warnings:
import warnings
def fxn():
warnings.warn("deprecated", DeprecationWarning)
with warnings.catch_warnings():
warnings.simplefilter("ignore")
fxn()
Пока менеджер контекста активен, все предупреждения просто игнорируются.
Это позволяет использовать заведомо устаревший код, не видя предупреждения, при этом не подавляя предупреждения для другого кода, который может не знать об использовании устаревших функций.
Примечание: это гарантируется только в однопоточном приложении. Если два или более потока одновременно используют менеджер контекста catch_warnings, поведение не определено.
Тестирование предупреждений¶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, поведение не определено.
При тестировании нескольких операций, вызывающих один и тот же тип предупреждения, важно тестировать их так, чтобы подтвердить, что каждая операция вызывает новое предупреждение (например, настроить предупреждения как исключения и проверить, что операции вызывают исключения, проверить, что длина списка предупреждений увеличивается после каждой операции, или удалять предыдущие записи из списка предупреждений перед каждой новой операцией).
Обновление кода для новых версий зависимостей¶Updating Code For New Versions of Dependencies
Категории предупреждений, представляющие интерес в первую очередь для разработчиков Python (а не для конечных пользователей приложений на Python), по умолчанию игнорируются.
Примечательно, что этот список «игнорируемых по умолчанию» включает DeprecationWarning (для каждого модуля, кроме __main__), что означает, что разработчики должны обязательно тестировать свой код с видимыми предупреждениями, которые обычно игнорируются, чтобы своевременно получать уведомления о будущих ломающих изменениях API (как в стандартной библиотеке, так и в сторонних пакетах).
В идеале код будет иметь подходящий набор тестов, а средство запуска тестов позаботится о неявном включении всех предупреждений при выполнении тестов (средство запуска тестов, предоставляемое модулем unittest, делает это).
В менее идеальных случаях приложения можно проверить на использование устаревших интерфейсов, передав -Wd интерпретатору Python (это сокращение для -W default) или установив PYTHONWARNINGS=default в окружении. Это включает обработку по умолчанию для всех предупреждений, включая те, которые игнорируются по умолчанию. Чтобы изменить действие для встреченных предупреждений, можно изменить аргумент, передаваемый -W (например, -W error). См. флаг -W для подробностей о возможностях.
Доступные функции¶Available Functions
- warnings.warn(message, category=None, stacklevel=1, source=None, *, skip_file_prefixes=())¶
Выдаёт предупреждение, или же игнорирует его, или вызывает исключение. Аргумент category, если указан, должен быть классом категории предупреждения; по умолчанию он равен
UserWarning. В качестве альтернативы message может быть экземпляромWarning, и в этом случае category игнорируется, а используетсяmessage.__class__. В этом случае текст сообщения будетstr(message). Эта функция вызывает исключение, если конкретное выданное предупреждение превращается в ошибку фильтром предупреждений. Аргумент stacklevel может использоваться функциями-обёртками, написанными на Python, например:def deprecated_api(message): warnings.warn(message, DeprecationWarning, stacklevel=2)
Это заставляет предупреждение ссылаться на вызывающий объект
deprecated_api, а не на источник самогоdeprecated_api(поскольку последнее противоречило бы цели сообщения предупреждения).Именованный аргумент skip_file_prefixes можно использовать для указания, какие кадры стека игнорируются при подсчёте уровней стека. Это может быть полезно, когда нужно, чтобы предупреждение всегда появлялось в местах вызова за пределами пакета, когда постоянное значение stacklevel не подходит для всех путей вызова или его сложно поддерживать. Если указан, он должен быть кортежем строк. При указании префиксов значение stacklevel неявно переопределяется в
max(2, stacklevel). Чтобы предупреждение приписывалось вызывающему коду за пределами текущего пакета, можно написать:# example/lower.py _warn_skips = (os.path.dirname(__file__),) def one_way(r_luxury_yacht=None, t_wobbler_mangrove=None): if r_luxury_yacht: warnings.warn("Please migrate to t_wobbler_mangrove=.", skip_file_prefixes=_warn_skips) # example/higher.py from . import lower def another_way(**kw): lower.one_way(**kw)
Это заставляет предупреждение ссылаться на точки вызова как
example.lower.one_way(), так иpackage.higher.another_way(), только из вызывающего кода, находящегося за пределами пакетаexample.Если указан, source – это уничтоженный объект, который породил
ResourceWarning.Изменено в версии 3.6: Добавлен параметр source.
Изменено в версии 3.12: Добавлено skip_file_prefixes.
- 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().
Доступные контекстные менеджеры¶Available Context Managers
- class warnings.catch_warnings(*, record=False, module=None, action=None, category=Warning, lineno=0, append=False)¶
Менеджер контекста, который копирует и при выходе восстанавливает фильтр предупреждений и функцию
showwarning(). Если аргумент record равенFalse(по умолчанию), менеджер контекста возвращаетNoneпри входе. Если record равенTrue, возвращается список, который постепенно заполняется объектами, как их видит пользовательская функцияshowwarning()(которая также подавляет вывод вsys.stdout). Каждый объект в списке имеет атрибуты с теми же именами, что и аргументыshowwarning().Аргумент module принимает модуль, который будет использоваться вместо модуля, возвращаемого при импорте
warnings, фильтр которого будет защищён. Этот аргумент существует в основном для тестирования самого модуляwarnings.Если аргумент action не равен
None, остальные аргументы передаются вsimplefilter(), как если бы она была вызвана сразу при входе в контекст.Смотрите Фильтр предупреждений для пояснения параметров category и lineno .
Примечание
Менеджер
catch_warningsработает путём замены, а затем восстановления функцииshowwarning()модуля и внутреннего списка спецификаций фильтров. Это означает, что менеджер контекста изменяет глобальное состояние и поэтому не является потокобезопасным.Изменено в версии 3.11: Добавлены параметры action, category, lineno и append.