Merge master
This commit is contained in:
188
infrastructure/lambda/task_queue_manager/redis/_compat.py
Normal file
188
infrastructure/lambda/task_queue_manager/redis/_compat.py
Normal file
@ -0,0 +1,188 @@
|
||||
"""Internal module for Python 2 backwards compatibility."""
|
||||
# flake8: noqa
|
||||
import errno
|
||||
import socket
|
||||
import sys
|
||||
|
||||
|
||||
def sendall(sock, *args, **kwargs):
|
||||
return sock.sendall(*args, **kwargs)
|
||||
|
||||
|
||||
def shutdown(sock, *args, **kwargs):
|
||||
return sock.shutdown(*args, **kwargs)
|
||||
|
||||
|
||||
def ssl_wrap_socket(context, sock, *args, **kwargs):
|
||||
return context.wrap_socket(sock, *args, **kwargs)
|
||||
|
||||
|
||||
# For Python older than 3.5, retry EINTR.
|
||||
if sys.version_info[0] < 3 or (sys.version_info[0] == 3 and
|
||||
sys.version_info[1] < 5):
|
||||
# Adapted from https://bugs.python.org/review/23863/patch/14532/54418
|
||||
import time
|
||||
|
||||
# Wrapper for handling interruptable system calls.
|
||||
def _retryable_call(s, func, *args, **kwargs):
|
||||
# Some modules (SSL) use the _fileobject wrapper directly and
|
||||
# implement a smaller portion of the socket interface, thus we
|
||||
# need to let them continue to do so.
|
||||
timeout, deadline = None, 0.0
|
||||
attempted = False
|
||||
try:
|
||||
timeout = s.gettimeout()
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
if timeout:
|
||||
deadline = time.time() + timeout
|
||||
|
||||
try:
|
||||
while True:
|
||||
if attempted and timeout:
|
||||
now = time.time()
|
||||
if now >= deadline:
|
||||
raise socket.error(errno.EWOULDBLOCK, "timed out")
|
||||
else:
|
||||
# Overwrite the timeout on the socket object
|
||||
# to take into account elapsed time.
|
||||
s.settimeout(deadline - now)
|
||||
try:
|
||||
attempted = True
|
||||
return func(*args, **kwargs)
|
||||
except socket.error as e:
|
||||
if e.args[0] == errno.EINTR:
|
||||
continue
|
||||
raise
|
||||
finally:
|
||||
# Set the existing timeout back for future
|
||||
# calls.
|
||||
if timeout:
|
||||
s.settimeout(timeout)
|
||||
|
||||
def recv(sock, *args, **kwargs):
|
||||
return _retryable_call(sock, sock.recv, *args, **kwargs)
|
||||
|
||||
def recv_into(sock, *args, **kwargs):
|
||||
return _retryable_call(sock, sock.recv_into, *args, **kwargs)
|
||||
|
||||
else: # Python 3.5 and above automatically retry EINTR
|
||||
def recv(sock, *args, **kwargs):
|
||||
return sock.recv(*args, **kwargs)
|
||||
|
||||
def recv_into(sock, *args, **kwargs):
|
||||
return sock.recv_into(*args, **kwargs)
|
||||
|
||||
if sys.version_info[0] < 3:
|
||||
# In Python 3, the ssl module raises socket.timeout whereas it raises
|
||||
# SSLError in Python 2. For compatibility between versions, ensure
|
||||
# socket.timeout is raised for both.
|
||||
import functools
|
||||
|
||||
try:
|
||||
from ssl import SSLError as _SSLError
|
||||
except ImportError:
|
||||
class _SSLError(Exception):
|
||||
"""A replacement in case ssl.SSLError is not available."""
|
||||
pass
|
||||
|
||||
_EXPECTED_SSL_TIMEOUT_MESSAGES = (
|
||||
"The handshake operation timed out",
|
||||
"The read operation timed out",
|
||||
"The write operation timed out",
|
||||
)
|
||||
|
||||
def _handle_ssl_timeout(func):
|
||||
@functools.wraps(func)
|
||||
def wrapper(*args, **kwargs):
|
||||
try:
|
||||
return func(*args, **kwargs)
|
||||
except _SSLError as e:
|
||||
message = len(e.args) == 1 and unicode(e.args[0]) or ''
|
||||
if any(x in message for x in _EXPECTED_SSL_TIMEOUT_MESSAGES):
|
||||
# Raise socket.timeout for compatibility with Python 3.
|
||||
raise socket.timeout(*e.args)
|
||||
raise
|
||||
return wrapper
|
||||
|
||||
recv = _handle_ssl_timeout(recv)
|
||||
recv_into = _handle_ssl_timeout(recv_into)
|
||||
sendall = _handle_ssl_timeout(sendall)
|
||||
shutdown = _handle_ssl_timeout(shutdown)
|
||||
ssl_wrap_socket = _handle_ssl_timeout(ssl_wrap_socket)
|
||||
|
||||
if sys.version_info[0] < 3:
|
||||
from urllib import unquote
|
||||
from urlparse import parse_qs, urlparse
|
||||
from itertools import imap, izip
|
||||
from string import letters as ascii_letters
|
||||
from Queue import Queue
|
||||
|
||||
# special unicode handling for python2 to avoid UnicodeDecodeError
|
||||
def safe_unicode(obj, *args):
|
||||
""" return the unicode representation of obj """
|
||||
try:
|
||||
return unicode(obj, *args)
|
||||
except UnicodeDecodeError:
|
||||
# obj is byte string
|
||||
ascii_text = str(obj).encode('string_escape')
|
||||
return unicode(ascii_text)
|
||||
|
||||
def iteritems(x):
|
||||
return x.iteritems()
|
||||
|
||||
def iterkeys(x):
|
||||
return x.iterkeys()
|
||||
|
||||
def itervalues(x):
|
||||
return x.itervalues()
|
||||
|
||||
def nativestr(x):
|
||||
return x if isinstance(x, str) else x.encode('utf-8', 'replace')
|
||||
|
||||
def next(x):
|
||||
return x.next()
|
||||
|
||||
unichr = unichr
|
||||
xrange = xrange
|
||||
basestring = basestring
|
||||
unicode = unicode
|
||||
long = long
|
||||
BlockingIOError = socket.error
|
||||
else:
|
||||
from urllib.parse import parse_qs, unquote, urlparse
|
||||
from string import ascii_letters
|
||||
from queue import Queue
|
||||
|
||||
def iteritems(x):
|
||||
return iter(x.items())
|
||||
|
||||
def iterkeys(x):
|
||||
return iter(x.keys())
|
||||
|
||||
def itervalues(x):
|
||||
return iter(x.values())
|
||||
|
||||
def nativestr(x):
|
||||
return x if isinstance(x, str) else x.decode('utf-8', 'replace')
|
||||
|
||||
def safe_unicode(value):
|
||||
if isinstance(value, bytes):
|
||||
value = value.decode('utf-8', 'replace')
|
||||
return str(value)
|
||||
|
||||
next = next
|
||||
unichr = chr
|
||||
imap = map
|
||||
izip = zip
|
||||
xrange = range
|
||||
basestring = str
|
||||
unicode = str
|
||||
long = int
|
||||
BlockingIOError = BlockingIOError
|
||||
|
||||
try: # Python 3
|
||||
from queue import LifoQueue, Empty, Full
|
||||
except ImportError: # Python 2
|
||||
from Queue import LifoQueue, Empty, Full
|
Reference in New Issue
Block a user