The Python wrapper for Platform LSF APIs allows users to call the LSF APIs from Python. You create a Python wrapper using the Simplified Wrapper and Interface Generator (SWIG), which is the tool used for interfacing the LSF C APIs and Python.
You are encouraged to contribute your own Python wrappers to the open source LSF APIs for Python on GitHub: https://github.com/PlatformLSF/platform-python-lsf-api.
In the Python wrapper for the LSF V9.1.2 APIs, the function typemap(in) char** that converts a Python string array to a C char** in C has been removed because of a bug in this function when the input string arrays are not NULL terminated. The following example shows another interface to handle the mapping from string arrays in Python to char ** in C.
$ cat test1.py from pythonlsf import lsf strArr = lsf.new_stringArray(1); # Create a new stringArray, length 1 lsf.stringArray_setitem(strArr, 0, "normal"); # Set its value intp_num_queues = lsf.new_intp(); # Create an int ptr lsf.intp_assign(intp_num_queues, 1); # Set the int value, which is the queue number if lsf.lsb_init("test") > 0: # LSB initialization exit(-1); queueInfo = lsf.lsb_queueinfo(strArr,intp_num_queues,None,None,0); # Query queue info if queueInfo == None: exit(0); print ’queue name = %s’ % queueInfo.queue; print ’queue description = %s’ % queueInfo.description; $ python test1.py queue name = normal queue description = For normal low priority jobs, running only if hosts are lightly loaded.
LSF APIs support multiple entities to be queried and returned, and similar APIs in Python are needed the LSF Python wrapper, for example, to return multiple queueinfo entities from lsf.lsb queueinfo(). You need to generate the required Python interface in accordance with LSF C APIs and SWIG. The following example uses the LSF C API lsb queueinfo() to demonstrate how to extend the Python LSF wrapper.
PyObject * get_queue_info_by_name(char** name, int num) { struct queueInfoEnt* queueinfo; int numqueues = num; int options = 0; queueinfo = lsb_queueinfo(name, // Return queries as C queueInfoEnt* &numqueues, NULL, 0, options); PyObject *result = PyList_New(numqueues); // Create PyObject * to get C returns int i; for (i = 0; i < numqueues; i++) { // Save queries in a loop to result PyObject *o = SWIG_NewPointerObj(SWIG_as_voidptr(&queueinfo[i]), SWIGTYPE_p_queueInfoEnt, 0 | 0 ); PyList_SetItem(result,i,o); } return result; }
$ python setup.py build $ sudo python setup.py install
$ cat test2.py from pythonlsf import lsf strArr = lsf.new_stringArray(2) # Create a new stringArray, length 2 lsf.stringArray_setitem(strArr, 0, "normal") # Set the 1st queue name lsf.stringArray_setitem(strArr, 1, "public") # Set the 2nd queue name if lsf.lsb_init("test") > 0: # LSB initialization exit(-1); for queueInfoEnt in lsf.get_queue_info_by_name(strArr, 2): # Query the queue info in batch if queueInfo == None: exit(0); print 'queue name = %s' % queueInfoEnt.queue; print 'queue description = %s\n' % queueInfoEnt.description; $ python test2.py queue name = normal queue description = For normal low priority jobs, running only if hosts are lightly loaded. queue name = public queue description = public queue
When you query a list of queues with one or more non-existing queue names, the Python API get queue info by name() returns ”[None]” value. You might expect the entities of existing queue names be returned, but this is the designed behavior. The following example shows how to test this:
$ cat test4.py from pythonlsf import lsf strArr = lsf.new_stringArray(2) lsf.stringArray_setitem(strArr, 0, "normal") lsf.stringArray_setitem(strArr, 1, "doesnotexist") if lsf.lsb_init("test") > 0: exit(-1); print lsf.get_queue_info_by_name(strArr, 2) $ python test4.py [None]
The low-level LSF C function lsb_queueinfo() returns NULL in case of any errors in user-specified arguments in queue, host, or user names. You can verify this with the LSF bqueues command, which internally calls lsb_queueinfo():
The following bqueues command shows normal output for two queues that exist:
$ bqueues normal public QUEUE_NAME PRIO STATUS MAX JL/U JL/P JL/H NJOBS PEND RUN SUSP normal 30 Open:Active - - - - 0 0 0 0 public 35 Open:Active - - - - 0 0 0
If you specify a queue name that does not exist, an error message is displayed and no other output is shown:
$ bqueues normal doesnotexist doesnotexist: No such queue
This is consistent with the Python API test.
By specifying the requested resource, LSF APIs support all entities of the specified resource to be returned, and the LSF Python wrapper need similar APIs for Python, for example, to return all queueinfo entities from lsf.lsb queueinfo(). You need to generate the required Python interface in accordance with LSF C APIs and SWIG. The following example uses the LSF C API lsb queueinfo()to demonstrate how to extend the Python API.
PyObject * get_queue_info_all() { struct queueInfoEnt *queueinfo; char *resreq; int numqueues = 0; int options = 0; resreq=""; queueinfo = lsb_queueinfo(resreq, // Return queries as C queueInfoEnt* &numqueues, NULL, 0, options); PyObject *result = PyList_New(numqueues); // Create PyObject * to get C returns int i; for (i = 0; i < numqueues; i++) { // Save queries in a loop to result PyObject *o = SWIG_NewPointerObj(SWIG_as_voidptr(&queueinfo[i]), SWIGTYPE_p_queueInfoEnt, 0 | 0 ); PyList_SetItem(result,i,o); } return result; }
$ python setup.py build $ sudo python setup.py install
$ cat test3.py from pythonlsf import lsf if lsf.lsb_init("test") > 0: # LSB initialization exit(-1); for queueInfoEnt in lsf.get_queue_info_all(): # Query all queues info in batch if queueInfo == None: exit(0); print 'queue name = %s' % queueInfoEnt.queue; print 'queue description = %s\n' % queueInfoEnt.description; $ python test3.py queue name = owners queue description = For owners of some machines. Only users listed in the HOSTSsection can submit jobs to this queue. ... ... ... queue name = interactive queue description = For interactive jobs only queue name = idle queue description = Running only if the machine is idle and very lightly loaded.