-
-
Notifications
You must be signed in to change notification settings - Fork 30.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Replace custom exceptions for timeouts with TimeoutError #86579
Comments
The socket module has a custom timeout exception "socket.timeout". The exception is documented https://docs.python.org/3/library/socket.html#socket.timeout as :
It's a distinct exception type and not the same as the global TimeoutError. >>> import socket
>>> socket.timeout == TimeoutError
False I like to follow the example of the deprecated "socket.error", replace the custom exception and make it an alias of TimeoutError. The risk is minimal. Both exceptions are subclasses of OSError. The change would not only make exception handling more consistent. It would also allow me to simplify some code in ssl and socket C code. I might even be able to remove the socket CAPI import from _ssl.c completely. |
There are also other distinct exceptions: multiprocessing.TimeoutError |
Thanks Serhiy! Andrew, Antoine, Yury, do you want to replace the custom Timeout exceptions in asyncio, multiprocessing, and concurrent with global TimeoutError, too? |
In futures and asyncio TimeoutError has no errno. I'm not sure should we care but I consider it as a show stopper. On another hand, two distinct timeout classes confuse people. I had many conversions about this during the aiohttp support. asyncio can raise both TimeoutError and asyncio.TimeoutError which is... unexpected at least. |
PyErr_SetString(PyErr_TimeoutError, "msg") and raise TimeoutError("msg") do not set any additional exception attributes. errno, strerror, filename, and filename2 are None: >>> try:
... raise TimeoutError("msg")
... except Exception as e:
... err = e
...
>>> err
TimeoutError('msg')
>>> (err.errno, err.filename, err.filename2, err.strerror)
(None, None, None, None) Is that a problem? |
Perhaps it is a good compromise. How many exceptions inherited from OSError have no errno set? Do we have a precedent in stdlib at all already? |
Yes, I think this is a problem. It is expected that an instance of OSError has valid errno. OSError is a merge of several old exception types, some of them did have errno, and others did not. Maybe add BaseTimeoutError and make TimeoutError a subclass of BaseTimeoutError and OSError? There as also several CancelledError, and exceptions with similar names and purpose, like asyncio.IncompleteReadError and http.client.IncompleteRead. |
They have an errno attribute, it's just to None by default. You have to call OSError with multiple arguments to set errno to a non-None value. |
I know that I just create OSError() with errno set to None. My question is: has the standard library such code examples already? |
I fixed many instantiations of OSError subclasses, but many are still left in Python code. |
Thus using bare TimeoutError in asyncio is safe, isn't it? |
There is another option: The subclasses of OSError could set a correct errno automatically. |
This is a good idea. Writing IsADirectoryError(errno.EISDIR, os.strerror(errno.EISDIR), filename) is boring. |
IMHO it's ok that exc.errno is None. It doesn't prevent to write code like: except OSError as exc:
if exc.errno == ...:
...
else:
... In the early days (first 5 years? :-D) of the asyncio documentation, TimeoutError was documented just as "TimeoutError", instead of "asyncio.TimeoutError". So if you followed carefully the asyncio documentation and wrote "except TimeoutError:", the except would never be reached beause asyncio.TimeoutError is *not* a subclass of the builtin Timeout... >>> issubclass(asyncio.TimeoutError, TimeoutError)
False It would be great to have a single TimeoutError class. I'm fine with having weird attributes depending who raise the exception. Honestly, in most cases "except TimeoutError:" is enough: there is no need to check for exception attributes. |
I see this issue as a follow-up of PEP-3151 which started to uniformize IOError, OSError and many variants that we had in Python 2. socket.timeout was introduced as a subclass of TimeoutError according to: In Python 3.9, socket.timeout and TimeoutError are subclasses of OSError but are different. I agree that it was confusion. |
Pull Request #23520 applies the discussed change to both asyncio and concurrent.futures. I did the minimally invasive change, libraries still use |
Andrew, could you please rebase your PR and get it submitted? |
Done. |
concurrent.futures.TimeoutError
andasyncio.TimeoutError
with builtinTimeoutError
#30197Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: