diff --git a/changelog/5541.feature.rst b/changelog/5541.feature.rst new file mode 100644 index 00000000000..3668a04e668 --- /dev/null +++ b/changelog/5541.feature.rst @@ -0,0 +1 @@ +Add ``.exception`` attribute as an alias for ``.value`` to facilitate porting tests written using unittest. diff --git a/src/_pytest/_code/code.py b/src/_pytest/_code/code.py index b0b4d653119..1cbbdd446a2 100644 --- a/src/_pytest/_code/code.py +++ b/src/_pytest/_code/code.py @@ -422,6 +422,20 @@ def type(self): def value(self): """the exception value""" return self._excinfo[1] + + @property + def exception(self): + """ + an alias to '.value' to facilitate porting porting tests written using + unittest. Prefer '.value' in new code. + """ + msg = ( + "The '.exception' attribute is an alias to facilitate porting " + "tests written using unittest.\n" + "Prefer '.value' in new code." + ) + warnings.warn(PytestWarning(msg), stacklevel=2) + return self.value @property def tb(self): diff --git a/src/_pytest/recwarn.py b/src/_pytest/recwarn.py index 006d97e7fc7..d8fbe658d32 100644 --- a/src/_pytest/recwarn.py +++ b/src/_pytest/recwarn.py @@ -186,28 +186,33 @@ def __exit__(self, *exc_info): __tracebackhide__ = True # only check if we're not currently handling an exception - if all(a is None for a in exc_info): - if self.expected_warning is not None: - if not any(issubclass(r.category, self.expected_warning) for r in self): - __tracebackhide__ = True - fail( - "DID NOT WARN. No warnings of type {} was emitted. " - "The list of emitted warnings is: {}.".format( - self.expected_warning, [each.message for each in self] - ) - ) - elif self.match_expr is not None: - for r in self: - if issubclass(r.category, self.expected_warning): - if re.compile(self.match_expr).search(str(r.message)): - break - else: - fail( - "DID NOT WARN. No warnings of type {} matching" - " ('{}') was emitted. The list of emitted warnings" - " is: {}.".format( - self.expected_warning, - self.match_expr, - [each.message for each in self], - ) - ) + if not all(a is None for a in exc_info): + return + + if self.expected_warning is None: + return + + for r in self: + if issubclass(r.category, self.expected_warning) and ( + self.match_expr is None or re.search(self.match_expr, str(r.message)) + ): + self.warning = r.message + self.filename = r.filename + self.lineno = r.lineno + return + + if self.match_expr is None: + fail( + "DID NOT WARN. No warnings of type {} was emitted. " + "The list of emitted warnings is: {}.".format( + self.expected_warning, [each.message for each in self] + ) + ) + + fail( + "DID NOT WARN. No warnings of type {} matching" + " ('{}') was emitted. The list of emitted warnings" + " is: {}.".format( + self.expected_warning, self.match_expr, [each.message for each in self] + ) + )