omni.inspect: Omniverse Data Inspector

The interfaces in this extension don’t do anything themselves, they merely provide a conduit through which other objects can provide various information through a simple ABI without each object being required to provide the same inspection interface boilerplate.

The general approach is that you create an inspector, then pass it to an object to be inspected. This model provides full access to the internal data to the inspector and makes it easy for objects to add inspection capabilities.

Inspecting Data

To add inspection to your data you need two things - an interface to pass the inspector, and an implementation of the inspection, or inspections. We’ll take two imaginary interface types, one of which uses the old Carbonite interface definitions and one which uses ONI. The interfaces just manage an integer and float value, though the concept extends to arbitrariliy complex structures.

Carbonite ABI Integer

// Interface definition --------------------------------------------------

// Implementation for the integer is just a handle, which is an int*, and the interface pointer
using IntegerHandle = uint64_t;
struct IInteger;
struct IntegerObj
{
    const IInteger* iInteger;
    IntegerHandle integerHandle;
};
struct IInteger
{
    CARB_PLUGIN_INTERFACE("omni::inspect::IInteger", 1, 0);
    void(CARB_ABI* set)(IntegerObj& intObj, int value) = nullptr;
    bool(CARB_ABI* inspect)(const IntegerObj& intObj, inspect::IInspector* inspector) = nullptr;
};

// Interface implementation --------------------------------------------------

void intSet(IntegerObj& intObj, int value)
{
    intObj.iInteger->set(intObj, value);
}
bool intInspect(const IntegerObj& intObj, inspect::IInspector* inspector)
{
    // This object can handle both a memory use inspector and a serialization inspector
    auto memoryInspector = omni::cast<inspect::IInspectMemoryUse>(inspector);
    if (memoryInspector)
    {
        // The memory used by this type is just a single integer, and the object itself
        memoryInspector->useMemory((void*)&intObj, sizeof(intObj));
        memoryInspector->useMemory((void*)intObj.integerHandle, sizeof(int));
        return true;
    }
    auto jsonSerializer = omni::cast<inspect::IInspectJsonSerializer>(inspector);
    if (jsonSerializer)
    {
        // Valid JSON requires more than just a bare integer.
        // Indenting on the return value gives you a visual representation of the JSON hierarchy
        if (jsonSerializer->openObject())
        {
            jsonSerializer->writeKey("Integer Value");
            jsonSerializer->writeInt(*(int*)(intObj.integerHandle));
            jsonSerializer->closeObject();
        }
        return true;
    }
    auto serializer = omni::cast<inspect::IInspectSerializer>(inspector);
    if (serializer)
    {
        // The interesting data to write is the integer value, though you could also write the pointer if desired
        serializer->write("Integer value %d", *(int*)(intObj.integerHandle));
        return true;
    }
    // Returning false indicates an unsupported inspector
    return false;
}

// Interface use --------------------------------------------------

IInteger iFace{ intInspect, intSet };
int myInt{ 0 };
IntegerObj iObj{ &iFace, (uint64_t)&myInt };

ONI Float

// Interface definition --------------------------------------------------

OMNI_DECLARE_INTERFACE(IFloat);
class IFloat_abi : public omni::Inherits<omni::core::IObject, OMNI_TYPE_ID("omni.inspect.IFloat")>
{
protected:
    virtual void set_abi(float newValue) noexcept = 0;
    virtual void inspect_abi(omni::inspect::IInspector* inspector) noexcept = 0;
};

// Interface implementation --------------------------------------------------

class IFloat : public omni::Implements<IIFloat>
{
protected:
    void set_abi(float newvalue) noexcept override
    {
        m_value = value;
    }

    bool inspect(omni::inspect::IInspector* inspector) noexcept override
    {
        // This object can handle both a memory use inspector and a serialization inspector
        auto memoryInspector = omni::cast<inspect::IInspectMemoryUse>(inspector);
        if (memoryInspector)
        {
            // The memory used by this type is just the size of this object
            memoryInspector->useMemory((void*)this, sizeof(*this));
            return true;
        }
        auto jsonSerializer = omni::cast<inspect::IInspectJsonSerializer>(inspector);
        if (jsonSerializer)
        {
            // Valid JSON requires more than just a bare float.
            // Indenting on the return value gives you a visual representation of the JSON hierarchy
            if (jsonSerializer->openObject())
            {
                jsonSerializer->writeKey("Float Value");
                jsonSerializer->writeFloat(m_value);
                jsonSerializer->closeObject();
            }
            return true;
        }
        auto serializer = omni::cast<inspect::IInspectSerializer>(inspector);
        if (serializer)
        {
            // The interesting data to write is the float value, though you could also write "this" if desired
            serializer->write("float value %g", m_value);
            return true;
        }
        // Returning false indicates an unsupported inspector
        return false;
    }

private:
    float m_value{ 0.0f };
};

Calling Inspectors From Python

The inspectors, being ONI objects, have Python bindings so they can be instantiated directly and passed to any of the interfaces that support them.

import omni.inspect as oi
memory_inspector = oi.IInspectMemoryUse()
my_random_object.inspect(memory_inspector)
print(f"Memory use is {memory_inspector.get_memory_use()} bytes")

json_serializer = oi.IInspectJsonSerializer()
my_random_object.inspect(json_serializer)
print(f"JSON object:\n{json_serializer.as_string()}" )

serializer = oi.IInspectSerializer()
my_random_object.inspect(serializer)
print(f"Serialized object:\n{serializer.as_string()}" )

omni.inspect Python Docs

Contains interfaces for inspecting values used within other interfaces

class omni.inspect.IInspectJsonSerializer

Base class for object inspection requests.

as_string(self: omni.inspect._omni_inspect.IInspectJsonSerializer)str

Get the current output as a string. If the output is being sent to a file path then read the file at that path and return the contents of the file (with the usual caveats about file size).

@returns String representation of the output so far

clear(self: omni.inspect._omni_inspect.IInspectJsonSerializer)None

Clear the contents of the serializer output, either emptying the file or clearing the string, depending on where the current output is directed.

close_array(self: omni.inspect._omni_inspect.IInspectJsonSerializer)bool

Finish writing a JSON array.

@returns whether or not validation succeeded.

close_object(self: omni.inspect._omni_inspect.IInspectJsonSerializer)bool

Finish writing a JSON object.

@returns whether or not validation succeeded.

finish(self: omni.inspect._omni_inspect.IInspectJsonSerializer)bool

Finishes writing the entire JSON dictionary.

@returns whether or not validation succeeded.

open_array(self: omni.inspect._omni_inspect.IInspectJsonSerializer)bool

Begin a JSON array.

@returns whether or not validation succeeded. @note This may throw a std::bad_alloc or a std::length_error if the stack of scopes gets too large

open_object(self: omni.inspect._omni_inspect.IInspectJsonSerializer)bool

Begin a JSON object.

@returns whether or not validation succeeded.

property output_location
property output_to_file_path
set_output_to_string(self: omni.inspect._omni_inspect.IInspectJsonSerializer)None

Set the output location of the serializer data to be a local string. No check is made to ensure that the string size doesn’t get too large so when in doubt use a file path.

write_base64_encoded(self: omni.inspect._omni_inspect.IInspectJsonSerializer, value: bytes, size: int)bool

Write a set of bytes into the output JSON as a base64 encoded string.

@param[in] value The bytes to be written. @param[in] size The number of bytes of data in @p value. @returns whether or not validation succeeded. @remarks This will take the input bytes and encode it in base64, then store that as base64 data in a string.

write_bool(self: omni.inspect._omni_inspect.IInspectJsonSerializer, value: bool)bool

Write out a JSON boolean value.

@param[in] value The boolean value. @returns whether or not validation succeeded.

write_double(self: omni.inspect._omni_inspect.IInspectJsonSerializer, value: float)bool

Write out a JSON double (aka number) value.

@param[in] value The double value. @returns whether or not validation succeeded.

write_float(self: omni.inspect._omni_inspect.IInspectJsonSerializer, value: float)bool

Write out a JSON float (aka number) value.

@param[in] value The double value. @returns whether or not validation succeeded.

write_int(self: omni.inspect._omni_inspect.IInspectJsonSerializer, value: int)bool

Write out a JSON integer value.

@param[in] value The integer value. @returns whether or not validation succeeded.

write_int64(self: omni.inspect._omni_inspect.IInspectJsonSerializer, value: int)bool

Write out a JSON 64-bit integer value.

@param[in] value The 64-bit integer value. @returns whether or not validation succeeded. @note 64 bit integers will be written as a string of they are too long to be stored as a number that’s interoperable with javascript’s double precision floating point format.

write_key(self: omni.inspect._omni_inspect.IInspectJsonSerializer, key: str)bool

Write out a JSON key for an object property.

@param[in] key The key name for this property. This may be nullptr. @returns whether or not validation succeeded.

write_key_with_length(self: omni.inspect._omni_inspect.IInspectJsonSerializer, key: str, key_len: int)bool

Write out a JSON key for an object property.

@param[in] key The string value for the key. This can be nullptr. @param[in] keyLen The length of @ref key, excluding the null terminator. @returns whether or not validation succeeded.

write_null(self: omni.inspect._omni_inspect.IInspectJsonSerializer)bool

Write out a JSON null value.

@returns whether or not validation succeeded.

write_string(self: omni.inspect._omni_inspect.IInspectJsonSerializer, value: str)bool

Write out a JSON string value.

@param[in] value The string value. This can be nullptr. @returns whether or not validation succeeded.

write_string_with_length(self: omni.inspect._omni_inspect.IInspectJsonSerializer, value: str, len: int)bool

Write out a JSON string value.

@param[in] value The string value. This can be nullptr if @p len is 0. @param[in] len The length of @p value, excluding the null terminator. @returns whether or not validation succeeded.

write_u_int(self: omni.inspect._omni_inspect.IInspectJsonSerializer, value: int)bool

Write out a JSON unsigned integer value.

@param[in] value The unsigned integer value. @returns whether or not validation succeeded.

write_u_int64(self: omni.inspect._omni_inspect.IInspectJsonSerializer, value: int)bool

Write out a JSON 64-bit unsigned integer value.

@param[in] value The 64-bit unsigned integer value. @returns whether or not validation succeeded. @note 64 bit integers will be written as a string of they are too long to be stored as a number that’s interoperable with javascript’s double precision floating point format.

class omni.inspect.IInspectMemoryUse

Base class for object inspection requests.

reset(self: omni.inspect._omni_inspect.IInspectMemoryUse)None

Reset the memory usage data to a zero state

total_used(self: omni.inspect._omni_inspect.IInspectMemoryUse)int

@returns the total number of bytes of memory used since creation or the last call to reset().

use_memory(self: omni.inspect._omni_inspect.IInspectMemoryUse, ptr: capsule, bytes_used: int)bool

Add a block of used memory Returns false if the memory was not recorded (e.g. because it was already recorded)

@param[in] ptr Pointer to the memory location being logged as in-use @param[in] bytesUsed Number of bytes in use at that location

class omni.inspect.IInspectSerializer

Base class for object serialization requests.

as_string(self: omni.inspect._omni_inspect.IInspectSerializer)str

Get the current output as a string.

@returns The output that has been sent to the serializer. If the output is being sent to a file path then read the file at that path and return the contents of the file. If the output is being sent to stdout or stderr then nothing is returned as that output is unavailable after flushing.

clear(self: omni.inspect._omni_inspect.IInspectSerializer)None

Clear the contents of the serializer output, either emptying the file or clearing the string, depending on where the current output is directed.

property output_location
property output_to_file_path
set_output_to_string(self: omni.inspect._omni_inspect.IInspectSerializer)None

Set the output location of the serializer data to be a local string. No check is made to ensure that the string size doesn’t get too large so when in doubt use a file path.

write_string(self: omni.inspect._omni_inspect.IInspectSerializer, to_write: str)None

Write a fixed string to the serializer output location

@param[in] toWrite String to be written to the serializer

class omni.inspect.IInspector

Base class for object inspection requests.

property help
help_flag(self: omni.inspect._omni_inspect.IInspector)str

Returns the common flag used to tell the inspection process to put the help information into the inspector using the setHelp_abi function. Using this approach avoids having every inspector/object combination add an extra ABI function just for retrieving the help information, as well as providing a consistent method for requesting it. @returns String containing the name of the common flag used for help information

help_information(self: omni.inspect._omni_inspect.IInspector)str

Returns the help information currently available on the inspector. Note that this could change from one invocation to the next so it’s important to read it immediately after requesting it. @returns String containing the help information describing the current configuration of the inspector

is_flag_set(self: omni.inspect._omni_inspect.IInspector, flag_name: str)bool

Checks whether a particular flag is currently set or not. @param[in] flagName Name of the flag to check @returns True if the named flag is set, false if not

set_flag(self: omni.inspect._omni_inspect.IInspector, flag_name: str, flag_state: bool)None

Enable or disable an inspection flag. It’s up to the individual inspection operations or the derived inspector interfaces to interpret the flag. @param[in] flagName Name of the flag to set @param[in] flagState New state for the flag

Administrative Details

Administrivia