-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
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
Refine exception stack API #29901
Refine exception stack API #29901
Conversation
Regarding struct ExceptionState
exception
backtrace
end
const ExceptionStack = Vector{ExceptionState} which might make more or less sense. It's a little nicer because it doesn't introduce a container type for this one small thing. It's a little worse because it would assume that any |
Travis failure on linux32 is failure of a single test, due to #29923 The appveyor failure on 64 bit is really odd (a timeout? but with no error message or other indication of what went wrong?) I've restarted that and we'll see. |
Win64 CI problem has symptoms the same as #29603 |
Would it make sense to have each exception have |
It does make sense and in some ways would be more natural and less disruptive. But the problem is user exception types: how do we ensure they actually have such a field? Basically, I don't think we can, at least not without the change being hugely breaking. We even allow people to throw things which aren't Given we don't have structural inheritance, that leaves us with composition: struct ExceptionState
exception
backtrace
next::Union{Nothing,ExceptionState}
end Which I think would be quite a natural way of expressing this. But unfortunately no less breaking and somewhat less flexible to use than just doing what I've done in this PR, and shoving them all in a |
Hmm. That's interesting: this may be the first compelling case I've encountered where allowing abstract types to have fields would be really useful—it would allow us to insert a |
By the way, my feeling was that there's no harm in providing a simple function-based interface to the exception stack system and seeing how that pans out. Clearly it's not the end game and you'd like it to integrate better with the syntax. But the best syntax also depends on deeper design questions about how exceptions should be matched. ... having said that I didn't want to talk syntax, now I can't resist suggesting the following which popped into my head: try
# blah
catch es... # equivalent to `es = current_exceptions()`
# whatever
end |
@@ -91,28 +91,34 @@ function catch_backtrace() | |||
return _reformat_bt(bt[], bt2[]) | |||
end | |||
|
|||
struct ExceptionStack <: AbstractArray{Any,1} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This type doesn't seem necessary to me. Since showing errors goes through display_error
anyway, having a type with a show
method is a bit redundant (and does have some duplicated code here).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since showing errors goes through display_error anyway
That's only true for the REPL where we pass exceptions and backtraces directly to display_error
rather than dispatching them to some generic machinery which needs to match on their type.
In the generic case, there's currently no nice way to pass around a package of exceptions and backtraces together such that their type can be dispatched on in a non-clumsy way. I'm thinking particularly of Logger
s, where I'd like to be able to have things like:
@error "Something bad happened" arbitrary_key_name=current_exceptions()
and have this actually display something sensible without clumsy matching of types in the Logger backend. We currently resort to such matching, for example
julia/stdlib/Logging/src/ConsoleLogger.jl
Lines 45 to 52 in 7a5042a
# Formatting of values in key value pairs | |
showvalue(io, msg) = show(io, "text/plain", msg) | |
function showvalue(io, e::Tuple{Exception,Any}) | |
ex,bt = e | |
showerror(io, ex, bt; backtrace = bt!=nothing) | |
end | |
showvalue(io, ex::Exception) = showerror(io, ex) | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not that I love ExceptionStack
as a type, it seems annoying and superfluous on the surface, and it's one of the main reasons I wanted some more eyes on this.
What I'd really like are suggestions about how to replace or improve it, while also having a way to pass these to logging macros and have them robustly recognized by the logger backend.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's true that there's a little duplication of code between show
and display_error
. Previously I tried making display_error
dispatch to show
and adding some IOContext
handling to turn on the simplifications we currently use in display_error
. That turned out somewhat complex though so I punted in the current iteration and left it with two concrete implementations.
I could give it another go.
074e39b
to
3137d44
Compare
I've rebased, fixed the minor conflict and renamed The remaining question in my mind is what to do about |
Codecov Report
@@ Coverage Diff @@
## master #29901 +/- ##
=========================================
Coverage ? 39.06%
=========================================
Files ? 344
Lines ? 61454
Branches ? 0
=========================================
Hits ? 24008
Misses ? 37446
Partials ? 0 Continue to review full report at Codecov.
|
Win64 issue appears to be #29603 again, restarted. |
My impression is that an exception or exception stack needs to be passed to a context that expects it --- it usually doesn't make sense to have a context that expects an arbitrary value, and then sometimes treats it as an error based on its type. |
Yes logging backends can have magic autodetection of "I think this vector looks structurally like it contains exceptions and backtrace pairs" and they can dig exception stacks out of the arbitrary list of user-supplied I'm also not sure why Putting those concerns aside in the interest of getting this done, would it be ok to define a type alias
and to remove the special |
@JeffBezanson As food for thought I've added a commit c886fef which removes both It's not too bad but on the whole it seems like a semantic step backward. On the upside it removes a small amount of code. |
Hm, yeah, that doesn't seem great. I think wrapping the vector in an |
That's not at all what I meant to suggest. Looking at the overall type of the value, or the element type, or the types of objects contained in it are all variations of the same thing: examining the value itself to determine how to use it. I'm saying there needs to be some information outside the value itself to tell you what it represents. For example as @vtjnash mentioned |
Sorry @JeffBezanson, I just couldn't catch your meaning before. I've reverted that last commit (will be rebased away later).
Right, this is exactly what the logging documentation already says :-) However, I'm worried about how to
If
Thanks @vtjnash that's an extremely relevant point. Previously things like |
In the spirit of seeing how The previous exception is still eagerly captured and stored in |
Yes, I agree LoadError (and InitError) saving the last exception is now redundant; nice! I would say keep everything the same except the printing of LoadError, which now doesn't need to show its inner exception. In 2.0 we can remove those fields. |
Unrelated to this PR, but just from looking at that screenshot, we should eventually hide all frames (but one) that are printed in a earlier (in printing order) list |
Also the simplest thing to do here is just unexport |
Triage tag was outdated. If there's something left to triage, re-apply the tag and specify the issue. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, conditional on addressing the needs-tests tag (and needs a rebase).
23b064d
to
ff25fee
Compare
bump. Are you able to rebase? |
* Rename the non-exported `catch_stack()` to the more descriptive name `current_exceptions()`. Keep the old name available but deprecated. * Introduce an ExceptionStack as the return type for the function, which (as an AbstractVector) is API-compatible with the previous type returned by `catch_stack()` Having ExceptionStack gives us a place to integrate exception printing in a natural way. In the same way this should be useful for dispatch in other areas of the ecosystem which want to dispatch on exception stacks.
ff25fee
to
35a501b
Compare
Wow, this PR has languished for a long time :-( I've found some time to rebase this and update the tests. I'll plan to merge it tomorrow, provided CI passes. |
* Rename the non-exported `catch_stack()` to the more descriptive name `current_exceptions()`. Keep the old name available but deprecated. * Introduce an ExceptionStack as the return type for the function, which (as an AbstractVector) is API-compatible with the previous type returned by `catch_stack()` Having ExceptionStack gives us a place to integrate exception printing in a natural way. In the same way this should be useful for dispatch in other areas of the ecosystem which want to dispatch on exception stacks.
See JuliaLang/julia#29901 This is limited to julia-1.1 and above because earlier versions don' have the necessary runtime library support (Base.catch_stack() etc).
* Rename the non-exported `catch_stack()` to the more descriptive name `current_exceptions()`. Keep the old name available but deprecated. * Introduce an ExceptionStack as the return type for the function, which (as an AbstractVector) is API-compatible with the previous type returned by `catch_stack()` Having ExceptionStack gives us a place to integrate exception printing in a natural way. In the same way this should be useful for dispatch in other areas of the ecosystem which want to dispatch on exception stacks.
See JuliaLang/julia#29901 This is limited to julia-1.1 and above because earlier versions don't have the necessary runtime library support (Base.catch_stack() etc).
* Port Base.current_exceptions() to older Julia versions See JuliaLang/julia#29901 This is limited to julia-1.1 and above because earlier versions don't have the necessary runtime library support (Base.catch_stack() etc). * Also implement current_exceptions on julia-1.0 * Tweak readme to mention Julia-1.0 limitations
Updated Description
This PR has been simplified with some parts merged separately (#30900, #30899). However, the
catch_stack
API has not been finalized. In the current version (as of 2019-02-06), I've got two things here:catch_stack()
->current_exceptions()
as this seems more descriptive.ExceptionStack
so that we can have a proper exception-and-backtrace specific type we can dispatch on. For example, this allows us to have ashow
implemented for exception and backtrace data which pretty prints the information in a much more readable way than the simpleVector
of tuples thatcatch_stack
returns right now.Original Description
Here's a few refinements to the API introduced in #28878. I'm not quite happy with that API for various reasons so I want to revisit it before 1.1 feature freeze (or unexport it before 1.1).
IMO this is a big improvement, but still a bit WIP so feedback would be great.
Rename
catch_stack()
->current_exceptions()
as this seems far more transparent, and is in fact how the function is summarized in the docs. I wasn't happy with the previous name, it's got an analogy tocatch_backtrace
but other than that seemes too obscure. Alternative name proposals gladly welcome (thecurrent_exceptions(task)
variant is perhaps less natural).Introduce a new type
ExceptionStack
so that we have a proper exception-and-backtrace specific type we can dispatch on. This allows us to treatshowerror
as more of an implementation detail, and simply overrideshow(::IO,::ExceptionStack)
in the usual way to get integrated pretty printing of exceptions and backtraces. I'm not quite certain about how this is a wrapper for aVector
; perhaps it should be anAbstractVector
.For PARTR sanity, prevent reading of current exceptions of a concurrently running task, at least for now.
Pretty printing of ExceptionStack in the REPL by overloading
display_error
. Could go into a separate PR if people want this simplified (or just review the commit 074e39b in isolation).Pretty printing of ExceptionStack via
show()
. Examples follow:Notice that by having proper
show
integration, we automatically get things like the following: