In python you can define an exception hook such that all errors go through it and you can print them as you’d like. I would like to the same in Julia, but haven’t found a way yet.
I haven’t found good docs on how errors are handled internally, but going through the code I’ve found functions like show_backtrace and showerror in Base.errorshow.jl and display_error in Base.client.jl as well as other similarly named functions.
I can re-define this to print out formatted error messages as above, but there’s several things I’m not clear with:
what calls show_backtrace and errorshow? Does it depend on where the code is run (e.g. in VSCode or in the Julia app?). I can re-define show-backtrace and errorshow, but ideally I’d like to intercept error messages before.
what prints out LoadErrors? It seems to bypass show_backtrace and errorshow as I can’t find a way to style that.
Accessing locals: in python’s exceptions hook you have access to locals at all levels in the callstack (see second image above). I know there’s Base.@locals but that only gives the locals where the macro is used. Is there a way to get locals at each frame in a stacktrace or backtrace?
Julia’s errors come with hints provided by Base.Experimental.show_error_hints, which is really nice. However when I try to use show_error_hints in my re-defined errorshow functions it doesn’t give any hint (it returns nothing). Is there a way to access error hints?
show_error_hints always returns nothing, the hints are printed to the supplied IO object. You can of course use sprint to get the output as a string or take a look at its source code if you want each separate hint.
Note however that refining any of these functions is type piracy and strongly discouraged
I would very much prefer not having to do that! But is there an alternative to it like python’s exception hook?
If lines like Base.invokelatest(Base.display_error, errio, val) that you’ve send above (and similar ones e.g. in VSCode’s Julia Extension) are what prints out the error, then I’m guessing I have to re-define Base.display_error?
At any rate, it wouldn’t be done by default in my package, it would be an option that users have to explicitly activate and I will warn them that it’s a hacky solution.
There is Base.Experimental.register_error_hint, but you seem to already have discovered that. Your projects looks very exciting, so if you have a concrete proposal for what kind of hooks you would need, I think the core devs would be open to discuss potential changes to base.
display_error should end up calling showerror, so redefining that should have similar effects.
Perhaps a solution would be to push your own display to the top of the display stack. Literate.jl uses pushdisplay and popdisplay to catch display calls. I believe something similar is done for e.g. the plot pane in the VS code extensions.
This is an exciting project to see being worked on!
It is not uncommon to receive three-page nested error messages when (ab)using DataFrames.jl, for example, and I think this is a significant problem for Julia’s general adoption. Especially for those coming from languages like Python, whose traceback messages are (mostly) very succinct and lucid, such long error messages can be scary and hard to glean information from.
I don’t think it’s appropriate for Term.jl’s style of displaying error messages to become Julia’s default, but I would love to see Julia’s error messages become something in between what they are now and the proof-of-concept shown in this post.
I hope the Julia devs agree that providing an interface for intercepting and display error messages is a good investment. I’m thinking this might also be a boon for HTML-based front-ends like Pluto.jl.