"""Some utilities for Python CGI
[brendan oconnor feb 2010, anyall.org/cgiutil.py]
OK, it's 2010 and there are now a zillion alternatives to CGI.
But every time I try one, I always come back.
It's just so much easier from a unix-based deployment perspective.
(PHP is ideal. CGI is close though not quite as good.)
If you run this you get a skeleton cgi app with example usage.
It requires the following Apache directives.
AddHandler cgi-script .cgi
Options [... bla bla ...] ExecCGI
And maybe (ubuntu/debian)
$ sudo a2enmod cgi && sudo /etc/init.d/apache2 reload
"""
from __future__ import with_statement
import sys,os,cgi
from copy import copy
import codecs; sys.stdout = codecs.open('/dev/stdout','w',encoding='utf8',buffering=0)
def safehtml(x):
return cgi.escape(str(x),quote=True)
def unicodify(s, encoding='utf8', *args):
""" because {str,unicode}.{encode,decode} is anti-polymorphic, but sometimes
you can't control which you have. """
if isinstance(s,unicode): return s
if isinstance(s,str): return s.decode(encoding, *args)
return unicode(s)
class Struct(dict):
def __getattr__(self, a):
if a.startswith('__'):
raise AttributeError
return self[a]
def __setattr__(self, a, v):
self[a] = v
def type_clean(val,type):
if type==bool:
if val in (False,0,'0','f','false','False','no','n'): return False
if val in (True,1,'1','t','true','True','yes','y'): return True
raise Exception("bad bool value %s" % repr(val))
if type==str or type==unicode:
# nope no strings, you're gonna get unicode instead!
return unicodify(val)
return type(val)
class Opt(object): pass
type_builtin = type
def opt(name, type=None, default=None, values=None):
o = Opt()
o.__dict__.update(name=name,type=type,default=default,values=values)
if type is None:
if default is not None:
o.type = type_builtin(default)
else:
o.type = str #raise Exception("need type for %s" % name)
#if o.type==bool: o.type=int
return o
class Opts(Struct):
" modelled on trollop.rubyforge.org and gist.github.com/5682 "
def __init__(self, *optlist):
self.optspecs = {}
environ = os.environ
# can't use cgi.py's form processing: we want to handle POST content ourselves now
vars = cgi.parse_qs(environ['QUERY_STRING'] or sys.stdin.read())
for opt in optlist:
# fix up the opt spec
if opt.values and not opt.default:
opt.default = opt.values[0]
# save it for later
self.optspecs[opt.name] = opt
# value processing from GET/POST info
val = vars.get(opt.name)
val = val[0] if val else None
if val is None and opt.default is not None:
val = copy(opt.default)
elif val is None:
raise Exception("option not given: %s" % opt.name)
val = type_clean(val, opt.type)
self[opt.name] = val
def input(self, name, **kwargs):
val = self[name]
h = '''"
return h
def select(self, name):
selected_value = self[name]
h = '"
return h
def make_skel():
"""makes options/viewer-oriented cgi skeleton app in current directory"""
os.system("cp %s ." % os.path.join(os.path.dirname(__file__), "cgiutil.py"))
assert not os.path.exists("index.cgi")
with open("index.cgi",'w') as f:
f.write(r'''#!/usr/bin/env python
import cgi,sys,os,re
import cgitb; cgitb.enable()
from cgiutil import * # anyall.org/cgiutil.py
print "Content-Type: text/html\n"
print """"""
print """"""
print """"""
print "this is an app
"
print "bla bla bla.
"
opts = Opts(
opt('q', default=""),
opt('parser', default="SP_DepSD", values=['SP_DepSD','SP_DepLTH']),
)
print opts
print "
| " + safehtml(k) + " | " + safehtml(v) print " |