Spec-Zone.ru › Python 3.6

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

Исходный код: Lib/warnings.py

Сообщения о предупреждениях обычно выдаются в ситуациях, когда полезно предупредить пользователя о каком-либо состоянии в программе, при этом это состояние (обычно) не оправдывает поднятия исключения и завершения программы. Например, можно выдать предупреждение, когда программа использует устаревший модуль.

Программисты Python выдают предупреждения, вызывая функцию warn(), определённую в этом модуле. (Программисты C используют PyErr_WarnEx(); см. Обработка исключений для получения подробностей).

Сообщения о предупреждениях обычно записываются в sys.stderr, но их поведение можно гибко изменять, от игнорирования всех предупреждений до преобразования их в исключения. Поведение предупреждений может варьироваться в зависимости от категории предупреждения (см. ниже), текста сообщения о предупреждении и местоположения источника, где оно выдаётся. Повторные предупреждения для одного и того же местоположения источника обычно подавляются.

Существует две стадии управления предупреждениями: во-первых, каждый раз при выдаче предупреждения определяется, должно ли сообщение выводиться; во-вторых, если сообщение должно быть выведено, оно форматируется и выводится с использованием настраиваемого обработчика.

Определение, следует ли выводить сообщение о предупреждении, контролируется фильтром предупреждений, который представляет собой последовательность правил сопоставления и действий. Правила можно добавить в фильтр, вызвав filterwarnings(), и сбросить до исходного состояния, вызвав resetwarnings().

Вывод сообщений о предупреждениях выполняется путем вызова showwarning(), который можно переопределить; по умолчанию эта функция форматирует сообщение, вызывая formatwarning(), которая также доступна для использования пользовательскими реализациями.

См. также

logging.captureWarnings() позволяет обрабатывать все предупреждения с использованием стандартной инфраструктуры регистрации.

29.5.1. Категории предупреждений

Существует ряд встроенных исключений, которые представляют категории предупреждений. Эта категоризация полезна для фильтрации групп предупреждений. В настоящее время определены следующие классы категорий предупреждений:

Класс

Описание

Warning

Это базовый класс всех классов категорий предупреждений. Это подкласс Exception.

UserWarning

По умолчанию категория для warn().

DeprecationWarning

Основная категория предупреждений об устаревших функциях (по умолчанию игнорируется).

SyntaxWarning

Основная категория предупреждений о сомнительных синтаксических конструкциях.

RuntimeWarning

Основная категория предупреждений о сомнительных функциях выполнения.

FutureWarning

Основная категория предупреждений о конструкциях, которые изменят семантику в будущем.

PendingDeprecationWarning

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

ImportWarning

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

UnicodeWarning

Основная категория предупреждений, связанных с Unicode.

BytesWarning

Основная категория предупреждений, связанных с bytes и bytearray.

ResourceWarning

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

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

Пользовательский код может определить дополнительные категории предупреждений, унаследовав один из стандартных категорий предупреждений. Категория предупреждений всегда должна быть подклассом класса Warning.

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

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

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

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

    Значение

    Поведение

    "error"

    превратить соответствующие предупреждения в исключения

    "ignore"

    никогда не выводить соответствующие предупреждения

    "always"

    всегда выводить соответствующие предупреждения

    "default"

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

    "module"

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

    "once"

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

  • сообщение — строка, содержащая регулярное выражение, с которым должно совпадать начало сообщения о предупреждении. Выражение компилируется таким образом, чтобы всегда игнорировать регистр.
  • категория — класс (подкласс Warning), подклассом которого должна быть категория предупреждения для совпадения.
  • модуль — строка, содержащая регулярное выражение, с которым должно совпадать имя модуля. Выражение компилируется таким образом, чтобы учитывать регистр.
  • номер_строки — целое число, с которым должен совпадать номер строки, где произошло предупреждение, или 0 для сопоставления всех номеров строк.

Поскольку класс Warning происходит от встроенного класса Exception, чтобы преобразовать предупреждение в ошибку, мы просто поднимаем category(message).

Фильтр предупреждений инициализируется параметрами -W, переданными в командную строку интерпретатора Python. Интерпретатор сохраняет аргументы для всех параметров -W без интерпретации в sys.warnoptions; модуль warnings анализирует их при первом импорте (некорректные параметры игнорируются после вывода сообщения в sys.stderr).

29.5.2.1. По умолчанию фильтры предупреждений

По умолчанию Python устанавливает несколько фильтров предупреждений, которые могут быть переопределены с помощью параметров командной строки, переданных -W и вызовам filterwarnings().

  • DeprecationWarning и PendingDeprecationWarning, а также ImportWarning игнорируются.
  • BytesWarning игнорируется, если параметр -b указан один или два раза; в этом случае это предупреждение либо отображается (-b) или преобразуется в исключение (-bb).
  • ResourceWarning игнорируется, если Python был скомпилирован в отладочном режиме.

Изменено в версии 3.2: DeprecationWarning теперь игнорируется по умолчанию, помимо PendingDeprecationWarning.

29.5.3. Временное подавление предупреждений

Если вы используете код, который, как известно, генерирует предупреждение, например, устаревшую функцию, но не хотите видеть это предупреждение, вы можете подавить его с помощью контекстного менеджера catch_warnings:

import warnings

def fxn():
    warnings.warn("deprecated", DeprecationWarning)

with warnings.catch_warnings():
    warnings.simplefilter("ignore")
    fxn()

Внутри контекстного менеджера все предупреждения просто будут проигнорированы. Это позволяет использовать известный устаревший код, не видя предупреждения, не подавляя предупреждения для другого кода, который может не знать о его использовании устаревшего кода. Примечание: это гарантируется только в однопоточных приложениях. Если два или более потока используют контекстный менеджер catch_warnings одновременно, поведение не определено.

29.5.4. Тестирование предупреждений

Для тестирования предупреждений, генерируемых кодом, используйте контекстный менеджер 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 одновременно, поведение не определено.

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

29.5.5. Обновление кода для новых версий Python

По умолчанию предупреждения, представляющие интерес только для разработчика, игнорируются. Поэтому необходимо убедиться, что ваш код тестируется с обычно игнорируемыми предупреждениями, сделанными видимыми. Это можно сделать из командной строки, передав -Wd интерпретатору (это сокращение от -W default). Это включает обработку по умолчанию для всех предупреждений, включая те, которые игнорируются по умолчанию. Чтобы изменить действие, выполняемое для встреченных предупреждений, просто измените аргумент, передаваемый в -W, например -W error. Подробнее о возможностях ознакомьтесь с флагом -W.

Для программной реализации того же, что и -Wd, используйте:

warnings.simplefilter('default')

Убедитесь, что этот код выполняется как можно скорее. Это предотвращает неожиданное влияние регистрации поднятых предупреждений на обработку будущих предупреждений.

Игнорирование некоторых предупреждений по умолчанию делается для предотвращения отображения предупреждений, представляющих интерес только для разработчика. Поскольку вы не обязательно контролируете интерпретатор, используемый пользователем для запуска кода, возможно, между вашими циклами выпуска будет выпущена новая версия Python. Новый релиз интерпретатора может сгенерировать новые предупреждения в вашем коде, которых не было в более старой версии интерпретатора, например, DeprecationWarning для используемого модуля. Хотя вы, как разработчик, хотите получать уведомления о том, что ваш код использует устаревший модуль, для пользователя эта информация фактически является шумом и не приносит никакой пользы.

Модуль unittest также был обновлён для использования фильтра 'default' при запуске тестов.

29.5.6. Доступные функции

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().

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

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

Spec-Zone.ru

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