Перейти к содержимому

Как отключить warnings python

  • автор:

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

Работа в IPython может иногда сопровождаться появлением различных предупреждений, которые генерируются с помощью вызовов warnings.warn из разных пакетов.

Алексей Кодов
Автор статьи
7 июля 2023 в 18:24

Работа в IPython может иногда сопровождаться появлением различных предупреждений, которые генерируются с помощью вызовов warnings.warn из разных пакетов. Это может быть нежелательно в некоторых ситуациях, например, при создании обучающего видео, где такие предупреждения могут сбивать с толку зрителей.

Пример

Рассмотрим простой пример кода на Python, который использует библиотеку numpy:

import numpy as np A = np.array([1, 2, 3]) B = np.array([2, 2, 2]) C = A / B

В приведенном примере предупреждения не будет, но если в массиве B будет хотя бы один ноль, то при попытке деления на ноль появится предупреждение.

Решение

Отключить все предупреждения в IPython можно с помощью модуля warnings . Для этого можно использовать функцию filterwarnings с аргументом ‘ignore’ , который означает, что все предупреждения нужно игнорировать.

import warnings warnings.filterwarnings('ignore')

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

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

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

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

import warnings def fxn(): warnings.warn("deprecated", DeprecationWarning) with warnings.catch_warnings(): warnings.simplefilter("ignore") fxn() 

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

Примечание: такое поведение может быть гарантировано только в однопоточном приложении. Если два или более потоков используют менеджер контекста warnings.catch_warnings() одновременно, поведение не протестировано.

  • КРАТКИЙ ОБЗОР МАТЕРИАЛА.
  • Категории предупреждений модуля warnings
  • Фильтр предупреждений модуля warnings
  • Переопределение фильтров предупреждений warnings
  • Подавление предупреждений warning
  • Тестирование предупреждений warnings
  • Функция warn() модуля warnings
  • Функция warn_explicit() модуля warnings
  • Функция showwarning() модуля warnings
  • Функция formatwarning() модуля warnings
  • Функция filterwarnings() модуля warnings
  • Функция simplefilter() модуля warnings
  • Функция resetwarnings() модуля warnings
  • Класс catch_warnings() модуля warnings

How to ignore warnings in Python

In Python, you can use the warnings module from the standard library to control warnings, such as ignoring (suppressing) warnings or turning matching warnings into exceptions.

  • Examples of warnings
    • SyntaxWarning by comparing literals with is
    • SettingWithCopyWarning in pandas
    • Ignore all warnings
    • Specify warning categories to ignore

    Although the warnings module provides a warn() function to issue warnings, this article will not cover it. Please refer to the official documentation if you want to issue warnings in your own functions.

    All sample code in this article assumes that the following modules have been imported. The pandas.DataFrame is only used as an example of a warning; its specific contents aren’t our focus here.

    import warnings import pandas as pd df = pd.DataFrame([[0, 1, 2], [3, 4, 5]]) 

    Examples of warnings

    SyntaxWarning by comparing literals with is

    Comparing string or numeric literals with is will trigger a SyntaxWarning .

    print(100 is 100) # True # # <>:1: SyntaxWarning: "is" with a literal. Did you mean "= c1"># <>:1: SyntaxWarning: "is" with a literal. Did you mean "= c1"># /var/folders/rf/b7l8_vgj5mdgvghn_326rn_c0000gn/T/ipykernel_60077/3973932639.py:1: SyntaxWarning: "is" with a literal. Did you mean "= c1"># print(100 is 100) 

    SettingWithCopyWarning in pandas

    A SettingWithCopyWarning is issued for chained assignments in pandas.

    df.iloc[:1][0] = 0 # /var/folders/rf/b7l8_vgj5mdgvghn_326rn_c0000gn/T/ipykernel_60077/1345802814.py:1: SettingWithCopyWarning: # A value is trying to be set on a copy of a slice from a DataFrame. # Try using .loc[row_indexer,col_indexer] = value instead # # See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy # df.iloc[:1][0] = 0 

    Ignore warnings

    Use warnings.simplefilter() to change the handling of warnings and warnings.resetwarnings() to reset.

    • warnings.simplefilter() — Warning control — Python 3.11.4 documentation
    • warnings.resetwarnings() — Warning control — Python 3.11.4 documentation

    Ignore all warnings

    All warnings are ignored by setting the first argument action of warnings.simplefilter() to ‘ignore’ .

    warnings.simplefilter('ignore') print(100 is 100) # True df.iloc[:1][0] = 0 

    Besides ‘ignore’ , for the action argument, you can specify ‘once’ , which issues a warning only the first time it occurs. See the official documentation for other options available for action .

    Specify warning categories to ignore

    You can specify a warning category for the second argument category of warnings.simplefilter() . Warning categories include FutureWarning , DeprecationWarning , SyntaxWarning , RuntimeWarning , etc.

    By default, category is set to Warning , the base class for all warning category classes. As in the example above, this means all warnings are covered.

    Warning categories are described in the warning message. As mentioned above, is comparison for literals issues a SyntaxWarning and chained assignment issues a SettingWithCopyWarning .

    For example, if category=SyntaxWarning , warnings for is comparison for literals are disabled, but warnings for chained assignments are still issued.

    warnings.resetwarnings() warnings.simplefilter('ignore', SyntaxWarning) print(100 is 100) # True df.iloc[:1][0] = 0 # /var/folders/rf/b7l8_vgj5mdgvghn_326rn_c0000gn/T/ipykernel_60077/1345802814.py:1: SettingWithCopyWarning: # A value is trying to be set on a copy of a slice from a DataFrame. # Try using .loc[row_indexer,col_indexer] = value instead # # See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy # df.iloc[:1][0] = 0 

    The warning category for chained assignments, SettingWithCopyWarning , is defined in pandas. You need to specify it as pd.core.common.SettingWithCopyWarning , not merely SettingWithCopyWarning .

    warnings.resetwarnings() # warnings.simplefilter('ignore', SettingWithCopyWarning) # NameError: name 'SettingWithCopyWarning' is not defined warnings.simplefilter('ignore', pd.errors.SettingWithCopyWarning) print(100 is 100) # True # # <>:1: SyntaxWarning: "is" with a literal. Did you mean "= c1"># <>:1: SyntaxWarning: "is" with a literal. Did you mean "= c1"># /var/folders/rf/b7l8_vgj5mdgvghn_326rn_c0000gn/T/ipykernel_60077/3973932639.py:1: SyntaxWarning: "is" with a literal. Did you mean "= c1"># print(100 is 100) df.iloc[:1][0] = 0 

    Treat warnings as exceptions

    Unlike exceptions, the process continues to run, even if a warning is issued.

    If you want to stop the process for warnings like exceptions, set action of warnings.simplefilter() to ‘error’ .

    warnings.resetwarnings() warnings.simplefilter('error') # print(100 is 100) # SyntaxError: "is" with a literal. Did you mean "= source">source: warnings_basic.py

The second argument category can be used to specify the warning category to be targeted. You can also specify separate actions for each category.

warnings.resetwarnings() warnings.simplefilter('ignore', SyntaxWarning) warnings.simplefilter('error', pd.errors.SettingWithCopyWarning) print(100 is 100) # True # df.iloc[:1][0] = 0 # SettingWithCopyWarning: . 

Temporarily control warnings

If you want to control warnings temporarily, use with and warnings.catch_warnings() .

The settings applied using warnings.simplefilter() are effective only inside the with block.

warnings.resetwarnings() with warnings.catch_warnings(): warnings.simplefilter('ignore') df.iloc[:1][0] = 0 df.iloc[:1][0] = 0 # /var/folders/rf/b7l8_vgj5mdgvghn_326rn_c0000gn/T/ipykernel_60077/1345802814.py:1: SettingWithCopyWarning: # A value is trying to be set on a copy of a slice from a DataFrame. # Try using .loc[row_indexer,col_indexer] = value instead # # See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy # df.iloc[:1][0] = 0 

In Python 3.11, the action and category arguments were added to warnings.catch_warnings() . They are treated as passed to the action and category arguments of warnings.simplefilter() .

with warnings.catch_warnings(action='ignore', category=pd.errors.SettingWithCopyWarning): df.iloc[:1][0] = 0 

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

Фреймворк pytest автоматически ловит предупреждения во время выполнения теста и отображает их в конце сеанса.

Содержание:

  • Управление предупреждениями в pytest ;
  • Использование декоратора @pytest.mark.filterwarnings() ;
  • Полное отключение предупреждений;
  • Предупреждения DeprecationWarning и PendingDeprecationWarning ;
    • Функция pytest.deprecated_call() ;

    Управление предупреждениями в pytest .

    Для управления предупреждениями при тестировании, какие нужно игнорировать, какие отображать в конце сеанса, а какие преобразовывать в ошибки, фреймворк pytest использует опцию CLI -W . Эта опция работает аналогично флагу -W интерпретатора Python. Более подробные варианты использования смотрите в материале "Фильтр предупреждений warnings ".

    Рассмотрим следующий тест:

    # test_warnings.py import warnings def api_v1(): # определяем пользовательское предупреждение warnings.warn(UserWarning("api v1, необходимы функции из v2")) return 1 def test_one(): assert api_v1() == 1 

    Теперь, что бы pytest рассматривал категорию предупреждений UserWarning как ошибку необходимо запустить тест со следующими опциями:

    $ pytest -q test_warnings.py -W error::UserWarning

    Тот же самое можно установить в файле pytest.ini или pyproject.toml с помощью параметра настройки filterwarnings . Например, приведенная ниже конфигурация будет игнорировать все пользовательские предупреждения UserWarning и конкретные предупреждения DeprecationWarning , соответствующие регулярному выражению, при этом все остальные предупреждения будут преобразованы в ошибки.

    # файл pytest.ini [pytest] filterwarnings = error ignore::UserWarning ignore:function ham\(\) is deprecated:DeprecationWarning 
    # файл pyproject.toml [tool.pytest.ini_options] filterwarnings = [ "error", "ignore::UserWarning", # обратите внимание на использование одинарной кавычки # для обозначения "сырых" строк в TOML. 'ignore:function ham\(\) is deprecated:DeprecationWarning', ] 

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

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

    Использование декоратора @pytest.mark.filterwarnings() .

    Чтобы добавить фильтры предупреждений к определенным элементам теста, можно использовать декоратор @pytest.mark.filterwarnings() . Этот декоратор позволит более точно контролировать, какие предупреждения должны фиксироваться на уровне теста, класса или даже модуля:

    import warnings def api_v1(): warnings.warn(UserWarning("api v1, необходимы функции из v2")) return 1 @pytest.mark.filterwarnings("ignore:api v1") def test_one(): assert api_v1() == 1 

    Фильтры, примененные с помощью декоратора/метки, имеют приоритет над фильтрами, переданными в командной строке или настроенными с помощью опции конфигурации filterwarnings .

    Можно применить фильтр ко всем тестам класса, используя @pytest.mark.filterwarnings в качестве декоратора класса, или ко всем тестам в модуле, установив переменную/атрибут модуля pytestmark :

    # переведет все предупреждения в ошибки для этого модуля pytestmark = pytest.mark.filterwarnings("error") 

    Полное отключение предупреждений.

    Плагин захвата предупреждений включен в pytest по умолчанию, но его можно полностью отключить в файле pytest.ini с помощью:

    # pytest.ini [pytest] addopts = -p no:warnings 

    Или передать опцию -p no:warnings в командной строке. Это может быть полезно, если наборы тестов обрабатывают предупреждения с помощью внешней системы.

    Предупреждения DeprecationWarning и PendingDeprecationWarning .

    По умолчанию pytest будет отображать предупреждения DeprecationWarning и PendingDeprecationWarning из пользовательского кода и сторонних библиотек. Это помогает пользователям поддерживать свой код в актуальном состоянии и избегать сбоев при эффективном удалении устаревших предупреждений.

    Иногда полезно скрыть некоторые конкретные предупреждения об устаревании в коде, который невозможно контролировать (например, в сторонних библиотеках). Чтобы игнорировать эти предупреждения можно использовать pytest.ini или @pytest.mark.filterwarnings() .

    # pytest.ini [pytest] filterwarnings = ignore:.*U.*mode is deprecated:DeprecationWarning 

    При этом будут игнорироваться все предупреждения типа DeprecationWarning , в которых начало сообщения соответствует регулярному выражению '.*U.*mode is deprecated' .

    Примечание:

    Если предупреждения настроены на уровне интерпретатора с использованием переменной среды PYTHONWARNINGS или параметра командной строки -W , то pytest не будет настраивать фильтры по умолчанию.

    Кроме того, pytest не сбрасывает все фильтры предупреждений, т.к. это может нарушить тесты, которые сами настраивают фильтры предупреждений, вызвав warnings.simplefilter() .

    Функция pytest.deprecated_call() .

    Для проверки того, что определенная функция вызывает предупреждение DeprecationWarning или PendingDeprecationWarning можно использовать функцию pytest.deprecated_call() :

    import pytest def test_myfunction_deprecated(): with pytest.deprecated_call(): myfunction(17) 

    Этот тест завершится ошибкой, если myfunction() не выдаст предупреждение об устаревании при вызове с аргументом 17.

    Функция pytest.warns() .

    Используя функцию pytest.warns(expected_warning, match=None) можно проверить, вызывает ли код конкретное предупреждение. Функция pytest.warns() работает так же, как и pytest.raises() :

    • Аргумент expected_warning : объект исключения Warning или кортеж объектов Warning ;
    • Аргумент match : если указано, то это строка, содержащая регулярное выражение или объект регулярного выражения, который проверяется на соответствие строковому представлению исключения с помощью re.search() . Может содержать специальные символы, шаблон может быть сначала экранирован с помощью re.escape() . Аргумент match используется только тогда, когда pytest.warns() используется в качестве диспетчера контекста. При использовании pytest.warns() в качестве функции можно использовать: pytest.warns(Warn, func, match="passed on").match("my pattern")
    import warnings import pytest def test_warning(): with pytest.warns(UserWarning): warnings.warn("my warning", UserWarning) 

    Если соответствующее предупреждение не возникнет, то тест завершится неудачей. Функция pytest.warns() имеет ключевой аргумент match , который принимает регулярное выражение для проверки соответствия тексту предупреждения:

    >>> with warns(UserWarning, match=r'must be 0 or None'): . warnings.warn("value must be 0 or None", UserWarning) >>> with warns(UserWarning, match=r'must be \d+$'): . warnings.warn("value must be 42", UserWarning) >>> with warns(UserWarning, match=r'must be \d+$'): . warnings.warn("this is not here", UserWarning) # Traceback (most recent call last): # . # Failed: DID NOT WARN. No warnings of type . UserWarning. were emitted. 

    Также можно вызвать pytest.warns() для функции или строки кода:

    pytest.warns(expected_warning, func, *args, **kwargs) # или pytest.warns(expected_warning, "func(*args, **kwargs)") 

    Функция возвращает список всех выданных предупреждений (в виде объектов warnings.WarningMessage ), которые можно запросить для получения дополнительной информации:

    with pytest.warns(RuntimeWarning) as record: warnings.warn("another warning", RuntimeWarning) # проверка на выдачу только одного предупреждения assert len(record) == 1 # проверка на соответствие сообщению assert record[0].message.args[0] == "another warning" 

    Кроме того, можно подробно изучить возникающие предупреждения, используя встроенную фикстуру recwarn .

    Встроенная фикстура recwarn автоматически обеспечивает сброс фильтра предупреждений в конце теста, поэтому утечка глобального состояния не происходит.

    Сохранение предупреждений (фикстура recwarn ).

    Можно сохранять поднятые предупреждения в объект для подробного изучения либо с помощью pytest.warns() , либо с помощью фикстуры recwarn .

    Сохранение поднятых предупреждений с помощью pytest.warns() :

    with pytest.warns() as record: warnings.warn("user", UserWarning) warnings.warn("runtime", RuntimeWarning) assert len(record) == 2 assert str(record[0].message) == "user" assert str(record[1].message) == "runtime" 

    Фикстура recwarn будет записывать предупреждения для всей тестовой функции:

    import warnings def test_hello(recwarn): warnings.warn("hello", UserWarning) assert len(recwarn) == 1 w = recwarn.pop(UserWarning) assert issubclass(w.category, UserWarning) assert str(w.message) == "hello" assert w.filename assert w.lineno 

    И recwarn , и pytest.warns() возвращают один и тот же интерфейс для записанных предупреждений: экземпляр WarningsRecorder . Чтобы просмотреть записанные предупреждения, можно выполнить итерацию по этому экземпляру, для получения количества записанных предупреждений можно вызвать len() или получить конкретное записанное предупреждение по индексу.

    Еще варианты использования предупреждений в тестах.

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

      Чтобы узнать, что выдается хотя бы одно предупреждение, используйте:

    with pytest.warns(): . 
    with warnings.catch_warnings(): warnings.simplefilter("error") . 
    with warnings.catch_warnings(): warnings.simplefilter("ignore") 

    Внутренние предупреждения pytest .

    Фреймворк pytest может генерировать собственные предупреждения в некоторых ситуациях, таких как неправильное использование или устаревшие функции.

    Например, pytest выдаст предупреждение, если встретит класс, соответствующий python_classes , но также определяющий конструктор __init__ , т.к. это предотвращает создание экземпляра класса:

    # test_pytest_warnings.py class Test: def __init__(self): pass def test_foo(self): assert 1 == 1 

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

    • КРАТКИЙ ОБЗОР МАТЕРИАЛА.
    • Интеграция с проектом тестов pytest
    • Как запускать/вызывать тесты pytest
    • Передача значений аргументов в тесты, @mark.parametrize в pytest Python
    • Область/scope действия фикстур модуля pytest
    • Фикстура как аргумент теста, модуль pytest
    • Передача параметров (params) в фикстуру pytest
    • Декоратор mark.usefixtures и autouse-фикстуры модуля pytest
    • Переопределение фикстур в тестах модуля pytest
    • Пропуск тестов: skip() и skipif() с модулем pytest
    • Ожидаемо падающие тесты xfail(), модуль pytest
    • Функция pytest.raises() модуля pytest
    • Пользовательские pytest.mark с аргументами модуля pytest
    • Объект фикстуры request модуля pytest
    • Шаблон: фикстура как фабрика, модуль pytest
    • Отладка тестов (PDB и faulthandler) pytest
    • Работа с предупреждениями warning, модуль pytest
    • Хук pytest_generate_tests модуля pytest Python
    • Управление выводом отчета о тестах pytest
    • Фикстура monkeypatch модуля pytest
    • Логирование (logging) журнала в pytest Python

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *