Предупреждения — Управление предупреждениями
Исходный код: 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": Предупреждение считается повторяющимся только в том случае, если (сообщение, категория, модуль, номер_строки) все одинаковые. -
"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, делает это).
В менее идеальных случаях приложения можно проверить на использование устаревших интерфейсов, передав -Wd интерпретатору Python (это сокращение для -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().
-
@warnings.deprecated(msg, *, 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__на декорируемом объекте. При применении к перегрузке, декоратор должен быть после декоратора@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.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.13/library/warnings.html