Comments of the PEP 3151
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
Hello,
By the way, is it faster to not handle and than re-raise unwanted exceptions?
You mean "is it faster to not handle than re-raise unwanted exceptions?". It probably is, yes.
I don't understand how Antoine decided which errno should have an exception or not.
Mostly experience with the stdlib combined with intuition. The list is not cast in stone.
If we add EINTR, I don't know if it's better to add it to BlockingIOError or to create a new exception (InterruptError?).
EINTR is not related to non-blocking I/O, so it shouldn't map to BlockingIOError.
Would it be possible to have an (exhaustive?) list of errno with their popularity? At least, their popularity in the Python standard library?
How do you suggest to do that?
Does raising a specific error (e.g. raise FileNotFound()) set errno and message attributes (to something different than None)?
No, it doesn't. "errno" should IMO only be set if it's truely returned by a system routine. As for the message, like with every other exception it should be supplied by the developer.
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?
It uses a dict. You could run some benchmarks if you want, but I doubt it makes much sense to worry about that.
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.
I'd have to research that a bit more. Perhaps EACCES can be mapped to AccessError and EPERM to PermissionError, but I think the proximity of the two concepts will make things confusing, for little benefit.
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.
Ok. Does anyone else have an opinion on deprecations? (not deprecating them means less work for me, anyway)
Test the implementation -----------------------
Did someone test Blender, Django or another major applications on the implementation of the PEP 3151?
Does Django have a working Python 3 port yet?
WindowsError and winerror attribute -----------------------------------
I don't like the idea of having a winerror attribute platforms other than Windows.
Well, there isn't, as you can see in the tests (test_windows_error in Lib/test/test_pep3151.py).
shutil module uses:
(...)
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
That's the kind of code the PEP hopes to discourage :)
Lock.acquire() doesn't raise an exception on timeout: just remove "(for example in Lock.acquire())".
Oops, will fix.
Should FileNotFound handle ENODEV? (see test_ossaudiodev)
That's not really the same thing. For example, mmap says: [ENODEV] The fildes argument refers to a file whose type is not supported by mmap(). (http://www.opengroup.org/sud/sud1/xsh/mmap.htm) Regards Antoine.
Antoine Pitrou writes:
Did someone test Blender, Django or another major applications on the implementation of the PEP 3151?
Does Django have a working Python 3 port yet?
Define "working". Martin ported Django to Python 3 years ago as proof of concept, but never claimed it was ready for production use or as the main line of development.
On 25/07/2011 02:24, Antoine Pitrou wrote:
Hello,
By the way, is it faster to not handle and than re-raise unwanted exceptions?
You mean "is it faster to not handle than re-raise unwanted exceptions?". It probably is, yes.
I asked if: try: ... except FileNotFound: pass is faster than: try: ... except IOError as err: if err.errno != errno.ENOENT: raise else: pass f an IOError with errno != ENOENT is raised.
I don't understand how Antoine decided which errno should have an exception or not.
Mostly experience with the stdlib combined with intuition. The list is not cast in stone.
"The list is not cast in stone." : ok :-)
If we add EINTR, I don't know if it's better to add it to BlockingIOError or to create a new exception (InterruptError?).
EINTR is not related to non-blocking I/O, so it shouldn't map to BlockingIOError.
Ok, so let add InterruptError.
Would it be possible to have an (exhaustive?) list of errno with their popularity? At least, their popularity in the Python standard library?
How do you suggest to do that?
Use the list of all errno from the Appendix A, and then count the number of occurence in the Python source code (excluding the test suite). You can for example using a shell for that: $ grep -h -c EINVAL $(find -name "*.py"|grep -v Lib/test)|grep -v '^0$' 1 1 2 These numbers give an approximation of the popularity of the different errno.
Does raising a specific error (e.g. raise FileNotFound()) set errno and message attributes (to something different than None)?
No, ... As for the message, like with every other exception it should be supplied by the developer.
Ok, I agree.
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?
It uses a dict. You could run some benchmarks if you want, but I doubt it makes much sense to worry about that.
Ok, a dict should be fast.
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.
I'd have to research that a bit more. Perhaps EACCES can be mapped to AccessError and EPERM to PermissionError, but I think the proximity of the two concepts will make things confusing, for little benefit.
You are probable right.
WindowsError and winerror attribute -----------------------------------
I don't like the idea of having a winerror attribute platforms other than Windows.
Well, there isn't, as you can see in the tests
Oh, it's not clear in the PEP.
Should FileNotFound handle ENODEV? (see test_ossaudiodev)
That's not really the same thing.
Ok. Victor
On Mon, Jul 25, 2011 at 9:56 AM, Victor Stinner
By the way, is it faster to not handle and than re-raise unwanted exceptions?
Yes, but probably not that much faster given the overhead of instantiating the exception and unwinding the stack in the first place.
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.
We do tend to call isdir() fairly often, though. Part of the appeal of isdir() is the ugliness of using EAFP when you have to do explicit errno checks.
If we add EINTR, I don't know if it's better to add it to BlockingIOError or to create a new exception (InterruptError?).
InterruptedError seems like a reasonable candidate for addition to me - catch and retry in that case is something developers are likely to want to do. Perhaps EPIPE should map to FileDescriptorError along with EBADF, with different messages based on the exact error code? Potentially renamed to DescriptorStateError? I'm not sure of the reason for singling out EBADF for special treatment in this case - there are several other errno values that indicate a descriptor is no longer in a usable state (ECONSHUTDOWN would be another one, in the same vein as EPIPE). To be honest though, what's the use case for *catching* FileDescriptorError without catching IOError in general? Perhaps this one should be dropped entirely, to be handled by broadly catching IOError?
Another good candidate is EINVAL.
As with EBADF, I'm having trouble visualising a clear use case for handling things like EINVAL and EOPNOTSUP differently from other kinds of IO errors.
Would it be possible to have an (exhaustive?) list of errno with their popularity? At least, their popularity in the Python standard library?
Probably, but the stdlib is more a *generator* of low level exceptions, so our code likely isn't representative enough to get a decent set of numbers.
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.
We don't localize anything else, so there's no reason to start here.
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.
Code that cares can still fall back to exc.errno == EPERM. I don't think we'd be doing anyone any favours by exposing subtle distinctions like this at the Python level.
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.
+1 for grandfathering in the old exception names, but documenting the recommended alternatives as of 3.3.
-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.
And that's precisely why FileSystemError is worthwhile - to separate out when the FS is objecting, rather than there being something wrong with the internal application state or when a previously valid descriptor has become unusable for some reason. It may also be reasonable to return a new DeviceNotAvailableError for ENODEV and EBUSY (as a new FileSystemError subclass).
I don't really care of ConnectionError. Anyway, FileSystemError and ConnectionError can be added later if needed.
But the use case for grouping them is quite obvious - there's is plenty of application code that will want to handle them in a particular way, while allowing other kinds of IOError to propagate further up the stack. Baking this into the exception heirarchy is far more future proof than people making their own explicit lists. There may be some error codes that we choose to map to these generic errors, even if we don't give them their own exception types at this point (e.g. ECONSHUTDOWN could map directly to ConnectionError).
Should FileNotFound handle ENODEV? (see test_ossaudiodev)
See above for my suggestion of a specific DeviceNotAvailable exception. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia
On Mon, 25 Jul 2011 15:28:47 +1000
Nick Coghlan
If we add EINTR, I don't know if it's better to add it to BlockingIOError or to create a new exception (InterruptError?).
InterruptedError seems like a reasonable candidate for addition to me - catch and retry in that case is something developers are likely to want to do.
Ok, let's call it InterruptError then. InterruptedError sounds like the error was interrupted ;)
Perhaps EPIPE should map to FileDescriptorError along with EBADF, with different messages based on the exact error code? Potentially renamed to DescriptorStateError?
I'd rather have a separate BrokenPipeError for EPIPE. EBADF and EPIPE are really quite different; EPIPE indicates that the other end of the pipe closed it, while EBADF generally points to a programming error (you are giving an invalid file descriptor to a system routine).
To be honest though, what's the use case for *catching* FileDescriptorError without catching IOError in general? Perhaps this one should be dropped entirely, to be handled by broadly catching IOError?
Good point indeed.
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.
+1 for grandfathering in the old exception names, but documenting the recommended alternatives as of 3.3.
Ok.
It may also be reasonable to return a new DeviceNotAvailableError for ENODEV and EBUSY (as a new FileSystemError subclass).
EBUSY is really quite different from these other errors. It is triggered by runtime protections in the OS (can't destroy some object that is in use, see for example in pthread_cond_destroy: http://pubs.opengroup.org/onlinepubs/009604499/functions/pthread_cond_destro...), rather than indication some misassumption about the filesystem layout. As for ENODEV, I'll have to take a look.
There may be some error codes that we choose to map to these generic errors, even if we don't give them their own exception types at this point (e.g. ECONSHUTDOWN could map directly to ConnectionError).
Good point as well. Regards Antoine.
On 7/25/2011 3:43 AM, Antoine Pitrou wrote:
On Mon, 25 Jul 2011 15:28:47 +1000 Nick Coghlan
wrote: If we add EINTR, I don't know if it's better to add it to BlockingIOError or to create a new exception (InterruptError?).
InterruptedError seems like a reasonable candidate for addition to me - catch and retry in that case is something developers are likely to want to do.
Ok, let's call it InterruptError then. InterruptedError sounds like the error was interrupted;)
Sorry, no. "InterruptError" sounds too much like a CPU interrupt signal, which the error is not. "InterruptedError" is OK by me, I don't see the confusion you do. But maybe "InterruptedOperationError" would be the most clear. Way too long, of course, so maybe "InterruptedAPIError" or "InterruptedOpError" or "EINTRError" in my order of preference.
Glenn Linderman wrote:
On 7/25/2011 3:43 AM, Antoine Pitrou wrote:
On Mon, 25 Jul 2011 15:28:47 +1000 Nick Coghlan
wrote: If we add EINTR, I don't know if it's better to add it to BlockingIOError or to create a new exception (InterruptError?).
InterruptedError seems like a reasonable candidate for addition to me - catch and retry in that case is something developers are likely to want to do.
Ok, let's call it InterruptError then. InterruptedError sounds like the error was interrupted ;)
Sorry, no. "InterruptError" sounds too much like a CPU interrupt signal, which the error is not.
It does, a bit -- but is that something we need to worry about at the Python level? Seems to me we should have the names make sense for Python, and not worry about what assembly, C, Pascal, Perl, or <insert language X here> names might mean for them.
"InterruptedError" is OK by me, I don't see the confusion you do. But maybe "InterruptedOperationError" would be the most clear. Way too long, of course, so maybe "InterruptedAPIError" or "InterruptedOpError" or "EINTRError" in my order of preference.
Please not that last one! ;) I prefer InterruptedError or InterruptError. ~Ethan~
Ethan Furman wrote:
[…] or "EINTRError" in my order of preference.
Please not that last one! ;)
Why not, exactly? When EINTR happens it's frequently a surprise, but programmers new to the concept can always search the web for advice on what causes it and how to deal with it (and after several attempts at dealing with it they may even get it right). Searching Google for “InterruptedError” isn't going to find anything helpful today, and eventually what I expect it would find is a bunch of pages saying “Look up EINTR.” How about we just cut out that middle step and call it what the rest of the world calls it? If “InterruptedError” were going to be used for anything other than EINTR then I could see an argument for abstracting the concept behind a platform-independent name. But I think it would be a mistake to treat anything else as being the same as EINTR. -Andrew.
On Tue, Jul 26, 2011 at 10:26 AM, Andrew Bennetts
When EINTR happens it's frequently a surprise, but programmers new to the concept can always search the web for advice on what causes it and how to deal with it (and after several attempts at dealing with it they may even get it right). Searching Google for “InterruptedError” isn't going to find anything helpful today, and eventually what I expect it would find is a bunch of pages saying “Look up EINTR.” How about we just cut out that middle step and call it what the rest of the world calls it?
If “InterruptedError” were going to be used for anything other than EINTR then I could see an argument for abstracting the concept behind a platform-independent name. But I think it would be a mistake to treat anything else as being the same as EINTR.
The whole point of PEP 3151 is so that Python programmers can perform key tasks without needing to worry about the existence of error numbers under the hood. Including the cryptic errno abbreviations in the interrupt names would completely miss the point. However, the docs will point to appropriate information in the errno module (and the exception details and docstrings may also mention the errno codes). Abstractions do leak, after all, but that doesn't mean we need to go punching holes in them with an icepick. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia
Andrew Bennetts wrote:
Ethan Furman wrote:
[…] or "EINTRError" in my order of preference.
Please not that last one! ;)
Why not, exactly?
Because this is Python, and readability counts. Yes, it does take some getting used to (I finally stopped typing 'enum' a couple months ago ;) , but it is a worthwhile goal -- a goal we take a step back from with names like EINTRError instead of InterruptedError. ~Ethan~
On Tue, Jul 26, 2011 at 4:44 AM, Ethan Furman
Glenn Linderman wrote:
On 7/25/2011 3:43 AM, Antoine Pitrou wrote:
Ok, let's call it InterruptError then. InterruptedError sounds like the error was interrupted ;)
Sorry, no. "InterruptError" sounds too much like a CPU interrupt signal, which the error is not.
It does, a bit -- but is that something we need to worry about at the Python level? Seems to me we should have the names make sense for Python, and not worry about what assembly, C, Pascal, Perl, or <insert language X here> names might mean for them.
Like Glenn, I believe "InterruptError" sounds wrong - the event being reported is that a system call was interrupted for some unknown reason, not necessarily that the process received an interrupt. 'Interrupt' in computer science requires context to distinguish between the verb and noun forms, and an exception name doesn't provide that context. 'Interrupted' forces interpretation as the past tense of the verb form, which is the meaning we want. If the subject of the verb feels too ambiguous then I'd prefer to switch to the explicit adjective form 'InterruptedCallError' rather than allowing the verb/noun ambiguity. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia
Glenn Linderman writes:
Sorry, no. "InterruptError" sounds too much like a CPU interrupt signal, which the error is not. "InterruptedError" is OK by me, I don't see the confusion you do. But maybe "InterruptedOperationError" would be the most clear. Way too long, of course, so maybe "InterruptedAPIError" or "InterruptedOpError" or "EINTRError" in my order of preference.
Eh, doesn't it bother anybody that it's not an error, but a user action? If it needs a separate name, something like InterruptException seems most accurate to me.
On Tue, Jul 26, 2011 at 1:47 PM, Stephen J. Turnbull
Eh, doesn't it bother anybody that it's not an error, but a user action?
Nope, doesn't bother me in the slightest. It's an error number code, just like all the others. Several other error numbers may or may not be errors too, depending on context. Rather than quibbling about that part of the naming scheme it's easier to say that the call failing to complete successfully is an error by default, but an application may choose to interpret some cases as not really being errors, since there's a defined response (most obvious case: a file or directory already existing or not existing often isn't an error from the application's point of view, it's just the application ensuring that a particular configuration exists on the file system in an idempotent fashion). Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia
On Mon, 25 Jul 2011 15:28:47 +1000
Nick Coghlan
There may be some error codes that we choose to map to these generic errors, even if we don't give them their own exception types at this point (e.g. ECONSHUTDOWN could map directly to ConnectionError).
Ok, I can find neither ECONSHUTDOWN nor ECONNSHUTDOWN on www.opengroup.org, and it's not mentioned in errnomodule.c. Is it some system-specific error code? Regards Antoine.
On Jul 26, 2011, at 6:49 PM, Antoine Pitrou wrote:
On Mon, 25 Jul 2011 15:28:47 +1000 Nick Coghlan
wrote: There may be some error codes that we choose to map to these generic errors, even if we don't give them their own exception types at this point (e.g. ECONSHUTDOWN could map directly to ConnectionError).
Ok, I can find neither ECONSHUTDOWN nor ECONNSHUTDOWN on www.opengroup.org, and it's not mentioned in errnomodule.c. Is it some system-specific error code?
I assume that ESHUTDOWN is the errno in question? (This is also already mentioned in the PEP.)
On Tue, 26 Jul 2011 19:32:56 -0400
Glyph Lefkowitz
On Jul 26, 2011, at 6:49 PM, Antoine Pitrou wrote:
On Mon, 25 Jul 2011 15:28:47 +1000 Nick Coghlan
wrote: There may be some error codes that we choose to map to these generic errors, even if we don't give them their own exception types at this point (e.g. ECONSHUTDOWN could map directly to ConnectionError).
Ok, I can find neither ECONSHUTDOWN nor ECONNSHUTDOWN on www.opengroup.org, and it's not mentioned in errnomodule.c. Is it some system-specific error code?
I assume that ESHUTDOWN is the errno in question? (This is also already mentioned in the PEP.)
Indeed, I mentioned it in the PEP, as it appears in asyncore.py. But I can't find it on www.opengroup.org, and no man page on my Linux system (except the "errno" man page) seems to mention it. The description from errnomodule.c says "Cannot send after transport endpoint shutdown", but send() actually returns EPIPE, not ESHUTDOWN, when the socket has been shutdown:
conn = socket.create_connection(("www.python.org", 80)) conn.shutdown(socket.SHUT_WR) conn.send(b"xxx") Traceback (most recent call last): File "<stdin>", line 1, in <module> socket.error: [Errno 32] Broken pipe
From the send() man page: EPIPE The local end has been shut down on a connection oriented socket. In this case the process will also receive a SIGPIPE unless MSG_NOSIGNAL is set. Regards Antoine.
Some more digging indicates that ESHUTDOWN appears in asyncore with the
following commit:
changeset: 10934:c089020a7a1e
branch: legacy-trunk
user: Guido van Rossum
I assume that ESHUTDOWN is the errno in question? (This is also already mentioned in the PEP.)
Indeed, I mentioned it in the PEP, as it appears in asyncore.py. But I can't find it on www.opengroup.org, and no man page on my Linux system (except the "errno" man page) seems to mention it.
It's not POSIX, but it's defined on Linux and FreeBSD (at least): http://lxr.free-electrons.com/source/include/asm-generic/errno.h#L81 http://fxr.watson.org/fxr/source/sys/errno.h?v=FREEBSD53#L122
The description from errnomodule.c says "Cannot send after transport endpoint shutdown", but send() actually returns EPIPE, not ESHUTDOWN, when the socket has been shutdown:
Indeed, as required by POSIX. But grepping through the Linux kernel source code, it seems to be used extensively for USB devices, see http://lxr.free-electrons.com/ident?i=ESHUTDOWN So the "transport endpoint" doesn't necessarily refer to a socket. It's also documented in http://lxr.free-electrons.com/source/Documentation/usb/error-codes.txt Finally, I found one place in the networking stack where ESHUTDOWN is used, in the SCTP code: http://lxr.free-electrons.com/source/net/sctp/outqueue.c#L329
2011/7/27 Charles-François Natali
I assume that ESHUTDOWN is the errno in question? (This is also already mentioned in the PEP.)
Indeed, I mentioned it in the PEP, as it appears in asyncore.py. But I can't find it on www.opengroup.org, and no man page on my Linux system (except the "errno" man page) seems to mention it.
It's not POSIX, but it's defined on Linux and FreeBSD (at least): http://lxr.free-electrons.com/source/include/asm-generic/errno.h#L81 http://fxr.watson.org/fxr/source/sys/errno.h?v=FREEBSD53#L122
The description from errnomodule.c says "Cannot send after transport endpoint shutdown", but send() actually returns EPIPE, not ESHUTDOWN, when the socket has been shutdown:
Indeed, as required by POSIX.
But grepping through the Linux kernel source code, it seems to be used extensively for USB devices, see http://lxr.free-electrons.com/ident?i=ESHUTDOWN So the "transport endpoint" doesn't necessarily refer to a socket. It's also documented in http://lxr.free-electrons.com/source/Documentation/usb/error-codes.txt
Finally, I found one place in the networking stack where ESHUTDOWN is used, in the SCTP code: http://lxr.free-electrons.com/source/net/sctp/outqueue.c#L329
Perhaps the right thing to do is to just have a ConnectionBrokenError that covers EPIPE, ESHUTDOWN and ECONNRESET? The current version of the PEP has these as two separate exception types (BrokenPipeError for the first two and ConnectionResetError for the last), but I'm not seeing a strong reason to avoid combining them. (ECONNABORTED and ECONNREFUSED are different, since they relate to failures when *initiating* a connection) Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia
participants (9)
-
Andrew Bennetts
-
Antoine Pitrou
-
Charles-François Natali
-
Ethan Furman
-
Glenn Linderman
-
Glyph Lefkowitz
-
Nick Coghlan
-
Stephen J. Turnbull
-
Victor Stinner