Python references and notes for labs 9 and 10

Python references:

Tutorial:
http://docs.python.org/tut/tut.html

Library reference:
http://docs.python.org/lib/lib.html

CGI Interface Suppoort:
http://www.python.org/doc/lib/module-cgi.html

Connecting to a PostgreSQL database - short example below
PyGreSQL - Python Interface

Python can be run from the command line either interactively, or by writing a file of python code, which will be executed.
For example:
python

python myprog.py

./myprog.py
In the last case, your first line must be
#!/usr/bin/python
When you run interactively, if you type a value, such as a variable or function on a line, you see the value. Errors, you can redo. Please practice this on timetable, only apache has rights to election/votes.

How to run python scripts

  1. Put the script in your public_html directory. Make it executable, [chmod a+x fleas.py] and be sure it has the #!/.... line, see above.
  2. The form action is "/cgi-bin/youracct/yourprog.py"
    This is done by a "link" in the server's "cgi-bin" directory. cgi-bin effectively clues the server into executing the program. Note: you can also refer to your perl scripts this way now.
  3. A link back must be out of cgi-bin, thus: <a href="/~youracct/yourform.html"> and similarly for an image.

How to debug, find syntax errors

Apache is configured to NOT send any error messages from python scripts to the browser, this is a security feature. Thus if there should be any syntax errors, you will see a blank page.
You will have to run the program from the command line, to see your syntax error messages. You can do this locally in the j-118 lab, or on Osiris. Execution errors can also be seen this way, but they will just result in abbreviated output in a browser (no error message visible).

If you don't have syntax errors, and still you see a blank page, you forgot to write the header, next item:

Write the header

The first thing a CGI program writes must be the content type:
print "Content-type: text/html\n"

Getting form data in python:

Here is a program to process the query string: foo=apple&foo=orange&dog=fido (foo is a select-multiple, perhaps)
#!/usr/bin/python
import cgi #helpful module that decodes the query string
form = cgi.FieldStorage() #form is now an object with the form data
dogname = form.getvalue("dog") #a string
fruits = form.getlist("foo") #a list of strings (0, 1, 2, ... items)
print "Content-type: text/plain\n"
print "My dog ", dogname, " has fleas, and she likes:"
for fruit in fruits:
print "\t", fruit #note that loop body must be indented
print "----------------------" #outside the loop

This actually works, and here is my html version example

Caution: Select multiple

This is no problem in Python, you will get a list. But do use getlist() so that you will always get a list, be it of 0 or 1 item.

Writing as text/html:

Be sure to use html encoding for any context in which it is expected. This includes new lines, which are simply "whitespace" to html, unless you add a <br> tag, or you enclose all of the "plain" text in <pre>   </pre> tags, which preserve the spacing of all "whitespace". This is good for program listings. But even here, you need to encode <, >, and & as entities, because some tags are recognized inside of <pre>
vhtml = cgi.escape(value)		#escapes <>&
vhtml = vhtml.replace('\n','<br>\n') #want <br> in textarea value outside of <pre>

Writing to a file:

You must always create your file and make it writable before letting Apache execute your script.
	chmod a+rw myguestbook.txt
You need to give the complete path name. In the script you need to open the file for writing or appending (writing starting from the current end), write what you want, then close. In this example, I have also "rewound" the file and read it all back, printing into a <pre> tag. Note also the try-except method of handling failure to open.
# write to a log file
try:
log=open("/home/jensen/public_html/quiz2.txt",'a') #log is the file object, open to append log.write("%s likes %s at %s\n"%(dogname,fruits,now) ) log.close()
print "<br><i>Logged your submission</i>"
except:
print "Trouble opening file"

Sending mail

Mail is sent by indirectly opening a pipe to sendmail. To be continued... Look at www.python.org here's their simple example:
# 	Import smtplib for the actual sending function
import smtplib

# Import the email modules we'll need
from email import MIMEText # Present version, this may change
myletter = "Hello Lin,\nThis is coming from Python\n" #sample message
msg=MIMEText.MIMEText(myletter)

# me == the sender's email address
# you == the recipient's email address
# another == another recipient's email address

# add headers to the msg object
msg['Subject'] = 'Sombody filled your form'
msg['From'] = me
msg['To'] = you #either yourself, or person who filled the form

# Send the message via our own SMTP server, but don't include the
# envelope header.
s = smtplib.SMTP()
s.connect()
s.sendmail(me, [you, another], msg.as_string())
s.close()

Database connections

A CGI program will connect to the local psql server as user "apache", you have to give apache permissions for what you want your script to do. Apache has select permission on timetable.
There are two python modules for PostgreSQL, this is the simple "classic" one. The new one is more complex, named pgdb.
import pg			#python's postgres module
con=pg.connect('timetable') #make a connection to database
#do some SQL queries
try:
result = con.query("select email from students where linux='tcort'")
except:
print con.error #if trouble, print the error message from database

print result # it is human-readable, just like psql
# or you can get a list of lists (2-D array)
rows = result.getresult() # which is machine-processable
dicts = result.dictresult() # or a list of dictionaries

con.close() # close the connection
Now, for example, you can refer to the first row and column of the result by either rows[0][0] or dicts[0]['email'].
You can also use for loops to go through a large result.

Safety in form data

You will notice that single quote plays a special role in SQL, so accordingly it must be "escaped" before using in an SQL statement. In Python, use the string replace method:
	nameesc = name.replace("'","''")
Note that you wouldn't want to double them for output as html text