# -*- coding: utf-8 -*-
Created on Sun Jan  6 14:17:00 2016

@author: kurner

Demonstrates a driver-along-road pattern where the
Driver(road) instance runs to completion when the 
target of 'yield from'.

This is not about interweaving event processing 
asynchonously.  It's about 'yield from' and how 
the iterator pattern lends itself to setting up 
coroutines, wherein a driver (future, task) 
experiences "maturation" (evolving state) based
on traversing a road that keeps continuing where
it left off.

from random import choice
from time import sleep
import sys

def road(co_id):
    """a bumpy road... 
    keeps relinquishing control back to the driver
    drv = yield None
    drv.result = 1
    drv.co_id = co_id
    drv = yield drv
    drv.result += 1
    drv.name = choice(["Alvin", "Eric", "Gwen"])
    drv = yield drv
    drv.result += 1
    drv.color = choice(["Red", "Purple", "Orange"])
    drv = yield drv
    drv.result += 1
    drv.age = 100
    return drv  # the driver registers changes made along the way

class Driver:
    """Iterator for driving along a road"""
    def __init__(self, r):
        self.g = r        # on your mark...
        self.g.send(None) # get set...
        self.counter = 1
    def __iter__(self):
        return self

    def __next__(self): 
        while True:  # go! ...drive to end of road
                self.counter *= 10
                self = self.g.send(self) # expect delays
            except StopIteration as exc:
                return exc.value         # returned by yield from
tasks = [Driver(road(n)) for n in range(4)] # a Driver is instanced per road

def delegator(task):   
    return (yield from task) # delegating to a task (blocking once started)

coroutines = (delegator(x) for x in tasks)  # each based on yield from

print("Non-blocking to here.")
results = [ ]   
for co in coroutines:
    results.append(co.send(None)) # go! drives each task to completion

for result in results:
    print("Result: {co_id}: {name} {color}".format(**result.__dict__))