-
Notifications
You must be signed in to change notification settings - Fork 142
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
Add tooltips to exception categories #790
Comments
See also #364 for similar concerns. Actually I believe that that issue has regressed now for all trio code, but again, hard to know, when I don't know what to expect. |
All modes are kind of independent (so, enabling one shouldn't change the behavior of the other, although @karthiknadig @int19h maybe something like that could be added to: https://code.visualstudio.com/docs/python/debugging. |
Thanks for taking a look at this. I am sorry if this seems nitpicky, but I really think it would be helpful to be precise on these points. Maybe we can go through these one at a time, to make sure I completely understand and that we are in agreement? Raised ExceptionsPrecondition: Expectation: Lets say I have a third party library (bad_sync_lib) with this test function:
In my code I have this function:
Actual: The debugger stops the code on the bad_func() line. Precondition: Expectation: Actual: |
Actually, in that case it only stops at your code when the exception is reraised there. -- if that's not the case then either it's a bug or the library code is being considered user code. |
The third party library is in a different project, which is build as a wheel file with poetry build. The wheel file is then added to the test project using Can you please explain what you mean by 'reraise'. To me reraise is a pattern like this:
|
Yes, that'd be an explicit reraise, but if you don't have any |
Ok? So as designed, the debugger will halt on the same exception through the entire stack frame? I am seeing this behaviour, and let me say I find it most surprising. My expectation would be, that the debugger only halts the first time a particular exception is raised (or reraised and you have the ability to see it). I don't see how it would be useful to see the same exception raised, again and again through the entire stack frame? This also explains the confusion about the second bit "if "justMyCode":true -- which is the default -- only triggers when an exception is raised or reraised in user code": In my example, if justMyCode is true, the reason I see the exception at all, is that it is reraised at that point. So in conclusion on the first issue, I see that the way you have explained it, is indeed how it behaves, however it leaves room for improvement, from my perspective, in that I think once a particular exception has been shown once, it shouldn't be shown again. As it currently works, the debugger halts again and again out through the entire python interpreter, which tells me nothing. I already know what I need to know, from the first time I saw the error. If I press play I shouldn't see that error again. Of cause, if the error causes a different error to be raised elsewhere, it would be fine to see that, but I think the debugger needs to keep track of, which errors the user has seen and hasn't seen. |
Keep in mind that we're significantly constrained by the design of the Python runtime wrt exceptions here. In most languages these days, exception handling is "two-pass" - that is, when exception is raised, first the stack is walked to determine which handler, if any, matches it, and then the stack is unwound to that handler. This makes it easy to determine whether the exception is unhandled or not at the point where it's raised, and whether the handler is in user code. In Python, however, exceptions are more like an open union type with regular values - when an exception is raised, semantically it's more like the function returns a special value to the caller to signal it. If the caller is currently in a try-block, it'll jump to the corresponding handler; if not, it "returns" that exception to its own caller etc. Which means that it's not actually possible to reliably tell whether a given exception is handled or not, and where it is handled, at the point where it's raised - the debugger actually has to look at the bytecode of all the callers on the stack to try to figure it out, and even then that breaks as soon as you have any native frames on the stack. It also means that exception propagating through the stack looks the same as the one that was freshly raised. This might change in the future if python/peps#2070 gets adopted, since it specifically distinguishes between raising and unwinding. |
I dont understand. Each exception instance has a unique hash. Can't you just store the hash when you stop at the exception and if this exception is raised again, ignore it? Seems like it should be straightforward? Anyway, we are getting sidetracked. It would be a great step forward, if the suggested documentation improvements were added. There is still the issue of how these different options interact. I am guessing that when an exception is raised, it is checked for each enabled option and if one of them matches, the debugger stops? I am guessing that this is what is meant by them being independent? From a user perspective, I don't think it is that simple. For example. If you select 'Raised Exceptions', as far as I can tell it doesn't matter if any of the other options are selected or not, because the 'Raised Exceptions' option would trigger in any case where the other options would. Looking at it that way, it does seem to me, that there can be a conceptual interaction between the options, even though it is not the case in the actual implementation. For me, it would help a lot, if this was explained further in the documentation. |
As a note,
Sort of... unique hashes are kind of tricky in that they are only valid while the object they refer to is alive as the same hash can be reused (the way that Python works, reusing a hash is actually pretty common), so, just knowing about the hash isn't enough -- i.e.: it'd almost always work except when a hash is reused by a new exception. Doing a strong ref to the exception isn't really an option (the debugger shouldn't keep objects alive) and a weak-ref to the exception may not work (anyways, inspecting the exception stack to determine if this would be the first place it should be shown is probably enough to implement that feature).
Sort of... @int19h To sum up the part related to showing exceptions just on the first raise, it should be doable, but may need some thought on the UI side of things too... |
Hi, just wanted to say thanks for the fantastic and constructive input. I hope some improvements will end up in the documentation eventually. I have nothing to add at this moment. |
Yes, it all boils down to the UI. Full VS also has many more options for exceptions (although it does conflate "user-unhandled" with Just My Code, basically). VSCode is very basic probably because the baseline was JS, where exception handling is very basic itself. At the minimum, we need some way to add tooltips to exception categories, so that "user-uncaught" could be properly explained. Putting it in the docs is also something that needs to happen - so let's keep this issue open - but docs alone aren't great for discoverability. |
Turns out that DAP already has the requisite properties to add tooltips, so: #798 |
I've added Fabio's initial explanation to the FAQ in the Wiki. |
Resolved by #798 |
The options for debugging exceptions are very confusion. There are now three different options, with some combinations seeming to not make sense.
I would very much like to see, not only thorough documentation, with examples, on each individual option, but also their expected interactions. With three options to chose from, there are now 8(!) possible combinations for how these settings could be picked. Probably most of these don't make sense.
UI wise, VSCode probably is lacking here, as it could be presented better, but good documentation is a first step.
I am seeing a lot of weird behaviour, when debugging exceptions. For instance, as far as I can see an old bug from ptvsd #2027 has regressed in debugpy (at least for async trio code), but it is hard for me to test and report anything, when I have no clue what the expected behaviour is, under the various conditions that are available.
The text was updated successfully, but these errors were encountered: