Skip to content

Commit 73d9fc0

Browse files
committed
Ensure all the exceptions cat be spied on
This change replaces `Exception` with `BaseException` in the `spy()` method provided by the `mocker` fixture. This enables the caller to spy on things like `KeyboardInterrupt`, `GeneratorExit` and `SystemExit` exceptions that hasn't been possible before because of a bug. Before this change, any occurances of the above exceptions caused `spy()` to assign `None` to both `spy_return` and `spy_exception` attributes. Fixes pytest-dev#215
1 parent 9e1464b commit 73d9fc0

File tree

2 files changed

+21
-6
lines changed

2 files changed

+21
-6
lines changed

src/pytest_mock/plugin.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ def wrapper(*args, **kwargs):
114114
spy_obj.spy_exception = None
115115
try:
116116
r = method(*args, **kwargs)
117-
except Exception as e:
117+
except BaseException as e:
118118
spy_obj.spy_exception = e
119119
raise
120120
else:
@@ -126,7 +126,7 @@ async def async_wrapper(*args, **kwargs):
126126
spy_obj.spy_exception = None
127127
try:
128128
r = await method(*args, **kwargs)
129-
except Exception as e:
129+
except BaseException as e:
130130
spy_obj.spy_exception = e
131131
raise
132132
else:

tests/test_pytest_mock.py

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import platform
33
import sys
44
from contextlib import contextmanager
5-
from typing import Callable, Any, Tuple, Generator
5+
from typing import Callable, Any, Tuple, Generator, Type
66
from unittest.mock import MagicMock
77

88
import pytest
@@ -235,17 +235,32 @@ def bar(self, arg):
235235
assert spy.spy_return == 20
236236

237237

238-
def test_instance_method_spy_exception(mocker: MockerFixture) -> None:
238+
# Ref: https://docs.python.org/3/library/exceptions.html#exception-hierarchy
239+
@pytest.mark.parametrize(
240+
'exc_cls',
241+
(
242+
BaseException,
243+
Exception,
244+
GeneratorExit, # BaseException
245+
KeyboardInterrupt, # BaseException
246+
RuntimeError, # regular Exception
247+
SystemExit, # BaseException
248+
)
249+
)
250+
def test_instance_method_spy_exception(
251+
exc_cls: Type[BaseException],
252+
mocker: MockerFixture,
253+
) -> None:
239254
class Foo:
240255
def bar(self, arg):
241-
raise Exception("Error with {}".format(arg))
256+
raise exc_cls("Error with {}".format(arg))
242257

243258
foo = Foo()
244259
spy = mocker.spy(foo, "bar")
245260

246261
expected_calls = []
247262
for i, v in enumerate([10, 20]):
248-
with pytest.raises(Exception, match="Error with {}".format(v)) as exc_info:
263+
with pytest.raises(exc_cls, match="Error with {}".format(v)) as exc_info:
249264
foo.bar(arg=v)
250265

251266
expected_calls.append(mocker.call(arg=v))

0 commit comments

Comments
 (0)