PROTON-2323: [Python] Remove all Python 2 compatibility code
Obviously, from this point the proton library will no longer work with
Python 2.
diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt
index ea75296..06caf61 100644
--- a/python/CMakeLists.txt
+++ b/python/CMakeLists.txt
@@ -62,7 +62,6 @@
set (pysrc-generated cproton.py)
set (pysrc
proton/__init__.py
- proton/_compat.py
proton/_common.py
proton/_condition.py
proton/_data.py
diff --git a/python/proton/_compat.py b/python/proton/_compat.py
deleted file mode 100644
index 2235d35..0000000
--- a/python/proton/_compat.py
+++ /dev/null
@@ -1,72 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-#
-
-"""
-Utilities to help Proton support both python2 and python3.
-"""
-
-import sys
-
-# bridge between py2 Queue renamed as py3 queue
-try:
- import Queue as queue
-except ImportError:
- import queue # type: ignore
-
-try:
- from urlparse import urlparse, urlunparse
- from urllib import quote, unquote # type: ignore
-except ImportError:
- from urllib.parse import urlparse, urlunparse, quote, unquote
-
-PY3 = sys.version_info[0] == 3
-
-if PY3:
- def raise_(t, v=None, tb=None):
- """Mimic the old 2.x raise behavior:
- Raise an exception of type t with value v using optional traceback tb
- """
- if v is None:
- v = t()
- if tb is None:
- raise v
- else:
- raise v.with_traceback(tb)
-
- def iteritems(d, **kw):
- return iter(d.items(**kw))
-
- def socket_errno(e):
- return e.errno
-
- unichr = chr
-else:
- # the raise syntax will cause a parse error in Py3, so 'sneak' in a
- # definition that won't cause the parser to barf
- exec("""def raise_(t, v=None, tb=None):
- raise t, v, tb
-""")
-
- def iteritems(d, **kw):
- return d.iteritems(**kw)
-
- def socket_errno(e):
- return e[0]
-
- unichr = unichr
diff --git a/python/proton/_data.py b/python/proton/_data.py
index 699a16f..7d63395 100644
--- a/python/proton/_data.py
+++ b/python/proton/_data.py
@@ -37,25 +37,11 @@
pn_data_put_string, pn_data_put_symbol, pn_data_put_timestamp, pn_data_put_ubyte, pn_data_put_uint, \
pn_data_put_ulong, pn_data_put_ushort, pn_data_put_uuid, pn_data_rewind, pn_data_type, pn_data_widen, pn_error_text
-from . import _compat
from ._common import Constant
from ._exceptions import DataException, EXCEPTIONS
-#
-# Hacks to provide Python2 <---> Python3 compatibility
-#
-# The results are
-# | |long|unicode|
-# |Python2|long|unicode|
-# |Python3| int| str|
-try:
- long()
-except NameError:
- long = int
-try:
- unicode()
-except NameError:
- unicode = str
+long = int
+unicode = str
class UnmappedType:
@@ -644,8 +630,8 @@
"""
Return a string name for an AMQP type.
- :param type: Numeric Proton AMQP type (`enum pn_type_t`)
- :type type: integer
+ :param amqptype: Numeric Proton AMQP type (`enum pn_type_t`)
+ :type amqptype: integer
:rtype: String describing the AMQP type with numeric value `amqptype`
"""
return Data.type_names[amqptype]
@@ -1000,7 +986,7 @@
Puts a signed long value.
:param l: an integral value in the range :math:`-(2^{63})` to :math:`2^{63} - 1` inclusive.
- :type ul: ``int``, ``long``
+ :type l: ``int``, ``long``
:raise: * ``AssertionError`` if parameter is out of the range :math:`-(2^{63})` to :math:`2^{63} - 1` inclusive.
* :exc:`DataException` if there is a Proton error.
"""
@@ -1296,7 +1282,7 @@
:return: If the current node is a char, its value, 0 otherwise.
:rtype: :class:`char`
"""
- return char(_compat.unichr(pn_data_get_char(self._data)))
+ return char(chr(pn_data_get_char(self._data)))
def get_ulong(self):
"""
@@ -1636,21 +1622,9 @@
Array: put_py_array,
AnnotationDict: put_dict,
PropertyDict: put_dict,
- SymbolList: put_sequence
+ SymbolList: put_sequence,
+ memoryview: put_memoryview
}
- # for Python 3.x, long is merely an alias for int, but for Python 2.x
- # we need to add an explicit int since it is a different type
- if int not in put_mappings:
- put_mappings[int] = put_int
- # Python >=3.0 has 'memoryview', <=2.5 has 'buffer', >=2.6 has both.
- try:
- put_mappings[memoryview] = put_memoryview
- except NameError:
- pass
- try:
- put_mappings[buffer] = put_buffer
- except NameError:
- pass
get_mappings = {
NULL: lambda s: None,
BOOL: get_bool,
diff --git a/python/proton/_io.py b/python/proton/_io.py
index 20a5a44..400b575 100644
--- a/python/proton/_io.py
+++ b/python/proton/_io.py
@@ -24,7 +24,6 @@
import select
import time
-from ._compat import socket_errno
PN_INVALID_SOCKET = -1
@@ -62,7 +61,7 @@
try:
s.connect(addr[4])
except socket.error as e:
- if socket_errno(e) not in (errno.EINPROGRESS, errno.EWOULDBLOCK, errno.EAGAIN):
+ if e.errno not in (errno.EINPROGRESS, errno.EWOULDBLOCK, errno.EAGAIN):
raise
return s
@@ -158,7 +157,7 @@
try:
r, w, ex = select_inner(timeout)
except select.error as e:
- if socket_errno(e) != errno.EINTR:
+ if e.errno != errno.EINTR:
raise
r, w, ex = ([], [], [])
diff --git a/python/proton/_message.py b/python/proton/_message.py
index c13ac53..f4a73ff 100644
--- a/python/proton/_message.py
+++ b/python/proton/_message.py
@@ -25,26 +25,19 @@
pn_message_get_content_type, pn_message_get_creation_time, pn_message_get_delivery_count, \
pn_message_get_expiry_time, pn_message_get_group_id, pn_message_get_group_sequence, pn_message_get_priority, \
pn_message_get_reply_to, pn_message_get_reply_to_group_id, pn_message_get_subject, pn_message_get_ttl, \
- pn_message_get_user_id, pn_message_id, pn_message_instructions, pn_message_is_durable, pn_message_is_first_acquirer, \
- pn_message_is_inferred, pn_message_properties, pn_message_set_address, pn_message_set_content_encoding, \
- pn_message_set_content_type, pn_message_set_creation_time, pn_message_set_delivery_count, pn_message_set_durable, \
- pn_message_set_expiry_time, pn_message_set_first_acquirer, pn_message_set_group_id, pn_message_set_group_sequence, \
- pn_message_set_inferred, pn_message_set_priority, pn_message_set_reply_to, pn_message_set_reply_to_group_id, \
- pn_message_set_subject, pn_message_set_ttl, pn_message_set_user_id
+ pn_message_get_user_id, pn_message_id, pn_message_instructions, pn_message_is_durable, \
+ pn_message_is_first_acquirer, pn_message_is_inferred, pn_message_properties, pn_message_set_address, \
+ pn_message_set_content_encoding, pn_message_set_content_type, pn_message_set_creation_time, \
+ pn_message_set_delivery_count, pn_message_set_durable, pn_message_set_expiry_time, pn_message_set_first_acquirer, \
+ pn_message_set_group_id, pn_message_set_group_sequence, pn_message_set_inferred, pn_message_set_priority, \
+ pn_message_set_reply_to, pn_message_set_reply_to_group_id, pn_message_set_subject, \
+ pn_message_set_ttl, pn_message_set_user_id
-from . import _compat
from ._common import isinteger, millis2secs, secs2millis, unicode2utf8, utf82unicode
-from ._data import char, Data, decimal128, symbol, ulong, AnnotationDict
+from ._data import char, Data, symbol, ulong, AnnotationDict
from ._endpoints import Link
from ._exceptions import EXCEPTIONS, MessageException
-#
-# Hack to provide Python2 <---> Python3 compatibility
-try:
- unicode()
-except NameError:
- unicode = str
-
class Message(object):
"""The :py:class:`Message` class is a mutable holder of message content.
@@ -72,7 +65,7 @@
self.annotations = None
self.properties = None
self.body = body
- for k, v in _compat.iteritems(kwargs):
+ for k, v in kwargs.items():
getattr(self, k) # Raise exception if it's not a valid attribute.
setattr(self, k, v)
@@ -89,35 +82,27 @@
return err
def _check_property_keys(self):
- '''
+ """
AMQP allows only string keys for properties. This function checks that this requirement is met
and raises a MessageException if not. However, in certain cases, conversions to string are
automatically performed:
- 1. When a key is a user-defined (non-AMQP) subclass of unicode/str (py2/py3).
- AMQP types symbol and char, although derived from unicode/str, are not converted,
+ 1. When a key is a user-defined (non-AMQP) subclass of str.
+ AMQP types symbol and char, although derived from str, are not converted,
and result in an exception.
-
- 2. In Py2, when a key is binary. This is a convenience for Py2 users that encode
- string literals without using the u'' prefix. In Py3, this is not the case, and
- using a binary key will result in an error. AMQP type decimal128, which is derived
- from binary, will not be converted, and will result in an exception.
- '''
+ """
# We cannot make changes to the dict while iterating, so we
# must save and make the changes afterwards
changed_keys = []
for k in self.properties.keys():
- if isinstance(k, unicode):
- # Py2 & Py3 strings and their subclasses
+ if isinstance(k, str):
+ # strings and their subclasses
if type(k) is symbol or type(k) is char:
# Exclude symbol and char
raise MessageException('Application property key is not string type: key=%s %s' % (str(k), type(k)))
- if type(k) is not unicode:
+ if type(k) is not str:
# Only for string subclasses, convert to string
- changed_keys.append((k, unicode(k)))
- elif isinstance(k, str) and not (type(k) is decimal128):
- # Py2 only: If key is binary string then convert to unicode. Exclude bytes subclass decimal128.
- changed_keys.append((k, k.decode('utf-8')))
+ changed_keys.append((k, str(k)))
else:
# Anything else: raise exception
raise MessageException('Application property key is not string type: key=%s %s' % (str(k), type(k)))
@@ -222,7 +207,8 @@
higher priority. The number of available priorities depends
on the implementation, but AMQP defines the default priority as
the value ``4``. See the
- `OASIS AMQP 1.0 standard <http://docs.oasis-open.org/amqp/core/v1.0/os/amqp-core-messaging-v1.0-os.html#type-header>`_
+ `OASIS AMQP 1.0 standard
+ <http://docs.oasis-open.org/amqp/core/v1.0/os/amqp-core-messaging-v1.0-os.html#type-header>`_
for more details on message priority.
:type: ``int``
diff --git a/python/proton/_reactor.py b/python/proton/_reactor.py
index 4eeb6b3..a56c57e 100644
--- a/python/proton/_reactor.py
+++ b/python/proton/_reactor.py
@@ -24,6 +24,7 @@
import logging
import re
import os
+import queue
import time
import traceback
import uuid
@@ -46,9 +47,6 @@
from ._io import IO
-from . import _compat
-from ._compat import queue
-
_logger = logging.getLogger("proton")
@@ -217,7 +215,12 @@
for exc, value, tb in self.errors[:-1]:
traceback.print_exception(exc, value, tb)
exc, value, tb = self.errors[-1]
- _compat.raise_(exc, value, tb)
+ if value is None:
+ value = exc()
+ if tb is None:
+ raise value
+ else:
+ raise value.with_traceback(tb)
def process(self):
# result = pn_reactor_process(self._impl)
diff --git a/python/proton/_url.py b/python/proton/_url.py
index 2794445..e24dd4d 100644
--- a/python/proton/_url.py
+++ b/python/proton/_url.py
@@ -21,7 +21,7 @@
import socket
-from ._compat import urlparse, urlunparse, quote, unquote
+from urllib.parse import urlparse, urlunparse, quote, unquote
class Url(object):
@@ -168,7 +168,7 @@
port = None
if not host:
host = None
- return (host, port)
+ return host, port
@property
def path(self):
diff --git a/python/tests/proton_tests/codec.py b/python/tests/proton_tests/codec.py
index be0da43..a23bcd9 100644
--- a/python/tests/proton_tests/codec.py
+++ b/python/tests/proton_tests/codec.py
@@ -23,7 +23,6 @@
from uuid import uuid4
from proton import *
-from proton._compat import raise_
from . import common
@@ -131,7 +130,12 @@
putter(v)
except Exception:
etype, value, trace = sys.exc_info()
- raise_(etype, etype("%s(%r): %s" % (putter.__name__, v, value)), trace)
+ v = etype("%s(%r): %s" % (putter.__name__, v, value))
+ if trace is None:
+ raise v
+ else:
+ raise v.with_traceback(trace)
+
return putter
# (bits, signed) for each integer type
diff --git a/python/tests/proton_tests/message.py b/python/tests/proton_tests/message.py
index ee6f9b0..2e616f8 100644
--- a/python/tests/proton_tests/message.py
+++ b/python/tests/proton_tests/message.py
@@ -110,21 +110,14 @@
self._test_str("reply_to_group_id")
-try:
- long()
-except NameError:
- long = int
-try:
- unicode()
-except NameError:
- unicode = str
+long = int
+unicode = str
class CodecTest(Test):
def testProperties(self):
- self.msg.properties = {}
- self.msg.properties['key'] = 'value'
+ self.msg.properties = {'key': 'value'}
data = self.msg.encode()
msg2 = Message()
@@ -199,7 +192,9 @@
for k in msg2.properties:
assert type(k) is unicode, 'non-string key %s %s' % (k, type(k))
- def testAnnotationsSymbolicAndUlongKey(self, a={symbol('one'): 1, 'two': 2, ulong(3): 'three'}):
+ def testAnnotationsSymbolicAndUlongKey(self, a=None):
+ if a is None:
+ a = {symbol('one'): 1, 'two': 2, ulong(3): 'three'}
self.msg.annotations = a
data = self.msg.encode()