Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I get my assertions in pytest to stop being abbreviated with ellipsis?

Tags:

python

pytest

How can I get my assertions in pytest to stop being abbreviated with ellipsis ?

Every time I have an assertion that reports error it truncates all my strings with "..." why is that? how can I stop that?

like image 612
Nicholas DiPiazza Avatar asked Jun 23 '16 20:06

Nicholas DiPiazza


People also ask

How do you fix assertion errors?

In order to handle the assertion error, we need to declare the assertion statement in the try block and catch the assertion error in the catch block.

How does assert work in pytest?

Assertions in PyTest Pytest assertions are checks that return either True or False status. In Python Pytest, if an assertion fails in a test method, then that method execution is stopped there. The remaining code in that test method is not executed, and Pytest assertions will continue with the next test method.


2 Answers

The other solution doesn't work in general. In our use case, for example, pytest truncates parameters passed to functions called from assertion statements:

E                   AssertionError: assert None is not None
E                    +  where None = search('\\n\\*\\s.*\\b[Tt]upla item 0\\b',
'@beartyped pep_hinted() parameter pep_hinted_param=((<function <lambda> at
0x7fe278838830>,),) violates PEP type hint...7fe278838830>,):\n  * Not int, bool, or
float.\n  * Tuple item 0 value <function <lambda> at 0x7fe278838830> not str.')

beartype_test/unit/pep/p484/test_p484.py:124: AssertionError

Note the ellipses (i.e., ...) that pytest interjected without our permission between the substrings violates PEP type hint and 7fe278838830>,):\n in the above output, replacing a mission-critical substring needed to make sense of that output.

Thanks, overly helpful pytest developers. You shouldn't have. Really.

what's the problem, bruh?

To corroborate both @NicholasDiPiazza and @MatthiasUrlichs, Pytest sadly ignores -v options when truncating parameters passed to functions called from assertion statements – which is more than mildly infuriating.

Pytest developers, if we ask for verbosity four friggin' times, it means: "Yes, we really do want verbosity, are well-apprised of the potential pitfalls, and could care less because uncensored error reporting is much more important than minimizing those nebulous theoretical harms that frankly don't apply to real-world continuous integration."

what's the solution, bruh?

Our working solution is as follows:

  • Pass the --showlocals option to the addopts setting in the project's top-level pytest.ini file: e.g.,
addopts = -vvvv --showlocals -p no:xvfb -r a --doctest-glob=
  • Assign the verbose string (or object representation, or whatever) being truncated to a local variable in the problematic test. In our use case, for example, we assign the verbose exception message being truncated to a local variable in that test: e.g.,
def test_problem_function():
    with raises(Exception) as exception_info:
        raise ValueError("a"*1024)

    exception_str = str(exception_info.value)   # <--- This is where the magic happens.
    assert problem_function("a"*1024, exception_str)

def problem_function(substr, bigstr):
    return substr not in bigstr
  • Manually inspect pytest output for that variable's value instead: e.g.,
========================================================== FAILURES ===========================================================
______________________________________________ test_truncated_exception_message _______________________________________________

    def test_truncated_exception_message():
        with raises(Exception) as exception_info:
            raise ValueError("a"*1024)
    
        exception_str = str(exception_info.value)
>       assert problem_function("a"*1024, exception_str)
E       AssertionError: assert False
E        +  where False = problem_function(('a' * 1024), 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')

exception_info = <ExceptionInfo ValueError('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa') tblen=1>
exception_str = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaa'

beartype_test/unit/pep/p484/test_p484.py:39: AssertionError

While the AssertionError itself remains truncated, the --showlocals option correctly preserves the untruncated value of the local exception_str test variable. Voilà!

This actually works as advertised, with the caveat that this only works as advertised for strings (or object representations, or whatever) that are directly assignable to local variables in tests. That's typically but not always the case – which is why pytest really needs to start respecting -vvvvvvvvvvvvvv options in its error reporting.

like image 59
Cecil Curry Avatar answered Sep 27 '22 23:09

Cecil Curry


Could you show an example? This is how the output looks for me:

    def test_foo():
>       assert "a"*100 == "a"*100 + "b"
E       assert 'aaaaaaaaaaaa...aaaaaaaaaaaaa' == 'aaaaaaaaaaaaa...aaaaaaaaaaaab'
E         Skipping 89 identical leading characters in diff, use -v to show
E         - aaaaaaaaaaa
E         + aaaaaaaaaaab
E         ?            +

I think the diff makes it perfectly clear what's failing - but with -v (as the message suggests) I get the full diff:

    def test_foo():
>       assert "a"*100 == "a"*100 + "b"
E       assert 'aaaaaaaaaaaa...aaaaaaaaaaaaa' == 'aaaaaaaaaaaaa...aaaaaaaaaaaab'
E         - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
E         + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab
E         ?  
like image 33
The Compiler Avatar answered Sep 27 '22 23:09

The Compiler