Skip to content

Support __notes__ in pytest.raises #11223

@ivirshup

Description

@ivirshup

I would like pytest.raises to have some form of support for __notes__.

What's the problem this feature will solve?

I am currently looking into replacing dynamic patching of error messages with the new __notes__ feature added in PEP-678.

However, once I use __notes__ my checks using pytest.raises now fail, and I'd like them to not. Or at least, I would like for pytest to have some features for matching these errors. Since this is a language level feature for python, I think it's usage should be covered by pytest.

Describe the solution you'd like

I would like the regex from pytest.raises to match against the notes as well as the body of the error. It would be fine for this to be specified with a keyword argument.

Example of usage:

import pytest

def foo():
    assert False

def bar():
    try:
        foo()
    except AssertionError as e:
        e.add_note("Raised by bar")
        raise

with pytest.raises(AssertionError, match="Raised by bar"):
    bar()

Alternative Solutions

Do nothing

I could manually check for notes, but I don't think python makes it obvious which part of an exception is from a note. Here is a small example of what a note looks like:

setup
# Python 3.11.4 | packaged by conda-forge | (main, Jun 10 2023, 18:10:28) [Clang 15.0.7 ] on darwin
# Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> 
>>> def add_note(err: BaseException, msg: str) -> None:
...     if sys.version_info < (3, 11):
...         err.__notes__ = getattr(err, "__notes__", []) + [msg]
...     else:
...         err.add_note(msg)
... 
>>> def foo():
...     raise AssertionError("foo is a bad function")
... 
>>> try:
...     foo()
... except AssertionError as e:
...     add_note(e, "yeah, foo is awful")
...     raise e
Traceback (most recent call last):
  File "<stdin>", line 5, in <module>
  File "<stdin>", line 2, in <module>
  File "<stdin>", line 2, in foo
AssertionError: foo is a bad function
yeah, foo is awful

I think this would make it quite difficult for someone receiving an exception with notes from an upstream library to know how to match against it.

I'm currently handling this with a helper function:

def check_error_or_notes_match(e: pytest.ExceptionInfo, pattern: str):
    """
    Checks whether the printed error message or the notes contains the given pattern.

    DOES NOT WORK IN IPYTHON - because of the way IPython handles exceptions
    """
    import traceback

    message = "".join(traceback.format_exception_only(e.type, e.value))
    assert re.search(
        pattern, message
    ), f"Could not find pattern: '{pattern}' in error:\n\n{message}\n"

Additional context

This line would have to change:

value = str(self.value)
.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions