Python Custom Modules (XSISDK)
Python has powerful ability to let you organize your code into modules (http://www.python.org/doc/current/tut/node8.html). It is an interesting way to organize your code into multiple script files. Modules are a Python feature, not a Softimage feature, but there are some tricks to make them work more succesfully inside of Softimage.
Since this article has been written, there have been some optimizations for working with custom python modules in Softimage.
|Table of contents|
Example Module Code
Imagine you have a Self-installed plugin and want to move some of the code into a Python Module. You don't want to hardcode the location of the module into your python environmental variables because the code needs to be placed on a workgroup and accessed by many users.
Here is an example self-installed plugin called ModuleDemo.py.
# Demonstration of a Self-installed plug-in # which uses a custom Python Module # # It shows how the python module could be # stored in the same workgroup or addon location # without the need to hardcode the PYTHONPATH # environmental variable for each user on the workgroup import win32com.client from win32com.client import constants null = None false = 0 true = 1 import sys def XSILoadPlugin( in_reg ): in_reg.Author = "askowron" in_reg.Name = "Python Module Demo" in_reg.Major = 1 in_reg.Minor = 0 in_reg.RegisterCommand("UsePythonModule","UsePythonModule") #RegistrationInsertionPoint - do not remove this line #Make sure that the location of our workgroup #based Python modules are part of the Python path, #This makes sure that the import statements doesn't fail pluginLocation = in_reg.OriginPath #in this case we assume the modules are stored a #Modules directory as a sibling to the plugin path, #e.g. \Application\Modules workgroupLibFolder = XSIUtils.BuildPath( pluginLocation, "..", "Modules" ) if workgroupLibFolder not in sys.path : sys.path.append( workgroupLibFolder ) Application.LogMessage( sys.path ) return true def UsePythonModule_Execute( ): #Import a file called Foo.py #We can't do the import at the top of the file #because we need to make sure the path has been #patched already by XSILoadPlugin import Foo #During development of Foo you will need to #call reload to force the module to reload itself #after you change its contents. Otherwise it is #cached in memory reload( Foo ) #Demonstrate that the methods are available Application.LogMessage(Foo.Foo()) Foo.PrintPropsOfSelectedObj() return true
It relies on this file, Foo.py, which should be stored in the \Application\Modules directory of your Workgroup or Addon.
# # Example python module for use by XSI # #The module doesn't automatically have access to #the global XSI objects, so this call would fail: #Application.LogMessage( "Loading Foo Module" ) #Instead we can create our own global #variables for XSIApplication and any other XSI intrinsic #objects we might want import win32com ap = win32com.client.Dispatch( 'XSI.Application' ).Application #Uncomment these lines if you want them #XSIFactory = win32com.client.Dispatch( 'XSI.Factory' ) #XSIMath = win32com.client.Dispatch( 'XSI.Math' ) #from win32com.client import constants as c #Basic Python routine def Foo(): return 7 #More interesting routine that is using the XSI Object Model #via our "ap" variable def PrintPropsOfSelectedObj(): for i in range(0,ap.Selection.Count): oObj = ap.Selection(i) ap.LogMessage( "%s has %s properties" % \ ( oObj.Name, oObj.Properties.Count ) )
Should Modules be Avoided?
Before decided to write your own modules you can also consider keeping all your code with-in self-installed plug-ins. You can have multiple plugins as a way of modularizing your code. By avoiding modules you won't have to do the special import and reload fixes and other workflow challenges described in this article.
Modules are clearly good if the code is not XSI specific and you want to access the same code from other scripts outside of XSI. Modules can also be great if you want to distribute the code once it is completely finished - you can send just the .pyc file and other people won't be able to see your code.
Explicitly Reload During Development
Python will cache your module script in memory even after you change it on disk, so you may need to call "Reload" as shown in the example above.
Accessing XSIApplication object inside the Module
The example above shows a workaround recreating an instance of the XSIApplication object as a global variable of your module. This lets you access the XSI scene within the Module.
import win32com ap = win32com.client.Dispatch( 'XSI.Application' ).Application
Location of the Module files
Normally you need to store your Module files inside your python installation. You can also update the PYTHONPATH environmental variable to extend the module search path.
However the example above shows how this path can be build "on-the-fly" via sys.path to give maximum location independence to your code. Location independence is most important when you want to distribute your code onto a XSI workgroup or inside an .xsiaddon because the module path could be different on each machine.