Spec-Zone.ru › Python 3.10

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"

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

  • сообщение — это строка, содержащая регулярное выражение, которому должно соответствовать начало сообщения предупреждения, не чувствительное к регистру. В -W и PYTHONWARNINGS сообщение — это буквальная строка, которая должна содержаться в начале сообщения предупреждения (нечувствительно к регистру), игнорируя пробелы в начале и конце сообщения.
  • категория — это класс (подкласс Warning), подклассом которого должна быть категория предупреждения для соответствия.
  • модуль — это строка, содержащая регулярное выражение, которому должно соответствовать начало полного имени модуля, чувствительное к регистру. В -W и PYTHONWARNINGS модуль — это буквальная строка, которая должна быть равна полному имени модуля (чувствительно к регистру), игнорируя пробелы в начале и конце модуля.
  • номер_строки — целое число, которому должен соответствовать номер строки, в которой возникло предупреждение, или 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"

Фильтр предупреждений по умолчанию

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

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

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

Вставить простую запись в список спецификаций фильтра предупреждений warnings filter specifications. Значение параметров функции такое же, как у 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–2023 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.10/library/warnings.html

Spec-Zone.ru

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