warnings — Управление предупреждениями
Исходный код: Lib/warnings.py
Предупреждения обычно выдаются в ситуациях, когда полезно сообщить пользователю о некотором условии в программе, которое (как правило) не является достаточной причиной для возбуждения исключения и завершения программы. Например, можно выдать предупреждение, если программа использует устаревший модуль.
Программисты на Python выдают предупреждения, вызывая функцию warn(), определённую в этом модуле. (Программисты на C используют PyErr_WarnEx(); подробности см. в разделе Обработка исключений.)
Предупреждения обычно выводятся в sys.stderr, но их обработку можно гибко изменить: от игнорирования всех предупреждений до преобразования их в исключения. Обработка предупреждений может различаться в зависимости от категории предупреждения, текста сообщения и места в исходном коде, где оно выдано. Повторные предупреждения в одном и том же месте исходного кода обычно подавляются.
Управление предупреждениями состоит из двух этапов: сначала при каждом выдаваемом предупреждении определяется, нужно ли выводить сообщение; затем, если сообщение следует вывести, оно форматируется и печатается с помощью настраиваемого пользователем обработчика.
Решение о выводе сообщения предупреждения определяется фильтром предупреждений, представляющим собой последовательность правил сопоставления и действий. Правила можно добавить в фильтр вызовом filterwarnings(), а вернуть его состояние по умолчанию — вызовом resetwarnings().
Сообщения предупреждений печатаются вызовом showwarning(), который можно переопределить; реализация этой функции по умолчанию форматирует сообщение вызовом formatwarning(). Эту функцию также можно использовать в пользовательских реализациях.
См. также
logging.captureWarnings() позволяет обрабатывать все предупреждения с помощью стандартной инфраструктуры ведения журнала.
Категории предупреждений
Существует несколько встроенных исключений, представляющих категории предупреждений. Такая классификация полезна для фильтрации групп предупреждений.
Хотя технически это встроенные исключения, они описаны здесь, поскольку по смыслу относятся к механизму предупреждений.
Пользовательский код может определять дополнительные категории предупреждений, создавая подклассы одной из стандартных категорий. Категория предупреждения всегда должна быть подклассом класса Warning.
В настоящее время определены следующие классы категорий предупреждений:
Класс | Описание |
|---|---|
Базовый класс всех классов категорий предупреждений. Он является подклассом | |
Категория по умолчанию для функции | |
Базовая категория предупреждений об устаревших возможностях, предназначенных для других разработчиков на Python (по умолчанию игнорируются, если только не вызваны кодом в | |
Базовая категория предупреждений о сомнительных синтаксических конструкциях. | |
Базовая категория предупреждений о сомнительных возможностях времени выполнения. | |
Базовая категория предупреждений об устаревших возможностях, предназначенных для конечных пользователей приложений, написанных на Python. | |
Базовая категория предупреждений о возможностях, которые будут объявлены устаревшими в будущем (по умолчанию игнорируются). | |
Базовая категория предупреждений, возникающих при импорте модуля (по умолчанию игнорируются). | |
Базовая категория предупреждений, связанных с Unicode. | |
Базовая категория предупреждений, связанных с | |
Базовая категория предупреждений, связанных с использованием ресурсов (по умолчанию игнорируются). |
Изменено в версии 3.7: Ранее DeprecationWarning и FutureWarning различались в зависимости от того, удалялась ли возможность полностью или менялось её поведение. Теперь они различаются по целевой аудитории и способу обработки стандартными фильтрами предупреждений.
Фильтр предупреждений
Фильтр предупреждений определяет, будут ли предупреждения игнорироваться, отображаться или преобразовываться в ошибки (с возбуждением исключения).
Концептуально фильтр предупреждений поддерживает упорядоченный список спецификаций фильтров; каждое предупреждение по очереди сопоставляется со спецификациями фильтров из списка, пока не будет найдено совпадение; фильтр определяет, как обработать совпадение. Каждая запись представляет собой кортеж вида (действие, сообщение, категория, модуль, номер_строки), где:
-
действие — одна из следующих строк:
Значение
Обработка
"default"вывести первое совпадающее предупреждение для каждого места (модуль + номер строки), где оно выдано
"error"преобразовать совпадающие предупреждения в исключения
"ignore"никогда не выводить совпадающие предупреждения
"always"всегда выводить совпадающие предупреждения
"module"вывести первое совпадающее предупреждение для каждого модуля, где оно выдано (независимо от номера строки)
"once"вывести только первое совпадающее предупреждение независимо от места
-
сообщение — строка с регулярным выражением, которому должно соответствовать начало текста предупреждения без учёта регистра. В
-WиPYTHONWARNINGSсообщение — буквальная строка, которая должна содержаться в начале текста предупреждения (без учёта регистра); начальные и конечные пробелы в сообщении игнорируются. -
категория — класс (подкласс
Warning), подклассом которого должна быть категория предупреждения, чтобы произошло совпадение. -
модуль — строка с регулярным выражением, которому должно соответствовать начало полного имени модуля с учётом регистра. В
-WиPYTHONWARNINGSмодуль — буквальная строка, которой должно в точности соответствовать полное имя модуля (с учётом регистра); начальные и конечные пробелы в модуле игнорируются. -
номер_строки — целое число, которому должен соответствовать номер строки, где возникло предупреждение, или
0для совпадения с любым номером строки.
Поскольку класс Warning является производным от встроенного класса Exception, для преобразования предупреждения в ошибку достаточно возбудить category(message).
Если выданное предупреждение не соответствует ни одному зарегистрированному фильтру, применяется действие «default» (отсюда и его название).
Критерии подавления повторных предупреждений
Фильтры, подавляющие повторные предупреждения, используют следующие критерии, чтобы определить, считается ли предупреждение повторным:
-
"default": предупреждение считается повторным только в том случае, если совпадают все значения (сообщение, категория, модуль, номер_строки). -
"module": предупреждение считается повторным, если совпадают значения (сообщение, категория, модуль); номер строки не учитывается. -
"once": предупреждение считается повторным, если совпадают значения (сообщение, категория); модуль и номер строки не учитываются.
Описание фильтров предупреждений
Фильтр предупреждений инициализируется параметрами -W, переданными в командной строке интерпретатора Python, и переменной окружения PYTHONWARNINGS. Интерпретатор сохраняет аргументы всех переданных записей без интерпретации в sys.warnoptions; модуль warnings разбирает их при первом импорте (недопустимые параметры игнорируются после вывода сообщения в sys.stderr).
Отдельные фильтры предупреждений задаются последовательностью полей, разделённых двоеточиями:
action:message:category:module:line
Значение каждого из этих полей описано в разделе Фильтр предупреждений. При перечислении нескольких фильтров в одной строке (например, в PYTHONWARNINGS) отдельные фильтры разделяются запятыми; фильтры, указанные позже, имеют приоритет над указанными ранее (поскольку они применяются слева направо, а последние применённые фильтры имеют приоритет над предыдущими).
Часто используемые фильтры предупреждений применяются ко всем предупреждениям, предупреждениям определённой категории или предупреждениям, выданным определёнными модулями или пакетами. Например:
default # Show all warnings (even those ignored by default) ignore # Ignore all warnings error # Convert all warnings to errors error::ResourceWarning # Treat ResourceWarning messages as errors default::DeprecationWarning # Show DeprecationWarning messages ignore,default:::mymodule # Only report warnings triggered by "mymodule" error:::mymodule # Convert warnings to errors in "mymodule"
Фильтр предупреждений по умолчанию
По умолчанию 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 указан дважды.
Переопределение фильтра по умолчанию
Разработчики приложений, написанных на 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") # Change the filter in this process
os.environ["PYTHONWARNINGS"] = "default" # Also affect subprocesses
Наконец, разработчикам интерактивных оболочек, выполняющих пользовательский код в пространстве имён, отличном от __main__, рекомендуется обеспечить отображение сообщений DeprecationWarning по умолчанию, используя, например, следующий код (где user_ns — модуль, используемый для выполнения кода, введённого в интерактивном режиме):
import warnings
warnings.filterwarnings("default", category=DeprecationWarning,
module=user_ns.get("__name__"))
Временное подавление предупреждений
Если вы используете код, который, как вам известно, выдаст предупреждение, например устаревшую функцию, но не хотите видеть это предупреждение (даже если предупреждения явно настроены через командную строку), его можно подавить с помощью менеджера контекста catch_warnings:
import warnings
def fxn():
warnings.warn("deprecated", DeprecationWarning)
with warnings.catch_warnings():
warnings.simplefilter("ignore")
fxn()
Внутри менеджера контекста все предупреждения просто игнорируются. Это позволяет использовать заведомо устаревший код, не видя предупреждения, и при этом не подавлять предупреждения для другого кода, который может не знать об использовании устаревшего кода. Примечание: это можно гарантировать только в однопоточном приложении. Если два или более потоков одновременно используют менеджер контекста catch_warnings, поведение не определено.
Тестирование предупреждений
Для тестирования предупреждений, выдаваемых кодом, используйте менеджер контекста catch_warnings. С его помощью можно временно изменять фильтр предупреждений, чтобы упростить тестирование. Например, выполните следующие действия, чтобы перехватить все выданные предупреждения и проверить их:
import warnings
def fxn():
warnings.warn("deprecated", DeprecationWarning)
with warnings.catch_warnings(record=True) as w:
# Cause all warnings to always be triggered.
warnings.simplefilter("always")
# Trigger a warning.
fxn()
# Verify some things
assert len(w) == 1
assert issubclass(w[-1].category, DeprecationWarning)
assert "deprecated" in str(w[-1].message)
Также можно преобразовать все предупреждения в исключения, используя error вместо always. Следует учитывать, что если предупреждение уже было выдано из-за правила once/default, то оно больше не появится независимо от установленных фильтров, пока не будет очищен реестр предупреждений, связанный с этим предупреждением.
После выхода из менеджера контекста фильтр предупреждений восстанавливается до состояния на момент входа в него. Это не позволяет тестам неожиданно менять фильтр предупреждений между запусками и приводить к неопределённым результатам. Функция showwarning() в модуле также восстанавливается до исходного значения. Примечание: это можно гарантировать только в однопоточном приложении. Если два или более потоков одновременно используют менеджер контекста catch_warnings, поведение не определено.
При тестировании нескольких операций, выдающих предупреждения одного типа, важно проводить тесты так, чтобы убедиться, что каждая операция выдаёт новое предупреждение (например, настроить преобразование предупреждений в исключения и проверить, что операции возбуждают исключения; проверить, что длина списка предупреждений увеличивается после каждой операции; либо перед каждой новой операцией удалять предыдущие записи из списка предупреждений).
Обновление кода для новых версий зависимостей
Категории предупреждений, представляющие интерес прежде всего для разработчиков на Python (а не для конечных пользователей приложений, написанных на Python), по умолчанию игнорируются.
В частности, в этот список «игнорируемых по умолчанию» предупреждений входит DeprecationWarning (для всех модулей, кроме __main__). Поэтому разработчикам следует проверять свой код, включив отображение предупреждений, которые обычно игнорируются, чтобы своевременно получать уведомления о будущих несовместимых изменениях API (как в стандартной библиотеке, так и в сторонних пакетах).
В идеальном случае у кода есть подходящий набор тестов, а средство запуска тестов неявно включает все предупреждения при выполнении тестов (средство запуска тестов, предоставляемое модулем unittest, делает именно это).
В менее идеальных случаях приложения можно проверить на использование устаревших интерфейсов, передав интерпретатору Python параметр -Wd (это сокращённая запись для -W default) или задав в окружении PYTHONWARNINGS=default. Это включает стандартную обработку всех предупреждений, в том числе тех, которые по умолчанию игнорируются. Чтобы изменить действие при обнаружении предупреждений, можно изменить аргумент, передаваемый параметру -W (например, -W error). Подробнее о возможных вариантах см. описание флага -W.
Доступные функции
-
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; если реестр не передан, предупреждение никогда не подавляется. message должен быть строкой, а category — подклассомWarning; также message может быть экземпляромWarning, и в этом случае category игнорируется.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 имеет значение true, она вставляется в конец. Функция проверяет типы аргументов, компилирует регулярные выражения message и module и вставляет их в список фильтров предупреждений в виде кортежа. Записи, расположенные ближе к началу списка, имеют приоритет над последующими, если обе соответствуют предупреждению. Для пропущенных аргументов используются значения, соответствующие всему.
-
warnings.simplefilter(action, category=Warning, lineno=0, append=False) -
Вставить простую запись в список спецификаций фильтров предупреждений. Параметры функции имеют тот же смысл, что и у
filterwarnings(), однако регулярные выражения не нужны: добавленный фильтр всегда соответствует любому сообщению в любом модуле, если категория и номер строки совпадают.
-
warnings.resetwarnings() -
Сбросить фильтр предупреждений. Это отменяет действие всех предыдущих вызовов
filterwarnings(), в том числе параметров командной строки-Wи вызововsimplefilter().
Доступные менеджеры контекста
-
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.
© 2001–2024 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.12/library/warnings.html