I have somewhat mixed feelings about Python 3's socket
module errors
Many years ago I wrote about some things that irritated me about
Python 2's socket
module. One of my
complaints was that many instances of socket.error
should actually
be IOError
or OSError
instead of a separate type, because that's
what they really were. Today I was reading AdamW’s Debugging
Adventures: Python 3 Porting 201
(via), where I discovered in a passing
mention that in Python 3, socket.error
is a deprecated alias of
OSError
.
(Well, from Python 3.3 onwards, due to PEP 3151.)
On the one hand, this is a change that I cautiously approve of.
Many socket errors are just operating system errors, especially on
Unix. On the other hand, in some ways this makes socket.herror
and socket.gaierror
feel worse. Both of these violate the rule
of leaving IOError and OSError alone, because
they are subclasses of OSError
that do not have authentic errno
values and are not quite genuine OS errors in the same way (they
are errors from the C library, but they don't come from errno
).
They do have errno
and strerror
fields, which is something, but
then I think all subclasses of OSError
do these days.
Somewhat to my surprise, when I looked at the Python 2 socket
module I discovered
that socket.error
is now a subclass of IOError
(since Python
2.6, which in practice means 'on any system with Python 2 that you
actually want to use'). Python 2 also has the same issue where
socket.herror
and socket.gaierror
are subclasses of socket.error
but are not real operating system errors.
Unfortunately for my feelings about leaving OSError alone, the
current situation in the socket
module is probably the best
pragmatic tradeoff. Since the module has high level interfaces that
can fail in multiple ways that result in different types of errors,
in practice people want to be able to just catch one overall error
and be done with it, which means that socket.gaierror
really
needs to be a subclass of socket.error
. When you combine this
with socket.error
really being some form of OSError
, you arrive
at the current state of affairs.
I've decided that I don't have a strong opinion on socket.error
changing from being a subclass of IOError/OSError to being an alias
for it. I can imagine Python code that might want to use try
at
a high level, call both socket functions and other OS functions
within that high level try
, and distinguish between the two sources
of errors, which is now impossible in Python 3, but I'm not sure
that this is a desirable pattern. I don't think I have anything like
this in my own Python code, but it's something that I should keep an
eye out for as I convert things over to Python 3.
(I do have some Python 2 code that catches both socket.error
and
EnvironmentError
, but fortunately it treats them the same.)
|
|