Python Tracebacks: 'Mimicking the interpreter'+'under program control' - python

The following is from the P3 documentation:
"The [traceback] module provides a standard interface to extract, format and print stack traces of Python programs. It exactly mimics the behavior of the Python interpreter when it prints a stack trace. This is useful when you want to print stack traces under program control, such as in a “wrapper” around the interpreter."
1) Why does the traceback module "mimic" the interpreter?
2) Why is this useful "under program control" (what does this phrase mean)?

From what I understand, by mimic the interpreter, it is meant that the formatting and wording on exception reporting is exactly similar to that performed by the interpreter. That is, this:
import traceback
try:
raise AttributeError("Foo")
except:
traceback.print_exc()
Displays the same message as this would:
raise AttributeError("Foo")
which is:
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
AttributeError: Foo
As for your second question, you can see an example of that in the examples section of the module documentation. The first example illustrates simple "wrapping" of the interpreter (with help from input and exec) and reporting by using print_exc (which mimics the interpreter).

Related

Can I modify what pdb prints when an Exception is thrown?

I run:
python -m pdb script_that_throws.py
When the script throws, say because of a failed assertion, pdb prints the entire stack trace + some pointless boilerplate text:
Traceback (most recent call last):
File "/usr/lib/python3.6/pdb.py", line 1667, in main
pdb._runscript(mainpyfile)
File "/usr/lib/python3.6/pdb.py", line 1548, in _runscript
self.run(statement)
File "/usr/lib/python3.6/bdb.py", line 434, in run
exec(cmd, globals, locals)
File "<string>", line 1, in <module>
[... many lines of stack trace omitted for brevity ...]
File "/path/to/script_that_throws.py", line 26, in _ul
assert v.keys() == self._expected_keys
AssertionError
Uncaught exception. Entering post mortem debugging
Running 'cont' or 'step' will restart the program
> /path/to/script_that_throws.py(26)_ul()
-> assert v.keys() == self._expected_keys
(Pdb)
I would like for Python to only show:
AssertionError
> /path/to/script_that_throws.py(26)_ul()
-> assert v.keys() == self._expected_keys
(Pdb)
Is there a way to achieve that?
There is a good and a bad answer.
The good one. Certainly, you can suppress these messages.
And now the bad answer comes into play.
You have to change cpython source code, and recompile it.
This is not so hard as it sounds at first, especially, as pdb is a Python module, no C knowledge required.
This is the important part of the source code:
https://github.com/python/cpython/blob/master/Lib/pdb.py#L1718-L1725
There is excellent documentation out there on how to compile Python:
https://docs.python.org/3/using/unix.html#building-python
Also, Anthony Shaw just published a book which gives a good introduction on how to work with cpython, the C implementation of the Python language.
Just in case you expected a different kind of answer, no, there is no configuration option for PDB to suppress these kind of messages.
It would be nice to know what script_that_throws.py does. Have you tried using try and except in your script? This can help you handle the pdb exceptions to print whatever you want. Like so:
n = input("age ")
try:
print(int(n))
except ValueError:
print("error")
You can also manually raise your own exception as shown in this thread:
Manually raising (throwing) an exception in Python

Unexpected line given when Python interpreter reports exception [duplicate]

This question already has an answer here:
Why does Python read from the current directory when printing a traceback?
(1 answer)
Closed 3 years ago.
When the Python interpreter reports an error/exception (I'm just going to say "error" to refer to both of these from now on), it prints the line number and contents of the line that caused the error.
Interestingly, if you have a long-running Python script which causes an error and change the .py file while the script is running, then the interpreter can report an incorrect line as raising the error, based on the changed contents of the .py file.
MWE:
sample.py
from time import sleep
for i in range(10):
print(i)
sleep(1)
raise Exception("foo", "bar")
This script runs for 10 seconds, then raises an exception.
sample2.py
from time import sleep
for i in range(10):
print(i)
sleep(1)
"""
This
is
just
some
filler
to
demonstrate
the
behavior
"""
raise Exception("foo", "bar")
This file is identical to sample.py except that it has some junk between the end of the loop and the line raises the following exception:
Traceback (most recent call last):
File "sample.py", line 7, in <module>
Exception: ('foo', 'bar')
What I Did
python3 sample.py
In a second terminal window, mv sample.py sample.py.bak && cp sample2.py sample.py before sample.py finishes execution
Expected Behavior
The interpreter reports the following:
Traceback (most recent call last):
File "sample.py", line 7, in <module>
Exception: ('foo', 'bar')
Here, the interpreter reports that there was an exception on line 7 of sample.py and prints the Exception.
Actual Behavior
The interpreter reports the following:
Traceback (most recent call last):
File "sample.py", line 7, in <module>
"""
Exception: ('foo', 'bar')
Here, the interpreter also reports """ when it reports the exception.
It seems to be looking in the file on disk to find this information, rather than the file loaded into memory to run the program.
Source of my Confusion
The following is my mental model for what happens when I run python3 sample.py:
The interpreter loads the contents of sample.py into memory
The interpreter performs lexical analysis, semantic analysis, code generation, etc. to produce machine code
The generated code is sent to the CPU and executed
If an error is raised, the interpreter consults the in-memory representation of the source code to produce an error message
Clearly, there is a flaw in my mental model.
What I want to know:
Why does the Python interpreter consult the file on disk to generate error message, rather than looking in memory?
Is there some other flaw in my understanding of what the interpreter is doing?
As per the answer linked by #b_c,
Python doesn't keep track of what source code corresponds to any compiled bytecode. It might not even read that source code until it needs to print a traceback.
[...]
When Python needs to print a traceback, that's when it tries to find source code corresponding to all the stack frames involved. The file name and line number you see in the stack trace are all Python has to go on
[...]
The default sys.excepthook goes through the native call PyErr_Display, which eventually winds up using _Py_DisplaySourceLine to display individual source lines. _Py_DisplaySourceLine unconditionally tries to find the file in the current working directory (for some reason - misguided optimization?), then calls _Py_FindSourceFile to search sys.path for a file matching that name if the working directory didn't have it.

How to redirect Python Syntax Error into a textbox in MFC or other GUI framwork?

I embed Python into my GUI application, when the script throws syntax errors, I want to redirect the error message into a textbox, so I can know where the error is.
My codes is very simple:
Py_Initialize()
PyRun_SimpleString( "execfile('my.py')" );
Py_Finalize();
If the file contains syntax error, it may looks like:
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "my.py", line 3, in <module>
app=everedit.Ap
AttributeError: 'module' object has no attribute 'Ap'
The above messages can be seen in a console window, but now I want to cache these messages in a GUI window.
A GUI window don't have a console. I want to output such messages into a text box.
Please note that I embed Python into C++, I want to cache Python's Syntax Error in C++.
As the documentation for PyRun_SimpleString clearly says:
Returns 0 on success or -1 if an exception was raised. If there was an error, there is no way to get the exception information.
So, if you want to get the exception information, you have to use slightly lower-level functions.
Meanwhile, once you're using the right function, and it returns NULL or -1 to tell you an exception occurred, how do you get the exception information (and distinguish SyntaxError from other exceptions, for whatever reason you want to do that)?
There's a whole chapter in the C-API docs on Exception Handling. But briefly: You call PyErr_Occurred to get the type of the exception. Then you call PyErr_ExceptionMatches to check whether it's the type you want. If so, use PyErr_Fetch to get the value and traceback so you can format them yourself, or PyErr_Format to get a simple formatted string, or whatever else you want. Then you just extract the Unicode or ASCII bytes from the string and put them in your GUI window.
Use a try/catch block and the traceback module (docs).
import traceback
try:
PyParser_SimpleParseString(input())
except SyntaxError as e:
# There will always be one line, but we're better off still looping over the list
# To be extra safe!
for line in traceback.format_exception_only(e.__class__, str(e)):
print(line) # Replace this with what write to the GUI
This will only give you the SyntaxError: x part, if you also want the traceback, use traceback.format_exception.

How to use the navigation-policy-decision-requested signal in Python Webkit

How can I use the navigation-policy-decision-requested (or equivalent) in association with webkit_web_policy_decision_ignore()?
The following is a small outtake form my code (the rest is just a wrapper and settings etc):
def check(view, frame, req, nav, policy):
webkit_web_policy_decision_ignore(TRUE)
...
view.connect("navigation-policy-decision-requested", check)
When I load a new page this error is returned:
Traceback (most recent call last):
File "browser.py", line 17, in check_exec
webkit_web_policy_decision_ignore(TRUE)
NameError: global name 'webkit_web_policy_decision_ignore' is not defined
What I'm trying to achieve is that if a certain address have been given, actions will be taken to prevent it from loading via Python. Any suggestions are welcome in the comments and any additional information you may need will be provided upon request.
Now I'm new to Python so please be specific in your answer, criticism and suggestions.
If you are using pygtk, try policy.ignore().
The object names are mapped slightly differently in pygtk. In python shell you can try after executing from gi.repository import WebKit
print dir(WebKit)
to find corresponding object and in your case
help(WebKit.WebPolicyDecision)

Python equivalent of PyErr_Print()

What is the Python API equivalent of PyErr_Print(), from the C interface?
I'm assuming a call in either the sys, or traceback modules, but can't find any functions therein that make calls to PyErr_Print().
Addendum
I'm after the Python call to get the same functionality as PyErr_PrintEx(), described as:
Print a standard traceback to sys.stderr and clear the error indicator.
That is I want to make the Python call that has this effect.
There's no Python function that's exactly equivalent to PyErr_PrintEx (the real name of PyErr_Print;-), including for example setting sys.last_traceback and friends (which are only supposed to be set to help a post-mortem debugging from the interactive interpreter for exceptions which have not been caught). What exact combination of functionality are you looking for?

Categories