durusmail: quixote-users: Publisher with argument unpacking from request.
Publisher with argument unpacking from request.
Publisher with argument unpacking from request.
Andreas Kostyrka
2002-08-06
# 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




reply