[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