Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ipython support #10

Open
kootenpv opened this issue Mar 22, 2017 · 21 comments
Open

ipython support #10

kootenpv opened this issue Mar 22, 2017 · 21 comments
Labels
💵 Funded on Issuehunt This issue has been funded on Issuehunt enhancement help wanted

Comments

@kootenpv
Copy link

kootenpv commented Mar 22, 2017

Issuehunt badges

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


IssueHunt Summary

Backers (Total: $70.00)

Become a backer now!

Or submit a pull request to get the deposits!

Tips


IssueHunt has been backed by the following sponsors. Become a sponsor

@Qix- Qix- added the bug label Mar 22, 2017
@Qix-
Copy link
Owner

Qix- commented Mar 22, 2017

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

Thanks!

@kootenpv
Copy link
Author

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

@Qix-
Copy link
Owner

Qix- commented Mar 22, 2017

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.

@lincolnfrias
Copy link

+1 on this

@Qix- Qix- added enhancement and removed bug labels Mar 24, 2017
@SylvainDe
Copy link

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!)

@Omnifarious
Copy link

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

@ramast
Copy link

ramast commented Apr 1, 2017

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

@Nosterx
Copy link

Nosterx commented Jan 15, 2018

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

@ramast
Copy link

ramast commented Jan 16, 2018

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'

@kootenpv
Copy link
Author

And now to make it work with pdb mode ;)

@Qix-
Copy link
Owner

Qix- commented Jan 16, 2018

@kootenpv It already does.

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

foo(12)

image

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

@Incanus3
Copy link

Incanus3 commented Feb 8, 2019

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).

@Macr0phag3
Copy link

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

@frostming
Copy link

frostming commented Apr 10, 2019

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)

@issuehunt-oss
Copy link

issuehunt-oss bot commented Jul 13, 2019

@issuehunt has funded $70.00 to this issue.


@issuehunt-oss issuehunt-oss bot added the 💵 Funded on Issuehunt This issue has been funded on Issuehunt label Jul 13, 2019
@techdragon
Copy link

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. 😄

@alexmojaki
Copy link

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: jupyter/notebook#1247

@alexmojaki
Copy link

OK, somewhat coincidentally, an alternative possibility has come up here: ipython/ipython#11827 (comment)

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.

@Qix-
Copy link
Owner

Qix- commented Jul 20, 2019

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.

@Carreau
Copy link

Carreau commented Jul 20, 2019

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 :-)

@alexmojaki
Copy link

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
💵 Funded on Issuehunt This issue has been funded on Issuehunt enhancement help wanted
Projects
None yet
Development

No branches or pull requests