Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does pytest.raises(Error) work?

Tags:

python

pytest

New-ish to Python but I'm trying to understand this slice of code:

with pytest.raises(ValueError):
    group_adjust(vals, [grps_1, grps_2], weights)

After reading this tutorial on with, I understand pytest.raises() returns a context manager that sets up and cleans up things before and after group_adjust() is called. I also understand that group_adjust() should raise a ValueError if something goes wrong.

How does pytest "react" when a ValueError is raised? AFAIK, there's only setting up and cleaning up so I'm not sure how it catches the exception. The end goal for this is to understand the benefits of having pytest as a context manager.

like image 771
joshualan Avatar asked Jun 19 '26 07:06

joshualan


2 Answers

__exit__ magic function accepts exception_type, exception_value and traceback parameters:

In [5]: class RaisesContext:
   ...:     def __enter__(self):
   ...:         return self
   ...:     def __exit__(self, exception_type, exception_value, traceback):
   ...:         print('Exception type:', exception_type)
   ...:         print('Exception value:', exception_value)
   ...:         print('Traceback:', traceback)
   ...:         return True
   ...:     

In [6]: with RaisesContext():
   ...:     raise ValueError('Something went wrong')
   ...: 
Exception type: <class 'ValueError'>
Exception value: Something went wrong
Traceback: <traceback object at 0x7fd92f4a2c48>

They are None, if the with block ends normally:

In [7]: with RaisesContext():
   ...:     pass
   ...: 
Exception type: None
Exception value: None
Traceback: None
like image 192
awesoon Avatar answered Jun 21 '26 02:06

awesoon


The with construct calls two "magic" methods, __enter__ and __exit__ at the beginning and end of the code block, respectively. Thus,

with foo:
    x = 1

Can be read as:

foo.__enter__()
x = 1
foo.__exit__()

Except that, as soon mentioned in hir answer, __exit__ is called with details on why the code block is exiting: if an exception, what kind, otherwise None.

So the object returned by pytest.raises(TYPE) has been configured to expect an exception of TYPE. The __exit__ method compares the parameter it receives declaring the actual (if any) exception with the internal data member it has storing the expected exception type, and then decides to pass or fail the test.

like image 37
aghast Avatar answered Jun 21 '26 03:06

aghast