Python: importing modules into plugins


New in the Softimage 2011 Subscription Advantage Pack

The siutils Python module makes it easier to import modules into your self-installing plugins. Just put your modules in the same location as your plugin file , and you can use the __sipath__ variable to specify the module location.

__sipath__ is always defined in the plugin namespace, so no matter where you put a plugin, you can simply use __sipath__ to specify the location.

Here’s a simple example that shows how to import a module into your plugin.

  • Line 04: Import the siutils module
  • Line 39: Use add_to_syspath() to add __sipath__ to the Python sys path.
    If the module was located in a subfolder of the plugin location, you could use siutils.add_subfolder_to_syspath( __sipath__, ‘mysubfolder’ )

  • Line 40: Import the module
import win32com.client
from win32com.client import constants

import siutils

null = None
false = 0
true = 1

def XSILoadPlugin( in_reg ):
	in_reg.Author = "blairs"
	in_reg.Name = "TestPlugin"
	in_reg.Major = 1
	in_reg.Minor = 0

	in_reg.RegisterCommand("Test","Test")
	#RegistrationInsertionPoint - do not remove this line

	return true

def XSIUnloadPlugin( in_reg ):
	strPluginName = in_reg.Name
	Application.LogMessage(str(strPluginName) + str(" has been unloaded."),constants.siVerbose)
	return true

def Test_Init( in_ctxt ):
	oCmd = in_ctxt.Source
	oCmd.Description = ""
	oCmd.ReturnValue = true

	return true

def Test_Execute(  ):

	Application.LogMessage("Test_Execute called",constants.siVerbose)

#	print __sipath__ 

	siutils.add_to_syspath( __sipath__ )
	import TestModule
	TestModule.test( "hello world" )

	return true

9 thoughts on “Python: importing modules into plugins

  1. Pingback: New SDK stuff in the Subscription Advantage Pack « eX-SI Support

  2. What’s the correct way to *not* have to use “import” atop each custom command that needs a particular custom module? I noticed __sipath__ is not set all the time the global scope of the plugin file is executed. Sometimes it’s empty/missing. 😦

    • Sorry, I’m not sure I understand the question. What do you mean by “atop each custom command” ?

      I tried to repro, but I didn’t. But I spent only 5 minutes loading and unloading the plugin and calling the command…does it take longer for the problem to manifest itself?

      # TestCmdPlugin
      
      import win32com.client
      from win32com.client import constants
      
      import siutils
      
      Application.LogMessage( "Global: %s" % __sipath__ )
      
      null = None
      false = 0
      true = 1
      
      def XSILoadPlugin( in_reg ):
      	in_reg.Author = "blairs"
      	in_reg.Name = "TestCmdPlugin"
      	in_reg.Major = 1
      	in_reg.Minor = 0
      
      	Application.LogMessage( "XSILoadPlugin: %s" % __sipath__ )
      
      	in_reg.RegisterCommand("TestCmd","TestCmd")
      	#RegistrationInsertionPoint - do not remove this line
      
      	return true
      
      Application.LogMessage( "Global: %s" % __sipath__ )
      
      
      def XSIUnloadPlugin( in_reg ):
      	strPluginName = in_reg.Name
      	Application.LogMessage( "XSIUnloadPlugin: %s" % __sipath__ )
      	Application.LogMessage(str(strPluginName) + str(" has been unloaded."),constants.siVerbose)
      	return true
      
      Application.LogMessage( "Global: %s" % __sipath__ )
      
      
      def TestCmd_Init( in_ctxt ):
      	oCmd = in_ctxt.Source
      	oCmd.Description = ""
      	oCmd.ReturnValue = true
      
      	oArgs = oCmd.Arguments
      	oArgs.AddWithHandler("Arg0","Collection")
      	Application.LogMessage( "TestCmd_Init: %s" % __sipath__ )
      
      	return true
      
      Application.LogMessage( "Global: %s" % __sipath__ )
      
      def TestCmd_Execute( Arg0 ):
      
      	Application.LogMessage("TestCmd_Execute called",constants.siVerbose)
      	Application.LogMessage( "TestCmd_Execute: %s" % __sipath__ )
      	foo()
      
      	# 
      	# TODO: Put your command implementation here.
      	# 
      	return true
      	
      def foo():
      	Application.LogMessage( "foo: %s" % __sipath__ )
      
      • My bug was something that was happening to me a long time ago in Windows on 2011 or 2012 and at the time __sipath__ was being set sometimes and other times it was blank, messing up my appending to the PATH and therefore importing my custom module.

        I’m on 2012 on Linux now and I tried __sipath__ again and it seems to work OK. Sorry for the noise. Maybe it’s been fixed. (I’ll check on Windows at home later.)

      • Oh, and for clarity sake, by “atop each custom command” I meant that in your sample you do the import at the function scope not in the global scope. When you do that the import is not registered globally, which would imply you would do an import statement on each custom command using that custom module. That seemed silly and redundant, and it is, because if __sipath__ is working as advertised you can do the import outside, first thing in your file and use it later in any functions you wish.

      • I take it back… It DOES fail sometimes:

        # ERROR : Traceback (most recent call last):
        # File “”, line 16, in
        # PLUGIN_PATH = __sipath__
        # NameError: name ‘__sipath__’ is not defined
        # – [line 16 in myconfidentialfile.py]
        # ERROR : Property Page Script Logic Error (Python ActiveX Scripting Engine)
        # ERROR : [14]
        # ERROR : [15] PLUGIN_NAME = ‘someName’
        # ERROR : >[16] PLUGIN_PATH = __sipath__
        # ERROR : [17] if PLUGIN_PATH not in sys.path:
        # ERROR : [18] siutils.add_to_syspath( __sipath__ )
        # ERROR : [19] import mymodule
        # ERROR : Traceback (most recent call last):
        # File “”, line 16, in
        # PLUGIN_PATH = __sipath__
        # NameError: name ‘__sipath__’ is not defined
        #

        I can’t send you the addon though, but if it helps… I got that error when opening a custom property in the scene, which triggered the PPG’s _DefineLayout() which triggered its _OnInit() which had a PPG.Refresh() in it. Not sure if it’s related.

        Maybe PPG logic code doesn’t “see” __sipath__?

      • PPGLogic could be a problem…usually it is executed its own instance of the scripting engine, and doesn’t see things (like functions) defined in the global scope. I don’t remember if I tested with modules.

      • Woo! I can repro. 🙂

        Don’t know how to paste code here so I put it at http://pastebin.com/tHgTrxCS

        Load that plugin. It will load without errors, but then try to select something and create the “fooProperty” by invoking its creation from the Plugin Manager. When it pops up, you will get an __sipath__ not set error.

        Tell me if it repros for you.

      • This workaround works for the PPG logic erroring:

        PLUGIN_NAME = ‘TestCmdPlugin’
        try:
        pluginpath = __sipath__
        except:
        pluginpath = Application.Plugins(PLUGIN_NAME).OriginPath

        if pluginpath not in sys.path:
        sys.path.append(pluginpath)

        import TestModule

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s