While debugging, how can I break on raised exceptions EXCEPT FOR specific errors?
Answer a question
I use Visual Studio Code for Python development.
In general, I want my IDE to break whenever an exception is raised, so I have the Raised Exceptions
option checked under the Debug window:
However, there is a specific (encoding-related) exception I would like to ignore because it is raised thousands of times per second. I wrap it in a try-except blocks but, as expected, it breaks when the exception is thrown. I want to suppress this behavior but only for a specific error type.
Is there a way to do this in Visual Studio Code?
Answers
There are a couple settings available for configuring Python exception behavior when debugging in VScode. For the following examples, we assume that the checkboxes Raised Exceptions and Uncaught Exceptions are both checked (enabled). This is normally a situation where there the debugger is stopping for lots of unwanted exceptions.
Intro
Consider the following example. For this code, the debugger will stop at the three places indicated.
try:
1 / 0 # FIRST STOP
except:
pass
func = lambda: 1 / 0 # SECOND STOP
try:
func() # THIRD STOP
except:
pass
Note that the exception that causes the "second stop" notated above doesn't occur at the point in the code where variable func is assigned. Indeed, being outside of a try-except
block, such code would otherwise cause the program to exit. Instead, of course, the exception happens later on nested within the delayed invocation, which thankfully is protected by try
. This distinction will become important for an example further below.
1. Line annotation
The first technique allows you to prevent the debugger from breaking on exceptions at specific locations in your code. Put the special @IgnoreException
token in a comment on the desired line or lines. See here for the RegEx forms of this tag which the debugger will recognize.
try:
1 / 0 #@IgnoreException
except:
pass
func = lambda: 1 / 0 #@IgnoreException
try:
func() #@IgnoreException
except:
pass
This is great for specialized, fine-grained control of where the debugger stops, but obviously as a more general solution, this approach will quickly get out-of-hand. Before moving on from this though, note that there is a way to globally enable or disable the @IgnoreException
behavior in the debugger.
This feature is enabled by default when the debugger starts; if that's all you need you can skip this section. To globally disable @IgnoreException
handling, you can either just insert the following snippet where it executes once at the start of your program or, if desired, instrument your code to programatically enable and disable @IgnoreException
handling according to runtime conditions as needed. A try-except
block prevents the code from crashing when it's not being debugged or if the debugger isn't installed.
# To enable or disable @IgnoreException handling when pydevd is active:
# 'True' - debugger won't stop on '@IgnoreException` lines (default)
# 'False' - the annotation are ignored, allowing the debugger to stop
try:
import pydevd
d = pydevd.GetGlobalDebugger()
d.ignore_exceptions_thrown_in_lines_with_ignore_exception = False
except:
pass
2. Context-aware ignore
Moving on to the second option, I'll reset back to the original code, without the line annotations. This time, by changing the value of a secret debugger switch, the debugger will only stop on exceptions which are raised outside of the caller's immediate context. This is the skip_on_exceptions_thrown_in_same_context
debugger flag, and it is not enabled by default, so if you want this behavior, you have to explicitly turn it on (as shown):
try:
from pydevd import GetGlobalDebugger
GetGlobalDebugger().skip_on_exceptions_thrown_in_same_context = True
except:
pass
try:
1 / 0
except:
pass
func = lambda: 1 / 0
try:
func() # ONLY STOP
except:
pass
Now the debugger only stops one time, versus stopping on three raised exceptions previously, in the first example. And I know what you're thinking, now it makes more sense to combine these two approaches, since there will typically be far fewer points in most code that will need annotating with @IgnoreException
.
3. Combine both techniques
So here's the final version of the example which, even with both the RaisedExceptions and UncaughtExceptions options enabled, the VScode debugger runs all the way through without stopping:
try:
from pydevd import GetGlobalDebugger
GetGlobalDebugger().skip_on_exceptions_thrown_in_same_context = True
except: pass
try:
1 / 0
except:
pass
func = lambda: 1 / 0
try:
func() #@IgnoreException
except:
pass
# NO DEBUGGER STOPS...
更多推荐
所有评论(0)