warnings — Управление предупреждениями
Исходный код: Lib/warnings.py
Предупреждения обычно выдаются в ситуациях, когда полезно уведомить пользователя о некотором условии в программе, которое (как правило) не требует возбуждения исключения и завершения программы. Например, можно выдать предупреждение, когда программа использует устаревший модуль.
Программисты на Python выдают предупреждения, вызывая функцию warn(), определённую в этом модуле. (Программисты на C используют PyErr_WarnEx(); подробности см. в разделе Обработка исключений.)
Предупреждения обычно выводятся в sys.stderr, но их обработку можно гибко изменять: от игнорирования всех предупреждений до преобразования их в исключения. Обработка предупреждений может зависеть от категории предупреждения, текста предупреждения и места в исходном коде, где оно выдано. Повторные предупреждения для одного и того же места в исходном коде обычно подавляются.
Управление предупреждениями состоит из двух этапов: сначала при каждом выдаваемом предупреждении определяется, следует ли выводить сообщение; затем, если сообщение нужно вывести, оно форматируется и печатается с помощью настраиваемой пользователем функции-перехватчика.
Решение о выводе предупреждения принимает фильтр предупреждений, представляющий собой последовательность правил сопоставления и действий. Правила можно добавлять в фильтр с помощью вызова filterwarnings(), а сбросить его в состояние по умолчанию — вызовом resetwarnings().
Печать предупреждений выполняется вызовом showwarning(), который можно переопределить; реализация этой функции по умолчанию форматирует сообщение с помощью formatwarning(), доступной также для использования в пользовательских реализациях.
См. также
logging.captureWarnings() позволяет обрабатывать все предупреждения с помощью стандартной инфраструктуры ведения журнала.
Категории предупреждений
Существует несколько встроенных исключений, представляющих категории предупреждений. Такая классификация полезна для фильтрации групп предупреждений.
Хотя технически это встроенные исключения, они описаны здесь, поскольку концептуально относятся к механизму предупреждений.
Пользовательский код может определять дополнительные категории предупреждений, создавая подклассы одной из стандартных категорий предупреждений. Категория предупреждения всегда должна быть подклассом класса Warning.
В настоящее время определены следующие классы категорий предупреждений:
Класс | Описание |
|---|---|
Базовый класс всех классов категорий предупреждений. Он является подклассом | |
Категория по умолчанию для | |
Базовая категория предупреждений об устаревших возможностях, предназначенных для других разработчиков Python (по умолчанию игнорируются, если только не вызваны кодом в | |
Базовая категория предупреждений о сомнительных синтаксических конструкциях (обычно выдаются при компиляции исходного кода Python и поэтому могут не подавляться фильтрами времени выполнения). | |
Базовая категория предупреждений о сомнительных возможностях времени выполнения. | |
Базовая категория предупреждений об устаревших возможностях, предназначенных для конечных пользователей приложений, написанных на Python. | |
Базовая категория предупреждений о возможностях, которые устареют в будущем (по умолчанию игнорируются). | |
Базовая категория предупреждений, возникающих при импорте модуля (по умолчанию игнорируются). | |
Базовая категория предупреждений, связанных с Unicode. | |
Базовая категория предупреждений, связанных с | |
Базовая категория предупреждений, связанных с использованием ресурсов (по умолчанию игнорируются). |
Изменено в версии 3.7: Ранее DeprecationWarning и FutureWarning различались в зависимости от того, удалялась ли возможность полностью или менялось её поведение. Теперь они различаются по предполагаемой аудитории и способу обработки фильтрами предупреждений по умолчанию.
Фильтр предупреждений
Фильтр предупреждений определяет, будут ли предупреждения игнорироваться, отображаться или преобразовываться в ошибки (с возбуждением исключения).
Концептуально фильтр предупреждений поддерживает упорядоченный список спецификаций фильтров; каждое конкретное предупреждение последовательно сопоставляется с каждой спецификацией из списка, пока не будет найдено совпадение; фильтр определяет способ обработки совпадения. Каждая запись — это кортеж вида (действие, сообщение, категория, модуль, номер_строки), где:
-
действие — одна из следующих строк:
Значение
Обработка
"default"вывести первое совпавшее предупреждение для каждого места (модуль + номер строки), где выдано предупреждение
"error"преобразовать совпавшие предупреждения в исключения
"ignore"никогда не выводить совпавшие предупреждения
"always"всегда выводить совпавшие предупреждения
"all"псевдоним для «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, то оно больше не появится независимо от установленных фильтров, если не очистить реестр предупреждений, связанный с этим предупреждением.
После выхода из менеджера контекста фильтр предупреждений восстанавливается в состояние, в котором он находился при входе в контекст. Это не позволяет тестам неожиданно изменять фильтр предупреждений между запусками и приводить к неопределённым результатам тестирования.
Примечание
Подробности о безопасности менеджера контекста 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()иexample.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(), который явно принимает сообщение, категорию, имя файла и номер строки, а также при необходимости другие аргументы. message должен быть строкой, а category — подклассомWarning; либо message может быть экземпляромWarning, и тогда category игнорируется.Параметр module, если он задан, должен содержать имя модуля. Если модуль не передан, используется имя файла без
.py.Параметр registry, если он задан, должен быть словарём
__warningregistry__модуля. Если реестр не передан, каждое предупреждение считается возникшим впервые, то есть действия фильтра"default","module"и"once"обрабатываются как"always".Параметр 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().
-
@warnings.deprecated(message, /, *, category=DeprecationWarning, stacklevel=1) -
Декоратор, указывающий, что класс, функция или перегруженная функция устарели.
При применении этого декоратора к объекту во время выполнения при его использовании могут выдаваться предупреждения об устаревании. средства статической проверки типов также будут выдавать диагностическое сообщение при использовании устаревшего объекта.
Использование:
from warnings import deprecated from typing import overload @deprecated("Use B instead") class A: pass @deprecated("Use g instead") def f(): pass @overload @deprecated("int support is deprecated") def g(x: int) -> int: ... @overload def g(x: str) -> int: ...Во время выполнения при использовании устаревших объектов будет выдано предупреждение, указанное параметром category. Для функций это происходит при вызове, а для классов — при создании экземпляра и при создании подклассов. Если category равен
None, во время выполнения предупреждение не выдаётся. Параметр stacklevel определяет, где будет выдано предупреждение. Если он равен1(значение по умолчанию), предупреждение выдаётся вызывающей стороне устаревшего объекта; если значение больше, предупреждение выдаётся выше по стеку вызовов. Аргументы category и stacklevel не влияют на поведение средств статической проверки типов.Сообщение об устаревании, переданное декоратору, сохраняется в атрибуте
__deprecated__декорированного объекта. При применении к перегруженной функции декоратор должен располагаться после декоратора@~typing.overload, чтобы атрибут присутствовал у перегрузки, возвращаемой функциейtyping.get_overloads().Добавлено в версии 3.13: См. PEP 702.
Доступные менеджеры контекста
-
class warnings.catch_warnings(*, record=False, module=None, action=None, category=Warning, lineno=0, append=False) -
Менеджер контекста, который копирует фильтр предупреждений и функцию
showwarning(), а при выходе из контекста восстанавливает их. Если аргумент record равенFalse(значение по умолчанию), при входе менеджер контекста возвращаетNone. Если record равенTrue, возвращается список, который постепенно заполняется объектами, передаваемыми пользовательской функцииshowwarning()(которая также подавляет вывод вsys.stderr). Гарантируется, что у каждого объекта в списке есть следующие атрибуты:-
message: сообщение-предупреждение (экземплярWarning) -
category: категория предупреждения (подклассWarning) -
filename: имя файла, в котором возникло предупреждение (str) -
lineno: номер строки в файле (int) -
file: файловый объект, использованный для вывода (если есть), илиNone -
line: строка исходного кода (если доступна) илиNone -
source: исходный объект, вызвавший предупреждение (если доступен), илиNone
Изменено в версии 3.6: Добавлен атрибут
source.Тип этих объектов не определён и может измениться; гарантируется только наличие указанных атрибутов.
Аргумент module принимает модуль, который будет использован вместо модуля, возвращаемого при импорте
warnings, фильтр которого будет защищён. Этот аргумент предназначен главным образом для тестирования самого модуляwarnings.Если аргумент action не равен
None, остальные аргументы передаются вsimplefilter(), как если бы она была немедленно вызвана при входе в контекст.Значение параметров category и lineno см. в разделе Фильтр предупреждений.
Примечание
Подробные сведения о безопасности менеджера контекста
catch_warningsпри параллельном выполнении в программах с несколькими потоками или асинхронными функциями см. в разделе Параллельная безопасность менеджеров контекста.Изменено в версии 3.11: Добавлены параметры action, category, lineno и append.
-
Параллельная безопасность менеджеров контекста
Поведение менеджера контекста catch_warnings зависит от флага sys.flags.context_aware_warnings. Если флаг включён, менеджер контекста безопасен при параллельном выполнении, в противном случае — нет. Безопасность при параллельном выполнении означает безопасность как для потоков, так и при использовании внутри корутин и задач asyncio. Безопасность для потоков означает предсказуемое поведение в многопоточной программе. По умолчанию флаг включён для сборок с отключённой блокировкой GIL и выключен в остальных случаях.
Если флаг context_aware_warnings выключен, catch_warnings изменяет глобальные атрибуты модуля warnings. Это небезопасно при использовании в параллельной программе (с несколькими потоками или с корутинами asyncio). Например, если два или более потока одновременно используют класс catch_warnings, поведение не определено.
Если флаг включён, catch_warnings не изменяет глобальные атрибуты, а использует ContextVar для хранения нового состояния фильтрации предупреждений. Переменная контекста обеспечивает локальное для потока хранилище, благодаря чему использование catch_warnings становится безопасным для потоков.
Поведение параметра record у обработчика контекста также зависит от значения флага. Когда record равен true, а флаг выключен, менеджер контекста работает, заменяя функцию showwarning() модуля, а затем восстанавливая её. Это небезопасно при параллельном выполнении.
Когда record равен true и флаг включён, функция showwarning() не заменяется. Вместо этого состояние записи указывается внутренним свойством переменной контекста. В этом случае функция showwarning() не будет восстановлена при выходе из обработчика контекста.
Флаг context_aware_warnings можно задать с помощью параметра командной строки -X
context_aware_warnings или переменной среды PYTHON_CONTEXT_AWARE_WARNINGS.
Примечание
Вероятно, большинство программ, которым нужна безопасность модуля warnings для потоков, также захотят установить флаг thread_inherit_context в true. Этот флаг заставляет потоки, создаваемые функцией threading.Thread, начинать работу с копией переменных контекста потока, который их создал. Если флаг включён, контекст, установленный функцией catch_warnings в одном потоке, также будет применяться к созданным им новым потокам. Если флаг выключен, новые потоки начинают работу с пустой переменной контекста предупреждений, то есть фильтрация, установленная менеджером контекста catch_warnings, больше не будет активна.
Изменено в версии 3.14: Добавлен флаг sys.flags.context_aware_warnings и добавлено использование переменной контекста для catch_warnings, если флаг включён. В предыдущих версиях Python флаг всегда считался выключенным.
© 2001 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.14/library/warnings.html