# 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