Error Handling
What is Error Handling
The concept of error handling is recognizing when an error might occur in a block of code, and instead of throwing the error, handling it gracefully. This can involve giving the user a more distinct error message, letting the user know that their attempt to run the code failed, or even undoing something that your code set it motion so that it can be started again from the same starting point.
Error Handling in Python
Within Python, we can use the try and except blocks to handle errors. We would first use try: and write the code we would like to try indented underneath it. We then must have an except: with code that will run if there is an error.
# With try, we can attempt any amount of code
try:
some code
more code
even more code
# If any of lines in the try block were to throw an error, then we move down and run the block under except.
# The except statement is NOT optional: you must define what your code should do in the event an exception occurs.
except:
failover code
When running the code above, there is a specific order to the way it executes.
- The try block is run, and the code within is executed line by line. a. If an error occurs, the code in the try block will immediately stop and the except block will begin to execute. b. If no error occurs after all code in the try block has been executed, the try block will be finished and the code in the except block will be skipped.
- After either outcome, any code after the except will then execute.
Because of the way the try and except blocks work, it is very useful on situations that require user input, where something may have been incorrectly entered which would usually result in an error.
The Pass Keyword
The pass keyword is unique in that it does nothing except to fill in a spot where code is required. This is useful if we want to handle the exception so that it doesn't throw an error message, but we don't actually want to do anything with it. In this case, we can use pass to tell the script to continue.
try:
some code
more code
even more code
except:
# The error will bring the code to the exception, and then the exception will simply do nothing.
pass
Error Handling Example
An easy way to demonstrate how error handling works is with a division example, since it is easy to cause an error by dividing by 0. Take the code below:
When we run it, we get a printed value of 50. There was no error in the division, and the try block finished successfully. However, if we were to change the value of x to 0, we can see that "An error occurred!" is printed.
# We start with a value, which could represent some user input.
x = 2
# We use that value in our try block, and have a simple print statement if there is an error.
try:
value = 100/x
print value
except:
print "An error occurred!"
Exception-Specific Failover
While each try block must be followed by at least one except block, there can be multiple except blocks to handle different types of errors. This is done by listing the error object after the except keyword and before the colon. Looking back at the example above, I know that my most common error is going to be a divide by zero error. So I can make an exception that is specific to divide by zero errors.
# We start with a value, which could represent some user input.
x = 0
# Use the user input in division in our try block.
try:
value = 100/x
print value
# If the exception that would occur is of type ZeroDivisionError, we can run a specific block of code
except ZeroDivisionError:
print "Dividing by zero is not allowed. Please stop trying to divide by zero"
# We can then have a second exception without a specific error. This except acts as a catch-all;
# if the user caused an exception we didn't account for above, we can failover to the block of code below.
except:
print "An error occurred!"
The except blocks in the code above cover all possible errors as represented in the table below. Now, we have a more tailored approach to how we handle errors while still catching all of them that may occur.
Inputs (x value) | Output |
---|---|
2 | 50 |
0 | Dividing by zero is not allowed. Please stop trying to divide by zero |
'a' | An error occurred! |
Each try block can have many except blocks, and each except block can also name multiple types of errors as shown below. However, an error that happens within a try block will only ever trigger a single except block.
try:
some code
except (ZeroDivisionError, RuntimeError, TypeError):
failover code
Determining the Error Object
To determine the name of the error object that will be thrown from certain errors, we can take a look at the error to figure that out. We already mentioned that dividing by zero gives a ZeroDivisionError, but what about when we divide by a string? If I divide 100 by the letter a without error handling, this is the error I get:
Traceback (most recent call last):File "buffer", line 3, in module
TypeError: unsupported operand type(s) for /: 'int' and 'str'
The last line of that error gives the name of the error object "TypeError" followed by the cause of that error. This makes sense, because the string 'a' is the wrong type to be using in division. However, not all errors are so simple and may require a bit more to find the name of the error. For a list of python error names check out this page in the python docs: https://docs.python.org/2.7/library/exceptions.html#Exception
Additionally, some exceptions may be returned by Java. In these cases, Oracle's documentation on the Exception class is more useful: https://docs.oracle.com/javase/8/docs/api/java/lang/Exception.html A list of common exceptions are listed below.
Exception | Description | Exception Demonstration |
---|---|---|
ArrayIndexOutOfBoundsException | This typically occurs when a line of code attempts to access an index in a collection, but the index specified doesn't exist. This exception is unique to datasets in Ignition. Lists, and other built-in Python objects will return the IndexError below. |
|
AttributeError | Typically seen when a script tries to access a property that doesn't exist. Example: a script tries to get the value of a property on a component, but the property name is misspelled. |
|
IndexError | Similar to ArrayIndexOutOfBoundsException above, but occurs when Python specific object, such as a list. |
|
NameError | Occurs when the local or global name is not found. Typically happens when referencing a variable that hasn't been assigned a value. |
|
TypeError | A TypeError occurs when a function or similar operation is applied to another object of an incorrect type. |
|
ValueError | A ValueError is returned when the value of an argument is inappropriate. Typically the exact issue is returned in the returned exception. |
|