Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion assertpy/assertpy.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
from .dict import DictMixin
from .dynamic import DynamicMixin
from .extracting import ExtractingMixin
from .exception import ExceptionMixin
from .exception import ExceptionMixin, _NoChainingMixin
from .file import FileMixin
from .helpers import HelpersMixin
from .numeric import NumericMixin
Expand Down Expand Up @@ -456,6 +456,10 @@ def error(self, msg):
return self
elif self.kind == 'soft':
global _soft_err
if callable(self.val):
# replace all callable methods of AssertionBuilder instance with empty function if self.val is callable
self.__class__ = type(self.__class__.__name__, (self.__class__, _NoChainingMixin), {})
out += " Any further chain assertions ignored."
_soft_err.append(out)
return self
else:
Expand Down
13 changes: 13 additions & 0 deletions assertpy/exception.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,3 +111,16 @@ def some_func(a):
self.val.__name__,
self.expected.__name__,
self._fmt_args_kwargs(*some_args, **some_kwargs)))


class _NoChainingMixin(object):
"""Mixin that replaces all method calls with empty function."""
def __getattribute__(self, item):
attr = super(_NoChainingMixin, self).__getattribute__(item)
if callable(attr) and item != "_do_nothing":
return self._do_nothing
return attr

def _do_nothing(self, *args, **kwargs):
"""Method that is used instead of all callable attributes of AssertionBuilder"""
return self
24 changes: 24 additions & 0 deletions tests/test_soft.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,30 @@ def test_expected_exception_failure():
assert_that(out).contains("Expected <func_ok> to raise <RuntimeError> when called with ('baz').")


def test_expected_exception_failure_chaining():
try:
with soft_assertions():
# No exception
assert_that(func_ok).raises(RuntimeError).when_called_with('a').is_equal_to('dog').matches('cat')
# Exception type mismatch
assert_that(func_ok).raises(TypeError).when_called_with('a').contains('dog')
# Error message mismatch
assert_that(func_err).raises(RuntimeError).when_called_with('a').matches('dog')
fail('should have raised error')
except AssertionError as ex:
out = str(ex)
assert_that(out).contains(
"1. Expected <func_ok> to raise <RuntimeError> when called with ('a')."
" Any further chain assertions ignored."
)
assert_that(out).contains(
"2. Expected <func_ok> to raise <TypeError> when called with ('a')."
" Any further chain assertions ignored."
)
assert_that(out).contains("3. Expected <err> to match pattern <dog>, but did not.")
assert_that(out).does_not_contain("4.")


def func_ok(arg):
pass

Expand Down