Как выполнить самоанализ assert в Python

Я изучаю, как выполнить интроспекцию assert в Python таким же образом это py.test. Например...

>>> a = 1
>>> b = 2
>>> assert a == b
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
AssertionError   # <--- I want more information here, eg 'AssertionError: 1 != 2'

Я вижу, что py.code библиотека имеет некоторые функции вокруг этого и я также видел этот ответ, в котором отмечалось, что sys.excepthook позволяет вы можете подключить любое поведение, которое вы хотите, к исключениям, но мне не ясно, как все это собрать.


person Tom Christie    schedule 18.11.2016    source источник
comment
Почему бы не использовать сам pytest?   -  person pylang    schedule 18.11.2016
comment
@pylang У меня нет проблем с повторным использованием частей py.test, которые позволяют этому случиться, но я не могу просто использовать сам py.test. Для целей моего вопроса я говорю, что вы должны предположить, например. что я на самом деле не провожу тесты в этом контексте.   -  person Tom Christie    schedule 18.11.2016
comment
@pylang Действительно ли возможно использовать утверждение pytest в общем контексте? Я предполагаю, что OP хочет использовать функциональность в автономной программе / библиотеке, например, для целей проверки.   -  person bluenote10    schedule 28.01.2019
comment
Думаю, теперь я понимаю. Да, я не верю, что у pytes есть интерактивный режим (по крайней мере, в ноутбуках jupyter). Обычно я использовал nose именно из-за этой проблемы.   -  person pylang    schedule 29.01.2019


Ответы (3)


Вы можете сделать что-то подобное, если хотите показать подробное сообщение об ошибке.

def assertion(a,b):
    try:
        assert a==b
    except AssertionError as e:
        e.args += ('some other', 'information',)
        raise

a=1
b=2
assertion(a,b)

Этот код даст следующий результат:

Traceback (most recent call last):
  File "tp.py", line 11, in <module>
    assertion(a,b)
  File "tp.py", line 4, in assertion
    assert a==b
AssertionError: ('some other', 'information')
person Nihal Rp    schedule 18.11.2016
comment
@Tom. Это помогает? - person Nihal Rp; 18.11.2016
comment
Не особенно-нет, но все равно ценится. Этот ответ добавляет другую дополнительную информацию к исключению, но меня интересует состояние самого сравнения. В данном случае это означает включение значений a и b и определение того, что проблема в том, что они не равны. (Но метод общего назначения, который также может быть полезен с другими операторами) - person Tom Christie; 18.11.2016

unittest assert дает дополнительную информацию (возможно, больше, чем вам нужно). На основе выступления Раймонда Хеттингера. Это частичный ответ, дающий только значения для a и b (последняя строка вывода), а не дополнительный самоанализ, который вы также ищете, который уникален для pytest.

import unittest

class EqualTest(unittest.TestCase):

    def testEqual(self, a, b):
        self.assertEqual(a, b)


a, b = 1, 2
assert_ = EqualTest().testEqual
assert_(a, b)

Вывод

---------------------------------------------------------------------------
AssertionError                            Traceback (most recent call last)
<ipython-input-4-851ce0f1f668> in <module>()
      9 a, b = 1, 2
     10 assert_ = EqualTest().testEqual
---> 11 assert_(a, b)

<ipython-input-4-851ce0f1f668> in testEqual(self, a, b)
      4 
      5     def testEqual(self, a, b):
----> 6         self.assertEqual(a, b)
      7 
      8 

C:\Anaconda3\lib\unittest\case.py in assertEqual(self, first, second, msg)
    818         """
    819         assertion_func = self._getAssertEqualityFunc(first, second)
--> 820         assertion_func(first, second, msg=msg)
    821 
    822     def assertNotEqual(self, first, second, msg=None):

C:\Anaconda3\lib\unittest\case.py in _baseAssertEqual(self, first, second, msg)
    811             standardMsg = '%s != %s' % _common_shorten_repr(first, second)
    812             msg = self._formatMessage(msg, standardMsg)
--> 813             raise self.failureException(msg)
    814 
    815     def assertEqual(self, first, second, msg=None):

AssertionError: 1 != 2
person pylang    schedule 18.11.2016
comment
Спасибо, но в данном случае меня особенно интересует самоанализ assert. - person Tom Christie; 21.11.2016

Я не думаю, что просто воспроизвести интроспекцию assert в pytest в автономном контексте. Документы содержат еще несколько подробностей о том, как это работает:

pytest перезаписывает тестовые модули при импорте. Он делает это с помощью ловушки импорта для записи новых файлов pyc. В большинстве случаев это работает прозрачно. Однако, если вы сами возитесь с импортом, ловушка импорта может помешать. В этом случае просто используйте --assert = reinterp или --assert = plain. Кроме того, перезапись завершится с ошибкой, если она не сможет записать новые файлы pycs, то есть в файловой системе только для чтения или в zip-файле.

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

person bluenote10    schedule 29.01.2019