Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

custom sys.excepthook doesn't work with pytest

Tags:

python

pytest

I wanted to put results of pytest aserts into log.

First I tried this solution

def logged_assert(self, testval, msg=None):
    if not testval:
        if msg is None:
            try:
                assert testval
            except AssertionError as e:
                self.logger.exception(e)
                raise e
        self.logger.error(msg)
        assert testval, msg

It work's fine but I need to use my own msg for every assert instead if build in. The problem is that testval evaluates when it passed into function and error msg is

AssertionError: False

I found an excellent way to solve the problem http://code.activestate.com/recipes/577074-logging-asserts/ here in first comment.

And I wrote this function in my logger wrapper module

def logged_excepthook(er_type, value, trace):
    print('HOOK!')
    if isinstance(er_type, AssertionError):
        current = sys.modules[sys._getframe(1).f_globals['__name__']]
        if 'logger' in sys.modules[current]:
            sys.__excepthook__(er_type, value, trace)
            sys.modules[current].error(exc_info=(er_type, value, trace))
        else:
            sys.__excepthook__(er_type, value, trace)
    else:
        sys.__excepthook__(er_type, value, trace)

and then

sys.excepthook = logged_excepthook

In test module, where i have asserts output of

import sys
print(sys.excepthook, sys.__excepthook__, logged_excepthook)

is

<function logged_excepthook at 0x02D672B8> <built-in function excepthook> <function logged_excepthook at 0x02D672B8>

But there is no 'Hook' message in my output. And also no ERROR message in my log files. All works like with builtin sys.excepthook.

I looked through pytest sources but sys.excepthook doesn't changed there. But if I interrupt my code execution with Cntrl-C I got 'Hook' message in stdout.

The main question is why builtin sys.excepthook called isntead my custom function and how can I fix that. But it also intresting to me if another way to log assert errors exists.

I am using python3.2 (32bit) at 64bit windows 8.1.

like image 422
capgelka Avatar asked Oct 31 '22 08:10

capgelka


1 Answers

excepthook is only triggered if there is an unhandled exception, i.e. the one that normally terminates your program. Any exceptions in a test are handled by the test framework.

See Asserting with the assert statement - pytest documentation on how the feature is intended to be used. A custom message is specified the standard way: assert condition, failure_message.

If you're not satisfied with the way pytest handles asserts, you need to either

  • use a wrapper, or
  • hook the assert statement.

pytest uses an assert hook as well. Its logic is located in Lib\site-packages\_pytest\assertion (a stock plugin). It's probably enough to wrap/replace a few functions in there. To avoid patching the code base, you may be able to do with your own plugin: patch the exceptions plugin at runtime, or disable it and reuse its functionality yourself instead.

like image 52
ivan_pozdeev Avatar answered Nov 15 '22 03:11

ivan_pozdeev