Spec-Zone.ru › Python 3.7

warnings — Управление предупреждениями

Исходный код: Lib/warnings.py

Сообщения о предупреждениях обычно выдаются в ситуациях, когда полезно оповестить пользователя о каком-либо состоянии в программе, где это состояние (обычно) не требует поднятия исключения и завершения программы. Например, можно выдать предупреждение, когда программа использует устаревший модуль.

Программисты Python выдают предупреждения, вызывая функцию warn(), определённую в этом модуле. (Программисты C используют PyErr_WarnEx(); см. Обработка исключений для получения подробной информации).

Сообщения о предупреждениях обычно записываются в sys.stderr, но их обработка может быть гибко изменена, от игнорирования всех предупреждений до преобразования их в исключения. Обработка предупреждений может изменяться в зависимости от категории предупреждения (см. ниже), текста сообщения о предупреждении и местоположения источника, где оно выводится. Повторные предупреждения для одного и того же места происхождения обычно подавляются.

Существует два этапа управления предупреждениями: во-первых, каждый раз, когда выдается предупреждение, определяется, следует ли выдавать сообщение; во-вторых, если сообщение должно быть выдано, оно форматируется и печатается с помощью настраиваемого обработчика.

Определение, следует ли выводить сообщение о предупреждении, контролируется фильтром предупреждений, который представляет собой последовательность правил сопоставления и действий. Правила можно добавить в фильтр, вызвав filterwarnings(), и сбросить в исходное состояние, вызвав resetwarnings().

Вывод сообщений о предупреждениях осуществляется вызовом showwarning(), который может быть переопределён; по умолчанию эта функция форматирует сообщение, вызывая formatwarning(), которая также доступна для использования пользовательскими реализациями.

См. также

logging.captureWarnings() позволяет обрабатывать все предупреждения с использованием стандартной инфраструктуры ведения журнала.

Категории предупреждений

Существует ряд встроенных исключений, представляющих категории предупреждений. Эта категоризация полезна для фильтрации групп предупреждений.

Хотя технически это встроенные исключения, они документированы здесь, потому что концептуально они относятся к механизму предупреждений.

Пользовательский код может определить дополнительные категории предупреждений, наследуя одну из стандартных категорий предупреждений. Категория предупреждений всегда должна быть подклассом класса Warning.

В настоящее время определены следующие классы категорий предупреждений:

Класс

Описание

Warning

Это базовый класс всех классов категорий предупреждений. Это подкласс Exception.

UserWarning

По умолчанию категория для warn().

DeprecationWarning

Базовая категория предупреждений об устаревших функциях, когда эти предупреждения предназначены для других разработчиков Python (по умолчанию игнорируются, если не вызваны кодом в __main__).

SyntaxWarning

Базовая категория предупреждений о сомнительных синтаксических конструкциях.

RuntimeWarning

Базовая категория предупреждений о сомнительных функциях выполнения.

FutureWarning

Базовая категория предупреждений об устаревших функциях, когда эти предупреждения предназначены для конечных пользователей приложений, написанных на Python.

PendingDeprecationWarning

Базовая категория предупреждений о функциях, которые будут устаревшими в будущем (по умолчанию игнорируются).

ImportWarning

Базовая категория предупреждений, вызываемых во время импорта модуля (по умолчанию игнорируются).

UnicodeWarning

Базовая категория предупреждений, связанных с Unicode.

BytesWarning

Базовая категория предупреждений, связанных с bytes и bytearray.

ResourceWarning

Базовая категория предупреждений, связанных с использованием ресурсов.

Изменено в версии 3.7: Ранее DeprecationWarning и FutureWarning отличались в зависимости от того, удаляется ли функция полностью или изменяется ли её поведение. Теперь они различаются на основе целевой аудитории и способа обработки по умолчанию.

Фильтр предупреждений

Фильтр предупреждений управляет тем, игнорируются предупреждения, отображаются или преобразуются в ошибки (вызывая исключение).

Концептуально, фильтр предупреждений поддерживает упорядоченный список спецификаций фильтра; любое конкретное предупреждение сопоставляется с каждой спецификацией фильтра в списке поочередно, пока не будет найдено соответствие; фильтр определяет расположение соответствия. Каждый элемент — это кортеж вида (действие, сообщение, категория, модуль, номер строки), где:

  • действие — одна из следующих строк:

    Значение

    Обработка

    "default"

    вывести первое вхождение соответствующих предупреждений для каждого местоположения (модуль + номер строки), где выводится предупреждение

    "error"

    преобразовать соответствующие предупреждения в исключения

    "ignore"

    никогда не выводить соответствующие предупреждения

    "always"

    всегда выводить соответствующие предупреждения

    "module"

    выводить первое вхождение соответствующих предупреждений для каждого модуля, где выводится предупреждение (независимо от номера строки)

    "once"

    выводить только первое вхождение соответствующих предупреждений, независимо от местоположения

  • сообщение — строка, содержащая регулярное выражение, которому должно соответствовать начало сообщения о предупреждении. Выражение компилируется для обеспечения игнорирования регистра.
  • категория — класс (подкласс Warning), подклассом которого должна быть категория предупреждения для соответствия.
  • модуль — строка, содержащая регулярное выражение, которому должен соответствовать имя модуля. Выражение компилируется для учета регистра.
  • номер строки — целое число, которому должен соответствовать номер строки, где возникло предупреждение, или 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"
                             # and any subpackages of "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). Эта функция вызывает исключение, если конкретное выданное предупреждение изменено на ошибку фильтром предупреждений, см. выше. Аргумент 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)

Добавить запись в список спецификаций фильтра предупреждений. По умолчанию запись вставляется в начало; если append равно true, она вставляется в конец. Проверяет типы аргументов, компилирует регулярные выражения message и module и вставляет их как кортеж в список фильтров предупреждений. Записи, расположенные ближе к началу списка, перекрывают записи, расположенные позже в списке, если оба соответствуют определённому предупреждению. Пропущенные аргументы по умолчанию имеют значение, соответствующее всему.

warnings.simplefilter(action, category=Warning, lineno=0, append=False)

Вставить простую запись в список спецификаций фильтра предупреждений. Значение параметров функции такое же, как у filterwarnings(), но регулярные выражения не нужны, так как вставляемый фильтр всегда соответствует любому сообщению в любом модуле, при условии, что категория и номер строки совпадают.

warnings.resetwarnings()

Сбросить фильтр предупреждений. Это отбрасывает действие всех предыдущих вызовов filterwarnings(), включая тот из командной строки -W и вызовов simplefilter().

Доступные менеджеры контекста

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.7/library/warnings.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API