Другое сообщение об ошибке, когда unittest.assertRaisesRegex вызывается как менеджер контекста - PullRequest
0 голосов
/ 10 февраля 2019

Контекст (можно пропустить, реальный вопрос возникает после)

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

Мой любимый проект имеет некоторую логику, основанную на сообщении об исключениях Python (а не только на типе).Поскольку он очень хрупкий, я проверяю, что на Travis у меня работают все версии большинства Python, которые я могу.

Недавно я понял, что фрагмент кода set.add(0) приводит к исключению, сообщение которого ожидаетсячто-то вроде:

дескриптор 'add' требует объекта 'set', но получил 'int'

Однако в некоторых версиях Python 3.7+,вещи начали выглядеть по-другому в нескольких тестовых случаях.Видимо, сообщение больше похоже на:

«дескриптор» add »для« set »объектов не относится к объекту« int »*

Просто потому, что я хотелЧтобы быть уверенным, что это было задумано разработчиками Python, я хотел найти точный коммит, изменяющий это, полагаясь на некоторую магию git bisect, и начал искать минималистичный способ воспроизвести эту проблему.К сожалению, я не мог воспроизвести это поведение локально, и одна вещь, ведущая к другой, я спустился в кроличью нору и закончил множеством загадок, одна из которых была связана с unittest.assertRaisesRegex.

Неожиданное unittest.assertRaisesRegex поведение

Я написал следующие тесты, которые выглядят удивительно похожими на unittest.assertRaisesRegex примеры из документа - один тест предоставляет вызываемые и соответствующие аргументы, другой тест полагается на менеджер контекста:

    DESCRIPT_REQUIRES_TYPE_RE = r"descriptor '\w+' requires a 'set' object but received a 'int'"

    ...

    def test_assertRaisesRegex(self):
        self.assertRaisesRegex(TypeError, DESCRIPT_REQUIRES_TYPE_RE, set.add, 0)

    def test_assertRaisesRegex_contextman(self):
        with self.assertRaisesRegex(TypeError, DESCRIPT_REQUIRES_TYPE_RE):
            set.add(0)

Я бы ожидал, что они оба будут вести себя одинаково, но они этого не делают.

(номера версий извлекаются с python -VV и python -c "import sys; print(sys._git)")

  • В некоторых версиях оба теста проходят:

    • Python 3.6 и ранее
    • Python 3.7.0a4 + (руководитель / мастер: 4666ec5, январь26 2018, 04:14:24) - [GCC 4.8.4] - («CPython», «Heads / Master», «4666ec5»))
  • На некоторыхверсии, оба теста не пройдены:

    • Python 3.8.0a1 + (руководитель / мастер: 8a03ff2, 9 февраля 2019, 07:30:26) [GCC 5.4.0 20160609] - ('CPython', 'Heads / Master', '8a03ff2')
  • В некоторых версиях сбой только test_assertRaisesRegex_contextman, что меня смущает:

    • Python 3.7.1 (по умолчанию, 5 декабря 2018, 18:09:53) [GCC 5.4.0 20160609] - ('CPython', '', '')
    • Python 3.7.2+ (Heads / 3.7: 3fcfef3, 9 февраля 2019, 07:30:09) [GCC 5.4.0 20160609] - ('CPython', 'Heads / 3.7', '3fcfef3')

Когда они случаются, сбои выглядят следующим образом:

======================================================================
FAIL: test_assertRaisesRegex (didyoumean_sugg_tests.SetAddIntRegexpTests)
----------------------------------------------------------------------
TypeError: descriptor 'add' for 'set' objects doesn't apply to 'int' object
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
  File "/home/travis/build/.../didyoumean_sugg_tests.py", line 19, in test_assertRaisesRegex
    self.assertRaisesRegex(TypeError, DESCRIPT_REQUIRES_TYPE_RE, set.add, 0)
AssertionError: "descriptor '\w+' requires a 'set' object but received a 'int'" does not match "descriptor 'add' for 'set' objects doesn't apply to 'int' object"

и

======================================================================
FAIL: test_assertRaisesRegex_contextman (didyoumean_sugg_tests.SetAddIntRegexpTests)
----------------------------------------------------------------------
TypeError: descriptor 'add' for 'set' objects doesn't apply to 'int' object
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
  File "/home/travis/build/.../didyoumean/didyoumean_sugg_tests.py", line 23, in test_assertRaisesRegex_contextman
    set.add(0)
AssertionError: "descriptor '\w+' requires a 'set' object but received a 'int'" does not match "descriptor 'add' for 'set' objects doesn't apply to 'int' object"

Почему эти два похожих теста выглядят по-разному?

Дополнительные моменты, которые меня смущают

  • Я не смог воспроизвести проблему локально на коде cpython, который я бы извлек и собрал (даже используяправильный SHA1)

  • на Travis, выполнение python -c "set.add(0)" всегда приводит к одной и той же (ожидаемой) строке:

TypeError: descriptor 'add' requires a 'set' object but received a 'int'

Статус пока что

Все, вероятно, сводится к простой детали, которую мне не хватает, но меня нетподсказки на данный момент.Любое предложение приветствуется.Я рад вызвать больше сборок Travis, если потребуется больше данных.

...