Reputation: 127
When I want to throw a warning or exception in Python 3, such as in the following code:
import warnings
def main():
warnings.warn('This is a warning.')
raise RuntimeError('This is an exception.')
if __name__=='__main__':
main()
The terminal tells me in which line the warning or exception was raised:
test_exception.py:4: UserWarning: This is a warning.
warnings.warn('This is a warning.')
Traceback (most recent call last):
File "test_exception.py", line 8, in <module>
main()
File "test_exception.py", line 5, in main
raise RuntimeError('This is an exception.')
RuntimeError: This is an exception.
It's nice to know the location, but line 2 and 7 are redundant. Since the contents will be displayed in line 1 and 8. How can I avoid printing the lines that throw an exception or warning? I notice that some packages like Pytorch throw warnings and exceptions elegantly, in exact the way I wish. For example, Pytorch raises exception in the following style:
import torch
import numpy as np
a = torch.from_numpy(np.random.rand(2, 3))
b = torch.from_numpy(np.random.rand(3, 4))
a = a.to('cpu')
b = b.to('cuda:0')
c = torch.mm(a, b)
Traceback (most recent call last):
File "test_torch_exception.py", line 7, in <module>
c = torch.mm(a, b)
RuntimeError: Expected object of device type cuda but got device type cpu for argument #1 'self' in call to _th_mm
Upvotes: 1
Views: 2019
Reputation: 149115
The reference manual is a great source. For the warnings
module, it says:
The printing of warning messages is done by calling
showwarning()
, which may be overridden
And later:
warnings.showwarning(message, category, filename, lineno, file=None, line=None)
... You may replace this function with any callable by assigning to
warnings.showwarning
.
So just declare your own function special_showwarning
with the same parameters, format the output the way you want and simply do: logging.showwarning = special_showwarning
.
An equivalent way is possible for exception by overriding sys.excepthook
:
sys.excepthook(type, value, traceback)
This function prints out a given traceback and exception to sys.stderr.
When an exception is raised and uncaught, the interpreter calls sys.excepthook with three arguments... The handling of such top-level exceptions can be customized by assigning another three-argument function to sys.excepthook.
Unfortunately, this may not work when executing python code in an IDE, for example IDLE uses a custom loop and does not call sys.excepthook
. In that case, you could simply wrap your current main in a try block and catch anything. It is then easy to display what you want:
def main():
# your code ...
if __name__ == '__main__':
try:
main()
except:
type, value, traceback = sys.exc_info()
# add your error formatting here
Upvotes: 3
Reputation: 29725
If you change your source code slightly to a real life situation it becomes maybe clearer why the behavior is like this:
import warnings
warn = 'This is a warning'
exception = 'This is an exception'
def main():
warnings.warn(warn)
raise RuntimeError(exception)
if __name__=='__main__':
main()
Now the output is:
test_exception.py:6: UserWarning: This is a warning
warnings.warn(warn)
Traceback (most recent call last):
File "C:\Users\11ldornbusch\Desktop\2del.py", line 10, in <module>
main()
File "C:\Users\11ldornbusch\Desktop\2del.py", line 7, in main
raise RuntimeError(exception)
RuntimeError: This is an exception
So if you use variables your output shows in one line the content of the variable, and in the other the name. This can give you more context on what the problem is, for example a "Nothing" as output will gives you also the name of the variable which is nothing.
You can also use logging or Hook the output in python to modify the output of the warning: From the documentation available here: https://docs.python.org/3/library/warnings.html
The printing of warning messages is done by calling showwarning(), which may be overridden; the default implementation of this function formats the message by calling formatwarning(), which is also available for use by custom implementations.
Upvotes: 1