[Tutor] Problem with a variable in a CGI program

Danny Yoo dyoo at hkn.eecs.berkeley.edu
Fri Jan 7 20:16:29 CET 2005



On Fri, 7 Jan 2005, Mark Kels wrote:

> I started to read the following code (I will start working on it when
> this problem is fixed) and it looks OK while I read it. But for some
> reason it doesn't work...

Hi Mark,


Ok, let's take a look at the error message:


> Traceback (most recent call last):
>   File "C:\maillist.py", line 80, in ?
>     useMailList.writelines(memMailList)     # Copy internal mailing list to file
>
> NameError: name 'memMailList' is not defined

Ok, good, so we know what we should look for: we should see where
'memMailList' is defined, and see if there's any way that the program flow
can route around the definition.


Ok, I see it, embedded within the context of a try/except block.

######
try:

    ## some code before definition of memMailList...

    memMailList=useMailList.readlines()

    ## some more code cut...

finally:
   useMailList=open("maillist.txt", "w")
   useMailList.writelines(memMailList)
   useMailList.close
   print useFoot.read()
   useHead.close;
   useFoot.close;
######


There's one possibility that strikes me: it's very possible that in the
code before the definition of memMailList might raise an exception, or
exit out prematurely due to a sys.exit().  If that happens, then Python
will finish things up by jumping into the 'finally' block.  And if that
happens, then we haven't reached memMailList's definition, and the
NameError is inevitable.


Here's a simplified example of what might be happening:

###
>>> try:
...     a = 42
...     5 / 0
...     b = 17
... finally:
...     print "a is", a
...     print "b is", b
...
a is 42
b is
Traceback (most recent call last):
  File "<stdin>", line 7, in ?
NameError: name 'b' is not defined
###



A direct way to debug this is to drop the 'finally' block altogether.  If
we do so, like this:

######
## some code before definition of memMailList...

memMailList=useMailList.readlines()

## some more code cut...

useMailList=open("maillist.txt", "w")
useMailList.writelines(memMailList)
useMailList.close
print useFoot.read()
useHead.close;
useFoot.close;
######


then the real cause of the problem should pop up quickly.



A few more comments:

1.  The calls to close() need parentheses.  Unlike some other programming
languages, function calls fire off only with parens.  Instead of:

    useFoot.close

you probably want:

    useFoot.close()



2.  I also see that the code is hardcoded to use Python 1.5.  Is there any
way you can use a more modern version of Python?  The reason I ask is that
recent versions of Python have really good modules for debugging CGI
programs, including the excellent 'cgitb' module:

    http://www.python.org/doc/current/lib/module-cgitb.html

Writing CGI programs without 'cgitb' is almost criminal.  *grin*  If you
can, use it.



3.  The program is long.  Can you break it down into some functions?  The
program looks like one big monolith, and I'm actually quite terrified of
it.  *grin*

Small functions are much easier to debug, and more approachable for
maintainers of the code.  This is a style critique, but it does matter
because although computers don't care what code looks like, human
programmers do.



4.  Related to Comment Three is: there are way too many comments on the
side margin.  Comments like:

###
if email != email2:                      # Checks to see if two entered
                                         # email addresses match
    print "Email addresses do not match" # If no match print error
    sys.exit(0)                          # Exit script with error 0
elif password != password2:              # Checks to see if two
                                         # entered passwords match
    print "Passwords do not match"       # If no match print error
    sys.exit(0)                          # Exit script with error 0
###

are redundant, since they basically parrot what the code is doing.


Concise comments that explain the reason why the code is doing what it's
doing can be more useful.  Comments are meant to show us authorial
intension: if we were interested in what the code was actually doing, we'd
just read the code.  *grin*


Something like:

######

## Check for valididated emails and passwords, and exit if either are
## invalid.
if email != email2:
    print "Email addresses do not match"
    sys.exit(0)
elif password != password2:
    print "Passwords do not match"
    sys.exit(0)
######

is probably sufficient.



Even better would be to break this out as a function:

###
def validateEmailsAndPasswords(email, email2, password, password2):
    """Check for valididated emails and passwords, and exit if either are
       invalid."""
    if email != email2:
        print "Email addresses do not match"
        sys.exit(0)
    elif password != password2:
        print "Passwords do not match"
        sys.exit(0)
###

but I guess we should take this one step at a time.




If you have any questions, please feel free to ask.  I hope this helps!



More information about the Tutor mailing list