How to verify the installation of a custom excepthook?

My applications log unhandled exceptions.

# app.py
import logging
import sys

logger = logging.getLogger(__name__)

def excepthook(exc_type, exc_value, traceback):
    exc_info = exc_type, exc_value, traceback
    if not issubclass(exc_type, (KeyboardInterrupt, SystemExit)):
        logger.error('Unhandled exception', exc_info=exc_info)
    sys.__excepthook__(*exc_info)

sys.excepthook = excepthook

def potato():
    logger.warning('about to die...')
    errorerrorerror

if __name__ == '__main__':
    potato()

These tests pass fine:

# test_app.py
import app
import pytest
import sys
from logging import WARNING, ERROR

def test_potato_raises():
    with pytest.raises(NameError):
        app.potato()

def test_excepthook_is_set():
    assert sys.excepthook is app.excepthook

# for caplog plugin: pip install pytest-catchlog
def test_excepthook_logs(caplog):  
    try:
        whatever
    except NameError as err:
        exc_info = type(err), err, err.__traceback__
    app.excepthook(*exc_info)
    assert caplog.record_tuples == [('app', ERROR, 'Unhandled exception')]
    [record] = caplog.records
    assert record.exc_info == exc_info

But I could not check the test process for unhandled exceptions:

def test_unhandled_exceptions_logged(caplog):
    try:
        app.potato()
    finally:
        assert caplog.record_tuples == [
            ('app', WARNING, 'about to die...'),
            ('app', ERROR, 'Unhandled exception'),
        ]
        return  # return eats exception

What is wrong here? How can we run app.excepthookfrom the test?

+6
source share
2 answers

Python will not call sys.excepthookuntil the exception actually spreads completely across the entire stack, and no more code can catch it. This is one of the most recent things that happen before Python shuts down in response to the exception.

, sys.excepthook . sys.excepthook, , . , atexit , . , , , , , sys.excepthook .

sys.excepthook, excepthook .

from subprocess import Popen, PIPE

def test_app():
    proc = Popen([sys.executable, 'app.py'], stdout=PIPE, stderr=PIPE)
    stdout, stderr = proc.communicate()
    assert proc.returncode == 1
    assert stdout == b''
    assert stderr.startswith(b'about to die...\nUnhandled exception')
+1

pytest . - :

>>> import pytest
>>> def foo():
...  raise ValueError('Unhandled Exception')
...
>>> with pytest.raises(ValueError) as exc:
...  foo()
...
>>> 'Unhandled Exception' in str(exc)
True
>>> str(exc)
'<stdin>:2: ValueError: Unhandled Exception'
>>>

. .

-2

All Articles