On this page |
General tips
-
If you need to check whether some code ran, the easiest way is to call hou.ui.displayMessage():
import hou hou.ui.displayMessage("I ran! I ran so far away!")
You can also use this to display the values of variables. For example, to see what’s in the
kwargs
global variable in an event handler:import hou hou.ui.displayMessage(repr(kwargs))
-
You can share code between handlers by putting it in a module on disk and calling it from the handler script. For example, the handler script might just pass the
kwargs
to a common function:import companyutils companyutils.on_created(kwargs)
-
Houdini has a very large, powerful (but verbose) set of APIs. Browsing through what’s available in the API reference will help you discover what’s possible with scripting.
-
In general, Houdini looks for "scripts" (usually callback scripts) on disk under
HOUDINIPATH/scripts/
, while modules you would import are underHOUDINIPATH/python2.7libs/
. Unfortunately, this is not consistent, so for example Houdini looks for thepythonrc.py
initialization script inpython2.7libs
.
Startup scripts
Houdini will look for these directories/files in the directories specified on the $HOUDINI_PATH
.
|
Houdini will find any files matching this pattern in the Houdini path and run them at startup. For example, |
|
Houdini runs this script when it is started without a scene ( This is the Python equivalent of the Note Only Houdini FX runs |
|
Houdini runs this script whenever a scene file is loaded (including when Houdini starts up with a scene file). This is the Python equivalent of the |
|
See node event scripts below. |
Note
You need to restart Houdini to have it recognize new scripts. However, you can change existing scripts without needing to restart Houdini.
Run scripts before and/or after saving the scene (.hip) file
Houdini lets you run scripts before and/or after a save. This can be useful to update asset management and source control tools whenever a save occurs.
-
Before Houdini saves the scene file, it will run
HOUDINIPATH/scripts/beforescenesave.py
if it exists. -
After Houdini attempts to save the scene file, it will run
HOUDINIPATH/scripts/afterscenesave.py
if it exists.
Tip
These scripts are useful because they're automatically global (they run for any scene file you work on), and they're easy to set up. On the other hand, they're difficult to set up programmatically, and they only relate to saving.
The more general/fine-grained way to react to scene file events is to set up a scene file event handler.
The scripts run in a context containing a global dictionary named kwargs
. This dictionary contains the following items:
file
(str
)
The path to the scene file will be saved to. (In beforescenesave.py
, a file may or may not already exist there).
autosave
(bool
)
Contains True
if this save was triggered by the autosave timer. If this is False
, this is a "regular" save caused by the user.
success
(bool
)
(afterscenesave.py
only) Contains True
if Houdini was able to save to the file.
Note
Houdini might not actually be able to save the file at the given path (for example, if the user doesn’t have the proper permissions), so the file still may not exist when afterscenesave.py
runs, or may not contain updated data. You should check kwargs["success"]
in the script before you assume the file contains the saved data.
The following example automatically "stages" the file for commit in git
when it’s saved:
# afterscenesave.py import subprocess # Only run the command if the save succeeded and it's # not an autosave if kwargs["success"] and not kwargs["autosave"]: # Pass the scene file path to the git command subprocess.call("git", "add", kwargs["file"])
Scene file event callbacks
You can register a callback function that Houdini will call whenever a the scene file changes. Houdini calls the function with one argument. The argument is a hou.hipFileEventType object representing the type of event that occurred.
Instead of subscribing to a specific event, the script will be called for every event, and you need to check the event type to see if it’s an event you're interested in. This is usually more convenient for scene events, since you will often share code between reactions to several events.
In the script, you can use the functions in the hou.hipFile module to get information about the current scene file. Each file operation (New file, Open file, Import file, Save) has corresponding "Before" and "After" event types, so you can read the scene file’s values before and/or after the change.
For example, to run some code every time a new scene file is loaded:
def scene_was_loaded(event_type): if event_type == hou.hipFileEventType.AfterLoad: print("The user loaded", hou.hipFile.path())
Parameter expressions
Session module
Houdini keeps a Python module associated with the scene file. You can edit it using Window ▸ Python source editor. When the scene file is loaded (or when you edit the source code), the module source code is evaluated and the module is available to other Python code as hou.session
. This gives you a convenient place to store functions, classes, and objects specific to the scene file, and automatically have them saved and loaded with the scene file.
You can programmatically modify the hou.session
source code using the hou.appendSessionModuleSource() function.
Tip
If you directly modify hou.session
in Python, for example hou.session.x = "foo"
, the changes are not saved with the scene file. You must edit the module source code to have the changes saved with the file.
Asset modules
Each digital asset type has a Python module, similar to the scene file’s hou.session
module. You can use this module to store functions, classes, and objects specific to the asset type.
The module source code is stored in a section of the asset named PythonModule
(on the Extra files tab of the type properties window). You can create this section manually. Houdini will create it automatically if you create a "Python Module" event handler on the Scripts tab.
You can access the module using the hou.NodeType.hdaModule() method (if you have a NodeType
object) or the hou.Node.hdaModule() method (if you nave a Node
object). For example, to call a myfunc
function on the myasset
object type:
hou.nodeType(hou.objNodeTypeCategory(), "myasset").hdaModule().myfunc()
Python expressions on nodes inside the asset definition can access the PythonModule
through relative references. For example, a Python parameter expression on a node in the asset’s definition subnetwork could use hou.node("..").hdaModule().foo()
.
If you have so much Python code inside an asset that you want to organize it into multiple modules, you can create other HDA sections to store those modules. For example, you could create a FooModule
section containing Python code. Then in the main PythonModule
section, use the following code to import the contents of FooModule
as foo
:
import toolutils foo = toolutils.createModuleFromSection('bar', kwargs['type'], 'FooModule')
Modules on disk
Houdini automatically adds any $HOUDINI_PATH/pythonX.Xlibs
directories to the Python path, meaning packages and modules inside those directories can be imported in Python code. For example, the module $HOUDINI_USER_PREF_DIR/python2.7libs/mystuff.py
can be imported in Python code using import mystuff
.
To make packages and modules in other locations available to python, use the $PYTHONPATH
environment variable, or modify the sys.path
list in Python.
Digital asset event handlers
You can write Digital asset event handlers in Python. After you create an event handler on the Scripts page of the type properties window (for example "On Created"), set Edit as to "Python".
The event script can access the event parameters in a global dictionary variable called kwargs
. For example, to get the hou.Node object involved in the event, use kwargs["node"]
.
See how to reference embedded files for information on how to refer to the embedded scripts wherever Houdini expects a filename.
Tip
These handlers let you set up scripts that run when an event happens for a specific node type. You can also set up general asset event handlers which run when any asset or asset library is loaded or unloaded.
Event types
The following events can trigger scripts:
Before First Create ( |
Runs when the first instance of a node type is created in a scene. This includes when Houdini is creating nodes as it loads a scene file from disk. For example, if a scene has no geometry objects, when you add one, this would trigger the This can be useful for setting up an environment necessary for one or more instances of the asset to work. For example, copying texture maps to required locations, or setting environment variables.
|
On Created ( |
Runs after the user creates a new instance of a node type (not when a scene file loads, see You can use this, for example, to make changes to a node that Houdini will automatically save (for example, add spare parameters). |
On Loaded ( |
Runs after an instance of a node type is created as Houdini loads a scene file from disk (not when a user creates a node in the network editor, see This does not run when loading the node as part of the contents of another asset. If you need to do something when a node inside an asset loads, you must put that code in the asset’s load handler. This runs on each node after all nodes are loaded, so the script will see the complete scene. |
On Updated ( |
Runs for each instance of an asset when the asset updates because the shared definition changed. |
On Deleted ( |
Runs before an instance of a node type is deleted (while the node still exists). This includes when Houdini is "unloading" the node because the user is starting a new file, opening a file, or quitting.
|
After Last Delete ( |
Runs after the last instance of a node type is deleted in a scene. This includes when Houdini is "unloading" the node because the user is starting a new file, opening a file, or quitting. This can be useful to clean up changes made in a
|
On Input Changed ( |
Runs when an input on a node of this type is connected, disconnected, or switched. The script can use |
On Name Changed ( |
Runs after the user changes the name of a node of this type. The script can use This can be useful, for example, if you are somehow indexing nodes by their names or paths in some external storage, to keep the external index up-to-date. |
Sync Node Version ( |
This is part of the older versioning system, allowing you to write an "upgrade" handler that can automatically convert old versions of a node to the latest version. This system may be useful for small-scale, backwards-compatible changes such as adding new parameters. See the two types of asset versioning for more information. This runs when an asset instance loads and notices the asset’s Version field has changed since the scene file was saved. It runs after a node’s parameters are loaded and resolved, but before the The script can get the old and new version strings in The handler then does the work of changing the node (using the reference in (You can trigger a node’s upgrade script manually using hou.Node.syncNodeVersionIfNeeded().) |
Script variables
The handler scripts run in an environment with a global kwargs
dictionary. The following table shows what items are available in the dictionary for the various event types:
Key |
Value |
Events |
---|---|---|
|
A hou.Node reference to the node instance |
|
|
A hou.NodeType reference to the node type |
|
|
A string containing the the old name of the HDA instance. |
|
|
The index of the input that was connected/disconnected. |
|
|
The current HDA version string. |
|
|
The HDA version string that the node was last saved with. |
|
Node event handler files
You can put event handler scripts in files in the Houdini path instead of/in addition to embedding them in assets. To respond to an event on a digital asset, you probably just want to use the built-in event handler support in the type properties window. However, using script files can have the following benefits:
-
These on-disk event scripts work for both assets and built-in node types.
-
You can install "global" event handler files that run for any node type.
Houdini looks for files matching the following patterns:
-
Files matching the pattern
HOUDINIPATH/scripts/category/nodename_event.py
(for example,$HOUDINI_USER_PREF_DIR/scripts/obj/geo_OnCreate.py
) will run when the given event type occurs to a node of the given type. -
Files matching the pattern
HOUDINIPATH/scripts/event.py
run when the given event type occurs to any node.
Note
The script path uses the "directory" form for node categories, not the "table" form. For example, obj
not Object
, sop
not Sop
, out
not Rop
. These different forms are an unfortunate historical inconsistency in Houdini.
An event script file will run in an environment with a built-in kwargs
global dictionary variable. To get the hou.Node object for the newly created node in the script, kwargs["node"]
. See script variables above for information on the items available in the dictionary.
Note
Houdini will also find files matching HOUDINIPATH/scripts/category/nodename.py
(no event suffix, for example $HOUDINI_USER_PREF_DIR/scripts/obj/geo.py
). This is a factory node’s "creation script", which is (confusingly) not the same as a node’s OnCreated
handler.
Old documentation or tutorials may refer to this type of a file as a way to run code when a node is created. However, this does not work with digital assets. You should now use an OnCreated event script instead. Consider the "creation script" an internal implementation detail subject to change without notice.
Individual node event handlers
You can set up event handlers on individual node instances. Unlike asset events, which trigger when the event happens for any instance of the asset, these handlers only run when an event happens to the specific node you set them up on.
See hou.Node.addEventCallback() for how to set up an event handler on a node. See hou.nodeEventType for the types of events you can react to.
General asset event handlers
You can set up handlers for changes to asset libraries. For example, when an asset is created or deleted, or an asset library is installed or uninstalled.
See hou.hda.addEventCallback() for how to set up an asset library event handler. See hou.hdaEventType for the types of events you can react to.
Shelf tool scripts
You write the script that runs when the user clicks a shelf tool in Python. See how to write a tool script for more information.
Parameter callback scripts
You can write Python scripts that are called whenever the value of a parameter on a node changes.
If the default callback language is HScript, remember to change it to Python.
The event script can access the event parameters in a global dictionary variable called kwargs
. For example, to get the hou.Node object containing the parameter, use kwargs["node"]
, and to get the hou.Parm object of the parameter, use kwargs["parm"]
.
Tip
The most convenient way to implement a callback script is to write one line of Python that calls the "real" callback function in your asset’s Python module and passes it the kwargs
dictionary.
For example, you can make a my_callback
function in the asset module that takes the dictionary of options and a hou.Node
object representing the current node instance. Then set the parameter’s Python Callback line to call the function from the module using the following:
hou.pwd().hm().my_callback(kwargs, hou.pwd())
(hou.pwd() returns the node which is currently cooking. hou.Node.hm() returns an asset’s Python module.)
The following table lists the contents of the kwargs
dictionary for parameter callbacks:
|
The hou.Parm object whose callback script was invoked. |
|
The hou.Node object containing the parameter. |
|
The name of the hou.Parm. This value is the same as |
|
The name of the hou.ParmTuple containing the parameter. This is the same as |
|
The value of the parameter. This entry is the same as |
|
The values of the parameter tuple. These entries are the same as |
|
The number of the multiparm, if the parameter is an instance of a multiparm (otherwise |
|
If this parameter is not an instance of a multiparm, this value is |
|
These values are only available if |
Parameter menu scripts
Scripting button/icon strip parameters
Key-value parameter button scripts
Background processes
You can set up Python code to execute "in the background" while the user is working.
-
You can use hou.ui.addEventLoopCallback() to set up a function that Houdini calls whenever the UI is not busy.
The callback function will be called very often (around 20 times a second). The function should be very fast to run so it doesn’t slow down the UI.
-
You can use a Qt
QTimer
object to schedule code to run in the future. That code can itself set up anotherQTimer
if you want some code to execute at a certain interval.
Tips
-
You can use hou.findFile() to search for filenames in the Houdini path.
-
To read content from an embedded file inside an asset, use hou.HDADefinition.sections() to get a dictionary of section names to
HDASection
objects, then use hou.HDASection.contents() to get the section contents.For example, to read the contents of an embedded file named
example
in themy_asset
object:objects = hou.nodeTypeCategories()["Object"] my_asset = objects.nodeTypes()["my_asset"] my_asset_def = my_asset.definition() section = my_asset_def.sections()["example"] contents = section.contents()
As a shortcut, you can use Houdini’s support for reading asset sections as if they were files using an
opdef:
path:content = hou.readFile("opdef:Object/my_asset?example")
-
To access Python variables in the global scope from
hou.session
, import__main__
. For example, ifx
is a variable in the global scope, you can access it as__main__.x
.You can use this approach to access Python global variables from parameter expressions, HDA Python modules, Python button callbacks, shelf scripts, and so on.
See also |