Python on z/OS advanced C extension

I found that to create a standard Python package with a C extension, the package has a very specific name – depending on the level of Python, the level of z/OS, the hardware the z/OS is running on. To be able to build a package for all levels of z/OS this would be a near impossible job; because I do not have access to every combination of z/OS hardware and software.

I’ve found a way to get round it. It took a few days to get it right, but it is pretty simple.

The standard way of packaging.

With the normal way of packaging the C executable module is stored deep in the Python tree, for example

/u/tmp/python/usr/lpp/IBM/cyp/v3r10/pyz/lib/python3.10/site-packages/pymqi-1.12.0-py3.10-os390-27.00-1090.egg/pymqi/pymqe.cpython-310.so

The easy way of using it

You can copy this file, for example to my working directory. I copied it as pymqe.so.

My Python program was

import pymqe
print(dir(pymqe))
name = “CSQ9”
rv = pymqe.MQCONN(name)
print(“rv”,rv)

This locates pymqe*.so in the current directory. It located pymqe.so; if I renamed it to pymqe.cpython-310.so it also worked.

You can put the .so object in the PYTHONPATH environment variable, and have it picked up from there.

When the file is imported, an initialisation routine is invoked which defines all of the Python entry points. You can see them using the dir(pymqe) statement. This gave me

[‘MQBACK’, ‘MQCLOSE’, ‘MQCMIT’, ‘MQCONN’, ‘MQCONNX’, ‘MQCRTMH’, ‘MQDISC’, ‘MQGET’, ‘MQINQ’, ‘MQINQMP’, ‘MQOPEN’, ‘MQPUT’, ‘MQPUT1′,’MQSET’, ‘MQSETMP’, ‘MQSUB’, ‘doc’, ‘file’, ‘loader’, ‘mqbuild’, ‘mqlevels’, ‘name’, ‘package’, ‘spec_ _’, ‘__version’, ‘pymqe.error’]

When the module is loaded Python looks for the entry name PyInit_… where … is the name of the module. For pymqe.so it looks for PyInit_pymqe. If you rename the module to mq.so and import mq, you get

ImportError: dynamic module does not define module export function (PyInit_mq)

The rv=pymqe.MQCONN invokes the MQ function which returns a handle, a return code and a reason code. For me it printed

rv (549309464, 0, 0)

So .. overall an easy solution.

I could find no way of using a load module from a PDSE, so it looks like the PYTHONPATH, or current directory is best for this.

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 )

Facebook photo

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

Connecting to %s