diff --git a/pep-3151.txt b/pep-3151.txt index 8508c0976..40669dc08 100644 --- a/pep-3151.txt +++ b/pep-3151.txt @@ -167,11 +167,31 @@ Compatibility strategy Reworking the exception hierarchy will obviously change the exact semantics of at least some existing code. While it is not possible to improve on the current situation without changing exact semantics, it is possible to define -a narrower type of compatibility, which we will call **useful compatibility**, -and define as follows: +a narrower type of compatibility, which we will call *useful compatibility*. -* *useful compatibility* doesn't make exception catching any narrower, but - it can be broader for *naïve* exception-catching code. Given the following +For this we first must explain what we will call *careful* and *careless* +exception handling. *Careless* (or "naïve") code is defined as code which +blindly catches either of ``OSError``, ``IOError``, ``socket.error``, +``mmap.error``, ``WindowsError``, ``select.error`` without cheking the ``errno`` +attribute. This is because such exception types are much too broad to signify +anything. Either of them can be raised for error conditions as diverse as: a +bad file descriptor (which will usually indicate a programming error), an +unconnected socket (ditto), a socket timeout, a file type mismatch, an invalid +argument, a transmission failure, insufficient permissions, a non-existent +directory, a full filesystem, etc. + +(moreover, the use of certain of these exceptions is irregular; `Appendix B`_ +exposes the case of the `select`_ module, which raises different exceptions +depending on the implementation) + +*Careful* code is defined as code which, when catching any of the above +exceptions, examines the ``errno`` attribute to determine the actual error +condition and takes action depending on it. + +The we can define *useful compatibility* as follows: + +* useful compatibility doesn't make exception catching any narrower, but + it can be broader for *careless* exception-catching code. Given the following kind of snippet, all exceptions caught before this PEP will also be caught after this PEP, but the reverse may be false:: @@ -180,7 +200,7 @@ and define as follows: except OSError: pass -* *useful compatibility* doesn't alter the behaviour of *careful* +* useful compatibility doesn't alter the behaviour of *careful* exception-catching code. Given the following kind of snippet, the same errors should be silenced or re-raised, regardless of whether this PEP has been implemented or not:: @@ -191,13 +211,13 @@ and define as follows: if e.errno != errno.ENOENT: raise -The rationale for this compromise is that careless (or "naïve") code -can't really be helped, but at least code which "works" won't suddenly -raise errors and crash. This is important since such code is likely to -be present in scripts used as cron tasks or automated system administration -programs. +The rationale for this compromise is that careless code can't really be +helped, but at least code which "works" won't suddenly raise errors and +crash. This is important since such code is likely to be present in +scripts used as cron tasks or automated system administration programs. -Careful code should not be penalized. +Careful code, on the other hand, should not be penalized. Actually, one +purpose of this PEP is to ease writing careful code. .. _Step 1: @@ -481,6 +501,20 @@ The moratorium in effect on language builtins means this PEP has little chance to be accepted for Python 3.2. +Implementation +============== + +A reference implementation has been started in ``branches/pep-3151`` in the +Python SVN repository. For now only `Step 1`_ is implemented, and without +the deprecation warnings. However, it shows that coalescing the exception +types doesn't produce any significant annoyance in the standard library. +The only observed trouble is with the respective constructors of ``IOError`` +and ``WindowsError``, which are slightly incompatible. The way it is solved +is by keeping the ``IOError`` semantics and adding a fourth optional argument +to allow passing the Windows error code (which is different from the POSIX +errno). All ``PyErr_SetFromWindowsErr*`` functions still do the right thing. + + Possible alternative ====================