Is there a way to set a dynamic breakpoint***, suspend on exception, in pdb?
***dynamic in the sense of not tied to any line number
In pycharm (pydev), this is possible and is a nice feature, but often times, I have to use pdb due to limitations of the pycharm debugger (no jump functionality and/or the machine doesn't have pycharm).
You're looking for postmortem mode:
try:
code_that_may_raise_exception()
except Exception:
import pdb; pdb.post_mortem()
This will break on exception and drop you into a debugger right where it is being raised from
Related
A similar question
When developing some Windows desktop stuff in Delphi, I had a habit of inserting
asm(int 3);.
If a debugger is running, that acts like a breakpoint. If no debugger is running, it does nothing (NOOP).
I would like to do something similar for my Python scripts. Is there some Python function like HaltDebugger()? Cross platform, of course.
[Update] I am looking for something that will work with PyCharm
This is the most portable solution. A more difficult one is sketched below for PyCharm.
Kind of depends on the debugger, but if you use pdb (which would be cross platform), the docs state:
The typical usage to break into the debugger from a running program is
to insert
import pdb; pdb.set_trace()
you want this to be conditional, so you can paste at each breakpoint:
try: pdb.set_trace()
except NameError: pass
and when you want to debug just import pdb at the top. If it must be one line you cannot use duck typing. Instead:
if 'pdb' in globals(): pdb.set_trace()
PyCharm only
Assuming you insist on not marking debugging lines with the mouse this might work:
Using exception breakpoints:
PyCharm provides exception breakpoints for Python, Django, and
JavaScript.
Exception breakpoints are triggered when the specified exception is
thrown. Unlike the line breakpoints, which require specific source
references, exception breakpoints apply globally to the exception
condition, rather than to a particular code reference.
Depending on the type of processing an exception, the debugging can
break when a process terminates with an exception, or as soon as an
exception occurs.
You could:
Create a custom exception in your project, DebugException
Set the exception breakpoint as per the link above. Make sure it is set to trigger immediately, not when program exits.
Finally,
paste
try: raise DebugException()
Exception: pass
wherever you want to break. This seems like a lot of trouble to not double click with your mouse to mark a breakpoint.
In my project that based on asyncio and asyncio tcp connections that debugs with PyCharm debugger I got very and very very absurd errors.
If I put breakpoint on code after running, the breakpoint never fires.
But breakpoints fires if breakpoint has been put before starting program.
But in some cases the firing on breakpoints causes strange errors (if paused on breakpoint and resumed).
The next exceptions I remarked:
TypeError: 'coroutine' object not callable
SystemError: unknown opcode
First exception is very rare. Can be raised in any place on code and unrepeatable.
Second exception I remarked the first time recently. This is repeatable in my code. The function where I put breakpoint is function in async task (asyncio.Task). I can't repeat from scratch. But I think the type of exception (unknown opcode??? O_O) should make you think.
Besides! The exception vanished if I change the code: for example I added the a = 0 line. Exception not raised after. The deleting a = 0 will return this exception again.
Is this error of kind of esoteric errors?
I think the PyCharm debugger conflicts with asnycio.
Or maybe I doing something wrong?
Unknown opcode can be any line of code in the function where breakpoint put. Repeats in specific places in code.
This exception also can be at line, but also inside another function. Very rare and unreproducible
which version of python you use? There is new debugger for python3.6 based on inserting opcodes before starting process. You can find some more info in this repo https://github.com/Elizaveta239/frame-eval
Is this idiomatic/pythonic to do like this or is there a better way? I want all the errors to get in log for in case I don't have access to the console output. Also I want to abort this code path in case the problem arises.
try:
with open(self._file_path, "wb") as out_f:
out_f.write(...)
...
except OSError as e:
log("Saving %s failed: %s" % (self._file_path, str(e)))
raise
EDIT: this question is about handling exceptions in a correct place/with correct idiom. It is not about logging class.
A proven, working scheme is to have a generic except clause at the top level of your application code to make sure any unhandled error will be logged (and re-raised fo course) - and it also gives you an opportunity to try and do some cleanup before crashing)
Once you have this, adding specific "log and re-reraise" exception handlers in your code makes sense if and when you want to capture more contextual informations in your log message, as in your snippet example. This means the exception might end up logged twice but this is hardly and issue .
If you really want to be pythonic (or if you value your error logs), use the stdlib's logging module and it's logger.exception() method that will automagically add the full traceback to the log.
Some (other) benefits of the logging module are the ability to decouple the logging configuration (which should be handled by the app itself, and can be quite fine-grained) from the logging calls (which most often happen at library code level), the compatibility with well-written libs (which already use logging so you just have to configure your loggers to get infos from 3rd-part libs - and this can really save your ass), and the ability to use different logging mechanisms (to stderr, to file, to syslog, via email alerts, whatever, and you're not restricted to a single handler) according to the log source and severity and the deployment environment.
Update:
What would you say about re-raising the same exception (as in example) or re-raising custom exception (MyLibException) instead of original one?
This is a common pattern indeed, but beware of overdoing it - you only want to do this for exceptions that are actually expected and where you really know the cause. Some exception classes can have different causes - cf OSError, 'IOErrorandRuntimeError- so never assume anything about what really caused the exception, either check it with a decently robust condition (for example the.errnofield forIOError`) or let the exception propagate. I once wasted a couple hours trying to understand why some lib complained about a malformed input file when the real reason was a permission issue (which I found out tracing the library code...).
Another possible issue with this pattern is that (in Python2 at least) you will loose the original exception and traceback, so better to log them appropriately before raising your own exception. IIRC Python3 has some mechanism to handle this situation in a cleaner way that let you preserve some of the original exception infos.
I am using Eclipse + PyDev, although I can break on exception using PyDev->Manage Exception Breakpoints, I am unable to continue the execution after the exception.
What I would like to be able to do is to set the next statement before the exception so I can run a few commands in the console window and continue execution. If I use Eclipse -> Run -> Set Next Statement before the exception, the editor will show the next statement being where I set it but then when resuming the execution, the program will be terminated.
Can this be done ?
Unfortunately no, this is a Python restriction on setting the next line to be executed: it can't set the next statement after an exception is thrown (it can't even go to a different block -- i.e.: if you're inside a try..except, you can't set the next statement to be out of that block).
You could in theory take a look at Python itself as it's open source and see how it handles that and make it more generic to handle your situation, but apart from that, what you want is not doable.
Is there a command in the Python debugger (pdb) that says something like "run until the next exception is raised?"
Seems an obvious requirement but can't seem to find it.
Update : To be clear, my problem is an exception which is being caught and turned into an inadequate message in a log file. And I can't find where the exception is raised.
I figured that if I could go into trace mode and say "run until an exception is thrown" that would be the most straightforward way of finding it. I don't think post-mortem will work here.
Execute your script as follows:
python -m pdb myscript.py
Press c and Enter.
When an uncaught exception is raised you program will stop running and fall back to the pdb debug prompt.
Can you search the code in the failing script for the text of the message that is logged (I realize that this may be difficult if the string is generated in a complex way). If you can find the point where the message is generated/logged then you can set an appropriate break point to troubleshoot the problem.
Unfortunately, AFAIK Python pdb debugging does not offer the capability that is present in some other languages to say, for example, break when Exception is raised.