warnings — Управление предупреждениями
Новая версия 2.1.
Исходный код: Lib/warnings.py
Сообщения о предупреждениях обычно выдаются в ситуациях, когда полезно предупредить пользователя о каком-либо состоянии в программе, когда это состояние (обычно) не оправдывает возникновение исключения и завершение программы. Например, можно выдать предупреждение, когда программа использует устаревший модуль.
Программисты Python выдают предупреждения, вызывая функцию warn(), определённую в этом модуле. (Программисты C используют PyErr_WarnEx(); см. Обработка исключений для получения подробностей).
Сообщения о предупреждениях обычно выводятся в sys.stderr, но их обработку можно гибко настроить, от игнорирования всех предупреждений до превращения их в исключения. Обработка предупреждений может различаться в зависимости от категории предупреждения (см. ниже), текста сообщения о предупреждении и места происхождения предупреждения. Повторные предупреждения для одного и того же места происхождения обычно подавляются.
Существует два этапа управления предупреждениями: сначала, каждый раз, когда выдаётся предупреждение, производится оценка, следует ли выводить сообщение; затем, если сообщение должно быть выведено, оно форматируется и печатается с использованием настраиваемого обработчика.
Определение, следует ли выводить сообщение о предупреждении, контролируется фильтром предупреждений, который представляет собой последовательность правил сопоставления и действий. Правила могут быть добавлены в фильтр вызовом filterwarnings() и сброшены до исходного состояния вызовом resetwarnings().
Вывод сообщений о предупреждениях осуществляется с помощью вызова showwarning(), который может быть переопределён; по умолчанию эта функция форматирует сообщение, вызывая formatwarning(), которая также доступна для использования в пользовательских реализациях.
См. также
logging.captureWarnings() позволяет обрабатывать все предупреждения с помощью стандартной инфраструктуры регистрации.
1. Категории предупреждений
Существует несколько встроенных исключений, которые представляют категории предупреждений. Эта категоризация полезна для фильтрации групп предупреждений. В настоящее время определены следующие классы категорий предупреждений:
Класс | Описание |
|---|---|
Это базовый класс всех классов категорий предупреждений. Это подкласс | |
По умолчанию категория для | |
Базовая категория предупреждений об устаревших функциях (по умолчанию игнорируется). | |
Базовая категория предупреждений о сомнительных синтаксических особенностях. | |
Базовая категория предупреждений о сомнительных особенностях выполнения. | |
Базовая категория предупреждений о конструкциях, семантика которых изменится в будущем. | |
Базовая категория предупреждений о функциях, которые будут устаревшими в будущем (по умолчанию игнорируется). | |
Базовая категория предупреждений, срабатывающих во время импорта модуля (по умолчанию игнорируется). | |
Базовая категория предупреждений, связанных с Unicode. | |
Базовая категория предупреждений, связанных с байтами и массивами байтов. |
Хотя технически это встроенные исключения, они документированы здесь, потому что концептуально они относятся к механизму предупреждений.
Пользовательский код может определять дополнительные категории предупреждений путём наследования от одной из стандартных категорий предупреждений. Категория предупреждений всегда должна быть подклассом класса Warning.
Изменено в версии 2.7: DeprecationWarning игнорируется по умолчанию.
2. Фильтр предупреждений
Фильтр предупреждений контролирует, игнорируются ли предупреждения, отображаются или преобразуются в ошибки (вызывая исключение).
Концептуально, фильтр предупреждений поддерживает упорядоченный список спецификаций фильтра; каждое конкретное предупреждение сопоставляется с каждой спецификацией фильтра в списке по очереди, пока не будет найдено совпадение; совпадение определяет обработку совпадения. Каждый элемент представляет собой кортеж вида (действие, сообщение, категория, модуль, номер_строки), где:
-
действие — одна из следующих строк:
Значение
Обработка
"error"преобразовать соответствующие предупреждения в исключения
"ignore"никогда не выводить соответствующие предупреждения
"always"всегда выводить соответствующие предупреждения
"default"выводить первое появление соответствующих предупреждений для каждого места, где выдаётся предупреждение
"module"выводить первое появление соответствующих предупреждений для каждого модуля, где выдаётся предупреждение
"once"выводить только первое появление соответствующих предупреждений, независимо от места
- сообщение — строка, содержащая регулярное выражение, которому должна соответствовать начало сообщения о предупреждении. Выражение компилируется для обеспечения регистронезависимого соответствия.
-
категория — класс (подкласс
Warning), подклассом которого должна быть категория предупреждения, чтобы соответствовать. - модуль — строка, содержащая регулярное выражение, которому должен соответствовать имя модуля. Выражение компилируется для обеспечения регистрозависимого соответствия.
-
номер_строки — целое число, которому должен соответствовать номер строки, где возникло предупреждение, или
0для соответствия всем номерам строк.
Поскольку класс Warning является производным от встроенного класса Exception, чтобы преобразовать предупреждение в ошибку, мы просто поднимаем category(message).
Фильтр предупреждений инициализируется с помощью опций -W, переданных в командную строку интерпретатора Python. Интерпретатор сохраняет аргументы всех опций -W без интерпретации в sys.warnoptions; модуль warnings анализирует их при первом импорте (недействительные опции игнорируются после вывода сообщения в sys.stderr).
2.1. Фильтры предупреждений по умолчанию
По умолчанию Python устанавливает несколько фильтров предупреждений, которые можно переопределить с помощью опций командной строки, переданных в -W и с помощью вызовов filterwarnings().
-
DeprecationWarning,PendingDeprecationWarningиImportWarningигнорируются. -
BytesWarningигнорируется, если опция-bне указана один или два раза; в этом случае это предупреждение либо отображается (-b), либо преобразуется в исключение (-bb).
3. Временное подавление предупреждений
Если вы используете код, который, по вашим знаниям, вызовет предупреждение, например, устаревшую функцию, но не хотите видеть это предупреждение, то можно подавить предупреждение, используя контекстный менеджер catch_warnings:
import warnings
def fxn():
warnings.warn("deprecated", DeprecationWarning)
with warnings.catch_warnings():
warnings.simplefilter("ignore")
fxn()
Внутри контекстного менеджера все предупреждения просто игнорируются. Это позволяет использовать известный устаревший код без отображения предупреждения, не подавляя предупреждения для другого кода, который может не знать о его использовании устаревшего кода. Примечание: это гарантируется только в однопоточной программе. Если два или более потока одновременно используют контекстный менеджер catch_warnings, поведение не определено.
4. Тестирование предупреждений
Для тестирования предупреждений, генерируемых кодом, используйте контекстный менеджер 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, поведение не определено.
При тестировании нескольких операций, которые генерируют один и тот же тип предупреждения, важно проверить их таким образом, чтобы подтвердить, что каждая операция генерирует новое предупреждение (например, установить предупреждения для повышения в качестве исключений и проверить, что операции вызывают исключения, проверить, что длина списка предупреждений продолжает увеличиваться после каждой операции, или же удалить предыдущие записи из списка предупреждений перед каждой новой операцией).
5. Обновление кода для новых версий Python
Предупреждения, которые интересны только разработчику, по умолчанию игнорируются. Поэтому вы должны убедиться, что протестировали свой код с обычно игнорируемыми предупреждениями, сделав их видимыми. Вы можете сделать это из командной строки, передав -Wd интерпретатору (это сокращение для -W default). Это включает обработку по умолчанию для всех предупреждений, включая те, которые по умолчанию игнорируются. Чтобы изменить действие, выполняемое для обнаруженных предупреждений, просто измените аргумент, передаваемый -W, например, -W error. Подробнее о возможностях см. флаг -W.
Чтобы программно сделать то же самое, что и -Wd, используйте:
warnings.simplefilter('default')
Убедитесь, что этот код выполняется как можно скорее. Это предотвращает неожиданное влияние регистрации поднятых предупреждений на обработку будущих предупреждений.
Игнорирование определенных предупреждений по умолчанию выполняется для предотвращения отображения предупреждений, которые интересны только разработчику. Так как вы не обязательно контролируете интерпретатор, который пользователь использует для выполнения своего кода, возможно, что между вашими циклами выпуска будет выпущена новая версия Python. Новый релиз интерпретатора может вызвать новые предупреждения в вашем коде, которые отсутствовали в более старой интерпретаторе, например, DeprecationWarning для модуля, который вы используете. Хотя как разработчик вы хотите быть проинформированным о том, что ваш код использует устаревший модуль, для пользователя эта информация, по сути, шум и не приносит никакой пользы.
6. Доступные функции
-
warnings.warn(message[, category[, stacklevel]]) -
Выдать предупреждение, или возможно проигнорировать его или вызвать исключение. Аргумент category, если задан, должен быть классом категории предупреждения (см. выше); по умолчанию
UserWarning. В качестве альтернативы message может быть экземпляромWarning, в этом случае category будет проигнорирован и будет использоватьсяmessage.__class__. В этом случае текст сообщения будетstr(message). Эта функция вызывает исключение, если конкретное выданное предупреждение изменяется на ошибку фильтром предупреждений, см. выше. Аргумент stacklevel может использоваться функциями-обёртками, написанными на Python, так:def deprecation(message): warnings.warn(message, DeprecationWarning, stacklevel=2)Это заставляет предупреждение ссылаться на вызывающую функцию
deprecation(), а не на источникdeprecation()(поскольку последнее поступит вразрез с целью сообщения предупреждения).
-
warnings.warn_explicit(message, category, filename, lineno[, module[, registry[, module_globals]]]) -
Это низкоуровневый интерфейс к функциональности
warn(), принимающий явно сообщение, категорию, имя файла и номер строки, а также необязательно имя модуля и реестр (который должен быть__warningregistry__словарем модуля). Имя модуля по умолчанию — имя файла с удалённой частью.py; если реестр не передан, предупреждение никогда не подавляется. message должен быть строкой, а category — подклассомWarningили message может быть экземпляромWarning, в этом случае category будет проигнорирован.module_globals, если указан, должен быть глобальным пространством имён, используемым кодом, для которого выдаётся предупреждение. (Этот аргумент используется для поддержки отображения исходного кода модулей, найденных в zip-файлах или других источниках импорта, не являющихся файловой системой).
Изменено в версии 2.5: Добавлен параметр module_globals.
-
warnings.warnpy3k(message[, category[, stacklevel]]) -
Выдать предупреждение, связанное с устареванием Python 3.x. Предупреждения отображаются только при запуске Python с опцией -3. Как и в
warn(), message должен быть строкой, а category — подклассомWarning.warnpy3k()используетDeprecationWarningв качестве категории предупреждения по умолчанию.Добавлена в версии 2.6.
-
warnings.showwarning(message, category, filename, lineno[, file[, line]]) -
Записать предупреждение в файл. По умолчанию реализация вызывает
formatwarning(message, category, filename, lineno, line)и записывает полученную строку в file, который по умолчаниюsys.stderr. Вы можете заменить эту функцию на альтернативную, присвоивwarnings.showwarning. line — строка исходного кода, которая должна быть включена в сообщение предупреждения; если line не указана,showwarning()попытается прочитать строку, указанную filename и lineno.Изменено в версии 2.7: Аргумент line является обязательным.
-
warnings.formatwarning(message, category, filename, lineno[, line]) -
Форматировать предупреждение стандартным способом. Возвращает строку, которая может содержать вложенные новые строки и заканчивается новой строкой. line — строка исходного кода, которая должна быть включена в сообщение предупреждения; если line не указана,
formatwarning()попытается прочитать строку, указанную filename и lineno.Изменено в версии 2.6: Добавлен аргумент line.
-
warnings.filterwarnings(action[, message[, category[, module[, lineno[, append]]]]]) -
Вставить запись в список спецификаций фильтра предупреждений. По умолчанию запись вставляется в начало списка; если append равно true, она вставляется в конец. Проверяет типы аргументов, компилирует регулярные выражения message и module и вставляет их как кортеж в список фильтров предупреждений. Записи, более близкие к началу списка, перезаписывают записи, расположенные позже в списке, если обе совпадают с конкретным предупреждением. Пропущенные аргументы по умолчанию устанавливаются таким образом, чтобы соответствовать всему.
-
warnings.simplefilter(action[, category[, lineno[, append]]]) -
Вставить простую запись в список спецификаций фильтра предупреждений. Значение параметров функции соответствует
filterwarnings(), но регулярные выражения не нужны, так как вставленный фильтр всегда соответствует любому сообщению в любом модуле, если категория и номер строки совпадают.
-
warnings.resetwarnings() -
Сброс фильтра предупреждений. Это отбрасывает эффект всех предыдущих вызовов
filterwarnings(), включая опции командной строки-Wи вызовыsimplefilter().
7. Доступные менеджеры контекста
-
class warnings.catch_warnings([*, record=False, module=None]) -
Менеджер контекста, который копирует и при выходе восстанавливает фильтр предупреждений и функцию
showwarning(). Если аргумент record равенFalse(значение по умолчанию), менеджер контекста возвращаетNoneпри входе. Если record равенTrue, возвращается список, который постепенно заполняется объектами, как их видит пользовательская функцияshowwarning()(которая также подавляет вывод вsys.stdout). Каждый объект в списке имеет атрибуты с теми же именами, что и аргументы функцииshowwarning().Аргумент module принимает модуль, который будет использоваться вместо модуля, возвращаемого при импорте
warnings, чей фильтр будет защищен. Этот аргумент предназначен в основном для тестирования самого модуляwarnings.Примечание
Менеджер
catch_warningsработает путем замены и последующего восстановления функции модуляshowwarning()и внутреннего списка спецификаций фильтра. Это означает, что менеджер контекста изменяет глобальное состояние и поэтому не является потокобезопасным.Примечание
В Python 3 аргументы конструктора
catch_warningsявляются только ключевыми аргументами.Добавлена в версии 2.6.
© 2001–2020 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/2.7/library/warnings.html