Предупреждения — Управление предупреждениями
Исходный код: 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).
Если предупреждение сообщается и не соответствует ни одному зарегистрированному фильтру, то применяется «стандартное» действие (отсюда и его название).
Описание Фильтров Предупреждений
Фильтр предупреждений инициализируется параметрами -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) -
Выдать предупреждение, или возможно проигнорировать его или вызвать исключение. Аргумент category, если указан, должен быть классом категории предупреждений; по умолчанию он равен
UserWarning. В качестве альтернативы, message может быть экземпляромWarning, в этом случае category будет проигнорирован, и будет использоватьсяmessage.__class__. В этом случае текст сообщения будетstr(message). Эта функция вызывает исключение, если конкретное выдаваемое предупреждение изменяется на ошибку фильтром предупреждений warnings filter. Аргумент stacklevel может использоваться функциями-обёртками, написанными на Python, например:def deprecation(message): warnings.warn(message, DeprecationWarning, stacklevel=2)Это делает так, что предупреждение относится к вызывающей функции
deprecation(), а не к источникуdeprecation()самого (поскольку последнее бы лишило смысла сообщение о предупреждении).source, если предоставлен, — это уничтоженный объект, который выдал
ResourceWarning.Изменено в версии 3.6: Добавлен параметр source.
-
warnings.warn_explicit(message, category, filename, lineno, module=None, registry=None, module_globals=None, source=None) -
Это низкоуровневый интерфейс к функциональности
warn(), позволяющий явно указать сообщение, категорию, имя файла и номер строки, а также необязательно имя модуля и регистр (который должен быть словарем__warningregistry__модуля). Имя модуля по умолчанию — имя файла без.py; если регистр не указан, предупреждение никогда не подавляется. 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) -
Вставить запись в список спецификаций фильтра предупреждений warnings filter specifications. По умолчанию запись вставляется в начало; если append равно true, она вставляется в конец. Проверяет типы аргументов, компилирует регулярные выражения message и module и вставляет их как кортеж в список фильтров предупреждений. Записи, расположенные ближе к началу списка, переопределяют записи, расположенные позже в списке, если обе соответствуют определённому предупреждению. Пропущенные аргументы по умолчанию соответствуют всему.
-
warnings.simplefilter(action, category=Warning, lineno=0, append=False) -
Вставить простую запись в список спецификаций фильтра предупреждений warnings filter specifications. Значение параметров функции аналогично параметрам
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(), как если бы она была вызвана сразу при входе в контекст.Примечание
Менеджер
catch_warningsработает путём замены и последующего восстановления функции модуляshowwarning()и внутреннего списка спецификаций фильтра. Это означает, что менеджер контекста изменяет глобальное состояние, и поэтому не является потокобезопасным.Изменено в версии 3.11: Добавлены параметры action, category, lineno и append.
© 2001–2023 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.11/library/warnings.html