Контекст (можно пропустить, реальный вопрос возникает после)
Все это не важно, но я нахожусь в расследовании, которое запутало меня все больше и больше.
Мой любимый проект имеет некоторую логику, основанную на сообщении об исключениях 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, если потребуется больше данных.