# `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` | Base category for warnings about dubious syntactic features (typically emitted when compiling Python source code, and hence may not be suppressed by runtime filters)
`RuntimeWarning` | Базова категорія для попереджень про сумнівні функції середовища виконання.
`FutureWarning` | Базова категорія для попереджень про застарілі функції, якщо ці попередження призначені для кінцевих користувачів програм, написаних на Python.
`PendingDeprecationWarning` | Базова категорія для попереджень про функції, які в майбутньому будуть припинені (ігноруються за умовчанням).
`ImportWarning` | Основна категорія для попереджень, що викликаються під час процесу імпорту модуля (ігнорується за умовчанням).
`Попередження Unicode` | Базова категорія для попереджень, пов’язаних із Unicode.
`BytesWarning` | Базова категорія для попереджень, пов’язаних із `bytes` і `bytearray`.
`ResourceWarning` | Базова категорія для попереджень, пов’язаних із використанням ресурсів (ігнорується за умовчанням).

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

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

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

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

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

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

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

Якщо повідомляється про попередження, яке не відповідає жодному зареєстрованому фільтру, тоді застосовується дія «за замовчуванням» (звідси й назва).

### Repeated Warning Suppression Criteria

The filters that suppress repeated warnings apply the following criteria to determine if a warning is considered a repeat:

- `"default"`: A warning is considered a repeat only if the (message, category, module, lineno) are all the same.

- `"module"`: A warning is considered a repeat if the (message, category, module) are the same, ignoring the line number.

- `"once"`: A warning is considered a repeat if the (message, category) are the same, ignoring the module and line number.

### Опис фільтрів попереджень

Фільтр попереджень ініціалізується параметрами `-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()

While within the context manager all warnings will simply be ignored. This allows you to use known-deprecated code without having to see the warning while not suppressing the warning for other code that might not be aware of its use of deprecated code.

> Примітка

> See Concurrent safety of Context Managers for details on the concurrency-safety of the `catch_warnings` context manager when used in programs using multiple threads or async functions.

## Попередження щодо тестування

Щоб перевірити попередження, викликані кодом, використовуйте контекстний менеджер `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`, то незалежно від того, які фільтри встановлено, попередження більше не відображатиметься, якщо тільки попередження не пов’язані з реєстром попереджень. до попередження було видалено.

Once the context manager exits, the warnings filter is restored to its state when the context was entered. This prevents tests from changing the warnings filter in unexpected ways between tests and leading to indeterminate test results.

> Примітка

> See Concurrent safety of Context Managers for details on the concurrency-safety of the `catch_warnings` context manager when used in programs using multiple threads or async functions.

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

## Оновлення коду для нових версій залежностей

Категорії попереджень, які в першу чергу цікавлять розробників 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=())

  Видайте попередження, або, можливо, проігноруйте його чи створіть виняток. Аргумент category, якщо він заданий, має бути класом категорії попередження; за замовчуванням `UserWarning`. Крім того, message може бути екземпляром `Warning`, у цьому випадку category буде проігноровано та використовуватиметься `message.__class__`. У цьому випадку текст повідомлення буде `str(message)`. Ця функція викликає виняток, якщо фільтр попереджень змінює конкретне видане попередження на помилку. Аргумент stacklevel може використовуватися функціями-обгортками, написаними на Python, наприклад:

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

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

  The skip_file_prefixes keyword argument can be used to indicate which stack frames are ignored when counting stack levels. This can be useful when you want the warning to always appear at call sites outside of a package when a constant stacklevel does not fit all call paths or is otherwise challenging to maintain. If supplied, it must be a tuple of strings. When prefixes are supplied, stacklevel is implicitly overridden to be `max(2, stacklevel)`. To cause a warning to be attributed to the caller from outside of the current package you might write:

      # 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)

  This makes the warning refer to both the `example.lower.one_way()` and `example.higher.another_way()` call sites only from calling code living outside of `example` package.

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

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

  Змінено в версії 3.12: Added skip_file_prefixes.

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

  This is a low-level interface to the functionality of `warn()`, passing in explicitly the message, category, filename and line number, and optionally other arguments. message must be a string and category a subclass of `Warning` or message may be a `Warning` instance, in which case category will be ignored.

  module, if supplied, should be the module name. If no module is passed, the filename with `.py` stripped is used.

  registry, if supplied, should be the `__warningregistry__` dictionary of the module. If no registry is passed, each warning is treated as the first occurrence, that is, filter actions `"default"`, `"module"` and `"once"` are handled as `"always"`.

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

@warnings.deprecated(msg, *, category=DeprecationWarning, stacklevel=1)

  Decorator to indicate that a class, function or overload is deprecated.

  When this decorator is applied to an object, deprecation warnings may be emitted at runtime when the object is used. static type checkers will also generate a diagnostic on usage of the deprecated object.

  Використання:

      from warnings import deprecated
      from typing import overload

      @deprecated("Use B instead")
      class A:
          pass

      @deprecated("Use g instead")
      def f():
          pass

      @overload
      @deprecated("int support is deprecated")
      def g(x: int) -> int: ...
      @overload
      def g(x: str) -> int: ...

  The warning specified by category will be emitted at runtime on use of deprecated objects. For functions, that happens on calls; for classes, on instantiation and on creation of subclasses. If the category is `None`, no warning is emitted at runtime. The stacklevel determines where the warning is emitted. If it is `1` (the default), the warning is emitted at the direct caller of the deprecated object; if it is higher, it is emitted further up the stack. Static type checker behavior is not affected by the category and stacklevel arguments.

  The deprecation message passed to the decorator is saved in the `__deprecated__` attribute on the decorated object. If applied to an overload, the decorator must be after the `@~typing.overload` decorator for the attribute to exist on the overload as returned by `typing.get_overloads()`.

  Added in version 3.13: See PEP 702.

## Доступні менеджери контексту

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.

  See Фільтр попереджень for the meaning of the category and lineno parameters.

  Примітка

  See Concurrent safety of Context Managers for details on the concurrency-safety of the `catch_warnings` context manager when used in programs using multiple threads or async functions.

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

## Concurrent safety of Context Managers

The behavior of `catch_warnings` context manager depends on the `sys.flags.context_aware_warnings` flag. If the flag is true, the context manager behaves in a concurrent-safe fashion and otherwise not. Concurrent-safe means that it is both thread-safe and safe to use within asyncio coroutines and tasks. Being thread-safe means that behavior is predictable in a multi-threaded program. The flag defaults to true for free-threaded builds and false otherwise.

If the `context_aware_warnings` flag is false, then `catch_warnings` will modify the global attributes of the `warnings` module. This is not safe if used within a concurrent program (using multiple threads or using asyncio coroutines). For example, if two or more threads use the `catch_warnings` class at the same time, the behavior is undefined.

If the flag is true, `catch_warnings` will not modify global attributes and will instead use a `ContextVar` to store the newly established warning filtering state. A context variable provides thread-local storage and it makes the use of `catch_warnings` thread-safe.

The record parameter of the context handler also behaves differently depending on the value of the flag. When record is true and the flag is false, the context manager works by replacing and then later restoring the module’s `showwarning()` function. That is not concurrent-safe.

When record is true and the flag is true, the `showwarning()` function is not replaced. Instead, the recording status is indicated by an internal property in the context variable. In this case, the `showwarning()` function will not be restored when exiting the context handler.

The `context_aware_warnings` flag can be set the `-X context_aware_warnings` command-line option or by the `PYTHON_CONTEXT_AWARE_WARNINGS` environment variable.

> Примітка

> It is likely that most programs that desire thread-safe behaviour of the warnings module will also want to set the `thread_inherit_context` flag to true. That flag causes threads created by `threading.Thread` to start with a copy of the context variables from the thread starting it. When true, the context established by `catch_warnings` in one thread will also apply to new threads started by it. If false, new threads will start with an empty warnings context variable, meaning that any filtering that was established by a `catch_warnings` context manager will no longer be active.

Змінено в версії 3.14: Added the `sys.flags.context_aware_warnings` flag and the use of a context variable for `catch_warnings` if the flag is true. Previous versions of Python acted as if the flag was always set to false.