An Introduction to Python on IBM i, Part 1
August 25, 2010 Timothy Prickett Morgan
Note: All of the files needed for this article are available for in one download here.
When we think of programming on IBM i, our minds usually turn to the venerable RPG, or maybe CL. Some of us will think of ILE C, and those who frequently entertain dinner guests from IBM will have the word “Java” seared into their brain, and mistakenly use “EGL” instead of friends’ names. However, ask a UNIX or Linux aficionado to name a scripting language, and they will probably come up with Perl, Ruby, or very likely, Python.
Python was created as an educational language. Consequently, Python is simple to learn, generally lacks legacy cruft found in just about every other language, and has a formality in its approach that is easier to understand than Perl, but not as daunting as Java. Python is an object-oriented language, but so casual in its syntax that you will hardly know it.
Python exists on just about any platform you can think of, from Android-powered cell phones to OpenVMS clusters. This cross-platform availability makes it an ideal candidate as a standard language in any company, as programmers can work on any platform and not exist in a UNIX, Windows, or OS/400 ghetto. The OS/400 port of Python was created by Per Gummedal, and the Website and forum maintenance is the hard work of Aaron Fransen. I wish to thank both for their vital efforts in providing this superb programming language to this great platform.
Finally, Python is free. You can install it on as many machines as you like, whatever tier, however many processors or sockets, and the price is always the same.
The first step on your road to enlightenment is to install Python on your iSeries machines. This involves restoring three save files, which are available here.
The files you need are python25.zip, lib25.zip, and python.zip. Download these onto your desktop computer and uncompress them. The last save file contains an updated version of the Python service program. This service program is not 100 percent required, but I recommend you get it.
If you have a normal method for copying save files to your iSeries, use that method. Otherwise, follow the instructions on the www.iseriespython.com website, which you can find here.
I made some changes, as these instructions seem to contain a couple of errors that prevented installation on my machine.
1. Create the library in which Python will reside:
2. Create two save files to populate with the save files you downloaded:
CRTSAVF PYTHON25/PYTHON25 CRTSAVF PYTHON25/LIB CRTSAVF PYTHON25/PYTHON
3. Create two IFS directories:
MKDIR '/usr/python2.5' MKDIR '/usr/python2.5/LIB'
4. Use FTP to upload the save files to your iSeries. In the command line FTP client on your desktop computer, enter the following:
5. Restore the objects:
RSTOBJ OBJ(*ALL) SAVLIB(PYTHON25) DEV(*SAVF) SAVF(PYTHON25/PYTHON25) RSTOBJ OBJ(*ALL) SAVLIB(PYTHON25) DEV(*SAVF) SAVF(PYTHON25/PYTHON) RST '/QSYS.LIB/PYTHON25.LIB/LIB.FILE' OBJ(('/usr/python2.5' '*INCLUDE' '/usr/python2.5'))
6. The next step is to change a system value so that Python can run with no default locale. This means that Python will be able to read and write simple system values such as the date in the format that it expects. It is recommended you choose option “c” for a live system. Then . . .
a) Change the system default:
CHGSYSVAL QLOCALE '/QSYS.LIB/NO_NO.LOCALE'
b) Change one user:
CHGUSRPRF username LOCALE('/QSYS.LIB/NO_NO.LOCALE')
c) Change the current job:
ADDENVVAR ENVVAR(LANG) VALUE('/QSYS.LIB/NO_NO.LOCALE')
7. And you’re done! You can now launch the Python interpreter:
Key your first line of Python: print “Hello!” And press “Enter.”
You now have a working Python system, and you’re ready to write your first Python script.
A Very Basic Script
Python scripts are stored as stream files in the IFS. You can write your scripts in any editor you like. From a green screen session, you can use EDTF. I like to use a graphical editor with syntax highlighting, and open the file over FTP or SFTP. TextWrangler is a good choice on the Mac. If you’re using Windows, Linux, or UNIX, try JEdit. Both are free, and both can open files directly over FTP.
Here is the first script, hello.py, which you can download here.
def main(): i = 0 while i < 10: print str(i)+") Hello" i += 1 main()
If you like, you can copy this code and paste it directly into your stream file, but you need to be aware of a couple of things.
If you like, you can copy this code and paste it directly into your stream file.
Python requires code to be indented to indicate where blocks start, so there is one tab before “i = 0”, and two tabs before the print statement. This is very important to Python, and also enforces a clean writing style.
Let’s go through this script line by line:
The first line defines a function with the name of main. A set of parentheses in which we can define parameters that are passed to the function follow the function name. In this case there are no parameters. Ending the line with a colon tells Python that a block of code follows.
In the main function, we first define a variable, and set it to the value of 0. In Python, you don’t need to say what type of variable it is, such as character, integer, decimal, etc. You just give a variable a name and set it to a value. Python works out the rest.
Now we start a “while” loop. This is very similar to a “while” loop in most other languages. In English, we are saying “while the value of i is less than 10, repeat this block of code”. Again, we end the line with a colon to tell Python that a block of code is next. In the block of code, the first word “print”, rather predictably, prints whatever line follows. On UNIX systems, print would print to your screen or terminal. On the iSeries, the printed data goes straight into a spool file. After the print statement, we have the str() function, which converts just about any value into a string (a stream of characters). Using str() allows us to join the value of the numeric value of i to to the character string “) Hello”.
The final line of the while loop adds 1 to the variable “i”, so each time the loop is iterated, i increases by one. After 10 loops, i will equal 10 and the loop will exit. The expression i += 1 is a quick shorthand for “i = i + 1” or “add 1 to i”.
Now we have exited the while loop, and as the end of the loop is the last line in the function, we exit the function, too.
The last line in the file calls the main() function. Without this line, Python would interpret the file, but not know where to enter processing, and exit. Since Python doesn’t require header files or prototypes, we could just as easily call main() before it is defined. Python will race through the file and find the function for us.
To run the Python script, type PYTHON25/PYTHON on a CL command line and press F4.
Enter the path to the script, which will be something like:
Press Enter and the script will run. If entered correctly, the command line will reappear immediately. Use WRKSPLF to look at spool files, page down to the bottom of the list, and display the last QPRINT spool file. You should be greeted with:
0) Hello 1) Hello 2) Hello 3) Hello 4) Hello 5) Hello 6) Hello 7) Hello 8) Hello 9) Hello
Let’s try something a little more useful.
This time we’re going to use Python to do something bordering on helpful. This script takes a tab-separated stream file of customer details, and for each customer, checks if he/she has a valid email address and logs a suitable message to the spool file. This script is available to download here.
def file_read(filename): fh = open(filename,"r") data = fh.read() fh.close() return data def main(): data = file_read("/home/garry/customers.txt") lines = data.split("n") #Split on a line feed for line in lines: cols = line.split("t") #Split on a tab email = cols if email.find("@") != -1: print "'" + email + "' appears to be a valid email address" else: print "'" + email + "' does not seem to be a real email address" main()
This script contains two functions. The main() function is the first function to run. You can call your functions just about anything you like. I have called it main(), as this is what the first function called is named in C. The other function, file_read(), takes one parameter, the name for a stream file. The file is opened, all data read from it and stored in a variable called “data”. The file is then closed, and the data is returned out of the function to where the function was called from. It is prudent to make tiny functions like this for just about everything. That way if you want to put in some error handling or debug print statements, you only need to put it in one place, and not all over your program. You will also notice a lot of “#” characters in this script. These are for commenting in Python. Any text after a “#” is ignored until the end of the line.
The main() function calls file_read() to get the contents of the stream file, then splits up the file on a line feed, putting each line in its own element of a tuple (a list, a sort of array). Now we can iterate over those lines with the “for” statement. The for statement is saying “For each item in this list, do this…”, so it is very much like a while loop, except that rather than check the statement is true for each loop, it runs the loop until it runs out of items in the list.
Now we’re into the block of code run by the “for” statement, and the first action is to again use the “split” method on the line, this time we split on a tab (“t”), so that each line is split into a tuple that contains each bit of information about a single customer. As it happens, the stream file contains data like this:
name<tab>email<tab>phone<linefeed> name<tab>email<tab>phone<linefeed> name<ta....
You can download this file here.
Name is element 0, email is element 1, and phone is element 2. So in our script we can make a new variable to hold email, by setting it to the value contained in cols, i.e., element 1 in the “cols” tuple. Now we can use the “find” method in the string to search for an “@” symbol. If an “@” symbol is found, its index in the string will be returned, otherwise the value -1 is returned. So now we can use an “if” statement to decide which print statement to use. The above “if” statement is saying: If the index of “@” in variable email is not -1, then print that the email address is valid, else print that it is not a valid email address. Now, the fact that this string contains an “@” symbol is not complete proof that the email address is valid, but it is enough as a quick demonstration.
On running this new script, check your spool files again. You should see output of:
'email@example.com' appears to be a valid email address 'nadine.company.com' does not seem to be a real email address 'firstname.lastname@example.org' appears to be a valid email address 'damo.ibm.com' does not seem to be a real email address
So in this case, our script has correctly determined what is a valid email, and what is not.
What We Have Learned, and Will Learn
In part one of this introduction to Python, we have learned how to create a couple of simple Python scripts and execute them. We have used what are possibly the two most vital constructs in any programming language: “while” and “if”. If you are new to object-oriented techniques, it may also surprise you to learn that you have been using them. The strings are in fact Python objects, and the “split” and “find” capabilities are in fact methods within these objects.
We have also learned how to open, read from, and close stream files, work with their content, and react differently based on what we find in the content.
In part two of this series, we will discover how to access built in SQL features in OS/400 using Python. We’ll set up databases, insert data, and learn how Python makes it very easy indeed to use the superb SQL features in IBM i. We will also learn how to better integrate Python into existing workflows and jobs, using its strengths to complement native CL or RPG programs.
Garry Taylor is a professional software developer, working with IBM i, Solaris, and Mac. Based in London, Garry is a co-founder of The Escapers, and developer for Kisco Information System. Send your questions or comments for Garry to Ted Holt via the IT Jungle Contact page.