On Tue, 2011-11-01 at 11:14 +1000, Nick Coghlan wrote:
On Tue, Nov 1, 2011 at 10:22 AM, Ron Adam <ron3200@gmail.com> wrote:
On Tue, 2011-11-01 at 10:06 +1300, Greg Ewing wrote:
Ron Adam wrote:
If we put some strict requirements on the idea.
1. Only have a *SINGLE* exception type as being resumable.
2. That exception should *NEVER* occur naturally.
3. Only allow continuing after it's *EXPLICITLY RAISED* by a raised statement.
All of the problem issues go away with those requirements in place, and you only have the issue of how to actually write the patch. Earlier discussions indicated, it might not be that hard to do.
I'm not familiar with these earlier discussions. Did they go as far as sketching a feasible implementation? It's all very well to propose things like this, but the devil is very much in the details.
Yeah, there isn't very much about the details, but I think it is worth looking into as it would pretty much does exactly what is needed. (IMHO)
It gave me another thought on an existing utility worth exploring in this context: pdb's post-mortem capabilities.
Now, those *don't* implement coroutines (when you do a postmortem, you end up in an emulation of the eval loop, not the eval loop itself). However, that exception instance *does* contain the full frame stack, all the way down to where the exception was thrown. Figuring out what hooks you would need in the core eval loop in order to reinstate an exception's frame stack as the "real" frame stack might be an interesting exercise.
Poking around a bit, it looks like 'raise' does most of the work and the exception is just an envelope for what ever 'raise' puts in it. Is that right? I'd like to be able to make this work. class Suspend: def __init__(self, source): self.source = source self.suspend = True def __next__(self): nonlocal self.suspend if self.suspend: self.suspend = False raise SuspendException self.suspend = True return next(self.source) There are two issues with it... The "self.suspend = False" doesn't seem to work. The __next__ seems to get it's own copies of the attributes at the time the generator is created. And after the SuspendException is raised, a StopIteratoion is issued on the next next() call. The StopIteration is from the whole chain. The only reason the scheduler doesn't stop is it catches the Suspendexception. I want to be able to stick something like this in the generator chained pipe example below. Cheers, Ron *This is broken down into finer steps than you would normally do in order to test how it behaves. """ Basic scheduler test -- co-pipes version """ from co_pipes import * def Person(args): name, count = args p = Producer(lambda:name) # call function each time p = Limit(p, count) # exit after count yields. p = Enumerate(p) # -> (n, data) #p = Suspend(p) # suspend doesn't work. p = Apply(p, "{0[0]}: {0[1]} ".format) p = Apply(p, print) # consumer for _ in p: yield # pull data from here. def main(data): p = Source(data) # take an iterable p = Apply(p, Person) # apply a callable to data p = Collect(p) # collect items in a list p = Scheduler(p) # take a list of generators. next(p) # start the scheduler. if __name__ == "__main__": data = [("John", 2), ("Micheal", 3), ("Terry", 4)] main(data) Prints... 1: John 1: Micheal 1: Terry 2: John 2: Micheal 2: Terry 3: Micheal 3: Terry 4: Terry