Spec-Zone.ru › Python 3.11

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

Исходный код: 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"

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

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

END_OF_DOCUMENT_MARKER

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

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

Spec-Zone.ru

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