[Python-Dev] Comments of the PEP 3151

Victor Stinner victor.stinner at haypocalc.com
Mon Jul 25 01:56:32 CEST 2011


Arguments in favor of specific errors
-------------------------------------

Using specific errors avoids the need of "import errno". The import is
sometimes done in the except block, which may raise a new error (and may
be slow).

I like specific exceptions because it avoids the need of re-raise
unwanted exception. It makes the code more readable: we ignore
explicitly specific errors instead of re-raised unwanted exceptions and
implicitly ignore some errors. For example:

     try:
         os.mkdir(dir)
     except OSError as err:
         if err.errno != errno.EEXIST:
             raise

becomes

     try:
         os.mkdir(dir)
     except FileExistsError:
         pass

By the way, is it faster to not handle and than re-raise unwanted
exceptions?

(I don't like tests like "err.errno != errno.EEXIST", it's confusing to
me. It uses errno identifier twice: once as an attribute, once as a
module name.)


Make specific errors builtins
-----------------------------

I agree that it's better to make specific errors builtins.

If we move exceptions to more specific modules, like io and socket, you
have to load these modules to catch an exception and remember in which
module the exception is. An advantage of builtin specific exceptions is
to avoid an import (import errno).

Making them builtin may also avoid a bootstrap issue (catch a specific
error at startup).


Choice of the specific errors
-----------------------------

I don't understand how Antoine decided which errno should have an
exception or not.

For example, EINTR and EPIPE are handled in many modules of the standard
library but don't have their exception, whereas EISDIR
(IsADirectoryError) and ENOTDIR (NotADirectoryError) are very rare
(EISDIR is never handled in the standard library) but have their
exception.

If we add EINTR, I don't know if it's better to add it to
BlockingIOError or to create a new exception (InterruptError?).

Another good candidate is EINVAL.

Would it be possible to have an (exhaustive?) list of errno with their
popularity? At least, their popularity in the Python standard library?


Raise a specific error
----------------------

Does raising a specific error (e.g. raise FileNotFound()) set errno and
message attributes (to something different than None)?

If we provide an error message error: should it be localized? The
description of FileDescriptorError tells about the "default error
message". It we use a localized message, it's not possible to
preallocate or cache instances.

I don't see how we could choose a default errno value, because some
exceptions handle multiple errno. For example, PermissionError.errno can
be EACCES or EPERM.

Do specific errors slows down raising exceptions? Do raising an IOError
(or a "legacy" error) use a O(1) lookup to choose the exception class?


PermissionError
---------------

EACCES and EPERM have a different meaning. Even that they are very
similar, we might provide two different exceptions. EPERM is only used
once in the Python stdlib, so we might only provide AccesError.

On Linux, EPERM usually indicates an operation requiring root
priviledge.  EACCES can be related to filesystem permissions (read-only,
user is not allowed to write, etc.) or can be an mmap error.


Deprecation
-----------

Because IOError, OSError, select.error, etc. are well known exceptions,
I'm not in favor of removing them from Python 3. It would make porting
from Python 2 worse. If we don't remove them, they should not be
deprecated.

I'm in favor of adding a note in the documentation of all legacy
exceptions to advice to use IOError or specific exceptions instead. I
suppose that these notes will have to indicate a Python version.


Test the implementation
-----------------------

Did someone test Blender, Django or another major applications on the
implementation of the PEP 3151?


-1 on FileSystemError
---------------------

I'm not sure that we need FileSystemError or ConnectionError. Careless
code will use IOError, whereas careful code will use an explicit list
like (ConnectionAbortedError, ConnectionRefusedError,
ConnectionResetError).

If we remove IsADirectoryError and NotADirectoryError, FileSystemError
only contains FileExistsError and FileNotFoundError. I don't think that
these errors can occur on a same function. For example, rmdir() only
raises ENOTDIR.

I only see one advantage of FileSystemError: it doesn't handle
FileDescriptorError. Advice usage of FileSystemError would avoid to hide
real bugs like FileDescriptorError.

I don't really care of ConnectionError. Anyway, FileSystemError and
ConnectionError can be added later if needed.

WindowsError and winerror attribute
-----------------------------------

I don't like the idea of having a winerror attribute platforms other
than Windows. Why not using hasattr(err, "winerror") instead?
WindowsError is already specific to Windows. I don't see any usage of
the winerror attribute in the Python stdlib.

shutil module uses:

     try:
         WindowsError
     except NameError:
         WindowsError = None

     (...)

     try:
         copystat(src, dst)
     except OSError as why:
         if WindowsError is not None and isinstance(why, WindowsError):
             # Copying file access times may fail on Windows
             pass
         else:
             errors.extend((src, dst, str(why)))


Misc
----

Lock.acquire() doesn't raise an exception on timeout: just remove "(for
example in Lock.acquire())".

Should FileNotFound handle ENODEV? (see test_ossaudiodev)

Victor



More information about the Python-Dev mailing list