You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by as...@apache.org on 2021/05/14 21:49:45 UTC

[qpid-proton] branch main updated (ea627e7 -> 8c0f668)

This is an automated email from the ASF dual-hosted git repository.

astitcher pushed a change to branch main
in repository https://gitbox.apache.org/repos/asf/qpid-proton.git.


    from ea627e7  PROTON-2377: [cpp] Make tag_counter in sender.cpp atomic
     new bee2418  PROTON-2323: [Python] Minimum supported version is Python 3.6
     new 8c0f668  PROTON-2323: [Python] Remove all Python 2 compatibility code

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 python/CMakeLists.txt                |  5 ---
 python/proton/_compat.py             | 72 ------------------------------------
 python/proton/_data.py               | 42 ++++-----------------
 python/proton/_io.py                 |  5 +--
 python/proton/_message.py            | 54 ++++++++++-----------------
 python/proton/_reactor.py            | 11 ++++--
 python/proton/_url.py                |  4 +-
 python/tests/proton_tests/codec.py   |  8 +++-
 python/tests/proton_tests/message.py | 17 +++------
 python/tox.ini                       |  4 +-
 10 files changed, 53 insertions(+), 169 deletions(-)
 delete mode 100644 python/proton/_compat.py

---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[qpid-proton] 01/02: PROTON-2323: [Python] Minimum supported version is Python 3.6

Posted by as...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

astitcher pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/qpid-proton.git

commit bee24180f75780fbdda8abd55fbfb9eb3d1bcf9b
Author: Andrew Stitcher <as...@apache.org>
AuthorDate: Thu May 13 15:58:24 2021 -0400

    PROTON-2323: [Python] Minimum supported version is Python 3.6
    
    Change Tox testing to stop testing Python 2.7, 3.5 and add 3.9. Also
    tidied up the way CTest calls tox.
---
 python/CMakeLists.txt | 4 ----
 python/tox.ini        | 4 ++--
 2 files changed, 2 insertions(+), 6 deletions(-)

diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt
index 44bc36a..ea75296 100644
--- a/python/CMakeLists.txt
+++ b/python/CMakeLists.txt
@@ -259,13 +259,9 @@ if (NOT TOX_MODULE_FOUND)
 else ()
   option(ENABLE_TOX_TEST "Enable multi-version python testing with TOX" ON)
 
-  set(tox_default "pep8,py27,py35,py36,py37,py38")
   set(TOX_ENVLIST "" CACHE STRING "List of python environments for TOX tests" )
   mark_as_advanced(TOX_ENVLIST)
 
-  if (NOT TOX_ENVLIST)
-    set (TOX_ENVLIST ${tox_default})
-  endif()
   if (ENABLE_TOX_TEST)
     if (CMAKE_BUILD_TYPE MATCHES "Coverage")
       message(STATUS "Building for coverage analysis; skipping the python-tox-tests")
diff --git a/python/tox.ini b/python/tox.ini
index 02f995b..9206d57 100644
--- a/python/tox.ini
+++ b/python/tox.ini
@@ -1,6 +1,6 @@
 [tox]
-# This will usually be overridden by ctest setting TOXENV
-envlist = py36,py37,py38
+# This will be overridden by ctest setting TOXENV for anything but this default
+envlist = pep8,py36,py37,py38,py39
 minversion = 1.7.2
 setupdir = {toxinidir}/dist
 skip_missing_interpreters = True

---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org


[qpid-proton] 02/02: PROTON-2323: [Python] Remove all Python 2 compatibility code

Posted by as...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

astitcher pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/qpid-proton.git

commit 8c0f6689521185d8825d89a984e3aae9f577fb2c
Author: Andrew Stitcher <as...@apache.org>
AuthorDate: Thu May 13 17:57:49 2021 -0400

    PROTON-2323: [Python] Remove all Python 2 compatibility code
    
    Obviously, from this point the proton library will no longer work with
    Python 2.
---
 python/CMakeLists.txt                |  1 -
 python/proton/_compat.py             | 72 ------------------------------------
 python/proton/_data.py               | 42 ++++-----------------
 python/proton/_io.py                 |  5 +--
 python/proton/_message.py            | 54 ++++++++++-----------------
 python/proton/_reactor.py            | 11 ++++--
 python/proton/_url.py                |  4 +-
 python/tests/proton_tests/codec.py   |  8 +++-
 python/tests/proton_tests/message.py | 17 +++------
 9 files changed, 51 insertions(+), 163 deletions(-)

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 @@ endif()
 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 @@ from cproton import PN_ARRAY, PN_BINARY, PN_BOOL, PN_BYTE, PN_CHAR, PN_DECIMAL12
     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 @@ class Data:
         """
         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 @@ class Data:
         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 @@ class Data:
         :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 @@ class Data:
         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 socket
 import select
 import time
 
-from ._compat import socket_errno
 
 PN_INVALID_SOCKET = -1
 
@@ -62,7 +61,7 @@ class IO(object):
         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 @@ class IO(object):
             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 @@ from cproton import PN_DEFAULT_PRIORITY, PN_OVERFLOW, pn_error_text, pn_message,
     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
-
-from . import _compat
+    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 ._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 @@ class Message(object):
         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 @@ class Message(object):
             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 @@ class Message(object):
         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 json
 import logging
 import re
 import os
+import queue
 import time
 import traceback
 import uuid
@@ -46,9 +47,6 @@ from ._handlers import OutgoingMessageHandler, IOHandler
 
 from ._io import IO
 
-from . import _compat
-from ._compat import queue
-
 
 _logger = logging.getLogger("proton")
 
@@ -217,7 +215,12 @@ class Reactor(object):
             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 @@ from __future__ import absolute_import
 
 import socket
 
-from ._compat import urlparse, urlunparse, quote, unquote
+from urllib.parse import urlparse, urlunparse, quote, unquote
 
 
 class Url(object):
@@ -168,7 +168,7 @@ class Url(object):
             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 @@ import sys
 from uuid import uuid4
 
 from proton import *
-from proton._compat import raise_
 
 from . import common
 
@@ -131,7 +130,12 @@ class DataTest(Test):
             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 @@ class AccessorsTest(Test):
         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 @@ class CodecTest(Test):
             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()
 

---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org