Skip to content

Map errno==ETIME to TimeoutError #83854

Open

Description

@YoSTEALTH
mannequin
BPO 39673
Nosy @ericvsmith, @giampaolo, @yaseppochi, @YoSTEALTH, @ZackerySpytz
PRs
  • gh-83854: Map errno==ETIME to TimeoutError #20253
  • Note: 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:

    assignee = None
    closed_at = None
    created_at = <Date 2020-02-18.09:51:59.405>
    labels = ['type-feature', '3.10']
    title = 'Map errno==ETIME to TimeoutError'
    updated_at = <Date 2020-05-26.12:20:54.219>
    user = 'https://github.com/YoSTEALTH'

    bugs.python.org fields:

    activity = <Date 2020-05-26.12:20:54.219>
    actor = 'eric.smith'
    assignee = 'none'
    closed = False
    closed_date = None
    closer = None
    components = []
    creation = <Date 2020-02-18.09:51:59.405>
    creator = 'YoSTEALTH'
    dependencies = []
    files = []
    hgrepos = []
    issue_num = 39673
    keywords = ['patch']
    message_count = 13.0
    messages = ['362187', '362188', '362190', '362191', '362192', '362200', '362201', '362204', '362205', '369924', '369932', '369960', '369973']
    nosy_count = 5.0
    nosy_names = ['eric.smith', 'giampaolo.rodola', 'sjt', 'YoSTEALTH', 'ZackerySpytz']
    pr_nums = ['20253']
    priority = 'normal'
    resolution = None
    stage = 'patch review'
    status = 'open'
    superseder = None
    type = 'enhancement'
    url = 'https://bugs.python.org/issue39673'
    versions = ['Python 3.10']

    Activity

    1. YoSTEALTH commented on Feb 18, 2020

      YoSTEALTHmannequin
      MannequinAuthor
      import os

      try:
      no = -62
      raise OSError(-no, os.strerror(-no))
      except TimeoutError:
      print('Success')
      except OSError as e:
      print('Failed:', e)
      # Failed: [Errno 62] Timer expired

      Shouldn't TimeoutError catch this error?

    2. ericvsmith commented on Feb 18, 2020

      @ericvsmith
      Member

      I don't see why it would. You're raising OSError, which is not a subclass of TimeoutError, so the TimeoutError code is not executing. You don't say, but I assume this is what you think should happen.

      The exception handling machinery does not look inside a raised exception to try to assign meaning to the values, so it doesn't know what errno=62 means. Nor should it: it's only based on the class of the exception, not its attributes.

    3. YoSTEALTH commented on Feb 18, 2020

      YoSTEALTHmannequin
      MannequinAuthor

      Since I provide OSError with appropriate errono, it raises that error for example:

      import os

      try:
      no = -11
      raise OSError(-no, os.strerror(-no))
      except BlockingIOError as e:
      print('Success:', e)
      # Success: [Errno 11] Resource temporarily unavailable
      except OSError as e:
      print('Failed:', e)

      should work the same to raise TimeoutError as well

    4. ericvsmith commented on Feb 18, 2020

      @ericvsmith
      Member

      In both examples, what's being printed? It's not clear from your messages.

    5. YoSTEALTH commented on Feb 18, 2020

      YoSTEALTHmannequin
      MannequinAuthor

      First example prints
      # Failed: [Errno 62] Timer expired

      Second example prints
      # Success: [Errno 11] Resource temporarily unavailable

    6. ericvsmith commented on Feb 18, 2020

      @ericvsmith
      Member

      Ah, I see.

      What platform are you on, and what's the value of errno.ETIMEDOUT?

      On cygwin I get:
      >>> errno.ETIMEDOUT
      116
      
      On a native Windows build I get:
      >>> errno.ETIMEDOUT
      10060
      
      and on Fedora I get:
      >>> errno.ETIMEDOUT
      110

      If you use errno.ETIMEDOUT instead of 62, do you get different behavior?

    7. YoSTEALTH commented on Feb 18, 2020

      YoSTEALTHmannequin
      MannequinAuthor

      I am on Linux 5.5.2-1-MANJARO

      >>> sorted(errno.errorcode.items())
      [(1, 'EPERM'), (2, 'ENOENT'), (3, 'ESRCH'), (4, 'EINTR'), (5, 'EIO'), (6, 'ENXIO'), (7, 'E2BIG'), (8, 'ENOEXEC'), (9, 'EBADF'), (10, 'ECHILD'), (11, 'EAGAIN'), (12, 'ENOMEM'), (13, 'EACCES'), (14, 'EFAULT'), (15, 'ENOTBLK'), (16, 'EBUSY'), (17, 'EEXIST'), (18, 'EXDEV'), (19, 'ENODEV'), (20, 'ENOTDIR'), (21, 'EISDIR'), (22, 'EINVAL'), (23, 'ENFILE'), (24, 'EMFILE'), (25, 'ENOTTY'), (26, 'ETXTBSY'), (27, 'EFBIG'), (28, 'ENOSPC'), (29, 'ESPIPE'), (30, 'EROFS'), (31, 'EMLINK'), (32, 'EPIPE'), (33, 'EDOM'), (34, 'ERANGE'), (35, 'EDEADLOCK'), (36, 'ENAMETOOLONG'), (37, 'ENOLCK'), (38, 'ENOSYS'), (39, 'ENOTEMPTY'), (40, 'ELOOP'), (42, 'ENOMSG'), (43, 'EIDRM'), (44, 'ECHRNG'), (45, 'EL2NSYNC'), (46, 'EL3HLT'), (47, 'EL3RST'), (48, 'ELNRNG'), (49, 'EUNATCH'), (50, 'ENOCSI'), (51, 'EL2HLT'), (52, 'EBADE'), (53, 'EBADR'), (54, 'EXFULL'), (55, 'ENOANO'), (56, 'EBADRQC'), (57, 'EBADSLT'), (59, 'EBFONT'), (60, 'ENOSTR'), (61, 'ENODATA'), (62, 'ETIME'), (63, 'ENOSR'), (64, 'ENONET'), (65, 'ENOPKG'), (66, 'EREMOTE'), (67, 'ENOLINK'), (68, 'EADV'), (69, 'ESRMNT'), (70, 'ECOMM'), (71, 'EPROTO'), (72, 'EMULTIHOP'), (73, 'EDOTDOT'), (74, 'EBADMSG'), (75, 'EOVERFLOW'), (76, 'ENOTUNIQ'), (77, 'EBADFD'), (78, 'EREMCHG'), (79, 'ELIBACC'), (80, 'ELIBBAD'), (81, 'ELIBSCN'), (82, 'ELIBMAX'), (83, 'ELIBEXEC'), (84, 'EILSEQ'), (85, 'ERESTART'), (86, 'ESTRPIPE'), (87, 'EUSERS'), (88, 'ENOTSOCK'), (89, 'EDESTADDRREQ'), (90, 'EMSGSIZE'), (91, 'EPROTOTYPE'), (92, 'ENOPROTOOPT'), (93, 'EPROTONOSUPPORT'), (94, 'ESOCKTNOSUPPORT'), (95, 'ENOTSUP'), (96, 'EPFNOSUPPORT'), (97, 'EAFNOSUPPORT'), (98, 'EADDRINUSE'), (99, 'EADDRNOTAVAIL'), (100, 'ENETDOWN'), (101, 'ENETUNREACH'), (102, 'ENETRESET'), (103, 'ECONNABORTED'), (104, 'ECONNRESET'), (105, 'ENOBUFS'), (106, 'EISCONN'), (107, 'ENOTCONN'), (108, 'ESHUTDOWN'), (109, 'ETOOMANYREFS'), (110, 'ETIMEDOUT'), (111, 'ECONNREFUSED'), (112, 'EHOSTDOWN'), (113, 'EHOSTUNREACH'), (114, 'EALREADY'), (115, 'EINPROGRESS'), (116, 'ESTALE'), (117, 'EUCLEAN'), (118, 'ENOTNAM'), (119, 'ENAVAIL'), (120, 'EISNAM'), (121, 'EREMOTEIO'), (122, 'EDQUOT'), (123, 'ENOMEDIUM'), (124, 'EMEDIUMTYPE'), (125, 'ECANCELED'), (126, 'ENOKEY'), (127, 'EKEYEXPIRED'), (128, 'EKEYREVOKED'), (129, 'EKEYREJECTED'), (130, 'EOWNERDEAD'), (131, 'ENOTRECOVERABLE'), (132, 'ERFKILL')]

      Its an automated process the value is return by the C/kernel. I suppose its calling ETIME

      ETIME - Timer expired (POSIX.1 (XSI STREAMS option)).
      (POSIX.1 says "STREAM ioctl(2) timeout".)
      ETIMEDOUT - Connection timed out (POSIX.1-2001).

      These are both timeout errors but only ETIMEDOUT is accounted for?

    8. ericvsmith commented on Feb 18, 2020

      @ericvsmith
      Member

      These are both timeout errors but only ETIMEDOUT is accounted for?

      Yes, only ETIMEDOUT is accounted for in Objects/exceptions.c. There's precedent for mapping multiple errnos to the same exception:

      ADD_ERRNO(BlockingIOError, EAGAIN);
      ADD_ERRNO(BlockingIOError, EALREADY);
      ADD_ERRNO(BlockingIOError, EINPROGRESS);
      ADD_ERRNO(BlockingIOError, EWOULDBLOCK);
      

      You should probably raise this on python-ideas. I don't know if ETIME has some other accepted meaning. It's not mapped to any other exception, so it could be easily added. The only thing it would affect are people who are catching OSError and TimeoutError and are expecting ETIME to give an OSError, which seems a pretty niche case. Or I guess people who only catch TimeoutError and want to not catch the case where errno==ETIME.

    9. YoSTEALTH commented on Feb 18, 2020

      YoSTEALTHmannequin
      MannequinAuthor

      If nothing else, it could be a feature of next Python release as its appropriate that TimeoutError catches both ETIME and ETIMEDOUT.

    10. 5 remaining items

    11. changed the title [-]TimeoutError[/-] [+]Map errno==ETIME to TimeoutError[/+] on Feb 18, 2020
    12. added
      type-featureA feature request or enhancement
      and removed
      type-bugAn unexpected behavior, bug, or error
      on Feb 18, 2020
    13. giampaolo commented on May 25, 2020

      @giampaolo
      Contributor

      I'm -1 about TimeoutError because the concept of "timeout" is generic enough to be often implemented as a custom exception, which poses questions re. backward/forward compatibilty. E.g. in psutil I have "TimeoutExpired", also providing a "seconds" attribute. Also I've probably never seen ETIME / ETIMEDOUT happening, whereas AFAIU the point of PEP-3151 was to create mappings for the most common errnos.

    14. yaseppochi commented on May 26, 2020

      yaseppochimannequin
      Mannequin

      First, let me say I like Giampaolo's TimeoutExpired *much* better as the name for this kind of exception! But that ship has sailed.

      I don't understand Giampaolo's comment. If I understand the claim correctly, the problem is that people who should be catching some application-specific exception may be misled into catching TimeoutError instead, or into trying to get application-specific attributes from TimeoutError. But that ship sailed with the creation of TimeoutError. (We have a whole fleet sailing with this exception.) Unless Giampaolo is proposing to deprecate TimeoutError? I'm sympathetic ;-), but deprecation is a PITA and takes forever.

      If we're not going to deprecate, it seems to me that it's much more developer-friendly to catch ETIME with TimeoutError, as that seems very likely to be the expected behavior. It's true that even if Giampaolo changes TimeoutExpired to subclass TimeoutError, generic TimeoutError won't have .seconds. But if you catch a TimeoutExpired with TimeoutError, that instance *will* have .seconds, and if you try to get .seconds on generic TimeoutError, you'll get a different uncaught exception (AttributeError vs. TimeoutError), but that TimeoutError wouldn't have been handled by catching TimeoutExpired.

      I agree with Eric that people who were distinguishing OSError with .errno=ETIME from TimeoutError might be at risk, but I wouldn't do that: if I were going to be distinguishing particular OSErrors on the basis of errno (other than in "Unexpected OSError (errno = %d)" reporting style), I'd just catch OSError and do that. On the other hand, I might expect TimeoutError to catch ETIME. And Giampaolo says he's never seen either. I suppose the author of psutil would be as likely as anyone to have seen it!

      On net (unless we go the deprecation route) it seems that the convenience and "intuition" of adding ETIME to TimeoutError outweighs that risk.

      I wish there were somebody who was there at the creation of ETIME!

    15. giampaolo commented on May 26, 2020

      @giampaolo
      Contributor

      Sigh! I misread the OP's post and thought the proposal was to add TimeoutError which I forgot existed. Sorry for the noise and please disregard my previous comment.

    16. ericvsmith commented on May 26, 2020

      @ericvsmith
      Member

      Thanks for clarifying, Giampaolo. I'll accept this PR once it's cleaned up.

    17. transferred this issue fromon Apr 10, 2022
    18. added
      3.13only security fixes
      and removed on Jan 5, 2024
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

    Metadata

    Metadata

    Assignees

    No one assigned

      Labels

      3.13only security fixesinterpreter-core(Objects, Python, Grammar, and Parser dirs)type-featureA feature request or enhancement

      Projects

      No projects

        Milestone

        No milestone

        Relationships

        None yet

        Development

        No branches or pull requests

        Issue actions