This is how we use it in my testing repo:
__init__.py
os.environ.setdefault('PYTHONBREAKPOINT', 'tests.utils.raise_or_debug')
tests.utils.raise_or_debug
def raise_or_debug(msg=''):
if settings.BREAKPOINT_ON_ERROR:
extype, value, tb = sys.exc_info()
if getattr(sys, 'last_traceback', None):
pdb.pm()
elif tb:
pdb.post_mortem(tb)
else:
pdb.set_trace()
elif msg:
raise AssertionError(msg)
else:
pdb.set_trace()
The reason is so we can leave breakpoints in the tests, and then depending on context run the tests in a context where debug is possible, or simply raise the failure again.
Selenium can be very flaky, so this has really sped up iteration and improvements. Standard functions with retries, and smart assertions and timeouts can then be fixed and resumed in dev - and give a good message on fail (for example headless chrome runner on CI).