In a python program I am making, I want it to only take integers, and if it gets a string say "There has been an error in the system." instead of murmering sensless information the user will not understand
Use a try-except block to capture the error and use the raise statement to say the error message of your choice:
try:
a = int(input())
except:
raise Exception('There has been an error in the system')
Using try, except and raise
Since ValueError inherits from the Exception class, the first parameter when creating a ValueError object is the message it prints:
try:
int("string") #the code that raises the error
except ValueError:
raise ValueError("Your custom message here.")
This prints:
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
ValueError: invalid literal for int() with base 10: 'string'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "<stdin>", line 4, in <module>
ValueError: Your custom message here.
If you don't want the previous error chain to print, put from None in the raise statement:
try:
int("string") #the code that raises the error
except ValueError:
raise ValueError("Your custom message here.") from None
This prints:
Traceback (most recent call last):
File "<stdin>", line 4, in <module>
ValueError: Your custom message here.
I suggest you leave the chain because it gives more information, like what was inputted that raised the error. If you want to include the information from the original error in the custom message, use the error's attributes:
from traceback import format_tb
try:
int("string") #the code that raises the error
except ValueError as err:
raise ValueError("Custom message with traceback and original message\n" + format_tb(err.__traceback__)[0] + err.args[0] + "\nEnd of error message.") from None
This prints
Traceback (most recent call last):
File "<stdin>", line 4, in <module>
ValueError: Custom message with traceback and message
File "<stdin>", line 2, in <module>
invalid literal for int() with base 10: 'string'
End of error message.
Though this allows for customization of the error's print, the code is a little unpythonic.
Using assert
Because in the question you said you wanted to block all strings, you can use assert and isinstance():
obj = "a string" #the input you want to raise the error on
assert not isinstance(obj, str), "Your custom message here."
This prints:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AssertionError: Your custom message here.
Though using assert looks clean, the error won't carry as much information because it would be a generic AssertionError. Raising a ValueError tells more information about what caused the error at a glance.
You need to use a try except block to catch the error - see the documentation. Then you could just print a message, and, if necessary, exit the program:
try:
value = int(input("Enter an integer: "))
except ValueError:
print("There has been an error in the system.")
input() # To let the user see the error message
# if you want to then exit the program
import sys
sys.exit(1)
If you want to make an error, you use raise. Here is an example:
raise SyntaxError('MUHAHA THIS IS A ERROR')
If you do not want to add another indentation level by using a try-except block, you can change the handling of all errors by adding the following to the beginning of your code:
import sys
def my_except_hook(exctype, value, traceback):
print('There has been an error in the system')
sys.excepthook = my_except_hook
In case of an error, only your specified error message is printed out. In addition, this prevents the stack trace from being displayed.
Use raise Exception('There has been an error in the system') may be useful for most cases but you may also need create meaningful errors for specific systems.
Eg.
class ExpiredTaxIdException(Exception):
def __init__(self):
Exception.__init__(self, 'Tax ID expired')
Then you can call it on your code, sample:
from your_execeptions_file import ExpiredTaxIdException
class ClientsController:
def is_profile_valid(client):
if client.tax_id.is_valid == False:
raise ExpiredTaxIdException()
return True
# eg. you call it on your API on another place of your code that can't accept invalid tax_id
try:
ClientsController().verify_client(client)
except ExpiredTaxIdException as e:
return {'error': str(e)}
>>> { "error": "Tax ID expired" }
You can try this..
import ctypes
ctypes.windll.user32.MessageBoxW(None, u"CUSTOM MESSAGE", u"TITLE BAR", 0)
Related
I have this line of Python code:
raise ValueError(f"Invalid input '{number}'")
When it raises an exception I get:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/snowcrash/Code/Python/mycode/mycode.py", line 8, in __init__
raise ValueError(f"Invalid input '{number}'")
ValueError: Invalid input 'a1b2c3'
however I'd prefer to get:
File "/home/snowcrash/Code/Python/mycode/mycode.py", line 8, in __init__
ValueError: Invalid input 'a1b2c3'
How do I achieve this?
sys.excepthook(type, value, traceback) is the function that does the printing when an exception is raised. You can write your own function (with a similar signature) and simply replace it with:
sys.excepthook = myfunction
You can do whatever you want in this function. You may log to files, or print some information about the state of the program when the exception occurred, for example. You may even arrange for different things to happen depending on the type of exception.
However if all you want to do is format your traceback message, lots of convenient stuff is already provided for you. You can dig into the traceback docs for the details, but here is an example that produces roughly the output you want:
import sys, traceback
def myhook(type, value, tb):
trace = traceback.format_tb(tb, limit=1)
trace = trace[0].split("\n")[0]
exc = traceback.format_exception_only(type, value)[0]
print(trace + "\n" + exc)
sys.excepthook = myhook
number = "a1b2c3"
raise ValueError(f"Invalid input {number}")
which produces an output of:
File "scratch/so.py", line 14, in <module>
ValueError: Invalid input a1b2c3
Note especially the use of traceback.format_tb with limit=1, to limit the stack trace output. There are a bunch of these functions in the traceback module.
Put simply, I have a piece of code that looks like this:
if some_condition_that_evals_to_True:
raise ValueError("Error message")
What I want to do is to insert a logging statement that logs this entire exception but doing it just this way only saves the logger message:
if some_condition_that_evals_to_True:
logger.error("Logged error message")
raise ValueError("Error message")
Any one know how to save the entire error message including the ValueError?
EDIT:
The following is what I am trying to recreate:
if some_condition_that_evals_to_True:
try:
raise ValueError("Error with value")
except ValueError:
logger.exception("Logging Error with Value")
raise
But this seems like a roundabout way to get the behavior I want, so another way to phrase my question: Is there a more elegant way get the same behavior as the above codeblock?
Try the stack_info keyword argument when using the logging module:
import logging
logging.basicConfig(filename='example.log',level=logging.DEBUG)
if True:
logging.error('Error Message', stack_info=True)
raise ValueError('Custom Error Message')
Running this shows the following:
J:\>python log_stack.py
Traceback (most recent call last):
File "log_stack.py", line 5, in <module>
raise ValueError('Custom Error Message')
ValueError: Custom Error Message
J:\>more example.log
ERROR:root:Error Message
Stack (most recent call last):
File "log_stack.py", line 4, in <module>
logging.error('Error Message', stack_info=True)
I'm learning to use python. I just came across this article:
http://nedbatchelder.com/blog/200711/rethrowing_exceptions_in_python.html
It describes rethrowing exceptions in python, like this:
try:
do_something_dangerous()
except:
do_something_to_apologize()
raise
Since you re-throw the exception, there should be an "outer catch-except" statement. But now, I was thinking, what if the do_something_to_apologize() inside the except throws an error. Which one will be caught in the outer "catch-except"? The one you rethrow or the one thrown by do_something_to_apologize() ?
Or will the exception with the highest priotiry be caught first?
Try it and see:
def failure():
raise ValueError, "Real error"
def apologize():
raise TypeError, "Apology error"
try:
failure()
except ValueError:
apologize()
raise
The result:
Traceback (most recent call last):
File "<pyshell#14>", line 10, in <module>
apologize()
File "<pyshell#14>", line 5, in apologize
raise TypeError, "Apology error"
TypeError: Apology error
The reason: the "real" error from the original function was already caught by the except. apologize raises a new error before the raise is reached. Therefore, the raise in the except clause is never executed, and only the apology's error propagates upward. If apologize raises an error, Python has no way of knowing that you were going to raise a different exception after apologize.
Note that in Python 3, the traceback will mention both exceptions, with a message explaining how the second one arose:
Traceback (most recent call last):
File "./prog.py", line 9, in <module>
File "./prog.py", line 2, in failure
ValueError: Real error
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "./prog.py", line 11, in <module>
File "./prog.py", line 5, in apologize
TypeError: Apology error
However, the second exception (the "apology" exception) is still the only one that propagates outward and can be caught by a higher-level except clause. The original exception is mentioned in the traceback but is subsumed in the later one and can no longer be caught.
The exception thrown by do_something_to_apologize() will be caught. The line containing raise will never run, because of the exception thrown by do_something_to_apologize. Also, I don't believe there is any idea of "priority" in python exceptions.
I believe a better idea is to use
raise NewException("Explain why") from CatchedException
pattern. In particular, considering Python 3 and the example given by #BrenBarn I use following
def failure():
raise ValueError("Real error")
try:
failure()
except ValueError as ex:
raise TypeError("Apology error") from ex
which yields
--------- ValueError----
Traceback (most recent call last)
4 try:
----> 5 failure()
6 except ValueError as ex:
1 def failure():
----> 2 raise ValueError("Real error")
3
ValueError: Real error
The above exception was the direct cause of the following exception:
-----TypeError-----
Traceback (most recent call last)
5 failure()
6 except ValueError as ex:
----> 7 raise TypeError("Apology error") from ex
TypeError: Apology error
I use ereporter in my GAE app to be informed about all uncaught exceptions thru email. But I also would like to be informed other (handled) issues, so, I use the following code:
if something:
pass
else:
logging.exception('something is wrong')
But ereporter fails with such cases with AttributeError:
Traceback (most recent call last):
File "/base/data/home/runtimes/python27/python27_lib/versions/1/google/appengine/ext/ereporter/ereporter.py", line 227, in emit
signature = self.__GetSignature(record.exc_info)
File "/base/data/home/runtimes/python27/python27_lib/versions/1/google/appengine/ext/ereporter/ereporter.py", line 175, in __GetSignature
fulltype = '%s.%s' % (ex_type.__module__, ex_type.__name__)
AttributeError: 'NoneType' object has no attribute '__module__'
I understand why it happens - there is no real Exception. But is there any way still to log such cases with ereporter?
As you said yourself - there's no exception to report. Since ereporter seems to only report exceptions, the solution is clear:
if something:
pass
else:
try:
raise Exception()
except Exception:
logging.exception('something is wrong')
Consider this try/except block I use for checking error message stored in e.
Try/Catch to get the e
queryString = "SELECT * FROM benchmark WHERE NOC = 2"
try:
res = db.query(queryString)
except SQLiteError, e:
# `e` has the error info
print `e`
The e object here contains nothing more than the above string. When python reports an unhandled error, however, it shows a pretty detailed info as below:
Traceback (most recent call last):
File "fool.py", line 1, in
open("abc.zyz", "r")
IOError: [Errno 2] No such file or directory: 'abc.zyz'
My question is, how can I get the information such as above (the file and the line number etc.)? Or, if e contains this info, how is it stored inside it?
This will show the trace to the error.
import traceback
try:
res = db.query(queryString)
except SQLiteError, e:
# `e` has the error info
print `e`
for tb in traceback.format_tb(sys.exc_info()[2]):
print tb
Like the first 2 answers, use traceback. Here is a more complete example.
import traceback
def foo():
raise RuntimeError('we have a problem')
try:
foo()
except:
traceback.print_exc()
When you run it, you'll see
Traceback (most recent call last):
File "C:\0\tmp\x.py", line 6, in <module>
foo()
File "C:\0\tmp\x.py", line 3, in foo
raise RuntimeError('we have a problem')
RuntimeError: we have a problem
See the traceback library.
If you want to just pass errors up the chain instead of modifying them, you can just use raise within an except block, which will then act like the except block isn't there (aside from any conditional logic/side effects you may have done before the raise).