Spec-Zone.ru › Python 3.8

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 отличались в зависимости от того, удалялась ли функция полностью или изменялся её функционал. Теперь они различаются на основе целевой аудитории и того, как они обрабатываются фильтрами предупреждений по умолчанию.

END_OF_DOCUMENT_MARKER

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

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

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

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

    Значение

    Обработка

    "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–2022 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.8/library/warnings.html

Spec-Zone.ru

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