How to automatically switch to debug mode on a warning?

I found the answer offered by @user2683246 elegant and useful. Here is a variant of the solution modified for compatibility with Python3 (tested with Python 3.7):

#!/usr/bin/env python

import pdb, warnings, sys
import builtins

if __name__ == '__main__':
    args, n = [], len(sys.argv)
    if n < 2:
        sys.exit(1)
    elif n > 2:
        args.append(builtins.__dict__[sys.argv[2]])
        if n > 3:
            args.append(int(sys.argv[3]))
    warnings.simplefilter('error', *args)  # treat warnings as exceptions
    try:
        with open(sys.argv[1]) as f:
            code = compile(f.read(), sys.argv[1], 'exec')
            exec(code)
    except:
        pdb.post_mortem(sys.exc_info()[-1])

Notable changes:

  • Replace the execfile() call with the Python 3 variant; and
  • Replace __builtin__ with builtins.

You can write a script dbg.py:

import pdb, warnings, sys
import __builtin__

if __name__ == '__main__':
    args, n = [], len(sys.argv)
    if n < 2:
        sys.exit(1)
    elif n > 2:
        args.append(__builtin__.__dict__[sys.argv[2]])
        if n > 3:
            args.append(int(sys.argv[3]))
    warnings.simplefilter('error', *args)  # treat warnings as exceptions
    try:
        execfile(sys.argv[1])
    except:
        pdb.post_mortem(sys.exc_info()[-1])

You can then use it to debug your script like that. Pass in your script name as the first argument if you want to run pdb on any warning:

$ python dbg.py yourscript.py

Pass in warning type as the second argument if you only want pdb to run when some particular type of warning is raised:

$ python dbg.py yourscript.py DeprecationWarning

Line number as the third argument:

$ python dbg.py yourscript.py DeprecationWarning 342

You can also rewrite the code using warnings.filterwarnings instead of warnings.simplefilter to make warnings filtering even more flexible.