# Hi!
# This is my current argument unpacking Publisher
# Consider this alpha grade software.
#
# Andreas
import quixote,types
COFLAG_KW=8
def isstring (x):
return isinstance(x, types.StringTypes)
class Publisher(quixote.Publisher):
formvarmapper={":int":int,
":float":float,}
def callrequest(self,object,request):
# first thing to decide: What is the real callable function below
# object:
droparg=0 # how many arguments need to be
# dropped. (self,...)
to=type(object)
if to==types.FunctionType: # function
func=object
elif to==types.MethodType: # method
if object.im_self:
droparg=1
func=object.im_func
elif callable(object): # object
if hasattr(object,"__call__") and object.__call__.im_self:
# object instance with __call__
droparg=1
func=object.__call__.im_func
else: # class instance?
if hasattr(func,"__init__"): # with constructor.
droparg=1
func=object.__init__.im_func
else:
return object() # class constructor without args.
else:
assert not callable(object)
raise TypeError("is not a callable type.")
calldict={}
flags=func.func_code.co_flags
if flags & COFLAG_KW: # has keyword argument. Just pass
# the request as a builtin dictionary.
for k,v in request.environ.items():
calldict[k]=v
for k in request.form.keys():
for ext,mapper in self.formvarmapper.items():
if k.endswith(ext):
calldict[k[-len(ext):]]=mapper(request.form[k])
calldict[k]=request.form[k]
for k,v in request.cookies.items():
calldict[k]=v
calldict["request"]=req
else: # no keyword argument. Do it the
# hard way.
names=list(func.func_code.co_varnames)
argcount=func.func_code.co_argcount
names=names[:argcount] # loose the local variables and
# possible *arguments.
if droparg:
names=names[droparg:]
for n in names:
if request.environ.has_key(n):
calldict[n]=request.environ[n]
for ext,mapper in self.formvarmapper.items():
if request.form.has_key(n+ext):
calldict[n]=mapper(request.form[n+ext])
if request.cookies.has_key(n):
calldict[n]=request.cookies[n]
if n=="request":
calldict["request"]=request
return apply(object,(),calldict)
def try_publish (self, request, path):
"""try_publish(request : HTTPRequest, path : string) -> string
The master method that does all the work for a single request. Uses
traverse_url() to get a callable object. The object is called and
the output is returned. Exceptions are handled by the caller.
"""
self.start_request(request)
# Traverse package to a (hopefully-) callable object
object = self.traverse_url(path, request)
# None means no output -- traverse_url() just issued a redirect.
if object is None:
return None
# Anything else must be either a string...
if isstring(object):
output = object
# ...or a callable.
elif callable(object):
try:
output = self.callrequest(object,request)
except SystemExit:
output = "SystemExit exception caught, shutting down"
self.log(output)
self.exit_now = 1
if output is None:
raise RuntimeError, 'callable %s returned None' % repr(object)
# Uh-oh: 'object' is neither a string nor a callable.
else:
raise RuntimeError(
"object is neither callable nor a string: %s" % repr(object))
# The callable ran OK, commit any changes to the session
self.finish_successful_request(request)
return output