Spec-Zone.ru › Python 3.12

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, *, skip_file_prefixes=None)

Выдать предупреждение, или, возможно, проигнорировать его или вызвать исключение. Аргумент category, если он указан, должен быть классом категории предупреждения; по умолчанию он равен UserWarning. В качестве альтернативы, message может быть экземпляром Warning, в этом случае category будет проигнорирован, и message.__class__ будет использован. В этом случае текст сообщения будет str(message). Эта функция вызывает исключение, если конкретное выданное предупреждение преобразовано в ошибку с помощью фильтра предупреждений фильтра предупреждений. Аргумент stacklevel может использоваться функциями-обёртками, написанными на Python, например:

def deprecated_api(message):
    warnings.warn(message, DeprecationWarning, stacklevel=2)

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

Ключевой аргумент skip_file_prefixes может использоваться для указания строк, которые игнорируются при подсчете уровней стека. Это может быть полезно, когда вы хотите, чтобы предупреждение всегда отображалось в местах вызова вне пакета, когда константный stacklevel не подходит для всех путей вызова или его в противном случае сложно поддерживать. Если он указан, он должен быть кортежем строк. При указании префиксов stacklevel неявным образом переопределяется на max(2, stacklevel). Для того, чтобы предупреждение приписывалось вызывающей функции извне текущего пакета, вы можете написать:

# example/lower.py
_warn_skips = (os.path.dirname(__file__),)

def one_way(r_luxury_yacht=None, t_wobbler_mangrove=None):
    if r_luxury_yacht:
        warnings.warn("Please migrate to t_wobbler_mangrove=.",
                      skip_file_prefixes=_warn_skips)

# example/higher.py
from . import lower

def another_way(**kw):
    lower.one_way(**kw)

Это заставляет предупреждение относиться как к местам вызова example.lower.one_way() и package.higher.another_way(), так и к местам вызова из вызывающего кода, находящегося вне пакета example.

source, если указан, — это уничтоженный объект, который выдал ResourceWarning.

Изменено в версии 3.6: Добавлен параметр source.

Изменено в версии 3.12: Добавлен skip_file_prefixes.

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, action=None, category=Warning, lineno=0, append=False)

Менеджер контекста, который копирует и при выходе восстанавливает фильтр предупреждений и функцию showwarning(). Если аргумент record равен False (по умолчанию), менеджер контекста возвращает None при входе. Если record равен True, возвращается список, который пополняется объектами, обрабатываемыми пользовательской функцией showwarning() (которая также подавляет вывод в sys.stdout). Каждый объект в списке имеет атрибуты с теми же именами, что и аргументы функции showwarning().

Аргумент module принимает модуль, который будет использоваться вместо модуля, возвращаемого при импорте warnings, фильтр которого будет защищён. Этот аргумент в основном предназначен для тестирования модуля warnings самому.

Если аргумент action не равен None, оставшиеся аргументы передаются функции simplefilter() так, как будто она была вызвана немедленно при входе в контекст.

Примечание

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

Изменено в версии 3.11: Добавлены параметры action, category, lineno и append.

© 2001–2024 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.12/library/warnings.html

Spec-Zone.ru

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