# `warnings` — Warning control

Вихідний код: 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` | Основна категорія для попереджень, що викликаються під час процесу імпорту модуля (ігнорується за умовчанням).
`Попередження Unicode` | Базова категорія для попереджень, пов’язаних із Unicode.
`BytesWarning` | Базова категорія для попереджень, пов’язаних із `bytes` і `bytearray`.
`ResourceWarning` | Базова категорія для попереджень, пов’язаних із використанням ресурсів (ігнорується за умовчанням).

Змінено в версії 3.7: Раніше `DeprecationWarning` і `FutureWarning` розрізняли залежно від того, видаляється функція повністю чи змінюється її поведінка. Тепер вони розрізняються на основі цільової аудиторії та способу їх обробки за допомогою фільтрів попереджень за замовчуванням.

## Фільтр попереджень

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

Концептуально, фільтр попереджень підтримує впорядкований список специфікацій фільтра; будь-яке конкретне попередження порівнюється з кожною специфікацією фільтра в списку по черзі, доки не буде знайдено збіг; фільтр визначає розташування відповідності. Кожен запис є кортежем у формі (дія, повідомлення, категорія, модуль, lineno), де:

- action є одним із таких рядків:

  Значення | Розпорядження
  --- | ---
  `"за умовчанням"` | надрукувати перше повторення відповідних попереджень для кожного місця (модуль + номер рядка), де видається попередження
  `"помилка"` | перетворити відповідні попередження на винятки
  `"ігнорувати"` | ніколи не друкувати відповідні попередження
  `"завжди"` | завжди друкувати відповідні попередження
  `"модуль"` | надрукувати перше повторення відповідних попереджень для кожного модуля, де видається попередження (незалежно від номера рядка)
  `"один раз"` | друкувати лише перше повторення відповідних попереджень, незалежно від розташування

- message — це рядок, що містить регулярний вираз, якому має відповідати початок попереджувального повідомлення без урахування регістру. У `-W` і `PYTHONWARNINGS` message — це літеральний рядок, який має містити початок попереджувального повідомлення (незалежно від регістру), ігноруючи пробіли на початку або в кінці message .

- category — це клас (підклас `Warning`), підкласом якого має бути категорія попередження, щоб відповідати.

- module is a string containing a regular expression that the start of the fully qualified module name must match, case-sensitively. In `-W` and `PYTHONWARNINGS`, module is a literal string that the fully qualified module name must be equal to (case-sensitively), ignoring any whitespace at the start or end of module.

- lineno — це ціле число, якому має відповідати номер рядка, у якому виникло попередження, або `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

У debug build список стандартних фільтрів попереджень порожній.

Змінено в версії 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)`. Ця функція викликає виняток, якщо фільтр попереджень змінює конкретне видане попередження на помилку. Аргумент stacklevel може використовуватися функціями-обгортками, написаними на Python, наприклад:

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

  This makes the warning refer to `deprecation()`“s caller, rather than to the source of `deprecation()` itself (since the latter would defeat the purpose of the warning message).

  джерело, якщо вказано, це знищений об’єкт, який випустив `ResourceWarning`.

  Змінено в версії 3.6: Додано параметр джерело.

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-файлах або інших джерелах імпорту, які не належать до файлової системи).

  джерело, якщо вказано, це знищений об’єкт, який випустив `ResourceWarning`.

  Змінено в версії 3.6: Додайте параметр source.

warnings.showwarning(message, category, filename, lineno, file=None, line=None)

  Записати попередження у файл. Стандартна реалізація викликає `formatwarning(message, category, filename, lineno, line)` і записує результуючий рядок у file, який за замовчуванням має значення `sys.stderr`. Ви можете замінити цю функцію будь-якою викликаною, призначивши `warning.showwarning`. рядок — це рядок вихідного коду, який буде включено в повідомлення попередження; якщо рядок не надано, `showwarning()` спробує прочитати рядок, визначений filename і lineno.

warnings.formatwarning(message, category, filename, lineno, line=None)

  Відформатуйте попередження стандартним способом. Це повертає рядок, який може містити вбудовані символи нового рядка та закінчується символом нового рядка. рядок — це рядок вихідного коду, який буде включено в повідомлення попередження; якщо рядок не вказано, `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`.

  If the action argument is not `None`, the remaining arguments are passed to `simplefilter()` as if it were called immediately on entering the context.

  Примітка

  Менеджер `catch_warnings` працює, замінюючи, а потім пізніше відновлюючи функцію `showwarning()` модуля та внутрішній список специфікацій фільтрів. Це означає, що менеджер контексту змінює глобальний стан і тому не є потоково-безпечним.

  Змінено в версії 3.11: Added the action, category, lineno, and append parameters.