Plug module

Summary: Provides a plug-in framework implementation. Define interfaces, discover, register, and apply plug-in modules to nodes.


This package defines facilities for dealing with plugins.

Classes:

Notice

Notifications sent by the Plug module.

Plugin

Defines an interface to registered plugins.

Registry

Defines an interface for registering plugins.

class pxr.Plug.Notice

Notifications sent by the Plug module.

Classes:

Base

DidRegisterPlugins

class Base
class DidRegisterPlugins

Methods:

GetNewPlugins

GetNewPlugins()
class pxr.Plug.Plugin

Defines an interface to registered plugins.

Plugins are registered using the interfaces in PlugRegistry .

For each registered plugin, there is an instance of PlugPlugin which can be used to load and unload the plugin and to retrieve information about the classes implemented by the plugin.

Methods:

DeclaresType(type, includeSubclasses)

Returns true if type is declared by this plugin.

FindPluginResource(path, verify)

Find a plugin resource by absolute or relative path optionally verifying that file exists.

GetMetadataForType(type)

Returns the metadata sub-dictionary for a particular type.

Load()

Loads the plugin.

MakeResourcePath(path)

Build a plugin resource path by returning a given absolute path or combining the plugin's resource path with a given relative path.

Attributes:

expired

True if this object has expired, False otherwise.

isLoaded

bool

isPythonModule

bool

isResource

bool

metadata

JsObject

name

str

path

str

resourcePath

str

DeclaresType(type, includeSubclasses) bool

Returns true if type is declared by this plugin.

If includeSubclasses is specified, also returns true if any subclasses of type have been declared.

Parameters
  • type (Type) –

  • includeSubclasses (bool) –

FindPluginResource(path, verify) str

Find a plugin resource by absolute or relative path optionally verifying that file exists.

If verification fails an empty path is returned. Relative paths are relative to the plugin’s resource path.

Parameters
  • path (str) –

  • verify (bool) –

GetMetadataForType(type) JsObject

Returns the metadata sub-dictionary for a particular type.

Parameters

type (Type) –

Load() bool

Loads the plugin.

This is a noop if the plugin is already loaded.

MakeResourcePath(path) str

Build a plugin resource path by returning a given absolute path or combining the plugin’s resource path with a given relative path.

Parameters

path (str) –

property expired

True if this object has expired, False otherwise.

property isLoaded

bool

Returns true if the plugin is currently loaded.

Resource plugins always report as loaded.

Type

type

property isPythonModule

bool

Returns true if the plugin is a python module.

Type

type

property isResource

bool

Returns true if the plugin is resource-only.

Type

type

property metadata

JsObject

Returns the dictionary containing meta-data for the plugin.

Type

type

property name

str

Returns the plugin’s name.

Type

type

property path

str

Returns the plugin’s filesystem path.

Type

type

property resourcePath

str

Returns the plugin’s resources filesystem path.

Type

type

class pxr.Plug.Registry

Defines an interface for registering plugins.

PlugRegistry maintains a registry of plug-ins known to the system and provides an interface for base classes to load any plug-ins required to instantiate a subclass of a given type.

Defining a Base Class API

In order to use this facility you will generally provide a module which defines the API for a plug-in base class. This API will be sufficient for the application or framework to make use of custom subclasses that will be written by plug-in developers.

For example, if you have an image processing application, you might want to support plug-ins that implement image filters. You can define an abstract base class for image filters that declares the API your application will require image filters to implement; perhaps something simple like C++ Code Example 1 (Doxygen only).

People writing custom filters would write a subclass of ImageFilter that overrides the two methods, implementing their own special filtering behavior.

Enabling Plug-in Loading for the Base Class

In order for ImageFilter to be able to load plug-ins that implement these custom subclasses, it must be registered with the TfType system.

The ImageFilter base class, as was mentioned earlier, should be made available in a module that the application links with. This is done so that plug-ins that want to provide ImageFilters can also link with the module allowing them to subclass ImageFilter.

Registering Plug-ins

A plug-in developer can now write plug-ins with ImageFilter subclasses. Plug-ins can be implemented either as native dynamic modules (either regular dynamic modules or framework bundles) or as Python modules.

Plug-ins must be registered with the registry. All plugins are registered via RegisterPlugins() . Plug-in Python modules must be directly importable (in other words they must be able to be found in Python’s module path.) Plugins are registered by providing a path or paths to JSON files that describe the location, structure and contents of the plugin. The standard name for these files in plugInfo.json.

Typically, the application that hosts plug-ins will locate and register plug-ins at startup.

The plug-in facility is lazy. It does not dynamically load code from plug-in bundles until that code is required.

plugInfo.json

A plugInfo.json file has the following structure:

{
    # Comments are allowed and indicated by a hash at the start of a
    # line or after spaces and tabs.  They continue to the end of line.
    # Blank lines are okay, too.

    # This is optional.  It may contain any number of strings.
    #   Paths may be absolute or relative.
    #   Paths ending with slash have plugInfo.json appended automatically.
    #   '\*' may be used anywhere to match any character except slash.
    #   '\*\*' may be used anywhere to match any character including slash.
    "Includes": [
        "/absolute/path/to/plugInfo.json",
        "/absolute/path/to/custom.filename",
        "/absolute/path/to/directory/with/plugInfo/",
        "relative/path/to/plugInfo.json",
        "relative/path/to/directory/with/plugInfo/",
        "glob\*/pa\*th/\*to\*/\*/plugInfo.json",
        "recursive/pa\*\*th/\*\*/"
    ],

    # This is optional.  It may contain any number of objects.
    "Plugins": [
        {
            # Type is required and may be "module", "python" or "resource".
            "Type": "module",

            # Name is required.  It should be the Python module name,
            # the shared module name, or a unique resource name.
            "Name": "myplugin",

            # Root is optional.  It defaults to ".".
            # This gives the path to the plugin as a whole if the plugin
            # has substructure.  For Python it should be the directory
            # with the __init__.py file.  The path is usually relative.
            "Root": ".",

            # LibraryPath is required by Type "module" and unused
            # otherwise.  It gives the path to the shared module
            # object, either absolute or relative to Root.
            "LibraryPath": "libmyplugin.so",

            # ResourcePath is option.  It defaults to ".".
            # This gives the path to the plugin's resources directory.
            # The path is either absolute or relative to Root.
            "ResourcePath": "resources",

            # Info is required.  It's described below.
            "Info": {
                # Plugin contents.
            }
        }
    ]
}

As a special case, if a plugInfo.json contains an object that doesn’t have either the”Includes”or”Plugins”keys then it’s as if the object was in a”Plugins”array.

Advertising a Plug-in’s Contents

Once the plug-ins are registered, the plug-in facility must also be able to tell what they contain. Specifically, it must be able to find out what subclasses of what plug-in base classes each plug-in contains. Plug-ins must advertise this information through their plugInfo.json file in the”Info”key. In the”Info”object there should be a key”Types”holding an object.

This”Types”object’s keys are names of subclasses and its values are yet more objects (the subclass meta-data objects). The meta-data objects can contain arbitrary key-value pairs. The plug-in mechanism will look for a meta-data key called”displayName”whose value should be the display name of the subclass. The plug-in mechanism will look for a meta-data key called”bases”whose value should be an array of base class type names.

For example, a bundle that contains a subclass of ImageFilter might have a plugInfo.json that looks like the following example.

{
    "Types": {
        "MyCustomCoolFilter" : {
            "bases": ["ImageFilter"],
            "displayName": "Add Coolness to Image"
            # other arbitrary metadata for MyCustomCoolFilter here
        }
    }
}

What this says is that the plug-in contains a type called MyCustomCoolFilter which has a base class ImageFilter and that this subclass should be called”Add Coolness to Image”in user-visible contexts.

In addition to the”displayName”meta-data key which is actually known to the plug-in facility, you may put whatever other information you want into a class’meta-data dictionary. If your plug-in base class wants to define custom keys that it requires all subclasses to provide, you can do that. Or, if a plug-in writer wants to define their own keys that their code will look for at runtime, that is OK as well.

Working with Subclasses of a Plug-in Base Class

Most code with uses types defined in plug-ins doesn’t deal with the Plug API directly. Instead, the TfType interface is used to lookup types and to manufacture instances. The TfType interface will take care to load any required plugins.

To wrap up our example, the application that wants to actually use ImageFilter plug-ins would probably do a couple of things. First, it would get a list of available ImageFilters to present to the user. This could be accomplished as shown in Python Code Example 2 (Doxygen only).

Then, when the user picks a filter from the list, it would manufacture and instance of the filter as shown in Python Code Example 3 (Doxygen only).

As was mentioned earlier, this plug-in facility tries to be as lazy as possible about loading the code associated with plug-ins. To that end, loading of a plugin will be deferred until an instance of a type is manufactured which requires the plugin.

Multiple Subclasses of Multiple Plug-in Base Classes

It is possible for a bundle to implement multiple subclasses for a plug-in base class if desired. If you want to package half a dozen ImageFilter subclasses in one bundle, that will work fine. All must be declared in the plugInfo.json.

It is possible for there to be multiple classes in your application or framework that are plug-in base classes. Plug-ins that implement subclasses of any of these base classes can all coexist. And, it is possible to have subclasses of multiple plug-in base classes in the same bundle.

When putting multiple subclasses (of the same or different base classes) in a bundle, keep in mind that dynamic loading happens for the whole bundle the first time any subclass is needed, the whole bundle will be loaded. But this is generally not a big concern.

For example, say the example application also has a plug-in base class”ImageCodec”that allows people to add support for reading and writing other image formats. Imagine that you want to supply a plug-in that has two codecs and a filter all in a single plug-in. Your plugInfo.json”Info”object might look something like this example.

{
    "Types": {
        "MyTIFFCodec": {
            "bases": ["ImageCodec"],
            "displayName": "TIFF Image"
        },
        "MyJPEGCodec": {
            "bases": ["ImageCodec"],
            "displayName": "JPEG Image"
        },
        "MyCustomCoolFilter" : {
            "bases": ["ImageFilter"],
            "displayName": "Add Coolness to Image"
        }
    }
}

Dependencies on Other Plug-ins

If you write a plug-in that has dependencies on another plug-in that you cannot (or do not want to) link against statically, you can declare the dependencies in your plug-in’s plugInfo.json. A plug-in declares dependencies on other classes with a PluginDependencies key whose value is a dictionary. The keys of the dictionary are plug-in base class names and the values are arrays of subclass names.

The following example contains an example of a plug-in that depends on two classes from the plug-in in the previous example.

{
    "Types": {
        "UltraCoolFilter": {
            "bases": ["MyCustomCoolFilter"],
            "displayName": "Add Unbelievable Coolness to Image"
            # A subclass of MyCustomCoolFilter that also uses MyTIFFCodec
        }
    },
    "PluginDependencies": {
        "ImageFilter": ["MyCustomCoolFilter"],
        "ImageCodec": ["MyTIFFCodec"]
    }
}

The ImageFilter provided by the plug-in in this example depends on the other ImageFilter MyCoolImageFilter and the ImageCodec MyTIFFCodec. Before loading this plug-in, the plug-in facility will ensure that those two classes are present, loading the plug-in that contains them if needed.

Methods:

FindDerivedTypeByName

classmethod FindDerivedTypeByName(base, typeName) -> Type

FindTypeByName

classmethod FindTypeByName(typeName) -> Type

GetAllDerivedTypes

classmethod GetAllDerivedTypes(base, result) -> None

GetAllPlugins()

Returns all registered plug-ins.

GetDirectlyDerivedTypes

classmethod GetDirectlyDerivedTypes(base) -> list[Type]

GetPluginForType(t)

Returns the plug-in for the given type, or a null pointer if there is no registered plug-in.

GetPluginWithName(name)

Returns a plugin with the specified module name.

GetStringFromPluginMetaData(type, key)

Looks for a string associated with type and key and returns it, or an empty string if type or key are not found.

RegisterPlugins(pathToPlugInfo)

Registers all plug-ins discovered at pathToPlugInfo.

Attributes:

expired

True if this object has expired, False otherwise.

static FindDerivedTypeByName()

classmethod FindDerivedTypeByName(base, typeName) -> Type

Retrieve the TfType that derives from base and has the given alias or type name typeName .

See the documentation for TfType::FindDerivedByName for more information. Use this function if you expect that the derived type may be provided by a plugin. Calling this function will incur plugin discovery (but not loading) if plugin discovery has not yet occurred.

Note that additional plugins may be registered during program runtime.

Plug-In Discovery & Registration

Parameters
  • base (Type) –

  • typeName (str) –


FindDerivedTypeByName(typeName) -> Type

Retrieve the TfType that derives from Base and has the given alias or type name typeName .

See the documentation for TfType::FindDerivedByName for more information. Use this function if you expect that the derived type may be provided by a plugin. Calling this function will incur plugin discovery (but not loading) if plugin discovery has not yet occurred.

Note that additional plugins may be registered during program runtime.

Plug-In Discovery & Registration

Parameters

typeName (str) –

static FindTypeByName()

classmethod FindTypeByName(typeName) -> Type

Retrieve the TfType corresponding to the given name .

See the documentation for TfType::FindByName for more information. Use this function if you expect that name may name a type provided by a plugin. Calling this function will incur plugin discovery (but not loading) if plugin discovery has not yet occurred.

Note that additional plugins may be registered during program runtime.

Plug-In Discovery & Registration

Parameters

typeName (str) –

static GetAllDerivedTypes()

classmethod GetAllDerivedTypes(base, result) -> None

Return the set of all types derived (directly or indirectly) from base.

Use this function if you expect that plugins may provide types derived from base. Otherwise, use TfType::GetAllDerivedTypes.

Note that additional plugins may be registered during program runtime.

Plug-In Discovery & Registration

Parameters
  • base (Type) –

  • result (set[Type]) –


GetAllDerivedTypes(result) -> None

Return the set of all types derived (directly or indirectly) from Base.

Use this function if you expect that plugins may provide types derived from base. Otherwise, use TfType::GetAllDerivedTypes.

Note that additional plugins may be registered during program runtime.

Plug-In Discovery & Registration

Parameters

result (set[Type]) –

GetAllPlugins() list[Plugin]

Returns all registered plug-ins.

Note that additional plugins may be registered during program runtime.

Plug-In Discovery & Registration

static GetDirectlyDerivedTypes()

classmethod GetDirectlyDerivedTypes(base) -> list[Type]

Return a vector of types derived directly from base.

Use this function if you expect that plugins may provide types derived from base. Otherwise, use TfType::GetDirectlyDerivedTypes.

Parameters

base (Type) –

GetPluginForType(t) Plugin

Returns the plug-in for the given type, or a null pointer if there is no registered plug-in.

Parameters

t (Type) –

GetPluginWithName(name) Plugin

Returns a plugin with the specified module name.

Note that additional plugins may be registered during program runtime.

Plug-In Discovery & Registration

Parameters

name (str) –

GetStringFromPluginMetaData(type, key) str

Looks for a string associated with type and key and returns it, or an empty string if type or key are not found.

Parameters
  • type (Type) –

  • key (str) –

RegisterPlugins(pathToPlugInfo) list[Plugin]

Registers all plug-ins discovered at pathToPlugInfo.

Sends PlugNotice::DidRegisterPlugins with any newly registered plugins.

Parameters

pathToPlugInfo (str) –


RegisterPlugins(pathsToPlugInfo) -> list[Plugin]

Registers all plug-ins discovered in any of pathsToPlugInfo.

Sends PlugNotice::DidRegisterPlugins with any newly registered plugins.

Parameters

pathsToPlugInfo (list[str]) –

property expired

True if this object has expired, False otherwise.