Implementing Chain of responsibility pattern in python using coroutines
Question: I am exploring different concepts in python and I happened to read upon an
example of coroutines which can be used for the chain of responsibility design
pattern. I wrote the following code:

    
    
    from functools import wraps
    
    def coroutine(function):
        @wraps(function)
        def wrapper(*args, **kwargs):
            generator = function(*args, **kwargs)
            next(generator)
            return generator
        return wrapper
    
    @coroutine
    def PlatinumCustomer(successor=None):
       cust = (yield)
       if cust.custtype == 'platinum':
           print "Platinum Customer"
       elif successor is not None:
           successor.send(cust)
    
    @coroutine
    def GoldCustomer(successor=None):
        cust = (yield)
        if cust.custtype == 'gold':
            print "Gold Customer"
        elif successor is not None:
            successor.send(cust)
    
    @coroutine
    def SilverCustomer(successor=None):
        cust = (yield)
        if cust.custtype == 'silver':
            print "Silver Customer"
        elif successor is not None:
            successor.send(cust)
    
    @coroutine
    def DiamondCustomer(successor=None):
        cust = (yield)
        if cust.custtype == 'diamond':
            print "Diamond Customer"
        elif successor is not None:
            successor.send(cust)
    
    class Customer:
        pipeline = PlatinumCustomer(GoldCustomer(SilverCustomer(DiamondCustomer())))
    
        def __init__(self,custtype):
            self.custtype = custtype
    
        def HandleCustomer(self):
            try:
                self.pipeline.send(self)
            except StopIteration:
                pass
    
    if __name__ == '__main__':
        platinum = Customer('platinum')
        gold = Customer('gold')
        silver = Customer('silver')
        diamond = Customer('diamond')
        undefined = Customer('undefined')
    
        platinum.HandleCustomer()
        gold.HandleCustomer()
        undefined.HandleCustomer()   
    

What I have tried to do here is try to create a chain of responsibility
pattern solution for handling different types of customers (Platinum, Gold,
Diamond, Silver).

For that Customer has a pipeline where I have mentioned the order in which the
different customers will be handled. Customer().HandleCustomer will send an
instance of itself through the pipeline which will check whether its custtype
matches and then process it accordingly or it will send it across to its
successor (if available)

PROBLEM: The problem is that when I run the above script, it will handle the
first platinum customer but not the gold or the undefined. I am assuming this
is because he has reached the end of the generator. How do I modify the code
so that everytime it is a new instance of a customer, it will go through the
pipeline from its beginning?


Answer: Your coroutines must loop forever in order to handle successive calls, as in:

    
    
    @coroutine
    def PlatinumCustomer(successor=None):
        while 1:    #   <---- this is missing from your coroutines
            cust = (yield)
            if cust.custtype == 'platinum':
               print "Platinum Customer"
            elif successor is not None:
               successor.send(cust)
    

And to handle the 'undefined' type, you'll need a final catch-all handler:

    
    
    @coroutine
    def UndefinedCustomer():
        while 1:
            cust = (yield)
            print "No such customer type '%s'" % cust.custtype
    

and add it to your pipeline:

    
    
    pipeline = PlatinumCustomer(GoldCustomer(SilverCustomer(DiamondCustomer(UndefinedCustomer()))))
    

(A terminating UndefinedCustomer handler also will allow you to remove the 'if
there is no successor' code from your coroutines - all will have successors
except for the terminator, which knows that it is the terminator and will not
call a successor.)

With these changes, I get this output from your tests:

    
    
    Platinum Customer
    Gold Customer
    No such customer type 'undefined'
    

Also, why the catch for StopIteration in HandleCustomer? This code should be
sufficient:

    
    
    def HandleCustomer(self):
        self.pipeline.send(self)
    

