warnings — Управление предупреждениями
Исходный код: Lib/warnings.py
Сообщения о предупреждениях обычно выдаются в ситуациях, когда полезно предупредить пользователя о каком-либо состоянии в программе, при этом это состояние (обычно) не оправдывает поднятия исключения и завершения программы. Например, можно выдать предупреждение, когда программа использует устаревший модуль.
Программисты Python выдают предупреждения, вызывая функцию warn(), определённую в этом модуле. (Программисты C используют PyErr_WarnEx(); см. Обработка исключений для получения подробной информации).
Сообщения о предупреждениях обычно записываются в sys.stderr, но их поведение можно гибко настраивать, от игнорирования всех предупреждений до преобразования их в исключения. Поведение предупреждений может различаться в зависимости от категории предупреждения (см. ниже), текста сообщения о предупреждении и местоположения источника, где оно выдаётся. Повторения конкретного предупреждения для одного и того же местоположения источника обычно подавляются.
Существуют два этапа управления предупреждениями: во-первых, каждый раз, когда выдаётся предупреждение, определяется, следует ли выдавать сообщение; во-вторых, если сообщение должно быть выдано, оно форматируется и печатается с помощью настраиваемого обработчика.
Определение, следует ли выдавать сообщение о предупреждении, контролируется фильтром предупреждений, который представляет собой последовательность правил сопоставления и действий. Правила можно добавить в фильтр, вызвав filterwarnings(), и сбросить до состояния по умолчанию, вызвав resetwarnings().
Вывод сообщений о предупреждениях выполняется путём вызова showwarning(), который может быть переопределён; стандартная реализация этой функции форматирует сообщение, вызывая formatwarning(), который также доступен для использования в пользовательских реализациях.
См. также
logging.captureWarnings() позволяет обрабатывать все предупреждения с помощью стандартной инфраструктуры регистрации.
1. Категории предупреждений
Существует несколько встроенных исключений, которые представляют категории предупреждений. Эта категоризация полезна для фильтрации групп предупреждений. В настоящее время определены следующие классы категорий предупреждений:
| Класс | Описание |
|---|---|
Warning | Это базовый класс всех классов категорий предупреждений. Это подкласс Exception. |
UserWarning | По умолчанию категория для warn(). |
DeprecationWarning | Основная категория предупреждений об устаревших функциях (по умолчанию игнорируется). |
SyntaxWarning | Основная категория предупреждений о сомнительных синтаксических конструкциях. |
RuntimeWarning | Основная категория предупреждений о сомнительных функциях выполнения. |
FutureWarning | Основная категория предупреждений о конструкциях, которые в будущем изменят своё семантическое значение. |
PendingDeprecationWarning | Основная категория предупреждений о функциях, которые будут устаревшими в будущем (по умолчанию игнорируется). |
ImportWarning | Основная категория предупреждений, вызываемых во время импорта модуля (по умолчанию игнорируется). |
UnicodeWarning | Основная категория предупреждений, связанных с Unicode. |
BytesWarning | Основная категория предупреждений, связанных с bytes и bytearray. |
ResourceWarning | Основная категория предупреждений, связанных с использованием ресурсов. |
Хотя это технически встроенные исключения, они документированы здесь, потому что концептуально они относятся к механизму предупреждений.
Пользовательский код может определить дополнительные категории предупреждений, унаследовав одну из стандартных категорий предупреждений. Категория предупреждений всегда должна быть подклассом класса Warning.
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). -
ResourceWarningигнорируется, если Python был скомпилирован в отладочном режиме.
Изменено в версии 3.2: DeprecationWarning теперь игнорируется по умолчанию, помимо PendingDeprecationWarning.
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 для модуля, который вы используете. Хотя вам как разработчику нужно получать уведомления о том, что ваш код использует устаревший модуль, для пользователя эта информация является, по сути, шумом и не приносит ему никакой пользы.
Модуль unittest также был обновлен для использования фильтра 'default' при выполнении тестов.
6. Доступные функции
-
warnings.warn(message, category=None, stacklevel=1) -
Выдать предупреждение, или, возможно, игнорировать его или вызвать исключение. Аргумент 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=None, registry=None, module_globals=None) -
Это низкоуровневый интерфейс для функциональности
warn(), в котором явно передаются сообщение, категория, имя файла и номер строки, а также необязательно имя модуля и реестр (который должен быть словарем__warningregistry__модуля). Имя модуля по умолчанию - имя файла с.pyудалено; если реестр не передан, предупреждение никогда не подавляется. message должно быть строкой, а category - подклассомWarningили message может быть экземпляромWarning, в этом случае category будет проигнорирован.module_globals, если задано, должно содержать глобальное пространство имён, используемое кодом, для которого выдаётся предупреждение. (Этот аргумент используется для поддержки отображения исходного кода для модулей, найденных в zip-файлах или других источниках импорта, не являющихся файлами на диске).
-
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().
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()и внутреннего списка спецификаций фильтра. Это означает, что менеджер контекста изменяет глобальное состояние и поэтому не является потокобезопасным.
© 2001–2020 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.5/library/warnings.html