11

I try to customize behavior of sys.excepthook as described by the recipe.

in ipython:

:import pdb, sys, traceback
:def info(type, value, tb):
:    traceback.print_exception(type, value, tb)
:    pdb.pm()
:sys.excepthook = info
:--
>>> x[10] = 5
-------------------------------------------------
Traceback (most recent call last):
  File "<ipython console>", line 1, in <module>
NameError: name 'x' is not defined
>>>

pdb.pm() is not being called. It seems that sys.excepthook = info doesn't work in my python 2.5 installation.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Mert Nuhoglu
  • 9,695
  • 16
  • 79
  • 117

5 Answers5

24

Five years after you wrote this, IPython still works this way, so I guess a solution might be useful to people googling this.

IPython replaces sys.excepthook every time you execute a line of code, so your overriding of sys.excepthook has no effect. Furthermore, IPython doesn't even call sys.excepthook, it catches all exceptions and handles them itself before things get that far.

To override the exception handler whilst IPython is running, you can monkeypatch over their shell's showtraceback method. For example, here's how I override to give what looks like an ordinary Python traceback (because I don't like how verbose IPython's are):

def showtraceback(self, *args, **kwargs):
    traceback_lines = traceback.format_exception(*sys.exc_info())
    del traceback_lines[1]
    message = ''.join(traceback_lines)
    sys.stderr.write(message)

import sys
import traceback
import IPython
IPython.core.interactiveshell.InteractiveShell.showtraceback = showtraceback

This works in both the normal terminal console and the Qt console.

Chris Billington
  • 855
  • 1
  • 8
  • 14
  • for reference: Running in django shell I get `TypeError: showtraceback() got an unexpected keyword argument 'running_compiled_code'` – Masterfool Nov 09 '21 at 21:24
  • Thanks @Masterfool, I've edited the answer to have it swallow any arguments that are passed in to `showtraceback()` – Chris Billington Nov 10 '21 at 22:08
14

ipython, which you're using instead of the normal Python interactive shell, traps all exceptions itself and does NOT use sys.excepthook. Run it as ipython -pdb instead of just ipython, and it will automatically invoke pdb upon uncaught exceptions, just as you are trying to do with your excepthook.

Alex Martelli
  • 854,459
  • 170
  • 1,222
  • 1,395
  • And how would someone go about using except hooks with ipython? – levesque Nov 20 '10 at 20:39
  • 2
    This is partially misleading. ipython does trap exceptions itself, but the way it does it is by using sys.excepthook, so you can't say it does not use sys.excepthook. ipython does remove from the user the ability to override this hook, though. – snapshoe Nov 21 '10 at 00:44
  • @fugacity and Alex - How can I launch an embedded shell in the scope where the exception occurs? I have just opened a question here: http://stackoverflow.com/questions/15752437/opening-an-ipython-shell-on-any-uncatched-exception and found this thread which seem highly relevant. Perhaps you may know how to do this. – Amelio Vazquez-Reina Apr 01 '13 at 22:01
2

expanding on Chris answer, you can use another function like a decorator to add your own functionality to jupyters showbacktrace:

from IPython.core.interactiveshell import InteractiveShell
from functools import wraps
import traceback
import sys

def change_function(func):
    @wraps(func)
    def showtraceback(*args, **kwargs):
        # extract exception type, value and traceback
        etype, evalue, tb = sys.exc_info()
        if issubclass(etype, Exception):
            print('caught an exception')
        else:
            # otherwise run the original hook
            value = func(*args, **kwargs)
            return value
    return showtraceback

InteractiveShell.showtraceback = change_function(InteractiveShell.showtraceback)

raise IOError
Matthias123
  • 882
  • 9
  • 15
2

sys.excepthook won't work in ipython. I think the recommended way of hooking to exceptions is to use the set_custom_exc method, like this:

from IPython import get_ipython
ip = get_ipython()


def exception_handler(self, etype, evalue, tb, tb_offset=None):
    print("##### Oh no!!! #####")  # your handling of exception here
    self.showtraceback((etype, evalue, tb), tb_offset=tb_offset)  # standard IPython's printout

    
ip.set_custom_exc((Exception,), exception_handler)  # register your handler
raise Exception("##### Bad things happened! #####")  # see it in action

See the docs for more details: https://ipython.readthedocs.io/en/stable/api/generated/IPython.core.interactiveshell.html#IPython.core.interactiveshell.InteractiveShell.set_custom_exc

Michał Jabłoński
  • 1,129
  • 1
  • 13
  • 15
0

See this SO question and make sure there isn't something in your sitecustomize.py that prevents debugging in interactive mode.

Community
  • 1
  • 1
Arkady
  • 14,305
  • 8
  • 42
  • 46