[Python-Dev] Pre-PEP: Exception Reorganization for Python 3.0 (original) (raw)
Brett Cannon bcannon at gmail.com
Sat Jul 30 02:34:07 CEST 2005
- Previous message: [Python-Dev] math.fabs redundant?
- Next message: [Python-Dev] Pre-PEP: Exception Reorganization for Python 3.0
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Well, it has been discussed at multiple times in the past and I have promised to write this PEP several times, so I finally found enough time to write a PEP on reorganizing exceptions for Python 3.0 .
Key points in this PEP is the reworking the hierarchy, requiring anything raised to inherit from a certain superclass, and to change bare 'except' clauses to catch a specific superclass. The first and last points I expect some contention, but the middle point I expect people are okay with (Guido liked the idea when Paul Prescod brought it up and the only person who didn't like it, Holger, ended up being okay with it when the superclass had a reasonable name).
One thing people might not notice is that I have some minor ideas listed in the tree in parentheses. If people have an opinion on the ideas please speak up.
Otherwise the other major points of contention are covered in the Open Issues section or will be brought up in the usual trashing of PEPs that cover contraversial changes.
And please realize this is for Python 3.0! None of this is being proposed for any version before then (they could be, but that is another PEP entirely). Hopefully this PEP along with Ping's PEP 344 will cover the major ideas for exceptions for Python 3.0 .
-Brett
PEP: XXX Title: Exception Reorganization for Python 3.0 Version: Revision:1.5Revision: 1.5 Revision:1.5 Last-Modified: Date:2005/06/0713:17:37Date: 2005/06/07 13:17:37 Date:2005/06/0713:17:37 Author: Brett Cannon <brett at python.org> Status: Draft Type: Standards Track Content-Type: text/x-rst Created: 28-Jul-2005 Post-History: XX-XXX-XXX
Abstract
Python, as of version 2.4, has 38 exceptions (including warnings) in
the built-in namespace in a rather shallow hierarchy.
This list of classes has grown over the years without a chance to
learn from mistakes and cleaning up the hierarchy.
This PEP proposes doing a reorganization for Python 3000 when
backwards-compatibility is not an issue.
It also proposes changing bare except clauses to catch only
exceptions inheriting from a specific superclass.
Lastly, this PEP proposes, in Python 3000, that all objects to be
passed to a raise statement must inherit from a specific
superclass.
Rationale
Exceptions are a critical part of Python. While exceptions are traditionally used to signal errors in a program, they have also grown to be used for flow control for things such as iterators. There importance is great.
But the organization of the exception hierarchy has not been maintained.
Mostly for backwards-compatibility reasons, the hierarchy has stayed
very flat and old exceptions who usefulness have not been proven have
been left in.
Making exceptions more hierarchical would help facilitate exception
handling by making catching exceptions much more logical with use of
superclasses.
This should also help lead to less errors from being too broad in what
exceptions are caught in an except clause.
A required superclass for all exceptions is also being proposed
[Summary2004-08-01].
By requiring any object that is used in a raise statement to
inherit from a specific superclass, certain attributes (such as those
laid out in PEP 344 [PEP344]) can be guaranteed to exist.
This also will lead to the planned removal of string exceptions.
Lastly, bare except clauses can be made less error-prone
[Summary2004-09-01]_.
Often people use a bare except when what they really wanted were
non-critical exceptions to be caught while more system-specific ones,
such as MemoryError, to pass through and to halt the interpreter.
With a hierarchy reorganization, bare except clauses can be
changed to only catch exceptions that subclass a non-critical
exception superclass, allowing more critical exceptions to propagate
to the top of the execution stack as was most likely intended.
Philosophy of Reorganization
There are several goals in this reorganization that defined the philosophy used to guide the work. One goal was to prune out unneeded exceptions. Extraneous exceptions should not be left in since it just serves to clutter the built-in namespace. Unneeded exceptions also dilute the importance of other exceptions by splitting uses between several exceptions when all uses should have been under a single exception.
Another goal was to introduce any exceptions that were deemed needed
to fill any holes in the hierarchy.
Most new exceptions were done to flesh out the inheritance hierarchy
to make it easier to catch a category of exceptions with a simpler
except clause.
Changing inheritance to make it more reasonable was a goal.
As stated above, having proper inheritance allows for more accurate
except statements when catching exceptions based on the
inheritance tree.
Lastly, any renaming to make an exception's use more obvious from its name was done. Having to look up what an exception is meant to be used for because the name does not proper reflect its usage is annoying and slows down debugging. Having a proper name also makes debugging easier on new programmers.
New Hierarchy
Raisable (new; rename BaseException?) +-- CriticalException (new) +-- KeyboardInterrupt +-- MemoryError +-- SystemExit +-- SystemError (subclass SystemExit?) +-- AssertionError +-- SyntaxError +-- IndentationError +-- TabError +-- Exception (replaces StandardError) +-- ArithmeticError +-- FloatingPointError +-- DivideByZeroError +-- OverflowError +-- ControlFlowException (new) +-- StopIteration +-- GeneratorExit (introduced by PEP 342 [PEP342]_; subclass StopIteration?) +-- UnicodeError +-- UnicodeDecodeError +-- UnicodeEncodeError +-- UnicodeTranslateError (subclass UnicodeEncodeError and UnicodeDecodeError?) +-- LookupError (better name?) +-- IndexError +-- KeyError +-- TypeError +-- AttributeError (subclassing new) +-- OSError (does not inherit from EnvironmentError) +-- WindowsError +-- MacError (new) +-- UnixError (new) +-- IOError (does not inherit from EnvironmentError) +-- EOFError (subclassing new) +-- ImportError +-- NotImplementedError +-- NamespaceException (new) +-- UnboundGlobalError (new name for NameError) +-- UnboundLocalError (no longer subclasses UnboundGlobalError which replaces NameError) +-- WeakReferenceError (rename for ReferenceError) +-- ValueError +-- Warning +-- UserWarning +-- PendingDeprecationWarning +-- DeprecationWarning (subclassing new) +-- SyntaxWarning +-- SemanticsWarning (new name for RuntimeWarning) +-- FutureWarning
Differences Compared to Python 2.4
Changes to exceptions from Python 2.4 can take shape in three forms: removal, renaming, or change in their superclass. There are also new exceptions introduced in the proposed hierarchy.
New Exceptions
Raisable ''''''''
The base exception all exceptions inherit from.
The name "Raisable" has been chosen to reflect that it is not meant to
be treated as an exception directly, but as the common object that all
things to base passed to raise must inherit from.
CriticalException '''''''''''''''''
The superclass for exceptions for which a severe error has occurred that one would not want to catch accidentally. The name is meant to reflect the point that these exceptions are usually raised only when the interpreter should most likely be terminated.
MacError ''''''''
Introduced for symmertry with WindowsError.
UnixError '''''''''
Introduced for symmetry with WindowsError.
NamespaceException ''''''''''''''''''
To provide a common superclass for exceptions dealing with namespace issues, this exception is introduced. Both UnboundLocalError and UnboundGlobalError (the new name for NameError) inherit from this class.
Removed Exceptions
EnvironmentError ''''''''''''''''
Originally meant as an exception for when an event outside of the
interpreter needed to raise an exception, its use has been deemed
unneeded.
While both IOError and OSError inherited this class, the distinction
between OS and I/O is significant enough to not warrant having a
common subclass that one might base an except clause on.
StandardError '''''''''''''
Originally meant to act as a superclass for exceptions not considered critical, its subclassing was rampant and partially negated its usefulness. The need for StandardError is negated thanks to the CriticalException/Exception dichotomy where Exception takes its place.
RuntimeError '''''''''''' Meant to be used when an existing exception does not fit, its usefulness is consider meager in Python 2.4 [exceptionsmodule]_. Also, with the CriticalException/Exception dichotomy, Exception or CriticalException can be raised directly for the same use.
Renamed Exceptions
ReferenceError ''''''''''''''
Renamed WeakReferenceError.
ReferenceError was added to the built-in exception hierarchy in Python
2.2 [exceptionsmodule]_.
Taken directly from the weakref module, its name comes directly
from its original name when it resided in the module.
Unfortunately its name does not suggest its connection to weak
references and thus deserves a renaming.
NameError '''''''''
Renamed UnboundGlobalError.
While NameError suggests its use, the name does not properly restrict its scope. With UnboundLocalError already in existence, it seems reasonable to change NameError to UnboundGlobalError to brings its name more in line.
RuntimeWarning ''''''''''''''
Renamed SemanticsWarning.
RuntimeWarning is to represent semantic changes coming in the future. But while saying that affects "runtime" is true, flat-out stating it is a semantic change is much clearer, eliminating any possible association of "runtime" with the virtual machine specifically.
Changed Inheritance
StopIteration and GeneratorExit '''''''''''''''''''''''''''''''
Inherit from ControlFlowException.
Collecting all control flow-related exceptions under a common superclass continues with the theme of maintaining a hierarchy.
AttributeError ''''''''''''''
Inherits TypeError.
Since most attribute access errors can be attributed to an object not being the type that one expects, it makes sense for AttributeError to be considered a type error.
IOError '''''''
No longer subclasses EnvironmentError.
While IOError does fall under the umbrella of EnvironmentError, the need for EnvironmentError has been deemed wanting, and thus has been removed. Thus IOError now subclasses Exception directly.
EOFError ''''''''
Subclasses IOError.
Since an EOF comes from I/O it only makes sense that it be considered an I/O error.
UnboundGlobalError and UnboundLocalError ''''''''''''''''''''''''''''''''''''''''
Both subclass NamespaceException.
Originally UnboundLocalError subclassed NameError (original name of UnboundGlobalError), but with both exceptions specifying a certain namespace, that subclassing has been deemed inappropriate. Instead, a common class between the two of them has been introduced.
DeprecationWarning '''''''''''''''''''
Subclasses PendingDeprecationWarning.
Since a DeprecationWarning is a PendingDeprecationWarning that is happening sooner, if you care about PendingDeprecationWarnings you are defintely going to care about DeprecationWarnings.
Required Base Class for raise
By requiring all objects passed to a raise statement, one is
guaranteed that all exceptions will have certain attributes.
If PEP 342 [PEP344]_ is accepted, the attributes outlined there will
be guaranteed to be on all exceptions raised.
This should help facilitate debugging by making the querying of
information from exceptions much easier.
Technically speaking, this can be easily implemented by modifying
RAISE_VARARGS to do an inheritance check and raise TypeError if it
does not inherit from Raisable.
Bare except Clauses
Bare except clauses typically are not meant to catch all exceptions.
Often times catching KeyboardInterrupt is not intended.
Unfortunately the exception hierarchy in Python 2.4 does not support a
simple way to control what exceptions are caught except to be very
explicit with a list of exceptions.
The reorganization changes this by adding more of a hierarchy.
If bare except statements only catch classes that inherit from
Exception, its use will be more in line with what people expect.
An implementation can be handled at the bytecode level by modifying
the compiler to emit bytecode to do a check for Exception when a bare
except is used.
Open Issues
Change the Name of Raisable?
It has been argued that Raisable is a bad name to use since it is not an actual word [python-dev1]_. At issue is choosing a name that clearly explains the class' usage. "BaseException" might be acceptable although the name does not quite make it as explicit as Raisable that the class is not meant to be raised directly.
Should Bare except Clauses be Removed?
It has been argued that bare except clauses should be removed
entirely [python-dev2]_.
The train of thought is that it will force people to specify what they
want to catch and not be too broad.
One issue with this, though, is whether people will make the proper
choices of what to catch or go too broadly.
Would a new Python programmer make the right decision and not catch
CriticalExceptions or would they go overboard and catch Raisable?
It would seem the issue boils down to whether we think people will
make proper decisions or make a reasonable solution available for the
simplest case assuming they might make a bad one.
Change the name of Exception?
Some have suggested names other than "Exception" for the superclass to
inherit from for bare except clauses to match against.
The issue with going with a name that is not simplistic is that it
raises the chance of people subclassing the wrong exception for what
they want.
By using the most generic name for the common case it raises the
chances that people will use this class for subclassing their own
exceptions rather than Raisable or CriticalException.
Acknowledgements
XXX
References
.. [PEP342] PEP 342 (Coroutines via Enhanced Generators) (http://www.python.org/peps/pep-0342.html)
.. [PEP344] PEP 344 (Exception Chaining and Embedded Tracebacks) (http://www.python.org/peps/pep-0344.html)
.. [exceptionsmodules] 'exceptions' module (http://docs.python.org/lib/module-exceptions.html)
.. [Summary2004-08-01] python-dev Summary (An exception is an exception, unless it doesn't inherit from Exception) (http://www.python.org/dev/summary/2004-08-01_2004-08-15.html#an-exception-is-an-exception-unless-it-doesn-t-inherit-from-exception)
.. [Summary2004-09-01] python-dev Summary (Cleaning the Exception House) (http://www.python.org/dev/summary/2004-09-01_2004-09-15.html#cleaning-the-exception-house)
.. [python-dev1] python-dev email (Exception hierarchy) (http://mail.python.org/pipermail/python-dev/2004-August/047908.html)
.. [python-dev2] python-dev email (Dangerous exceptions) (http://mail.python.org/pipermail/python-dev/2004-September/048681.html)
Copyright
This document has been placed in the public domain.
- Previous message: [Python-Dev] math.fabs redundant?
- Next message: [Python-Dev] Pre-PEP: Exception Reorganization for Python 3.0
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]