Source

python-peps / pep-0348.txt

Full commit
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
PEP: 348
Title: Exception Reorganization for Python 3.0
Version: $Revision$
Last-Modified: $Date$
Author: Brett Cannon <brett@python.org>
Status: Rejected
Type: Standards Track
Content-Type: text/x-rst
Created: 28-Jul-2005
Post-History:

.. |2.x| replace:: 2.5

.. note:: This PEP has been rejected [#rejected]_.


Abstract
========

Python, as of version 2.4, has 38 exceptions (including warnings) in
the built-in namespace in a rather shallow hierarchy.  These
classes have come about over the years without a chance to learn from
experience.  This PEP proposes doing a reorganization of the hierarchy
for Python 3.0 when backwards-compatibility is not as much of an
issue.

Along with this reorganization, adding a requirement that all
objects passed to a ``raise`` statement must inherit from a specific
superclass is proposed.  This is to have guarantees about the basic
interface of exceptions and to further enhance the natural hierarchy
of exceptions.

Lastly, bare ``except`` clauses will be changed to be semantically
equivalent to ``except Exception``.  Most people currently use bare
``except`` clause for this purpose and with the exception hierarchy
reorganization becomes a viable default.


Rationale For Wanting Change
============================

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.

While their importance is great, there is a lack of structure to them.
This stems from the fact that any object can be raised as an
exception.  Because of this you have no guarantee in terms of what
kind of object will be raised, destroying any possible hierarchy
raised objects might adhere to.

But exceptions do have a hierarchy, showing the severity of the
exception.  The hierarchy also groups related exceptions together to
simplify catching them in ``except`` clauses.  To allow people to
be able to rely on this hierarchy, a common superclass that all
raise objects must inherit from is being proposed.  It also allows
guarantees about the interface to raised objects to be made (see
PEP 344 [#PEP344]_).  A discussion about all of this has occurred
before on python-dev [#Summary2004-08-01]_.

As bare ``except`` clauses stand now, they catch *all* exceptions.
While this can be handy, it is rather overreaching for the common
case.  Thanks to having a required superclass, catching all
exceptions is as easy as catching just one specific exception.
This allows bare ``except`` clauses to be used for a more useful
purpose.
Once again, this has been discussed on python-dev [#python-dev3]_.

Finally, slight changes to the exception hierarchy will make it much
more reasonable in terms of structure.  By minor rearranging
exceptions
that should not typically be caught can be allowed to propagate to the
top of the execution stack, terminating the interpreter as intended.


Philosophy of Reorganization
============================

For the reorganization of the hierarchy, there was a general
philosophy followed that developed from discussion of earlier drafts
of this PEP [#python-dev-thread1]_, [#python-dev-thread2]_,
[#python-dev-thread3]_, [#python-dev-thread4]_,
[#python-dev-thread5]_, [#python-dev-thread6]_.
First and foremost was to not break anything
that works.  This meant that renaming exceptions was out of the
question unless the name was deemed severely bad.  This
also meant no removal of exceptions unless they were viewed as
truly misplaced. The introduction of new exceptions were only done in
situations where there might be a use for catching a superclass of a
category of exceptions.  Lastly, existing exceptions would have their
inheritance tree changed only if it was felt they were truly
misplaced to begin with.

For all new exceptions, the proper suffix had to be chosen.  For
those that signal an error, "Error" is to be used.  If the exception
is a warning, then "Warning".  "Exception" is to be used when none
of the other suffixes are proper to use and no specific suffix is
a better fit.

After that it came down to choosing which exceptions should and
should not inherit from Exception.  This was for the purpose of
making bare ``except`` clauses more useful.

Lastly, the entire existing hierarchy had to inherit from the new
exception meant to act as the required superclass for all exceptions
to inherit from.


New Hierarchy
=============

.. Note:: Exceptions flagged with "stricter inheritance" will no
   longer inherit from a certain class.  A "broader inheritance" flag
   means a class has been added to the exception's inheritance tree.
   All comparisons are against the Python 2.4 exception hierarchy.

.. parsed-literal::

   +-- BaseException (new; broader inheritance for subclasses)
       +-- Exception
	   +-- GeneratorExit (defined in PEP 342 [#PEP342]_)
	   +-- StandardError
	       +-- ArithmeticError
		   +-- DivideByZeroError
		   +-- FloatingPointError
		   +-- OverflowError
	       +-- AssertionError
	       +-- AttributeError
	       +-- EnvironmentError
		   +-- IOError
		   +-- EOFError
		   +-- OSError
	       +-- ImportError
	       +-- LookupError
		   +-- IndexError
		   +-- KeyError
	       +-- MemoryError
	       +-- NameError
		   +-- UnboundLocalError
	       +-- NotImplementedError (stricter inheritance)
	       +-- SyntaxError
		   +-- IndentationError
		       +-- TabError
	       +-- TypeError
	       +-- RuntimeError
	       +-- UnicodeError
		   +-- UnicodeDecodeError
		   +-- UnicodeEncodeError
		   +-- UnicodeTranslateError
	       +-- ValueError
	       +-- ReferenceError
	   +-- StopIteration
	   +-- SystemError
	   +-- Warning
	       +-- DeprecationWarning
	       +-- FutureWarning
	       +-- PendingDeprecationWarning
	       +-- RuntimeWarning
	       +-- SyntaxWarning
	       +-- UserWarning
	   + -- WindowsError
       +-- KeyboardInterrupt (stricter inheritance)
       +-- SystemExit (stricter inheritance)


Differences Compared to Python 2.4
==================================

A more thorough explanation of terms is needed when discussing
inheritance changes.  Inheritance changes result in either broader or
more restrictive inheritance.  "Broader" is when a class has an
inheritance tree like ``cls, A`` and then becomes ``cls, B, A``.
"Stricter" is the reverse.


BaseException
-------------

The superclass that all exceptions must inherit from.  It's name was
chosen to reflect that it is at the base of the exception hierarchy
while being an exception itself.  "Raisable" was considered as a name,
it was passed on because its name did not properly reflect the fact
that it is an exception itself.

Direct inheritance of BaseException is not expected, and will
be discouraged for the general case.  Most user-defined
exceptions should inherit from Exception instead.  This allows
catching Exception to continue to work in the common case of catching
all exceptions that should be caught.  Direct inheritance of
BaseException should only be done in cases where an entirely new
category of exception is desired.

But, for cases where all
exceptions should be caught blindly, ``except BaseException`` will
work.


KeyboardInterrupt and SystemExit
--------------------------------

Both exceptions are no longer under Exception.  This is to allow bare
``except`` clauses to act as a more viable default case by catching
exceptions that inherit from Exception.  With both KeyboardInterrupt
and SystemExit acting as signals that the interpreter is expected to
exit, catching them in the common case is the wrong semantics.


NotImplementedError
-------------------

Inherits from Exception instead of from RuntimeError.

Originally inheriting from RuntimeError, NotImplementedError does not
have any direct relation to the exception meant for use in user code
as a quick-and-dirty exception.  Thus it now directly inherits from
Exception.


Required Superclass for ``raise``
=================================

By requiring all objects passed to a ``raise`` statement to inherit
from a specific superclass, all exceptions are guaranteed to have
certain attributes.  If PEP 344 [#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.

The proposed hierarchy has BaseException as the required base class.


Implementation
--------------

Enforcement is straightforward.  Modifying ``RAISE_VARARGS`` to do an
inheritance check first before raising an exception should be enough.
For the C API, all functions that set an exception will have the same
inheritance check applied.


Bare ``except`` Clauses Catch Exception
=======================================

In most existing Python 2.4 code, bare ``except`` clauses are too
broad in the exceptions they catch.  Typically only exceptions that
signal an error are desired to be caught.  This means that exceptions
that are used to signify that the interpreter should exit should not
be caught in the common case.

With KeyboardInterrupt and SystemExit moved to inherit from
BaseException instead of Exception, changing bare ``except`` clauses
to act as ``except Exception`` becomes a much more reasonable
default.  This change also will break very little code since these
semantics are what most people want for bare ``except`` clauses.

The complete removal of bare ``except`` clauses has been argued for.
The case has been made that they violate both Only One Way To Do It
(OOWTDI) and Explicit Is Better Than Implicit (EIBTI) as listed in the
Zen of Python [#zen]_.  But Practicality Beats Purity (PBP), also in
the Zen of Python, trumps both of these in this case.  The BDFL has
stated that bare ``except`` clauses will work this way
[#python-dev8]_.


Implementation
--------------

The compiler will emit the bytecode for ``except Exception`` whenever
a bare ``except`` clause is reached.


Transition Plan
===============

Because of the complexity and clutter that would be required to add
all features planned in this PEP, the transition plan is very simple.
In Python |2.x| BaseException is added.  In Python 3.0, all remaining
features (required superclass, change in inheritance, bare ``except``
clauses becoming the same as ``except Exception``) will go into
affect.  In order to make all of this work in a backwards-compatible
way in Python |2.x| would require very deep hacks in the exception
machinery which could be error-prone and lead to a slowdown in
performance for little benefit.

To help with the transition, the documentation will be changed to
reflect several programming guidelines:

- When one wants to catch *all* exceptions, catch BaseException
- To catch all exceptions that do not represent the termination of
  the interpreter, catch Exception explicitly
- Explicitly catch KeyboardInterrupt and SystemExit; don't rely on
  inheritance from Exception to lead to the capture
- Always catch NotImplementedError explicitly instead of relying on
  the inheritance from RuntimeError

The documentation for the 'exceptions' module [#exceptions-stdlib]_,
tutorial [#tutorial]_, and PEP 290 [#PEP290]_ will all require
updating.


Rejected Ideas
==============

DeprecationWarning Inheriting From PendingDeprecationWarning
------------------------------------------------------------

This was originally proposed because a DeprecationWarning can be
viewed as a PendingDeprecationWarning that is being removed in the
next version.  But since enough people thought the inheritance could
logically work the other way around, the idea was dropped.


AttributeError Inheriting From TypeError or NameError
-----------------------------------------------------

Viewing attributes as part of the interface of a type caused the idea
of inheriting from TypeError.  But that partially defeats the thinking
of duck typing and thus the idea was dropped.

Inheriting from NameError was suggested because objects can be viewed
as having their own namespace where the attributes live and when an
attribute is not found it is a namespace failure.  This was also
dropped as a possibility since not everyone shared this view.


Removal of EnvironmentError
---------------------------

Originally proposed based on the idea that EnvironmentError was an
unneeded distinction, the BDFL overruled this idea [#python-dev4]_.


Introduction of MacError and UnixError
--------------------------------------

Proposed to add symmetry to WindowsError, the BDFL said they won't be
used enough [#python-dev4]_.  The idea of then removing WindowsError
was proposed and accepted as reasonable, thus completely negating the
idea of adding these exceptions.


SystemError Subclassing SystemExit
----------------------------------

Proposed because a SystemError is meant to lead to a system exit, the
idea was removed since CriticalError indicates this better.


ControlFlowException Under Exception
------------------------------------

It has been suggested that ControlFlowException should inherit from
Exception.  This idea has been rejected based on the thinking that
control flow exceptions typically do not all need to be caught by a
single ``except`` clause.

Rename NameError to NamespaceError
----------------------------------

NameError is considered more succinct and leaves open no possible
mistyping of
the capitalization of "Namespace" [#python-dev5]_.


Renaming RuntimeError or Introducing SimpleError
''''''''''''''''''''''''''''''''''''''''''''''''

The thinking was that RuntimeError was in no way an obvious name for
an exception meant to be used when a situation did not call for the
creation of a new exception.  The renaming was rejected on the basis
that the exception is already used throughout the interpreter
[#python-dev6]_.
Rejection of SimpleError was founded on the thought that people
should be free to use whatever exception they choose and not have one
so blatently suggested [#python-dev7]_.

Renaming Existing Exceptions
----------------------------

Various renamings were suggested but non garnered more than a +0 vote
(renaming ReferenceError to WeakReferenceError).  The thinking was
that the existing names were fine and no one had actively complained
about them ever.  To minimize backwards-compatibility issues and
causing existing Python programmers extra pain, the renamings were
removed.

Have EOFError Subclass IOError
------------------------------

The original thought was that since EOFError deals directly with I/O,
it should
subclass IOError.  But since EOFError is used more as a signal that an
event
has occurred (the exhaustion of an I/O port), it should not subclass
such a specific error exception.


Have MemoryError and SystemError Have a Common Superclass
---------------------------------------------------------

Both classes deal with the interpreter, so why not have them have a
common
superclass?  Because one of them means that the interpreter is in a
state that it should not recover from while the other does not.


Common Superclass for PendingDeprecationWarning and DeprecationWarning
----------------------------------------------------------------------

Grouping the deprecation warning exceptions together makes intuitive
sense.
But this sensical idea does not extend well when one considers how
rarely either warning is used, let along at the same time.


Removing WindowsError
---------------------

Originally proposed based on the idea that having such a
platform-specific exception should not be in the built-in namespace.
It turns out, though, enough code exists that uses the exception to
warrant it staying.


Superclass for KeyboardInterrupt and SystemExit
-----------------------------------------------

Proposed to make catching non-Exception inheriting exceptions easier
along with easing the transition to the new hierarchy, the idea was
rejected by the BDFL [#python-dev8]_.  The argument that existing
code did not show enough instances of the pair of exceptions being
caught and thus did not justify cluttering the built-in namespace
was used.


Acknowledgements
================

Thanks to Robert Brewer, Josiah Carlson, Nick Coghlan, Timothy
Delaney, Jack Diedrich, Fred L. Drake, Jr., Philip J. Eby, Greg Ewing,
James Y. Knight, MA Lemburg, Guido van Rossum, Stephen J. Turnbull,
Raymond Hettinger, and everyone else I missed for participating in the
discussion.


References
==========

.. [#PEP342] PEP 342 (Coroutines via Enhanced Generators)
   http://www.python.org/dev/peps/pep-0342/

.. [#PEP344] PEP 344 (Exception Chaining and Embedded Tracebacks)
   http://www.python.org/dev/peps/pep-0344/

.. [#PEP290] PEP 290 (Code Migration and Modernization)
   http://www.python.org/dev/peps/pep-0290/

.. [#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

.. [#python-dev3] python-dev email (PEP, take 2: Exception
   Reorganization for Python 3.0)
   http://mail.python.org/pipermail/python-dev/2005-August/055116.html

.. [#exceptions-stdlib] exceptions module
   http://docs.python.org/library/exceptions.html

.. [#python-dev-thread1] python-dev thread (Pre-PEP: Exception
   Reorganization for Python 3.0)
   http://mail.python.org/pipermail/python-dev/2005-July/055020.html,
   http://mail.python.org/pipermail/python-dev/2005-August/055065.html

.. [#python-dev-thread2] python-dev thread (PEP, take 2: Exception
   Reorganization for Python 3.0)
   http://mail.python.org/pipermail/python-dev/2005-August/055103.html

.. [#python-dev-thread3] python-dev thread (Reorg PEP checked in)
    http://mail.python.org/pipermail/python-dev/2005-August/055138.html

.. [#python-dev-thread4] python-dev thread (Major revision of PEP 348 committed)
   http://mail.python.org/pipermail/python-dev/2005-August/055199.html

.. [#python-dev-thread5] python-dev thread (Exception Reorg PEP revised yet again)
   http://mail.python.org/pipermail/python-dev/2005-August/055292.html

.. [#python-dev-thread6] python-dev thread (PEP 348 (exception reorg) revised again)
   http://mail.python.org/pipermail/python-dev/2005-August/055412.html

.. [#python-dev4] python-dev email (Pre-PEP: Exception Reorganization
   for Python 3.0)
   http://mail.python.org/pipermail/python-dev/2005-July/055019.html

.. [#python-dev5] python-dev email (PEP, take 2: Exception Reorganization for
    Python 3.0)
    http://mail.python.org/pipermail/python-dev/2005-August/055159.html

.. [#python-dev6] python-dev email (Exception Reorg PEP checked in)
    http://mail.python.org/pipermail/python-dev/2005-August/055149.html

.. [#python-dev7] python-dev email (Exception Reorg PEP checked in)
    http://mail.python.org/pipermail/python-dev/2005-August/055175.html

.. [#python-dev8] python-dev email (PEP 348 (exception reorg) revised again)
   http://mail.python.org/pipermail/python-dev/2005-August/055423.html

.. [#zen] PEP 20 (The Zen of Python)
   http://www.python.org/dev/peps/pep-0020/

.. [#tutorial] Python Tutorial
   http://docs.python.org/tutorial/

.. [#rejected] python-dev email (Bare except clauses in PEP 348)
   http://mail.python.org/pipermail/python-dev/2005-August/055676.html


Copyright
=========

This document has been placed in the public domain.


..
   Local Variables:
   mode: indented-text
   indent-tabs-mode: nil
   sentence-end-double-space: t
   fill-column: 70
   End: