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
- 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.
- 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.
- 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