/home/socr/b/bmi219/current/z/conrad/cgi-bin
current
(a.k.a., 2017
).$ cd /home/socr/b/bmi219/current/z/conrad/cgi-bin
$ ls -l
total 4
-rw-rw-r-- 1 conrad bmi219 179 Apr 17 09:58 example.cgi
$ chmod +x example.cgi
$ ./example.cgi
???
#!/usr/bin/python2
$ cd /usr/local/www/logs/plato-test-httpd/bmi219
$ grep example.cgi bmi219-ssl-access_log
169.230.21.23 - - [17/Apr/2017:09:56:19 -0700] "GET /z/conrad/cgi-bin/example.cgi HTTP/1.1" 401 362 "-" "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0" 0/29321
169.230.21.23 - conrad [17/Apr/2017:09:56:22 -0700] "GET /z/conrad/cgi-bin/example.cgi HTTP/1.1" 500 613 "-" "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0" 0/117099
169.230.21.23 - conrad [17/Apr/2017:09:56:46 -0700] "GET /z/conrad/cgi-bin/example.cgi HTTP/1.1" 200 50 "-" "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0" 0/155331
401
is "Unauthorized", and is normal when web site requires login200
is "Success"500
is "Internal Server Error"$ cd /usr/local/www/logs/plato-test-httpd/bmi219
$ grep example.cgi bmi219-ssl-error_log
[Mon Apr 17 09:56:22.793106 2017] [cgi:error] [pid 34932] [client 169.230.21.23:39853] End of script output before headers: example.cgi
[Mon Apr 17 09:58:34.034631 2017] [cgi:error] [pid 34932] [client 169.230.21.23:40281] AH01215: File "/home/socr/b/bmi219/current/z/conrad/cgi-bin/example.cg ", line 7, in
[Mon Apr 17 10:25:06.924289 2017] [cgi:error] [pid 55993] [client 169.230.21.23:40643] malformed header from script 'example.cgi': Bad header:
[Mon Apr 17 10:25:06.925424 2017] [cgi:error] [pid 55993] [client 169.230.21.23:40643] AH01215: File "/home/socr/b/bmi219/current/z/conrad/cgi-bin/example.cg ", line 7, in
#!/usr/bin/python2
import cgitb; cgitb.enable()
import sys, StringIO
orig_stdout = sys.stdout
sys.stdout = StringIO.StringIO()
print "Content-Type: text/xml"
print
print ""
print ""
raise ValueError("bad value")
print "This is content"
print " "
print " "
orig_stdout.write(sys.stdout.getvalue())
Portions Copyright © 2005-06 Python Software Foundation.
Tests = [
[[], [], 'empty list'],
[[1], [1], 'single value'],
[[1, 3], [1, 4], 'two values'],
[[1, 3, 7], [1, 4, 11], 'three values'],
[[-1, 1], [-1, 0], 'negative values'],
[[1, 3.0], [1, 4.0], 'mixed types'],
["string", ValueError, 'non-list input'],
[['a'], ValueError, 'non-numeric value']
]
True
if the first is greater than the second
string.startswith
True
if the string starts with the given prefix,
and False
otherwiseTests = [
# String Prefix Expected
['a', 'a', True],
['a', 'b', False],
['abc', 'a', True],
['abc', 'ab', True],
['abc', 'abc', True],
['abc', 'abcd', False],
['abc', '', True]
]
passes = 0
failures = 0
for (s, p, expected) in Tests:
actual = s.startswith(p)
if actual == expected:
passes += 1
else:
failures += 1
print 'passed', passes, 'out of', passes+failures, 'tests'
if
/else
try
blockexcept
blocktry
block,
Python
raises an exception
except
else
block
try
blockfor num in [-1, 0, 1]:
try:
inverse = 1/num
except:
print 'inverting', num, 'caused error'
else:
print 'inverse of', num, 'is', inverse
inverse of -1 is -1 inverting 0 caused error inverse of 1 is 1
Flow of Control in Try/Except/Else
except
statement
# Note: mix of numeric and non-numeric values.
values = [0, 1, 'momentum']
# Note: top index will be out of bounds.
for i in range(4):
try:
print 'dividing by value', i
x = 1.0 / values[i]
print 'result is', x
except ZeroDivisionError, e:
print 'divide by zero:', e
except IndexError, e:
print 'index error:', e
except:
print 'some other error:', e
dividing by value 0 divide by zero: float division dividing by value 1 result is 1.0 dividing by value 2 some other error: float division dividing by value 3 index error: list index out of range
except
blocks are tested in
order—whichever matches first, wins
except
appears,
it must come last (since it catches everything)except Exception as e
so that you have the exception objectZeroDivisionError
,
OverflowError
, and FloatingPointError
are all types of ArithmeticError
Name | Purpose | ||
---|---|---|---|
Exception |
Root of exception hierarchy | ||
ArithmeticError |
Illegal arithmetic operation | ||
FloatingPointError |
Generic error in floating point calculation | ||
OverflowError |
Result too large to represent | ||
ZeroDivisionError |
Attempt to divide by zero | ||
IndexError |
Bad index to sequence (out of bounds or illegal type) | ||
TypeError |
Illegal type (e.g., trying to add integer and string) | ||
ValueError |
Illegal value (e.g., math.sqrt(-1) ) |
||
EnvironmentError |
Error interacting with the outside world | ||
IOError |
Unable to create or open file, read data, etc. | ||
OSError |
No permissions, no such device, etc. | ||
Table 11.1: Common Exception Types in Python |
Stacking Exception Handlers
try
/except
block,
it pushes the except
handlers on a stack
def invert(vals, index):
try:
vals[index] = 10.0/vals[index]
except ArithmeticError, e:
print 'inner exception handler:', e
def each(vals, indices):
try:
for i in indices:
invert(vals, i)
except IndexError, e:
print 'outer exception handler:', e
# Once again, the top index will be out of bounds.
values = [-1, 0, 1]
print 'values before:', values
each(values, range(4))
print 'values after:', values
values before: [-1, 0, 1] inner exception handler: float division outer exception handler: list index out of range values after: [-10.0, 0, 10.0]
raise
to trigger exception processing
raise Exception('this is an error message')
for i in range(4):
try:
if (i % 2) == 1:
raise ValueError('index is odd')
else:
print 'not raising exception for %d' % i
except ValueError, e:
print 'caught exception for %d' % i, e
not raising exception for 0 caught exception for 1 index is odd not raising exception for 2 caught exception for 3 index is odd
None
, -1, False
, or some other value
list.find
breaks this rule
stderr
try
/except
Tests = [
['a', 'a', False], # wrong expected value
['a', 1, False], # wrong type
['abc', 'a', True] # everything legal
]
passes = failures = errors = 0
for (s, p, expected) in Tests:
try:
actual = s.startswith(p)
if actual == expected:
passes += 1
else:
failures += 1
except:
errors += 1
print 'tests:', passes + failures + errors
print 'passes:', passes
print 'failures:', failures
print 'errors:', errors
tests: 3 passes: 1 failures: 1 errors: 1
unittest
, py.test
,
doctest
, nose
, etc.unittest
comes standard and is easy to use#!/usr/bin/python2
import unittest
class TestExample(unittest.TestCase):
def setUp(self):
import getpass
passwd = getpass.getpass()
import base64
token = base64.encodestring("%s:%s" % (getpass.getuser(), passwd))
global headers
self.headers = {"Authorization": "Basic %s" % token.replace('\n', '')}
def test_example(self):
import urllib2
url = "http://bmi219.rbvi.ucsf.edu/z/conrad/cgi-bin/example.cgi"
data = None
req = urllib2.Request(url, data, self.headers)
f = urllib2.urlopen(req)
data = f.read()
f.close()
assert(f.getcode() == 200)
assert("Traceback" not in data)
if __name__ == "__main__":
unittest.main()
AssertionError
exceptiondef find_range(values):
'''Find the non-empty range of values in the input sequence.'''
assert (type(values) is list) and (len(values) > 0)
left = min(values)
right = max(values)
assert (left in values) and (right in values) and (left <= right)
return left, right
left
is less than or equal to all
other values, or that right is greater than or equal toassert
or custom code that
provides more information to help identify detected problemsdef can_transmute(element):
'''Can this element be turned into gold?'''
# Bug #172: make sure the input is actually an element.
assert is_valid_element(element)
# Gold is trivial.
if element is Gold:
return True
# Trans-uranic metals and halogens are impossible.
if (element.atomic_number > Uranium.atomic_number) or \
(element in Halogens):
return False
# Look for a sequence of steps that leads to gold.
steps = search_transmutations(element, Gold)
if steps == []:
return False
else:
# Bug #201: must be at least two elements in sequence.
assert len(steps) >= 2
return True
assert
to check things that ought to be right
profile
, cProfile
and line_profile