Spec-Zone.ru › Python 3.9

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

Spec-Zone.ru

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