Last Updated: September 28, 2005
The version of Python used to build the STAF Python libraries is the only Python version that will work with those STAF Python libraries.
Once STAF's Python support is installed, you need to set/update your PYTHONPATH environment variable. On Unix, add the /usr/local/staf/lib directory to your PYTHONPATH, assuming you installed STAF to directory /usr/local/staf. On Win32, add the C:\STAF\bin directory to your PYTHONPATH, assuming you installed STAF to directory C:\STAF.
Finally, you simply need to import the modules described below.
Note: You can build STAF Python support yourself if you want to use a different version of Python or if you want STAF Python support for a different operating system. See the STAF Developer's Guide for more information on how to build the STAF python project. Or, you can submit a Support Request via the STAF SourceForge website for us to build it for you (but it may take a while until we get a chance to implement your request). Be sure to check the existing STAF Support Requests as we may have already provided STAF Python support for the Python version and operating system that you want and attached it to an existing STAF Support Request. For example, the following additional STAF V3 Python support is provided via the STAF Support Requests:
If you build STAF Python support for a different operating system and/or different Python version, please contribute it to the STAF project. To contribute it, browse the STAF Support Requests to see if someone else has already provided STAF Python support for this operating system and Python version combination. If not, open a STAF Support Request with the "Summary" containing "STAF V3 Support for Python x.x.x (Platform)", replacing x.x.x with the Python version and replacing Platform with the operating system on which you built the support. Attach the necessary file (e.g. PYSTAF.dll on Windows or PYSTAF.so for Unix) to the Support Request.
The STAF Python classes that it externalizes are:
The STAF Python functions that it externalizes are:
from PySTAF import *
Since the STAF Python libraries include several files with "PYSTAF" as their file name (with varying cases, i.e. PySTAF, PYSTAF), make sure that you are not using the "PYTHONCASEOK" environment variable. For example, if you have it set as "PYTHONCASEOK=1" and then try to use the STAF Python libraries, you will get the following error:
Traceback (most recent call last): File "TestPython.py", line 9, in ? from PySTAF import * ImportError: dynamic module does not define init function (initPySTAF)
To correct this error, set "PYTHONCASEOK=".
The required argument handleNameOrHandle specifies a handle name or number.
The optional argument handleType specifies the type of handle. Valid handle types are STAFHandle.Standard and STAFHandle.Static. The default is STAFHandle.Standard.
STAFHandle defines the following methods:
The required argument location specifies the endpoint of the machine where the service is registered.
The required argument service specifies the name of the service to submit the request to.
The required argument request specifies the request to submit to the service.
The optional argument mode specifies the mode to use when submitting the request. The default is STAFHandle.Synchronous. Other possible values are:
STAFHandle defines the following constants:
# STAFHandle types Standard = 0 Static = 1 # Modes for submit call Synchronous = 0 FireAndForget = 1 Queue = 2 Retain = 3 QueueRetain = 4Note, you can obtain more information on standard vs. static handles and the various submission modes in the C API reference in the STAF User's Guide.
from PySTAF import * import sys try: handle = STAFHandle("MyTest") except STAFException, e: print "Error registering with STAF, RC: %d" % e.rc sys.exit(e.rc) result = handle.submit("local", "ping", "ping") if (result.rc != 0): print "Error submitting request, RC: %d, Result: %s" % (result.rc, result.result) result = handle.submit("local", "var", "resolve string {STAF/Config/OS/Name}") if (result.rc != 0): print "Error submitting request, RC: %d, Result: %s" % (result.rc, result.result) else: print "OS Name: %s" % result.result rc = handle.unregister() sys.exit(rc)The following is an example which uses a static STAF handle to call STAF asynchronously and then waits for the result of the call to come back.
from PySTAF import * # Other code would be in here that obtains a static handle number from somewhere. # See section 5.2 of the STAF User's Guide for more information on static handles. try: handle = STAFHandle(staticHandleNumber, STAFHandle.Static) except STAFException, e: print "Error registering with STAF, RC: %d" % e.rc sys.exit(e.rc) result = handle.submit("local", "fs", "copy file /tmp/abc tomachine xyz", STAFHandle.Queue) if (result.rc != 0): print "Error submitting request, RC: %d, Result: %s" % (result.rc, result.result) requestNumber = result.result # At this point I can do some other work while the file transfer completes ... # And now, I want to wait until the request has completed result = handle.submit("local", "queue", "get contains %s wait") % \ STAFWrapData("STAF/RequestComplete %s;" % requestNumber)) # result.result now contains a message which includes the result of FS service request. # I can now check the result and/or continue with the rest of my script
The optional argument rc specifies the numeric return code
of the service request. The default is 0.
The optional argument result specifies a string result buffer
returned from the service request. The default is "".
STAFResult defines the following member variables. They are initialized by the constructor, and should not be modified directly.
STAFResult defines the following constants representing the various common STAF return codes.
Ok = 0 InvalidAPI = 1 UnknownService = 2 InvalidHandle = 3 HandleAlreadyExists = 4 HandleDoesNotExist = 5 UnknownError = 6 InvalidRequestString = 7 InvalidServiceResult = 8 REXXError = 9 BaseOSError = 10 ProcessAlreadyComplete = 11 ProcessNotComplete = 12 VariableDoesNotExist = 13 UnResolvableString = 14 InvalidResolveString = 15 NoPathToMachine = 16 FileOpenError = 17 FileReadError = 18 FileWriteError = 19 FileDeleteError = 20 STAFNotRunning = 21 CommunicationError = 22 TrusteeDoesNotExist = 23 InvalidTrustLevel = 24 AccessDenied = 25 STAFRegistrationError = 26 ServiceConfigurationError = 27 QueueFull = 28 NoQueueElement = 29 NotifieeDoesNotExist = 30 InvalidAPILevel = 31 ServiceNotUnregisterable = 32 ServiceNotAvailable = 33 SemaphoreDoesNotExist = 34 NotSemaphoreOwner = 35 SemaphoreHasPendingRequests = 36 Timeout = 37 JavaError = 38 ConverterError = 39 InvalidObject = 41 InvalidParm = 42 RequestNumberNotFound = 43 InvalidAsynchOption = 44 RequestNotComplete = 45 ProcessAuthenticationDenied = 46 InvalidValue = 47 DoesNotExist = 48 AlreadyExists = 49 DirectoryNotEmpty = 50 DirectoryCopyError = 51 DiagnosticsNotEnabled = 52 HandleAuthenticationDenied = 53 HandleAlreadyAuthenticated = 54 InvalidSTAFVersion = 55
# The variable "handle" is an instance of the STAFHandle class that was # previously instantiated result = handle.submit("local", "ping", "ping") print "Ping request RC: %d" % result.rc print "Ping request result buffer: %s" % result.result
The optional argument rc specifies the numeric return code which
is the basis of the exception. The default is 0.
The optional argument result specifies a string which further
describes the exception. The default is "".
STAFException defines the following member variables. They are initialized by the constructor, and should not be modified directly.
from PySTAF import * import sys try: handle = STAFHandle("MyTest") except STAFException, e: print "Error registering with STAF, RC: %d" % e.rc
The optional keyword argument name specifies the name of the STAF map class definition. The default is None.
STAFMapClassDefinition defines the following methods:
The required keyword argument keyName specifies the name of a key.
The optional keyword argument displayName specifies a string to use when displaying the key. The default is None which indicates to use the actual key name when displaying the key.
The required keyword argument keyName specifies the name of a key for which this property is being set.
The required keyword argument property specifies the name of the property being set. The only property name currently recognized is 'display-short-name' which is used by the STAF executable when displaying a result in a tabular format when the length of the values for the fields is less than the length of the 'display-name'.
The required keyword argument value specifies the value for the property being set.
myMapClassDef = STAFMapClassDefinition('Test/MyMap') myMapClassDef.addKey('name', 'Name') myMapClassDef.addKey('exec', 'Executable') myMapClassDef.addKey('testType', 'Test Type') myMapClassDef.setKeyProperty('testType', 'display-short-name', 'Test') myMapClassDef.addKey('outputList', 'Outputs') print "The keys for map class definition '%s' are:" % (myMapClassDef.name()) print formatObject(myMapClassDef.keys())
The keys for map class definition 'Test/MyMap' are: [ { display-name: Name key : name } { display-name: Executable key : exec } { display-name : Test Type key : testType display-short-name: Test } { display-name: Outputs key : outputList } ]
In order to use a map class when marshalling data, you must add the map class definition to the marshalling context, set the root object of the marshalling context to the object you want to marshall, and then marshall the marshalling context itself. When you unmarshall a data structure, you will always receive a marshalling context. Any map class definitions referenced by map classes within the data structure will be present in the marshalling context.
The primary use of this class is to represent multi-valued results that consist of a data structure (e.g. results from a QUERY/LIST service request, etc.) as a string that can also be converted back into the data structure. This string can be assigned to the string result buffer returned from the service request.
The optional keyword argument obj specifies the root object to be marshalled. The default is None.
STAFMarshallingContext defines the following methods:
The required argument mapClassDef specifies a STAFMapClassDefinition object that can be used when marshalling the object. You may call this method any number of times to set multiple STAFMapClassDefinition objects for the marshalling context.
The required argument mapClassName specifies a string containing the name of the MapClassDefinition object that you want to return.
The required argument mapClassName specifies a string containing the name of the MapClassDefinition object that you want to check if the marshalling context's contains in its list of map class defintions.
The required argument rootObject can specify any object.
# Create a map class definition myMapClassDef = STAFMapClassDefinition('Test/MyMap') myMapClassDef.addKey('name', 'Name') myMapClassDef.addKey('exec', 'Executable') testList = [ {'name': 'TestA', 'exec': '/tests/TestA.py'}, {'name': 'TestB', 'exec': '/tests/TestB.sh'}, {'name': 'TestC', 'exec': '/tests/TestC.cmd'} ] # Create a marshalling context with testList mc = STAFMarshallingContext() mc.setMapClassDefinition(myMapClassDef) myTestList = [] for test in testList: testMap = myMapClassDef.createInstance() testMap['name'] = test['name'] testMap['exec'] = test['exec'] myTestList.append(testMap) mc.setRootObject(myTestList) print 'Test List:\n%s' % (mc) # Create a string from the marshalling context # This string could be a message that you log or send to a queue, etc. stringResult = mc.marshall() # Convert the marshalled string representation back into a list mc2 = unmarshall(stringResult) theTestList = mc2.getRootObject()
Test List: [ { Name : TestA Executable: /tests/TestA.py } { Name : TestB Executable: /tests/TestB.sh } { Name : TestC Executable: /tests/TestC.cmd } ]
if isMarshalledData(result.result): mc = unmarshall(result.result)
The default for optional keyword argument context is None.
Note, normally you would use a STAFMarshallingContext object's marshall() method instead of this function.
myTestMap = {'name': 'TestA', 'exec': '/tests/TestA.py', 'testType': 'FVT', 'outputs': ['TestA.out', 'TestA.err']} message = marshall(myTestMap) result = handle.submit('local', 'QUEUE', 'QUEUE MESSAGE %s' % message) if result.rc != STAFResult.Ok: print 'QUEUE MESSAGE failed with RC=%s Result=%s' % (result.rc, result.result) sys.exit(1) # Another process could obtain the message from the queue and unmarshall # it to get the original dictionary (map) object result = handle.submit('local', 'QUEUE', 'GET MESSAGE') if result.rc == STAFResult.Ok: mc = unmarshall(result.result) yourTestMap = mc.getRootObject()
This example creates a marshalling context with one map class definition and a Python list where each entry is a map. It then creates a string-based marshalled representation of it.
myMapClassDef = STAFMapClassDefinition('Test/MyMap') myMapClassDef.addKey('name', 'Name') myMapClassDef.addKey('exec', 'Executable') testList = [ {'name': 'TestA', 'exec': '/tests/TestA.py'}, {'name': 'TestB', 'exec': '/tests/TestB.sh'}, {'name': 'TestC', 'exec': '/tests/TestC.cmd'} ] mc = STAFMarshallingContext() mc.setMapClassDefinition(myMapClassDef) myTestList = [] for test in testList: testMap = myMapClassDef.createInstance() testMap['name'] = test['name'] testMap['exec'] = test['exec'] myTestList.append(testMap) message = marshall(myTestList, mc)
The required keyword argument data is a string to be unmarshalled.
The optional keyword argument context specifies the STAFMarshallingContext object that should be used when generating when unmarshalling the string. The default is None.
The optional keyword argument flags can be used to control how to unmarshall the string. When a string is unmarshalled into a data structure, it is possible that one of the string objects that is unmarshalled is itself the string form of another marshalled data structure. The default is UNMARSHALLING_DEFAULTS which will recursively unmarshall these nested objects. Use IGNORE_INDIRECT_OBJECTS to disable this additional processing.
fileName = 'C:/tests/testA' result = handle.submit('local', 'FS', 'QUERY ENTRY %s' % fileName) if result.rc != STAFResult.Ok: print 'FS QUERY ENTRY %s failed' % fileName print 'RC=%s Result=%s' % (result.rc, result,result) sys.exit(1) mc = unmarshall(result.result) entryMap = mc.getRootObject() if entryMap['type'] == 'F': print 'File %s has size %s and was last modified on %s' % \ (fileName, entryMap['lowerSize'], entryMap['lastModifiedTimestamp']) else: print '%s is not a file. Type=%s' % entryMap['type']
The required keyword argument obj specifies the object to be formatted in a verbose, more readable format.
The optional keyword argument context specifies the STAFMarshallingContext object that should be used when generating the "pretty print" output. The default is None.
The optional keyword argument indentLevel controls the indentation level used when generating the "pretty print" output. The default is 0.
The optional keyword argument flags is not currently used (it's for future use). The default is 0.
myTestMap = {'name': 'TestA', 'exec': '/tests/TestA.py', 'testType': 'FVT', 'outputs': ['TestA.out', 'TestA.err']} print formatObject(myTestMap)
{ outputs : [ TestA.out TestA.err ] testType: FVT name : TestA exec : /tests/TestA.py }
This example prints the result from a FS QUERY ENTRY request in a "pretty" verbose format:
fileName = '{STAF/Config/ConfigFile}' result = handle.submit('local', 'FS', 'QUERY ENTRY %s' % fileName) if result.rc != STAFResult.Ok: print 'FS QUERY ENTRY %s failed' % fileName print 'RC=%s Result=%s' % (result.rc, result,result) sys.exit(1) mc = unmarshall(result.result) print 'Formatted output:\n%s' % formatObject(mc.getRootObject(), mc)
Formatted output: { Name : c:\staf\bin\STAF.cfg Type : F Upper 32-bit Size : 0 Lower 32-bit Size : 5902 Modified Date-Time: 20050322-11:07:02 }
print 'Formatted output:\n%s' % (mc)
Note that STAFWrapData is an alias for the wrapData function and can be used instead to call this function.
outputString = wrapData("Hello world")
semName = "My Synch Sem" result = handle.submit("local", "sem", "event %s post" % wrapData(semName))
This method should be used by anyone who wants to protect private data specified in a STAF command option that supports handling private data.
Required argument data is a String that contains data you want to protect.
Returns a String object containing the string with opening and closing privacy delimiters added and escapes any privacy delimiters already contained in the string with a caret (^). If the string has length 0 or already has an unescaped opening privacy delimiter at the beginning and an unescaped closing privacy delimiter at the end, privacy delimiters are not added.
Examples:
Since: STAF V3.1.0
Note that STAFAddPrivacyDelimiters is an alias for the addPrivacyDelimiters function and can be used instead to call this function.
password = addPrivacyDelimiters('passw0rd') request = 'START COMMAND C:/tests/TestA USERNAME Test1 PASSWORD %s' % (password) result = handle.submit('local', 'PROCESS', request);
command = 'C:/tests/admin -password %s' % (addPrivacyDelimiters('secret')) request = 'START COMMAND %s" % (wrapData(command)) result = handle.submit('local', "PROCESS", request)
This method should be used before calling the addPrivacyDelimiters method for data that needs to be protected but may contain substrings !!@ and/or @!! that should not be mistaken for privacy delimiters .
Required argument data is a String.
Returns a String object containing the updated data.
For example, if the data is 'passw@!!d', this method would return 'passw^@!!d'.
Since: STAF V3.1.0
Note that STAFEscapePrivacyDelimiters is an alias for the escapePrivacyDelimiters function and can be used instead to call this function.
password = addPrivacyDelimiters(escapePrivacyDelimiters('passw@!!d')) request = 'START COMMAND C:/tests/TestA USERNAME Test1 PASSWORD %s' % (password) result = handle.submit('local', 'PROCESS', request);
Required argument data is a String that may contain privacy delimiters (e.g. !!@, @!!).
Optional argument numLevels in an int that specifies the number of levels of privacy data to remove. The default is 0 which indicates to remove all levels of privacy data. Note that, generally, you'll want to remove all levels of privacy delimiters.
Returns a String object containing the updated data with privacy delimiters removed.
Examples:
Since: STAF V3.1.0
Note that STAFRemovePrivacyDelimiters is an alias for the removePrivacyDelimiters function and can be used instead to call this function.
protectedPassword = '!!@secret@!!' password = removePrivacyDelimiters(protectedPassword)
Required argument data is a String that may contain privacy delimiters (e.g. !!@, @!!).
Returns a String object containing the string with any private data masked.
Examples:
Since: STAF V3.1.0
Note that STAFMaskPrivateData is an alias for the maskPrivateData function and can be used instead to call this function.
request = 'START COMMAND C:/tests/TestA.exe USERNAME Test1 PASSWORD %s' % \ (addPrivacyDelimiters('passw0rd')) print maskPrivateData(request)
from PySTAFMon import *
The required keyword argument stafHandle specifies the STAF handle to use to submit the request to the Monitor service.
The optional keyword argument system specifies the endpoint of the machine to submit the request to. The default is "local".
The optional keyword argument service specifies the registered name of the STAF Monitor service. The default is "Monitor".
Note: By default, the STAFMonitor class will use the service named "Monitor" on the local system. This can be changed by explicitly specifying the system and/or service when you construct the STAFMonitor object.
STAFMonitor defines the following methods:
The required keyword argument message specifies the message to log.
from PySTAFMon import * # The variable "handle" is an instance of the STAFHandle class that was # previously instantiated monitor = STAFMonitor(handle) result = monitor.log("Beginning section ABC of test")
from PySTAFLog import *
The required keyword argument handle specifies the STAF handle to use to submit the request to the Log service.
The required keyword argument logType specifies the log type (e.g. STAFLog.Global, STAFLog.Machine, or STAFLog.Handle)
The required keyword argument name specifies the name of the log.
The optional keyword argument monitorMask specifies a mask that consists of a list of logging levels. This list controls which messages are also sent to the Monitor service. The default is to enable "Fatal", "Error", "Warning", "Start", "Stop", "Pass", and "Fail". If there is an error logging, STAFLog will also try to send an error to the Monitor service.
The optional keyword argument system specifies the endpoint of the machine to submit the log request to. The default is "local".
The optional keyword argument service specifies the registered name of the STAF Log service. The default is "Log".
Note: By default, the STAFLog class will use the service named "Log" on the local system. This can be changed by explicitly specifying the system and/or service when you construct the STAFLog object.
STAFLog defines the following methods:
The required keyword argument level specifies the logging level (e.g. STAFLog.Info, STAFLog.Error, etc.
The required keyword argument message specifies the message to log.
STAFLog defines the following constants:
# Log type constants Global = "GLOBAL" Machine = "MACHINE" Handle = "HANDLE" # Log level constants Fatal = "Fatal" Error = "Error" Warning = "Warning" Info = "Info" Trace = "Trace" Trace2 = "Trace2" Trace3 = "Trace3" Debug = "Debug" Debug2 = "Debug2" Debug3 = "Debug3" Start = "Start" Stop = "Stop" Pass = "Pass" Fail = "Fail" Status = "Status" User1 = "User1" User2 = "User2" User3 = "User3" User4 = "User4" User5 = "User5" User6 = "User6" User7 = "User7" User8 = "User8" # Log service return codes InvalidLevel = 4004 InvalidLogFileFormat = 4007 PurgeFailure = 4008
from PySTAFLog import * # The variable "handle" is an instance of the STAFHandle class that was # previously instantiated # Let's create a machine based log file that also sends fatal, error, and # warning messages to the Monitor service log = STAFLog(handle, STAFLog.Machine, "MyLog", [STAFLog.Fatal, STAFLog.Error, STAFLog.Warning]) # This message will only go to the log service, since we didn't specify # that start message get sent to the Monitor service result = log.log(STAFLog.Start, "Beginning ABC test") # This message will be sent to the Log and Monitor services result = log.log(STAFLog.Warning, "Got some ambiguous result")