On Dec 1, 2007 2:38 PM, Chad Austin <[EMAIL PROTECTED]> wrote: > Here at IMVU, we love Python 2.5's generators-as-coroutines. That feature has > let us succinctly express algorithms that intermix asynchronous network > requests > and UI operations without writing complicated state machines, and, perhaps > most > importantly, get high-quality unit tests around these algorithms. > > However, we've been having a problem with the way GeneratorExit interacts with > our coroutine system. Let's take a bit of simplified example code from our > system: > > @task > def pollForChatInvites(chatGateway, userId): > while True: > try: > # Network call. > result = yield > chatGateway.checkForInvite({'userId': userId}) > except Exception: # An XML-RPC call can fail for > many reasons. > result = None > # ... handle result here > yield Sleep(10) > > If a task (coroutine) is cancelled while it's waiting for the result from > checkForInvite, a GeneratorExit will be raised from that point in the > generator, > which will be caught and ignored by the "except Exception:" clause, causing a > RuntimeError to be raised from whoever tried to close the generator. > Moreover, > any finally: clauses or with-statement contexts don't run. > > We have also run into problems where a task tries to "return" (yield Return()) > from within a try: except Exception: block. Since returning from a coroutine > is > roughly equivalent to "raise GeneratorExit", the exception can be caught and > ignored, with the same consequences as above. > > This problem could be solved in several ways: > > 1) Make GeneratorExit derive from BaseException, just like SystemExit. > > 2) Add "except GeneratorExit: raise" to every usage of except Exception: in > tasks. > > 3) Change the semantics of except clauses so that you can use any container as > an exception filter. You could have a custom exception filter object that > would > catch any Exception-derived exception except for GeneratorExit. Then we'd > have > to teach the team to use "except ImvuExceptionFilter:" rather than "except > Exception:". > > I prefer option #1, because it matches SystemExit and I haven't ever seen a > case > where I wanted to catch GeneratorExit. When a generator is closed, I just > want > finally: clauses to run, like a normal return statement would. In fact, we > have > already implemented option #1 locally, but would like it to be standard. > > Option #2 would add needless noise throughout the system, > > You could argue that it's bad style to catch Exception, but there are many > situations where that's exactly what I want. I don't actually care _how_ the > xml-rpc call failed, just that the error is logged and the call is retried > later. Same with loading caches from disk. > > Proposals for changing GeneratorExit to be a BaseException have come up on > this > list in the past [1] [2], but were rejected as being too "theoretical". A > significant portion of the IMVU client is now specified with coroutines, so I > hope to resume this conversation. > > Thoughts? > > Chad > > [1] http://mail.python.org/pipermail/python-dev/2006-March/062654.html > [2] http://mail.python.org/pipermail/python-dev/2006-March/062825.html
Well argued. I suggest to go for option (1) -- make GeneratorExit inherit from BaseException. We can do this starting 2.6. Feel free to upload a patch to bugs.python.org. -- --Guido van Rossum (home page: http://www.python.org/~guido/) _______________________________________________ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com