211 lines
5.8 KiB
Python
211 lines
5.8 KiB
Python
import errno
|
|
import os
|
|
import platform
|
|
import re
|
|
import socket
|
|
import sys as _sys
|
|
|
|
PY2 = _sys.version_info < (3,)
|
|
PY3 = not PY2
|
|
RE_NUM = re.compile(r'(\d+).+')
|
|
|
|
if _sys.version_info[:2] < (3, 3):
|
|
SOCKET_ERROR = socket.error
|
|
else:
|
|
# socket.error was deprecated and replaced by OSError in python 3.3
|
|
SOCKET_ERROR = OSError
|
|
|
|
try:
|
|
SOL_TCP = socket.SOL_TCP
|
|
except AttributeError:
|
|
SOL_TCP = socket.IPPROTO_TCP
|
|
|
|
if not PY2:
|
|
# these were moved around for Python 3
|
|
from urllib.parse import (quote as url_quote, unquote as url_unquote,
|
|
urlencode)
|
|
|
|
# Python 3 does not have basestring anymore; we include
|
|
# *only* the str here as this is used for textual data.
|
|
basestring = (str,)
|
|
|
|
# for assertions that the data is either encoded or non-encoded text
|
|
str_or_bytes = (str, bytes)
|
|
|
|
# xrange is gone, replace it with range
|
|
xrange = range
|
|
|
|
# the unicode type is str
|
|
unicode_type = str
|
|
|
|
def dictkeys(dct):
|
|
"""
|
|
Returns a list of keys of dictionary
|
|
|
|
dict.keys returns a view that works like .keys in Python 2
|
|
*except* any modifications in the dictionary will be visible
|
|
(and will cause errors if the view is being iterated over while
|
|
it is modified).
|
|
"""
|
|
|
|
return list(dct.keys())
|
|
|
|
def dictvalues(dct):
|
|
"""
|
|
Returns a list of values of a dictionary
|
|
|
|
dict.values returns a view that works like .values in Python 2
|
|
*except* any modifications in the dictionary will be visible
|
|
(and will cause errors if the view is being iterated over while
|
|
it is modified).
|
|
"""
|
|
return list(dct.values())
|
|
|
|
def dict_iteritems(dct):
|
|
"""
|
|
Returns an iterator of items (key/value pairs) of a dictionary
|
|
|
|
dict.items returns a view that works like .items in Python 2
|
|
*except* any modifications in the dictionary will be visible
|
|
(and will cause errors if the view is being iterated over while
|
|
it is modified).
|
|
"""
|
|
return dct.items()
|
|
|
|
def dict_itervalues(dct):
|
|
"""
|
|
:param dict dct:
|
|
:returns: an iterator of the values of a dictionary
|
|
"""
|
|
return dct.values()
|
|
|
|
def byte(*args):
|
|
"""
|
|
This is the same as Python 2 `chr(n)` for bytes in Python 3
|
|
|
|
Returns a single byte `bytes` for the given int argument (we
|
|
optimize it a bit here by passing the positional argument tuple
|
|
directly to the bytes constructor.
|
|
"""
|
|
return bytes(args)
|
|
|
|
class long(int):
|
|
"""
|
|
A marker class that signifies that the integer value should be
|
|
serialized as `l` instead of `I`
|
|
"""
|
|
|
|
def __repr__(self):
|
|
return str(self) + 'L'
|
|
|
|
def canonical_str(value):
|
|
"""
|
|
Return the canonical str value for the string.
|
|
In both Python 3 and Python 2 this is str.
|
|
"""
|
|
|
|
return str(value)
|
|
|
|
def is_integer(value):
|
|
return isinstance(value, int)
|
|
else:
|
|
from urllib import quote as url_quote, unquote as url_unquote, urlencode
|
|
|
|
basestring = basestring
|
|
str_or_bytes = basestring
|
|
xrange = xrange
|
|
unicode_type = unicode
|
|
dictkeys = dict.keys
|
|
dictvalues = dict.values
|
|
dict_iteritems = dict.iteritems
|
|
dict_itervalues = dict.itervalues
|
|
byte = chr
|
|
long = long
|
|
|
|
def canonical_str(value):
|
|
"""
|
|
Returns the canonical string value of the given string.
|
|
In Python 2 this is the value unchanged if it is an str, otherwise
|
|
it is the unicode value encoded as UTF-8.
|
|
"""
|
|
|
|
try:
|
|
return str(value)
|
|
except UnicodeEncodeError:
|
|
return str(value.encode('utf-8'))
|
|
|
|
def is_integer(value):
|
|
return isinstance(value, (int, long))
|
|
|
|
|
|
def as_bytes(value):
|
|
if not isinstance(value, bytes):
|
|
return value.encode('UTF-8')
|
|
return value
|
|
|
|
|
|
def to_digit(value):
|
|
if value.isdigit():
|
|
return int(value)
|
|
match = RE_NUM.match(value)
|
|
return int(match.groups()[0]) if match else 0
|
|
|
|
|
|
def get_linux_version(release_str):
|
|
ver_str = release_str.split('-')[0]
|
|
return tuple(map(to_digit, ver_str.split('.')[:3]))
|
|
|
|
|
|
HAVE_SIGNAL = os.name == 'posix'
|
|
|
|
EINTR_IS_EXPOSED = _sys.version_info[:2] <= (3, 4)
|
|
|
|
LINUX_VERSION = None
|
|
if platform.system() == 'Linux':
|
|
LINUX_VERSION = get_linux_version(platform.release())
|
|
|
|
_LOCALHOST = '127.0.0.1'
|
|
_LOCALHOST_V6 = '::1'
|
|
|
|
def _nonblocking_socketpair(family=socket.AF_INET, type=socket.SOCK_STREAM, proto=0):
|
|
"""
|
|
Returns a pair of sockets in the manner of socketpair with the additional
|
|
feature that they will be non-blocking. Prior to Python 3.5, socketpair
|
|
did not exist on Windows at all.
|
|
"""
|
|
if family == socket.AF_INET:
|
|
host = _LOCALHOST
|
|
elif family == socket.AF_INET6:
|
|
host = _LOCALHOST_V6
|
|
else:
|
|
raise ValueError(
|
|
'Only AF_INET and AF_INET6 socket address families '
|
|
'are supported')
|
|
if type != socket.SOCK_STREAM:
|
|
raise ValueError('Only SOCK_STREAM socket type is supported')
|
|
if proto != 0:
|
|
raise ValueError('Only protocol zero is supported')
|
|
|
|
lsock = socket.socket(family, type, proto)
|
|
try:
|
|
lsock.bind((host, 0))
|
|
lsock.listen(min(socket.SOMAXCONN, 128))
|
|
# On IPv6, ignore flow_info and scope_id
|
|
addr, port = lsock.getsockname()[:2]
|
|
csock = socket.socket(family, type, proto)
|
|
try:
|
|
csock.connect((addr, port))
|
|
ssock, _ = lsock.accept()
|
|
except Exception:
|
|
csock.close()
|
|
raise
|
|
finally:
|
|
lsock.close()
|
|
|
|
# Make sockets non-blocking to prevent deadlocks
|
|
# See https://github.com/pika/pika/issues/917
|
|
csock.setblocking(False)
|
|
ssock.setblocking(False)
|
|
|
|
return ssock, csock
|