Guru: Calling RPG Programs From Python, Part 2
April 27, 2020 Mike Larsen
In Calling RPG Programs From Python, Part 1, I showed how to call an RPG program from a Python script passing single string parameters as input and output. In the second part of this series, I’ll make the process a little more robust by passing a data structure to the RPG program.
The first part of the Python script (shown in the first piece of code below) imports the itoolkit modules and assigns them to local names. Next, I set up the first command that adds a library list entry to where the RPG object resides.
from itoolkit import * from itoolkit.lib.ilibcall import * itool.add(iCmd('addlible', 'addlible mllib'))
So far, the code is the same as in the first article. The next part, however, is where we start to see some differences. Since I’m passing a data structure to the RPG program in addition to the string input and output parameters, I needed to add some code to the iPgm function:
itool.add( iPgm('my_results','Mlr101Tk') .addParm(iData('InFirstName','10a','Mike')) .addParm( iDS('Address') .addData(iData('Street','25a','123 Main Street')) .addData(iData('City','25a','Washington Township')) .addData(iData('State','2a','NJ')) .addData(iData('Zip','5p0','07676')) ) .addParm(iData('OutLastName','10a',' ')) .addParm(iData('OutAddress','75a',' ')) )
Here, I added the call to my program, Mlr101Tk, and assigned the output to the variable, my_results. Notice that in this example, I have four parameters (indicated by addparm) instead of the two that I had last time. While the first and third parameters are the same, the second and fourth were added. The second parameter defines a data structure, iDS, that contains an address. Within the data structure, I defined parameters for street, city, state, and ZIP code. The data type and length of each parameter must match what the RPG program is expecting. I also supplied values for each of the parameters that will be used in the RPG program. The fourth parameter is passed back from the RPG program and will contain a formatted address. The formatted address will be a concatenation of the street, city, state, and zip being passed.
I used the iLibCall function to add the library list entry and call the RPG program. Once again, I assigned the results to the variable, mypgm_results:
itool.call(itransport) # results are returned as a dictionary formatted as Json mypgm_results = itool.dict_out('my_results')
Let’s look at the RPG program before going any further so you can see what it does. Here I defined a data structure to match the Python script:
dcl-ds AddressDs qualified template; Street char(25); City char(25); State char(2); Zip packed(5:0); end-ds;
This next piece of code shows the parameters coming into the RPG program. Note that the parameters are in the same order as defined in the Python script.
// - - - - - - - // Prototypes (entry parameters) dcl-pr Mlr101Tk ExtPgm; inFirstName char(10); Address likeds(AddressDs); outLastName char(10); outAddress char(75); End-pr; // - - - - - - - // Main procedure interface dcl-pi Mlr101Tk; inFirstName char(10); Address likeds(AddressDs); outLastName char(10); outAddress char(75); end-pi;
As was the case in the first article, the rest of the program is very simple. I populate the output parameter, outLastName, with a value of Larsen, and populate the output parameter outAddress as a single string from the Address data structure passed in.
If %trim(inFirstName) = 'Mike'; outLastName = 'Larsen'; Else; outLastName = 'Smith'; Endif; // format the address passed in as one string and send it back to the // Python script. outAddress = %trim(Address.Street) + ' ' + %trim(Address.City) + ', ' + %trim(Address.State) + ' ' + %editc(Address.Zip:'X');
Now, I fire up an SSH terminal and execute the Python script.
The result from this program contains a bit more information than the last time. While I can still read it easily, I thought I’d make it print a little nicer. I added some code to the Python script to pretty print the resulting JSON and I also printed the formatted address on a separate line:
mypgm_results = itool.dict_out('my_results') # Pretty Printing JSON string back print(json.dumps(mypgm_results, indent = 4)) print('\n') print ("Formatted address from RPG: " + mypgm_results['OutAddress'])
This screen shot shows the results when printed to the terminal.
Integrating Python and RPG has been made very easy by using itoolkit. I’m looking forward to seeing what else I can do with it.