[Python-checkins] r83020 - sandbox/trunk/errnopep/pepXXXX.txt
antoine.pitrou
python-checkins at python.org
Wed Jul 21 15:40:35 CEST 2010
Author: antoine.pitrou
Date: Wed Jul 21 15:40:35 2010
New Revision: 83020
Log:
Add some considerations
Modified:
sandbox/trunk/errnopep/pepXXXX.txt
Modified: sandbox/trunk/errnopep/pepXXXX.txt
==============================================================================
--- sandbox/trunk/errnopep/pepXXXX.txt (original)
+++ sandbox/trunk/errnopep/pepXXXX.txt Wed Jul 21 15:40:35 2010
@@ -13,6 +13,24 @@
Abstract
========
+The standard exception hierarchy is an important part of the Python
+language. It has two defining qualities: it is both generic and
+selective. Generic in that the same exception type can be raised
+- and handled - regardless of the context (for example, whether you are
+trying to add something to an integer, to call a string method, or to write
+an object on a socket, a TypeError will be raised for bad argument types).
+Selective in that it allows the user to easily handle (silence, examine,
+process, store or encapsulate...) specific kinds of error conditions
+while letting other errors bubble up to higher calling contexts. For
+example, you can choose to catch ZeroDivisionErrors without affecting
+the default handling of other ArithmeticErrors (such as OverflowErrors).
+
+This PEP proposes changes to a part of the exception hierarchy in order
+to better embody the qualities mentioned above: the errors related to
+operating system calls (OSError, IOError, select.error, and all their
+subclasses).
+
+
Rationale
=========
@@ -29,7 +47,6 @@
+-- socket.error
+-- OSError
+-- WindowsError
-
+-- select.error
While some of these distinctions can be explained by implementation
@@ -54,11 +71,17 @@
part of the interpreter it comes from (since the latter is obvious from
reading the traceback message or application source code).
+In fact, it is hard to think of any situation where OSError should be
+caught but not IOError, or the reverse.
+
A further proof of the ambiguity of this segmentation is that the standard
library itself sometimes has problems deciding. For example, in the
``select`` module, similar failures will raise either ``select.error``,
``OSError`` or ``IOError`` depending on whether you are using select(),
-a poll object, a kqueue object, or an epoll object.
+a poll object, a kqueue object, or an epoll object. This makes user code
+uselessly complicated since it has to be prepared to catch various
+exception types, depending on which exact implementation of a single
+primitive it chooses to use at runtime.
As for WindowsError, it seems to be a pointless distinction. First, it
only exists on Windows systems, which requires tedious compatibility code
@@ -121,6 +144,13 @@
pass
+Moratorium
+==========
+
+The moratorium in effect on language builtins means this PEP has little
+chance to be accepted for Python 3.2.
+
+
Step 1: coalesce exception types
================================
@@ -129,7 +159,7 @@
changes are listed hereafter::
* alias both socket.error and select.error to IOError
-* alias OSError to IOError
+* alias IOError to OSError
* alias WindowsError to OSError
Each of these changes doesn't preserve exact compatibility, but it does
@@ -140,15 +170,21 @@
it also allows for a better and more complete resolution of step 2
(see "Prerequisite" below).
+Deprecation of names
+--------------------
+
+It is not yet decided whether the old names will be deprecated (then removed)
+or all alternative names will continue living in the root namespace.
+
Step 2: define additional subclasses
====================================
The second step of the resolution is to extend the hierarchy by defining
subclasses which will be raised, rather than their parent, for specific
-errno values. Which errno values is not decided yet, but a survey of
-existing exception matching practices (see Appendix A) will help us
-choose a reasonable subset of all values. Trying to map all errno
+errno values. Which errno values is subject to discussion, but a survey
+of existing exception matching practices (see Appendix A) helps us
+propose a reasonable subset of all values. Trying to map all errno
mnemonics, indeed, seems foolish, pointless, and would pollute the root
namespace.
@@ -156,10 +192,9 @@
the same exception subclass. For example, EAGAIN, EALREADY, EWOULDBLOCK
and EINPROGRESS are all used to signal that an operation on a non-blocking
socket would block (and therefore needs trying again later). They could
-therefore all raise an identical subclass (perhaps even the existing
-``io.BlockingIOError``) and let the user examine the ``errno`` attribute
-if (s)he so desires (see below "exception attributes").
-
+therefore all raise an identical subclass and let the user examine the
+``errno`` attribute if (s)he so desires (see below "exception
+attributes").
Prerequisite
------------
@@ -183,6 +218,51 @@
ones). It would, however, make the hierarchy more complicated and
therefore harder to grasp for the user.
+New exception classes
+---------------------
+
+The following temptative list of subclasses, along with a description and
+the list of errnos mapped to them, is submitted to discussion:
+
+* FileAlreadyExists: trying to create a file or directory which already
+ exists (EEXIST)
+
+* FileNotFound: for all circumstances where a file and directory is
+ requested but doesn't exist (ENOENT)
+
+* IsADirectory: file-level operation (open(), os.remove()...) requested
+ on a directory (EISDIR)
+
+* NotADirectory: directory-level operation requested on something else
+ (ENOTDIR)
+
+* PermissionDenied: trying to run an operation without the adequate access
+ rights - for example filesystem permissions (EACCESS, optionally EPERM)
+
+* BlockingIOError: an operation would block on an object (e.g. socket) set
+ for non-blocking operation (EAGAIN, EALREADY, EWOULDBLOCK, EINPROGRESS);
+ this is the existing ``io.BlockingIOError`` with an extended role
+
+* BadFileDescriptor: operation on an invalid file descriptor (EBADF);
+ the default error message could point out that most causes are that
+ an existing file descriptor has been closed
+
+* ConnectionAborted: connection attempt aborted by peer (ECONNABORTED)
+
+* ConnectionRefused: connection reset by peer (ECONNREFUSED)
+
+* ConnectionReset: connection reset by peer (ECONNRESET)
+
+* TimeoutError: connection timed out (ECONNTIMEOUT); this could be re-cast
+ as a generic timeout exception, useful for other types of timeout (for
+ example in Lock.acquire())
+
+This list assumes step 1 is accepted in full; the exception classes
+described above would all derive from the now unified exception type
+OSError. It will need reworking if a partial version of step 1 is accepted
+instead (again, see appendix A for the current distribution of errnos
+and exception types).
+
Exception attributes
--------------------
@@ -192,6 +272,27 @@
superclass (for example ``errno``, ``filename``, and optionally
``winerror``).
+Implementation
+--------------
+
+Since it is proposed that the subclasses are raised based purely on the
+value of ``errno``, little or no changes should be required in extension
+modules (either standard or third-party). As long as they use the
+``PyErr_SetFromErrno()`` family of functions (or the
+``PyErr_SetFromWindowsErr()`` family of functions under Windows), they
+should automatically benefit from the new, finer-grained exception classes.
+
+Library modules written in Python, though, will have to be adapted where
+they currently use the following idiom::
+
+ raise OSError(errno.ENOTDIR, "execve called")
+
+Fortunately, such Python code is quite rare since raising OSError or IOError
+with an errno value normally happens when interfacing with system calls,
+which is usually done in C extensions.
+
+If there is popular demand, the subroutine choosing an exception type based
+on the errno value could be exposed for use in pure Python.
Compatibility concerns
@@ -233,6 +334,28 @@
Careful code should not be penalized.
+Possible objections
+===================
+
+Namespace pollution
+-------------------
+
+Making the exception hierarchy finer-grained makes the root (or builtins)
+namespace larger. This is to be moderated, however, as:
+
+* only a handful of additional classes are proposed;
+
+* while standard exception types live in the root namespace, they are
+ visually distinguished by the fact that they use the CamelCase convention,
+ while almost all other builtins use lowercase naming (except True, False,
+ None, Ellipsis and NotImplemented)
+
+An alternative would be to provide a separate module containing the
+finer-grained exceptions, but that would defeat the purpose of
+encouraging careful code over careless code, since the user would first
+have to import the new module instead of using names already accessible.
+
+
Possible alternative
====================
More information about the Python-checkins
mailing list