_compat.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. """Internal module for Python 2 backwards compatibility."""
  2. import errno
  3. import sys
  4. # For Python older than 3.5, retry EINTR.
  5. if sys.version_info[0] < 3 or (sys.version_info[0] == 3 and
  6. sys.version_info[1] < 5):
  7. # Adapted from https://bugs.python.org/review/23863/patch/14532/54418
  8. import socket
  9. import time
  10. from select import select as _select, error as select_error
  11. def select(rlist, wlist, xlist, timeout):
  12. while True:
  13. try:
  14. return _select(rlist, wlist, xlist, timeout)
  15. except select_error as e:
  16. if e.args[0] == errno.EINTR:
  17. continue
  18. raise
  19. # Wrapper for handling interruptable system calls.
  20. def _retryable_call(s, func, *args, **kwargs):
  21. # Some modules (SSL) use the _fileobject wrapper directly and
  22. # implement a smaller portion of the socket interface, thus we
  23. # need to let them continue to do so.
  24. timeout, deadline = None, 0.0
  25. attempted = False
  26. try:
  27. timeout = s.gettimeout()
  28. except AttributeError:
  29. pass
  30. if timeout:
  31. deadline = time.time() + timeout
  32. try:
  33. while True:
  34. if attempted and timeout:
  35. now = time.time()
  36. if now >= deadline:
  37. raise socket.error(errno.EWOULDBLOCK, "timed out")
  38. else:
  39. # Overwrite the timeout on the socket object
  40. # to take into account elapsed time.
  41. s.settimeout(deadline - now)
  42. try:
  43. attempted = True
  44. return func(*args, **kwargs)
  45. except socket.error as e:
  46. if e.args[0] == errno.EINTR:
  47. continue
  48. raise
  49. finally:
  50. # Set the existing timeout back for future
  51. # calls.
  52. if timeout:
  53. s.settimeout(timeout)
  54. def recv(sock, *args, **kwargs):
  55. return _retryable_call(sock, sock.recv, *args, **kwargs)
  56. def recv_into(sock, *args, **kwargs):
  57. return _retryable_call(sock, sock.recv_into, *args, **kwargs)
  58. else: # Python 3.5 and above automatically retry EINTR
  59. from select import select
  60. def recv(sock, *args, **kwargs):
  61. return sock.recv(*args, **kwargs)
  62. def recv_into(sock, *args, **kwargs):
  63. return sock.recv_into(*args, **kwargs)
  64. if sys.version_info[0] < 3:
  65. from urllib import unquote
  66. from urlparse import parse_qs, urlparse
  67. from itertools import imap, izip
  68. from string import letters as ascii_letters
  69. from Queue import Queue
  70. # special unicode handling for python2 to avoid UnicodeDecodeError
  71. def safe_unicode(obj, *args):
  72. """ return the unicode representation of obj """
  73. try:
  74. return unicode(obj, *args)
  75. except UnicodeDecodeError:
  76. # obj is byte string
  77. ascii_text = str(obj).encode('string_escape')
  78. return unicode(ascii_text)
  79. def iteritems(x):
  80. return x.iteritems()
  81. def iterkeys(x):
  82. return x.iterkeys()
  83. def itervalues(x):
  84. return x.itervalues()
  85. def nativestr(x):
  86. return x if isinstance(x, str) else x.encode('utf-8', 'replace')
  87. def next(x):
  88. return x.next()
  89. def byte_to_chr(x):
  90. return x
  91. unichr = unichr
  92. xrange = xrange
  93. basestring = basestring
  94. unicode = unicode
  95. bytes = str
  96. long = long
  97. else:
  98. from urllib.parse import parse_qs, unquote, urlparse
  99. from string import ascii_letters
  100. from queue import Queue
  101. def iteritems(x):
  102. return iter(x.items())
  103. def iterkeys(x):
  104. return iter(x.keys())
  105. def itervalues(x):
  106. return iter(x.values())
  107. def byte_to_chr(x):
  108. return chr(x)
  109. def nativestr(x):
  110. return x if isinstance(x, str) else x.decode('utf-8', 'replace')
  111. next = next
  112. unichr = chr
  113. imap = map
  114. izip = zip
  115. xrange = range
  116. basestring = str
  117. unicode = str
  118. safe_unicode = str
  119. bytes = bytes
  120. long = int
  121. try: # Python 3
  122. from queue import LifoQueue, Empty, Full
  123. except ImportError: # Python 2
  124. from Queue import LifoQueue, Empty, Full