Saturday, August 25, 2018

Automatically enter interactive mode after Python exception

By Vasudev Ram



Bug image attribution

Hi, readers,

Here's a Python command-line option that can facilitate debugging, when your program raises an exception:

It's the Python interpreter's -i option.

Here is a small Python program (ent-inter.py, for enter interactive mode) to show how the option can be used:
$ type ent-inter.py

from __future__ import print_function

print("before for loop")
for divisor in (1, 0, -1):
    print("1/{} = {}".format(divisor, 1/divisor))
print("after for loop")
If I run it in the normal way (without the -i option), I get:
$ python ent-inter.py
before for loop
1/1 = 1
Traceback (most recent call last):
  File "ent-inter.py", line 6, in 
    print("1/{} = {}".format(divisor, 1/divisor))
ZeroDivisionError: integer division or modulo by zero
The error message does tell us that there was a division by zero. But it doesn't tell us what exactly caused it.

Okay, in this particular case, from the stack trace (in particular, from the print statement), we can figure out that the variable divisor must have been zero. That was because I kept the code small and simple, though, for illustrative purposes.

But suppose that the cause of the error had been a more complex arithmetic expression, say with multiple division operations, or some other kind of statement (or sequence of statements). In that case, just the stack trace alone might not be enough for us to figure out the root cause of the error.

If we could immediately be launched into a Python interactive session with the current state (i.e. the variables) of the crashed program still available to inspect, that would likely help us to find the root cause. This is what the -i option helps with.

Let's see how:
$ python -i ent-inter.py
before for loop
1/1 = 1
Traceback (most recent call last):
  File "ent-inter.py", line 6, in 
    print("1/{} = {}".format(divisor, 1/divisor))
ZeroDivisionError: integer division or modulo by zero
>>> divisor
0
>>>
I ran the same program again, but this time with the -i option given.

After the program crashed due to the ZeroDivisionError, an interactive Python shell was automatically launched (as we can see from the Python prompt shown).

I typed "divisor" at the prompt, and the shell printed that variable's current value, 0.
From this (plus the stack trace), we can see that this value is the cause of the error. Then we can look one line above, in the program's code (at the for statement) and see that one of the items in the tuple is a zero.

Of course, we can run the program under the control of a command-line debugger (like pdb) or single-step through the code in an IDE, to find the error. But that will only work if the error occurs during one of those runs. If the error is intermittent, running the program multiple times using the debugger or an IDE, will be tedious and time-consuming.

Instead, with this -i option, we can run the program as many times as we want, and for the times when it works properly, we don't waste any time stepping through the code. But when it does give an error like the above one, we are launched into the interactive mode, with the state of the crashed program available for inspection, to help debug the issue.

Another advantage of this approach is that we may not need to replicate the problem, because we have it right there in front of us (due to use of the -i option), and also, replicating the exact conditions that cause a bug is not always easy.

Note: I ran this program with the -i option on both Python 2.7 and Python 3.7 [1] on Windows, and on Python 2.7 on Linux. Got the same results in all 3 cases, except that in Python 3, the error message is slightly different:

ZeroDivisionError: division by zero

[1] Running it with Python 3 (on Windows) can be done in the usual way, by changing your PATH to point to Python 3 (if it is not already set to that), or by using Py, the Python launcher for Windows, like this:
$ py -3 -i ent-inter.py
So, overall, Python's -i option is useful.

Here is an excerpt from the output of "python -h" (the python command's help option):
-i     : inspect interactively after running script;
The picture at the top of the post is of one of the first software bugs recorded.

Read that story here on Wikipedia: Software bug

Enjoy.

Interested in a standard or customized Python course? Contact me

- Vasudev Ram - Online Python training and consulting

Hit the ground running with my vi quickstart tutorial.

Jump to posts: Python * DLang * xtopdf

Subscribe to my blog by email

My ActiveState Code recipes

Follow me on: LinkedIn * Twitter

Are you a blogger with some traffic? Get Convertkit:

Email marketing for professional bloggers



No comments: