Exception Handling
Don't try to do it in code (like with if statements), it's awkward, slow, programmer's don't like doing it. But is should be done, exceptions could leave resource in an 'inaccessible state'.
What happens if your script tries to open a file, but it crashes? Your file has been opened to a script that doesn't exist anymore, and it's possible your file cannot be accessed. It becomes a 'zombie' file. Depending on how bad the crash is, you might have to restart your entire computer in order to open the file.
Example: say you want the user to enter in a value for scale and then create the object.
But what if you only wanted the scale to be less than 5? You can raise an error for the user
We came up with this special situation, and then gave an error message to the user (a pop up box). Basic format for handling exceptions:
try:
code
except ExceptionClass:
code
except:
code
else:
code
finally:
code
It's either going to: perform the operations in try. If it catches an exception, it will either go specifically to the code bloc where you specified the Exception Class, or go straight to the unspecificed except code bloc. The else statement runs when it does not find any exception. Finally runs no matter what, this statement wille xecute regardless of 'try'. This is an ideal location for resource De-Allocation. Try is not optional, everything else is optional.
Can have only one empty 'except' at the end before 'else' statement.
Try puts it in a special state where python is geared up to know it might get an exception types (errors).
Here we're asking for user input again. We use a try statement here (because usually user error is where it's going to break). We want to catch when the user enters zero, because we have a statement that has 360 divided by the user input, and we cannot divide by 0. So when we come accross this, we can use the ZeroDivisionError to tell the user you cannot put in 0. We can also put in a ValueError for when users enter things like strings. The final one, the 'Exception' is just a catch all for errors.
This will run after you've run the try code, and everything runs smoothly.
Exception Classes
There is an exception class that you can use to make child classes to create new errors to catch. (You can see more here) Here we want to create an error that catches when we input a negative integer. It's a child of the value Error, because it is the most similar to that parent class. We don't actually need to put anything in the class for this one.
You can test if the number is less than 0, and then raise a SubZeroPigs class. Then in your exceptions:
This will create a squab instead of pigs if you get a negative user inputted number. Note it needs to be before ValueError, because it is a child class of Value Error, and if you raise it it can also trigger the ValueError exception.
There is a way of using a library called traceback and print out the actual data that caused the error in your code, as well as all the steps that led up to it. We've been dealing with this before in Houdini when we get errors in our code.
File Processing
Four fundamental operations:
1. Open a file
2. Read file contents to a string OR
3. Write a string to a file
4. Close the file
Here's the syntax for opening and closing a file. I give the exact file path but had to put an 'r' infront of the path string to let python know it's a raw string (Don't use \ as an escape character)
Now since we're going to be dealing with user error when they input a wrong file, we can use 'try' to check for errors.
For open() there are different types of 'open modes'.
- r : opens a file for reading, raises IOError if file doe not exist
- w : opens a file for writing. truncates if file exists. creates if does not exist (WILL NOT THROW AN ERROR)
- a : appends to the end of the file. creates if does not exist
- r+ : opens file for reading or writing. raises IOError if file does not exist (be careful for this, because if you change the file, whatever you read is not what's in the file currently)
- w+ : opens for reading or writing. truncates if file exists. creates if does not exists
We can take the contents of the file and give it to a variable.
inFile.read() will take the entirety of the file, and put it as a string. We then give this to a variable named filecontents. When we run this we get this: Trying the write open mode
If you wanted to try to create a file, use the write open mode ('w').
Here we're creating a file named crag.py and opening it for write. Then we're going to assign the rocky variable the houdini node crag test geometry that's already in our scene. Next we're going to write:
This writes out the content of any houdini node object entirely as a python script. Then we just close the file, along with testing for any exceptions.  |
We shouldn't necessarily need it since usually the write open mode doesn't usually throw an error, unless you're trying to write a place you don't have permission to.
|
Responsible Close
You must guarantee any file access will not abandon an 'open' resource!. Use 'finally' to guarantee resource closure.
myFilePointer = open(myFile, mode)
try:
performOperations(myFIlePointer)
finally:
myFilePointer.close()
Even when the computer is about to crash, the finally node will always run before it crashes.
Context Managers
Allow groups of statements to be run under control of single objects
with contextManager.Expression as targetVariable:
doSomething(targetVariable)
Python gives us nice context managers for 'open', instead of try-finally
with open(fileName, mode='r') as fileVariable:
inputString = fileVariable.read()
with open(fileName, mode'w') as fileVariable:
fileVariable.write(outputString)
It handles all the exceptions and trys for you within the Context Manager. It handles the close and everything. Here's an example of how to use it to write out the contents of Roberto into a python file:
And then we can continue this, destroying the rubbertoy and then reading back the contents of the file. This method only raises the exception, it does not catch it (meaning it would not print out whatever data it has at the moment of crash).
JSON
A Json file is like an infinitely recursive python dictionary. It is a dictionary where the 'value' can be a list of directionaries.
Example of using Json files with python
First we get the json file and read it. It starts off as a string, and then using 'json.loads' we convert it to a python dictionary. Then we can manipulate the data (maybe append a new key+value), we use json.dumps
What this does is it converts a dictionary to a bigass string. But dictionaries don't know what new lines or formatting is; so you have to tell it to format a certain way. The indent = 4 with the separators = , ; means whenever you encounter a comma or colon, stick in an indent with 4 spaces. Now you can write this string out as a new json file. XML
An XML file has a parent element, and then the parent has child elements, and then those child elements have further child elements underneath it. It has a branching tree structure. HTML is an XML format.
Every Element requires an opening tag and a closing tag.
You can use ElementTree module to parse through an XML file.
Difference between JSON and XML:
If your data is inherently recursive, use XML (if you're rigging and you want to output all of your bones, use XML to recursive walk through the bone hierarchy).
JSON seems to look better formatted when printed out.