This rule raises an issue when pytest.raises() is called without a with statement, including standalone calls, the
deprecated callable-passing form, and typos that call the function before entering the context manager.
In Python, this refers to the different usages of pytest.raises() without a with statement, such as:
pytest.raises(ValueError) that never wrap the code under testpytest.raises(ExpectedError, func, *args, **kwargs) that passes a callable and its argumentspytest.raises(ExpectedError, func(*args, **kwargs)) that calls the function immediately and silently skips verification
when no exception is raisedPytest cannot verify the outcome if the code under test is not wrapped in a with pytest.raises(…): block.
pytest.raises(ValueError) without with constructs a context manager and discards it. The test passes even when the
following code does not raise:
def test_invalid_input():
pytest.raises(ValueError)
process_data('hello') # No exception — test still passes
Pytest still supports passing the callable and its arguments:
pytest.raises(ValueError, bootstrap_session, df=-1) # Deprecated
This executes bootstrap_session(df=-1) and fails when no exception is raised. It works, but pytest deprecates it. Refactoring this
form into a bare standalone call silently stops verifying exceptions.
A common mistake adds parentheses around the call:
pytest.raises(NotImplementedError, bootstrap_session(df=10)) # Silent failure
Here bootstrap_session runs before pytest.raises is entered. When df=10 is valid and no exception is raised,
pytest.raises receives the return value and the test passes without verifying anything.
with pytest.raises(ValueError):
bootstrap_session(df=-1)
The with block must raise the expected exception, or the test fails.
Tests that never enter the pytest.raises context manager can pass when no exception is raised, leaving error-handling regressions
undetected. Deprecated callable-passing syntax and the parenthesis typo are prone to silent breakage during refactors.
In Python with pytest, use with pytest.raises(ValueError): around the code that should fail.
Wrap the code that should raise with with pytest.raises(ExpectedError):. To inspect the exception, use as exc_info or the
match parameter.
Migrate deprecated callable-passing calls by moving the invocation into the with block.
import pytest
def process_data(data):
return data.upper()
def test_invalid_input():
pytest.raises(ValueError) # Noncompliant: context manager never entered
process_data('hello')
import pytest
def process_data(data):
return data.upper()
def test_invalid_input():
with pytest.raises(ValueError):
process_data('hello')
import pytest
def bootstrap_session(df=10):
if df <= 0:
raise ValueError('df must be positive')
if df > 20:
raise NotImplementedError('df > 20 not supported')
def test_invalid_df():
pytest.raises(ValueError, bootstrap_session, df=-1) # Noncompliant: deprecated form
def test_unsupported_df():
pytest.raises(NotImplementedError, bootstrap_session(df=10)) # Noncompliant: function called immediately
import pytest
def bootstrap_session(df=10):
if df <= 0:
raise ValueError('df must be positive')
if df > 20:
raise NotImplementedError('df > 20 not supported')
def test_invalid_df():
with pytest.raises(ValueError):
bootstrap_session(df=-1)
def test_unsupported_df():
with pytest.raises(NotImplementedError):
bootstrap_session(df=25)