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()