Qix-/better-exceptions

Do you want to work on this issue?

You can request for a bounty in order to promote it!


3 active bounty requests

$40.00$40.00$40.00
Solve someone else's bounty request by clicking on it and completing the funding to earn additional credits

ipython support #10

kootenpv posted onGitHub

Does not appear to work in ipython (at least in emacs)


Hi - can you post exact errors so I know Im reproducing correctly?

Thanks!

posted by Qix- about 8 years ago

There's just no difference when I import it, it's not actually an error. Try running ipython and importing better_exceptions

posted by kootenpv about 8 years ago

Ah, iPython uses a different means to hook into exceptions...

I'll have to do a bit of research about this. iPython doesn't seem to want to install for me at the moment.

posted by Qix- about 8 years ago

+1 on this

posted by lincolnfrias almost 8 years ago

You may find some inspiration in the following projects working on exception hooks as well:

The trick is probably to call set_custom_exc(exc_tuple, handler).

(By the way, awesome project!)

posted by SylvainDe almost 8 years ago

If you put this in $HOME/.ipython/profile_default/startup/00-better_exceptions.py this will enable better_exceptions to be used as the default exception formatter in ipython. Maybe this should go in a contrib folder or something like that.

from __future__ import print_function
import better_exceptions, sys

ip = get_ipython()
old_show = ip.showtraceback

def exception_thunk(exc_tuple=None, filename=None,
                    tb_offset=None, exception_only=False):
    print("Thunk: %r %r %r %r" % (exc_tuple, filename, tb_offset, exception_only),
          file=sys.stderr)
    notuple = False
    if exc_tuple is None:
        notuple = True
        exc_tuple = sys.exc_info()
    use_better = True
    use_better = use_better and (filename is None)
    use_better = use_better and (tb_offset is None)
    use_better = use_better and (not exception_only)
    use_better = use_better and (not isinstance(exc_tuple[0], SyntaxError))
    if use_better:
        return better_exceptions.excepthook(*exc_tuple)
    else:
        return old_show(None if notuple else exc_tuple,
                        filename, tb_offset, exception_only)

ip.showtraceback = exception_thunk
posted by Omnifarious almost 8 years ago

doesnt work with python3

Python 3.5.3 (default, Jan 19 2017, 14:11:04)
Type "copyright", "credits" or "license" for more information.

IPython 5.3.0 -- An enhanced Interactive Python.
?         -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help      -> Python's own help system.
object?   -> Details about 'object', use 'object??' for extra details.

In [1]: def hey(a):
   ...:     return a/a
   ...:

In [2]: hey(0)
Thunk: None None None False
posted by ramast almost 8 years ago

example by @Omnifarious rewritten for IPython with python3 put in $HOME/.ipython/profile_default/startup/00-better_exceptions.py

import better_exceptions, sys 

ip = get_ipython()
old_show_tb = ip.showtraceback

def exception_thunk(exc_tuple=None, filename=None,
                    tb_offset=None, exception_only=False):
    new_exc_tuple = exc_tuple or sys.exc_info()
    if not isinstance(new_exc_tuple[0], SyntaxError):
        return print(better_exceptions.format_exception(*new_exc_tuple))
    else:
        return old_show_tb(exc_tuple, filename,
                           tb_offset, exception_only)

ip.showtraceback = exception_thunk

WARNING: as alternative you can use %xmode magic

posted by Nosterx about 7 years ago

Re-writing the example above to work with IPython 3.2.1 and also to handle the case where better_exceptions_module is not present in the system

import sys
try:
    import better_exceptions
except ImportError:
    better_exceptions = None

def exception_thunk(exc_tuple=None, filename=None,
                    tb_offset=None, exception_only=False, **kwargs):
    new_exc_tuple = exc_tuple or sys.exc_info()
    if not isinstance(new_exc_tuple[0], SyntaxError):
        return print(better_exceptions.format_exception(*new_exc_tuple))
    else:
        return old_show_tb(exc_tuple, filename,
                           tb_offset, exception_only)
if better_exceptions:
    ip = get_ipython()
    old_show_tb = ip.showtraceback
    ip.showtraceback = exception_thunk

I've added **kwargs because IPython gave that error TypeError: exception_thunk() got an unexpected keyword argument 'running_compiled_code'

posted by ramast about 7 years ago

And now to make it work with pdb mode ;)

posted by kootenpv about 7 years ago

@kootenpv It already does.

def foo(a):
    import pdb; pdb.set_trace()
    assert a == 10

foo(12)

<img alt="image" src="https://user-images.githubusercontent.com/885648/35006749-ab39e806-faf7-11e7-8a2a-74324a5c6f53.png" />

EDIT: ah I see, it doesn't with stepping.

posted by Qix- about 7 years ago

Hi, I just tried the startup script from @ramast and it works fine, but the better_exceptions output isn't colorized. To make colors work, you can add better_exceptions.SUPPORTS_COLOR = True to the final if body (not sure what it will do if the terminal doesn't support colors, probably just print the color codes).

posted by Incanus3 about 6 years ago

Hi~

if you don't want to see ipython's exception in the Traceback, you can use this one:

import sys
try:
    import better_exceptions
except ImportError:
    better_exceptions = None

def exception_thunk(exc_tuple=None, filename=None,
                    tb_offset=None, exception_only=False, **kwargs):
    new_exc_tuple = exc_tuple or sys.exc_info()
    if not isinstance(new_exc_tuple[0], SyntaxError):
        # return print(better_exceptions.format_exception(*new_exc_tuple))
        error = better_exceptions.format_exception(*new_exc_tuple).split('\n')
        return print("Traceback (most recent call last):\n"+'\n'.join(error[6:]), end='')
    else:
        return old_show_tb(exc_tuple, filename,
                           tb_offset, exception_only)
if better_exceptions:
    ip = get_ipython()
    old_show_tb = ip.showtraceback
    ip.showtraceback = exception_thunk

example:

before:

In [1]: def foo(a):
   ...:     assert a > 1
   ...:

In [2]: foo(0)
Traceback (most recent call last):
  File "/xxxx/xxxx/.pyenv/versions/3.6.5/lib/python3.6/site-packages/IPython/core/interactiveshell.py", line 3267, in run_code
    exec(code_obj, self.user_global_ns, self.user_ns)
         │         │                    └ <IPython.terminal.interactiveshell.TerminalInteractiveShell object at 0x10433f438>
         │         └ <IPython.terminal.interactiveshell.TerminalInteractiveShell object at 0x10433f438>
         â”” <code object <module> at 0x1047096f0, file "<ipython-input-2-e3ad81521767>", line 1>
  File "<ipython-input-2-e3ad81521767>", line 1, in <module>
    foo(0)
    â”” <function foo at 0x104706f28>
  File "<ipython-input-1-41263cb52715>", line 2, in foo
    assert a > 1
           â”” 0
AssertionError: assert a > 1

after:

In [5]: def foo(a):
   ...:     assert a > 1
   ...:

In [6]: foo(0)
Traceback (most recent call last):
  File "<ipython-input-6-7d8d25071659>", line 1, in <module>
    foo(0)
    â”” <function foo at 0x111562950>
  File "<ipython-input-5-46c24d49c44a>", line 2, in foo
    assert a > 1
           â”” 0
AssertionError: assert a > 1

i don't know how to pop the exception in the Traceback...so i just delete the line 1 to 6

posted by Macr0phag3 about 6 years ago

To make it work with IPython debug, use this improved version:

from __future__ import print_function
import better_exceptions, sys, types
ip = get_ipython()
old_show = ip.showtraceback
def exception_thunk(self, exc_tuple=None, filename=None,
                    tb_offset=None, exception_only=False, **kwargs):

    notuple = False
    if exc_tuple is None:
        notuple = True
        exc_tuple = sys.exc_info()
    etype, value, tb = self._get_exc_info(exc_tuple)
    use_better = not any ([filename, tb_offset, exception_only, issubclass(etype, SyntaxError)])
    if use_better:
        return better_exceptions.excepthook(etype, value, tb)
    else:
        return old_show(None if notuple else exc_tuple,
                        filename, tb_offset, exception_only, **kwargs)

ip.showtraceback = types.MethodType(exception_thunk, ip)
posted by frostming almost 6 years ago

@issuehunt has funded $70.00 to this issue.


posted by issuehunt-app[bot] over 5 years ago

There are a number of code snippets posted in this issue. It seems like this may already work, but not out of the box. Is there a canonical workaround for ipython's different way of handling tracebacks

Ideally one that doesn't require messing with creating a personal ipython startup script. My personal preference would be registering an ipython magic like many other ipython related libraries do. Something like %%better_exceptions so it can be explicitly turned on/off per cell... But anything is usually an improvement on nothing. So it would be good to just have a clear workaround at all. 😄

posted by techdragon over 5 years ago

Someone mentioned %xmode in passing and I think it deserves more attention. For those who don't know, %xmode Verbose will change the builtin exception handler to display variables. It's trying to solve the same problem as better-exceptions. Wouldn't the best solution be to identify what better-exceptions has to offer that xmode doesn't and then integrate those features directly into IPython?

Going a little off-track, it's possible to do better than either in some cases. In GUI environments like Jupyter notebooks and Jupyterlab, one can create an interactive traceback that only shows variables when requested. Django puts them in a collapsible panel:

django

Flask/werkzeug lets you open a console in any frame:

flask

I don't know if anyone does this, but I think it might be awesome if hovering over a variable name in a traceback displays it.

There's an open issue about this: https://github.com/jupyter/notebook/issues/1247

posted by alexmojaki over 5 years ago

OK, somewhat coincidentally, an alternative possibility has come up here: https://github.com/ipython/ipython/issues/11827#issuecomment-513001601

In particular:

Ultratb is a real mess and really old. Any refactor to it is welcomed; I've been willing from some time to separate the traceback information extracting from the formatting, to potentially make a nice HTML repr... If we want/can extract these into common packages I'm all for it. There is also https://github.com/qix-/better-exceptions that looks nice; though showing variable values can be a security issue s can't be enabled by default.

Essentially it would be good if there was a package which had a lower level API that returned information about a traceback which a user could easily format in different ways. IPython would be interested in such a package, as would I, and potentially other packages such as Django and Flask.

@Qix- are you interested in this package being refactored to offer such an API? It would then power the existing higher level API which does the formatting, hooks, REPL, etc. The higher level API could also still be useful to other packages, e.g. @Carreau was probably mainly interested in the variable formatting.

I would be happy to work on the coding, and I'm guessing others would too. But I'm concerned by the PRs that are starting to queue up with little/no response. @Qix-, do you still have the time and energy to maintain this repository and review contributions? Would you be able to handle the increased pressure if this became a dependency of IPython? If not, would you be willing to hand the responsibility over to others such as @Delgan? Otherwise I am tempted to write such a package myself from scratch and borrowing bits of code from here.

posted by alexmojaki over 5 years ago

Hey @alexmojaki, I'm still around - moved around the world about 8 months ago and have just lately been getting back into OSS.

I appreciate the heads up about the ipython issue - I'd be very interested in a more comprehensive package.

As for the neglect, I will be rectifying that in the coming week.

posted by Qix- over 5 years ago

Thanks that is great ! Hope you enjoyed your trip around the world !

Some notes: IPython also support showing variables values in stacktraces; it is disabled by default because we had issues where this was leaking secrets in tracebacks during talks, or to notebooks published on github. Though the way you show it is way nicer than ours!

There are also 2 things that we do, which I believe this does not do yet is 1) show more than 1 line context, and 2) elide when there is a recursion error with N frames repeated X times.

A more comprehensive package and single-stop-shop is always good. Even better if we can at some point justify movin some of the functionality to core Python :-)

posted by Carreau over 5 years ago

@Carreau I've opened #92 to discuss showing multiple lines in a frame.

posted by alexmojaki over 5 years ago

Fund this Issue

$70.00
Funded
Only logged in users can fund an issue

Pull requests

Recent activities

issuehunt funded 70.00 for Qix-/better-exceptions# 10
over 5 years ago