Как включить тестирование для DeprecationWarning и PendingDeprecationWarning с использованием tox+pytest

На протяжении многих лет я тестировал ruamel.yaml с tox а также pytest на регулярной основе для нескольких версий Python. Вскоре после того, как вышла первая бета-версия Python 3.7, я включил ее и обновил тестирование до версии 3.7, когда она была выпущена. Я все еще выполнял большую часть своей повседневной работы с Python 3.6 (и 2.7, где это необходимо).

Поэтому я был очень удивлен тем, что проблема вошла в bitbucket, для DeprecationWarning так как ruamel.yaml все еще импортировал вещи из collections путь Python 2.X (начиная с 3.8 они должны быть импортированы из collections.abcгде они уже живут). Я бы ожидал, что мой tox запуски, которые являются обязательным условием в моем наборе инструментов для возможности выдвинуть новую версию в PyPI, чтобы понять это несколько месяцев назад.

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

python3.7 -W always -c "import ruamel.yaml"

После некоторых исследований я добавил:

[pytest]
filterwarnings =
    error::DeprecationWarning
    error::PendingDeprecationWarning

к моему tox.ini, который не изменил результаты теста для цели py37 (321 проходов /2 пропущенных /7 xfail).

Затем я добавил:

setenv = PYTHONWARNINGS = ошибка

по умолчанию ([testenv]) цель. Это дало некоторые интересные изменения в результате, так как тестирование завершилось сбоем из-за предупреждений об устаревании в tox/pytest/virtualenv сам набор инструментов

Я исправил их вручную (намереваясь автоматизировать это после tox -r запустить), чтобы увидеть, если с этим по крайней мере получить ошибку на токсина для ruamel.yaml сам, но это не так. Если вы вместо этого добавите:

setenv =
    PYTHONWARNINGS=always::DeprecationWarning

в [testenv] вы увидите, что набор инструментов имеет:

DeprecationWarning: режим 'U' устарел
DeprecationWarning: модуль imp устарел в пользу importlib
DeprecationWarning: Использование или импорт ABC из "коллекций" вместо "коллекций.abc" устарело, и в 3.8 он перестанет работать

Последнее, на самом деле, - то, что я искал, но эта ошибка была из-за кода в pyparsing зависимости tox...

Тогда я новый файл test_import.py с одним тестом:

def test_import():
    from ruamel.yaml

и дважды проверил, что tox выполняет тест (прохождение 322 тестов), но никакие сообщения или предупреждения не отображаются, даже при добавлении -ra в pytest,

Я ожидал tox чтобы помочь мне найти амортизацию на ранней стадии, но на самом деле кажется невозможным заставить их срабатывать вообще. Конечно, я могу добавить командную строку, показанную выше, в качестве дополнительной команды в моем tox.ini, Но некоторое устаревание может быть вызвано не так легко, и я не хочу дублировать мои усилия по тестированию, просто чтобы поймать потенциальные амортизации.

Как я могу вызвать DeprecationWarning в моем коде с помощью tox?

1 ответ

Если вы начнете с минимальной test_one.py

def test_one():
    from collections import Hashable

просто setup.py:

from setuptools import setup, find_packages

if __name__ == '__main__':
    setup(
        name="depwarntest",
        version="0.0.1",
        description="test to get DeprecationWarning in code on 3.7",
        long_description = "more details soon",
        author_email="a.van.der.neut@ruamel.eu",
        author="Anthon van der Neut",
        license="MIT",
        url="",
        packages=find_packages(),
    )

И основной tox.ini:

[tox]
envlist = py37,py36,py27

[testenv]
commands =
    /bin/bash -c 'pytest test_*.py'
deps =
    pytest

[pytest]
filterwarnings =
    error::DeprecationWarning
    error::PendingDeprecationWarning

и беги tox вы получите хорошее чистое исключение из-за вашего import:

==================================================================================== FAILURES =====================================================================================
____________________________________________________________________________________ test_one _____________________________________________________________________________________

    def test_one():
>       from collections import Hashable

test_one.py:6: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
<frozen importlib._bootstrap>:1032: in _handle_fromlist
    ???
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

name = 'Hashable'

    def __getattr__(name):
        # For backwards compatibility, continue to make the collections ABCs
        # through Python 3.6 available through the collections module.
        # Note, no new collections ABCs were added in Python 3.7
        if name in _collections_abc.__all__:
            obj = getattr(_collections_abc, name)
            import warnings
            warnings.warn("Using or importing the ABCs from 'collections' instead "
                          "of from 'collections.abc' is deprecated, "
                          "and in 3.8 it will stop working",
>                         DeprecationWarning, stacklevel=2)
E           DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated, and in 3.8 it will stop working

.tox/py37/lib/python3.7/collections/__init__.py:52: DeprecationWarning
============================================================================ 1 failed in 0.31 seconds =============================================================================

на py37, в то время как py36 а также py27 беги нормально.

Достаточно интересно, если вы измените тестовый файл, чтобы прочитать

from collections import Hashable    

def test_one():
    from collections import Hashable

Бег tox будет работать на py37 также. И это даже в том случае, если вы перемещаете этот уровень импорта модуля на другой test_XYZ.py файл

За ruamel.yaml это означает, что все импорты уровня модуля ruamel.yaml в тестовых файлах нужно перемещать методы / функции; что любые классы корневого уровня в тесте, которые зависят, например, от ruamel.yaml.YAML() нужно использовать генератор; и что уровень модуля yaml_object() необходимо обрабатывать также особым образом.

Дополнительный tox Цель помогает проверить постепенное движение, выполняя тестирование на соответствие:

# deprecation warning fail
[testenv:dwf]
basepython = python3.7
commands =
    /bin/sed 's/collections.abc/collections/' -i .tox/dwf/lib/python3.7/site-packages/ruamel/yaml/comments.py
    /bin/bash -c 'pytest --maxfail=2 _test/test_[a-cz]*.py'

Вот уже исправленный источник comments.py перевернут, только для протестированных модулей. ted -e py37,dwf должен пройти первый (еще раз с прохождением 321 теста) и потерпеть неудачу на второй цели.

Другие вопросы по тегам