AutoNode Implementation#
The AutoNode user document shows how to make use of AutoNode
features. This document
shows how these features are implemented under the covers.
There are two modes of operation of AutoNode
, Live Mode and Developer Mode. The two have very different
use cases. If you just want to get started using AutoNode
without any outside development then look into the
Live Mode section. If you want to create AutoNode
definitions you can bundle with your extension then jump
right to the Developer Mode sections.
Live Mode#
“Live” in this context refers to the fact that the AutoNode
definitions will be parsed and implemented directly
within the Python scripting environment. These are definitions you might type directly in to the script editor, or
run as part of an external script.
They are processed as part of the Python parsing, generate a .ogn definition internally, and from that generate the node type definition and API, which are added directly to the extension’s Python module. No files are saved are loaded. All of the Python definition are processed in code.
Note
This section must be filled in with more details on live mode.
Developer Mode#
As the name might hint, this mode is mostly for use by developers. It provides the framework for defining AutoNode
node types in a way that lets the node definitions persist in the extension. In the same way that a .ogn file will be
used to generate the database definition for the node implementation to use, an AutoNode
definition will be used
to create the .ogn and .py files that implement a node based on a Python function or class.
Locating The AutoNode Definitions#
The AutoNode
system must locate the definitions for parsing. It makes use of extension information and by
monitoring the state of extensions to optimize the number of places it will look for these definitions.
extension.toml Configuration#
The first piece the developer must put in place is a few settings in their extension.toml
configuration file.
A typical addition will look like this:
[omni.graph.autonode]
developer_mode = true
import_paths = ["omni.graph.examples.python._impl.autonode"]
This is the content used by the omni.graph.examples.python
extension to enable developer mode for a few
AutoNode
definitions it has.
The [omni.graph.autonode] line defines the dictionary entry to which these settings belong. It has to be exactly
as written since the AutoNode
code looks for it by name.
developer_mode = true tells the system that AutoNode
should enable developer mode for this extension to scan
for AutoNode
definitions when the extension is enabled.
import_paths = [] provides a list of specific Python import modules in which to look for AutoNode
definitions.
It’s more efficient to keep them isolated to a small module, but if you do not know where they will be implemented or
they can be implemented anywhere in your extension you can point this at the module(s) specified in your
extension.toml
s [[python.module]] section.
Extension Monitoring#
Once the AutoNode
module has been initialized it creates a subscription to the extension enabled event in the
class omni.graph.core.autonode.AutoNodeExtensionWatcher
.
When an extension enabled event is encountered AutoNode
reads the configuration information from the extension’s
extension.toml
file to check if developer mode is enabled and find the list of modules in which it can find any
AutoNode
definitions. It then runs omni.graph.tools.ogn.build_autonode_from_folder()
on each folder to
populate the AutoNode
registry, which will be used to generate the node type definitions.
omni.graph.tools.ogn.build_autonode_from_folder()
generates the AutoNode
node type definitions from the
descriptions it finds, and then optionally runs the OGN node generator on those definitions if it has been give a
directory in which to write those generated files.
Direct Invocation#
In addition to the indirect extension monitoring that will automatically scan an extension for AutoNode
definitions there is also a utility in ogn_helpers.lua
named make_inline_generator_command()
that can be
called as part of the build to accomplish the same goal. The difference is that the location of the module is assumed
to correspond to the extension, and there is only one, rather than being inferred from the extension configuration.
The above example could also have been implemented in the premake5.lua
file of omni.graph.examples.python
as
the function call:
make_inline_generator_command(ogn, "omni.graph.examples.python")
Parsing The Definitions#
After it has found the locations of all definitions omni.graph.tools.ogn.build_autonode_from_folder()
creates an omni.graph.tools._impl.autonode_generator.compiler.AutoNodeModule
object that will scan all
of the files in the module looking for AutoNode
definitions.
For each file it uses the Python ast
module to scan for decorators, gathering the annotation data for each
decorator it encounters as well as the object it decorates.
For each decorator that is part of AutoNode
it uses the AST to create a wrapper around the function definition
of type omni.graph.tools._impl.autonode_generator.function.AOTAutoFunctionWrapper
. It extracts the
syntactic information from the function to create the corresponding .ogn and .py node type implementation files.
The wrapper has two functions get_ogn()
and get_node_impl_source()
tha accomplish this.
Cleanup Needed#
The two implementation trees, one in omni.graph
and the other in omni.graph.tools
have a lot of duplication
that should be resolved. The originals all live in omni.graph
.
Support Files#
These are the various files that mention or implement the AutoNode features.
omni.graph.tools/ omni.graph/ omni.graph.docs/
python/ python/ docs/
generate_inline_nodes.py __init__.py CoreConcepts.md
ogn.py autonode.py Overview.md
_impl/ _impl/ dev/
autonode_generator/ bundles.py Versioning.md
__init__.py autonode/ WritingNodes.md
compiler.py __init__.py
function.py autonode.py
main.py core.py
type_definitions.py enum_wrappers.py
util.py event.py
tests/ function.py
compiler/ property.py
data/ type_definitions.py
imported_module.py util.py
test_module.py docs/
test-subfolder/ AutoNode.md
test_subfolder_file.py AutoNodeOperation.md
Generated Files#
Live mode has no generated files. For Developer mode in extension omni.mine
with script an.py
in Python module omni.mine.autonode
containing OmniGraphNode
decorations on functions node_a
and node_b
these are the potential files that will exist when those nodes are fully realized.
BUILD is the root of the build directory. CACHE is the root of the code generator’s cache directory, which it
uses for storing nodes generated when the supplied generated code is out of date. Assumes version 1.2.3 of OmniGraph
and version 2.3.4 of omni.mine
.
BUILD/ CACHE/
exts/ 1.2.3/
omni.mine/ omni.mine-2.3.4/
ogn/ omni.mine/
docs/ ogn/
OgnNodeA.rst __init__.py
OgnNodeB.rst OgnNodeADatabase.py
omni/ OgnNodeBDatabase.py
mine/ docs/
autonode.py OgnNodeA.rst
ogn/ OgnNodeB.rst
OgnNodeADatabase.py tests/
OgnNodeBDatabase.py TestOgnNodeA.py
_autonode/ TestOgnNodeB.py
OgnNodeA.ogn usd/
OgnNodeA.py OgnNodeATemplate.usda
OgnNodeB.ogn OgnNodeBTemplate.usda
OgnNodeB.py _autonode/
tests/ OgnNodeA.ogn
TestOgnNodeA.py OgnNodeA.py
TestOgnNodeB.py OgnNodeB.ogn
usd/ OgnNodeB.py
OgnNodeATemplate.usda
OgnNodeBTemplate.usda