Proposing a sys.special_exceptions tuple
I spent some time the other day looking at the use of bare except statements in the standard library. Many of them seemed to fall into the category of 'need to catch anything user code is likely to throw, but shouldn't be masking SystemExit, StopIteration, KeyboardInterrupt, MemoryError, etc'. Changing them to "except Exception:" doesn't help, since all of the above still fit into that category (Tim posted a message recently about rearranging the Exception heirarchy to fix this. Backwards compatibility woes pretty much killed the discussion though). However, another possibility occurred to me: try: # Do stuff except sys.special_exceptions: raise except: # Deal with all the mundane stuff With an appropriately defined tuple, that makes it easy for people to "do the right thing" with regards to critical exceptions. Such a tuple could also be useful for invoking isinstance() and issubclass(). Who knows? If something like this caught on, it might some day be possible to kill a Python script with a single press of Ctrl-C };> Cheers, Nick. -- Nick Coghlan Brisbane, Australia
At 08:21 PM 9/30/04 +1000, Nick Coghlan wrote:
However, another possibility occurred to me:
try: # Do stuff except sys.special_exceptions: raise except: # Deal with all the mundane stuff
With an appropriately defined tuple, that makes it easy for people to "do the right thing" with regards to critical exceptions. Such a tuple could also be useful for invoking isinstance() and issubclass().
+1. This would be a big help for developers, if only in that it will tell us what exceptions we ought to do this with. IMO, this is probably important enough to make it a builtin; maybe call it CriticalExceptions or some such. Also, maybe in 2.5 we could begin warning about bare excepts that aren't preceded by non-bare exceptions.
On Thu, 2004-09-30 at 10:19, Phillip J. Eby wrote:
At 08:21 PM 9/30/04 +1000, Nick Coghlan wrote:
However, another possibility occurred to me:
try: # Do stuff except sys.special_exceptions: raise except: # Deal with all the mundane stuff
+0, except that I'd rather see it put in the exceptions module and given a name in builtins. -Barry
Quoting Barry Warsaw <barry@python.org>:
At 08:21 PM 9/30/04 +1000, Nick Coghlan wrote:
However, another possibility occurred to me:
try: # Do stuff except sys.special_exceptions: raise except: # Deal with all the mundane stuff
+0, except that I'd rather see it put in the exceptions module and given a name in builtins.
Hmm, I forgot about the existence of the exceptions module. I agree that makes a more sensible location than sys. As for it being a builtin, I have no objections to that. I'll come up with two patches, though. One to create the tuple in exceptions, and one to give it a name in builtins (since the latter would presumably be more controversial, like any new builtin). My current list of exceptions for inclusion is KeyboardInterrupt, MemoryError, SystemExit & StopIteration. The inclusion of StopIteration is what makes me prefer 'special_exceptions' as the name of the tuple, rather than 'critical_exceptions'. Cheers, Nick. -- Nick Coghlan Brisbane, Australia
A candidate implementation is up at SF. Patch # 1038256. It uses the name 'special_exceptions' and includes SystemExit, MemoryError, KeyboardInterrupt and StopIteration (adding/removing exceptions from the list is easy, as is changing the name). One version of the patch creates 'exceptions.special_exceptions' only, and the other version also creates a builtin. Cheers, Nick. -- Nick Coghlan Brisbane, Australia
A candidate implementation is up at SF. Patch # 1038256.
It uses the name 'special_exceptions' and includes SystemExit, MemoryError, KeyboardInterrupt and StopIteration (adding/removing exceptions from the list is easy, as is changing the name).
One version of the patch creates 'exceptions.special_exceptions' only, and the other version also creates a builtin.
Since we're trying to catch anything *not* special, is the intended usage something like this: try: func() except special_exceptions: raise except: altfunc() # handle non-special exceptions Raymond
Quoting Raymond Hettinger <python@rcn.com>:
Since we're trying to catch anything *not* special, is the intended usage something like this:
try: func() except special_exceptions: raise except: altfunc() # handle non-special exceptions
Yep. It's essentially a workaround for the fact that we can't do anything too drastic to the exception heirarchy without serious backwards compatibility problems, but have some 'critical' exceptions that most code shouldn't be suppressing. At the moment, 'except:' is bad, and in most cases 'except Exception:' isn't any better (which surprised me - I didn't realise this until Tim brought it up recently). Tim suggested 'except StandardError:' which is an improvement but still not quite right (SystemExit and StopIteration make it through then, but MemoryError and KeyboardInterrupt still get eaten). I'm dreaming of the day when I can hit 'Ctrl-C' on any Python script and actually have the darn thing stop without hitting it 10 more times ;) Cheers, Nick. -- Nick Coghlan Brisbane, Australia
On Thu, Sep 30, 2004 at 10:19:22AM -0400, Phillip J. Eby wrote:
Also, maybe in 2.5 we could begin warning about bare excepts that aren't preceded by non-bare exceptions.
try: foo() except: print_or_log_exception_in_a_way_that_is_meaningful() raise doesn't seem to be incorrect to me. For example, if the program is a daemon, I want the exception logged somewhere so that I can see it later, because I won't be watching stderr. []s, |alo +---- -- Those who trade freedom for security lose both and deserve neither. -- http://www.laranja.org/ mailto:lalo@laranja.org pgp key: http://garfield.laranja.org/~lalo/gpgkey-signed.asc GNU: never give up freedom http://www.gnu.org/
At 12:52 PM 9/30/04 -0300, Lalo Martins wrote:
On Thu, Sep 30, 2004 at 10:19:22AM -0400, Phillip J. Eby wrote:
Also, maybe in 2.5 we could begin warning about bare excepts that aren't preceded by non-bare exceptions.
try: foo() except: print_or_log_exception_in_a_way_that_is_meaningful() raise
doesn't seem to be incorrect to me. For example, if the program is a daemon, I want the exception logged somewhere so that I can see it later, because I won't be watching stderr.
1. If the exception raised is a MemoryError, your daemon is in trouble. 2. I said *warn*, and it'd be easy to suppress the warning using 'except Exception:', if that's what you really mean 3. But I suppose this could be considered a job for pychecker.
"Phillip J. Eby" <pje@telecommunity.com> writes:
At 12:52 PM 9/30/04 -0300, Lalo Martins wrote:
On Thu, Sep 30, 2004 at 10:19:22AM -0400, Phillip J. Eby wrote:
Also, maybe in 2.5 we could begin warning about bare excepts that aren't preceded by non-bare exceptions.
try: foo() except: print_or_log_exception_in_a_way_that_is_meaningful() raise
doesn't seem to be incorrect to me. For example, if the program is a daemon, I want the exception logged somewhere so that I can see it later, because I won't be watching stderr.
1. If the exception raised is a MemoryError, your daemon is in trouble.
Not necessarily. Typing 'range(sys.maxint)' into the interactive interpreter gives a fairly harmless MemoryError (the only exception PyRepl doesn't catch is SystemExit).
2. I said *warn*, and it'd be easy to suppress the warning using except Exception:', if that's what you really mean
Well, apart from the fact that this doesn't catch, uh, exceptions that don't derive from Exception? Until/unless that's enforced (something that gets thrashed around every other month) there's still a place for 'bare except:'. Cheers, mwh -- SCSI is not magic. There are fundamental technical reasons why it is necessary to sacrifice a young goat to your SCSI chain now and then. -- John Woods
participants (6)
-
Barry Warsaw
-
Lalo Martins
-
Michael Hudson
-
Nick Coghlan
-
Phillip J. Eby
-
Raymond Hettinger