GeneratorExit should derive from BaseException, not Exception

Chad Austin chad at imvu.com
Tue Aug 21 09:41:03 CEST 2007


Oops, forgot to mention this:

I wouldn't be opposed to a different extension that would effectively 
let me accomplish the same goals...  arbitrary exception filters. 
Imagine this:

	try:
		raise GeneratorExit
	except ExceptionFilter:
		# blah

where ExceptionFilter is any object that can be tested for containment. 
  Perhaps implemented like this:

	class ExceptionFilter(object):
		def __init__(self):
			self.includes = set()
			self.excludes = set()

			self.include = self.includes.add
			self.exclude = self.excludes.add

		def __contains__(self, exc):
			return any(isinstance(exc, cls) for cls in self.includes) and \
				not any(isinstance(exc, cls) for cls in self.excludes)

	ImvuExceptionFilter = ExceptionFilter()
	ImvuExceptionFilter.include(Exception)
	ImvuExceptionFilter.exclude(GeneratorExit)

Then, our code could just "catch" ImvuExceptionFilter.  This type of 
extension would be backwards compatible with the current except 
(FooError, BarError) tuple syntax.

I've never hacked on CPython itself, so I don't know what kind of 
changes there would be involved, but if there is sufficient pushback 
against making GeneratorExit derive from BaseException, I think this is 
a fine alternative.  Thoughts?

Chad

Chad Austin wrote:
> Hi Terry,
> 
> Thank you for your feedback.  Responses inline:
> 
> Terry Reedy wrote:
>> "Chad Austin" <chad at imvu.com> wrote in message 
>> news:46CA0EFE.6020103 at imvu.com...
>> || try:
>> | result = yield chatGateway.checkForInvite({'userId': userId})
>> | logger.info('checkForInvite2 returned %s', result)
>>
>> would not
>> except GeneratorExit: <do whatever>
>> solve your problem?
> 
> Yes, we could add an "except GeneratorExit: raise" clause to every place
> we currently catch Exception, but I feel like this is one of those
> things where it's hard to get it right in all places and also hard to
> cover with unit tests.  Instead, we'll have subtle bugs where finally
> clauses don't run because the GeneratorExit was swallowed.
> 
> Also, SystemExit and KeyboardInterrupt were made into BaseExceptions for
> the same reasons as I'm giving.  (As I understand it, anyway.)
> 
>> | except Exception:
>>
>> Such catchalls are known to be prone to catch too much
>> and are therefore not encouraged ;-).
>> As in 'use at your own risk'.
>> Guido encourages specific catches just for the reasons you give here.
> 
> More below:
> 
>> There was a *long* discussion of the current 2.5 exception hierarchy on 
>> pydev.  Search either python.org's or gmane's archive if you want to pursue 
>> this.  But I expect the people involved would say much the same as above.
> 
> I've actually read the background on the exception hierarchy (and agree
> with it all), especially other suggestions that GeneratorExit derive
> from BaseException.  As I understand it, Guido's objections are threefold:
> 
> 1) The previous "generators as coroutines" examples were too
> theoretical:  I've wanted GeneratorExit to derive from BaseException for
> months now, but didn't write this proposal until I actually wrote code
> that failed in the presence of task cancellation.
> 
> 2) You should avoid catching everything with except Exception:  I think
> that's too idealistic. Just do a search for try: except: through
> publicly available Python.  :)  Sometimes, you really _do_ want to catch
> everything.  When you're making a network request that involves
> xmlrpclib, urllib2, httplib, etc. you don't actually care what the error
> was.  (Well, except that the exceptions are submitted for automated
> analysis.)  Similarly, when loading a cache file with pickle, I don't
> care what went wrong, because it's not critical and should not be turned
> into a crash for the user.  (We automatically report exceptions that
> bubble into the main loop as crashes.)
> 
> 3) If GeneratorExit escapes from the generator somehow and gets raised
> in the main loop, then it will bubble out of the application like
> SystemExit and KeyboardInterrupt would:  I think this argument is
> somewhat specious, because I can't imagine how that would happen.  You'd
> have to store exceptions in your generator and explicitly bubble them
> out somehow.  Our crash handling has to specially handle
> KeyboardInterrupt and SystemExit anyway, since there are currently
> non-Exception exceptions, such as strings and custom classes that forgot
> to derive from Exception, that should count as crashes.
> 
> I personally can't think of any cases where I would _want_ to handle
> GeneratorExit.  I just want finally: and with: clauses to do the right
> thing when a task is cancelled.  Anyway, I haven't yet encountered any
> serious bugs due to this yet...  I'm just worried that if a task is
> holding some resource and blocking on something, then the resource won't
> get released.  If this really does come up, then I do have a little bit
> of python + ctypes that replaces GeneratorExit with ImvuGeneratorExit
> (deriving from BaseException), but that's not very appealing.
> 
> Thanks again,
> 

-- 
Chad Austin
http://imvu.com/technology



More information about the Python-list mailing list