When setting up your return values from a custom command authored in Python, you need to be aware that you cannot pass native Python dictionaries and Python custom classes as-is:
Using Python Dictionaries as Return Values
The Python native dictionary type does not conform to any of the possible data types that Softimage allows for return values from custom commands. As a workaround, you can use an ActiveX scripting dictionary instead, as demonstrated in this snippet from a self-installing custom command:
#--------- def testdictionary_Execute( ): import win32com.client oDict = win32com.client.Dispatch( "Scripting.Dictionary" ) oDict[ 'key1' ] = 123 oDict[ 'key2' ] = 45 oDict[ 'key3' ] = 6789 return oDict #---------
Using Custom Python Classes as Return Values
Python allows you to return a Python class as an ActiveX object, but extra work is needed:
Some attributes must be set at the class definition level to define which methods and attributes are exposed:
The class must be wrapped before being returned. Use the win32com.server.util.wrap( ) function
Python Example: Self-Installing Command Returning a Python Class
The following self-installable plug-in returns a Python object which can be used from either JScript or VBScript:
# This class is going to be exported to VB and jscript class TestPython: # Declare list of exported functions: _public_methods_ = ['GetAnswer'] # Declare list of exported attributes _public_attrs_ = ['exclamation', 'answer'] # Declare list of exported read-only attributes: _readonly_attrs_ = ['answer'] # Class init: def __init__(self): # Initialize exported attributes: self.exclamation = 1 self.answer = 42 # Perfectly legal to have other non exported attributes # Exported function def GetAnswer(self, question): return "The answer to " + str(question) + " is " + str(self.answer) + "!"*self.exclamation # Perfectly legal to have other non exported functions. # Traditional plug-in installation: true = 1 def XSILoadPlugin( in_reg ): in_reg.Author = "Command Wizard User" in_reg.Name = "TestPython Plug-in" in_reg.Major = 1 in_reg.Minor = 0 in_reg.RegisterCommand( "TestPython","TestPython" ) return true def TestPython_Init( io_Context ): oCmd = io_Context.Source Application.LogMessage( "TestPython_Init called" ) oCmd.Description = "" oCmd.ToolTip = "" oCmd.ReturnValue = true return true def TestPython_Execute( ): Application.LogMessage( "TestPython_Execute called" ) oClass = TestPython() import win32com.server # Class MUST be wrapped before being returned: return win32com.server.util.wrap(oClass)
Then you can run this test VBScript snippet in the Script Editor, which uses the Python object successfully:
set a = TestPython() 'INFO : TestPython_Execute called LogMessage a.GetAnswer("life, the universe, everything") 'INFO : The answer to life, the universe, everything is 42! a.exclamation = 10 LogMessage a.GetAnswer("life, the universe, everything") 'INFO : The answer to life, the universe, everything is 42!!!!!!!!!!
For more information, see these Python sources:
aspn.activestate.com/ASPN/docs/ActivePython/2.3/pywin32/html/com/win32com/HTML/QuickStartServerCom.html—contains information about COM-wrapping custom Python classes and how to expose its methods and properties to COM using the policy attributes
www.oreilly.com/catalog/pythonwin32/chapter/ch12.html—this is a sample chapter ("Implementing COM Objects in Python") from the the definitive guide Python Programming on Win32 which also explains working with COM; however, you can skip the CLSID/ProgID information because custom commands already return a fully created object.