Spec-Zone.ru › Python 3.5

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

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

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

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

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

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

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

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

См. также

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

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

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

Класс Описание
Warning Это базовый класс всех классов категорий предупреждений. Это подкласс Exception.
UserWarning По умолчанию категория для warn().
DeprecationWarning Основная категория предупреждений об устаревших функциях (по умолчанию игнорируется).
SyntaxWarning Основная категория предупреждений о сомнительных синтаксических конструкциях.
RuntimeWarning Основная категория предупреждений о сомнительных функциях выполнения.
FutureWarning Основная категория предупреждений о конструкциях, которые в будущем изменят своё семантическое значение.
PendingDeprecationWarning Основная категория предупреждений о функциях, которые будут устаревшими в будущем (по умолчанию игнорируется).
ImportWarning Основная категория предупреждений, вызываемых во время импорта модуля (по умолчанию игнорируется).
UnicodeWarning Основная категория предупреждений, связанных с Unicode.
BytesWarning Основная категория предупреждений, связанных с bytes и bytearray.
ResourceWarning Основная категория предупреждений, связанных с использованием ресурсов.

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

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

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

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

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

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

    Значение Поведение
    "error" преобразовать соответствующие предупреждения в исключения
    "ignore" никогда не печатать соответствующие предупреждения
    "always" всегда печатать соответствующие предупреждения
    "default" печатать первое вхождение соответствующих предупреждений для каждого местоположения, где выдаётся предупреждение
    "module" печатать первое вхождение соответствующих предупреждений для каждого модуля, где выдаётся предупреждение
    "once" печатать только первое вхождение соответствующих предупреждений, независимо от местоположения
  • сообщение — строка, содержащая регулярное выражение, которому должно соответствовать начало сообщения о предупреждении. Выражение компилируется для обеспечения регистронезависимого соответствия.
  • категория — класс (подкласс Warning), подклассом которого должна быть категория предупреждения для соответствия.
  • модуль — строка, содержащая регулярное выражение, которому должно соответствовать имя модуля. Выражение компилируется для обеспечения регистрозависимого соответствия.
  • номер строки — целое число, которому должен соответствовать номер строки, где произошло предупреждение, или 0 для соответствия всем номерам строк.

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

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

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

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

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

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

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

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

import warnings

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

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

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

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 одновременно, поведение не определено.

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

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

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

Чтобы программно сделать то же, что и -Wd, используйте:

warnings.simplefilter('default')

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

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

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

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

warnings.warn(message, category=None, stacklevel=1)

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

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

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

warnings.warn_explicit(message, category, filename, lineno, module=None, registry=None, module_globals=None)

Это низкоуровневый интерфейс для функциональности warn(), в котором явно передаются сообщение, категория, имя файла и номер строки, а также необязательно имя модуля и реестр (который должен быть словарем __warningregistry__ модуля). Имя модуля по умолчанию - имя файла с .py удалено; если реестр не передан, предупреждение никогда не подавляется. message должно быть строкой, а category - подклассом Warning или message может быть экземпляром Warning, в этом случае category будет проигнорирован.

module_globals, если задано, должно содержать глобальное пространство имён, используемое кодом, для которого выдаётся предупреждение. (Этот аргумент используется для поддержки отображения исходного кода для модулей, найденных в zip-файлах или других источниках импорта, не являющихся файлами на диске).

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

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.5/library/warnings.html

Spec-Zone.ru

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