Tutorial 12 - Python ABI Override Node

Although the .ogn format creates an easy-to-use interface to the ABI of the OmniGraph node and the associated data model, there may be cases where you want to override the ABI to perform special processing.

OgnTutorialABIPy.ogn

The ogn file shows the implementation of a node named “omni.graph.tutorials.AbiPy”, in its first version, with a simple description.

 1{
 2    "AbiPy" : {
 3        "version": 1,
 4        "categories": ["tutorials", { "internal:abiPy": "Internal nodes that override the Python ABI functions" }],
 5        "language": "python",
 6        "description": ["This tutorial node shows how to override ABI methods on your Python node.",
 7                        "The algorithm of the node converts an RGB color into HSV components."],
 8        "metadata": {
 9            "uiName": "Tutorial Python Node: ABI Overrides"
10        },
11        "inputs": {
12            "color": {
13                "type": "colord[3]",
14                "description": ["The color to be converted"],
15                "default": [0.0, 0.0, 0.0],
16                "metadata": {
17                    "$comment": "Metadata is key/value pairs associated with the attribute type.",
18                    "$specialNames": "Kit may recognize specific keys. 'uiName' is a human readable version of the attribute name",
19                    "uiName": "Color To Convert",
20                    "multipleValues": ["value1", "value2", "value3"]
21                }
22            }
23        },
24        "outputs": {
25            "h": {
26                "type": "double",
27                "description": ["The hue component of the input color"]
28            },
29            "s": {
30                "type": "double",
31                "description": ["The saturation component of the input color"]
32            },
33            "v": {
34                "type": "double",
35                "description": ["The value component of the input color"]
36            }
37        },
38        "tests": [ {"inputs:color": [0.2, 0.4, 0.4], "outputs:h": 0.5, "outputs:s": 0.5, "outputs:v": 0.4} ]
39    }
40}

OgnTutorialABIPy.py

The py file contains the implementation of the node class with every possible ABI method replaced with customized processing. The node still functions the same as any other node, although it is forced to write a lot of extra boilerplate code to do so.

  1"""
  2Implementation of the Python node accessing all of the simple data types.
  3This class exercises access to the DataModel through the generated database class for all simple data types.
  4It implements the same algorithm as the C++ node OgnTutorialABI.cpp
  5"""
  6
  7import colorsys
  8from contextlib import suppress
  9
 10import carb
 11import omni.graph.core as og
 12
 13
 14class OgnTutorialABIPy:
 15    """Illustrate overrides of the various ABI functions available to a Python OmniGraph node"""
 16
 17    @staticmethod
 18    def compute(context, node) -> bool:
 19        """
 20        Convert a color into components using the raw ABI function without the nice Database interface.
 21
 22        Rarely Overridden:
 23            Usually you will implement the much more friendly and Pythonic compute(OgnTutorialABIDatabasePy)
 24            method so that you can have easier access to your data.
 25        """
 26        # Manually acquire the data on the known attributes
 27        input_color_attr = node.get_attribute("inputs:color")
 28
 29        # Extract the input value from the controller
 30        input_color = og.Controller.get(input_color_attr)
 31
 32        output_hue_attr = node.get_attribute("outputs:h")
 33        output_saturation_attr = node.get_attribute("outputs:s")
 34        output_value_attr = node.get_attribute("outputs:v")
 35
 36        (h, s, v) = colorsys.rgb_to_hsv(*input_color)
 37
 38        # This exception is triggered if you accidentally reverse the parameters to set_attr_value.
 39        # The error isn't recovered, to prevent proliferation of inconsistent calls. The exception is
 40        # thrown to help with debugging. (As this is an example the exception is caught and ignored here.)
 41        with suppress(og.OmniGraphError):
 42            og.Controller.set(h, output_hue_attr)
 43
 44        og.Controller.set(output_hue_attr, h)
 45        og.Controller.set(output_saturation_attr, s)
 46        og.Controller.set(output_value_attr, v)
 47
 48        #
 49        # For comparison, here is the same algorithm implemented using "compute(db)"
 50        #
 51        # def compute(db) -> bool:
 52        #     (db.outputs.h, db.outputs.s, db.outputs.v) = colorsys.rgb_to_hsv(*db.inputs.color)
 53        return True
 54
 55    # ----------------------------------------------------------------------
 56    @staticmethod
 57    def get_node_type() -> str:
 58        """
 59        Rarely overridden
 60
 61        This should almost never be overridden as the auto-generated code will handle the name
 62        """
 63        carb.log_info("Python ABI override of get_node_type")
 64        return "omni.graph.tutorials.AbiPy"
 65
 66    # ----------------------------------------------------------------------
 67    @staticmethod
 68    def initialize(graph_context, node):
 69        """
 70        Occasionally overridden
 71
 72        This method might be overridden to set up initial conditions when a node of this type is created.
 73        Note that overridding this puts the onus on the node writer to set up initial conditions such as
 74        attribute default values and metadata.
 75
 76        When a node is created this will be called
 77        """
 78        carb.log_info("Python ABI override of initialize")
 79        # There is no default behavior on initialize so nothing else is needed for this tutorial to function
 80
 81    # ----------------------------------------------------------------------
 82    @staticmethod
 83    def initialize_type(node_type) -> bool:
 84        """
 85        Rarely overridden
 86
 87        This method might be overridden to set up initial conditions when a node type is registered.
 88        Note that overriding this puts the onus on the node writer to initialize the attributes and metadata.
 89
 90        By returning "True" the function is requesting that the attributes and metadata be initialized upon return,
 91        otherwise the caller will assume that this override has already done that.
 92        """
 93        carb.log_info("Python ABI override of initialize_type")
 94        return True
 95
 96    # ----------------------------------------------------------------------
 97    @staticmethod
 98    def release(node):
 99        """
100        Occasionally overridden
101
102        After a node is removed it will get a release call where anything set up in initialize() can be torn down
103        """
104        carb.log_info("Python ABI override of release")
105        # There is no default behavior on release so nothing else is needed for this tutorial to function
106
107    # ----------------------------------------------------------------------
108    @staticmethod
109    def update_node_version(graph_context, node, old_version: int, new_version: int):
110        """
111        Occasionally overridden
112
113        This is something you do want to override when you have more than version of your node.
114        In it you would translate attribute information from older versions into the current one.
115        """
116        carb.log_info(f"Python ABI override of update_node_version from {old_version} to {new_version}")
117        # There is no default behavior on update_node_version so nothing else is needed for this tutorial to function
118        return old_version < new_version
119
120    # ----------------------------------------------------------------------
121    @staticmethod
122    def on_connection_type_resolve(node):
123        """
124        Occasionally overridden
125
126        When there is a connection change to this node which results in an extended type attribute being automatically
127        resolved, this callback gives the node a change to resolve other extended type attributes. For example a generic
128        'Increment' node can resolve its output to an int only after its input has been resolved to an int. Attribute
129        types are resolved using omni.graph.attribute.set_resolved_type(), or the utility functions such as
130        og.resolve_fully_coupled().
131        """
132        carb.log_info("Python ABI override of on_connection_type_resolve")
133        # There is no default behavior for on_connection_type_resolve so nothing else is needed for this
134        # tutorial to function

Metadata Attached To Attributes

This file introduces the metadata keyword to attributes, whose value is a dictionary of key/value pairs associated with the attribute in which it appears that may be extracted using the ABI metadata functions. These are not persisted in any files and so must be set either in the .ogn file or in an override of the initialize() method in the node definition.