Example #1
0
def any_of(*cls, **kwargs):
    '''Creates an ``Action`` subclass that passes requests to one of the given classes.

    The returned subclass is a dynamically created subclass of :class:`AnyAction`
    called ``AnyAction_<hash value>``, where ``<hash value>`` is a deterministic
    function of the arguments provided to this function. It delegates calls to
    :meth:`~Action.handles()` to its constituent classes (the parameters given
    in ``cls``) such that it accepts the request if *any* of the constituent
    classes individually accept the request.
    
    Instances of ``AnyAction`` are never actually created; when you construct
    an ``AnyAction`` for a given request, what you actually get is an instance
    of the first constituent class which has agreed to handle the request.

    If one of the parameters to this method is itself a subclass of ``AnyAction``,
    its list of constituent classes, rather than the parameter class itself, will
    be copied into the new AnyAction. This means that, for efficiency, ``AnyAction``
    will never be nested.'''
    handler_classes = []
    for n in cls:
        if not issubclass(n, Action):
            return NotImplemented
        if issubclass(n, AnyAction):
            handler_classes.extend(n.handler_classes)
        else:
            handler_classes.append([0,n])
    return type('AnyAction_%s' % hash_iterable(handler_classes), (AnyAction,), {'handler_classes': handler_classes, '_count': 8, '_sortable': kwargs.get('sortable', False)})
Example #2
0
def all_of(*cls):
    '''Creates an ``Action`` subclass that passes requests to all given classes.

    The returned subclass is a dynamically created subclass of :class:`AllActions`
    called ``AllActions_<hash value>``, where ``<hash value>`` is a deterministic
    function of the arguments provided to this function. The subclass delegates calls
    to :meth:`~Action.handles` to its constituent classes (the parameters given in
    ``cls``) such that the ``AllActions`` subclass only accepts the request if *all*
    its constituent classes individually accept the request. When an instance of
    ``AllActions_<hash value>`` is created in the second phase of processing, it
    internally also creates instances of all its constituent classes to which it
    will delegate calls to instance methods like :meth:`update_mtime` and
    :meth:`generate`.

    If one of the parameters to this method is itself a subclass of ``AllActions``,
    its list of constituent classes, rather than the parameter class itself, will
    be copied into the new ``AllActions``. This reduces the total number of instances
    of ``AllActions`` necessary.'''
    handler_classes = []
    for n in cls:
        if not issubclass(n, Action):
            return NotImplemented
        if issubclass(n, AllActions):
            handler_classes.extend(n.handler_classes)
        else:
            handler_classes.append(n)
    # Use the metaclass to create a dynamic subclass of AllActions
    # with our list of handler classes.
    return ActionMetaclass('AllActions_%s' % hash_iterable(handler_classes), (AllActions,), {'handler_classes': handler_classes})
Example #3
0
    def derive(cls, **kwargs):
        '''Returns a subclass of this class with selected class variables set.

        You can think of ``derive()`` as a constructor of sorts. Normally, of course,
        a constructor takes a class and some values and creates an instance
        of the class based on those values. This method works similarly, except
        that instead of creating an instance, it creates a subclass. By default,
        each keyword argument passed to ``derive()`` will be copied over to a 
        corresponding class variable of that subclass. For example,
        ``Action.derive(foo='bar')`` returns a subclass of ``Action`` with a class
        variable ``foo`` that has a default value of ``bar``. Another way
        to get the same effect would be ::
        
            class RandomActionSubclass(Action):
                foo = 'bar'
        
        Some subclasses of Action override ``derive()`` to do something more
        complicated with the given values, but they generally wind up as
        class variables in some form.
        
        The subclass returned by ``derive()`` will have a name of the form
        ``<class name>_<hash value>``, where ``<class name>` is the name of the base
        class, and ``<hash value>`` is some deterministic function of the keys and
        values passed in as keyword arguments. (The specific hash function used
        is purposely undocumented and may change; in practice it should probably
        never be necessary to know the hash generated.)

        If you write a subclass of Action that requires this sort of customization,
        and you don't have default values for the custom class variables, you can
        override ``derive()`` as follows to specify which properties your class
        requires::

            def derive(cls, <property1>, <property2>, ..., **kwargs):
                return super(<class>, cls).derive(<property1>=<property1>, <property2>=<property2>, ..., **kwargs)

        Just replace ``property1``, ``property2``, etc. in all three spots with the name of
        each property, and ``<class>`` with the name of the class. Make sure to leave the
        ``**kwargs`` in at the end, because your class might be subclassed yet again and
        the subsubclass might want to have additional custom properties. It's boilerplate
        code but I haven't found a way to reduce it further than this. If you have sensible
        defaults for all your properties, you can just set those defaults as class variables
        and then you don't have to override ``derive()`` at all.
        
        In any case, you really should document which variables ``derive()`` accepts or
        requires for your class, if any.'''
        return type('%s_%s' % (cls.__name__, hash_iterable(kwargs)), (cls,), kwargs)
Example #4
0
def opt(cls):
    '''Creates an Action subclass that wraps a given handler class to make it optional.

    The returned subclass is called OptAction_<hash value>, where <hash value> is a
    deterministic function of the argument. It returns True from handles(req) for all
    requests, but if its constituent class (the parameter given in cls) doesn't actually
    handle the request, attempting to create an instance of OptAction returns a NoopHandler
    (which does nothing) instead. If the constituent class does handle the request, than an
    instance of it itself is created and returned.

    If the parameter to this method is itself a subclass of OptAction, then it will be
    returned itself, rather than a new OptAction being created to wrap it.'''
    if not issubclass(cls, Action):
        return NotImplemented
    elif cls.__name__.startswith('OptAction'):
        return cls
    else:
        return type('OptAction_%s' % hash_iterable([cls]), (OptAction,), {'handler_class': cls})
Example #5
0
 def action_id(self):
     return hash_iterable(filter(None, (h.action_id() for h in self.handlers)))